[extern main] [extern _kernel_stack_loc] enter_longmode: cli ; TODO check if a20 is already set mov al, 0x92 or al, 2 out 0x92, al lgdt [protected_gdt.descriptor] mov eax, cr0 or eax, 0x1 mov cr0, eax mov eax, 0x8 mov ds, eax jmp 0x8:init_longmode bits 32 init_longmode: mov ebp, 0xffff mov esp, ebp mov ax, PROTECTED_DATA_SEGMENT mov ds, ax mov ss, ax mov es, ax mov fs, ax mov gs, ax mov edi, 0x3000 ; this is where our page tables will be mov cr3, edi mov eax, 0 ; what we'll be putting there mov ecx, 4096 ; how many times we'll put it there rep stosd ; kinda like memset(&edi, ecx, edi) mov edi, cr3 mov DWORD [edi], 0x4003 ; pml4e[0] = pdpe add edi, 0x1000 mov DWORD [edi], 0x5003 ; pdpe[0] = pde add edi, 0x1000 mov DWORD [edi], 0x6003 ; pde[0] = pte add edi, 0x1000 mov ebx, 0x00000003 ; the flags mov ecx, 512; the loop counter, will map 2 mib .idmap_pte_loop: mov DWORD [edi], ebx add ebx, 0x1000 ; physical address. Should leave us at 0x7000 add edi, 8 ; position in page table loop .idmap_pte_loop mov eax, cr4 or eax, 1 << 5 mov cr4, eax mov ecx, 0xc0000080 rdmsr or eax, 1 << 8 wrmsr mov eax, cr0 or eax, 1 << 31 | 1 << 0 ; this is where we set paging and protected mode (respectively)! mov cr0, eax mov ecx, 0xc0000080 rdmsr or eax, 1 << 8 wrmsr mov eax, cr0 or eax, 1 << 31 mov cr0, eax lgdt [long_gdt.descriptor] jmp LONG_CODE_SEGMENT:enter_kernel enter_kernel: bits 64 mov rbp, _kernel_stack_loc mov rsp, _kernel_stack_loc call main ; where we actually call the kernel jmp $ ret