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