- subl %eax, %eax
- subl %edi, %edi
- movl $0x400, %ecx
- rep stosl
-
-# Add PDEs to point to PTEs for the first 64 MB of RAM.
-# Also add identical PDEs starting at LOADER_PHYS_BASE.
-# See [IA32-v3a] section 3.7.6 "Page-Directory and Page-Table Entries"
-# for a description of the bits in %eax.
-
-
- movl $0x11007, %eax
- movl $0x11, %ecx
- subl %edi, %edi
-1: movl %eax, %es:(%di)
- movl %eax, %es:LOADER_PHYS_BASE >> 20(%di)
- addw $4, %di
- addl $0x1000, %eax
- loop 1b
-
-# Set up one-to-map linear to physical map for the first 64 MB of RAM.
-# See [IA32-v3a] section 3.7.6 "Page-Directory and Page-Table Entries"
-# for a description of the bits in %eax.
-
- movw $0x1100, %ax
- movw %ax, %es
- movl $0x7, %eax
- movl $0x4000, %ecx
- subl %edi, %edi
-1: movl %eax, %es:(%di)
- addw $4, %di
- addl $0x1000, %eax
- loop 1b
-
-# Set page directory base register.
-
- movl $0x10000, %eax
- movl %eax, %cr3
-
-#### Switch to protected mode.
-
-# Note that interrupts are still off.
-
-# Point the GDTR to our GDT. Protected mode requires a GDT.
-# We need a data32 prefix to ensure that all 32 bits of the GDT
-# descriptor are loaded (default is to load only 24 bits).
-
- data32 lgdt gdtdesc
-
-# Then we turn on the following bits in CR0:
-# PE (Protect Enable): this turns on protected mode.
-# PG (Paging): turns on paging.
-# WP (Write Protect): if unset, ring 0 code ignores
-# write-protect bits in page tables (!).
-# EM (Emulation): forces floating-point instructions to trap.
-# We don't support floating point.
-
- movl %cr0, %eax
- orl $CR0_PE | CR0_PG | CR0_WP | CR0_EM, %eax
- movl %eax, %cr0
-
-# We're now in protected mode in a 16-bit segment. The CPU still has
-# the real-mode code segment cached in %cs's segment descriptor. We
-# need to reload %cs, and the easiest way is to use a far jump.
-# Because we're not in a 32-bit segment the data32 prefix is needed to
-# jump to a 32-bit offset.
-
- data32 ljmp $SEL_KCSEG, $1f + LOADER_PHYS_BASE
-
-# We're now in protected mode in a 32-bit segment.
-
- .code32
-
-# Reload all the other segment registers and the stack pointer to
-# point into our new GDT.
-
-1: movw $SEL_KDSEG, %ax
- movw %ax, %ds
- movw %ax, %es
- movw %ax, %fs
- movw %ax, %gs
- movw %ax, %ss
- movl $LOADER_PHYS_BASE + 0x30000, %esp
-
-#### Load kernel starting at physical address LOADER_KERN_BASE by
-#### frobbing the IDE controller directly.
-
- movl $1, %ebx
- movl $LOADER_KERN_BASE + LOADER_PHYS_BASE, %edi
-
-# Disable interrupt delivery by IDE controller, because we will be
-# polling for data.
-# (If we don't do this, Bochs 2.2.6 will never deliver any IDE
-# interrupt to us later after we reset the interrupt controller during
-# boot, even if we also reset the IDE controller.)
-
- movw $0x3f6, %dx
- movb $0x02, %al
- outb %al, %dx
-
-read_sector:
-
-# Poll status register while controller busy.
-
- movl $0x1f7, %edx
-1: inb %dx, %al
- testb $0x80, %al
- jnz 1b
-
-# Read a single sector.
-
- movl $0x1f2, %edx
- movb $1, %al
- outb %al, %dx
-
-# Sector number to write in low 28 bits.
-# LBA mode, device 0 in top 4 bits.
-
- movl %ebx, %eax
- andl $0x0fffffff, %eax
- orl $0xe0000000, %eax
-
-# Dump %eax to ports 0x1f3...0x1f6.
-
- movl $4, %ecx
-1: incw %dx
- outb %al, %dx
- shrl $8, %eax
- loop 1b
-
-# READ command to command register.
-
- incw %dx
- movb $0x20, %al
- outb %al, %dx
-
-# Poll status register while controller busy.
-
-1: inb %dx, %al
- testb $0x80, %al
- jnz 1b