Files
nt-lite/code/kernel/ke_syscall.asm
T

788 lines
20 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 used by user APC return redirection.
EXTERN KeSyscallDispatch:PROC
EXTERN KiEnterTrapFrame:PROC
EXTERN KiExitTrapFrame:PROC
EXTERN KeFaultDispatchFrame: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_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
swapgs ; GS_BASE: user TEB -> KCPU, KERNEL_GS_BASE: KCPU -> user TEB
; 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 [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
swapgs ; GS_BASE: KCPU -> user TEB before returning to ring 3
iretq
KeSyscallEntry ENDP
; ---------------------------------------------------------------------------
; Fault stubs - snapshot a full user fault frame before entering C.
;
; For null indirect calls/jumps the CPU reports RIP=0, which is almost useless
; by itself. The captured user RSP lets the C crash dumper read [RSP], which is
; usually the return address immediately after the bad CALL. The GPR snapshot
; also shows which register held the null target.
;
; KeFaultDispatchFrame signature (MS x64):
; KSTATUS KeFaultDispatchFrame(const KFAULT_FRAME* frame) ; rcx
; ---------------------------------------------------------------------------
KFAULT_MAGIC EQU 3146544C5541464Bh ; "KFAULTF1" little-ish
KFAULT_SIZE EQU 0C0h
KF_Magic EQU 000h
KF_Vector EQU 008h
KF_ErrorCode EQU 010h
KF_Cr2 EQU 018h
KF_Rip EQU 020h
KF_Cs EQU 028h
KF_Rflags EQU 030h
KF_Rsp EQU 038h
KF_Ss EQU 040h
KF_Rax EQU 048h
KF_Rcx EQU 050h
KF_Rdx EQU 058h
KF_Rbx EQU 060h
KF_Rbp EQU 068h
KF_Rsi EQU 070h
KF_Rdi EQU 078h
KF_R8 EQU 080h
KF_R9 EQU 088h
KF_R10 EQU 090h
KF_R11 EQU 098h
KF_R12 EQU 0A0h
KF_R13 EQU 0A8h
KF_R14 EQU 0B0h
KF_R15 EQU 0B8h
FAULT_CALL_SHADOW EQU 28h
; ---------------------------------------------------------
; Divide Error (#0) - NO error code pushed by CPU
; User exception frame: [E]=RIP [E+8]=CS [E+16]=RFLAGS [E+24]=RSP [E+32]=SS
; ---------------------------------------------------------
KeFaultDE PROC
push rax ; [rsp+8] after next push = original RAX
push r11 ; [rsp] = original R11
mov r11, rsp ; saved pair; CPU frame starts at [r11+16]
sub rsp, KFAULT_SIZE
mov rax, rsp ; rax = KFAULT_FRAME*
mov [rax + KF_R10], r10
mov r10, KFAULT_MAGIC
mov [rax + KF_Magic], r10
mov qword ptr [rax + KF_Vector], 0
mov qword ptr [rax + KF_ErrorCode], 0
mov qword ptr [rax + KF_Cr2], 0
mov [rax + KF_Rcx], rcx
mov [rax + KF_Rdx], rdx
mov [rax + KF_Rbx], rbx
mov [rax + KF_Rbp], rbp
mov [rax + KF_Rsi], rsi
mov [rax + KF_Rdi], rdi
mov [rax + KF_R8], r8
mov [rax + KF_R9], r9
mov r10, [r11]
mov [rax + KF_R11], r10
mov r10, [r11+8]
mov [rax + KF_Rax], r10
mov [rax + KF_R12], r12
mov [rax + KF_R13], r13
mov [rax + KF_R14], r14
mov [rax + KF_R15], r15
lea rdx, [r11+16]
mov r10, [rdx]
mov [rax + KF_Rip], r10
mov r10, [rdx+8]
mov [rax + KF_Cs], r10
mov r10, [rdx+16]
mov [rax + KF_Rflags], r10
mov r10, [rax + KF_Cs]
test r10, 3
jz de_kernel_frame
mov r10, [rdx+24]
mov [rax + KF_Rsp], r10
mov r10, [rdx+32]
mov [rax + KF_Ss], r10
swapgs
jmp de_call
de_kernel_frame:
lea r10, [rdx+24] ; same-privilege no-error frame has RIP/CS/RFLAGS
mov [rax + KF_Rsp], r10
mov qword ptr [rax + KF_Ss], 0
de_call:
and rsp, -16
sub rsp, FAULT_CALL_SHADOW
mov rcx, rax
call KeFaultDispatchFrame
KeFaultDE ENDP
; ---------------------------------------------------------
; General Protection Fault (#13) - error code pushed by CPU
; User exception frame: [E]=ERR [E+8]=RIP [E+16]=CS [E+24]=RFLAGS [E+32]=RSP [E+40]=SS
; ---------------------------------------------------------
KeFaultGP PROC
push rax
push r11
mov r11, rsp
sub rsp, KFAULT_SIZE
mov rax, rsp
mov [rax + KF_R10], r10
mov r10, KFAULT_MAGIC
mov [rax + KF_Magic], r10
mov qword ptr [rax + KF_Vector], 13
mov qword ptr [rax + KF_Cr2], 0
mov [rax + KF_Rcx], rcx
mov [rax + KF_Rdx], rdx
mov [rax + KF_Rbx], rbx
mov [rax + KF_Rbp], rbp
mov [rax + KF_Rsi], rsi
mov [rax + KF_Rdi], rdi
mov [rax + KF_R8], r8
mov [rax + KF_R9], r9
mov r10, [r11]
mov [rax + KF_R11], r10
mov r10, [r11+8]
mov [rax + KF_Rax], r10
mov [rax + KF_R12], r12
mov [rax + KF_R13], r13
mov [rax + KF_R14], r14
mov [rax + KF_R15], r15
lea rdx, [r11+16]
mov r10, [rdx]
mov [rax + KF_ErrorCode], r10
mov r10, [rdx+8]
mov [rax + KF_Rip], r10
mov r10, [rdx+16]
mov [rax + KF_Cs], r10
mov r10, [rdx+24]
mov [rax + KF_Rflags], r10
mov r10, [rax + KF_Cs]
test r10, 3
jz gp_kernel_frame
mov r10, [rdx+32]
mov [rax + KF_Rsp], r10
mov r10, [rdx+40]
mov [rax + KF_Ss], r10
swapgs
jmp gp_call
gp_kernel_frame:
lea r10, [rdx+32] ; same-privilege fault: original RSP is above ERR/RIP/CS/RFLAGS
mov [rax + KF_Rsp], r10
mov qword ptr [rax + KF_Ss], 0
gp_call:
and rsp, -16
sub rsp, FAULT_CALL_SHADOW
mov rcx, rax
call KeFaultDispatchFrame
KeFaultGP ENDP
; ---------------------------------------------------------
; Page Fault (#14) - error code pushed by CPU
; User exception frame: [E]=ERR [E+8]=RIP [E+16]=CS [E+24]=RFLAGS [E+32]=RSP [E+40]=SS
; ---------------------------------------------------------
KeFaultPF PROC
push rax
push r11
mov r11, rsp
sub rsp, KFAULT_SIZE
mov rax, rsp
mov [rax + KF_R10], r10
mov r10, KFAULT_MAGIC
mov [rax + KF_Magic], r10
mov qword ptr [rax + KF_Vector], 14
mov [rax + KF_Rcx], rcx
mov [rax + KF_Rdx], rdx
mov [rax + KF_Rbx], rbx
mov [rax + KF_Rbp], rbp
mov [rax + KF_Rsi], rsi
mov [rax + KF_Rdi], rdi
mov [rax + KF_R8], r8
mov [rax + KF_R9], r9
mov r10, cr2
mov [rax + KF_Cr2], r10
mov r10, [r11]
mov [rax + KF_R11], r10
mov r10, [r11+8]
mov [rax + KF_Rax], r10
mov [rax + KF_R12], r12
mov [rax + KF_R13], r13
mov [rax + KF_R14], r14
mov [rax + KF_R15], r15
lea rdx, [r11+16]
mov r10, [rdx]
mov [rax + KF_ErrorCode], r10
mov r10, [rdx+8]
mov [rax + KF_Rip], r10
mov r10, [rdx+16]
mov [rax + KF_Cs], r10
mov r10, [rdx+24]
mov [rax + KF_Rflags], r10
mov r10, [rax + KF_Cs]
test r10, 3
jz pf_kernel_frame
mov r10, [rdx+32]
mov [rax + KF_Rsp], r10
mov r10, [rdx+40]
mov [rax + KF_Ss], r10
swapgs
jmp pf_call
pf_kernel_frame:
lea r10, [rdx+32] ; same-privilege #PF frame has ERR/RIP/CS/RFLAGS
mov [rax + KF_Rsp], r10
mov qword ptr [rax + KF_Ss], 0
pf_call:
and rsp, -16
sub rsp, FAULT_CALL_SHADOW
mov rbx, rax ; Keep the KFAULT_FRAME pointer across C.
mov rcx, rax
call KeFaultDispatchFrame
test eax, eax
jnz pf_unhandled_return
mov rdx, rbx ; rdx = KFAULT_FRAME*.
mov rcx, [rdx + KF_Rcx]
mov r8, [rdx + KF_R8]
mov r9, [rdx + KF_R9]
mov rsi, [rdx + KF_Rsi]
mov rdi, [rdx + KF_Rdi]
mov rbp, [rdx + KF_Rbp]
mov r12, [rdx + KF_R12]
mov r13, [rdx + KF_R13]
mov r14, [rdx + KF_R14]
mov r15, [rdx + KF_R15]
mov rbx, [rdx + KF_Rbx]
lea rsp, [rdx + KFAULT_SIZE + 24] ; Skip saved RAX/R11 and the CPU error code.
mov rax, [rdx + KF_Rax]
mov r11, [rdx + KF_R11]
mov r10, [rdx + KF_Cs]
test r10, 3
jz pf_resume_no_swapgs
mov r10, [rdx + KF_R10]
mov rdx, [rdx + KF_Rdx]
swapgs
iretq
pf_resume_no_swapgs:
mov r10, [rdx + KF_R10]
mov rdx, [rdx + KF_Rdx]
iretq
pf_unhandled_return:
cli
pf_unhandled_halt:
hlt
jmp pf_unhandled_halt
KeFaultPF ENDP
; ---------------------------------------------------------
; Generic CPU exception stubs.
; Each vector gets its own IDT entry and vector number so faults like #UD
; do not fall through an absent descriptor and reappear as #GP.
; ---------------------------------------------------------
FAULT_NOERR MACRO StubName, VecNum
LOCAL noerr_kernel_frame, noerr_call
StubName PROC
push rax
push r11
mov r11, rsp
sub rsp, KFAULT_SIZE
mov rax, rsp
mov [rax + KF_R10], r10
mov r10, KFAULT_MAGIC
mov [rax + KF_Magic], r10
mov qword ptr [rax + KF_Vector], VecNum
mov qword ptr [rax + KF_ErrorCode], 0
mov qword ptr [rax + KF_Cr2], 0
mov [rax + KF_Rcx], rcx
mov [rax + KF_Rdx], rdx
mov [rax + KF_Rbx], rbx
mov [rax + KF_Rbp], rbp
mov [rax + KF_Rsi], rsi
mov [rax + KF_Rdi], rdi
mov [rax + KF_R8], r8
mov [rax + KF_R9], r9
mov r10, [r11]
mov [rax + KF_R11], r10
mov r10, [r11+8]
mov [rax + KF_Rax], r10
mov [rax + KF_R12], r12
mov [rax + KF_R13], r13
mov [rax + KF_R14], r14
mov [rax + KF_R15], r15
lea rdx, [r11+16]
mov r10, [rdx]
mov [rax + KF_Rip], r10
mov r10, [rdx+8]
mov [rax + KF_Cs], r10
mov r10, [rdx+16]
mov [rax + KF_Rflags], r10
mov r10, [rax + KF_Cs]
test r10, 3
jz noerr_kernel_frame
mov r10, [rdx+24]
mov [rax + KF_Rsp], r10
mov r10, [rdx+32]
mov [rax + KF_Ss], r10
swapgs
jmp noerr_call
noerr_kernel_frame:
lea r10, [rdx+24] ; same-privilege no-error frame has RIP/CS/RFLAGS
mov [rax + KF_Rsp], r10
mov qword ptr [rax + KF_Ss], 0
noerr_call:
and rsp, -16
sub rsp, FAULT_CALL_SHADOW
mov rcx, rax
call KeFaultDispatchFrame
StubName ENDP
ENDM
FAULT_ERR MACRO StubName, VecNum
LOCAL err_kernel_frame, err_call
StubName PROC
push rax
push r11
mov r11, rsp
sub rsp, KFAULT_SIZE
mov rax, rsp
mov [rax + KF_R10], r10
mov r10, KFAULT_MAGIC
mov [rax + KF_Magic], r10
mov qword ptr [rax + KF_Vector], VecNum
mov qword ptr [rax + KF_Cr2], 0
mov [rax + KF_Rcx], rcx
mov [rax + KF_Rdx], rdx
mov [rax + KF_Rbx], rbx
mov [rax + KF_Rbp], rbp
mov [rax + KF_Rsi], rsi
mov [rax + KF_Rdi], rdi
mov [rax + KF_R8], r8
mov [rax + KF_R9], r9
mov r10, [r11]
mov [rax + KF_R11], r10
mov r10, [r11+8]
mov [rax + KF_Rax], r10
mov [rax + KF_R12], r12
mov [rax + KF_R13], r13
mov [rax + KF_R14], r14
mov [rax + KF_R15], r15
lea rdx, [r11+16]
mov r10, [rdx]
mov [rax + KF_ErrorCode], r10
mov r10, [rdx+8]
mov [rax + KF_Rip], r10
mov r10, [rdx+16]
mov [rax + KF_Cs], r10
mov r10, [rdx+24]
mov [rax + KF_Rflags], r10
mov r10, [rax + KF_Cs]
test r10, 3
jz err_kernel_frame
mov r10, [rdx+32]
mov [rax + KF_Rsp], r10
mov r10, [rdx+40]
mov [rax + KF_Ss], r10
swapgs
jmp err_call
err_kernel_frame:
lea r10, [rdx+32] ; same-privilege error-code frame has ERR/RIP/CS/RFLAGS
mov [rax + KF_Rsp], r10
mov qword ptr [rax + KF_Ss], 0
err_call:
and rsp, -16
sub rsp, FAULT_CALL_SHADOW
mov rcx, rax
call KeFaultDispatchFrame
StubName ENDP
ENDM
EXTERN KeHandleNmiIpi:PROC
PUBLIC KeNmiIpiStub
KeNmiIpiStub PROC
; Returning NMI path for SMP control IPIs. If KeHandleNmiIpi returns 1,
; the NMI was a panic/TLB-control event and is fully handled. If it
; returns 0, restore the interrupted context and fall through to the normal
; #NMI fault stub so unexpected NMIs still panic with a useful frame.
push rax
push rcx
push rdx
push r8
push r9
push r10
push r11
sub rsp, 32
call KeHandleNmiIpi
add rsp, 32
test eax, eax
jz short NmiUnhandled
pop r11
pop r10
pop r9
pop r8
pop rdx
pop rcx
pop rax
iretq
NmiUnhandled:
pop r11
pop r10
pop r9
pop r8
pop rdx
pop rcx
pop rax
jmp KeFaultNMI
KeNmiIpiStub ENDP
FAULT_NOERR KeFaultDB, 1
FAULT_NOERR KeFaultNMI, 2
FAULT_NOERR KeFaultBP, 3
FAULT_NOERR KeFaultOF, 4
FAULT_NOERR KeFaultBR, 5
FAULT_NOERR KeFaultUD, 6
FAULT_NOERR KeFaultNM, 7
FAULT_ERR KeFaultDF, 8
FAULT_NOERR KeFaultCSO, 9
FAULT_ERR KeFaultTS, 10
FAULT_ERR KeFaultNP, 11
FAULT_ERR KeFaultSS, 12
FAULT_NOERR KeFaultRSV15, 15
FAULT_NOERR KeFaultMF, 16
FAULT_ERR KeFaultAC, 17
FAULT_NOERR KeFaultMC, 18
FAULT_NOERR KeFaultXM, 19
FAULT_NOERR KeFaultVE, 20
FAULT_ERR KeFaultCP, 21
FAULT_NOERR KeFaultRSV22, 22
FAULT_NOERR KeFaultRSV23, 23
FAULT_NOERR KeFaultRSV24, 24
FAULT_NOERR KeFaultRSV25, 25
FAULT_NOERR KeFaultRSV26, 26
FAULT_NOERR KeFaultRSV27, 27
FAULT_NOERR KeFaultHV, 28
FAULT_ERR KeFaultVC, 29
FAULT_ERR KeFaultSX, 30
FAULT_NOERR KeFaultRSV31, 31
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
PUBLIC KeRescheduleIpiStub
KeRescheduleIpiStub PROC
push rax
mov al, 0F0h
jmp KeIrqCommon
KeRescheduleIpiStub ENDP
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
; 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
swapgs ; interrupted ring 3: install kernel GS/KCPU
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
mov eax, [rbx + TF_PreviousMode]
cmp eax, KTRAP_MODE_USER
jne short IrqNoSwapGsOut
swapgs ; returning to ring 3: restore user GS/TEB
IrqNoSwapGsOut:
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