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