X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fthreads%2Fstart.S;h=4c6ed2f84a7a05c59af52d44f405d23c1c167965;hb=9869570326bb4e6d39fb41912a9076d53a82ad2d;hp=5a495c4651fecd6bf3d920130123f47f55f6588e;hpb=2f2b3a9b0e72eb25010d1fa757687fd8a87658ef;p=pintos-anon diff --git a/src/threads/start.S b/src/threads/start.S index 5a495c4..4c6ed2f 100644 --- a/src/threads/start.S +++ b/src/threads/start.S @@ -4,13 +4,185 @@ #### so that this module appears at the very beginning of the kernel #### image, and then using that as the entry point. +#include "threads/loader.h" + .intel_syntax noprefix + .section .start +# Code runs in real mode, which is a 16-bit segment. + .code16 + .globl start -.func start - # Call main. -start: call main +start: + +# Disable interrupts. +# String instructions go upward. + + cli + cld + +# Set up data segments. + + sub ax, ax + mov ds, ax + mov es, ax + +#### Enable A20. Address line 20 is tied to low when the machine +#### boots, which prevents addressing memory about 1 MB. This code +#### fixes it. + +# Poll status register while busy. + +1: in al, 0x64 + test al, 0x2 + jnz 1b + +# Send command for writing output port. + + mov al, 0xd1 + outb 0x64, al + +# Poll status register while busy. + +1: in al, 0x64 + test al, 0x2 + jnz 1b + +# Enable A20 line. + + mov al, 0xdf + out 0x60, al + +#### Get memory size, via interrupt 15h function 88h, which returns CF +#### clear if successful, with AX = (kB of physical memory) - 1024. +#### This only works for memory sizes <= 65 MB, which should be fine +#### for our purposes. We only reserve enough memory for page tables +#### for 64 MB of RAM, so we cap it at that value. + + mov ah, 0x88 + int 0x15 + jc panic + cli # BIOS might have enabled interrupts + add eax, 1024 # Total kB memory + cmp eax, 64 * 1024 + jbe 1f + mov eax, 64 * 1024 +1: shr eax, 2 # Total 4 kB pages + mov [ram_pages], eax + +#### Create temporary page directory and page table and set page +#### directory base register. + +# Create page directory at 64 kB and fill with zeroes. + mov ax, LOADER_PD_BASE / 16 + mov es, ax + sub eax, eax + sub edi, edi + mov ecx, 0x400 + rep stosd + +# Add a PDE mapping both virtual addresses 0 and LOADER_PHYS_BASE +# to a single PTE. +# See [IA32-v3] section 3.7.6 for a description of the bits in eax. + + mov eax, LOADER_PT_BASE / 16 + 7 + mov es:[0], eax + mov es:[LOADER_PHYS_BASE / 1024 / 1024], eax + +# Set up one-to-map linear to physical map for the first 4 MB of RAM. +# See [IA32-v3] section 3.7.6 for a description of the bits in eax. - # main() should not return, but if it does, spin. + mov ax, LOADER_PT_BASE / 16 + mov es, ax + mov eax, 0x7 + mov cx, 0x400 +1: stosd + add eax, 0x1000 + loop 1b + +# Set page directory base register. + + mov eax, LOADER_PD_BASE + mov cr3, eax + +#### Switch to protected mode. + +# Then we point the GDTR to our GDT. Protected mode requires a GDT. +# We need a data32 prefix to ensure that all 32 bits of the GDT +# descriptor are loaded (default is to load only 24 bits). + + data32 lgdt gdtdesc + +# Then we turn on the following bits in CR0: +# PE (Protect Enable): this turns on protected mode. +# PG (Paging): turns on paging. +# WP (Write Protect): if unset, ring 0 code ignores +# write-protect bits in page tables (!). +# EM (Emulation): forces floating-point instructions to trap. +# We don't support floating point. + +#define CR0_PE 0x00000001 +#define CR0_EM 0x00000004 +#define CR0_PG 0x80000000 +#define CR0_WP 0x00010000 + + mov eax, cr0 + or eax, CR0_PE + CR0_PG + CR0_WP + CR0_EM + mov cr0, eax + +# We're now in protected mode in a 16-bit segment. The CPU still has +# the real-mode code segment cached in cs's segment descriptor. We +# need to reload cs, and the easiest way is to use a far jump. +# Because we're not in a 32-bit segment the data32 prefix is needed to +# jump to a 32-bit offset. + + data32 ljmp SEL_KCSEG, 1f + LOADER_PHYS_BASE + +# We're now in protected mode in a 32-bit segment. + + .code32 + +# Reload all the other segment registers and the stack pointer to +# point into our new GDT. + +1: mov ax, SEL_KDSEG + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + add esp, LOADER_PHYS_BASE + +#### Jump to kernel entry point. + + mov eax, main + call eax 1: jmp 1b -.endfunc + +#### GDT + +gdt: + .quad 0x0000000000000000 # null seg + .quad 0x00cf9a000000ffff # code seg + .quad 0x00cf92000000ffff # data seg + +gdtdesc: + .word 0x17 # sizeof (gdt) - 1 + .long gdt + LOADER_PHYS_BASE # address gdt + +#### Fatal error. +#### Print panicmsg (with help from the BIOS) and spin. + +panic: .code16 # We only panic in real mode. + mov si, offset panicmsg + mov ah, 0xe + sub bh, bh +1: lodsb + test al, al +2: jz 2b # Spin. + int 0x10 + jmp 1b + +panicmsg: + .ascii "Panic!" + .byte 0