bits 64

extern do_syscall

section .text

syscall_entry:
  mov r11, rsp
  mov rsp, 0xfffffffffffff000
  push r11
  push rcx

  push rdx
  push rsi
  push rdi
  push rax

  mov rdi, rsp
  lea rsi, [rsp + 8]
  lea rdx, [rsp + 16]
  lea rcx, [rsp + 24]

  call do_syscall

  pop rax
  pop rdi
  pop rsi
  pop rdx

  xor r8, r8
  xor r9, r9
  xor r10, r10
  xor r11, r11
  or r11, 0x200
  pop rcx
  pop rsp

  o64 sysret

global init_applications_asm
init_applications_asm:

  ;efer <- efer | 0x1
  mov rcx, 0xc0000080
  rdmsr
  or al, 1
  wrmsr

  ;lstar <- syscall_entry
  mov rdx, syscall_entry
  mov eax, edx
  shr rdx, 32
  mov ecx, 0xc0000082
  wrmsr

  ;star <- 0x0030.0028.0000.0000
  mov edx, 0x00300028
  xor eax, eax
  mov ecx, 0xc0000081
  wrmsr

  ;sfmask <- 0x0000.0000.0000.0200 (if)
  xor edx, edx
  mov eax, 0x200
  mov ecx, 0xc0000084
  wrmsr

  ret

section .bss

resume_stack:
  resb 4096

section .text

extern restore_syscall_stack
;rdi = pointer to copy
;rsi = intended rsp

global resume_thread
resume_thread:
;rdi = ptr to cpu_state
;rdi is not inside stack
;interrupts are disabled

  mov al, byte [rdi + 160] ;in_syscall
  test al, al
  jnz .in_syscall

  mov rax, 0x3b
  mov rbx, 0x43

.common:
  push rax
  mov rax, qword [rdi + 56] ;rsp
  push rax
  mov rax, qword [rdi + 128] ;rflags
  push rax
  push rbx
  mov rax, qword [rdi + 136] ;rip
  push rax

  mov rax, qword [rdi + 144] ;cr3
  mov cr3, rax

  mov rax, qword [rdi]
  mov rbx, qword [rdi + 8]
  mov rcx, qword [rdi + 16]
  mov rdx, qword [rdi + 24]
  mov rsi, qword [rdi + 40]
  mov rbp, qword [rdi + 48]
  mov r8, qword [rdi + 64]
  mov r9, qword [rdi + 72]
  mov r10, qword [rdi + 80]
  mov r11, qword [rdi + 88]
  mov r12, qword [rdi + 96]
  mov r13, qword [rdi + 104]
  mov r14, qword [rdi + 112]
  mov r15, qword [rdi + 120]
  mov rdi, qword [rdi + 32]

  iretq

.in_syscall:
  mov rsp, resume_stack + 4096

  push rdi
  mov rsi, qword [rdi + 56] ;rsp
  mov rdi, qword [rdi + 152] ;kernel_stack_copy
  call restore_syscall_stack
  pop rdi

  mov rax, 0x30
  mov rbx, 0x28
  jmp .common

extern copy_syscall_stack
;rdi = bottom

global save_thread_state
save_thread_state:
;rdi = pointer to cpu state structure

  ;only saving registers that need to be preserved by this function
  mov qword [rdi + 8], rbx
  mov qword [rdi + 48], rbp
  mov qword [rdi + 56], rsp
  mov qword [rdi + 96], r12
  mov qword [rdi + 104], r13
  mov qword [rdi + 112], r14
  mov qword [rdi + 120], r15

  mov qword [rdi + 136], .resume_to ;rip
  mov rax, cr3
  mov qword [rdi + 144], rax ;cr3

  push rdi
  lea rdi, [rsp + 8]
  call copy_syscall_stack
  pop rdi

  mov qword [rdi + 152], rax ;kernel_stack_copy
  mov byte [rdi + 160], 0x01 ;in_syscall

  xor al, al
  ret

.resume_to:
  mov al, 0x01
  ret
