1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/include/internal/i386/trap_x.h
5 * PURPOSE: Internal Inlined Functions for the Trap Handling Code
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 #pragma once
10
11 #if defined(_MSC_VER)
12 #define __builtin_expect(a,b) (a)
13 #endif
14
15 //
16 // Helper Code
17 //
18 FORCEINLINE
19 BOOLEAN
KiUserTrap(IN PKTRAP_FRAME TrapFrame)20 KiUserTrap(IN PKTRAP_FRAME TrapFrame)
21 {
22 /* Anything else but Ring 0 is Ring 3 */
23 return !!(TrapFrame->SegCs & MODE_MASK);
24 }
25
26 //
27 // Debug Macros
28 //
29 FORCEINLINE
30 VOID
KiDumpTrapFrame(IN PKTRAP_FRAME TrapFrame)31 KiDumpTrapFrame(IN PKTRAP_FRAME TrapFrame)
32 {
33 /* Dump the whole thing */
34 DbgPrint("DbgEbp: %x\n", TrapFrame->DbgEbp);
35 DbgPrint("DbgEip: %x\n", TrapFrame->DbgEip);
36 DbgPrint("DbgArgMark: %x\n", TrapFrame->DbgArgMark);
37 DbgPrint("DbgArgPointer: %x\n", TrapFrame->DbgArgPointer);
38 DbgPrint("TempSegCs: %x\n", TrapFrame->TempSegCs);
39 DbgPrint("TempEsp: %x\n", TrapFrame->TempEsp);
40 DbgPrint("Dr0: %x\n", TrapFrame->Dr0);
41 DbgPrint("Dr1: %x\n", TrapFrame->Dr1);
42 DbgPrint("Dr2: %x\n", TrapFrame->Dr2);
43 DbgPrint("Dr3: %x\n", TrapFrame->Dr3);
44 DbgPrint("Dr6: %x\n", TrapFrame->Dr6);
45 DbgPrint("Dr7: %x\n", TrapFrame->Dr7);
46 DbgPrint("SegGs: %x\n", TrapFrame->SegGs);
47 DbgPrint("SegEs: %x\n", TrapFrame->SegEs);
48 DbgPrint("SegDs: %x\n", TrapFrame->SegDs);
49 DbgPrint("Edx: %x\n", TrapFrame->Edx);
50 DbgPrint("Ecx: %x\n", TrapFrame->Ecx);
51 DbgPrint("Eax: %x\n", TrapFrame->Eax);
52 DbgPrint("PreviousPreviousMode: %x\n", TrapFrame->PreviousPreviousMode);
53 DbgPrint("ExceptionList: %p\n", TrapFrame->ExceptionList);
54 DbgPrint("SegFs: %x\n", TrapFrame->SegFs);
55 DbgPrint("Edi: %x\n", TrapFrame->Edi);
56 DbgPrint("Esi: %x\n", TrapFrame->Esi);
57 DbgPrint("Ebx: %x\n", TrapFrame->Ebx);
58 DbgPrint("Ebp: %x\n", TrapFrame->Ebp);
59 DbgPrint("ErrCode: %x\n", TrapFrame->ErrCode);
60 DbgPrint("Eip: %x\n", TrapFrame->Eip);
61 DbgPrint("SegCs: %x\n", TrapFrame->SegCs);
62 DbgPrint("EFlags: %x\n", TrapFrame->EFlags);
63 DbgPrint("HardwareEsp: %x\n", TrapFrame->HardwareEsp);
64 DbgPrint("HardwareSegSs: %x\n", TrapFrame->HardwareSegSs);
65 DbgPrint("V86Es: %x\n", TrapFrame->V86Es);
66 DbgPrint("V86Ds: %x\n", TrapFrame->V86Ds);
67 DbgPrint("V86Fs: %x\n", TrapFrame->V86Fs);
68 DbgPrint("V86Gs: %x\n", TrapFrame->V86Gs);
69 }
70
71 #if DBG
72 FORCEINLINE
73 VOID
KiFillTrapFrameDebug(IN PKTRAP_FRAME TrapFrame)74 KiFillTrapFrameDebug(IN PKTRAP_FRAME TrapFrame)
75 {
76 /* Set the debug information */
77 TrapFrame->DbgArgPointer = TrapFrame->Edx;
78 TrapFrame->DbgArgMark = 0xBADB0D00;
79 TrapFrame->DbgEip = TrapFrame->Eip;
80 TrapFrame->DbgEbp = TrapFrame->Ebp;
81 TrapFrame->PreviousPreviousMode = (ULONG)-1;
82 }
83
84 #define DR7_RESERVED_READ_AS_1 0x400
85
86 #define CheckDr(DrNumner, ExpectedValue) \
87 { \
88 ULONG DrValue = __readdr(DrNumner); \
89 if (DrValue != (ExpectedValue)) \
90 { \
91 DbgPrint("Dr%ld: expected %.8lx, got %.8lx\n", \
92 DrNumner, ExpectedValue, DrValue); \
93 __debugbreak(); \
94 } \
95 }
96
97 extern BOOLEAN StopChecking;
98
99 FORCEINLINE
100 VOID
KiExitTrapDebugChecks(IN PKTRAP_FRAME TrapFrame,IN BOOLEAN SkipPreviousMode)101 KiExitTrapDebugChecks(IN PKTRAP_FRAME TrapFrame,
102 IN BOOLEAN SkipPreviousMode)
103 {
104 /* Don't check recursively */
105 if (StopChecking) return;
106 StopChecking = TRUE;
107
108 /* Make sure interrupts are disabled */
109 if (__readeflags() & EFLAGS_INTERRUPT_MASK)
110 {
111 DbgPrint("Exiting with interrupts enabled: %lx\n", __readeflags());
112 __debugbreak();
113 }
114
115 /* Make sure this is a real trap frame */
116 if (TrapFrame->DbgArgMark != 0xBADB0D00)
117 {
118 DbgPrint("Exiting with an invalid trap frame? (No MAGIC in trap frame)\n");
119 KiDumpTrapFrame(TrapFrame);
120 __debugbreak();
121 }
122
123 /* Make sure we're not in user-mode or something */
124 if (Ke386GetFs() != KGDT_R0_PCR)
125 {
126 DbgPrint("Exiting with an invalid FS: %lx\n", Ke386GetFs());
127 __debugbreak();
128 }
129
130 /* Make sure we have a valid SEH chain */
131 if (KeGetPcr()->NtTib.ExceptionList == 0)
132 {
133 DbgPrint("Exiting with NULL exception chain: %p\n", KeGetPcr()->NtTib.ExceptionList);
134 __debugbreak();
135 }
136
137 /* Make sure we're restoring a valid SEH chain */
138 if (TrapFrame->ExceptionList == 0)
139 {
140 DbgPrint("Entered a trap with a NULL exception chain: %p\n", TrapFrame->ExceptionList);
141 __debugbreak();
142 }
143
144 /* If we're ignoring previous mode, make sure caller doesn't actually want it */
145 if (SkipPreviousMode && (TrapFrame->PreviousPreviousMode != (ULONG)-1))
146 {
147 DbgPrint("Exiting a trap witout restoring previous mode, yet previous mode seems valid: %lx\n", TrapFrame->PreviousPreviousMode);
148 __debugbreak();
149 }
150
151 /* FIXME: KDBG messes around with these improperly */
152 #if !defined(KDBG)
153 /* Check DR values */
154 if (KiUserTrap(TrapFrame))
155 {
156 /* Check for active debugging */
157 if (KeGetCurrentThread()->Header.DebugActive)
158 {
159 if ((TrapFrame->Dr7 & ~DR7_RESERVED_MASK) == 0) __debugbreak();
160
161 CheckDr(0, TrapFrame->Dr0);
162 CheckDr(1, TrapFrame->Dr1);
163 CheckDr(2, TrapFrame->Dr2);
164 CheckDr(3, TrapFrame->Dr3);
165 CheckDr(7, TrapFrame->Dr7 | DR7_RESERVED_READ_AS_1);
166 }
167 }
168 else
169 {
170 PKPRCB Prcb = KeGetCurrentPrcb();
171 CheckDr(0, Prcb->ProcessorState.SpecialRegisters.KernelDr0);
172 CheckDr(1, Prcb->ProcessorState.SpecialRegisters.KernelDr1);
173 CheckDr(2, Prcb->ProcessorState.SpecialRegisters.KernelDr2);
174 CheckDr(3, Prcb->ProcessorState.SpecialRegisters.KernelDr3);
175 // CheckDr(7, Prcb->ProcessorState.SpecialRegisters.KernelDr7); // Disabled, see CORE-10165 for more details.
176 }
177 #endif
178
179 StopChecking = FALSE;
180 }
181
182 #else
183 #define KiExitTrapDebugChecks(x, y)
184 #define KiFillTrapFrameDebug(x)
185 #endif
186
187 FORCEINLINE
188 VOID
KiExitSystemCallDebugChecks(IN ULONG SystemCall,IN PKTRAP_FRAME TrapFrame)189 KiExitSystemCallDebugChecks(IN ULONG SystemCall,
190 IN PKTRAP_FRAME TrapFrame)
191 {
192 KIRQL OldIrql;
193
194 /* Check if this was a user call */
195 if (KiUserTrap(TrapFrame))
196 {
197 /* Make sure we are not returning with elevated IRQL */
198 OldIrql = KeGetCurrentIrql();
199 if (OldIrql != PASSIVE_LEVEL)
200 {
201 /* Forcibly put us in a sane state */
202 KeGetPcr()->Irql = PASSIVE_LEVEL;
203 _disable();
204
205 /* Fail */
206 KeBugCheckEx(IRQL_GT_ZERO_AT_SYSTEM_SERVICE,
207 SystemCall,
208 OldIrql,
209 0,
210 0);
211 }
212
213 /* Make sure we're not attached and that APCs are not disabled */
214 if ((KeGetCurrentThread()->ApcStateIndex != OriginalApcEnvironment) ||
215 (KeGetCurrentThread()->CombinedApcDisable != 0))
216 {
217 /* Fail */
218 KeBugCheckEx(APC_INDEX_MISMATCH,
219 SystemCall,
220 KeGetCurrentThread()->ApcStateIndex,
221 KeGetCurrentThread()->CombinedApcDisable,
222 0);
223 }
224 }
225 }
226
227 //
228 // Generic Exit Routine
229 //
230 DECLSPEC_NORETURN VOID FASTCALL KiSystemCallReturn(IN PKTRAP_FRAME TrapFrame);
231 DECLSPEC_NORETURN VOID FASTCALL KiSystemCallSysExitReturn(IN PKTRAP_FRAME TrapFrame);
232 DECLSPEC_NORETURN VOID FASTCALL KiSystemCallTrapReturn(IN PKTRAP_FRAME TrapFrame);
233 DECLSPEC_NORETURN VOID FASTCALL KiEditedTrapReturn(IN PKTRAP_FRAME TrapFrame);
234 DECLSPEC_NORETURN VOID FASTCALL KiTrapReturn(IN PKTRAP_FRAME TrapFrame);
235 DECLSPEC_NORETURN VOID FASTCALL KiTrapReturnNoSegments(IN PKTRAP_FRAME TrapFrame);
236 DECLSPEC_NORETURN VOID FASTCALL KiTrapReturnNoSegmentsRet8(IN PKTRAP_FRAME TrapFrame);
237
238 typedef
239 VOID
240 (FASTCALL *PFAST_SYSTEM_CALL_EXIT)(
241 IN PKTRAP_FRAME TrapFrame
242 );
243
244 extern PFAST_SYSTEM_CALL_EXIT KiFastCallExitHandler;
245
246 //
247 // Save user mode debug registers and restore kernel values
248 //
249 FORCEINLINE
250 VOID
KiHandleDebugRegistersOnTrapEntry(IN PKTRAP_FRAME TrapFrame)251 KiHandleDebugRegistersOnTrapEntry(
252 IN PKTRAP_FRAME TrapFrame)
253 {
254 PKPRCB Prcb = KeGetCurrentPrcb();
255
256 /* Save all debug registers in the trap frame */
257 TrapFrame->Dr0 = __readdr(0);
258 TrapFrame->Dr1 = __readdr(1);
259 TrapFrame->Dr2 = __readdr(2);
260 TrapFrame->Dr3 = __readdr(3);
261 TrapFrame->Dr6 = __readdr(6);
262 TrapFrame->Dr7 = __readdr(7);
263
264 /* Disable all active debugging */
265 __writedr(7, 0);
266
267 /* Restore kernel values */
268 __writedr(0, Prcb->ProcessorState.SpecialRegisters.KernelDr0);
269 __writedr(1, Prcb->ProcessorState.SpecialRegisters.KernelDr1);
270 __writedr(2, Prcb->ProcessorState.SpecialRegisters.KernelDr2);
271 __writedr(3, Prcb->ProcessorState.SpecialRegisters.KernelDr3);
272 __writedr(6, Prcb->ProcessorState.SpecialRegisters.KernelDr6);
273 __writedr(7, Prcb->ProcessorState.SpecialRegisters.KernelDr7);
274 }
275
276 FORCEINLINE
277 VOID
KiHandleDebugRegistersOnTrapExit(PKTRAP_FRAME TrapFrame)278 KiHandleDebugRegistersOnTrapExit(
279 PKTRAP_FRAME TrapFrame)
280 {
281 /* Disable all active debugging */
282 __writedr(7, 0);
283
284 /* Load all debug registers from the trap frame */
285 __writedr(0, TrapFrame->Dr0);
286 __writedr(1, TrapFrame->Dr1);
287 __writedr(2, TrapFrame->Dr2);
288 __writedr(3, TrapFrame->Dr3);
289 __writedr(6, TrapFrame->Dr6);
290 __writedr(7, TrapFrame->Dr7);
291 }
292
293 //
294 // Virtual 8086 Mode Optimized Trap Exit
295 //
296 FORCEINLINE
297 DECLSPEC_NORETURN
298 VOID
KiExitV86Trap(IN PKTRAP_FRAME TrapFrame)299 KiExitV86Trap(IN PKTRAP_FRAME TrapFrame)
300 {
301 PKTHREAD Thread;
302 KIRQL OldIrql;
303
304 /* Get the thread */
305 Thread = KeGetCurrentThread();
306 while (TRUE)
307 {
308 /* Return if this isn't V86 mode anymore */
309 if (!(TrapFrame->EFlags & EFLAGS_V86_MASK)) KiEoiHelper(TrapFrame);
310
311 /* Turn off the alerted state for kernel mode */
312 Thread->Alerted[KernelMode] = FALSE;
313
314 /* Are there pending user APCs? */
315 if (__builtin_expect(!Thread->ApcState.UserApcPending, 1)) break;
316
317 /* Raise to APC level and enable interrupts */
318 OldIrql = KfRaiseIrql(APC_LEVEL);
319 _enable();
320
321 /* Deliver APCs */
322 KiDeliverApc(UserMode, NULL, TrapFrame);
323
324 /* Restore IRQL and disable interrupts once again */
325 KfLowerIrql(OldIrql);
326 _disable();
327 }
328
329 /* If we got here, we're still in a valid V8086 context, so quit it */
330 if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0))
331 {
332 /* Restore debug registers from the trap frame */
333 KiHandleDebugRegistersOnTrapExit(TrapFrame);
334 }
335
336 /* Return from interrupt */
337 KiTrapReturnNoSegments(TrapFrame);
338 }
339
340 //
341 // Virtual 8086 Mode Optimized Trap Entry
342 //
343 FORCEINLINE
344 VOID
KiEnterV86Trap(IN PKTRAP_FRAME TrapFrame)345 KiEnterV86Trap(IN PKTRAP_FRAME TrapFrame)
346 {
347 PVOID ExceptionList;
348
349 /* Check exception list */
350 ExceptionList = KeGetPcr()->NtTib.ExceptionList;
351 ASSERTMSG("V86 trap handler must not register an SEH frame\n",
352 ExceptionList == TrapFrame->ExceptionList);
353
354 /* Save DR7 and check for debugging */
355 TrapFrame->Dr7 = __readdr(7);
356 if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0))
357 {
358 /* Handle debug registers */
359 KiHandleDebugRegistersOnTrapEntry(TrapFrame);
360 }
361 }
362
363 //
364 // Interrupt Trap Entry
365 //
366 FORCEINLINE
367 VOID
KiEnterInterruptTrap(IN PKTRAP_FRAME TrapFrame)368 KiEnterInterruptTrap(IN PKTRAP_FRAME TrapFrame)
369 {
370 PVOID ExceptionList;
371
372 /* Check exception list and terminate it */
373 ExceptionList = KeGetPcr()->NtTib.ExceptionList;
374 ASSERTMSG("Interrupt handler must not register an SEH frame\n",
375 ExceptionList == TrapFrame->ExceptionList);
376 KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
377
378 /* Default to debugging disabled */
379 TrapFrame->Dr7 = 0;
380
381 /* Check if the frame was from user mode or v86 mode */
382 if (KiUserTrap(TrapFrame) ||
383 (TrapFrame->EFlags & EFLAGS_V86_MASK))
384 {
385 /* Check for active debugging */
386 if (KeGetCurrentThread()->Header.DebugActive & 0xFF)
387 {
388 /* Handle debug registers */
389 KiHandleDebugRegistersOnTrapEntry(TrapFrame);
390 }
391 }
392
393 /* Set debug header */
394 KiFillTrapFrameDebug(TrapFrame);
395 }
396
397 //
398 // Generic Trap Entry
399 //
400 FORCEINLINE
401 VOID
KiEnterTrap(IN PKTRAP_FRAME TrapFrame)402 KiEnterTrap(IN PKTRAP_FRAME TrapFrame)
403 {
404 PVOID ExceptionList;
405
406 /* Check exception list */
407 ExceptionList = KeGetPcr()->NtTib.ExceptionList;
408 ASSERTMSG("Trap handler must not register an SEH frame\n",
409 ExceptionList == TrapFrame->ExceptionList);
410
411 /* Default to debugging disabled */
412 TrapFrame->Dr7 = 0;
413
414 /* Check if the frame was from user mode or v86 mode */
415 if (KiUserTrap(TrapFrame) ||
416 (TrapFrame->EFlags & EFLAGS_V86_MASK))
417 {
418 /* Check for active debugging */
419 if (KeGetCurrentThread()->Header.DebugActive & 0xFF)
420 {
421 /* Handle debug registers */
422 KiHandleDebugRegistersOnTrapEntry(TrapFrame);
423 }
424 }
425
426 /* Set debug header */
427 KiFillTrapFrameDebug(TrapFrame);
428 }
429