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