[NTOS]
[reactos.git] / reactos / ntoskrnl / include / internal / trap_x.h
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/include/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 1
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 #else
25 #define UNREACHABLE
26 #endif
27
28 //
29 // Helper Code
30 //
31 BOOLEAN
32 FORCEINLINE
33 KiUserTrap(IN PKTRAP_FRAME TrapFrame)
34 {
35 /* Anything else but Ring 0 is Ring 3 */
36 return (TrapFrame->SegCs & MODE_MASK);
37 }
38
39 //
40 // Debug Macros
41 //
42 VOID
43 FORCEINLINE
44 KiDumpTrapFrame(IN PKTRAP_FRAME TrapFrame)
45 {
46 /* Dump the whole thing */
47 DbgPrint("DbgEbp: %x\n", TrapFrame->DbgEbp);
48 DbgPrint("DbgEip: %x\n", TrapFrame->DbgEip);
49 DbgPrint("DbgArgMark: %x\n", TrapFrame->DbgArgMark);
50 DbgPrint("DbgArgPointer: %x\n", TrapFrame->DbgArgPointer);
51 DbgPrint("TempSegCs: %x\n", TrapFrame->TempSegCs);
52 DbgPrint("TempEsp: %x\n", TrapFrame->TempEsp);
53 DbgPrint("Dr0: %x\n", TrapFrame->Dr0);
54 DbgPrint("Dr1: %x\n", TrapFrame->Dr1);
55 DbgPrint("Dr2: %x\n", TrapFrame->Dr2);
56 DbgPrint("Dr3: %x\n", TrapFrame->Dr3);
57 DbgPrint("Dr6: %x\n", TrapFrame->Dr6);
58 DbgPrint("Dr7: %x\n", TrapFrame->Dr7);
59 DbgPrint("SegGs: %x\n", TrapFrame->SegGs);
60 DbgPrint("SegEs: %x\n", TrapFrame->SegEs);
61 DbgPrint("SegDs: %x\n", TrapFrame->SegDs);
62 DbgPrint("Edx: %x\n", TrapFrame->Edx);
63 DbgPrint("Ecx: %x\n", TrapFrame->Ecx);
64 DbgPrint("Eax: %x\n", TrapFrame->Eax);
65 DbgPrint("PreviousPreviousMode: %x\n", TrapFrame->PreviousPreviousMode);
66 DbgPrint("ExceptionList: %x\n", TrapFrame->ExceptionList);
67 DbgPrint("SegFs: %x\n", TrapFrame->SegFs);
68 DbgPrint("Edi: %x\n", TrapFrame->Edi);
69 DbgPrint("Esi: %x\n", TrapFrame->Esi);
70 DbgPrint("Ebx: %x\n", TrapFrame->Ebx);
71 DbgPrint("Ebp: %x\n", TrapFrame->Ebp);
72 DbgPrint("ErrCode: %x\n", TrapFrame->ErrCode);
73 DbgPrint("Eip: %x\n", TrapFrame->Eip);
74 DbgPrint("SegCs: %x\n", TrapFrame->SegCs);
75 DbgPrint("EFlags: %x\n", TrapFrame->EFlags);
76 DbgPrint("HardwareEsp: %x\n", TrapFrame->HardwareEsp);
77 DbgPrint("HardwareSegSs: %x\n", TrapFrame->HardwareSegSs);
78 DbgPrint("V86Es: %x\n", TrapFrame->V86Es);
79 DbgPrint("V86Ds: %x\n", TrapFrame->V86Ds);
80 DbgPrint("V86Fs: %x\n", TrapFrame->V86Fs);
81 DbgPrint("V86Gs: %x\n", TrapFrame->V86Gs);
82 }
83
84 #ifdef TRAP_DEBUG
85 VOID
86 FORCEINLINE
87 KiFillTrapFrameDebug(IN PKTRAP_FRAME TrapFrame)
88 {
89 /* Set the debug information */
90 TrapFrame->DbgArgPointer = TrapFrame->Edx;
91 TrapFrame->DbgArgMark = 0xBADB0D00;
92 TrapFrame->DbgEip = TrapFrame->Eip;
93 TrapFrame->DbgEbp = TrapFrame->Ebp;
94 TrapFrame->PreviousPreviousMode = -1;
95 }
96
97 VOID
98 FORCEINLINE
99 KiExitTrapDebugChecks(IN PKTRAP_FRAME TrapFrame,
100 IN KTRAP_EXIT_SKIP_BITS SkipBits)
101 {
102 /* Make sure interrupts are disabled */
103 if (__readeflags() & EFLAGS_INTERRUPT_MASK)
104 {
105 DbgPrint("Exiting with interrupts enabled: %lx\n", __readeflags());
106 __debugbreak();
107 }
108
109 /* Make sure this is a real trap frame */
110 if (TrapFrame->DbgArgMark != 0xBADB0D00)
111 {
112 DbgPrint("Exiting with an invalid trap frame? (No MAGIC in trap frame)\n");
113 KiDumpTrapFrame(TrapFrame);
114 __debugbreak();
115 }
116
117 /* Make sure we're not in user-mode or something */
118 if (Ke386GetFs() != KGDT_R0_PCR)
119 {
120 DbgPrint("Exiting with an invalid FS: %lx\n", Ke386GetFs());
121 __debugbreak();
122 }
123
124 /* Make sure we have a valid SEH chain */
125 if (KeGetPcr()->NtTib.ExceptionList == 0)
126 {
127 DbgPrint("Exiting with NULL exception chain: %p\n", KeGetPcr()->NtTib.ExceptionList);
128 __debugbreak();
129 }
130
131 /* Make sure we're restoring a valid SEH chain */
132 if (TrapFrame->ExceptionList == 0)
133 {
134 DbgPrint("Entered a trap with a NULL exception chain: %p\n", TrapFrame->ExceptionList);
135 __debugbreak();
136 }
137
138 /* If we're ignoring previous mode, make sure caller doesn't actually want it */
139 if ((SkipBits.SkipPreviousMode) && (TrapFrame->PreviousPreviousMode != -1))
140 {
141 DbgPrint("Exiting a trap witout restoring previous mode, yet previous mode seems valid: %lx\n", TrapFrame->PreviousPreviousMode);
142 __debugbreak();
143 }
144 }
145
146 VOID
147 FORCEINLINE
148 KiExitSystemCallDebugChecks(IN ULONG SystemCall,
149 IN PKTRAP_FRAME TrapFrame)
150 {
151 KIRQL OldIrql;
152
153 /* Check if this was a user call */
154 if (KiUserTrap(TrapFrame))
155 {
156 /* Make sure we are not returning with elevated IRQL */
157 OldIrql = KeGetCurrentIrql();
158 if (OldIrql != PASSIVE_LEVEL)
159 {
160 /* Forcibly put us in a sane state */
161 KeGetPcr()->Irql = PASSIVE_LEVEL;
162 _disable();
163
164 /* Fail */
165 KeBugCheckEx(IRQL_GT_ZERO_AT_SYSTEM_SERVICE,
166 SystemCall,
167 OldIrql,
168 0,
169 0);
170 }
171 #if 0
172 /* Make sure we're not attached and that APCs are not disabled */
173 if ((KeGetCurrentThread()->ApcStateIndex != CurrentApcEnvironment) ||
174 (KeGetCurrentThread()->CombinedApcDisable != 0))
175 {
176 /* Fail */
177 KeBugCheckEx(APC_INDEX_MISMATCH,
178 SystemCall,
179 KeGetCurrentThread()->ApcStateIndex,
180 KeGetCurrentThread()->CombinedApcDisable,
181 0);
182 }
183 #endif
184 }
185 }
186 #else
187 #define KiExitTrapDebugChecks(x, y)
188 #define KiFillTrapFrameDebug(x)
189 #define KiExitSystemCallDebugChecks(x, y)
190 #endif
191
192 //
193 // Generic Exit Routine
194 //
195 DECLSPEC_NORETURN VOID FASTCALL KiSystemCallReturn(IN PKTRAP_FRAME TrapFrame);
196 DECLSPEC_NORETURN VOID FASTCALL KiSystemCallSysExitReturn(IN PKTRAP_FRAME TrapFrame);
197 DECLSPEC_NORETURN VOID FASTCALL KiSystemCallTrapReturn(IN PKTRAP_FRAME TrapFrame);
198 DECLSPEC_NORETURN VOID FASTCALL KiEditedTrapReturn(IN PKTRAP_FRAME TrapFrame);
199 DECLSPEC_NORETURN VOID FASTCALL KiTrapReturn(IN PKTRAP_FRAME TrapFrame);
200 DECLSPEC_NORETURN VOID FASTCALL KiTrapReturnNoSegments(IN PKTRAP_FRAME TrapFrame);
201
202 typedef
203 VOID
204 (FASTCALL
205 *PFAST_SYSTEM_CALL_EXIT)(IN PKTRAP_FRAME TrapFrame);
206
207 extern PFAST_SYSTEM_CALL_EXIT KiFastCallExitHandler;
208
209 //
210 // Virtual 8086 Mode Optimized Trap Exit
211 //
212 VOID
213 FORCEINLINE
214 DECLSPEC_NORETURN
215 KiExitV86Trap(IN PKTRAP_FRAME TrapFrame)
216 {
217 PKTHREAD Thread;
218 KIRQL OldIrql;
219
220 /* Get the thread */
221 Thread = KeGetCurrentThread();
222 while (TRUE)
223 {
224 /* Return if this isn't V86 mode anymore */
225 if (!(TrapFrame->EFlags & EFLAGS_V86_MASK)) KiEoiHelper(TrapFrame);;
226
227 /* Turn off the alerted state for kernel mode */
228 Thread->Alerted[KernelMode] = FALSE;
229
230 /* Are there pending user APCs? */
231 if (__builtin_expect(!Thread->ApcState.UserApcPending, 1)) break;
232
233 /* Raise to APC level and enable interrupts */
234 OldIrql = KfRaiseIrql(APC_LEVEL);
235 _enable();
236
237 /* Deliver APCs */
238 KiDeliverApc(UserMode, NULL, TrapFrame);
239
240 /* Restore IRQL and disable interrupts once again */
241 KfLowerIrql(OldIrql);
242 _disable();
243 }
244
245 /* If we got here, we're still in a valid V8086 context, so quit it */
246 if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0))
247 {
248 /* Not handled yet */
249 DbgPrint("Need Hardware Breakpoint Support!\n");
250 while (TRUE);
251 }
252
253 /* Return from interrupt */
254 KiTrapReturnNoSegments(TrapFrame);
255 }
256
257 //
258 // Virtual 8086 Mode Optimized Trap Entry
259 //
260 VOID
261 FORCEINLINE
262 KiEnterV86Trap(IN PKTRAP_FRAME TrapFrame)
263 {
264 /* Save exception list */
265 TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
266
267 /* Save DR7 and check for debugging */
268 TrapFrame->Dr7 = __readdr(7);
269 if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0))
270 {
271 DbgPrint("Need Hardware Breakpoint Support!\n");
272 while (TRUE);
273 }
274 }
275
276 //
277 // Interrupt Trap Entry
278 //
279 VOID
280 FORCEINLINE
281 KiEnterInterruptTrap(IN PKTRAP_FRAME TrapFrame)
282 {
283 /* Save exception list and terminate it */
284 TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
285 KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
286
287 /* Flush DR7 and check for debugging */
288 TrapFrame->Dr7 = 0;
289 if (__builtin_expect(KeGetCurrentThread()->DispatcherHeader.DebugActive & 0xFF, 0))
290 {
291 DbgPrint("Need Hardware Breakpoint Support!\n");
292 while (TRUE);
293 }
294
295 /* Set debug header */
296 KiFillTrapFrameDebug(TrapFrame);
297 }
298
299 //
300 // Generic Trap Entry
301 //
302 VOID
303 FORCEINLINE
304 KiEnterTrap(IN PKTRAP_FRAME TrapFrame)
305 {
306 /* Save exception list */
307 TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
308
309 /* Flush DR7 and check for debugging */
310 TrapFrame->Dr7 = 0;
311 if (__builtin_expect(KeGetCurrentThread()->DispatcherHeader.DebugActive & 0xFF, 0))
312 {
313 DbgPrint("Need Hardware Breakpoint Support!\n");
314 while (TRUE);
315 }
316
317 /* Set debug header */
318 KiFillTrapFrameDebug(TrapFrame);
319 }