365 lines
10 KiB
NASM
365 lines
10 KiB
NASM
; 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
|