xref: /reactos/sdk/include/asm/trapamd64.inc (revision 9452b29c)
1/*
2 * PROJECT:     ReactOS SDK
3 * LICENSE:     MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE:     ASM macros for x64 trap handling
5 * COPYRIGHT:   Copyright 2011-2024 Timo Kreuzer (timo.kreuzer@reactos.org)
6 */
7
8MACRO(ASSERT_TRAP_FRAME_INTS_ENABLED, Register)
9#if DBG
10    LOCAL IntsAreEnabled
11    test dword ptr [Register + KTRAP_FRAME_EFlags], HEX(200)
12    jnz IntsAreEnabled
13    int HEX(2C)
14IntsAreEnabled:
15#endif
16ENDM
17
18MACRO(ASSERT_TRAP_FRAME_IRQL_VALID, Register)
19#if DBG
20    LOCAL IrqlIsValid
21    mov rax, cr8
22    cmp byte ptr [Register + KTRAP_FRAME_PreviousIrql], al
23    je IrqlIsValid
24    int HEX(2C)
25IrqlIsValid:
26#endif
27ENDM
28
29MACRO(ASSERT_IRQL_PASSIVE)
30#if DBG
31    LOCAL IrqlIsPassive
32    mov rax, cr8
33    test rax, rax
34    jz IrqlIsPassive
35    int HEX(2C)
36IrqlIsPassive:
37#endif
38ENDM
39
40// Checks for user APCs and delivers them if necessary.
41// Clobbers all volatile registers except rax.
42MACRO(HANDLE_USER_APCS, ThreadReg, TrapFrame)
43    LOCAL NoUserApcPending
44
45    /* Check for pending user APC */
46    cmp byte ptr [ThreadReg + ThApcState + AsUserApcPending], 0
47    jz NoUserApcPending
48    lea rcx, [TrapFrame]
49    call KiInitiateUserApc
50NoUserApcPending:
51ENDM
52
53APIC_EOI = HEX(0FFFFFFFFFFFE00B0)
54
55TF_SEGMENTS             = HEX(08)
56TF_DEBUG                = HEX(10)
57TF_IRQL                 = HEX(20)
58TF_SAVE_ALL             = (TF_SEGMENTS)
59TF_HAS_ERROR_CODE       = HEX(40)
60TF_SEND_EOI             = HEX(80)
61//TF_SYSTEMSERVICE        = (TRAPFLAG_VOLATILES or TRAPFLAG_DEBUG)
62TF_CHECKUSERAPC         = HEX(100)
63
64/*
65 * Stack Layout:
66 * |-------------------|
67 * | KTRAP_FRAME       |
68 * |-------------------| <- rbp
69 * | EXCEPTION_RECORD  |
70 * |-------------------|
71 * | KEXCEPTION_FRAME  |
72 * |-------------------| <- rsp
73 *
74 */
75
76/*
77 * EnterTrap - Allocate KTRAP_FRAME_LENGTH and save registers to it
78 */
79MACRO(EnterTrap, Flags)
80    LOCAL kernel_mode_entry
81
82    /* Save the trap flags for this trap */
83    CurrentTrapFlags = VAL(Flags)
84
85    /* Size of hardware trap frame */
86    if (Flags AND TF_HAS_ERROR_CODE)
87        .pushframe code
88        SIZE_INITIAL_FRAME = 6 * 8
89    else
90        .pushframe
91        SIZE_INITIAL_FRAME = 5 * 8
92    endif
93
94    /* Make room for a KTRAP_FRAME */
95    sub rsp, (KTRAP_FRAME_LENGTH - SIZE_INITIAL_FRAME)
96    .allocstack (KTRAP_FRAME_LENGTH - SIZE_INITIAL_FRAME)
97
98    /* Save rbp */
99    mov [rsp + KTRAP_FRAME_Rbp], rbp
100    .savereg rbp, KTRAP_FRAME_Rbp
101
102    /* Point rbp to the KTRAP_FRAME */
103    lea rbp, [rsp]
104    .setframe rbp, 0
105
106    .endprolog
107
108    /* Save volatile registers */
109    mov [rbp + KTRAP_FRAME_Rax], rax
110    mov [rbp + KTRAP_FRAME_Rcx], rcx
111    mov [rbp + KTRAP_FRAME_Rdx], rdx
112    mov [rbp + KTRAP_FRAME_R8], r8
113    mov [rbp + KTRAP_FRAME_R9], r9
114    mov [rbp + KTRAP_FRAME_R10], r10
115    mov [rbp + KTRAP_FRAME_R11], r11
116
117    /* Save volatile xmm registers */
118    movaps [rbp + KTRAP_FRAME_Xmm0], xmm0
119    movaps [rbp + KTRAP_FRAME_Xmm1], xmm1
120    movaps [rbp + KTRAP_FRAME_Xmm2], xmm2
121    movaps [rbp + KTRAP_FRAME_Xmm3], xmm3
122    movaps [rbp + KTRAP_FRAME_Xmm4], xmm4
123    movaps [rbp + KTRAP_FRAME_Xmm5], xmm5
124
125    if (Flags AND TF_SEGMENTS)
126        /* Save segment selectors */
127        mov [rbp + KTRAP_FRAME_SegDs], ds
128        mov [rbp + KTRAP_FRAME_SegEs], es
129        mov [rbp + KTRAP_FRAME_SegFs], fs
130        mov [rbp + KTRAP_FRAME_SegGs], gs
131    endif
132
133    /* Save MCXSR */
134    stmxcsr [rbp + KTRAP_FRAME_MxCsr]
135
136#if DBG
137    mov ecx, MSR_GS_BASE
138    rdmsr
139    mov [rbp + KTRAP_FRAME_GsBase], eax
140    mov [rbp + KTRAP_FRAME_GsBase + 4], edx
141#endif
142
143    /* Save previous mode and check if it was user mode */
144    mov ax, [rbp + KTRAP_FRAME_SegCs]
145    and al, 1
146    mov [rbp + KTRAP_FRAME_PreviousMode], al
147    jz kernel_mode_entry
148
149    /* Set sane segments */
150    mov ax, (KGDT64_R3_DATA or RPL_MASK)
151    mov ds, ax
152    mov es, ax
153    swapgs
154
155    /* Load kernel MXCSR */
156    ldmxcsr gs:[PcMxCsr]
157
158    ASSERT_IRQL_PASSIVE
159
160kernel_mode_entry:
161
162//    if (Flags AND TF_IRQL)
163        /* Save previous irql */
164        mov rax, cr8
165        mov [rbp + KTRAP_FRAME_PreviousIrql], al
166//    endif
167
168    if (Flags AND TF_DEBUG)
169        /* Save debug registers */
170        mov rax, dr0
171        mov [rbp + KTRAP_FRAME_Dr0], rax
172        mov rax, dr1
173        mov [rbp + KTRAP_FRAME_Dr1], rax
174        mov rax, dr2
175        mov [rbp + KTRAP_FRAME_Dr2], rax
176        mov rax, dr3
177        mov [rbp + KTRAP_FRAME_Dr3], rax
178        mov rax, dr6
179        mov [rbp + KTRAP_FRAME_Dr6], rax
180        mov rax, dr7
181        mov [rbp + KTRAP_FRAME_Dr7], rax
182    endif
183
184    /* Make sure the direction flag is cleared */
185    cld
186ENDM
187
188/*
189 *  ExitTrap - Restore registers and free stack space
190 */
191MACRO(ExitTrap, Flags)
192    LOCAL kernel_mode_return
193
194    ASSERT_TRAP_FRAME_IRQL_VALID rbp
195
196    if (Flags AND TF_SEGMENTS)
197        /* Restore segment selectors */
198        mov ds, [rbp + KTRAP_FRAME_SegDs]
199        mov es, [rbp + KTRAP_FRAME_SegEs]
200        mov fs, [rbp + KTRAP_FRAME_SegFs]
201    endif
202
203    if (Flags AND TF_IRQL)
204        /* Restore previous irql */
205        movzx rax, byte ptr [rbp + KTRAP_FRAME_PreviousIrql]
206        mov cr8, rax
207    endif
208
209    /* Check if we came from user mode */
210    test byte ptr [rbp + KTRAP_FRAME_SegCs], 1
211    jz kernel_mode_return
212
213    if (Flags AND TF_CHECKUSERAPC)
214        mov r10, gs:[PcCurrentThread]
215        HANDLE_USER_APCS r10, rbp
216    endif
217
218    ASSERT_TRAP_FRAME_INTS_ENABLED rbp
219    ASSERT_IRQL_PASSIVE
220
221    cli
222
223    /* Swap gs to user mode */
224    swapgs
225
226kernel_mode_return:
227
228    /* Restore volatile registers */
229    mov rax, [rbp + KTRAP_FRAME_Rax]
230    mov rcx, [rbp + KTRAP_FRAME_Rcx]
231    mov rdx, [rbp + KTRAP_FRAME_Rdx]
232    mov r8, [rbp + KTRAP_FRAME_R8]
233    mov r9, [rbp + KTRAP_FRAME_R9]
234    mov r10, [rbp + KTRAP_FRAME_R10]
235    mov r11, [rbp + KTRAP_FRAME_R11]
236
237    /* Restore xmm registers */
238    movaps xmm0, [rbp + KTRAP_FRAME_Xmm0]
239    movaps xmm1, [rbp + KTRAP_FRAME_Xmm1]
240    movaps xmm2, [rbp + KTRAP_FRAME_Xmm2]
241    movaps xmm3, [rbp + KTRAP_FRAME_Xmm3]
242    movaps xmm4, [rbp + KTRAP_FRAME_Xmm4]
243    movaps xmm5, [rbp + KTRAP_FRAME_Xmm5]
244
245    /* Restore MCXSR */
246    ldmxcsr [rbp + KTRAP_FRAME_MxCsr]
247
248    /* Restore rbp */
249    mov rbp, [rbp + KTRAP_FRAME_Rbp]
250
251    /* Adjust stack pointer */
252    add rsp, KTRAP_FRAME_Rip
253
254    if (Flags AND TF_SEND_EOI)
255        /* Write 0 to the local APIC EOI register */
256        mov dword ptr [APIC_EOI], 0
257    endif
258
259    /* Return from the trap */
260    iretq
261ENDM
262
263
264MACRO(TRAP_ENTRY, Trap, Flags)
265    EXTERN Trap&Handler :PROC
266    PUBLIC &Trap
267    FUNC &Trap
268        /* Common code to create the trap frame */
269        EnterTrap Flags
270
271        /* Call the C handler */
272        mov rcx, rbp
273        call Trap&Handler
274
275        /* Leave */
276        ExitTrap Flags
277    ENDFUNC
278ENDM
279
280