.code16 .section boot.stage1, "aw" .include "rt/+x86_64/gdt16.S" .include "rt/+x86_64/gdt32.S" .include "rt/+x86_64/gdt64.S" .include "rt/+x86_64/realcall.S" .code16 _stage1_real: xchg %bx, %bx # :At this point, we are in the newly loaded code, but still in 16 bits Real Mode, # we will want to switch to 32 bits protected mode # This is done by # (1) Loading the 32 bits GDT # (2) Enabling protected mode bit # (3) Loading segment registers with the data and code segment offsets # in the GDT # Load the 32 bits GDT by using lgdt on the gdtr32 structure lgdt gdtr32 # :Enable the protected mode bit is bit 1 in %cr0 mov %cr0, %eax or $1, %eax mov %eax, %cr0 # :Longjumping to set the %cs segment register # (the rest will be set there) ljmp $gdt32_code - gdt32, $_stage1 # :Tell the assembler to emit 32 bits code from now on in the file .code32 _stage1: # :We are now in 32 bits protected mode! # Our goal now is to load the stage 3 and to set up the long mode # in order to get to our sweet 64 bits xchg %bx, %bx # :Load the rest of the 32 bits data segments (%cs was set by the longjump) mov $gdt32_data - gdt32, %ax mov %ax, %ds mov %ax, %es mov %ax, %ss mov %ax, %fs mov %ax, %gs pages_clear: # :We know that the pages are located in free memory (in the 0x500 -> 0x7BFF zone) # However, they might contain garbage so we need to free it xchg %bx, %bx mov $_p4, %edi call pages_clear_page mov $_p3, %edi call pages_clear_page mov $_p2, %edi call pages_clear_page mov $_p1, %edi call pages_clear_page pages_fill: # :Set each page level's first entry to point to the next level # in order to identity map the first 2 megabytes of memory # :Here, we or with 3 in order to enable the # 'present' bit and the 'rw' bit on the page entry mov $_p3, %edi or $3, %edi mov %edi, (_p4) # Recursive map the page 4 mov $_p4, %edi or $3, %edi mov $_p4, %ebx mov %edi, 4088(%ebx) mov $_p2, %edi or $3, %edi mov %edi, (_p3) mov $_p1, %edi or $3, %edi mov $_p3, %ebx mov %edi, 8(%ebx) # :Now we are going to fill the first page mov $(1 << 7| 0x3), %ebx mov $512, %ecx mov $_p2, %edi pages_fill_p2_loop: mov %ebx, (%edi) add $0x200000, %ebx add $8, %edi loop pages_fill_p2_loop mov $512, %ecx mov $_p1, %edi pages_fill_p1_loop: mov %ebx, (%edi) add $0x200000, %ebx add $8, %edi loop pages_fill_p1_loop # :Now that the pages are prepared, we must set the %cr3 to point to the level 4 # page table. This register contains the address of the level 4 page mov $_p4, %edi mov %edi, %cr3 pages_enable_pae: # :Enable the physical address extension, extends the virtually addressable # space above 4GB. Also, this is required for long mode # The PAE bit is the 5th bit of the %cr4 register mov %cr4, %eax or $1 << 5, %eax mov %eax, %cr4 pages_enable_longmode_bit: # :Enable the longmode bit. It is the 8th bit of the model specific register # identified with 0xC00000080 mov $0xC0000080, %ecx rdmsr or $1 << 8, %eax wrmsr # :We are now in Compatibility mode. This is a transitational mode between 32 bits protected # and long mode. We still have 2 things to do before entering long mode: # (1) Enabling paging # (2) Loading a 64 bits GDT pages_enable_paging: # :Enable the paging and also make sure that the protected mode is enabled # Everything is in %cr0, paging is bit 31st and protected is bit 0th mov %cr0, %eax or $1 << 31 | 1 << 0, %eax mov %eax, %cr0 reload_segments: # :Last thing to do, reloading the segments xchg %bx, %bx lgdt gdtr64 ljmp $gdt64_code - gdt64, $stage1_long # :pages_clear_page: # Clears the page located at address # pointed by %edi pages_clear_page: push %ecx push %edi mov $0x1000, %ecx pages_clear_page_loop: movb $0x0, (%edi) inc %edi loop pages_clear_page_loop pop %edi pop %ecx ret # :Tell the assembler to emit 64 bits code .code64 stage1_long: # :Finally! We are in long mode. We shall now setup the rest of the segments # registers, as well as the stack, then jump to Hare xchg %bx, %bx mov $gdt64_data - gdt64, %ax mov %ax, %ds mov %ax, %es mov %ax, %ss mov %ax, %fs mov %ax, %gs # :Clear all the registers # (QBE makes this assumption?) xor %rax, %rax xor %rbx, %rbx xor %rcx, %rcx xor %rdx, %rdx xor %rdi, %rdi xor %rsi, %rsi xor %r8, %r8 xor %r9, %r9 xor %r10, %r10 xor %r11, %r11 xor %r12, %r12 xor %r13, %r13 xor %r14, %r14 xor %r15, %r15 xor %rbp, %rbp cli jmp _hare