2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/ke/i386/traphdlr.c
5 * PURPOSE: Kernel Trap Handlers
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
15 VOID __cdecl
KiFastCallEntry(VOID
);
16 VOID __cdecl
KiFastCallEntryWithSingleStep(VOID
);
18 extern PVOID FrRestore
;
19 VOID FASTCALL
Ke386LoadFpuState(IN PFX_SAVE_AREA SaveArea
);
21 /* GLOBALS ********************************************************************/
23 UCHAR KiTrapPrefixTable
[] =
26 0xF3, /* REP INS/OUTS */
38 UCHAR KiTrapIoTable
[] =
54 PFAST_SYSTEM_CALL_EXIT KiFastCallExitHandler
;
55 #if DBG && defined(_M_IX86) && !defined(_WINKD_)
56 PKDBG_PRESERVICEHOOK KeWin32PreServiceHook
= NULL
;
57 PKDBG_POSTSERVICEHOOK KeWin32PostServiceHook
= NULL
;
60 BOOLEAN StopChecking
= FALSE
;
64 /* TRAP EXIT CODE *************************************************************/
68 KiVdmTrap(IN PKTRAP_FRAME TrapFrame
)
70 /* Either the V8086 flag is on, or this is user-mode with a VDM */
71 return ((TrapFrame
->EFlags
& EFLAGS_V86_MASK
) ||
72 ((KiUserTrap(TrapFrame
)) && (PsGetCurrentProcess()->VdmObjects
)));
77 KiV86Trap(IN PKTRAP_FRAME TrapFrame
)
79 /* Check if the V8086 flag is on */
80 return ((TrapFrame
->EFlags
& EFLAGS_V86_MASK
) != 0);
85 KiIsFrameEdited(IN PKTRAP_FRAME TrapFrame
)
87 /* An edited frame changes esp. It is marked by clearing the bits
88 defined by FRAME_EDITED in the SegCs field of the trap frame */
89 return ((TrapFrame
->SegCs
& FRAME_EDITED
) == 0);
94 KiCommonExit(IN PKTRAP_FRAME TrapFrame
, BOOLEAN SkipPreviousMode
)
96 /* Disable interrupts until we return */
99 /* Check for APC delivery */
100 KiCheckForApcDelivery(TrapFrame
);
102 /* Restore the SEH handler chain */
103 KeGetPcr()->NtTib
.ExceptionList
= TrapFrame
->ExceptionList
;
105 /* Check if there are active debug registers */
106 if (__builtin_expect(TrapFrame
->Dr7
& ~DR7_RESERVED_MASK
, 0))
108 /* Check if the frame was from user mode or v86 mode */
109 if (KiUserTrap(TrapFrame
) ||
110 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
112 /* Handle debug registers */
113 KiHandleDebugRegistersOnTrapExit(TrapFrame
);
117 /* Debugging checks */
118 KiExitTrapDebugChecks(TrapFrame
, SkipPreviousMode
);
124 KiEoiHelper(IN PKTRAP_FRAME TrapFrame
)
126 /* Common trap exit code */
127 KiCommonExit(TrapFrame
, TRUE
);
129 /* Check if this was a V8086 trap */
130 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
) KiTrapReturnNoSegments(TrapFrame
);
132 /* Check for user mode exit */
133 if (KiUserTrap(TrapFrame
)) KiTrapReturn(TrapFrame
);
135 /* Check for edited frame */
136 if (KiIsFrameEdited(TrapFrame
)) KiEditedTrapReturn(TrapFrame
);
138 /* Check if we have single stepping enabled */
139 if (TrapFrame
->EFlags
& EFLAGS_TF
) KiTrapReturnNoSegments(TrapFrame
);
141 /* Exit the trap to kernel mode */
142 KiTrapReturnNoSegmentsRet8(TrapFrame
);
148 KiServiceExit(IN PKTRAP_FRAME TrapFrame
,
151 ASSERT((TrapFrame
->EFlags
& EFLAGS_V86_MASK
) == 0);
152 ASSERT(!KiIsFrameEdited(TrapFrame
));
154 /* Copy the status into EAX */
155 TrapFrame
->Eax
= Status
;
157 /* Common trap exit code */
158 KiCommonExit(TrapFrame
, FALSE
);
160 /* Restore previous mode */
161 KeGetCurrentThread()->PreviousMode
= (CCHAR
)TrapFrame
->PreviousPreviousMode
;
163 /* Check for user mode exit */
164 if (KiUserTrap(TrapFrame
))
166 /* Check if we were single stepping */
167 if (TrapFrame
->EFlags
& EFLAGS_TF
)
169 /* Must use the IRET handler */
170 KiSystemCallTrapReturn(TrapFrame
);
174 /* We can use the sysexit handler */
175 KiFastCallExitHandler(TrapFrame
);
180 /* Exit to kernel mode */
181 KiSystemCallReturn(TrapFrame
);
187 KiServiceExit2(IN PKTRAP_FRAME TrapFrame
)
189 /* Common trap exit code */
190 KiCommonExit(TrapFrame
, FALSE
);
192 /* Restore previous mode */
193 KeGetCurrentThread()->PreviousMode
= (CCHAR
)TrapFrame
->PreviousPreviousMode
;
195 /* Check if this was a V8086 trap */
196 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
) KiTrapReturnNoSegments(TrapFrame
);
198 /* Check for user mode exit */
199 if (KiUserTrap(TrapFrame
)) KiTrapReturn(TrapFrame
);
201 /* Check for edited frame */
202 if (KiIsFrameEdited(TrapFrame
)) KiEditedTrapReturn(TrapFrame
);
204 /* Check if we have single stepping enabled */
205 if (TrapFrame
->EFlags
& EFLAGS_TF
) KiTrapReturnNoSegments(TrapFrame
);
207 /* Exit the trap to kernel mode */
208 KiTrapReturnNoSegmentsRet8(TrapFrame
);
212 /* TRAP HANDLERS **************************************************************/
217 KiDebugHandler(IN PKTRAP_FRAME TrapFrame
,
222 /* Check for VDM trap */
223 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
225 /* Enable interrupts if the trap came from user-mode */
226 if (KiUserTrap(TrapFrame
)) _enable();
228 /* Dispatch the exception */
229 KiDispatchExceptionFromTrapFrame(STATUS_BREAKPOINT
,
242 KiNpxHandler(IN PKTRAP_FRAME TrapFrame
,
244 IN PFX_SAVE_AREA SaveArea
)
246 ULONG Cr0
, Mask
, Error
, ErrorOffset
, DataOffset
;
248 /* Check for VDM trap */
249 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
251 /* Check for kernel trap */
252 if (!KiUserTrap(TrapFrame
))
254 /* Kernel might've tripped a delayed error */
255 SaveArea
->Cr0NpxState
|= CR0_TS
;
257 /* Only valid if it happened during a restore */
258 if ((PVOID
)TrapFrame
->Eip
== FrRestore
)
260 /* It did, so just skip the instruction */
261 TrapFrame
->Eip
+= 3; /* Size of FRSTOR instruction */
262 KiEoiHelper(TrapFrame
);
266 /* User or kernel trap -- check if we need to unload the current state */
267 if (Thread
->NpxState
== NPX_STATE_LOADED
)
271 Cr0
&= ~(CR0_MP
| CR0_EM
| CR0_TS
);
275 Ke386SaveFpuState(SaveArea
);
277 /* Mark CR0 state dirty */
278 Cr0
|= NPX_STATE_NOT_LOADED
;
279 Cr0
|= SaveArea
->Cr0NpxState
;
282 /* Update NPX state */
283 Thread
->NpxState
= NPX_STATE_NOT_LOADED
;
284 KeGetCurrentPrcb()->NpxThread
= NULL
;
287 /* Clear the TS bit and re-enable interrupts */
288 SaveArea
->Cr0NpxState
&= ~CR0_TS
;
291 /* Check if we should get the FN or FX error */
292 if (KeI386FxsrPresent
)
295 Mask
= SaveArea
->U
.FxArea
.ControlWord
;
296 Error
= SaveArea
->U
.FxArea
.StatusWord
;
298 /* Get the FPU exception address too */
299 ErrorOffset
= SaveArea
->U
.FxArea
.ErrorOffset
;
300 DataOffset
= SaveArea
->U
.FxArea
.DataOffset
;
305 Mask
= SaveArea
->U
.FnArea
.ControlWord
;
306 Error
= SaveArea
->U
.FnArea
.StatusWord
;
308 /* Get the FPU exception address too */
309 ErrorOffset
= SaveArea
->U
.FnArea
.ErrorOffset
;
310 DataOffset
= SaveArea
->U
.FnArea
.DataOffset
;
313 /* Get legal exceptions that software should handle */
314 Mask
&= (FSW_INVALID_OPERATION
|
322 /* Check for invalid operation */
323 if (Error
& FSW_INVALID_OPERATION
)
326 * Now check if this is actually a Stack Fault. This is needed because
327 * on x86 the Invalid Operation error is set for Stack Check faults as well.
329 if (Error
& FSW_STACK_FAULT
)
331 /* Issue stack check fault */
332 KiDispatchException2Args(STATUS_FLOAT_STACK_CHECK
,
340 /* This is an invalid operation fault after all, so raise that instead */
341 KiDispatchException1Args(STATUS_FLOAT_INVALID_OPERATION
,
348 /* Check for divide by zero */
349 if (Error
& FSW_ZERO_DIVIDE
)
352 KiDispatchException1Args(STATUS_FLOAT_DIVIDE_BY_ZERO
,
358 /* Check for denormal */
359 if (Error
& FSW_DENORMAL
)
362 KiDispatchException1Args(STATUS_FLOAT_INVALID_OPERATION
,
368 /* Check for overflow */
369 if (Error
& FSW_OVERFLOW
)
372 KiDispatchException1Args(STATUS_FLOAT_OVERFLOW
,
378 /* Check for underflow */
379 if (Error
& FSW_UNDERFLOW
)
382 KiDispatchException1Args(STATUS_FLOAT_UNDERFLOW
,
388 /* Check for precision fault */
389 if (Error
& FSW_PRECISION
)
392 KiDispatchException1Args(STATUS_FLOAT_INEXACT_RESULT
,
398 /* Unknown FPU fault */
399 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 1, Error
, 0, 0, TrapFrame
);
405 KiTrap00Handler(IN PKTRAP_FRAME TrapFrame
)
407 /* Save trap frame */
408 KiEnterTrap(TrapFrame
);
410 /* Check for VDM trap */
411 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
413 /* Enable interrupts */
416 /* Dispatch the exception */
417 KiDispatchException0Args(STATUS_INTEGER_DIVIDE_BY_ZERO
,
425 KiTrap01Handler(IN PKTRAP_FRAME TrapFrame
)
427 /* Save trap frame */
428 KiEnterTrap(TrapFrame
);
430 /* Check for VDM trap */
431 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
433 /* Check if this was a single step after sysenter */
434 if (TrapFrame
->Eip
== (ULONG
)KiFastCallEntry
)
436 /* Disable single stepping */
437 TrapFrame
->EFlags
&= ~EFLAGS_TF
;
439 /* Re-enter at the alternative sysenter entry point */
440 TrapFrame
->Eip
= (ULONG
)KiFastCallEntryWithSingleStep
;
443 KiEoiHelper(TrapFrame
);
446 /* Enable interrupts if the trap came from user-mode */
447 if (KiUserTrap(TrapFrame
)) _enable();
449 /* Mask out trap flag and dispatch the exception */
450 TrapFrame
->EFlags
&= ~EFLAGS_TF
;
451 KiDispatchException0Args(STATUS_SINGLE_STEP
,
465 KTRAP_FRAME TrapFrame
;
469 // In some sort of strange recursion case, we might end up here with the IF
470 // flag incorrectly on the interrupt frame -- during a normal NMI this would
471 // normally already be set.
473 // For sanity's sake, make sure interrupts are disabled for sure.
474 // NMIs will already be since the CPU does it for us.
479 // Get the current TSS, thread, and process
482 Thread
= ((PKIPCR
)PCR
)->PrcbData
.CurrentThread
;
483 Process
= Thread
->ApcState
.Process
;
486 // Save data usually not in the TSS
488 Tss
->CR3
= Process
->DirectoryTableBase
[0];
489 Tss
->IoMapBase
= Process
->IopmOffset
;
490 Tss
->LDT
= Process
->LdtDescriptor
.LimitLow
? KGDT_LDT
: 0;
493 // Now get the base address of the NMI TSS
495 TssGdt
= &((PKIPCR
)KeGetPcr())->GDT
[KGDT_NMI_TSS
/ sizeof(KGDTENTRY
)];
496 NmiTss
= (PKTSS
)(ULONG_PTR
)(TssGdt
->BaseLow
|
497 TssGdt
->HighWord
.Bytes
.BaseMid
<< 16 |
498 TssGdt
->HighWord
.Bytes
.BaseHi
<< 24);
501 // Switch to it and activate it, masking off the nested flag
503 // Note that in reality, we are already on the NMI tss -- we just need to
504 // update the PCR to reflect this
507 __writeeflags(__readeflags() &~ EFLAGS_NESTED_TASK
);
508 TssGdt
->HighWord
.Bits
.Dpl
= 0;
509 TssGdt
->HighWord
.Bits
.Pres
= 1;
510 TssGdt
->HighWord
.Bits
.Type
= I386_TSS
;
513 // Now build the trap frame based on the original TSS
515 // The CPU does a hardware "Context switch" / task switch of sorts and so it
516 // takes care of saving our context in the normal TSS.
518 // We just have to go get the values...
520 RtlZeroMemory(&TrapFrame
, sizeof(KTRAP_FRAME
));
521 TrapFrame
.HardwareSegSs
= Tss
->Ss0
;
522 TrapFrame
.HardwareEsp
= Tss
->Esp0
;
523 TrapFrame
.EFlags
= Tss
->EFlags
;
524 TrapFrame
.SegCs
= Tss
->Cs
;
525 TrapFrame
.Eip
= Tss
->Eip
;
526 TrapFrame
.Ebp
= Tss
->Ebp
;
527 TrapFrame
.Ebx
= Tss
->Ebx
;
528 TrapFrame
.Esi
= Tss
->Esi
;
529 TrapFrame
.Edi
= Tss
->Edi
;
530 TrapFrame
.SegFs
= Tss
->Fs
;
531 TrapFrame
.ExceptionList
= PCR
->NtTib
.ExceptionList
;
532 TrapFrame
.PreviousPreviousMode
= (ULONG
)-1;
533 TrapFrame
.Eax
= Tss
->Eax
;
534 TrapFrame
.Ecx
= Tss
->Ecx
;
535 TrapFrame
.Edx
= Tss
->Edx
;
536 TrapFrame
.SegDs
= Tss
->Ds
;
537 TrapFrame
.SegEs
= Tss
->Es
;
538 TrapFrame
.SegGs
= Tss
->Gs
;
539 TrapFrame
.DbgEip
= Tss
->Eip
;
540 TrapFrame
.DbgEbp
= Tss
->Ebp
;
543 // Store the trap frame in the KPRCB
545 KiSaveProcessorState(&TrapFrame
, NULL
);
548 // Call any registered NMI handlers and see if they handled it or not
553 // They did not, so call the platform HAL routine to bugcheck the system
555 // Make sure the HAL believes it's running at HIGH IRQL... we can't use
556 // the normal APIs here as playing with the IRQL could change the system
560 PCR
->Irql
= HIGH_LEVEL
;
566 // Although the CPU disabled NMIs, we just did a BIOS Call, which could've
567 // totally changed things.
569 // We have to make sure we're still in our original NMI -- a nested NMI
570 // will point back to the NMI TSS, and in that case we're hosed.
572 if (PCR
->TSS
->Backlink
!= KGDT_NMI_TSS
)
575 // Restore original TSS
580 // Set it back to busy
582 TssGdt
->HighWord
.Bits
.Dpl
= 0;
583 TssGdt
->HighWord
.Bits
.Pres
= 1;
584 TssGdt
->HighWord
.Bits
.Type
= I386_ACTIVE_TSS
;
587 // Restore nested flag
589 __writeeflags(__readeflags() | EFLAGS_NESTED_TASK
);
592 // Handled, return from interrupt
598 // Unhandled: crash the system
600 KiSystemFatalException(EXCEPTION_NMI
, NULL
);
606 KiTrap03Handler(IN PKTRAP_FRAME TrapFrame
)
608 /* Save trap frame */
609 KiEnterTrap(TrapFrame
);
611 /* Continue with the common handler */
612 KiDebugHandler(TrapFrame
, BREAKPOINT_BREAK
, 0, 0);
618 KiTrap04Handler(IN PKTRAP_FRAME TrapFrame
)
620 /* Save trap frame */
621 KiEnterTrap(TrapFrame
);
623 /* Check for VDM trap */
624 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
626 /* Enable interrupts */
629 /* Dispatch the exception */
630 KiDispatchException0Args(STATUS_INTEGER_OVERFLOW
,
638 KiTrap05Handler(IN PKTRAP_FRAME TrapFrame
)
640 /* Save trap frame */
641 KiEnterTrap(TrapFrame
);
643 /* Check for VDM trap */
644 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
646 /* Check for kernel-mode fault */
647 if (!KiUserTrap(TrapFrame
)) KiSystemFatalException(EXCEPTION_BOUND_CHECK
, TrapFrame
);
649 /* Enable interrupts */
652 /* Dispatch the exception */
653 KiDispatchException0Args(STATUS_ARRAY_BOUNDS_EXCEEDED
,
661 KiTrap06Handler(IN PKTRAP_FRAME TrapFrame
)
667 /* Check for V86 GPF */
668 if (__builtin_expect(KiV86Trap(TrapFrame
), 1))
671 KiEnterV86Trap(TrapFrame
);
673 /* Must be a VDM process */
674 if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects
, 0))
676 /* Enable interrupts */
679 /* Setup illegal instruction fault */
680 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION
,
685 /* Go to APC level */
686 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
690 if (!VdmDispatchBop(TrapFrame
))
692 /* Should only happen in VDM mode */
693 UNIMPLEMENTED_FATAL();
696 /* Bring IRQL back */
697 KeLowerIrql(OldIrql
);
700 /* Do a quick V86 exit if possible */
701 KiExitV86Trap(TrapFrame
);
704 /* Save trap frame */
705 KiEnterTrap(TrapFrame
);
707 /* Enable interrupts */
708 Instruction
= (PUCHAR
)TrapFrame
->Eip
;
711 /* Check for user trap */
712 if (KiUserTrap(TrapFrame
))
716 /* Scan next 4 opcodes */
717 for (i
= 0; i
< 4; i
++)
719 /* Check for LOCK instruction */
720 if (Instruction
[i
] == 0xF0)
722 /* Send invalid lock sequence exception */
723 KiDispatchException0Args(STATUS_INVALID_LOCK_SEQUENCE
,
729 /* FIXME: SEH ends here */
732 /* Kernel-mode or user-mode fault (but not LOCK) */
733 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION
,
742 KiTrap07Handler(IN PKTRAP_FRAME TrapFrame
)
744 PKTHREAD Thread
, NpxThread
;
745 PFX_SAVE_AREA SaveArea
, NpxSaveArea
;
748 /* Save trap frame */
749 KiEnterTrap(TrapFrame
);
751 /* Try to handle NPX delay load */
754 /* Get the current thread */
755 Thread
= KeGetCurrentThread();
757 /* Get the NPX frame */
758 SaveArea
= KiGetThreadNpxArea(Thread
);
760 /* Check if emulation is enabled */
761 if (SaveArea
->Cr0NpxState
& CR0_EM
)
763 /* Not implemented */
764 UNIMPLEMENTED_FATAL();
767 /* Save CR0 and check NPX state */
769 if (Thread
->NpxState
!= NPX_STATE_LOADED
)
772 Cr0
&= ~(CR0_MP
| CR0_EM
| CR0_TS
);
775 /* Get the NPX thread */
776 NpxThread
= KeGetCurrentPrcb()->NpxThread
;
779 /* Get the NPX frame */
780 NpxSaveArea
= KiGetThreadNpxArea(NpxThread
);
783 Ke386SaveFpuState(NpxSaveArea
);
785 /* Update NPX state */
786 NpxThread
->NpxState
= NPX_STATE_NOT_LOADED
;
790 Ke386LoadFpuState(SaveArea
);
792 /* Update NPX state */
793 Thread
->NpxState
= NPX_STATE_LOADED
;
794 KeGetCurrentPrcb()->NpxThread
= Thread
;
796 /* Enable interrupts */
799 /* Check if CR0 needs to be reloaded due to context switch */
800 if (!SaveArea
->Cr0NpxState
) KiEoiHelper(TrapFrame
);
802 /* Otherwise, we need to reload CR0, disable interrupts */
807 Cr0
|= SaveArea
->Cr0NpxState
;
810 /* Now restore interrupts and check for TS */
812 if (Cr0
& CR0_TS
) KiEoiHelper(TrapFrame
);
814 /* We're still here -- clear TS and try again */
815 __writecr0(__readcr0() &~ CR0_TS
);
820 /* This is an actual fault, not a lack of FPU state */
825 /* TS should not be set */
829 * If it's incorrectly set, then maybe the state is actually still valid
830 * but we could have lost track of that due to a BIOS call.
831 * Make sure MP is still set, which should verify the theory.
835 /* Indeed, the state is actually still valid, so clear TS */
836 __writecr0(__readcr0() &~ CR0_TS
);
837 KiEoiHelper(TrapFrame
);
840 /* Otherwise, something strange is going on */
841 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 2, Cr0
, 0, 0, TrapFrame
);
844 /* It's not a delayed load, so process this trap as an NPX fault */
845 KiNpxHandler(TrapFrame
, Thread
, SaveArea
);
851 KiTrap08Handler(IN PKTRAP_FRAME TrapFrame
)
853 /* FIXME: Not handled */
854 KiSystemFatalException(EXCEPTION_DOUBLE_FAULT
, TrapFrame
);
860 KiTrap09Handler(IN PKTRAP_FRAME TrapFrame
)
862 /* Save trap frame */
863 KiEnterTrap(TrapFrame
);
865 /* Enable interrupts and kill the system */
867 KiSystemFatalException(EXCEPTION_NPX_OVERRUN
, TrapFrame
);
873 KiTrap0AHandler(IN PKTRAP_FRAME TrapFrame
)
875 /* Save trap frame */
876 KiEnterTrap(TrapFrame
);
878 /* Check for VDM trap */
879 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
881 /* Kill the system */
882 KiSystemFatalException(EXCEPTION_INVALID_TSS
, TrapFrame
);
888 KiTrap0BHandler(IN PKTRAP_FRAME TrapFrame
)
890 /* Save trap frame */
891 KiEnterTrap(TrapFrame
);
893 /* FIXME: Kill the system */
895 KiSystemFatalException(EXCEPTION_SEGMENT_NOT_PRESENT
, TrapFrame
);
901 KiTrap0CHandler(IN PKTRAP_FRAME TrapFrame
)
903 /* Save trap frame */
904 KiEnterTrap(TrapFrame
);
906 /* FIXME: Kill the system */
908 KiSystemFatalException(EXCEPTION_STACK_FAULT
, TrapFrame
);
914 KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame
)
917 BOOLEAN Privileged
= FALSE
;
919 UCHAR Instruction
= 0;
922 /* Check for V86 GPF */
923 if (__builtin_expect(KiV86Trap(TrapFrame
), 1))
926 KiEnterV86Trap(TrapFrame
);
928 /* Must be a VDM process */
929 if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects
, 0))
931 /* Enable interrupts */
934 /* Setup illegal instruction fault */
935 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION
,
940 /* Go to APC level */
941 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
944 /* Handle the V86 opcode */
945 if (__builtin_expect(Ki386HandleOpcodeV86(TrapFrame
) == 0xFF, 0))
947 /* Should only happen in VDM mode */
948 UNIMPLEMENTED_FATAL();
951 /* Bring IRQL back */
952 KeLowerIrql(OldIrql
);
955 /* Do a quick V86 exit if possible */
956 KiExitV86Trap(TrapFrame
);
959 /* Save trap frame */
960 KiEnterTrap(TrapFrame
);
962 /* Check for user-mode GPF */
963 if (KiUserTrap(TrapFrame
))
965 /* Should not be VDM */
966 ASSERT(KiVdmTrap(TrapFrame
) == FALSE
);
968 /* Enable interrupts and check error code */
970 if (!TrapFrame
->ErrCode
)
973 Instructions
= (PUCHAR
)TrapFrame
->Eip
;
975 /* Scan next 15 bytes */
976 for (i
= 0; i
< 15; i
++)
978 /* Skip prefix instructions */
979 for (j
= 0; j
< sizeof(KiTrapPrefixTable
); j
++)
981 /* Is this a prefix instruction? */
982 if (Instructions
[i
] == KiTrapPrefixTable
[j
])
989 /* Is this NOT any prefix instruction? */
990 if (j
== sizeof(KiTrapPrefixTable
))
992 /* We can go ahead and handle the fault now */
993 Instruction
= Instructions
[i
];
998 /* If all we found was prefixes, then this instruction is too long */
1001 /* Setup illegal instruction fault */
1002 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION
,
1007 /* Check for privileged instructions */
1008 DPRINT("Instruction (%lu) at fault: %lx %lx %lx %lx\n",
1011 Instructions
[i
+ 1],
1012 Instructions
[i
+ 2],
1013 Instructions
[i
+ 3]);
1014 if (Instruction
== 0xF4) // HLT
1016 /* HLT is privileged */
1019 else if (Instruction
== 0x0F)
1021 /* Test if it's any of the privileged two-byte opcodes */
1022 if (((Instructions
[i
+ 1] == 0x00) && // LLDT or LTR
1023 (((Instructions
[i
+ 2] & 0x38) == 0x10) || // LLDT
1024 (Instructions
[i
+ 2] == 0x18))) || // LTR
1025 ((Instructions
[i
+ 1] == 0x01) && // LGDT or LIDT or LMSW
1026 (((Instructions
[i
+ 2] & 0x38) == 0x10) || // LGDT
1027 (Instructions
[i
+ 2] == 0x18) || // LIDT
1028 (Instructions
[i
+ 2] == 0x30))) || // LMSW
1029 (Instructions
[i
+ 1] == 0x08) || // INVD
1030 (Instructions
[i
+ 1] == 0x09) || // WBINVD
1031 (Instructions
[i
+ 1] == 0x35) || // SYSEXIT
1032 (Instructions
[i
+ 1] == 0x21) || // MOV DR, XXX
1033 (Instructions
[i
+ 1] == 0x06) || // CLTS
1034 (Instructions
[i
+ 1] == 0x20) || // MOV CR, XXX
1035 (Instructions
[i
+ 1] == 0x22) || // MOV XXX, CR
1036 (Instructions
[i
+ 1] == 0x23) || // MOV YYY, DR
1037 (Instructions
[i
+ 1] == 0x30) || // WRMSR
1038 (Instructions
[i
+ 1] == 0x33)) // RDPMC
1039 // INVLPG, INVLPGA, SYSRET
1041 /* These are all privileged */
1047 /* Get the IOPL and compare with the RPL mask */
1048 Iopl
= (TrapFrame
->EFlags
& EFLAGS_IOPL
) >> 12;
1049 if ((TrapFrame
->SegCs
& RPL_MASK
) > Iopl
)
1051 /* I/O privilege error -- check for known instructions */
1052 if ((Instruction
== 0xFA) || (Instruction
== 0xFB)) // CLI or STI
1054 /* These are privileged */
1059 /* Last hope: an IN/OUT instruction */
1060 for (j
= 0; j
< sizeof(KiTrapIoTable
); j
++)
1062 /* Is this an I/O instruction? */
1063 if (Instruction
== KiTrapIoTable
[j
])
1065 /* Then it's privileged */
1074 /* So now... was the instruction privileged or not? */
1077 /* Whew! We have a privileged instruction, so dispatch the fault */
1078 KiDispatchException0Args(STATUS_PRIVILEGED_INSTRUCTION
,
1084 /* If we got here, send an access violation */
1085 KiDispatchException2Args(STATUS_ACCESS_VIOLATION
,
1093 * Check for a fault during checking of the user instruction.
1095 * Note that the SEH handler will catch invalid EIP, but we could be dealing
1096 * with an invalid CS, which will generate another GPF instead.
1099 if (((PVOID
)TrapFrame
->Eip
>= (PVOID
)KiTrap0DHandler
) &&
1100 ((PVOID
)TrapFrame
->Eip
< (PVOID
)KiTrap0DHandler
))
1102 /* Not implemented */
1103 UNIMPLEMENTED_FATAL();
1107 * NOTE: The ASM trap exit code would restore segment registers by doing
1108 * a POP <SEG>, which could cause an invalid segment if someone had messed
1109 * with the segment values.
1111 * Another case is a bogus SS, which would hit a GPF when doing the iret.
1112 * This could only be done through a buggy or malicious driver, or perhaps
1113 * the kernel debugger.
1115 * The kernel normally restores the "true" segment if this happens.
1117 * However, since we're restoring in C, not ASM, we can't detect
1118 * POP <SEG> since the actual instructions will be different.
1120 * A better technique would be to check the EIP and somehow edit the
1121 * trap frame before restarting the instruction -- but we would need to
1122 * know the extract instruction that was used first.
1124 * We could force a special instrinsic to use stack instructions, or write
1125 * a simple instruction length checker.
1127 * Nevertheless, this is a lot of work for the purpose of avoiding a crash
1128 * when the user is purposedly trying to create one from kernel-mode, so
1129 * we should probably table this for now since it's not a "real" issue.
1133 * NOTE2: Another scenario is the IRET during a V8086 restore (BIOS Call)
1134 * which will cause a GPF since the trap frame is a total mess (on purpose)
1135 * as built in KiEnterV86Mode.
1137 * The idea is to scan for IRET, scan for the known EIP adress, validate CS
1138 * and then manually issue a jump to the V8086 return EIP.
1140 Instructions
= (PUCHAR
)TrapFrame
->Eip
;
1141 if (Instructions
[0] == 0xCF)
1144 * Some evil shit is going on here -- this is not the SS:ESP you're
1145 * looking for! Instead, this is actually CS:EIP you're looking at!
1146 * Why? Because part of the trap frame actually corresponds to the IRET
1147 * stack during the trap exit!
1149 if ((TrapFrame
->HardwareEsp
== (ULONG
)Ki386BiosCallReturnAddress
) &&
1150 (TrapFrame
->HardwareSegSs
== (KGDT_R0_CODE
| RPL_MASK
)))
1152 /* Exit the V86 trap! */
1153 Ki386BiosCallReturnAddress(TrapFrame
);
1157 /* Otherwise, this is another kind of IRET fault */
1158 UNIMPLEMENTED_FATAL();
1162 /* So since we're not dealing with the above case, check for RDMSR/WRMSR */
1163 if ((Instructions
[0] == 0xF) && // 2-byte opcode
1164 ((Instructions
[1] == 0x32) || // RDMSR
1165 (Instructions
[1] == 0x30))) // WRMSR
1167 /* Unknown CPU MSR, so raise an access violation */
1168 KiDispatchException0Args(STATUS_ACCESS_VIOLATION
,
1173 /* Check for lazy segment load */
1174 if (TrapFrame
->SegDs
!= (KGDT_R3_DATA
| RPL_MASK
))
1177 TrapFrame
->SegDs
= (KGDT_R3_DATA
| RPL_MASK
);
1179 else if (TrapFrame
->SegEs
!= (KGDT_R3_DATA
| RPL_MASK
))
1182 TrapFrame
->SegEs
= (KGDT_R3_DATA
| RPL_MASK
);
1186 /* Whatever it is, we can't handle it */
1187 KiSystemFatalException(EXCEPTION_GP_FAULT
, TrapFrame
);
1190 /* Return to where we came from */
1191 KiTrapReturn(TrapFrame
);
1197 KiTrap0EHandler(IN PKTRAP_FRAME TrapFrame
)
1201 BOOLEAN StoreInstruction
;
1205 /* Save trap frame */
1206 KiEnterTrap(TrapFrame
);
1208 /* Check if this is the base frame */
1209 Thread
= KeGetCurrentThread();
1210 if (KeGetTrapFrame(Thread
) != TrapFrame
)
1212 /* It isn't, check if this is a second nested frame */
1213 if (((ULONG_PTR
)KeGetTrapFrame(Thread
) - (ULONG_PTR
)TrapFrame
) <=
1214 FIELD_OFFSET(KTRAP_FRAME
, EFlags
))
1216 /* The stack is somewhere in between frames, we need to fix it */
1217 UNIMPLEMENTED_FATAL();
1224 /* Enable interrupts */
1227 /* Interpret the error code */
1228 Present
= (TrapFrame
->ErrCode
& 1) != 0;
1229 StoreInstruction
= (TrapFrame
->ErrCode
& 2) != 0;
1231 /* Check if we came in with interrupts disabled */
1232 if (!(TrapFrame
->EFlags
& EFLAGS_INTERRUPT_MASK
))
1234 /* This is completely illegal, bugcheck the system */
1235 KeBugCheckWithTf(IRQL_NOT_LESS_OR_EQUAL
,
1243 /* Check for S-LIST fault in kernel mode */
1244 if (TrapFrame
->Eip
== (ULONG_PTR
)ExpInterlockedPopEntrySListFault
)
1246 PSLIST_HEADER SListHeader
;
1248 /* Sanity check that the assembly is correct:
1249 This must be mov ebx, [eax]
1250 Followed by cmpxchg8b [ebp] */
1251 ASSERT((((UCHAR
*)TrapFrame
->Eip
)[0] == 0x8B) &&
1252 (((UCHAR
*)TrapFrame
->Eip
)[1] == 0x18) &&
1253 (((UCHAR
*)TrapFrame
->Eip
)[2] == 0x0F) &&
1254 (((UCHAR
*)TrapFrame
->Eip
)[3] == 0xC7) &&
1255 (((UCHAR
*)TrapFrame
->Eip
)[4] == 0x4D) &&
1256 (((UCHAR
*)TrapFrame
->Eip
)[5] == 0x00));
1258 /* Get the pointer to the SLIST_HEADER */
1259 SListHeader
= (PSLIST_HEADER
)TrapFrame
->Ebp
;
1261 /* Check if the Next member of the SLIST_HEADER was changed */
1262 if (SListHeader
->Next
.Next
!= (PSLIST_ENTRY
)TrapFrame
->Eax
)
1264 /* Restart the operation */
1265 TrapFrame
->Eip
= (ULONG_PTR
)ExpInterlockedPopEntrySListResume
;
1267 /* Continue execution */
1268 KiEoiHelper(TrapFrame
);
1273 /* Do what windows does and issue an invalid access violation */
1274 KiDispatchException2Args(KI_EXCEPTION_ACCESS_VIOLATION
,
1283 /* Call the access fault handler */
1284 Status
= MmAccessFault(Present
,
1286 KiUserTrap(TrapFrame
),
1288 if (NT_SUCCESS(Status
))
1291 /* Check whether the kernel debugger has owed breakpoints to be inserted */
1292 KdSetOwedBreakpoints();
1294 /* We succeeded, return */
1295 KiEoiHelper(TrapFrame
);
1298 /* Check for syscall fault */
1300 if ((TrapFrame
->Eip
== (ULONG_PTR
)CopyParams
) ||
1301 (TrapFrame
->Eip
== (ULONG_PTR
)ReadBatch
))
1303 /* Not yet implemented */
1304 UNIMPLEMENTED_FATAL();
1308 /* Check for VDM trap */
1309 if (KiVdmTrap(TrapFrame
))
1311 DPRINT1("VDM PAGE FAULT at %lx:%lx for address %lx\n",
1312 TrapFrame
->SegCs
, TrapFrame
->Eip
, Cr2
);
1313 if (VdmDispatchPageFault(TrapFrame
))
1315 /* Return and end VDM execution */
1316 DPRINT1("VDM page fault with status 0x%lx resolved\n", Status
);
1317 KiEoiHelper(TrapFrame
);
1319 DPRINT1("VDM page fault with status 0x%lx NOT resolved\n", Status
);
1322 /* Either kernel or user trap (non VDM) so dispatch exception */
1323 if (Status
== STATUS_ACCESS_VIOLATION
)
1325 /* This status code is repurposed so we can recognize it later */
1326 KiDispatchException2Args(KI_EXCEPTION_ACCESS_VIOLATION
,
1332 else if ((Status
== STATUS_GUARD_PAGE_VIOLATION
) ||
1333 (Status
== STATUS_STACK_OVERFLOW
))
1335 /* These faults only have two parameters */
1336 KiDispatchException2Args(Status
,
1343 /* Only other choice is an in-page error, with 3 parameters */
1344 KiDispatchExceptionFromTrapFrame(STATUS_IN_PAGE_ERROR
,
1357 KiTrap0FHandler(IN PKTRAP_FRAME TrapFrame
)
1359 /* Save trap frame */
1360 KiEnterTrap(TrapFrame
);
1362 /* FIXME: Kill the system */
1364 KiSystemFatalException(EXCEPTION_RESERVED_TRAP
, TrapFrame
);
1370 KiTrap10Handler(IN PKTRAP_FRAME TrapFrame
)
1373 PFX_SAVE_AREA SaveArea
;
1375 /* Save trap frame */
1376 KiEnterTrap(TrapFrame
);
1378 /* Check if this is the NPX thrad */
1379 Thread
= KeGetCurrentThread();
1380 SaveArea
= KiGetThreadNpxArea(Thread
);
1381 if (Thread
!= KeGetCurrentPrcb()->NpxThread
)
1383 /* It isn't, enable interrupts and set delayed error */
1385 SaveArea
->Cr0NpxState
|= CR0_TS
;
1388 KiEoiHelper(TrapFrame
);
1391 /* Otherwise, proceed with NPX fault handling */
1392 KiNpxHandler(TrapFrame
, Thread
, SaveArea
);
1398 KiTrap11Handler(IN PKTRAP_FRAME TrapFrame
)
1400 /* Save trap frame */
1401 KiEnterTrap(TrapFrame
);
1403 /* Enable interrupts and kill the system */
1405 KiSystemFatalException(EXCEPTION_ALIGNMENT_CHECK
, TrapFrame
);
1411 KiTrap13Handler(IN PKTRAP_FRAME TrapFrame
)
1414 PFX_SAVE_AREA SaveArea
;
1415 ULONG Cr0
, MxCsrMask
, Error
;
1417 /* Save trap frame */
1418 KiEnterTrap(TrapFrame
);
1420 /* Check if this is the NPX thrad */
1421 Thread
= KeGetCurrentThread();
1422 if (Thread
!= KeGetCurrentPrcb()->NpxThread
)
1424 /* It isn't, kill the system */
1425 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 13, (ULONG_PTR
)Thread
, 0, 0, TrapFrame
);
1428 /* Get the NPX frame */
1429 SaveArea
= KiGetThreadNpxArea(Thread
);
1431 /* Check for VDM trap */
1432 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
1434 /* Check for user trap */
1435 if (!KiUserTrap(TrapFrame
))
1437 /* Kernel should not fault on XMMI */
1438 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 13, 0, 0, 2, TrapFrame
);
1443 Cr0
&= ~(CR0_MP
| CR0_EM
| CR0_TS
);
1446 /* Save FPU state */
1447 Ke386SaveFpuState(SaveArea
);
1449 /* Mark CR0 state dirty */
1450 Cr0
|= NPX_STATE_NOT_LOADED
;
1451 Cr0
|= SaveArea
->Cr0NpxState
;
1454 /* Update NPX state */
1455 Thread
->NpxState
= NPX_STATE_NOT_LOADED
;
1456 KeGetCurrentPrcb()->NpxThread
= NULL
;
1458 /* Clear the TS bit and re-enable interrupts */
1459 SaveArea
->Cr0NpxState
&= ~CR0_TS
;
1462 /* Now look at MxCsr to get the mask of errors we should care about */
1463 MxCsrMask
= ~((USHORT
)SaveArea
->U
.FxArea
.MXCsr
>> 7);
1465 /* Get legal exceptions that software should handle */
1466 Error
= (USHORT
)SaveArea
->U
.FxArea
.MXCsr
& (FSW_INVALID_OPERATION
|
1474 /* Now handle any of those legal errors */
1475 if (Error
& (FSW_INVALID_OPERATION
|
1482 /* By issuing an exception */
1483 KiDispatchException1Args(STATUS_FLOAT_MULTIPLE_TRAPS
,
1489 /* Unknown XMMI fault */
1490 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 13, 0, 0, 1, TrapFrame
);
1493 /* SOFTWARE SERVICES **********************************************************/
1497 KiRaiseSecurityCheckFailureHandler(IN PKTRAP_FRAME TrapFrame
)
1499 /* Save trap frame */
1500 KiEnterTrap(TrapFrame
);
1502 /* Decrement EIP to point to the INT29 instruction (2 bytes, not 1 like INT3) */
1503 TrapFrame
->Eip
-= 2;
1505 /* Check if this is a user trap */
1506 if (KiUserTrap(TrapFrame
))
1508 /* Dispatch exception to user mode */
1509 KiDispatchExceptionFromTrapFrame(STATUS_STACK_BUFFER_OVERRUN
,
1510 EXCEPTION_NONCONTINUABLE
,
1520 EXCEPTION_RECORD ExceptionRecord
;
1522 /* Bugcheck the system */
1523 ExceptionRecord
.ExceptionCode
= STATUS_STACK_BUFFER_OVERRUN
;
1524 ExceptionRecord
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
1525 ExceptionRecord
.ExceptionRecord
= NULL
;
1526 ExceptionRecord
.ExceptionAddress
= (PVOID
)TrapFrame
->Eip
;
1527 ExceptionRecord
.NumberParameters
= 1;
1528 ExceptionRecord
.ExceptionInformation
[0] = TrapFrame
->Ecx
;
1530 KeBugCheckWithTf(KERNEL_SECURITY_CHECK_FAILURE
,
1532 (ULONG_PTR
)TrapFrame
,
1533 (ULONG_PTR
)&ExceptionRecord
,
1541 KiGetTickCountHandler(IN PKTRAP_FRAME TrapFrame
)
1543 /* Save trap frame */
1544 KiEnterTrap(TrapFrame
);
1547 * Just fail the request
1549 DbgPrint("INT 0x2A attempted, returning 0 tick count\n");
1553 KiEoiHelper(TrapFrame
);
1558 KiCallbackReturnHandler(IN PKTRAP_FRAME TrapFrame
)
1563 /* Save the SEH chain, NtCallbackReturn will restore this */
1564 TrapFrame
->ExceptionList
= KeGetPcr()->NtTib
.ExceptionList
;
1566 /* Set thread fields */
1567 Thread
= KeGetCurrentThread();
1568 Thread
->TrapFrame
= TrapFrame
;
1569 Thread
->PreviousMode
= KiUserTrap(TrapFrame
);
1570 ASSERT(Thread
->PreviousMode
!= KernelMode
);
1572 /* Pass the register parameters to NtCallbackReturn.
1573 Result pointer is in ecx, result length in edx, status in eax */
1574 Status
= NtCallbackReturn((PVOID
)TrapFrame
->Ecx
,
1578 /* If we got here, something went wrong. Return an error to the caller */
1579 KiServiceExit(TrapFrame
, Status
);
1585 KiRaiseAssertionHandler(IN PKTRAP_FRAME TrapFrame
)
1587 /* Save trap frame */
1588 KiEnterTrap(TrapFrame
);
1590 /* Decrement EIP to point to the INT2C instruction (2 bytes, not 1 like INT3) */
1591 TrapFrame
->Eip
-= 2;
1593 /* Dispatch the exception */
1594 KiDispatchException0Args(STATUS_ASSERTION_FAILURE
,
1602 KiDebugServiceHandler(IN PKTRAP_FRAME TrapFrame
)
1604 /* Save trap frame */
1605 KiEnterTrap(TrapFrame
);
1607 /* Increment EIP to skip the INT3 instruction */
1610 /* Continue with the common handler */
1611 KiDebugHandler(TrapFrame
, TrapFrame
->Eax
, TrapFrame
->Ecx
, TrapFrame
->Edx
);
1617 KiDbgPreServiceHook(ULONG SystemCallNumber
, PULONG_PTR Arguments
)
1619 #if DBG && !defined(_WINKD_)
1620 if (SystemCallNumber
>= 0x1000 && KeWin32PreServiceHook
)
1621 KeWin32PreServiceHook(SystemCallNumber
, Arguments
);
1627 KiDbgPostServiceHook(ULONG SystemCallNumber
, ULONG_PTR Result
)
1629 #if DBG && !defined(_WINKD_)
1630 if (SystemCallNumber
>= 0x1000 && KeWin32PostServiceHook
)
1631 return KeWin32PostServiceHook(SystemCallNumber
, Result
);
1639 KiSystemServiceHandler(IN PKTRAP_FRAME TrapFrame
,
1643 PKSERVICE_TABLE_DESCRIPTOR DescriptorTable
;
1644 ULONG Id
, Offset
, StackBytes
;
1647 ULONG SystemCallNumber
= TrapFrame
->Eax
;
1649 /* Get the current thread */
1650 Thread
= KeGetCurrentThread();
1652 /* Set debug header */
1653 KiFillTrapFrameDebug(TrapFrame
);
1655 /* Chain trap frames */
1656 TrapFrame
->Edx
= (ULONG_PTR
)Thread
->TrapFrame
;
1659 TrapFrame
->ErrCode
= 0;
1661 /* Save previous mode */
1662 TrapFrame
->PreviousPreviousMode
= Thread
->PreviousMode
;
1664 /* Save the SEH chain and terminate it for now */
1665 TrapFrame
->ExceptionList
= KeGetPcr()->NtTib
.ExceptionList
;
1666 KeGetPcr()->NtTib
.ExceptionList
= EXCEPTION_CHAIN_END
;
1668 /* Default to debugging disabled */
1671 /* Check if the frame was from user mode */
1672 if (KiUserTrap(TrapFrame
))
1674 /* Check for active debugging */
1675 if (KeGetCurrentThread()->Header
.DebugActive
& 0xFF)
1677 /* Handle debug registers */
1678 KiHandleDebugRegistersOnTrapEntry(TrapFrame
);
1682 /* Set thread fields */
1683 Thread
->TrapFrame
= TrapFrame
;
1684 Thread
->PreviousMode
= KiUserTrap(TrapFrame
);
1686 /* Enable interrupts */
1689 /* Decode the system call number */
1690 Offset
= (SystemCallNumber
>> SERVICE_TABLE_SHIFT
) & SERVICE_TABLE_MASK
;
1691 Id
= SystemCallNumber
& SERVICE_NUMBER_MASK
;
1693 /* Get descriptor table */
1694 DescriptorTable
= (PVOID
)((ULONG_PTR
)Thread
->ServiceTable
+ Offset
);
1696 /* Validate the system call number */
1697 if (__builtin_expect(Id
>= DescriptorTable
->Limit
, 0))
1699 /* Check if this is a GUI call */
1700 if (!(Offset
& SERVICE_TABLE_TEST
))
1703 Status
= STATUS_INVALID_SYSTEM_SERVICE
;
1707 /* Convert us to a GUI thread -- must wrap in ASM to get new EBP */
1708 Status
= KiConvertToGuiThread();
1710 /* Reload trap frame and descriptor table pointer from new stack */
1711 TrapFrame
= *(volatile PVOID
*)&Thread
->TrapFrame
;
1712 DescriptorTable
= (PVOID
)(*(volatile ULONG_PTR
*)&Thread
->ServiceTable
+ Offset
);
1714 if (!NT_SUCCESS(Status
))
1716 /* Set the last error and fail */
1720 /* Validate the system call number again */
1721 if (Id
>= DescriptorTable
->Limit
)
1724 Status
= STATUS_INVALID_SYSTEM_SERVICE
;
1729 /* Check if this is a GUI call */
1730 if (__builtin_expect(Offset
& SERVICE_TABLE_TEST
, 0))
1732 /* Get the batch count and flush if necessary */
1733 if (NtCurrentTeb()->GdiBatchCount
) KeGdiFlushUserBatch();
1736 /* Increase system call count */
1737 KeGetCurrentPrcb()->KeSystemCalls
++;
1739 /* FIXME: Increase individual counts on debug systems */
1740 //KiIncreaseSystemCallCount(DescriptorTable, Id);
1742 /* Get stack bytes */
1743 StackBytes
= DescriptorTable
->Number
[Id
];
1745 /* Probe caller stack */
1746 if (__builtin_expect((Arguments
< (PVOID
)MmUserProbeAddress
) && !(KiUserTrap(TrapFrame
)), 0))
1748 /* Access violation */
1749 UNIMPLEMENTED_FATAL();
1752 /* Call pre-service debug hook */
1753 KiDbgPreServiceHook(SystemCallNumber
, Arguments
);
1755 /* Get the handler and make the system call */
1756 Handler
= (PVOID
)DescriptorTable
->Base
[Id
];
1757 Status
= KiSystemCallTrampoline(Handler
, Arguments
, StackBytes
);
1759 /* Call post-service debug hook */
1760 Status
= KiDbgPostServiceHook(SystemCallNumber
, Status
);
1762 /* Make sure we're exiting correctly */
1763 KiExitSystemCallDebugChecks(Id
, TrapFrame
);
1765 /* Restore the old trap frame */
1767 Thread
->TrapFrame
= (PKTRAP_FRAME
)TrapFrame
->Edx
;
1769 /* Exit from system call */
1770 KiServiceExit(TrapFrame
, Status
);
1775 KiCheckForSListAddress(IN PKTRAP_FRAME TrapFrame
)
1785 Kei386EoiHelper(VOID
)
1787 /* We should never see this call happening */
1788 KeBugCheck(MISMATCHED_HAL
);