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
10 #if __GNUC__ * 100 + __GNUC_MINOR__ >= 405
11 #define UNREACHABLE __builtin_unreachable()
13 #define UNREACHABLE __builtin_trap()
15 #else /* not __GNUC__ */
24 KiDumpTrapFrame(IN PKTRAP_FRAME TrapFrame
)
26 /* Dump the whole thing */
27 DPRINT1("DbgEbp: %x\n", TrapFrame
->DbgEbp
);
28 DPRINT1("DbgEip: %x\n", TrapFrame
->DbgEip
);
29 DPRINT1("DbgArgMark: %x\n", TrapFrame
->DbgArgMark
);
30 DPRINT1("DbgArgPointer: %x\n", TrapFrame
->DbgArgPointer
);
31 DPRINT1("TempSegCs: %x\n", TrapFrame
->TempSegCs
);
32 DPRINT1("TempEsp: %x\n", TrapFrame
->TempEsp
);
33 DPRINT1("Dr0: %x\n", TrapFrame
->Dr0
);
34 DPRINT1("Dr1: %x\n", TrapFrame
->Dr1
);
35 DPRINT1("Dr2: %x\n", TrapFrame
->Dr2
);
36 DPRINT1("Dr3: %x\n", TrapFrame
->Dr3
);
37 DPRINT1("Dr6: %x\n", TrapFrame
->Dr6
);
38 DPRINT1("Dr7: %x\n", TrapFrame
->Dr7
);
39 DPRINT1("SegGs: %x\n", TrapFrame
->SegGs
);
40 DPRINT1("SegEs: %x\n", TrapFrame
->SegEs
);
41 DPRINT1("SegDs: %x\n", TrapFrame
->SegDs
);
42 DPRINT1("Edx: %x\n", TrapFrame
->Edx
);
43 DPRINT1("Ecx: %x\n", TrapFrame
->Ecx
);
44 DPRINT1("Eax: %x\n", TrapFrame
->Eax
);
45 DPRINT1("PreviousPreviousMode: %x\n", TrapFrame
->PreviousPreviousMode
);
46 DPRINT1("ExceptionList: %x\n", TrapFrame
->ExceptionList
);
47 DPRINT1("SegFs: %x\n", TrapFrame
->SegFs
);
48 DPRINT1("Edi: %x\n", TrapFrame
->Edi
);
49 DPRINT1("Esi: %x\n", TrapFrame
->Esi
);
50 DPRINT1("Ebx: %x\n", TrapFrame
->Ebx
);
51 DPRINT1("Ebp: %x\n", TrapFrame
->Ebp
);
52 DPRINT1("ErrCode: %x\n", TrapFrame
->ErrCode
);
53 DPRINT1("Eip: %x\n", TrapFrame
->Eip
);
54 DPRINT1("SegCs: %x\n", TrapFrame
->SegCs
);
55 DPRINT1("EFlags: %x\n", TrapFrame
->EFlags
);
56 DPRINT1("HardwareEsp: %x\n", TrapFrame
->HardwareEsp
);
57 DPRINT1("HardwareSegSs: %x\n", TrapFrame
->HardwareSegSs
);
58 DPRINT1("V86Es: %x\n", TrapFrame
->V86Es
);
59 DPRINT1("V86Ds: %x\n", TrapFrame
->V86Ds
);
60 DPRINT1("V86Fs: %x\n", TrapFrame
->V86Fs
);
61 DPRINT1("V86Gs: %x\n", TrapFrame
->V86Gs
);
67 KiFillTrapFrameDebug(IN PKTRAP_FRAME TrapFrame
)
69 /* Set the debug information */
70 TrapFrame
->DbgArgPointer
= TrapFrame
->Edx
;
71 TrapFrame
->DbgArgMark
= 0xBADB0D00;
72 TrapFrame
->DbgEip
= TrapFrame
->Eip
;
73 TrapFrame
->DbgEbp
= TrapFrame
->Ebp
;
78 KiExitTrapDebugChecks(IN PKTRAP_FRAME TrapFrame
,
79 IN KTRAP_STATE_BITS SkipBits
)
81 /* Make sure interrupts are disabled */
82 if (__readeflags() & EFLAGS_INTERRUPT_MASK
)
84 DPRINT1("Exiting with interrupts enabled: %lx\n", __readeflags());
88 /* Make sure this is a real trap frame */
89 if (TrapFrame
->DbgArgMark
!= 0xBADB0D00)
91 DPRINT1("Exiting with an invalid trap frame? (No MAGIC in trap frame)\n");
92 KiDumpTrapFrame(TrapFrame
);
96 /* Make sure we're not in user-mode or something */
97 if (Ke386GetFs() != KGDT_R0_PCR
)
99 DPRINT1("Exiting with an invalid FS: %lx\n", Ke386GetFs());
103 /* Make sure we have a valid SEH chain */
104 if (KeGetPcr()->Tib
.ExceptionList
== 0)
106 DPRINT1("Exiting with NULL exception chain: %p\n", KeGetPcr()->Tib
.ExceptionList
);
110 /* Make sure we're restoring a valid SEH chain */
111 if (TrapFrame
->ExceptionList
== 0)
113 DPRINT1("Entered a trap with a NULL exception chain: %p\n", TrapFrame
->ExceptionList
);
117 /* If we're ignoring previous mode, make sure caller doesn't actually want it */
118 if ((SkipBits
.SkipPreviousMode
) && (TrapFrame
->PreviousPreviousMode
!= -1))
120 DPRINT1("Exiting a trap witout restoring previous mode, yet previous mode seems valid: %lx", TrapFrame
->PreviousPreviousMode
);
127 KiExitSystemCallDebugChecks(IN ULONG SystemCall
,
128 IN PKTRAP_FRAME TrapFrame
)
132 /* Check if this was a user call */
133 if (KiUserMode(TrapFrame
))
135 /* Make sure we are not returning with elevated IRQL */
136 OldIrql
= KeGetCurrentIrql();
137 if (OldIrql
!= PASSIVE_LEVEL
)
139 /* Forcibly put us in a sane state */
140 KeGetPcr()->CurrentIrql
= PASSIVE_LEVEL
;
144 KeBugCheckEx(IRQL_GT_ZERO_AT_SYSTEM_SERVICE
,
151 /* Make sure we're not attached and that APCs are not disabled */
152 if ((KeGetCurrentThread()->ApcStateIndex
!= CurrentApcEnvironment
) ||
153 (KeGetCurrentThread()->CombinedApcDisable
!= 0))
156 KeBugCheckEx(APC_INDEX_MISMATCH
,
158 KeGetCurrentThread()->ApcStateIndex
,
159 KeGetCurrentThread()->CombinedApcDisable
,
165 #define KiExitTrapDebugChecks(x, y)
166 #define KiFillTrapFrameDebug(x)
167 #define KiExitSystemCallDebugChecks(x, y)
175 KiUserTrap(IN PKTRAP_FRAME TrapFrame
)
177 /* Anything else but Ring 0 is Ring 3 */
178 return (TrapFrame
->SegCs
& MODE_MASK
);
183 KiVdmTrap(IN PKTRAP_FRAME TrapFrame
)
185 /* Either the V8086 flag is on, or this is user-mode with a VDM */
186 return ((TrapFrame
->EFlags
& EFLAGS_V86_MASK
) ||
187 ((KiUserTrap(TrapFrame
)) && (PsGetCurrentProcess()->VdmObjects
)));
192 KiCheckForApcDelivery(IN PKTRAP_FRAME TrapFrame
)
197 /* Check for V8086 or user-mode trap */
198 if ((TrapFrame
->EFlags
& EFLAGS_V86_MASK
) ||
199 (KiUserTrap(TrapFrame
)))
202 Thread
= KeGetCurrentThread();
205 /* Turn off the alerted state for kernel mode */
206 Thread
->Alerted
[KernelMode
] = FALSE
;
208 /* Are there pending user APCs? */
209 if (!Thread
->ApcState
.UserApcPending
) break;
211 /* Raise to APC level and enable interrupts */
212 OldIrql
= KfRaiseIrql(APC_LEVEL
);
216 KiDeliverApc(UserMode
, NULL
, TrapFrame
);
218 /* Restore IRQL and disable interrupts once again */
219 KfLowerIrql(OldIrql
);
228 KiDispatchException0Args(IN NTSTATUS Code
,
229 IN ULONG_PTR Address
,
230 IN PKTRAP_FRAME TrapFrame
)
232 /* Helper for exceptions with no arguments */
233 KiDispatchExceptionFromTrapFrame(Code
, Address
, 0, 0, 0, 0, TrapFrame
);
239 KiDispatchException1Args(IN NTSTATUS Code
,
240 IN ULONG_PTR Address
,
242 IN PKTRAP_FRAME TrapFrame
)
244 /* Helper for exceptions with no arguments */
245 KiDispatchExceptionFromTrapFrame(Code
, Address
, 1, P1
, 0, 0, TrapFrame
);
251 KiDispatchException2Args(IN NTSTATUS Code
,
252 IN ULONG_PTR Address
,
255 IN PKTRAP_FRAME TrapFrame
)
257 /* Helper for exceptions with no arguments */
258 KiDispatchExceptionFromTrapFrame(Code
, Address
, 2, P1
, P2
, 0, TrapFrame
);
264 KiSystemCallReturn(IN PKTRAP_FRAME TrapFrame
)
266 /* Restore nonvolatiles, EAX, and do a "jump" back to the kernel caller */
270 "movl %c[b](%%esp), %%ebx\n"
271 "movl %c[s](%%esp), %%esi\n"
272 "movl %c[i](%%esp), %%edi\n"
273 "movl %c[p](%%esp), %%ebp\n"
274 "movl %c[a](%%esp), %%eax\n"
275 "movl %c[e](%%esp), %%edx\n"
276 "addl $%c[v],%%esp\n" /* A WHOLE *KERNEL* frame since we're not IRET'ing */
280 [b
] "i"(KTRAP_FRAME_EBX
),
281 [s
] "i"(KTRAP_FRAME_ESI
),
282 [i
] "i"(KTRAP_FRAME_EDI
),
283 [p
] "i"(KTRAP_FRAME_EBP
),
284 [a
] "i"(KTRAP_FRAME_EAX
),
285 [e
] "i"(KTRAP_FRAME_EIP
),
286 [v
] "i"(KTRAP_FRAME_ESP
)
295 KiSystemCallTrapReturn(IN PKTRAP_FRAME TrapFrame
)
297 /* Regular interrupt exit, but we only restore EAX as a volatile */
301 "movl %c[b](%%esp), %%ebx\n"
302 "movl %c[s](%%esp), %%esi\n"
303 "movl %c[i](%%esp), %%edi\n"
304 "movl %c[p](%%esp), %%ebp\n"
305 "movl %c[a](%%esp), %%eax\n"
306 "addl $%c[e],%%esp\n"
310 [b
] "i"(KTRAP_FRAME_EBX
),
311 [s
] "i"(KTRAP_FRAME_ESI
),
312 [i
] "i"(KTRAP_FRAME_EDI
),
313 [p
] "i"(KTRAP_FRAME_EBP
),
314 [a
] "i"(KTRAP_FRAME_EAX
),
315 [e
] "i"(KTRAP_FRAME_EIP
)
324 KiSystemCallSysExitReturn(IN PKTRAP_FRAME TrapFrame
)
326 /* Restore nonvolatiles, EAX, and do a SYSEXIT back to the user caller */
330 "movl %c[s](%%esp), %%esi\n"
331 "movl %c[b](%%esp), %%ebx\n"
332 "movl %c[i](%%esp), %%edi\n"
333 "movl %c[p](%%esp), %%ebp\n"
334 "movl %c[a](%%esp), %%eax\n"
335 "movl %c[e](%%esp), %%edx\n" /* SYSEXIT says EIP in EDX */
336 "movl %c[x](%%esp), %%ecx\n" /* SYSEXIT says ESP in ECX */
337 "addl $%c[v],%%esp\n" /* A WHOLE *USER* frame since we're not IRET'ing */
341 [b
] "i"(KTRAP_FRAME_EBX
),
342 [s
] "i"(KTRAP_FRAME_ESI
),
343 [i
] "i"(KTRAP_FRAME_EDI
),
344 [p
] "i"(KTRAP_FRAME_EBP
),
345 [a
] "i"(KTRAP_FRAME_EAX
),
346 [e
] "i"(KTRAP_FRAME_EIP
),
347 [x
] "i"(KTRAP_FRAME_ESP
),
348 [v
] "i"(KTRAP_FRAME_V86_ES
)
357 KiTrapReturn(IN PKTRAP_FRAME TrapFrame
)
359 /* Regular interrupt exit */
363 "movl %c[a](%%esp), %%eax\n"
364 "movl %c[b](%%esp), %%ebx\n"
365 "movl %c[c](%%esp), %%ecx\n"
366 "movl %c[d](%%esp), %%edx\n"
367 "movl %c[s](%%esp), %%esi\n"
368 "movl %c[i](%%esp), %%edi\n"
369 "movl %c[p](%%esp), %%ebp\n"
370 "addl $%c[e],%%esp\n"
374 [a
] "i"(KTRAP_FRAME_EAX
),
375 [b
] "i"(KTRAP_FRAME_EBX
),
376 [c
] "i"(KTRAP_FRAME_ECX
),
377 [d
] "i"(KTRAP_FRAME_EDX
),
378 [s
] "i"(KTRAP_FRAME_ESI
),
379 [i
] "i"(KTRAP_FRAME_EDI
),
380 [p
] "i"(KTRAP_FRAME_EBP
),
381 [e
] "i"(KTRAP_FRAME_EIP
)
390 KiEditedTrapReturn(IN PKTRAP_FRAME TrapFrame
)
392 /* Regular interrupt exit */
396 "movl %c[a](%%esp), %%eax\n"
397 "movl %c[b](%%esp), %%ebx\n"
398 "movl %c[c](%%esp), %%ecx\n"
399 "movl %c[d](%%esp), %%edx\n"
400 "movl %c[s](%%esp), %%esi\n"
401 "movl %c[i](%%esp), %%edi\n"
402 "movl %c[p](%%esp), %%ebp\n"
403 "addl $%c[e],%%esp\n"
404 "movl (%%esp), %%esp\n"
408 [a
] "i"(KTRAP_FRAME_EAX
),
409 [b
] "i"(KTRAP_FRAME_EBX
),
410 [c
] "i"(KTRAP_FRAME_ECX
),
411 [d
] "i"(KTRAP_FRAME_EDX
),
412 [s
] "i"(KTRAP_FRAME_ESI
),
413 [i
] "i"(KTRAP_FRAME_EDI
),
414 [p
] "i"(KTRAP_FRAME_EBP
),
415 [e
] "i"(KTRAP_FRAME_ERROR_CODE
) /* We *WANT* the error code since ESP is there! */
423 KiSystemCallTrampoline(IN PVOID Handler
,
430 * This sequence does a RtlCopyMemory(Stack - StackBytes, Arguments, StackBytes)
431 * and then calls the function associated with the system call.
433 * It's done in assembly for two reasons: we need to muck with the stack,
434 * and the call itself restores the stack back for us. The only way to do
435 * this in C is to do manual C handlers for every possible number of args on
436 * the stack, and then have the handler issue a call by pointer. This is
437 * wasteful since it'll basically push the values twice and require another
438 * level of call indirection.
440 * The ARM kernel currently does this, but it should probably be changed
441 * later to function like this as well.
447 "movl %%esp, %%edi\n"
457 : "%esp", "%esi", "%edi"
465 KiConvertToGuiThread(VOID
)
471 * Converting to a GUI thread safely updates ESP in-place as well as the
472 * current Thread->TrapFrame and EBP when KeSwitchKernelStack is called.
474 * However, PsConvertToGuiThread "helpfully" restores EBP to the original
475 * caller's value, since it is considered a nonvolatile register. As such,
476 * as soon as we're back after the conversion and we try to store the result
477 * which will probably be in some stack variable (EBP-based), we'll crash as
478 * we are touching the de-allocated non-expanded stack.
480 * Thus we need a way to update our EBP before EBP is touched, and the only
481 * way to guarantee this is to do the call itself in assembly, use the EAX
482 * register to store the result, fixup EBP, and then let the C code continue
490 "call _PsConvertToGuiThread@0\n"
494 : "=r"(Result
), "=r"(StackFrame
)
496 : "%esp", "%ecx", "%edx"
504 KiSwitchToBootStack(IN ULONG_PTR InitialStack
)
506 /* We have to switch to a new stack before continuing kernel initialization */
512 "jmp _KiSystemStartupBootStack@0\n"
515 "i"(NPX_FRAME_LENGTH
+ KTRAP_FRAME_ALIGN
+ KTRAP_FRAME_LENGTH
),
516 "i"(CR0_EM
| CR0_TS
| CR0_MP
)