[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, 0x4000 ; 0x3000
mov cr3, edi     
mov eax, 0      
mov ecx, 0xc00 ; 0x1000
rep stosd       
mov edi, cr3


mov DWORD [edi], 0x5003 ; pml4e[0] = pdpe
add edi, 0x1000
mov DWORD [edi], 0x6003 ; pdpe[0] = pde
add edi, 0x1000
mov DWORD [edi], 0x83 ; pde[0] = pte

mov eax, cr4         
or eax, 1 << 5     
mov cr4, eax         

;end of setting up pages

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
