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
12 // Unreachable code hint for GCC 4.5.x, 4.4.x, and MSVC
14 #if __GNUC__ * 100 + __GNUC_MINOR__ >= 405
15 #define UNREACHABLE __builtin_unreachable()
16 #elif __GNUC__ * 100 + __GNUC_MINOR__ >= 404
17 #define UNREACHABLE __builtin_trap()
19 #define UNREACHABLE __assume(0)
29 KiDumpTrapFrame(IN PKTRAP_FRAME TrapFrame
)
31 /* Dump the whole thing */
32 DbgPrint("DbgEbp: %x\n", TrapFrame
->DbgEbp
);
33 DbgPrint("DbgEip: %x\n", TrapFrame
->DbgEip
);
34 DbgPrint("DbgArgMark: %x\n", TrapFrame
->DbgArgMark
);
35 DbgPrint("DbgArgPointer: %x\n", TrapFrame
->DbgArgPointer
);
36 DbgPrint("TempSegCs: %x\n", TrapFrame
->TempSegCs
);
37 DbgPrint("TempEsp: %x\n", TrapFrame
->TempEsp
);
38 DbgPrint("Dr0: %x\n", TrapFrame
->Dr0
);
39 DbgPrint("Dr1: %x\n", TrapFrame
->Dr1
);
40 DbgPrint("Dr2: %x\n", TrapFrame
->Dr2
);
41 DbgPrint("Dr3: %x\n", TrapFrame
->Dr3
);
42 DbgPrint("Dr6: %x\n", TrapFrame
->Dr6
);
43 DbgPrint("Dr7: %x\n", TrapFrame
->Dr7
);
44 DbgPrint("SegGs: %x\n", TrapFrame
->SegGs
);
45 DbgPrint("SegEs: %x\n", TrapFrame
->SegEs
);
46 DbgPrint("SegDs: %x\n", TrapFrame
->SegDs
);
47 DbgPrint("Edx: %x\n", TrapFrame
->Edx
);
48 DbgPrint("Ecx: %x\n", TrapFrame
->Ecx
);
49 DbgPrint("Eax: %x\n", TrapFrame
->Eax
);
50 DbgPrint("PreviousPreviousMode: %x\n", TrapFrame
->PreviousPreviousMode
);
51 DbgPrint("ExceptionList: %x\n", TrapFrame
->ExceptionList
);
52 DbgPrint("SegFs: %x\n", TrapFrame
->SegFs
);
53 DbgPrint("Edi: %x\n", TrapFrame
->Edi
);
54 DbgPrint("Esi: %x\n", TrapFrame
->Esi
);
55 DbgPrint("Ebx: %x\n", TrapFrame
->Ebx
);
56 DbgPrint("Ebp: %x\n", TrapFrame
->Ebp
);
57 DbgPrint("ErrCode: %x\n", TrapFrame
->ErrCode
);
58 DbgPrint("Eip: %x\n", TrapFrame
->Eip
);
59 DbgPrint("SegCs: %x\n", TrapFrame
->SegCs
);
60 DbgPrint("EFlags: %x\n", TrapFrame
->EFlags
);
61 DbgPrint("HardwareEsp: %x\n", TrapFrame
->HardwareEsp
);
62 DbgPrint("HardwareSegSs: %x\n", TrapFrame
->HardwareSegSs
);
63 DbgPrint("V86Es: %x\n", TrapFrame
->V86Es
);
64 DbgPrint("V86Ds: %x\n", TrapFrame
->V86Ds
);
65 DbgPrint("V86Fs: %x\n", TrapFrame
->V86Fs
);
66 DbgPrint("V86Gs: %x\n", TrapFrame
->V86Gs
);
72 KiFillTrapFrameDebug(IN PKTRAP_FRAME TrapFrame
)
74 /* Set the debug information */
75 TrapFrame
->DbgArgPointer
= TrapFrame
->Edx
;
76 TrapFrame
->DbgArgMark
= 0xBADB0D00;
77 TrapFrame
->DbgEip
= TrapFrame
->Eip
;
78 TrapFrame
->DbgEbp
= TrapFrame
->Ebp
;
83 KiExitTrapDebugChecks(IN PKTRAP_FRAME TrapFrame
,
84 IN KTRAP_STATE_BITS SkipBits
)
86 /* Make sure interrupts are disabled */
87 if (__readeflags() & EFLAGS_INTERRUPT_MASK
)
89 DbgPrint("Exiting with interrupts enabled: %lx\n", __readeflags());
93 /* Make sure this is a real trap frame */
94 if (TrapFrame
->DbgArgMark
!= 0xBADB0D00)
96 DbgPrint("Exiting with an invalid trap frame? (No MAGIC in trap frame)\n");
97 KiDumpTrapFrame(TrapFrame
);
101 /* Make sure we're not in user-mode or something */
102 if (Ke386GetFs() != KGDT_R0_PCR
)
104 DbgPrint("Exiting with an invalid FS: %lx\n", Ke386GetFs());
108 /* Make sure we have a valid SEH chain */
109 if (KeGetPcr()->Tib
.ExceptionList
== 0)
111 DbgPrint("Exiting with NULL exception chain: %p\n", KeGetPcr()->Tib
.ExceptionList
);
115 /* Make sure we're restoring a valid SEH chain */
116 if (TrapFrame
->ExceptionList
== 0)
118 DbgPrint("Entered a trap with a NULL exception chain: %p\n", TrapFrame
->ExceptionList
);
122 /* If we're ignoring previous mode, make sure caller doesn't actually want it */
123 if ((SkipBits
.SkipPreviousMode
) && (TrapFrame
->PreviousPreviousMode
!= -1))
125 DbgPrint("Exiting a trap witout restoring previous mode, yet previous mode seems valid: %lx", TrapFrame
->PreviousPreviousMode
);
132 KiExitSystemCallDebugChecks(IN ULONG SystemCall
,
133 IN PKTRAP_FRAME TrapFrame
)
137 /* Check if this was a user call */
138 if (KiUserMode(TrapFrame
))
140 /* Make sure we are not returning with elevated IRQL */
141 OldIrql
= KeGetCurrentIrql();
142 if (OldIrql
!= PASSIVE_LEVEL
)
144 /* Forcibly put us in a sane state */
145 KeGetPcr()->CurrentIrql
= PASSIVE_LEVEL
;
149 KeBugCheckEx(IRQL_GT_ZERO_AT_SYSTEM_SERVICE
,
156 /* Make sure we're not attached and that APCs are not disabled */
157 if ((KeGetCurrentThread()->ApcStateIndex
!= CurrentApcEnvironment
) ||
158 (KeGetCurrentThread()->CombinedApcDisable
!= 0))
161 KeBugCheckEx(APC_INDEX_MISMATCH
,
163 KeGetCurrentThread()->ApcStateIndex
,
164 KeGetCurrentThread()->CombinedApcDisable
,
170 #define KiExitTrapDebugChecks(x, y)
171 #define KiFillTrapFrameDebug(x)
172 #define KiExitSystemCallDebugChecks(x, y)
180 KiUserTrap(IN PKTRAP_FRAME TrapFrame
)
182 /* Anything else but Ring 0 is Ring 3 */
183 return (TrapFrame
->SegCs
& MODE_MASK
);
187 // Assembly exit stubs
192 KiSystemCallReturn(IN PKTRAP_FRAME TrapFrame
)
194 /* Restore nonvolatiles, EAX, and do a "jump" back to the kernel caller */
198 "movl %c[b](%%esp), %%ebx\n"
199 "movl %c[s](%%esp), %%esi\n"
200 "movl %c[i](%%esp), %%edi\n"
201 "movl %c[p](%%esp), %%ebp\n"
202 "movl %c[a](%%esp), %%eax\n"
203 "movl %c[e](%%esp), %%edx\n"
204 "addl $%c[v],%%esp\n" /* A WHOLE *KERNEL* frame since we're not IRET'ing */
208 [b
] "i"(KTRAP_FRAME_EBX
),
209 [s
] "i"(KTRAP_FRAME_ESI
),
210 [i
] "i"(KTRAP_FRAME_EDI
),
211 [p
] "i"(KTRAP_FRAME_EBP
),
212 [a
] "i"(KTRAP_FRAME_EAX
),
213 [e
] "i"(KTRAP_FRAME_EIP
),
214 [v
] "i"(KTRAP_FRAME_ESP
)
223 KiSystemCallTrapReturn(IN PKTRAP_FRAME TrapFrame
)
225 /* Regular interrupt exit, but we only restore EAX as a volatile */
229 "movl %c[b](%%esp), %%ebx\n"
230 "movl %c[s](%%esp), %%esi\n"
231 "movl %c[i](%%esp), %%edi\n"
232 "movl %c[p](%%esp), %%ebp\n"
233 "movl %c[a](%%esp), %%eax\n"
234 "addl $%c[e],%%esp\n"
238 [b
] "i"(KTRAP_FRAME_EBX
),
239 [s
] "i"(KTRAP_FRAME_ESI
),
240 [i
] "i"(KTRAP_FRAME_EDI
),
241 [p
] "i"(KTRAP_FRAME_EBP
),
242 [a
] "i"(KTRAP_FRAME_EAX
),
243 [e
] "i"(KTRAP_FRAME_EIP
)
252 KiSystemCallSysExitReturn(IN PKTRAP_FRAME TrapFrame
)
254 /* Restore nonvolatiles, EAX, and do a SYSEXIT back to the user caller */
258 "movl %c[s](%%esp), %%esi\n"
259 "movl %c[b](%%esp), %%ebx\n"
260 "movl %c[i](%%esp), %%edi\n"
261 "movl %c[p](%%esp), %%ebp\n"
262 "movl %c[a](%%esp), %%eax\n"
263 "movl %c[e](%%esp), %%edx\n" /* SYSEXIT says EIP in EDX */
264 "movl %c[x](%%esp), %%ecx\n" /* SYSEXIT says ESP in ECX */
265 "addl $%c[v],%%esp\n" /* A WHOLE *USER* frame since we're not IRET'ing */
269 [b
] "i"(KTRAP_FRAME_EBX
),
270 [s
] "i"(KTRAP_FRAME_ESI
),
271 [i
] "i"(KTRAP_FRAME_EDI
),
272 [p
] "i"(KTRAP_FRAME_EBP
),
273 [a
] "i"(KTRAP_FRAME_EAX
),
274 [e
] "i"(KTRAP_FRAME_EIP
),
275 [x
] "i"(KTRAP_FRAME_ESP
),
276 [v
] "i"(KTRAP_FRAME_V86_ES
)
285 KiTrapReturn(IN PKTRAP_FRAME TrapFrame
)
287 /* Regular interrupt exit */
291 "movl %c[a](%%esp), %%eax\n"
292 "movl %c[b](%%esp), %%ebx\n"
293 "movl %c[c](%%esp), %%ecx\n"
294 "movl %c[d](%%esp), %%edx\n"
295 "movl %c[s](%%esp), %%esi\n"
296 "movl %c[i](%%esp), %%edi\n"
297 "movl %c[p](%%esp), %%ebp\n"
298 "addl $%c[e],%%esp\n"
302 [a
] "i"(KTRAP_FRAME_EAX
),
303 [b
] "i"(KTRAP_FRAME_EBX
),
304 [c
] "i"(KTRAP_FRAME_ECX
),
305 [d
] "i"(KTRAP_FRAME_EDX
),
306 [s
] "i"(KTRAP_FRAME_ESI
),
307 [i
] "i"(KTRAP_FRAME_EDI
),
308 [p
] "i"(KTRAP_FRAME_EBP
),
309 [e
] "i"(KTRAP_FRAME_EIP
)
318 KiEditedTrapReturn(IN PKTRAP_FRAME TrapFrame
)
320 /* Regular interrupt exit */
324 "movl %c[a](%%esp), %%eax\n"
325 "movl %c[b](%%esp), %%ebx\n"
326 "movl %c[c](%%esp), %%ecx\n"
327 "movl %c[d](%%esp), %%edx\n"
328 "movl %c[s](%%esp), %%esi\n"
329 "movl %c[i](%%esp), %%edi\n"
330 "movl %c[p](%%esp), %%ebp\n"
331 "addl $%c[e],%%esp\n"
332 "movl (%%esp), %%esp\n"
336 [a
] "i"(KTRAP_FRAME_EAX
),
337 [b
] "i"(KTRAP_FRAME_EBX
),
338 [c
] "i"(KTRAP_FRAME_ECX
),
339 [d
] "i"(KTRAP_FRAME_EDX
),
340 [s
] "i"(KTRAP_FRAME_ESI
),
341 [i
] "i"(KTRAP_FRAME_EDI
),
342 [p
] "i"(KTRAP_FRAME_EBP
),
343 [e
] "i"(KTRAP_FRAME_ERROR_CODE
) /* We *WANT* the error code since ESP is there! */
350 // Generic Exit Routine
355 KiExitTrap(IN PKTRAP_FRAME TrapFrame
,
358 KTRAP_EXIT_SKIP_BITS SkipBits
= { .Bits
= Skip
};
361 /* Debugging checks */
362 KiExitTrapDebugChecks(TrapFrame
, SkipBits
);
364 /* Restore the SEH handler chain */
365 KeGetPcr()->Tib
.ExceptionList
= TrapFrame
->ExceptionList
;
367 /* Check if the previous mode must be restored */
368 if (__builtin_expect(!SkipBits
.SkipPreviousMode
, 0)) /* More INTS than SYSCALLs */
371 KeGetCurrentThread()->PreviousMode
= TrapFrame
->PreviousPreviousMode
;
374 /* Check if there are active debug registers */
375 if (__builtin_expect(TrapFrame
->Dr7
& ~DR7_RESERVED_MASK
, 0))
377 /* Not handled yet */
378 DbgPrint("Need Hardware Breakpoint Support!\n");
383 /* Check if this was a V8086 trap */
384 if (__builtin_expect(TrapFrame
->EFlags
& EFLAGS_V86_MASK
, 0)) KiTrapReturn(TrapFrame
);
386 /* Check if the trap frame was edited */
387 if (__builtin_expect(!(TrapFrame
->SegCs
& FRAME_EDITED
), 0))
390 * An edited trap frame happens when we need to modify CS and/or ESP but
391 * don't actually have a ring transition. This happens when a kernelmode
392 * caller wants to perform an NtContinue to another kernel address, such
393 * as in the case of SEH (basically, a longjmp), or to a user address.
395 * Therefore, the CPU never saved CS/ESP on the stack because we did not
396 * get a trap frame due to a ring transition (there was no interrupt).
397 * Even if we didn't want to restore CS to a new value, a problem occurs
398 * due to the fact a normal RET would not work if we restored ESP since
399 * RET would then try to read the result off the stack.
401 * The NT kernel solves this by adding 12 bytes of stack to the exiting
402 * trap frame, in which EFLAGS, CS, and EIP are stored, and then saving
403 * the ESP that's being requested into the ErrorCode field. It will then
404 * exit with an IRET. This fixes both issues, because it gives the stack
405 * some space where to hold the return address and then end up with the
406 * wanted stack, and it uses IRET which allows a new CS to be inputted.
410 /* Set CS that is requested */
411 TrapFrame
->SegCs
= TrapFrame
->TempSegCs
;
413 /* First make space on requested stack */
414 ReturnStack
= (PULONG
)(TrapFrame
->TempEsp
- 12);
415 TrapFrame
->ErrCode
= (ULONG_PTR
)ReturnStack
;
417 /* Now copy IRET frame */
418 ReturnStack
[0] = TrapFrame
->Eip
;
419 ReturnStack
[1] = TrapFrame
->SegCs
;
420 ReturnStack
[2] = TrapFrame
->EFlags
;
422 /* Do special edited return */
423 KiEditedTrapReturn(TrapFrame
);
426 /* Check if this is a user trap */
427 if (__builtin_expect(KiUserTrap(TrapFrame
), 1)) /* Ring 3 is where we spend time */
429 /* Check if segments should be restored */
430 if (!SkipBits
.SkipSegments
)
432 /* Restore segments */
433 Ke386SetGs(TrapFrame
->SegGs
);
434 Ke386SetEs(TrapFrame
->SegEs
);
435 Ke386SetDs(TrapFrame
->SegDs
);
436 Ke386SetFs(TrapFrame
->SegFs
);
439 /* Always restore FS since it goes from KPCR to TEB */
440 Ke386SetFs(TrapFrame
->SegFs
);
443 /* Check for system call -- a system call skips volatiles! */
444 if (__builtin_expect(SkipBits
.SkipVolatiles
, 0)) /* More INTs than SYSCALLs */
446 /* Kernel call or user call? */
447 if (__builtin_expect(KiUserTrap(TrapFrame
), 1)) /* More Ring 3 than 0 */
449 /* Is SYSENTER supported and/or enabled, or are we stepping code? */
450 if (__builtin_expect((KiFastSystemCallDisable
) ||
451 (TrapFrame
->EFlags
& EFLAGS_TF
), 0))
454 KiSystemCallTrapReturn(TrapFrame
);
458 /* Restore user FS */
459 Ke386SetFs(KGDT_R3_TEB
| RPL_MASK
);
461 /* Remove interrupt flag */
462 TrapFrame
->EFlags
&= ~EFLAGS_INTERRUPT_MASK
;
463 __writeeflags(TrapFrame
->EFlags
);
465 /* Exit through SYSEXIT */
466 KiSystemCallSysExitReturn(TrapFrame
);
472 __writeeflags(TrapFrame
->EFlags
);
474 /* Call is kernel, so do a jump back since this wasn't a real INT */
475 KiSystemCallReturn(TrapFrame
);
480 /* Return from interrupt */
481 KiTrapReturn(TrapFrame
);
486 // Virtual 8086 Mode Optimized Trap Exit
490 KiExitV86Trap(IN PKTRAP_FRAME TrapFrame
)
496 Thread
= KeGetCurrentThread();
499 /* Turn off the alerted state for kernel mode */
500 Thread
->Alerted
[KernelMode
] = FALSE
;
502 /* Are there pending user APCs? */
503 if (__builtin_expect(!Thread
->ApcState
.UserApcPending
, 1)) break;
505 /* Raise to APC level and enable interrupts */
506 OldIrql
= KfRaiseIrql(APC_LEVEL
);
510 KiDeliverApc(UserMode
, NULL
, TrapFrame
);
512 /* Restore IRQL and disable interrupts once again */
513 KfLowerIrql(OldIrql
);
516 /* Return if this isn't V86 mode anymore */
517 if (__builtin_expect(TrapFrame
->EFlags
& EFLAGS_V86_MASK
, 0)) return;
520 /* If we got here, we're still in a valid V8086 context, so quit it */
521 if (__builtin_expect(TrapFrame
->Dr7
& ~DR7_RESERVED_MASK
, 0))
523 /* Not handled yet */
524 DbgPrint("Need Hardware Breakpoint Support!\n");
528 /* Return from interrupt */
529 KiTrapReturn(TrapFrame
);
533 // Virtual 8086 Mode Optimized Trap Entry
537 KiEnterV86Trap(IN PKTRAP_FRAME TrapFrame
)
539 /* Load correct registers */
540 Ke386SetFs(KGDT_R0_PCR
);
541 Ke386SetDs(KGDT_R3_DATA
| RPL_MASK
);
542 Ke386SetEs(KGDT_R3_DATA
| RPL_MASK
);
544 /* Save exception list and bogus previous mode */
545 TrapFrame
->PreviousPreviousMode
= -1;
546 TrapFrame
->ExceptionList
= KeGetPcr()->Tib
.ExceptionList
;
548 /* Clear direction flag */
549 Ke386ClearDirectionFlag();
551 /* Save DR7 and check for debugging */
552 TrapFrame
->Dr7
= __readdr(7);
553 if (__builtin_expect(TrapFrame
->Dr7
& ~DR7_RESERVED_MASK
, 0))
555 DbgPrint("Need Hardware Breakpoint Support!\n");
561 // Interrupt Trap Entry
565 KiEnterInterruptTrap(IN PKTRAP_FRAME TrapFrame
)
567 /* Set bogus previous mode */
568 TrapFrame
->PreviousPreviousMode
= -1;
570 /* Check for V86 mode */
571 if (__builtin_expect(TrapFrame
->EFlags
& EFLAGS_V86_MASK
, 0))
573 DbgPrint("Need V8086 Interrupt Support!\n");
577 /* Check if this wasn't kernel code */
578 if (__builtin_expect(TrapFrame
->SegCs
!= KGDT_R0_CODE
, 1)) /* Ring 3 is more common */
580 /* Save segments and then switch to correct ones */
581 TrapFrame
->SegFs
= Ke386GetFs();
582 TrapFrame
->SegGs
= Ke386GetGs();
583 TrapFrame
->SegDs
= Ke386GetDs();
584 TrapFrame
->SegEs
= Ke386GetEs();
585 Ke386SetFs(KGDT_R0_PCR
);
586 Ke386SetDs(KGDT_R3_DATA
| RPL_MASK
);
587 Ke386SetEs(KGDT_R3_DATA
| RPL_MASK
);
590 /* Save exception list and terminate it */
591 TrapFrame
->ExceptionList
= KeGetPcr()->Tib
.ExceptionList
;
592 KeGetPcr()->Tib
.ExceptionList
= EXCEPTION_CHAIN_END
;
595 TrapFrame
->ErrCode
= 0;
597 /* Clear direction flag */
598 Ke386ClearDirectionFlag();
600 /* Flush DR7 and check for debugging */
602 if (__builtin_expect(KeGetCurrentThread()->DispatcherHeader
.DebugActive
& 0xFF, 0))
604 DbgPrint("Need Hardware Breakpoint Support!\n");
608 /* Set debug header */
609 KiFillTrapFrameDebug(TrapFrame
);
613 // Generic Trap Entry
617 KiEnterTrap(IN PKTRAP_FRAME TrapFrame
)
622 * We really have to get a good DS/ES first before touching any data.
624 * These two reads will either go in a register (with optimizations ON) or
625 * a stack variable (which is on SS:ESP, guaranteed to be good/valid).
627 * Because the assembly is marked volatile, the order of instructions is
628 * as-is, otherwise the optimizer could simply get rid of our DS/ES.
633 Ke386SetDs(KGDT_R3_DATA
| RPL_MASK
);
634 Ke386SetEs(KGDT_R3_DATA
| RPL_MASK
);
635 TrapFrame
->SegDs
= Ds
;
636 TrapFrame
->SegEs
= Es
;
638 /* Now we can save the other segments and then switch to the correct FS */
639 TrapFrame
->SegFs
= Ke386GetFs();
640 TrapFrame
->SegGs
= Ke386GetGs();
641 Ke386SetFs(KGDT_R0_PCR
);
643 /* Save exception list and bogus previous mode */
644 TrapFrame
->PreviousPreviousMode
= -1;
645 TrapFrame
->ExceptionList
= KeGetPcr()->Tib
.ExceptionList
;
647 /* Check for V86 mode */
648 if (__builtin_expect(TrapFrame
->EFlags
& EFLAGS_V86_MASK
, 0))
650 /* Restore V8086 segments into Protected Mode segments */
651 TrapFrame
->SegFs
= TrapFrame
->V86Fs
;
652 TrapFrame
->SegGs
= TrapFrame
->V86Gs
;
653 TrapFrame
->SegDs
= TrapFrame
->V86Ds
;
654 TrapFrame
->SegEs
= TrapFrame
->V86Es
;
657 /* Clear direction flag */
658 Ke386ClearDirectionFlag();
660 /* Flush DR7 and check for debugging */
662 if (__builtin_expect(KeGetCurrentThread()->DispatcherHeader
.DebugActive
& 0xFF, 0))
664 DbgPrint("Need Hardware Breakpoint Support!\n");
668 /* Set debug header */
669 KiFillTrapFrameDebug(TrapFrame
);