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