3 ###################################################################################
5 # This code should be stored in the first sector of the hard disk. When the
6 # BIOS runs, it loads this code at physical address 0x7c00 - 0x7e00 (512 bytes).
7 # Then jumps to the beginning of it, in real-mode (BIOS runs in real mode).
9 # This code switches into protected mode (32-bit mode) so that all of
10 # memory can accessed, then calls into C.
11 ###################################################################################
13 .globl start # Entry point
14 start: .code16 # This runs in real mode
15 cli # Disable interrupts
18 movw %ax,%es # Address
21 movw $start,%sp # stack (grows down)
24 #### Address line 20 is tied to low when the machine boots,
25 #### obviously this a bit of a drag, such as when trying to
26 #### address memory above 1MB. This code undoes this.
28 1: inb $0x64,%al # Get status
29 testb $0x2,%al # Busy?
31 movb $0xd1,%al # Command: Write
32 outb %al,$0x64 # output port
33 2: inb $0x64,%al # Get status
34 testb $0x2,%al # Busy?
36 movb $0xdf,%al # Enable
39 #### Get memory size, via interrupt 15h function 88h.
40 #### Returns CF clear if successful, with AX = (kB of physical memory) - 1024.
41 #### This only works for memory sizes <= 65 MB, which should be fine for our purposes.
45 jc panic # Carry flag set on error
46 addl $1024,%eax # Total kB
47 shrl $2,%eax # Total 4 kB pages
50 #### switch from real to protected mode
51 #### The segments in GDT allow all of physical memory to be accessed.
52 #### Furthermore, the segments have base addresses of 0, so that the
53 #### segment translation is a NOP, ie. virtual addresses are identical to
54 #### their physical addresses. With this setup, it appears to this code
55 #### that it is running directly on physical memory.
57 cli # Mandatory since we dont set up an IDT
58 lgdt gdtdesc # load GDT -- mandatory in protected mode
59 movl %cr0, %eax # turn on protected mode
62 ### CPU magic: jump to relocation, flush prefetch queue, and reload %cs
63 ### Has the effect of just jmp to the next instruction, but simultaneous
64 ### loads CS with $PROT_MODE_CSEG.
65 ljmp $SEL_KCSEG, $protcseg
67 #### We are in protected mode in a 32-bit segment (hence the .code32)
70 movw $SEL_KDSEG, %ax # set up data segment registers
77 #### Load kernel at 1 MB by frobbing the IDE controller directly.
92 andl $0x0fffffff, %eax
114 cmpl $KERNEL_LOAD_PAGES*8 + 1, %ebx
117 ##### Create temporary PDE and PTE and set page directory pointer
118 ##### FIXME? We could use a single 4 MB page instead of 1024 4 kB pages.
125 movl $0x11000 | PG_U | PG_W | PG_P, %eax
128 movl $PG_U | PG_W | PG_P, %eax
142 ##### Jump to kernel entry point.
144 movl $0xc0007c00, %esp
145 movl $0xc0100000, %eax
151 .quad 0x0000000000000000 # null seg
152 .quad 0x00cf9a000000ffff # code seg
153 .quad 0x00cf92000000ffff # data seg
156 .word 0x17 # sizeof (gdt) - 1
157 .long gdt # address gdt
159 ##### Arrive here on error
162 ##### Memory size in 4 kB pages.
167 ##### Boot-sector signature for BIOS inspection.