; ; SyscallEntry.asm ; SYSCALL/SYSRET entry point and user-mode transition (SMP-aware) ; Copyright (c) 2025-2026 Daniel Hammer ; [bits 64] section .text extern SyscallDispatch ; ==================================================================== ; Per-CPU data offsets (must match CpuData in SmpBoot.hpp) ; ==================================================================== %define CPUDATA_KERNEL_RSP 8 %define CPUDATA_USER_RSP 16 ; ==================================================================== ; SyscallEntry -- called by the SYSCALL instruction ; RCX = user RIP, R11 = user RFLAGS, RAX = syscall number ; Args: RDI, RSI, RDX, R10, R8, R9 ; Interrupts are masked (FMASK clears IF) ; ==================================================================== global SyscallEntry SyscallEntry: swapgs ; GS now points to per-CPU CpuData mov [gs:CPUDATA_USER_RSP], rsp ; save user RSP to per-CPU scratch mov rsp, [gs:CPUDATA_KERNEL_RSP] ; switch to per-CPU kernel stack ; Build SyscallFrame on kernel stack (push order matches struct) push qword [gs:CPUDATA_USER_RSP] ; user_rsp push rcx ; user_rip push r11 ; user_rflags push rax ; syscall_nr push rdi ; arg1 push rsi ; arg2 push rdx ; arg3 push r10 ; arg4 push r8 ; arg5 push r9 ; arg6 ; Callee-saved registers (preserve for user) push rbx push rbp push r12 push r13 push r14 push r15 sti ; safe to take interrupts now mov rdi, rsp ; arg1 = pointer to SyscallFrame call SyscallDispatch ; returns int64_t in rax cli ; disable interrupts for sysret pop r15 pop r14 pop r13 pop r12 pop rbp pop rbx add rsp, 56 ; skip arg6..arg1 (6*8) + syscall_nr (1*8) = 56 pop r11 ; user RFLAGS pop rcx ; user RIP pop rsp ; user RSP swapgs ; restore user GS o64 sysret ; ==================================================================== ; JumpToUserMode -- initial transition to ring 3 via IRETQ ; RDI = user RIP (entry point) ; RSI = user RSP (top of user stack) ; RDX = user RDI (first SystemV arg, e.g. thread arg; 0 for new processes) ; ==================================================================== global JumpToUserMode JumpToUserMode: mov ax, 0x1B ; UserData | RPL3 mov ds, ax mov es, ax push 0x1B ; SS = UserData | RPL3 push rsi ; RSP = user stack top push 0x202 ; RFLAGS (IF=1) push 0x23 ; CS = UserCode | RPL3 push rdi ; RIP = entry point mov rdi, rdx ; SystemV arg #1 -> user RDI xor rsi, rsi ; zero argv-ish registers for hygiene xor rdx, rdx xor rcx, rcx xor r8, r8 xor r9, r9 swapgs ; switch from kernel GS to user GS iretq