1 #include "threads/loader.h"
3 #### Kernel startup code.
5 #### The loader (in loader.S) loads the kernel at physical address
6 #### 0x20000 (128 kB) and jumps to "start", defined here. This code
7 #### switches from real mode to 32-bit protected mode and calls
10 /* Flags in control register 0. */
11 #define CR0_PE 0x00000001 /* Protection Enable. */
12 #define CR0_EM 0x00000004 /* (Floating-point) Emulation. */
13 #define CR0_PG 0x80000000 /* Paging. */
14 #define CR0_WP 0x00010000 /* Write-Protect enable in kernel mode. */
18 # The following code runs in real mode, which is a 16-bit code segment.
25 # The loader called into us with CS = 0x2000, SS = 0x0000, ESP = 0xf000,
26 # but we should initialize the other segment registers.
32 # Set string instructions to go upward.
35 #### Get memory size, via interrupt 15h function 88h (see [IntrList]),
36 #### which returns AX = (kB of physical memory) - 1024. This only
37 #### works for memory sizes <= 65 MB, which should be fine for our
38 #### purposes. We cap memory at 64 MB because that's all we prepare
39 #### page tables for, below.
43 addl $1024, %eax # Total kB memory
44 cmp $0x10000, %eax # Cap at 64 MB
47 1: shrl $2, %eax # Total 4 kB pages
48 addr32 movl %eax, init_ram_pages - LOADER_PHYS_BASE - 0x20000
50 #### Enable A20. Address line 20 is tied low when the machine boots,
51 #### which prevents addressing memory about 1 MB. This code fixes it.
53 # Poll status register while busy.
59 # Send command for writing output port.
64 # Poll status register while busy.
75 # Poll status register while busy.
81 #### Create temporary page directory and page table and set page
82 #### directory base register.
84 # Create page directory at 0xf000 (60 kB) and fill with zeroes.
92 # Add PDEs to point to page tables for the first 64 MB of RAM.
93 # Also add identical PDEs starting at LOADER_PHYS_BASE.
94 # See [IA32-v3a] section 3.7.6 "Page-Directory and Page-Table Entries"
95 # for a description of the bits in %eax.
100 1: movl %eax, %es:(%di)
101 movl %eax, %es:LOADER_PHYS_BASE >> 20(%di)
106 # Set up page tables for one-to-map linear to physical map for the
107 # first 64 MB of RAM.
108 # See [IA32-v3a] section 3.7.6 "Page-Directory and Page-Table Entries"
109 # for a description of the bits in %eax.
116 1: movl %eax, %es:(%di)
121 # Set page directory base register.
126 #### Switch to protected mode.
128 # First, disable interrupts. We won't set up the IDT until we get
129 # into C code, so any interrupt would blow us away.
133 # Protected mode requires a GDT, so point the GDTR to our GDT.
134 # We need a data32 prefix to ensure that all 32 bits of the GDT
135 # descriptor are loaded (default is to load only 24 bits).
136 # The CPU doesn't need an addr32 prefix but ELF doesn't do 16-bit
139 data32 addr32 lgdt gdtdesc - LOADER_PHYS_BASE - 0x20000
141 # Then we turn on the following bits in CR0:
142 # PE (Protect Enable): this turns on protected mode.
143 # PG (Paging): turns on paging.
144 # WP (Write Protect): if unset, ring 0 code ignores
145 # write-protect bits in page tables (!).
146 # EM (Emulation): forces floating-point instructions to trap.
147 # We don't support floating point.
150 orl $CR0_PE | CR0_PG | CR0_WP | CR0_EM, %eax
153 # We're now in protected mode in a 16-bit segment. The CPU still has
154 # the real-mode code segment cached in %cs's segment descriptor. We
155 # need to reload %cs, and the easiest way is to use a far jump.
156 # Because we're not running in a 32-bit segment the data32 prefix is
157 # needed to jump to a 32-bit offset in the target segment.
159 data32 ljmp $SEL_KCSEG, $1f
161 # We're now in protected mode in a 32-bit segment.
162 # Let the assembler know.
166 # Reload all the other segment registers and the stack pointer to
167 # point into our new GDT.
169 1: mov $SEL_KDSEG, %ax
175 addl $LOADER_PHYS_BASE, %esp
176 movl $0, %ebp # Null-terminate main()'s backtrace
182 # main() shouldn't ever return. If it does, spin.
191 .quad 0x0000000000000000 # Null segment. Not used by CPU.
192 .quad 0x00cf9a000000ffff # System code, base 0, limit 4 GB.
193 .quad 0x00cf92000000ffff # System data, base 0, limit 4 GB.
196 .word gdtdesc - gdt - 1 # Size of the GDT, minus 1 byte.
197 .long gdt # Address of the GDT.
199 #### Physical memory size in 4 kB pages. This is exported to the rest
201 .globl init_ram_pages