5ead64057e29322e0808cec1ac6d97570401a9e7
[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 0
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 #if 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
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 }
184 }
185 #else
186 #define KiExitTrapDebugChecks(x, y)
187 #define KiFillTrapFrameDebug(x)
188 #define KiExitSystemCallDebugChecks(x, y)
189 #endif
190
191 //
192 // Generic Exit Routine
193 //
194 DECLSPEC_NORETURN VOID FASTCALL KiSystemCallReturn(IN PKTRAP_FRAME TrapFrame);
195 DECLSPEC_NORETURN VOID FASTCALL KiSystemCallSysExitReturn(IN PKTRAP_FRAME TrapFrame);
196 DECLSPEC_NORETURN VOID FASTCALL KiSystemCallTrapReturn(IN PKTRAP_FRAME TrapFrame);
197 DECLSPEC_NORETURN VOID FASTCALL KiEditedTrapReturn(IN PKTRAP_FRAME TrapFrame);
198 DECLSPEC_NORETURN VOID FASTCALL KiTrapReturn(IN PKTRAP_FRAME TrapFrame);
199 DECLSPEC_NORETURN VOID FASTCALL KiTrapReturnNoSegments(IN PKTRAP_FRAME TrapFrame);
200
201 typedef
202 ATTRIB_NORETURN
203 VOID
204 (FASTCALL *PFAST_SYSTEM_CALL_EXIT)(
205 IN PKTRAP_FRAME TrapFrame
206 );
207
208 extern PFAST_SYSTEM_CALL_EXIT KiFastCallExitHandler;
209
210 //
211 // Virtual 8086 Mode Optimized Trap Exit
212 //
213 VOID
214 FORCEINLINE
215 DECLSPEC_NORETURN
216 KiExitV86Trap(IN PKTRAP_FRAME TrapFrame)
217 {
218 PKTHREAD Thread;
219 KIRQL OldIrql;
220
221 /* Get the thread */
222 Thread = KeGetCurrentThread();
223 while (TRUE)
224 {
225 /* Return if this isn't V86 mode anymore */
226 if (!(TrapFrame->EFlags & EFLAGS_V86_MASK)) KiEoiHelper(TrapFrame);
227
228 /* Turn off the alerted state for kernel mode */
229 Thread->Alerted[KernelMode] = FALSE;
230
231 /* Are there pending user APCs? */
232 if (__builtin_expect(!Thread->ApcState.UserApcPending, 1)) break;
233
234 /* Raise to APC level and enable interrupts */
235 OldIrql = KfRaiseIrql(APC_LEVEL);
236 _enable();
237
238 /* Deliver APCs */
239 KiDeliverApc(UserMode, NULL, TrapFrame);
240
241 /* Restore IRQL and disable interrupts once again */
242 KfLowerIrql(OldIrql);
243 _disable();
244 }
245
246 /* If we got here, we're still in a valid V8086 context, so quit it */
247 if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0))
248 {
249 /* Not handled yet */
250 DbgPrint("Need Hardware Breakpoint Support!\n");
251 while (TRUE);
252 }
253
254 /* Return from interrupt */
255 KiTrapReturnNoSegments(TrapFrame);
256 }
257
258 //
259 // Virtual 8086 Mode Optimized Trap Entry
260 //
261 VOID
262 FORCEINLINE
263 KiEnterV86Trap(IN PKTRAP_FRAME TrapFrame)
264 {
265 /* Save exception list */
266 TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
267
268 /* Save DR7 and check for debugging */
269 TrapFrame->Dr7 = __readdr(7);
270 if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0))
271 {
272 DbgPrint("Need Hardware Breakpoint Support!\n");
273 while (TRUE);
274 }
275 }
276
277 //
278 // Interrupt Trap Entry
279 //
280 VOID
281 FORCEINLINE
282 KiEnterInterruptTrap(IN PKTRAP_FRAME TrapFrame)
283 {
284 /* Save exception list and terminate it */
285 TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
286 KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
287
288 /* Flush DR7 and check for debugging */
289 TrapFrame->Dr7 = 0;
290 if (__builtin_expect(KeGetCurrentThread()->DispatcherHeader.DebugActive & 0xFF, 0))
291 {
292 DbgPrint("Need Hardware Breakpoint Support!\n");
293 while (TRUE);
294 }
295
296 /* Set debug header */
297 KiFillTrapFrameDebug(TrapFrame);
298 }
299
300 //
301 // Generic Trap Entry
302 //
303 VOID
304 FORCEINLINE
305 KiEnterTrap(IN PKTRAP_FRAME TrapFrame)
306 {
307 /* Save exception list */
308 TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
309
310 /* Flush DR7 and check for debugging */
311 TrapFrame->Dr7 = 0;
312 if (__builtin_expect(KeGetCurrentThread()->DispatcherHeader.DebugActive & 0xFF, 0))
313 {
314 DbgPrint("Need Hardware Breakpoint Support!\n");
315 while (TRUE);
316 }
317
318 /* Set debug header */
319 KiFillTrapFrameDebug(TrapFrame);
320 }