; ke_syscall.asm - INT 0x40, fault, and IRQ kernel entries (MASM64) ; ; Syscall entry now builds an editable KTRAP_FRAME on the current kernel ; stack. KiExitTrapFrame commits Rip/Cs/Rflags/Rsp/Ss back to the CPU IRET ; slots, which is the foundation for future user APC return redirection. EXTERN KeSyscallDispatch:PROC EXTERN KiEnterTrapFrame:PROC EXTERN KiExitTrapFrame:PROC KTRAP_FRAME_SIZE EQU 240 KTRAP_FRAME_MAGIC EQU 4650545241544B31h KTRAP_KIND_SYSCALL EQU 1 KTRAP_KIND_INTERRUPT EQU 2 KTRAP_MODE_KERNEL EQU 0 KTRAP_MODE_USER EQU 1 TF_Magic EQU 0 TF_Kind EQU 8 TF_Vector EQU 12 TF_PreviousMode EQU 16 TF_Reserved EQU 20 TF_Rax EQU 24 TF_Rcx EQU 32 TF_Rdx EQU 40 TF_Rbx EQU 48 TF_Rbp EQU 56 TF_Rsi EQU 64 TF_Rdi EQU 72 TF_R8 EQU 80 TF_R9 EQU 88 TF_R10 EQU 96 TF_R11 EQU 104 TF_R12 EQU 112 TF_R13 EQU 120 TF_R14 EQU 128 TF_R15 EQU 136 TF_Rip EQU 144 TF_Cs EQU 152 TF_Rflags EQU 160 TF_Rsp EQU 168 TF_Ss EQU 176 TF_RipSlot EQU 184 TF_CsSlot EQU 192 TF_RflagsSlot EQU 200 TF_RspSlot EQU 208 TF_SsSlot EQU 216 .CODE KeSyscallEntry PROC ; CPU frame at entry, ring 3 -> ring 0: ; [rsp+00] RIP, [rsp+08] CS, [rsp+10] RFLAGS, ; [rsp+18] user RSP, [rsp+20] SS ; Save RBX because we use it as the trap-frame pointer and user-mode code ; sees the syscall stub as a normal function call. push rbx sub rsp, KTRAP_FRAME_SIZE mov rbx, rsp mov [rbx + TF_Rax], rax mov rax, KTRAP_FRAME_MAGIC mov [rbx + TF_Magic], rax mov dword ptr [rbx + TF_Kind], KTRAP_KIND_SYSCALL mov dword ptr [rbx + TF_Vector], 40h mov dword ptr [rbx + TF_PreviousMode], KTRAP_MODE_USER mov dword ptr [rbx + TF_Reserved], 0 mov [rbx + TF_Rcx], rcx mov [rbx + TF_Rdx], rdx mov rax, [rbx + KTRAP_FRAME_SIZE] mov [rbx + TF_Rbx], rax mov [rbx + TF_Rbp], rbp mov [rbx + TF_Rsi], rsi mov [rbx + TF_Rdi], rdi mov [rbx + TF_R8], r8 mov [rbx + TF_R9], r9 mov [rbx + TF_R10], r10 mov [rbx + TF_R11], r11 mov [rbx + TF_R12], r12 mov [rbx + TF_R13], r13 mov [rbx + TF_R14], r14 mov [rbx + TF_R15], r15 lea rax, [rbx + KTRAP_FRAME_SIZE + 8] mov [rbx + TF_RipSlot], rax mov rdx, [rax] mov [rbx + TF_Rip], rdx lea rax, [rbx + KTRAP_FRAME_SIZE + 16] mov [rbx + TF_CsSlot], rax mov rdx, [rax] mov [rbx + TF_Cs], rdx lea rax, [rbx + KTRAP_FRAME_SIZE + 24] mov [rbx + TF_RflagsSlot], rax mov rdx, [rax] mov [rbx + TF_Rflags], rdx lea rax, [rbx + KTRAP_FRAME_SIZE + 32] mov [rbx + TF_RspSlot], rax mov rdx, [rax] mov [rbx + TF_Rsp], rdx lea rax, [rbx + KTRAP_FRAME_SIZE + 40] mov [rbx + TF_SsSlot], rax mov rdx, [rax] mov [rbx + TF_Ss], rdx sub rsp, 32 mov rcx, rbx call KiEnterTrapFrame add rsp, 32 ; Re-order original user arguments into KeSyscallDispatch(nr,a0..a5). ; Original registers were saved in the trap frame before any C calls. sub rsp, 64 mov rax, [rbx + TF_R9] mov [rsp + 32], rax ; a3 mov rax, [rbx + TF_R10] mov [rsp + 40], rax ; a4 mov rax, [rbx + TF_R11] mov [rsp + 48], rax ; a5 mov r9, [rbx + TF_R8] ; a2 mov r8, [rbx + TF_Rdx] ; a1 mov rdx, [rbx + TF_Rcx] ; a0 mov rcx, [rbx + TF_Rax] ; nr call KeSyscallDispatch add rsp, 64 mov [rbx + TF_Rax], rax sub rsp, 32 mov rcx, rbx call KiExitTrapFrame add rsp, 32 mov rax, [rbx + TF_Rax] add rsp, KTRAP_FRAME_SIZE pop rbx iretq KeSyscallEntry ENDP ; --------------------------------------------------------------------------- ; Fault stubs - thin wrappers that collect the CPU exception frame and ; forward to KeFaultDispatch (C), which handles both kernel panics and ; user-process bugchecks. ; ; KeFaultDispatch signature (MS x64): ; void KeFaultDispatch(int vector, // rcx ; UINT64 rip, // rdx ; UINT64 errCode, // r8 ; UINT64 cr2, // r9 ; UINT64 cs) // [rsp+20h] (5th arg, on stack) ; --------------------------------------------------------------------------- EXTERN KeFaultDispatch:PROC ; Allocation for a 5-argument call (MS x64): ; 32 bytes shadow space (0x00..0x1F) ; 8 bytes for 5th arg (0x20..0x27) ; Total = 0x28 bytes. ; After "and rsp,-16" rsp%16==0; sub 0x28 (40) → rsp%16==8, ; so the subsequent "call" push makes rsp 16-byte aligned at callee entry. ✓ FAULT_FRAME_SIZE EQU 28h ; --------------------------------------------------------- ; Divide Error (#0) - NO error code pushed by CPU ; Exception frame at entry: [rsp]=RIP [rsp+8]=CS [rsp+16]=RFLAGS ; --------------------------------------------------------- KeFaultDE PROC mov rdx, [rsp] ; Arg2: rip xor r8, r8 ; Arg3: errCode = 0 (no error code for #DE) xor r9, r9 ; Arg4: cr2 = 0 (not a page fault) mov r10, [rsp+8] ; cs (save before we clobber rsp) mov ecx, 0 ; Arg1: vector = 0 and rsp, -16 sub rsp, FAULT_FRAME_SIZE mov [rsp+20h], r10 ; Arg5: cs call KeFaultDispatch ; _Noreturn - never returns KeFaultDE ENDP ; --------------------------------------------------------- ; General Protection Fault (#13) - error code pushed by CPU ; Exception frame at entry: [rsp]=ErrCode [rsp+8]=RIP [rsp+16]=CS ; --------------------------------------------------------- KeFaultGP PROC mov r8, [rsp] ; Arg3: errCode mov rdx, [rsp+8] ; Arg2: rip xor r9, r9 ; Arg4: cr2 = 0 (not a page fault) mov r10, [rsp+16] ; cs mov ecx, 13 ; Arg1: vector = 13 and rsp, -16 sub rsp, FAULT_FRAME_SIZE mov [rsp+20h], r10 ; Arg5: cs call KeFaultDispatch KeFaultGP ENDP ; --------------------------------------------------------- ; Page Fault (#14) - error code pushed by CPU ; Exception frame at entry: [rsp]=ErrCode [rsp+8]=RIP [rsp+16]=CS ; --------------------------------------------------------- KeFaultPF PROC mov r8, [rsp] ; Arg3: errCode mov rdx, [rsp+8] ; Arg2: rip mov r9, cr2 ; Arg4: cr2 (faulting virtual address) mov r10, [rsp+16] ; cs mov ecx, 14 ; Arg1: vector = 14 and rsp, -16 sub rsp, FAULT_FRAME_SIZE mov [rsp+20h], r10 ; Arg5: cs call KeFaultDispatch KeFaultPF ENDP EXTERN KeIrqDispatch:PROC EXTERN KiEnterInterrupt:PROC EXTERN KiExitInterrupt:PROC IrqStub MACRO num PUBLIC KeIrqStub&num KeIrqStub&num PROC push rax mov al, num jmp KeIrqCommon KeIrqStub&num ENDP ENDM IrqStub 0 IrqStub 1 IrqStub 2 IrqStub 3 IrqStub 4 IrqStub 5 IrqStub 6 IrqStub 7 IrqStub 8 IrqStub 9 IrqStub 10 IrqStub 11 IrqStub 12 IrqStub 13 IrqStub 14 IrqStub 15 IrqStub 16 IrqStub 17 IrqStub 18 IrqStub 19 IrqStub 20 IrqStub 21 IrqStub 22 IrqStub 23 KeIrqCommon PROC ; al = irq number, original rax saved by the per-IRQ stub. push rcx push rdx push r8 push r9 push r10 push r11 push rbx sub rsp, KTRAP_FRAME_SIZE mov rbx, rsp movzx edx, al mov rax, KTRAP_FRAME_MAGIC mov [rbx + TF_Magic], rax mov dword ptr [rbx + TF_Kind], KTRAP_KIND_INTERRUPT mov [rbx + TF_Vector], edx mov dword ptr [rbx + TF_Reserved], 0 ; Saved volatile registers live immediately above the trap frame. mov rax, [rbx + KTRAP_FRAME_SIZE + 56] mov [rbx + TF_Rax], rax mov rax, [rbx + KTRAP_FRAME_SIZE + 48] mov [rbx + TF_Rcx], rax mov rax, [rbx + KTRAP_FRAME_SIZE + 40] mov [rbx + TF_Rdx], rax mov rax, [rbx + KTRAP_FRAME_SIZE + 0] mov [rbx + TF_Rbx], rax mov [rbx + TF_Rbp], rbp mov [rbx + TF_Rsi], rsi mov [rbx + TF_Rdi], rdi mov rax, [rbx + KTRAP_FRAME_SIZE + 32] mov [rbx + TF_R8], rax mov rax, [rbx + KTRAP_FRAME_SIZE + 24] mov [rbx + TF_R9], rax mov rax, [rbx + KTRAP_FRAME_SIZE + 16] mov [rbx + TF_R10], rax mov rax, [rbx + KTRAP_FRAME_SIZE + 8] mov [rbx + TF_R11], rax mov [rbx + TF_R12], r12 mov [rbx + TF_R13], r13 mov [rbx + TF_R14], r14 mov [rbx + TF_R15], r15 ; CPU interrupt frame starts after the 8 saved registers. lea rax, [rbx + KTRAP_FRAME_SIZE + 64] mov [rbx + TF_RipSlot], rax mov rdx, [rax] mov [rbx + TF_Rip], rdx lea rax, [rbx + KTRAP_FRAME_SIZE + 72] mov [rbx + TF_CsSlot], rax mov rdx, [rax] mov [rbx + TF_Cs], rdx lea rax, [rbx + KTRAP_FRAME_SIZE + 80] mov [rbx + TF_RflagsSlot], rax mov rdx, [rax] mov [rbx + TF_Rflags], rdx mov rax, [rbx + TF_Cs] and eax, 3 cmp eax, 3 jne short IrqKernelModeFrame mov dword ptr [rbx + TF_PreviousMode], KTRAP_MODE_USER lea rax, [rbx + KTRAP_FRAME_SIZE + 88] mov [rbx + TF_RspSlot], rax mov rdx, [rax] mov [rbx + TF_Rsp], rdx lea rax, [rbx + KTRAP_FRAME_SIZE + 96] mov [rbx + TF_SsSlot], rax mov rdx, [rax] mov [rbx + TF_Ss], rdx jmp short IrqFrameReady IrqKernelModeFrame: mov dword ptr [rbx + TF_PreviousMode], KTRAP_MODE_KERNEL mov qword ptr [rbx + TF_Rsp], 0 mov qword ptr [rbx + TF_Ss], 0 mov qword ptr [rbx + TF_RspSlot], 0 mov qword ptr [rbx + TF_SsSlot], 0 IrqFrameReady: sub rsp, 40 ; 32-byte shadow space + alignment/local slack mov rcx, rbx call KiEnterTrapFrame call KiEnterInterrupt mov ecx, [rbx + TF_Vector] call KeIrqDispatch call KiExitInterrupt mov rcx, rbx call KiExitTrapFrame add rsp, 40 add rsp, KTRAP_FRAME_SIZE pop rbx pop r11 pop r10 pop r9 pop r8 pop rdx pop rcx pop rax iretq KeIrqCommon ENDP END