; SPDX-License-Identifier: MPL-2.0
bits 16
org 0x7000

start:
  cli
  lgdt [gdtr]
  mov eax, cr0
  or eax, 1
  mov cr0, eax
  jmp 0x10:second_stage_entry

gdt_phys_addr equ 0x8000 ; the bsp will always place the 32 bits gdt at 0x8000

gdtr:
  dw 32 - 1 ; the size of three segment less 1
  dd gdt_phys_addr

bits 32

second_stage_entry:
  mov ax, 0x18
  mov ds, ax
  mov es, ax
  mov ss, ax
  ; read lapic base
  mov eax, [0x9000]
  ; get lapic id and keep it safe
  mov esi, [eax + 0x20]
  shr esi, 24
  ; enable PAE
  mov eax, cr4
  or eax, 1 << 5
  mov cr4, eax
  ; load cr3
  mov eax, [0x9010]
  mov cr3, eax
  ; enable LME
  mov ecx, 0xC0000080
  rdmsr
  or eax, 1 << 8
  or eax, 1 << 11 ; enable this fuckingly useless kill switch that is the NXE bit, this should be enabled by default
  wrmsr
  ; enable pagging
  mov eax, cr0
  or eax, (1 << 31)
  mov cr0, eax
  jmp 0x08:third_stage_entry

bits 64

cpu_struct_size_bytes equ 22

far_jump:
  dq 0x08
  dq fourth_stage_entry

third_stage_entry:
  mov rax, [0x9018] ; base pointer
  mov rdi, cpu_struct_size_bytes
  mov rsi, rsi
  ; rdi = lapic_id * struct_size
  imul rdi, rsi
  ; rax = base + offset
  add rax, rdi

  ; test if cpu struct is the expected one
  mov edi, [rax + 0x8]
  cmp rsi, rdi
  jne incorrect_lapic_id

  ; load stack
  mov rcx, [rax]
  mov rsp, rcx
  and rsp, -16
  sub rsp, 8

  ; load gdt 64
  mov rcx, 0x9028
  lgdt [rcx]
  mov cx, 0x10
  mov ds, cx
  mov es, cx
  mov ss, cx
  xor cx, cx
  mov fs, cx
  mov gs, cx

  ; reload cs
  push 0x08
  lea rcx, [rel fourth_stage_entry]
  push rcx
  retfq

incorrect_lapic_id:
  hlt;

fourth_stage_entry:
  ; load ltr
  mov cx, [rax + 12]
  ltr cx

  ; load gs
  mov rdx, rax
  shr rdx, 32
  mov ecx, 0xC0000101
  wrmsr

  ; jump to C
  mov rcx, [0x9008]
  jmp rcx
  hlt
