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 KeUserPopEntrySListFault
;
19 extern PVOID KeUserPopEntrySListResume
;
20 extern PVOID FrRestore
;
21 VOID FASTCALL
Ke386LoadFpuState(IN PFX_SAVE_AREA SaveArea
);
23 /* GLOBALS ********************************************************************/
25 UCHAR KiTrapPrefixTable
[] =
28 0xF3, /* REP INS/OUTS */
40 UCHAR KiTrapIoTable
[] =
56 PFAST_SYSTEM_CALL_EXIT KiFastCallExitHandler
;
57 #if DBG && defined(_M_IX86) && !defined(_WINKD_)
58 PKDBG_PRESERVICEHOOK KeWin32PreServiceHook
= NULL
;
59 PKDBG_POSTSERVICEHOOK KeWin32PostServiceHook
= NULL
;
62 BOOLEAN StopChecking
= FALSE
;
66 /* TRAP EXIT CODE *************************************************************/
70 KiVdmTrap(IN PKTRAP_FRAME TrapFrame
)
72 /* Either the V8086 flag is on, or this is user-mode with a VDM */
73 return ((TrapFrame
->EFlags
& EFLAGS_V86_MASK
) ||
74 ((KiUserTrap(TrapFrame
)) && (PsGetCurrentProcess()->VdmObjects
)));
79 KiV86Trap(IN PKTRAP_FRAME TrapFrame
)
81 /* Check if the V8086 flag is on */
82 return ((TrapFrame
->EFlags
& EFLAGS_V86_MASK
) != 0);
87 KiIsFrameEdited(IN PKTRAP_FRAME TrapFrame
)
89 /* An edited frame changes esp. It is marked by clearing the bits
90 defined by FRAME_EDITED in the SegCs field of the trap frame */
91 return ((TrapFrame
->SegCs
& FRAME_EDITED
) == 0);
96 KiCommonExit(IN PKTRAP_FRAME TrapFrame
, BOOLEAN SkipPreviousMode
)
98 /* Disable interrupts until we return */
101 /* Check for APC delivery */
102 KiCheckForApcDelivery(TrapFrame
);
104 /* Restore the SEH handler chain */
105 KeGetPcr()->NtTib
.ExceptionList
= TrapFrame
->ExceptionList
;
107 /* Check if there are active debug registers */
108 if (__builtin_expect(TrapFrame
->Dr7
& ~DR7_RESERVED_MASK
, 0))
110 /* Check if the frame was from user mode or v86 mode */
111 if (KiUserTrap(TrapFrame
) ||
112 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
114 /* Handle debug registers */
115 KiHandleDebugRegistersOnTrapExit(TrapFrame
);
119 /* Debugging checks */
120 KiExitTrapDebugChecks(TrapFrame
, SkipPreviousMode
);
126 KiEoiHelper(IN PKTRAP_FRAME TrapFrame
)
128 /* Common trap exit code */
129 KiCommonExit(TrapFrame
, TRUE
);
131 /* Check if this was a V8086 trap */
132 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
) KiTrapReturnNoSegments(TrapFrame
);
134 /* Check for user mode exit */
135 if (KiUserTrap(TrapFrame
)) KiTrapReturn(TrapFrame
);
137 /* Check for edited frame */
138 if (KiIsFrameEdited(TrapFrame
)) KiEditedTrapReturn(TrapFrame
);
140 /* Check if we have single stepping enabled */
141 if (TrapFrame
->EFlags
& EFLAGS_TF
) KiTrapReturnNoSegments(TrapFrame
);
143 /* Exit the trap to kernel mode */
144 KiTrapReturnNoSegmentsRet8(TrapFrame
);
150 KiServiceExit(IN PKTRAP_FRAME TrapFrame
,
153 ASSERT((TrapFrame
->EFlags
& EFLAGS_V86_MASK
) == 0);
154 ASSERT(!KiIsFrameEdited(TrapFrame
));
156 /* Copy the status into EAX */
157 TrapFrame
->Eax
= Status
;
159 /* Common trap exit code */
160 KiCommonExit(TrapFrame
, FALSE
);
162 /* Restore previous mode */
163 KeGetCurrentThread()->PreviousMode
= (CCHAR
)TrapFrame
->PreviousPreviousMode
;
165 /* Check for user mode exit */
166 if (KiUserTrap(TrapFrame
))
168 /* Check if we were single stepping */
169 if (TrapFrame
->EFlags
& EFLAGS_TF
)
171 /* Must use the IRET handler */
172 KiSystemCallTrapReturn(TrapFrame
);
176 /* We can use the sysexit handler */
177 KiFastCallExitHandler(TrapFrame
);
182 /* Exit to kernel mode */
183 KiSystemCallReturn(TrapFrame
);
189 KiServiceExit2(IN PKTRAP_FRAME TrapFrame
)
191 /* Common trap exit code */
192 KiCommonExit(TrapFrame
, FALSE
);
194 /* Restore previous mode */
195 KeGetCurrentThread()->PreviousMode
= (CCHAR
)TrapFrame
->PreviousPreviousMode
;
197 /* Check if this was a V8086 trap */
198 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
) KiTrapReturnNoSegments(TrapFrame
);
200 /* Check for user mode exit */
201 if (KiUserTrap(TrapFrame
)) KiTrapReturn(TrapFrame
);
203 /* Check for edited frame */
204 if (KiIsFrameEdited(TrapFrame
)) KiEditedTrapReturn(TrapFrame
);
206 /* Check if we have single stepping enabled */
207 if (TrapFrame
->EFlags
& EFLAGS_TF
) KiTrapReturnNoSegments(TrapFrame
);
209 /* Exit the trap to kernel mode */
210 KiTrapReturnNoSegmentsRet8(TrapFrame
);
214 /* TRAP HANDLERS **************************************************************/
219 KiDebugHandler(IN PKTRAP_FRAME TrapFrame
,
224 /* Check for VDM trap */
225 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
227 /* Enable interrupts if the trap came from user-mode */
228 if (KiUserTrap(TrapFrame
)) _enable();
230 /* Dispatch the exception */
231 KiDispatchExceptionFromTrapFrame(STATUS_BREAKPOINT
,
244 KiNpxHandler(IN PKTRAP_FRAME TrapFrame
,
246 IN PFX_SAVE_AREA SaveArea
)
248 ULONG Cr0
, Mask
, Error
, ErrorOffset
, DataOffset
;
250 /* Check for VDM trap */
251 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
253 /* Check for kernel trap */
254 if (!KiUserTrap(TrapFrame
))
256 /* Kernel might've tripped a delayed error */
257 SaveArea
->Cr0NpxState
|= CR0_TS
;
259 /* Only valid if it happened during a restore */
260 if ((PVOID
)TrapFrame
->Eip
== FrRestore
)
262 /* It did, so just skip the instruction */
263 TrapFrame
->Eip
+= 3; /* Size of FRSTOR instruction */
264 KiEoiHelper(TrapFrame
);
268 /* User or kernel trap -- check if we need to unload the current state */
269 if (Thread
->NpxState
== NPX_STATE_LOADED
)
273 Cr0
&= ~(CR0_MP
| CR0_EM
| CR0_TS
);
277 Ke386SaveFpuState(SaveArea
);
279 /* Mark CR0 state dirty */
280 Cr0
|= NPX_STATE_NOT_LOADED
;
281 Cr0
|= SaveArea
->Cr0NpxState
;
284 /* Update NPX state */
285 Thread
->NpxState
= NPX_STATE_NOT_LOADED
;
286 KeGetCurrentPrcb()->NpxThread
= NULL
;
289 /* Clear the TS bit and re-enable interrupts */
290 SaveArea
->Cr0NpxState
&= ~CR0_TS
;
293 /* Check if we should get the FN or FX error */
294 if (KeI386FxsrPresent
)
297 Mask
= SaveArea
->U
.FxArea
.ControlWord
;
298 Error
= SaveArea
->U
.FxArea
.StatusWord
;
300 /* Get the FPU exception address too */
301 ErrorOffset
= SaveArea
->U
.FxArea
.ErrorOffset
;
302 DataOffset
= SaveArea
->U
.FxArea
.DataOffset
;
307 Mask
= SaveArea
->U
.FnArea
.ControlWord
;
308 Error
= SaveArea
->U
.FnArea
.StatusWord
;
310 /* Get the FPU exception address too */
311 ErrorOffset
= SaveArea
->U
.FnArea
.ErrorOffset
;
312 DataOffset
= SaveArea
->U
.FnArea
.DataOffset
;
315 /* Get legal exceptions that software should handle */
316 Mask
&= (FSW_INVALID_OPERATION
|
324 /* Check for invalid operation */
325 if (Error
& FSW_INVALID_OPERATION
)
328 * Now check if this is actually a Stack Fault. This is needed because
329 * on x86 the Invalid Operation error is set for Stack Check faults as well.
331 if (Error
& FSW_STACK_FAULT
)
333 /* Issue stack check fault */
334 KiDispatchException2Args(STATUS_FLOAT_STACK_CHECK
,
342 /* This is an invalid operation fault after all, so raise that instead */
343 KiDispatchException1Args(STATUS_FLOAT_INVALID_OPERATION
,
350 /* Check for divide by zero */
351 if (Error
& FSW_ZERO_DIVIDE
)
354 KiDispatchException1Args(STATUS_FLOAT_DIVIDE_BY_ZERO
,
360 /* Check for denormal */
361 if (Error
& FSW_DENORMAL
)
364 KiDispatchException1Args(STATUS_FLOAT_INVALID_OPERATION
,
370 /* Check for overflow */
371 if (Error
& FSW_OVERFLOW
)
374 KiDispatchException1Args(STATUS_FLOAT_OVERFLOW
,
380 /* Check for underflow */
381 if (Error
& FSW_UNDERFLOW
)
384 KiDispatchException1Args(STATUS_FLOAT_UNDERFLOW
,
390 /* Check for precision fault */
391 if (Error
& FSW_PRECISION
)
394 KiDispatchException1Args(STATUS_FLOAT_INEXACT_RESULT
,
400 /* Unknown FPU fault */
401 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 1, Error
, 0, 0, TrapFrame
);
407 KiTrap00Handler(IN PKTRAP_FRAME TrapFrame
)
409 /* Save trap frame */
410 KiEnterTrap(TrapFrame
);
412 /* Check for VDM trap */
413 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
415 /* Enable interrupts */
418 /* Dispatch the exception */
419 KiDispatchException0Args(STATUS_INTEGER_DIVIDE_BY_ZERO
,
427 KiTrap01Handler(IN PKTRAP_FRAME TrapFrame
)
429 /* Save trap frame */
430 KiEnterTrap(TrapFrame
);
432 /* Check for VDM trap */
433 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
435 /* Check if this was a single step after sysenter */
436 if (TrapFrame
->Eip
== (ULONG
)KiFastCallEntry
)
438 /* Disable single stepping */
439 TrapFrame
->EFlags
&= ~EFLAGS_TF
;
441 /* Re-enter at the alternative sysenter entry point */
442 TrapFrame
->Eip
= (ULONG
)KiFastCallEntryWithSingleStep
;
445 KiEoiHelper(TrapFrame
);
448 /* Enable interrupts if the trap came from user-mode */
449 if (KiUserTrap(TrapFrame
)) _enable();
451 /* Mask out trap flag and dispatch the exception */
452 TrapFrame
->EFlags
&= ~EFLAGS_TF
;
453 KiDispatchException0Args(STATUS_SINGLE_STEP
,
467 KTRAP_FRAME TrapFrame
;
471 // In some sort of strange recursion case, we might end up here with the IF
472 // flag incorrectly on the interrupt frame -- during a normal NMI this would
473 // normally already be set.
475 // For sanity's sake, make sure interrupts are disabled for sure.
476 // NMIs will already be since the CPU does it for us.
481 // Get the current TSS, thread, and process
484 Thread
= ((PKIPCR
)PCR
)->PrcbData
.CurrentThread
;
485 Process
= Thread
->ApcState
.Process
;
488 // Save data usually not in the TSS
490 Tss
->CR3
= Process
->DirectoryTableBase
[0];
491 Tss
->IoMapBase
= Process
->IopmOffset
;
492 Tss
->LDT
= Process
->LdtDescriptor
.LimitLow
? KGDT_LDT
: 0;
495 // Now get the base address of the NMI TSS
497 TssGdt
= &((PKIPCR
)KeGetPcr())->GDT
[KGDT_NMI_TSS
/ sizeof(KGDTENTRY
)];
498 NmiTss
= (PKTSS
)(ULONG_PTR
)(TssGdt
->BaseLow
|
499 TssGdt
->HighWord
.Bytes
.BaseMid
<< 16 |
500 TssGdt
->HighWord
.Bytes
.BaseHi
<< 24);
503 // Switch to it and activate it, masking off the nested flag
505 // Note that in reality, we are already on the NMI tss -- we just need to
506 // update the PCR to reflect this
509 __writeeflags(__readeflags() &~ EFLAGS_NESTED_TASK
);
510 TssGdt
->HighWord
.Bits
.Dpl
= 0;
511 TssGdt
->HighWord
.Bits
.Pres
= 1;
512 TssGdt
->HighWord
.Bits
.Type
= I386_TSS
;
515 // Now build the trap frame based on the original TSS
517 // The CPU does a hardware "Context switch" / task switch of sorts and so it
518 // takes care of saving our context in the normal TSS.
520 // We just have to go get the values...
522 RtlZeroMemory(&TrapFrame
, sizeof(KTRAP_FRAME
));
523 TrapFrame
.HardwareSegSs
= Tss
->Ss0
;
524 TrapFrame
.HardwareEsp
= Tss
->Esp0
;
525 TrapFrame
.EFlags
= Tss
->EFlags
;
526 TrapFrame
.SegCs
= Tss
->Cs
;
527 TrapFrame
.Eip
= Tss
->Eip
;
528 TrapFrame
.Ebp
= Tss
->Ebp
;
529 TrapFrame
.Ebx
= Tss
->Ebx
;
530 TrapFrame
.Esi
= Tss
->Esi
;
531 TrapFrame
.Edi
= Tss
->Edi
;
532 TrapFrame
.SegFs
= Tss
->Fs
;
533 TrapFrame
.ExceptionList
= PCR
->NtTib
.ExceptionList
;
534 TrapFrame
.PreviousPreviousMode
= (ULONG
)-1;
535 TrapFrame
.Eax
= Tss
->Eax
;
536 TrapFrame
.Ecx
= Tss
->Ecx
;
537 TrapFrame
.Edx
= Tss
->Edx
;
538 TrapFrame
.SegDs
= Tss
->Ds
;
539 TrapFrame
.SegEs
= Tss
->Es
;
540 TrapFrame
.SegGs
= Tss
->Gs
;
541 TrapFrame
.DbgEip
= Tss
->Eip
;
542 TrapFrame
.DbgEbp
= Tss
->Ebp
;
545 // Store the trap frame in the KPRCB
547 KiSaveProcessorState(&TrapFrame
, NULL
);
550 // Call any registered NMI handlers and see if they handled it or not
555 // They did not, so call the platform HAL routine to bugcheck the system
557 // Make sure the HAL believes it's running at HIGH IRQL... we can't use
558 // the normal APIs here as playing with the IRQL could change the system
562 PCR
->Irql
= HIGH_LEVEL
;
568 // Although the CPU disabled NMIs, we just did a BIOS Call, which could've
569 // totally changed things.
571 // We have to make sure we're still in our original NMI -- a nested NMI
572 // will point back to the NMI TSS, and in that case we're hosed.
574 if (PCR
->TSS
->Backlink
!= KGDT_NMI_TSS
)
577 // Restore original TSS
582 // Set it back to busy
584 TssGdt
->HighWord
.Bits
.Dpl
= 0;
585 TssGdt
->HighWord
.Bits
.Pres
= 1;
586 TssGdt
->HighWord
.Bits
.Type
= I386_ACTIVE_TSS
;
589 // Restore nested flag
591 __writeeflags(__readeflags() | EFLAGS_NESTED_TASK
);
594 // Handled, return from interrupt
600 // Unhandled: crash the system
602 KiSystemFatalException(EXCEPTION_NMI
, NULL
);
608 KiTrap03Handler(IN PKTRAP_FRAME TrapFrame
)
610 /* Save trap frame */
611 KiEnterTrap(TrapFrame
);
613 /* Continue with the common handler */
614 KiDebugHandler(TrapFrame
, BREAKPOINT_BREAK
, 0, 0);
620 KiTrap04Handler(IN PKTRAP_FRAME TrapFrame
)
622 /* Save trap frame */
623 KiEnterTrap(TrapFrame
);
625 /* Check for VDM trap */
626 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
628 /* Enable interrupts */
631 /* Dispatch the exception */
632 KiDispatchException0Args(STATUS_INTEGER_OVERFLOW
,
640 KiTrap05Handler(IN PKTRAP_FRAME TrapFrame
)
642 /* Save trap frame */
643 KiEnterTrap(TrapFrame
);
645 /* Check for VDM trap */
646 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
648 /* Check for kernel-mode fault */
649 if (!KiUserTrap(TrapFrame
)) KiSystemFatalException(EXCEPTION_BOUND_CHECK
, TrapFrame
);
651 /* Enable interrupts */
654 /* Dispatch the exception */
655 KiDispatchException0Args(STATUS_ARRAY_BOUNDS_EXCEEDED
,
663 KiTrap06Handler(IN PKTRAP_FRAME TrapFrame
)
669 /* Check for V86 GPF */
670 if (__builtin_expect(KiV86Trap(TrapFrame
), 1))
673 KiEnterV86Trap(TrapFrame
);
675 /* Must be a VDM process */
676 if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects
, 0))
678 /* Enable interrupts */
681 /* Setup illegal instruction fault */
682 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION
,
687 /* Go to APC level */
688 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
692 if (!VdmDispatchBop(TrapFrame
))
694 /* Should only happen in VDM mode */
695 UNIMPLEMENTED_FATAL();
698 /* Bring IRQL back */
699 KeLowerIrql(OldIrql
);
702 /* Do a quick V86 exit if possible */
703 KiExitV86Trap(TrapFrame
);
706 /* Save trap frame */
707 KiEnterTrap(TrapFrame
);
709 /* Enable interrupts */
710 Instruction
= (PUCHAR
)TrapFrame
->Eip
;
713 /* Check for user trap */
714 if (KiUserTrap(TrapFrame
))
718 /* Scan next 4 opcodes */
719 for (i
= 0; i
< 4; i
++)
721 /* Check for LOCK instruction */
722 if (Instruction
[i
] == 0xF0)
724 /* Send invalid lock sequence exception */
725 KiDispatchException0Args(STATUS_INVALID_LOCK_SEQUENCE
,
731 /* FIXME: SEH ends here */
734 /* Kernel-mode or user-mode fault (but not LOCK) */
735 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION
,
744 KiTrap07Handler(IN PKTRAP_FRAME TrapFrame
)
746 PKTHREAD Thread
, NpxThread
;
747 PFX_SAVE_AREA SaveArea
, NpxSaveArea
;
750 /* Save trap frame */
751 KiEnterTrap(TrapFrame
);
753 /* Try to handle NPX delay load */
756 /* Get the current thread */
757 Thread
= KeGetCurrentThread();
759 /* Get the NPX frame */
760 SaveArea
= KiGetThreadNpxArea(Thread
);
762 /* Check if emulation is enabled */
763 if (SaveArea
->Cr0NpxState
& CR0_EM
)
765 /* Not implemented */
766 UNIMPLEMENTED_FATAL();
769 /* Save CR0 and check NPX state */
771 if (Thread
->NpxState
!= NPX_STATE_LOADED
)
774 Cr0
&= ~(CR0_MP
| CR0_EM
| CR0_TS
);
777 /* Get the NPX thread */
778 NpxThread
= KeGetCurrentPrcb()->NpxThread
;
781 /* Get the NPX frame */
782 NpxSaveArea
= KiGetThreadNpxArea(NpxThread
);
785 Ke386SaveFpuState(NpxSaveArea
);
787 /* Update NPX state */
788 NpxThread
->NpxState
= NPX_STATE_NOT_LOADED
;
792 Ke386LoadFpuState(SaveArea
);
794 /* Update NPX state */
795 Thread
->NpxState
= NPX_STATE_LOADED
;
796 KeGetCurrentPrcb()->NpxThread
= Thread
;
798 /* Enable interrupts */
801 /* Check if CR0 needs to be reloaded due to context switch */
802 if (!SaveArea
->Cr0NpxState
) KiEoiHelper(TrapFrame
);
804 /* Otherwise, we need to reload CR0, disable interrupts */
809 Cr0
|= SaveArea
->Cr0NpxState
;
812 /* Now restore interrupts and check for TS */
814 if (Cr0
& CR0_TS
) KiEoiHelper(TrapFrame
);
816 /* We're still here -- clear TS and try again */
817 __writecr0(__readcr0() &~ CR0_TS
);
822 /* This is an actual fault, not a lack of FPU state */
827 /* TS should not be set */
831 * If it's incorrectly set, then maybe the state is actually still valid
832 * but we could have lost track of that due to a BIOS call.
833 * Make sure MP is still set, which should verify the theory.
837 /* Indeed, the state is actually still valid, so clear TS */
838 __writecr0(__readcr0() &~ CR0_TS
);
839 KiEoiHelper(TrapFrame
);
842 /* Otherwise, something strange is going on */
843 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 2, Cr0
, 0, 0, TrapFrame
);
846 /* It's not a delayed load, so process this trap as an NPX fault */
847 KiNpxHandler(TrapFrame
, Thread
, SaveArea
);
853 KiTrap08Handler(IN PKTRAP_FRAME TrapFrame
)
855 /* FIXME: Not handled */
856 KiSystemFatalException(EXCEPTION_DOUBLE_FAULT
, TrapFrame
);
862 KiTrap09Handler(IN PKTRAP_FRAME TrapFrame
)
864 /* Save trap frame */
865 KiEnterTrap(TrapFrame
);
867 /* Enable interrupts and kill the system */
869 KiSystemFatalException(EXCEPTION_NPX_OVERRUN
, TrapFrame
);
875 KiTrap0AHandler(IN PKTRAP_FRAME TrapFrame
)
877 /* Save trap frame */
878 KiEnterTrap(TrapFrame
);
880 /* Check for VDM trap */
881 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
883 /* Kill the system */
884 KiSystemFatalException(EXCEPTION_INVALID_TSS
, TrapFrame
);
890 KiTrap0BHandler(IN PKTRAP_FRAME TrapFrame
)
892 /* Save trap frame */
893 KiEnterTrap(TrapFrame
);
895 /* FIXME: Kill the system */
897 KiSystemFatalException(EXCEPTION_SEGMENT_NOT_PRESENT
, TrapFrame
);
903 KiTrap0CHandler(IN PKTRAP_FRAME TrapFrame
)
905 /* Save trap frame */
906 KiEnterTrap(TrapFrame
);
908 /* FIXME: Kill the system */
910 KiSystemFatalException(EXCEPTION_STACK_FAULT
, TrapFrame
);
916 KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame
)
919 BOOLEAN Privileged
= FALSE
;
921 UCHAR Instruction
= 0;
924 /* Check for V86 GPF */
925 if (__builtin_expect(KiV86Trap(TrapFrame
), 1))
928 KiEnterV86Trap(TrapFrame
);
930 /* Must be a VDM process */
931 if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects
, 0))
933 /* Enable interrupts */
936 /* Setup illegal instruction fault */
937 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION
,
942 /* Go to APC level */
943 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
946 /* Handle the V86 opcode */
947 if (__builtin_expect(Ki386HandleOpcodeV86(TrapFrame
) == 0xFF, 0))
949 /* Should only happen in VDM mode */
950 UNIMPLEMENTED_FATAL();
953 /* Bring IRQL back */
954 KeLowerIrql(OldIrql
);
957 /* Do a quick V86 exit if possible */
958 KiExitV86Trap(TrapFrame
);
961 /* Save trap frame */
962 KiEnterTrap(TrapFrame
);
964 /* Check for user-mode GPF */
965 if (KiUserTrap(TrapFrame
))
967 /* Should not be VDM */
968 ASSERT(KiVdmTrap(TrapFrame
) == FALSE
);
970 /* Enable interrupts and check error code */
972 if (!TrapFrame
->ErrCode
)
975 Instructions
= (PUCHAR
)TrapFrame
->Eip
;
977 /* Scan next 15 bytes */
978 for (i
= 0; i
< 15; i
++)
980 /* Skip prefix instructions */
981 for (j
= 0; j
< sizeof(KiTrapPrefixTable
); j
++)
983 /* Is this a prefix instruction? */
984 if (Instructions
[i
] == KiTrapPrefixTable
[j
])
991 /* Is this NOT any prefix instruction? */
992 if (j
== sizeof(KiTrapPrefixTable
))
994 /* We can go ahead and handle the fault now */
995 Instruction
= Instructions
[i
];
1000 /* If all we found was prefixes, then this instruction is too long */
1003 /* Setup illegal instruction fault */
1004 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION
,
1009 /* Check for privileged instructions */
1010 DPRINT("Instruction (%lu) at fault: %lx %lx %lx %lx\n",
1013 Instructions
[i
+ 1],
1014 Instructions
[i
+ 2],
1015 Instructions
[i
+ 3]);
1016 if (Instruction
== 0xF4) // HLT
1018 /* HLT is privileged */
1021 else if (Instruction
== 0x0F)
1023 /* Test if it's any of the privileged two-byte opcodes */
1024 if (((Instructions
[i
+ 1] == 0x00) && // LLDT or LTR
1025 (((Instructions
[i
+ 2] & 0x38) == 0x10) || // LLDT
1026 (Instructions
[i
+ 2] == 0x18))) || // LTR
1027 ((Instructions
[i
+ 1] == 0x01) && // LGDT or LIDT or LMSW
1028 (((Instructions
[i
+ 2] & 0x38) == 0x10) || // LGDT
1029 (Instructions
[i
+ 2] == 0x18) || // LIDT
1030 (Instructions
[i
+ 2] == 0x30))) || // LMSW
1031 (Instructions
[i
+ 1] == 0x08) || // INVD
1032 (Instructions
[i
+ 1] == 0x09) || // WBINVD
1033 (Instructions
[i
+ 1] == 0x35) || // SYSEXIT
1034 (Instructions
[i
+ 1] == 0x21) || // MOV DR, XXX
1035 (Instructions
[i
+ 1] == 0x06) || // CLTS
1036 (Instructions
[i
+ 1] == 0x20) || // MOV CR, XXX
1037 (Instructions
[i
+ 1] == 0x22) || // MOV XXX, CR
1038 (Instructions
[i
+ 1] == 0x23) || // MOV YYY, DR
1039 (Instructions
[i
+ 1] == 0x30) || // WRMSR
1040 (Instructions
[i
+ 1] == 0x33)) // RDPMC
1041 // INVLPG, INVLPGA, SYSRET
1043 /* These are all privileged */
1049 /* Get the IOPL and compare with the RPL mask */
1050 Iopl
= (TrapFrame
->EFlags
& EFLAGS_IOPL
) >> 12;
1051 if ((TrapFrame
->SegCs
& RPL_MASK
) > Iopl
)
1053 /* I/O privilege error -- check for known instructions */
1054 if ((Instruction
== 0xFA) || (Instruction
== 0xFB)) // CLI or STI
1056 /* These are privileged */
1061 /* Last hope: an IN/OUT instruction */
1062 for (j
= 0; j
< sizeof(KiTrapIoTable
); j
++)
1064 /* Is this an I/O instruction? */
1065 if (Instruction
== KiTrapIoTable
[j
])
1067 /* Then it's privileged */
1076 /* So now... was the instruction privileged or not? */
1079 /* Whew! We have a privileged instruction, so dispatch the fault */
1080 KiDispatchException0Args(STATUS_PRIVILEGED_INSTRUCTION
,
1086 /* If we got here, send an access violation */
1087 KiDispatchException2Args(STATUS_ACCESS_VIOLATION
,
1095 * Check for a fault during checking of the user instruction.
1097 * Note that the SEH handler will catch invalid EIP, but we could be dealing
1098 * with an invalid CS, which will generate another GPF instead.
1101 if (((PVOID
)TrapFrame
->Eip
>= (PVOID
)KiTrap0DHandler
) &&
1102 ((PVOID
)TrapFrame
->Eip
< (PVOID
)KiTrap0DHandler
))
1104 /* Not implemented */
1105 UNIMPLEMENTED_FATAL();
1109 * NOTE: The ASM trap exit code would restore segment registers by doing
1110 * a POP <SEG>, which could cause an invalid segment if someone had messed
1111 * with the segment values.
1113 * Another case is a bogus SS, which would hit a GPF when doing the iret.
1114 * This could only be done through a buggy or malicious driver, or perhaps
1115 * the kernel debugger.
1117 * The kernel normally restores the "true" segment if this happens.
1119 * However, since we're restoring in C, not ASM, we can't detect
1120 * POP <SEG> since the actual instructions will be different.
1122 * A better technique would be to check the EIP and somehow edit the
1123 * trap frame before restarting the instruction -- but we would need to
1124 * know the extract instruction that was used first.
1126 * We could force a special instrinsic to use stack instructions, or write
1127 * a simple instruction length checker.
1129 * Nevertheless, this is a lot of work for the purpose of avoiding a crash
1130 * when the user is purposedly trying to create one from kernel-mode, so
1131 * we should probably table this for now since it's not a "real" issue.
1135 * NOTE2: Another scenario is the IRET during a V8086 restore (BIOS Call)
1136 * which will cause a GPF since the trap frame is a total mess (on purpose)
1137 * as built in KiEnterV86Mode.
1139 * The idea is to scan for IRET, scan for the known EIP adress, validate CS
1140 * and then manually issue a jump to the V8086 return EIP.
1142 Instructions
= (PUCHAR
)TrapFrame
->Eip
;
1143 if (Instructions
[0] == 0xCF)
1146 * Some evil shit is going on here -- this is not the SS:ESP you're
1147 * looking for! Instead, this is actually CS:EIP you're looking at!
1148 * Why? Because part of the trap frame actually corresponds to the IRET
1149 * stack during the trap exit!
1151 if ((TrapFrame
->HardwareEsp
== (ULONG
)Ki386BiosCallReturnAddress
) &&
1152 (TrapFrame
->HardwareSegSs
== (KGDT_R0_CODE
| RPL_MASK
)))
1154 /* Exit the V86 trap! */
1155 Ki386BiosCallReturnAddress(TrapFrame
);
1159 /* Otherwise, this is another kind of IRET fault */
1160 UNIMPLEMENTED_FATAL();
1164 /* So since we're not dealing with the above case, check for RDMSR/WRMSR */
1165 if ((Instructions
[0] == 0xF) && // 2-byte opcode
1166 ((Instructions
[1] == 0x32) || // RDMSR
1167 (Instructions
[1] == 0x30))) // WRMSR
1169 /* Unknown CPU MSR, so raise an access violation */
1170 KiDispatchException0Args(STATUS_ACCESS_VIOLATION
,
1175 /* Check for lazy segment load */
1176 if (TrapFrame
->SegDs
!= (KGDT_R3_DATA
| RPL_MASK
))
1179 TrapFrame
->SegDs
= (KGDT_R3_DATA
| RPL_MASK
);
1181 else if (TrapFrame
->SegEs
!= (KGDT_R3_DATA
| RPL_MASK
))
1184 TrapFrame
->SegEs
= (KGDT_R3_DATA
| RPL_MASK
);
1188 /* Whatever it is, we can't handle it */
1189 KiSystemFatalException(EXCEPTION_GP_FAULT
, TrapFrame
);
1192 /* Return to where we came from */
1193 KiTrapReturn(TrapFrame
);
1199 KiTrap0EHandler(IN PKTRAP_FRAME TrapFrame
)
1203 BOOLEAN StoreInstruction
;
1207 /* Save trap frame */
1208 KiEnterTrap(TrapFrame
);
1210 /* Check if this is the base frame */
1211 Thread
= KeGetCurrentThread();
1212 if (KeGetTrapFrame(Thread
) != TrapFrame
)
1214 /* It isn't, check if this is a second nested frame */
1215 if (((ULONG_PTR
)KeGetTrapFrame(Thread
) - (ULONG_PTR
)TrapFrame
) <=
1216 FIELD_OFFSET(KTRAP_FRAME
, EFlags
))
1218 /* The stack is somewhere in between frames, we need to fix it */
1219 UNIMPLEMENTED_FATAL();
1226 /* Enable interrupts */
1229 /* Interpret the error code */
1230 Present
= (TrapFrame
->ErrCode
& 1) != 0;
1231 StoreInstruction
= (TrapFrame
->ErrCode
& 2) != 0;
1233 /* Check if we came in with interrupts disabled */
1234 if (!(TrapFrame
->EFlags
& EFLAGS_INTERRUPT_MASK
))
1236 /* This is completely illegal, bugcheck the system */
1237 KeBugCheckWithTf(IRQL_NOT_LESS_OR_EQUAL
,
1245 /* Check for S-List fault
1247 Explanation: An S-List fault can occur due to a race condition between 2
1248 threads simultaneously trying to pop an element from the S-List. After
1249 thread 1 has read the pointer to the top element on the S-List it is
1250 preempted and thread 2 calls InterlockedPopEntrySlist on the same S-List,
1251 removing the top element and freeing it's memory. After that thread 1
1252 resumes and tries to read the address of the Next pointer from the top
1253 element, which it assumes will be the next top element.
1254 But since that memory has been freed, we get a page fault. To handle this
1255 race condition, we let thread 1 repeat the operation.
1256 We do NOT invoke the page fault handler in this case, since we do not
1257 want to trigger any side effects, like paging or a guard page fault.
1259 Sequence of operations:
1261 Thread 1 : mov eax, [ebp] <= eax now points to the first element
1262 Thread 1 : mov edx, [ebp + 4] <= edx is loaded with Depth and Sequence
1264 Thread 2 : calls InterlockedPopEntrySlist, changing the top element
1265 Thread 2 : frees the memory of the element that was popped
1267 Thread 1 : checks if eax is NULL
1268 Thread 1 : InterlockedPopEntrySListFault: mov ebx, [eax] <= faults
1270 To be sure that we are dealing with exactly the case described above, we
1271 check whether the ListHeader has changed. If Thread 2 only popped one
1272 entry, the Next field in the S-List-header has changed.
1273 If after thread 1 has faulted, thread 2 allocates a new element, by
1274 chance getting the same address as the previously freed element and
1275 pushes it on the list again, we will see the same top element, but the
1276 Sequence member of the S-List header has changed. Therefore we check
1277 both fields to make sure we catch any concurrent modification of the
1280 if ((TrapFrame
->Eip
== (ULONG_PTR
)ExpInterlockedPopEntrySListFault
) ||
1281 (TrapFrame
->Eip
== (ULONG_PTR
)KeUserPopEntrySListFault
))
1283 ULARGE_INTEGER SListHeader
;
1284 PVOID ResumeAddress
;
1286 /* Sanity check that the assembly is correct:
1287 This must be mov ebx, [eax]
1288 Followed by cmpxchg8b [ebp] */
1289 ASSERT((((UCHAR
*)TrapFrame
->Eip
)[0] == 0x8B) &&
1290 (((UCHAR
*)TrapFrame
->Eip
)[1] == 0x18) &&
1291 (((UCHAR
*)TrapFrame
->Eip
)[2] == 0x0F) &&
1292 (((UCHAR
*)TrapFrame
->Eip
)[3] == 0xC7) &&
1293 (((UCHAR
*)TrapFrame
->Eip
)[4] == 0x4D) &&
1294 (((UCHAR
*)TrapFrame
->Eip
)[5] == 0x00));
1296 /* Check if this is a user fault */
1297 if (TrapFrame
->Eip
== (ULONG_PTR
)KeUserPopEntrySListFault
)
1299 /* EBP points to the S-List-header. Copy it inside SEH, to protect
1300 against a bogus pointer from user mode */
1303 ProbeForRead((PVOID
)TrapFrame
->Ebp
,
1304 sizeof(ULARGE_INTEGER
),
1305 TYPE_ALIGNMENT(SLIST_HEADER
));
1306 SListHeader
= *(PULARGE_INTEGER
)TrapFrame
->Ebp
;
1308 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1310 /* The S-List pointer is not valid! */
1314 ResumeAddress
= KeUserPopEntrySListResume
;
1318 SListHeader
= *(PULARGE_INTEGER
)TrapFrame
->Ebp
;
1319 ResumeAddress
= ExpInterlockedPopEntrySListResume
;
1322 /* Check if either the Next pointer or the Sequence member in the
1323 S-List-header has changed. If any of these has changed, we restart
1324 the operation. Otherwise we only have a bogus pointer and let the
1325 page fault handler deal with it. */
1326 if ((SListHeader
.LowPart
!= TrapFrame
->Eax
) ||
1327 (SListHeader
.HighPart
!= TrapFrame
->Edx
))
1329 DPRINT1("*** Got an S-List-Fault ***\n");
1330 KeGetCurrentThread()->SListFaultCount
++;
1332 /* Restart the operation */
1333 TrapFrame
->Eip
= (ULONG_PTR
)ResumeAddress
;
1335 /* Continue execution */
1336 KiEoiHelper(TrapFrame
);
1341 /* Call the access fault handler */
1342 Status
= MmAccessFault(Present
,
1344 KiUserTrap(TrapFrame
),
1346 if (NT_SUCCESS(Status
))
1349 /* Check whether the kernel debugger has owed breakpoints to be inserted */
1350 KdSetOwedBreakpoints();
1352 /* We succeeded, return */
1353 KiEoiHelper(TrapFrame
);
1356 /* Check for syscall fault */
1358 if ((TrapFrame
->Eip
== (ULONG_PTR
)CopyParams
) ||
1359 (TrapFrame
->Eip
== (ULONG_PTR
)ReadBatch
))
1361 /* Not yet implemented */
1362 UNIMPLEMENTED_FATAL();
1366 /* Check for VDM trap */
1367 if (KiVdmTrap(TrapFrame
))
1369 DPRINT1("VDM PAGE FAULT at %lx:%lx for address %lx\n",
1370 TrapFrame
->SegCs
, TrapFrame
->Eip
, Cr2
);
1371 if (VdmDispatchPageFault(TrapFrame
))
1373 /* Return and end VDM execution */
1374 DPRINT1("VDM page fault with status 0x%lx resolved\n", Status
);
1375 KiEoiHelper(TrapFrame
);
1377 DPRINT1("VDM page fault with status 0x%lx NOT resolved\n", Status
);
1380 /* Either kernel or user trap (non VDM) so dispatch exception */
1381 if (Status
== STATUS_ACCESS_VIOLATION
)
1383 /* This status code is repurposed so we can recognize it later */
1384 KiDispatchException2Args(KI_EXCEPTION_ACCESS_VIOLATION
,
1390 else if ((Status
== STATUS_GUARD_PAGE_VIOLATION
) ||
1391 (Status
== STATUS_STACK_OVERFLOW
))
1393 /* These faults only have two parameters */
1394 KiDispatchException2Args(Status
,
1401 /* Only other choice is an in-page error, with 3 parameters */
1402 KiDispatchExceptionFromTrapFrame(STATUS_IN_PAGE_ERROR
,
1415 KiTrap0FHandler(IN PKTRAP_FRAME TrapFrame
)
1417 /* Save trap frame */
1418 KiEnterTrap(TrapFrame
);
1420 /* FIXME: Kill the system */
1422 KiSystemFatalException(EXCEPTION_RESERVED_TRAP
, TrapFrame
);
1428 KiTrap10Handler(IN PKTRAP_FRAME TrapFrame
)
1431 PFX_SAVE_AREA SaveArea
;
1433 /* Save trap frame */
1434 KiEnterTrap(TrapFrame
);
1436 /* Check if this is the NPX thrad */
1437 Thread
= KeGetCurrentThread();
1438 SaveArea
= KiGetThreadNpxArea(Thread
);
1439 if (Thread
!= KeGetCurrentPrcb()->NpxThread
)
1441 /* It isn't, enable interrupts and set delayed error */
1443 SaveArea
->Cr0NpxState
|= CR0_TS
;
1446 KiEoiHelper(TrapFrame
);
1449 /* Otherwise, proceed with NPX fault handling */
1450 KiNpxHandler(TrapFrame
, Thread
, SaveArea
);
1456 KiTrap11Handler(IN PKTRAP_FRAME TrapFrame
)
1458 /* Save trap frame */
1459 KiEnterTrap(TrapFrame
);
1461 /* Enable interrupts and kill the system */
1463 KiSystemFatalException(EXCEPTION_ALIGNMENT_CHECK
, TrapFrame
);
1469 KiTrap13Handler(IN PKTRAP_FRAME TrapFrame
)
1472 PFX_SAVE_AREA SaveArea
;
1473 ULONG Cr0
, MxCsrMask
, Error
;
1475 /* Save trap frame */
1476 KiEnterTrap(TrapFrame
);
1478 /* Check if this is the NPX thrad */
1479 Thread
= KeGetCurrentThread();
1480 if (Thread
!= KeGetCurrentPrcb()->NpxThread
)
1482 /* It isn't, kill the system */
1483 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 13, (ULONG_PTR
)Thread
, 0, 0, TrapFrame
);
1486 /* Get the NPX frame */
1487 SaveArea
= KiGetThreadNpxArea(Thread
);
1489 /* Check for VDM trap */
1490 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
1492 /* Check for user trap */
1493 if (!KiUserTrap(TrapFrame
))
1495 /* Kernel should not fault on XMMI */
1496 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 13, 0, 0, 2, TrapFrame
);
1501 Cr0
&= ~(CR0_MP
| CR0_EM
| CR0_TS
);
1504 /* Save FPU state */
1505 Ke386SaveFpuState(SaveArea
);
1507 /* Mark CR0 state dirty */
1508 Cr0
|= NPX_STATE_NOT_LOADED
;
1509 Cr0
|= SaveArea
->Cr0NpxState
;
1512 /* Update NPX state */
1513 Thread
->NpxState
= NPX_STATE_NOT_LOADED
;
1514 KeGetCurrentPrcb()->NpxThread
= NULL
;
1516 /* Clear the TS bit and re-enable interrupts */
1517 SaveArea
->Cr0NpxState
&= ~CR0_TS
;
1520 /* Now look at MxCsr to get the mask of errors we should care about */
1521 MxCsrMask
= ~((USHORT
)SaveArea
->U
.FxArea
.MXCsr
>> 7);
1523 /* Get legal exceptions that software should handle */
1524 Error
= (USHORT
)SaveArea
->U
.FxArea
.MXCsr
& (FSW_INVALID_OPERATION
|
1532 /* Now handle any of those legal errors */
1533 if (Error
& (FSW_INVALID_OPERATION
|
1540 /* By issuing an exception */
1541 KiDispatchException1Args(STATUS_FLOAT_MULTIPLE_TRAPS
,
1547 /* Unknown XMMI fault */
1548 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 13, 0, 0, 1, TrapFrame
);
1551 /* SOFTWARE SERVICES **********************************************************/
1555 KiRaiseSecurityCheckFailureHandler(IN PKTRAP_FRAME TrapFrame
)
1557 /* Save trap frame */
1558 KiEnterTrap(TrapFrame
);
1560 /* Decrement EIP to point to the INT29 instruction (2 bytes, not 1 like INT3) */
1561 TrapFrame
->Eip
-= 2;
1563 /* Check if this is a user trap */
1564 if (KiUserTrap(TrapFrame
))
1566 /* Dispatch exception to user mode */
1567 KiDispatchExceptionFromTrapFrame(STATUS_STACK_BUFFER_OVERRUN
,
1568 EXCEPTION_NONCONTINUABLE
,
1578 EXCEPTION_RECORD ExceptionRecord
;
1580 /* Bugcheck the system */
1581 ExceptionRecord
.ExceptionCode
= STATUS_STACK_BUFFER_OVERRUN
;
1582 ExceptionRecord
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
1583 ExceptionRecord
.ExceptionRecord
= NULL
;
1584 ExceptionRecord
.ExceptionAddress
= (PVOID
)TrapFrame
->Eip
;
1585 ExceptionRecord
.NumberParameters
= 1;
1586 ExceptionRecord
.ExceptionInformation
[0] = TrapFrame
->Ecx
;
1588 KeBugCheckWithTf(KERNEL_SECURITY_CHECK_FAILURE
,
1590 (ULONG_PTR
)TrapFrame
,
1591 (ULONG_PTR
)&ExceptionRecord
,
1599 KiGetTickCountHandler(IN PKTRAP_FRAME TrapFrame
)
1601 /* Save trap frame */
1602 KiEnterTrap(TrapFrame
);
1605 * Just fail the request
1607 DbgPrint("INT 0x2A attempted, returning 0 tick count\n");
1611 KiEoiHelper(TrapFrame
);
1616 KiCallbackReturnHandler(IN PKTRAP_FRAME TrapFrame
)
1621 /* Save the SEH chain, NtCallbackReturn will restore this */
1622 TrapFrame
->ExceptionList
= KeGetPcr()->NtTib
.ExceptionList
;
1624 /* Set thread fields */
1625 Thread
= KeGetCurrentThread();
1626 Thread
->TrapFrame
= TrapFrame
;
1627 Thread
->PreviousMode
= KiUserTrap(TrapFrame
);
1628 ASSERT(Thread
->PreviousMode
!= KernelMode
);
1630 /* Pass the register parameters to NtCallbackReturn.
1631 Result pointer is in ecx, result length in edx, status in eax */
1632 Status
= NtCallbackReturn((PVOID
)TrapFrame
->Ecx
,
1636 /* If we got here, something went wrong. Return an error to the caller */
1637 KiServiceExit(TrapFrame
, Status
);
1643 KiRaiseAssertionHandler(IN PKTRAP_FRAME TrapFrame
)
1645 /* Save trap frame */
1646 KiEnterTrap(TrapFrame
);
1648 /* Decrement EIP to point to the INT2C instruction (2 bytes, not 1 like INT3) */
1649 TrapFrame
->Eip
-= 2;
1651 /* Dispatch the exception */
1652 KiDispatchException0Args(STATUS_ASSERTION_FAILURE
,
1660 KiDebugServiceHandler(IN PKTRAP_FRAME TrapFrame
)
1662 /* Save trap frame */
1663 KiEnterTrap(TrapFrame
);
1665 /* Increment EIP to skip the INT3 instruction */
1668 /* Continue with the common handler */
1669 KiDebugHandler(TrapFrame
, TrapFrame
->Eax
, TrapFrame
->Ecx
, TrapFrame
->Edx
);
1675 KiDbgPreServiceHook(ULONG SystemCallNumber
, PULONG_PTR Arguments
)
1677 #if DBG && !defined(_WINKD_)
1678 if (SystemCallNumber
>= 0x1000 && KeWin32PreServiceHook
)
1679 KeWin32PreServiceHook(SystemCallNumber
, Arguments
);
1685 KiDbgPostServiceHook(ULONG SystemCallNumber
, ULONG_PTR Result
)
1687 #if DBG && !defined(_WINKD_)
1688 if (SystemCallNumber
>= 0x1000 && KeWin32PostServiceHook
)
1689 return KeWin32PostServiceHook(SystemCallNumber
, Result
);
1697 KiSystemServiceHandler(IN PKTRAP_FRAME TrapFrame
,
1701 PKSERVICE_TABLE_DESCRIPTOR DescriptorTable
;
1702 ULONG Id
, Offset
, StackBytes
;
1705 ULONG SystemCallNumber
= TrapFrame
->Eax
;
1707 /* Get the current thread */
1708 Thread
= KeGetCurrentThread();
1710 /* Set debug header */
1711 KiFillTrapFrameDebug(TrapFrame
);
1713 /* Chain trap frames */
1714 TrapFrame
->Edx
= (ULONG_PTR
)Thread
->TrapFrame
;
1717 TrapFrame
->ErrCode
= 0;
1719 /* Save previous mode */
1720 TrapFrame
->PreviousPreviousMode
= Thread
->PreviousMode
;
1722 /* Save the SEH chain and terminate it for now */
1723 TrapFrame
->ExceptionList
= KeGetPcr()->NtTib
.ExceptionList
;
1724 KeGetPcr()->NtTib
.ExceptionList
= EXCEPTION_CHAIN_END
;
1726 /* Default to debugging disabled */
1729 /* Check if the frame was from user mode */
1730 if (KiUserTrap(TrapFrame
))
1732 /* Check for active debugging */
1733 if (KeGetCurrentThread()->Header
.DebugActive
& 0xFF)
1735 /* Handle debug registers */
1736 KiHandleDebugRegistersOnTrapEntry(TrapFrame
);
1740 /* Set thread fields */
1741 Thread
->TrapFrame
= TrapFrame
;
1742 Thread
->PreviousMode
= KiUserTrap(TrapFrame
);
1744 /* Enable interrupts */
1747 /* Decode the system call number */
1748 Offset
= (SystemCallNumber
>> SERVICE_TABLE_SHIFT
) & SERVICE_TABLE_MASK
;
1749 Id
= SystemCallNumber
& SERVICE_NUMBER_MASK
;
1751 /* Get descriptor table */
1752 DescriptorTable
= (PVOID
)((ULONG_PTR
)Thread
->ServiceTable
+ Offset
);
1754 /* Validate the system call number */
1755 if (__builtin_expect(Id
>= DescriptorTable
->Limit
, 0))
1757 /* Check if this is a GUI call */
1758 if (!(Offset
& SERVICE_TABLE_TEST
))
1761 Status
= STATUS_INVALID_SYSTEM_SERVICE
;
1765 /* Convert us to a GUI thread -- must wrap in ASM to get new EBP */
1766 Status
= KiConvertToGuiThread();
1768 /* Reload trap frame and descriptor table pointer from new stack */
1769 TrapFrame
= *(volatile PVOID
*)&Thread
->TrapFrame
;
1770 DescriptorTable
= (PVOID
)(*(volatile ULONG_PTR
*)&Thread
->ServiceTable
+ Offset
);
1772 if (!NT_SUCCESS(Status
))
1774 /* Set the last error and fail */
1778 /* Validate the system call number again */
1779 if (Id
>= DescriptorTable
->Limit
)
1782 Status
= STATUS_INVALID_SYSTEM_SERVICE
;
1787 /* Check if this is a GUI call */
1788 if (__builtin_expect(Offset
& SERVICE_TABLE_TEST
, 0))
1790 /* Get the batch count and flush if necessary */
1791 if (NtCurrentTeb()->GdiBatchCount
) KeGdiFlushUserBatch();
1794 /* Increase system call count */
1795 KeGetCurrentPrcb()->KeSystemCalls
++;
1797 /* FIXME: Increase individual counts on debug systems */
1798 //KiIncreaseSystemCallCount(DescriptorTable, Id);
1800 /* Get stack bytes */
1801 StackBytes
= DescriptorTable
->Number
[Id
];
1803 /* Probe caller stack */
1804 if (__builtin_expect((Arguments
< (PVOID
)MmUserProbeAddress
) && !(KiUserTrap(TrapFrame
)), 0))
1806 /* Access violation */
1807 UNIMPLEMENTED_FATAL();
1810 /* Call pre-service debug hook */
1811 KiDbgPreServiceHook(SystemCallNumber
, Arguments
);
1813 /* Get the handler and make the system call */
1814 Handler
= (PVOID
)DescriptorTable
->Base
[Id
];
1815 Status
= KiSystemCallTrampoline(Handler
, Arguments
, StackBytes
);
1817 /* Call post-service debug hook */
1818 Status
= KiDbgPostServiceHook(SystemCallNumber
, Status
);
1820 /* Make sure we're exiting correctly */
1821 KiExitSystemCallDebugChecks(Id
, TrapFrame
);
1823 /* Restore the old trap frame */
1825 Thread
->TrapFrame
= (PKTRAP_FRAME
)TrapFrame
->Edx
;
1827 /* Exit from system call */
1828 KiServiceExit(TrapFrame
, Status
);
1833 KiCheckForSListAddress(IN PKTRAP_FRAME TrapFrame
)
1843 Kei386EoiHelper(VOID
)
1845 /* We should never see this call happening */
1846 KeBugCheck(MISMATCHED_HAL
);