[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
