[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/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 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 = (ULONG)-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 /* FIXME: KDBG messes around with these improperly */
157 #if !defined(KDBG)
158 /* Check DR values */
159 if (KiUserTrap(TrapFrame))
160 {
161 /* Check for active debugging */
162 if (KeGetCurrentThread()->Header.DebugActive)
163 {
164 if ((TrapFrame->Dr7 & ~DR7_RESERVED_MASK) == 0) __debugbreak();
165
166 CheckDr(0, TrapFrame->Dr0);
167 CheckDr(1, TrapFrame->Dr1);
168 CheckDr(2, TrapFrame->Dr2);
169 CheckDr(3, TrapFrame->Dr3);
170 CheckDr(7, TrapFrame->Dr7 | DR7_RESERVED_READ_AS_1);
171 }
172 }
173 else
174 {
175 PKPRCB Prcb = KeGetCurrentPrcb();
176 CheckDr(0, Prcb->ProcessorState.SpecialRegisters.KernelDr0);
177 CheckDr(1, Prcb->ProcessorState.SpecialRegisters.KernelDr1);
178 CheckDr(2, Prcb->ProcessorState.SpecialRegisters.KernelDr2);
179 CheckDr(3, Prcb->ProcessorState.SpecialRegisters.KernelDr3);
180 // CheckDr(7, Prcb->ProcessorState.SpecialRegisters.KernelDr7); // Disabled, see CORE-10165 for more details.
181 }
182 #endif
183
184 StopChecking = FALSE;
185 }
186
187 #else
188 #define KiExitTrapDebugChecks(x, y)
189 #define KiFillTrapFrameDebug(x)
190 #endif
191
192 FORCEINLINE
193 VOID
194 KiExitSystemCallDebugChecks(IN ULONG SystemCall,
195 IN PKTRAP_FRAME TrapFrame)
196 {
197 KIRQL OldIrql;
198
199 /* Check if this was a user call */
200 if (KiUserTrap(TrapFrame))
201 {
202 /* Make sure we are not returning with elevated IRQL */
203 OldIrql = KeGetCurrentIrql();
204 if (OldIrql != PASSIVE_LEVEL)
205 {
206 /* Forcibly put us in a sane state */
207 KeGetPcr()->Irql = PASSIVE_LEVEL;
208 _disable();
209
210 /* Fail */
211 KeBugCheckEx(IRQL_GT_ZERO_AT_SYSTEM_SERVICE,
212 SystemCall,
213 OldIrql,
214 0,
215 0);
216 }
217
218 /* Make sure we're not attached and that APCs are not disabled */
219 if ((KeGetCurrentThread()->ApcStateIndex != OriginalApcEnvironment) ||
220 (KeGetCurrentThread()->CombinedApcDisable != 0))
221 {
222 /* Fail */
223 KeBugCheckEx(APC_INDEX_MISMATCH,
224 SystemCall,
225 KeGetCurrentThread()->ApcStateIndex,
226 KeGetCurrentThread()->CombinedApcDisable,
227 0);
228 }
229 }
230 }
231
232 //
233 // Generic Exit Routine
234 //
235 DECLSPEC_NORETURN VOID FASTCALL KiSystemCallReturn(IN PKTRAP_FRAME TrapFrame);
236 DECLSPEC_NORETURN VOID FASTCALL KiSystemCallSysExitReturn(IN PKTRAP_FRAME TrapFrame);
237 DECLSPEC_NORETURN VOID FASTCALL KiSystemCallTrapReturn(IN PKTRAP_FRAME TrapFrame);
238 DECLSPEC_NORETURN VOID FASTCALL KiEditedTrapReturn(IN PKTRAP_FRAME TrapFrame);
239 DECLSPEC_NORETURN VOID FASTCALL KiTrapReturn(IN PKTRAP_FRAME TrapFrame);
240 DECLSPEC_NORETURN VOID FASTCALL KiTrapReturnNoSegments(IN PKTRAP_FRAME TrapFrame);
241 DECLSPEC_NORETURN VOID FASTCALL KiTrapReturnNoSegmentsRet8(IN PKTRAP_FRAME TrapFrame);
242
243 typedef
244 VOID
245 (FASTCALL *PFAST_SYSTEM_CALL_EXIT)(
246 IN PKTRAP_FRAME TrapFrame
247 );
248
249 extern PFAST_SYSTEM_CALL_EXIT KiFastCallExitHandler;
250
251 //
252 // Save user mode debug registers and restore kernel values
253 //
254 FORCEINLINE
255 VOID
256 KiHandleDebugRegistersOnTrapEntry(
257 IN PKTRAP_FRAME TrapFrame)
258 {
259 PKPRCB Prcb = KeGetCurrentPrcb();
260
261 /* Save all debug registers in the trap frame */
262 TrapFrame->Dr0 = __readdr(0);
263 TrapFrame->Dr1 = __readdr(1);
264 TrapFrame->Dr2 = __readdr(2);
265 TrapFrame->Dr3 = __readdr(3);
266 TrapFrame->Dr6 = __readdr(6);
267 TrapFrame->Dr7 = __readdr(7);
268
269 /* Disable all active debugging */
270 __writedr(7, 0);
271
272 /* Restore kernel values */
273 __writedr(0, Prcb->ProcessorState.SpecialRegisters.KernelDr0);
274 __writedr(1, Prcb->ProcessorState.SpecialRegisters.KernelDr1);
275 __writedr(2, Prcb->ProcessorState.SpecialRegisters.KernelDr2);
276 __writedr(3, Prcb->ProcessorState.SpecialRegisters.KernelDr3);
277 __writedr(6, Prcb->ProcessorState.SpecialRegisters.KernelDr6);
278 __writedr(7, Prcb->ProcessorState.SpecialRegisters.KernelDr7);
279 }
280
281 FORCEINLINE
282 VOID
283 KiHandleDebugRegistersOnTrapExit(
284 PKTRAP_FRAME TrapFrame)
285 {
286 /* Disable all active debugging */
287 __writedr(7, 0);
288
289 /* Load all debug registers from the trap frame */
290 __writedr(0, TrapFrame->Dr0);
291 __writedr(1, TrapFrame->Dr1);
292 __writedr(2, TrapFrame->Dr2);
293 __writedr(3, TrapFrame->Dr3);
294 __writedr(6, TrapFrame->Dr6);
295 __writedr(7, TrapFrame->Dr7);
296 }
297
298 //
299 // Virtual 8086 Mode Optimized Trap Exit
300 //
301 FORCEINLINE
302 DECLSPEC_NORETURN
303 VOID
304 KiExitV86Trap(IN PKTRAP_FRAME TrapFrame)
305 {
306 PKTHREAD Thread;
307 KIRQL OldIrql;
308
309 /* Get the thread */
310 Thread = KeGetCurrentThread();
311 while (TRUE)
312 {
313 /* Return if this isn't V86 mode anymore */
314 if (!(TrapFrame->EFlags & EFLAGS_V86_MASK)) KiEoiHelper(TrapFrame);
315
316 /* Turn off the alerted state for kernel mode */
317 Thread->Alerted[KernelMode] = FALSE;
318
319 /* Are there pending user APCs? */
320 if (__builtin_expect(!Thread->ApcState.UserApcPending, 1)) break;
321
322 /* Raise to APC level and enable interrupts */
323 OldIrql = KfRaiseIrql(APC_LEVEL);
324 _enable();
325
326 /* Deliver APCs */
327 KiDeliverApc(UserMode, NULL, TrapFrame);
328
329 /* Restore IRQL and disable interrupts once again */
330 KfLowerIrql(OldIrql);
331 _disable();
332 }
333
334 /* If we got here, we're still in a valid V8086 context, so quit it */
335 if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0))
336 {
337 /* Restore debug registers from the trap frame */
338 KiHandleDebugRegistersOnTrapExit(TrapFrame);
339 }
340
341 /* Return from interrupt */
342 KiTrapReturnNoSegments(TrapFrame);
343 }
344
345 //
346 // Virtual 8086 Mode Optimized Trap Entry
347 //
348 FORCEINLINE
349 VOID
350 KiEnterV86Trap(IN PKTRAP_FRAME TrapFrame)
351 {
352 /* Save exception list */
353 TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
354
355 /* Save DR7 and check for debugging */
356 TrapFrame->Dr7 = __readdr(7);
357 if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0))
358 {
359 /* Handle debug registers */
360 KiHandleDebugRegistersOnTrapEntry(TrapFrame);
361 }
362 }
363
364 //
365 // Interrupt Trap Entry
366 //
367 FORCEINLINE
368 VOID
369 KiEnterInterruptTrap(IN PKTRAP_FRAME TrapFrame)
370 {
371 /* Save exception list and terminate it */
372 TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
373 KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
374
375 /* Default to debugging disabled */
376 TrapFrame->Dr7 = 0;
377
378 /* Check if the frame was from user mode or v86 mode */
379 if (KiUserTrap(TrapFrame) ||
380 (TrapFrame->EFlags & EFLAGS_V86_MASK))
381 {
382 /* Check for active debugging */
383 if (KeGetCurrentThread()->Header.DebugActive & 0xFF)
384 {
385 /* Handle debug registers */
386 KiHandleDebugRegistersOnTrapEntry(TrapFrame);
387 }
388 }
389
390 /* Set debug header */
391 KiFillTrapFrameDebug(TrapFrame);
392 }
393
394 //
395 // Generic Trap Entry
396 //
397 FORCEINLINE
398 VOID
399 KiEnterTrap(IN PKTRAP_FRAME TrapFrame)
400 {
401 /* Save exception list */
402 TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
403
404 /* Default to debugging disabled */
405 TrapFrame->Dr7 = 0;
406
407 /* Check if the frame was from user mode or v86 mode */
408 if (KiUserTrap(TrapFrame) ||
409 (TrapFrame->EFlags & EFLAGS_V86_MASK))
410 {
411 /* Check for active debugging */
412 if (KeGetCurrentThread()->Header.DebugActive & 0xFF)
413 {
414 /* Handle debug registers */
415 KiHandleDebugRegistersOnTrapEntry(TrapFrame);
416 }
417 }
418
419 /* Set debug header */
420 KiFillTrapFrameDebug(TrapFrame);
421 }