-#### Enable A20:
-#### Address line 20 is tied to low when the machine boots,
-#### obviously this a bit of a drag, such as when trying to
-#### address memory above 1MB. This code undoes this.
-
-1: inb $0x64,%al # Get status
- testb $0x2,%al # Busy?
- jnz 1b # Yes
- movb $0xd1,%al # Command: Write
- outb %al,$0x64 # output port
-2: inb $0x64,%al # Get status
- testb $0x2,%al # Busy?
- jnz 2b # Yes
- movb $0xdf,%al # Enable
- outb %al,$0x60 # A20
-
-#### Get memory size, via interrupt 15h function 88h.
-#### Returns CF clear if successful, with AX = (kB of physical memory) - 1024.
-#### This only works for memory sizes <= 65 MB, which should be fine for our purposes.
-
- movb $0x88,%ah
- int $0x15
- jc panic # Carry flag set on error
-2: addl $1024,%eax # Total kB
- shrl $2,%eax # Total 4 kB pages
- movl %eax, ram_pages
-
-#### switch from real to protected mode
-#### The segments in GDT allow all of physical memory to be accessed.
-#### Furthermore, the segments have base addresses of 0, so that the
-#### segment translation is a NOP, ie. virtual addresses are identical to
-#### their physical addresses. With this setup, it appears to this code
-#### that it is running directly on physical memory.
-
- cli # Mandatory since we dont set up an IDT
- lgdt gdtdesc # load GDT -- mandatory in protected mode
- movl %cr0, %eax # turn on protected mode
- orl $CR0_PE, %eax #
- movl %eax, %cr0 #
- ### CPU magic: jump to relocation, flush prefetch queue, and
- ### reload %cs Has the effect of just jmp to the next
- ### instruction, but simultaneous loads CS with
- ### $PROT_MODE_CSEG.
- ljmp $SEL_KCSEG, $protcseg
-
-#### We are in protected mode in a 32-bit segment (hence the .code32)
-protcseg:
- .code32
- movw $SEL_KDSEG, %ax # set up data segment registers
- movw %ax, %ds
- movw %ax, %es
- movw %ax, %fs
- movw %ax, %gs
- movw %ax, %ss
-
-#### Load kernel starting at physical address LOADER_KERN_BASE by
-#### frobbing the IDE controller directly.
-
- movl $1, %ebx
- movl $LOADER_KERN_BASE, %edi
-read_sector: