5 ##############################################################################
8 # This code should be stored in the first sector of the hard disk. When the
9 # BIOS runs, it loads this code at physical address 0x7c00-0x7e00 (512 bytes).
10 # Then it jumps to the beginning of it, in real mode.
11 # This code switches into protected mode (32-bit mode) so that all of
12 # memory can accessed, loads the kernel into memory, and jumps to the
13 # first byte of the kernel, where start.S is linked.
14 ##############################################################################
16 /* Flags in control register 0 */
17 #define CR0_PE 0x00000001 /* Protection Enable. */
18 #define CR0_EM 0x00000004 /* (Floating-point) Emulation. */
19 #define CR0_PG 0x80000000 /* Paging. */
20 #define CR0_WP 0x00010000 /* Write-Protect enable in kernel mode. */
22 .globl start # Entry point
23 start: .code16 # This runs in real mode
24 cli # Disable interrupts
27 movw %ax,%es # Address
30 movw $start,%sp # stack (grows down)
33 #### Address line 20 is tied to low when the machine boots,
34 #### obviously this a bit of a drag, such as when trying to
35 #### address memory above 1MB. This code undoes this.
37 1: inb $0x64,%al # Get status
38 testb $0x2,%al # Busy?
40 movb $0xd1,%al # Command: Write
41 outb %al,$0x64 # output port
42 2: inb $0x64,%al # Get status
43 testb $0x2,%al # Busy?
45 movb $0xdf,%al # Enable
48 #### Get memory size, via interrupt 15h function 88h.
49 #### Returns CF clear if successful, with AX = (kB of physical memory) - 1024.
50 #### This only works for memory sizes <= 65 MB, which should be fine for our purposes.
54 jc panic # Carry flag set on error
55 2: addl $1024,%eax # Total kB
56 shrl $2,%eax # Total 4 kB pages
59 #### switch from real to protected mode
60 #### The segments in GDT allow all of physical memory to be accessed.
61 #### Furthermore, the segments have base addresses of 0, so that the
62 #### segment translation is a NOP, ie. virtual addresses are identical to
63 #### their physical addresses. With this setup, it appears to this code
64 #### that it is running directly on physical memory.
66 cli # Mandatory since we dont set up an IDT
67 lgdt gdtdesc # load GDT -- mandatory in protected mode
68 movl %cr0, %eax # turn on protected mode
71 ### CPU magic: jump to relocation, flush prefetch queue, and
72 ### reload %cs Has the effect of just jmp to the next
73 ### instruction, but simultaneous loads CS with
75 ljmp $SEL_KCSEG, $protcseg
77 #### We are in protected mode in a 32-bit segment (hence the .code32)
80 movw $SEL_KDSEG, %ax # set up data segment registers
87 #### Load kernel starting at physical address LOADER_KERN_BASE by
88 #### frobbing the IDE controller directly.
91 movl $LOADER_KERN_BASE, %edi
94 ### Poll status register while controller busy.
100 ### Read a single sector.
105 ### Sector number to write in low 28 bits.
106 ### LBA mode, device 0 in top 4 bits.
108 andl $0x0fffffff, %eax
109 orl $0xe0000000, %eax
111 ### Dump %eax to ports 0x1f3...0x1f6.
118 ### READ command to command register.
123 ### Poll status register while controller busy.
128 ### Poll status register until data ready.
140 cmpl $KERNEL_LOAD_PAGES*8 + 1, %ebx
143 ##### Create temporary page directory and page table, set page
144 ##### directory pointer, and turn on paging.
145 ##### FIXME? We could use a single 4 MB page instead of 1024 4 kB pages.
147 # Create page directory at 64 kB.
151 # Fill page directory with zeroes.
156 # Set PDEs for 0 and LOADER_PHYS_BASE to point to the
158 movl $0x11000 | PG_U | PG_W | PG_P, %eax
160 movl %eax, 0x10000 | (LOADER_PHYS_BASE >> 20)
162 # Initialize page table.
163 movl $PG_U | PG_W | PG_P, %eax
169 # Turn on paging and kernel write-protect.
171 orl $CR0_PG | CR0_WP, %eax
176 ##### Turn on EM bit in CR0, forcing most floating-point instructions
177 ##### to trap. We don't support floating-point or MMX.
183 ##### Jump to kernel entry point.
185 movl $LOADER_PHYS_BASE + LOADER_BASE, %esp
186 movl $LOADER_PHYS_BASE + LOADER_KERN_BASE, %eax
192 .quad 0x0000000000000000 # null seg
193 .quad 0x00cf9a000000ffff # code seg
194 .quad 0x00cf92000000ffff # data seg
197 .word 0x17 # sizeof (gdt) - 1
198 .long gdt # address gdt
200 ##### To panic, we print panicmsg (with help from the BIOS) and spin.
201 panic: .code16 # We only panic in real mode.
212 .ascii "Loader panic!\r\n"
215 ##### Memory size in 4 kB pages.
216 .org LOADER_RAM_PAGES - LOADER_BASE
220 ##### Command-line arguments inserted by another utility.
221 ##### The loader doesn't use these, but we note their
222 ##### location here for easy reference.
223 .org LOADER_CMD_LINE - LOADER_BASE
227 ##### Boot-sector signature for BIOS inspection.
228 .org LOADER_BIOS_SIG - LOADER_BASE