3 ##############################################################################
6 # This code should be stored in the first sector of the hard disk. When the
7 # BIOS runs, it loads this code at physical address 0x7c00-0x7e00 (512 bytes).
8 # Then it jumps to the beginning of it, in real mode.
9 # This code switches into protected mode (32-bit mode) so that all of
10 # memory can accessed, loads the kernel into memory, and jumps to the
11 # first byte of the kernel, where start.S is linked.
12 ##############################################################################
14 .globl start # Entry point
15 start: .code16 # This runs in real mode
16 cli # Disable interrupts
19 movw %ax,%es # Address
22 movw $start,%sp # stack (grows down)
25 #### Address line 20 is tied to low when the machine boots,
26 #### obviously this a bit of a drag, such as when trying to
27 #### address memory above 1MB. This code undoes this.
29 1: inb $0x64,%al # Get status
30 testb $0x2,%al # Busy?
32 movb $0xd1,%al # Command: Write
33 outb %al,$0x64 # output port
34 2: inb $0x64,%al # Get status
35 testb $0x2,%al # Busy?
37 movb $0xdf,%al # Enable
40 #### Get memory size, via interrupt 15h function 88h.
41 #### Returns CF clear if successful, with AX = (kB of physical memory) - 1024.
42 #### This only works for memory sizes <= 65 MB, which should be fine for our purposes.
46 jc panic # Carry flag set on error
47 2: addl $1024,%eax # Total kB
48 shrl $2,%eax # Total 4 kB pages
51 #### switch from real to protected mode
52 #### The segments in GDT allow all of physical memory to be accessed.
53 #### Furthermore, the segments have base addresses of 0, so that the
54 #### segment translation is a NOP, ie. virtual addresses are identical to
55 #### their physical addresses. With this setup, it appears to this code
56 #### that it is running directly on physical memory.
58 cli # Mandatory since we dont set up an IDT
59 lgdt gdtdesc # load GDT -- mandatory in protected mode
60 movl %cr0, %eax # turn on protected mode
63 ### CPU magic: jump to relocation, flush prefetch queue, and reload %cs
64 ### Has the effect of just jmp to the next instruction, but simultaneous
65 ### loads CS with $PROT_MODE_CSEG.
66 ljmp $SEL_KCSEG, $protcseg
68 #### We are in protected mode in a 32-bit segment (hence the .code32)
71 movw $SEL_KDSEG, %ax # set up data segment registers
78 #### Load kernel at 1 MB by frobbing the IDE controller directly.
84 ### Poll status register while controller busy.
90 ### Read a single sector.
95 ### Sector number to write in low 28 bits.
96 ### LBA mode, device 0 in top 4 bits.
98 andl $0x0fffffff, %eax
101 ### Dump %eax to ports 0x1f3...0x1f6.
108 ### READ command to command register.
113 ### Poll status register while controller busy.
118 ### Poll status register until data ready.
130 cmpl $KERNEL_LOAD_PAGES*8 + 1, %ebx
133 ##### Create temporary PDE and PTE and set page directory pointer
134 ##### FIXME? We could use a single 4 MB page instead of 1024 4 kB pages.
141 movl $0x11000 | PG_U | PG_W | PG_P, %eax
144 movl $PG_U | PG_W | PG_P, %eax
158 ##### Turn on EM bit in CR0, forcing most floating-point instructions
159 ##### to trap. We don't support floating-point or MMX.
165 ##### Jump to kernel entry point.
167 movl $0xc0007c00, %esp
168 movl $0xc0100000, %eax
174 .quad 0x0000000000000000 # null seg
175 .quad 0x00cf9a000000ffff # code seg
176 .quad 0x00cf92000000ffff # data seg
179 .word 0x17 # sizeof (gdt) - 1
180 .long gdt # address gdt
182 ##### To panic, we print panicmsg (with help from the BIOS) and spin.
183 panic: .code16 # We only panic in real mode.
194 .ascii "Loader panic!\r\n"
197 ##### Command-line arguments inserted by another utility.
198 ##### The loader doesn't use these, but we note their
199 ##### location here for easy reference.
203 ##### Memory size in 4 kB pages.
208 ##### Boot-sector signature for BIOS inspection.