Reactos
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