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