mirror of
https://github.com/reactos/reactos.git
synced 2024-10-31 20:02:55 +00:00
8feb078692
It does the same thing, but is one byte shorter.
280 lines
6.5 KiB
PHP
280 lines
6.5 KiB
PHP
/*
|
|
* PROJECT: ReactOS SDK
|
|
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
|
* PURPOSE: ASM macros for x64 trap handling
|
|
* COPYRIGHT: Copyright 2011-2024 Timo Kreuzer (timo.kreuzer@reactos.org)
|
|
*/
|
|
|
|
MACRO(ASSERT_TRAP_FRAME_INTS_ENABLED, Register)
|
|
#if DBG
|
|
LOCAL IntsAreEnabled
|
|
test dword ptr [Register + KTRAP_FRAME_EFlags], HEX(200)
|
|
jnz IntsAreEnabled
|
|
int HEX(2C)
|
|
IntsAreEnabled:
|
|
#endif
|
|
ENDM
|
|
|
|
MACRO(ASSERT_TRAP_FRAME_IRQL_VALID, Register)
|
|
#if DBG
|
|
LOCAL IrqlIsValid
|
|
mov rax, cr8
|
|
cmp byte ptr [Register + KTRAP_FRAME_PreviousIrql], al
|
|
je IrqlIsValid
|
|
int HEX(2C)
|
|
IrqlIsValid:
|
|
#endif
|
|
ENDM
|
|
|
|
MACRO(ASSERT_IRQL_PASSIVE)
|
|
#if DBG
|
|
LOCAL IrqlIsPassive
|
|
mov rax, cr8
|
|
test rax, rax
|
|
jz IrqlIsPassive
|
|
int HEX(2C)
|
|
IrqlIsPassive:
|
|
#endif
|
|
ENDM
|
|
|
|
// Checks for user APCs and delivers them if necessary.
|
|
// Clobbers all volatile registers except rax.
|
|
MACRO(HANDLE_USER_APCS, ThreadReg, TrapFrame)
|
|
LOCAL NoUserApcPending
|
|
|
|
/* Check for pending user APC */
|
|
cmp byte ptr [ThreadReg + ThApcState + AsUserApcPending], 0
|
|
jz NoUserApcPending
|
|
lea rcx, [TrapFrame]
|
|
call KiInitiateUserApc
|
|
NoUserApcPending:
|
|
ENDM
|
|
|
|
APIC_EOI = HEX(0FFFFFFFFFFFE00B0)
|
|
|
|
TF_SEGMENTS = HEX(08)
|
|
TF_DEBUG = HEX(10)
|
|
TF_IRQL = HEX(20)
|
|
TF_SAVE_ALL = (TF_SEGMENTS)
|
|
TF_HAS_ERROR_CODE = HEX(40)
|
|
TF_SEND_EOI = HEX(80)
|
|
//TF_SYSTEMSERVICE = (TRAPFLAG_VOLATILES or TRAPFLAG_DEBUG)
|
|
TF_CHECKUSERAPC = HEX(100)
|
|
|
|
/*
|
|
* Stack Layout:
|
|
* |-------------------|
|
|
* | KTRAP_FRAME |
|
|
* |-------------------| <- rbp
|
|
* | EXCEPTION_RECORD |
|
|
* |-------------------|
|
|
* | KEXCEPTION_FRAME |
|
|
* |-------------------| <- rsp
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* EnterTrap - Allocate KTRAP_FRAME_LENGTH and save registers to it
|
|
*/
|
|
MACRO(EnterTrap, Flags)
|
|
LOCAL kernel_mode_entry
|
|
|
|
/* Save the trap flags for this trap */
|
|
CurrentTrapFlags = VAL(Flags)
|
|
|
|
/* Size of hardware trap frame */
|
|
if (Flags AND TF_HAS_ERROR_CODE)
|
|
.pushframe code
|
|
SIZE_INITIAL_FRAME = 6 * 8
|
|
else
|
|
.pushframe
|
|
SIZE_INITIAL_FRAME = 5 * 8
|
|
endif
|
|
|
|
/* Make room for a KTRAP_FRAME */
|
|
sub rsp, (KTRAP_FRAME_LENGTH - SIZE_INITIAL_FRAME)
|
|
.allocstack (KTRAP_FRAME_LENGTH - SIZE_INITIAL_FRAME)
|
|
|
|
/* Save rbp */
|
|
mov [rsp + KTRAP_FRAME_Rbp], rbp
|
|
.savereg rbp, KTRAP_FRAME_Rbp
|
|
|
|
/* Point rbp to the KTRAP_FRAME */
|
|
lea rbp, [rsp]
|
|
.setframe rbp, 0
|
|
|
|
.endprolog
|
|
|
|
/* Save volatile registers */
|
|
mov [rbp + KTRAP_FRAME_Rax], rax
|
|
mov [rbp + KTRAP_FRAME_Rcx], rcx
|
|
mov [rbp + KTRAP_FRAME_Rdx], rdx
|
|
mov [rbp + KTRAP_FRAME_R8], r8
|
|
mov [rbp + KTRAP_FRAME_R9], r9
|
|
mov [rbp + KTRAP_FRAME_R10], r10
|
|
mov [rbp + KTRAP_FRAME_R11], r11
|
|
|
|
/* Save volatile xmm registers */
|
|
movaps [rbp + KTRAP_FRAME_Xmm0], xmm0
|
|
movaps [rbp + KTRAP_FRAME_Xmm1], xmm1
|
|
movaps [rbp + KTRAP_FRAME_Xmm2], xmm2
|
|
movaps [rbp + KTRAP_FRAME_Xmm3], xmm3
|
|
movaps [rbp + KTRAP_FRAME_Xmm4], xmm4
|
|
movaps [rbp + KTRAP_FRAME_Xmm5], xmm5
|
|
|
|
if (Flags AND TF_SEGMENTS)
|
|
/* Save segment selectors */
|
|
mov [rbp + KTRAP_FRAME_SegDs], ds
|
|
mov [rbp + KTRAP_FRAME_SegEs], es
|
|
mov [rbp + KTRAP_FRAME_SegFs], fs
|
|
mov [rbp + KTRAP_FRAME_SegGs], gs
|
|
endif
|
|
|
|
/* Save MCXSR */
|
|
stmxcsr [rbp + KTRAP_FRAME_MxCsr]
|
|
|
|
#if DBG
|
|
mov ecx, MSR_GS_BASE
|
|
rdmsr
|
|
mov [rbp + KTRAP_FRAME_GsBase], eax
|
|
mov [rbp + KTRAP_FRAME_GsBase + 4], edx
|
|
#endif
|
|
|
|
/* Save previous mode and check if it was user mode */
|
|
mov ax, [rbp + KTRAP_FRAME_SegCs]
|
|
and al, 1
|
|
mov [rbp + KTRAP_FRAME_PreviousMode], al
|
|
jz kernel_mode_entry
|
|
|
|
/* Set sane segments */
|
|
mov ax, (KGDT64_R3_DATA or RPL_MASK)
|
|
mov ds, ax
|
|
mov es, ax
|
|
swapgs
|
|
|
|
/* Load kernel MXCSR */
|
|
ldmxcsr gs:[PcMxCsr]
|
|
|
|
ASSERT_IRQL_PASSIVE
|
|
|
|
kernel_mode_entry:
|
|
|
|
// if (Flags AND TF_IRQL)
|
|
/* Save previous irql */
|
|
mov rax, cr8
|
|
mov [rbp + KTRAP_FRAME_PreviousIrql], al
|
|
// endif
|
|
|
|
if (Flags AND TF_DEBUG)
|
|
/* Save debug registers */
|
|
mov rax, dr0
|
|
mov [rbp + KTRAP_FRAME_Dr0], rax
|
|
mov rax, dr1
|
|
mov [rbp + KTRAP_FRAME_Dr1], rax
|
|
mov rax, dr2
|
|
mov [rbp + KTRAP_FRAME_Dr2], rax
|
|
mov rax, dr3
|
|
mov [rbp + KTRAP_FRAME_Dr3], rax
|
|
mov rax, dr6
|
|
mov [rbp + KTRAP_FRAME_Dr6], rax
|
|
mov rax, dr7
|
|
mov [rbp + KTRAP_FRAME_Dr7], rax
|
|
endif
|
|
|
|
/* Make sure the direction flag is cleared */
|
|
cld
|
|
ENDM
|
|
|
|
/*
|
|
* ExitTrap - Restore registers and free stack space
|
|
*/
|
|
MACRO(ExitTrap, Flags)
|
|
LOCAL kernel_mode_return
|
|
|
|
ASSERT_TRAP_FRAME_IRQL_VALID rbp
|
|
|
|
if (Flags AND TF_SEGMENTS)
|
|
/* Restore segment selectors */
|
|
mov ds, [rbp + KTRAP_FRAME_SegDs]
|
|
mov es, [rbp + KTRAP_FRAME_SegEs]
|
|
mov fs, [rbp + KTRAP_FRAME_SegFs]
|
|
endif
|
|
|
|
if (Flags AND TF_IRQL)
|
|
/* Restore previous irql */
|
|
movzx rax, byte ptr [rbp + KTRAP_FRAME_PreviousIrql]
|
|
mov cr8, rax
|
|
endif
|
|
|
|
/* Check if we came from user mode */
|
|
test byte ptr [rbp + KTRAP_FRAME_SegCs], 1
|
|
jz kernel_mode_return
|
|
|
|
if (Flags AND TF_CHECKUSERAPC)
|
|
mov r10, gs:[PcCurrentThread]
|
|
HANDLE_USER_APCS r10, rbp
|
|
endif
|
|
|
|
ASSERT_TRAP_FRAME_INTS_ENABLED rbp
|
|
ASSERT_IRQL_PASSIVE
|
|
|
|
cli
|
|
|
|
/* Swap gs to user mode */
|
|
swapgs
|
|
|
|
kernel_mode_return:
|
|
|
|
/* Restore volatile registers */
|
|
mov rax, [rbp + KTRAP_FRAME_Rax]
|
|
mov rcx, [rbp + KTRAP_FRAME_Rcx]
|
|
mov rdx, [rbp + KTRAP_FRAME_Rdx]
|
|
mov r8, [rbp + KTRAP_FRAME_R8]
|
|
mov r9, [rbp + KTRAP_FRAME_R9]
|
|
mov r10, [rbp + KTRAP_FRAME_R10]
|
|
mov r11, [rbp + KTRAP_FRAME_R11]
|
|
|
|
/* Restore xmm registers */
|
|
movaps xmm0, [rbp + KTRAP_FRAME_Xmm0]
|
|
movaps xmm1, [rbp + KTRAP_FRAME_Xmm1]
|
|
movaps xmm2, [rbp + KTRAP_FRAME_Xmm2]
|
|
movaps xmm3, [rbp + KTRAP_FRAME_Xmm3]
|
|
movaps xmm4, [rbp + KTRAP_FRAME_Xmm4]
|
|
movaps xmm5, [rbp + KTRAP_FRAME_Xmm5]
|
|
|
|
/* Restore MCXSR */
|
|
ldmxcsr [rbp + KTRAP_FRAME_MxCsr]
|
|
|
|
/* Restore rbp */
|
|
mov rbp, [rbp + KTRAP_FRAME_Rbp]
|
|
|
|
/* Adjust stack pointer */
|
|
add rsp, KTRAP_FRAME_Rip
|
|
|
|
if (Flags AND TF_SEND_EOI)
|
|
/* Write 0 to the local APIC EOI register */
|
|
mov dword ptr [APIC_EOI], 0
|
|
endif
|
|
|
|
/* Return from the trap */
|
|
iretq
|
|
ENDM
|
|
|
|
|
|
MACRO(TRAP_ENTRY, Trap, Flags)
|
|
EXTERN Trap&Handler :PROC
|
|
PUBLIC &Trap
|
|
FUNC &Trap
|
|
/* Common code to create the trap frame */
|
|
EnterTrap Flags
|
|
|
|
/* Call the C handler */
|
|
mov rcx, rbp
|
|
call Trap&Handler
|
|
|
|
/* Leave */
|
|
ExitTrap Flags
|
|
ENDFUNC
|
|
ENDM
|
|
|