08acc3f647c53cfbc31a54c347f7e33f7430eff5
[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 #if defined(_MSC_VER)
12 #define UNREACHABLE __assume(0)
13 #define __builtin_expect(a,b) (a)
14 #elif defined(__GNUC__)
15 #define UNREACHABLE __builtin_unreachable()
16 #else
17 #error
18 #endif
19
20 //
21 // Helper Code
22 //
23 FORCEINLINE
24 BOOLEAN
25 KiUserTrap(IN PKTRAP_FRAME TrapFrame)
26 {
27 /* Anything else but Ring 0 is Ring 3 */
28 return !!(TrapFrame->SegCs & MODE_MASK);
29 }
30
31 //
32 // Debug Macros
33 //
34 FORCEINLINE
35 VOID
36 KiDumpTrapFrame(IN PKTRAP_FRAME TrapFrame)
37 {
38 /* Dump the whole thing */
39 DbgPrint("DbgEbp: %x\n", TrapFrame->DbgEbp);
40 DbgPrint("DbgEip: %x\n", TrapFrame->DbgEip);
41 DbgPrint("DbgArgMark: %x\n", TrapFrame->DbgArgMark);
42 DbgPrint("DbgArgPointer: %x\n", TrapFrame->DbgArgPointer);
43 DbgPrint("TempSegCs: %x\n", TrapFrame->TempSegCs);
44 DbgPrint("TempEsp: %x\n", TrapFrame->TempEsp);
45 DbgPrint("Dr0: %x\n", TrapFrame->Dr0);
46 DbgPrint("Dr1: %x\n", TrapFrame->Dr1);
47 DbgPrint("Dr2: %x\n", TrapFrame->Dr2);
48 DbgPrint("Dr3: %x\n", TrapFrame->Dr3);
49 DbgPrint("Dr6: %x\n", TrapFrame->Dr6);
50 DbgPrint("Dr7: %x\n", TrapFrame->Dr7);
51 DbgPrint("SegGs: %x\n", TrapFrame->SegGs);
52 DbgPrint("SegEs: %x\n", TrapFrame->SegEs);
53 DbgPrint("SegDs: %x\n", TrapFrame->SegDs);
54 DbgPrint("Edx: %x\n", TrapFrame->Edx);
55 DbgPrint("Ecx: %x\n", TrapFrame->Ecx);
56 DbgPrint("Eax: %x\n", TrapFrame->Eax);
57 DbgPrint("PreviousPreviousMode: %x\n", TrapFrame->PreviousPreviousMode);
58 DbgPrint("ExceptionList: %p\n", TrapFrame->ExceptionList);
59 DbgPrint("SegFs: %x\n", TrapFrame->SegFs);
60 DbgPrint("Edi: %x\n", TrapFrame->Edi);
61 DbgPrint("Esi: %x\n", TrapFrame->Esi);
62 DbgPrint("Ebx: %x\n", TrapFrame->Ebx);
63 DbgPrint("Ebp: %x\n", TrapFrame->Ebp);
64 DbgPrint("ErrCode: %x\n", TrapFrame->ErrCode);
65 DbgPrint("Eip: %x\n", TrapFrame->Eip);
66 DbgPrint("SegCs: %x\n", TrapFrame->SegCs);
67 DbgPrint("EFlags: %x\n", TrapFrame->EFlags);
68 DbgPrint("HardwareEsp: %x\n", TrapFrame->HardwareEsp);
69 DbgPrint("HardwareSegSs: %x\n", TrapFrame->HardwareSegSs);
70 DbgPrint("V86Es: %x\n", TrapFrame->V86Es);
71 DbgPrint("V86Ds: %x\n", TrapFrame->V86Ds);
72 DbgPrint("V86Fs: %x\n", TrapFrame->V86Fs);
73 DbgPrint("V86Gs: %x\n", TrapFrame->V86Gs);
74 }
75
76 #if DBG
77 FORCEINLINE
78 VOID
79 KiFillTrapFrameDebug(IN PKTRAP_FRAME TrapFrame)
80 {
81 /* Set the debug information */
82 TrapFrame->DbgArgPointer = TrapFrame->Edx;
83 TrapFrame->DbgArgMark = 0xBADB0D00;
84 TrapFrame->DbgEip = TrapFrame->Eip;
85 TrapFrame->DbgEbp = TrapFrame->Ebp;
86 TrapFrame->PreviousPreviousMode = -1;
87 }
88
89 #define DR7_RESERVED_READ_AS_1 0x400
90
91 #define CheckDr(DrNumner, ExpectedValue) \
92 { \
93 ULONG DrValue = __readdr(DrNumner); \
94 if (DrValue != (ExpectedValue)) \
95 { \
96 DbgPrint("Dr%ld: expected %.8lx, got %.8lx\n", \
97 DrNumner, ExpectedValue, DrValue); \
98 __debugbreak(); \
99 } \
100 }
101
102 extern BOOLEAN StopChecking;
103
104 FORCEINLINE
105 VOID
106 KiExitTrapDebugChecks(IN PKTRAP_FRAME TrapFrame,
107 IN BOOLEAN SkipPreviousMode)
108 {
109 /* Don't check recursively */
110 if (StopChecking) return;
111 StopChecking = TRUE;
112
113 /* Make sure interrupts are disabled */
114 if (__readeflags() & EFLAGS_INTERRUPT_MASK)
115 {
116 DbgPrint("Exiting with interrupts enabled: %lx\n", __readeflags());
117 __debugbreak();
118 }
119
120 /* Make sure this is a real trap frame */
121 if (TrapFrame->DbgArgMark != 0xBADB0D00)
122 {
123 DbgPrint("Exiting with an invalid trap frame? (No MAGIC in trap frame)\n");
124 KiDumpTrapFrame(TrapFrame);
125 __debugbreak();
126 }
127
128 /* Make sure we're not in user-mode or something */
129 if (Ke386GetFs() != KGDT_R0_PCR)
130 {
131 DbgPrint("Exiting with an invalid FS: %lx\n", Ke386GetFs());
132 __debugbreak();
133 }
134
135 /* Make sure we have a valid SEH chain */
136 if (KeGetPcr()->NtTib.ExceptionList == 0)
137 {
138 DbgPrint("Exiting with NULL exception chain: %p\n", KeGetPcr()->NtTib.ExceptionList);
139 __debugbreak();
140 }
141
142 /* Make sure we're restoring a valid SEH chain */
143 if (TrapFrame->ExceptionList == 0)
144 {
145 DbgPrint("Entered a trap with a NULL exception chain: %p\n", TrapFrame->ExceptionList);
146 __debugbreak();
147 }
148
149 /* If we're ignoring previous mode, make sure caller doesn't actually want it */
150 if (SkipPreviousMode && (TrapFrame->PreviousPreviousMode != -1))
151 {
152 DbgPrint("Exiting a trap witout restoring previous mode, yet previous mode seems valid: %lx\n", TrapFrame->PreviousPreviousMode);
153 __debugbreak();
154 }
155
156 /* Check DR values */
157 if (KiUserTrap(TrapFrame))
158 {
159 /* Check for active debugging */
160 if (KeGetCurrentThread()->Header.DebugActive)
161 {
162 if ((TrapFrame->Dr7 & ~DR7_RESERVED_MASK) == 0) __debugbreak();
163
164 CheckDr(0, TrapFrame->Dr0);
165 CheckDr(1, TrapFrame->Dr1);
166 CheckDr(2, TrapFrame->Dr2);
167 CheckDr(3, TrapFrame->Dr3);
168 CheckDr(7, TrapFrame->Dr7 | DR7_RESERVED_READ_AS_1);
169 }
170 }
171 else
172 {
173 PKPRCB Prcb = KeGetCurrentPrcb();
174 CheckDr(0, Prcb->ProcessorState.SpecialRegisters.KernelDr0);
175 CheckDr(1, Prcb->ProcessorState.SpecialRegisters.KernelDr1);
176 CheckDr(2, Prcb->ProcessorState.SpecialRegisters.KernelDr2);
177 CheckDr(3, Prcb->ProcessorState.SpecialRegisters.KernelDr3);
178 //CheckDr(7, Prcb->ProcessorState.SpecialRegisters.KernelDr7);
179 }
180
181 StopChecking = FALSE;
182 }
183
184 #else
185 #define KiExitTrapDebugChecks(x, y)
186 #define KiFillTrapFrameDebug(x)
187 #endif
188
189 FORCEINLINE
190 VOID
191 KiExitSystemCallDebugChecks(IN ULONG SystemCall,
192 IN PKTRAP_FRAME TrapFrame)
193 {
194 KIRQL OldIrql;
195
196 /* Check if this was a user call */
197 if (KiUserTrap(TrapFrame))
198 {
199 /* Make sure we are not returning with elevated IRQL */
200 OldIrql = KeGetCurrentIrql();
201 if (OldIrql != PASSIVE_LEVEL)
202 {
203 /* Forcibly put us in a sane state */
204 KeGetPcr()->Irql = PASSIVE_LEVEL;
205 _disable();
206
207 /* Fail */
208 KeBugCheckEx(IRQL_GT_ZERO_AT_SYSTEM_SERVICE,
209 SystemCall,
210 OldIrql,
211 0,
212 0);
213 }
214
215 /* Make sure we're not attached and that APCs are not disabled */
216 if ((KeGetCurrentThread()->ApcStateIndex != OriginalApcEnvironment) ||
217 (KeGetCurrentThread()->CombinedApcDisable != 0))
218 {
219 /* Fail */
220 KeBugCheckEx(APC_INDEX_MISMATCH,
221 SystemCall,
222 KeGetCurrentThread()->ApcStateIndex,
223 KeGetCurrentThread()->CombinedApcDisable,
224 0);
225 }
226 }
227 }
228
229 //
230 // Generic Exit Routine
231 //
232 DECLSPEC_NORETURN VOID FASTCALL KiSystemCallReturn(IN PKTRAP_FRAME TrapFrame);
233 DECLSPEC_NORETURN VOID FASTCALL KiSystemCallSysExitReturn(IN PKTRAP_FRAME TrapFrame);
234 DECLSPEC_NORETURN VOID FASTCALL KiSystemCallTrapReturn(IN PKTRAP_FRAME TrapFrame);
235 DECLSPEC_NORETURN VOID FASTCALL KiEditedTrapReturn(IN PKTRAP_FRAME TrapFrame);
236 DECLSPEC_NORETURN VOID FASTCALL KiTrapReturn(IN PKTRAP_FRAME TrapFrame);
237 DECLSPEC_NORETURN VOID FASTCALL KiTrapReturnNoSegments(IN PKTRAP_FRAME TrapFrame);
238 DECLSPEC_NORETURN VOID FASTCALL KiTrapReturnNoSegmentsRet8(IN PKTRAP_FRAME TrapFrame);
239
240 typedef
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 }