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.
480 /* Get the current TSS, thread, and process */
482 Thread
= ((PKIPCR
)PCR
)->PrcbData
.CurrentThread
;
483 Process
= Thread
->ApcState
.Process
;
485 /* Save data usually not present in the TSS */
486 Tss
->CR3
= Process
->DirectoryTableBase
[0];
487 Tss
->IoMapBase
= Process
->IopmOffset
;
488 Tss
->LDT
= Process
->LdtDescriptor
.LimitLow
? KGDT_LDT
: 0;
490 /* Now get the base address of the NMI TSS */
491 TssGdt
= &((PKIPCR
)KeGetPcr())->GDT
[KGDT_NMI_TSS
/ sizeof(KGDTENTRY
)];
492 NmiTss
= (PKTSS
)(ULONG_PTR
)(TssGdt
->BaseLow
|
493 TssGdt
->HighWord
.Bytes
.BaseMid
<< 16 |
494 TssGdt
->HighWord
.Bytes
.BaseHi
<< 24);
497 * Switch to it and activate it, masking off the nested flag.
499 * Note that in reality, we are already on the NMI TSS -- we just
500 * need to update the PCR to reflect this.
503 __writeeflags(__readeflags() &~ EFLAGS_NESTED_TASK
);
504 TssGdt
->HighWord
.Bits
.Dpl
= 0;
505 TssGdt
->HighWord
.Bits
.Pres
= 1;
506 TssGdt
->HighWord
.Bits
.Type
= I386_TSS
;
509 * Now build the trap frame based on the original TSS.
511 * The CPU does a hardware "Context switch" / task switch of sorts
512 * and so it takes care of saving our context in the normal TSS.
514 * We just have to go get the values...
516 RtlZeroMemory(&TrapFrame
, sizeof(KTRAP_FRAME
));
517 TrapFrame
.HardwareSegSs
= Tss
->Ss0
;
518 TrapFrame
.HardwareEsp
= Tss
->Esp0
;
519 TrapFrame
.EFlags
= Tss
->EFlags
;
520 TrapFrame
.SegCs
= Tss
->Cs
;
521 TrapFrame
.Eip
= Tss
->Eip
;
522 TrapFrame
.Ebp
= Tss
->Ebp
;
523 TrapFrame
.Ebx
= Tss
->Ebx
;
524 TrapFrame
.Esi
= Tss
->Esi
;
525 TrapFrame
.Edi
= Tss
->Edi
;
526 TrapFrame
.SegFs
= Tss
->Fs
;
527 TrapFrame
.ExceptionList
= PCR
->NtTib
.ExceptionList
;
528 TrapFrame
.PreviousPreviousMode
= (ULONG
)-1;
529 TrapFrame
.Eax
= Tss
->Eax
;
530 TrapFrame
.Ecx
= Tss
->Ecx
;
531 TrapFrame
.Edx
= Tss
->Edx
;
532 TrapFrame
.SegDs
= Tss
->Ds
;
533 TrapFrame
.SegEs
= Tss
->Es
;
534 TrapFrame
.SegGs
= Tss
->Gs
;
535 TrapFrame
.DbgEip
= Tss
->Eip
;
536 TrapFrame
.DbgEbp
= Tss
->Ebp
;
538 /* Store the trap frame in the KPRCB */
539 KiSaveProcessorState(&TrapFrame
, NULL
);
541 /* Call any registered NMI handlers and see if they handled it or not */
545 * They did not, so call the platform HAL routine to bugcheck the system
547 * Make sure the HAL believes it's running at HIGH IRQL... we can't use
548 * the normal APIs here as playing with the IRQL could change the system
552 PCR
->Irql
= HIGH_LEVEL
;
558 * Although the CPU disabled NMIs, we just did a BIOS call, which could've
559 * totally changed things.
561 * We have to make sure we're still in our original NMI -- a nested NMI
562 * will point back to the NMI TSS, and in that case we're hosed.
564 if (PCR
->TSS
->Backlink
!= KGDT_NMI_TSS
)
566 /* Restore original TSS */
569 /* Set it back to busy */
570 TssGdt
->HighWord
.Bits
.Dpl
= 0;
571 TssGdt
->HighWord
.Bits
.Pres
= 1;
572 TssGdt
->HighWord
.Bits
.Type
= I386_ACTIVE_TSS
;
574 /* Restore nested flag */
575 __writeeflags(__readeflags() | EFLAGS_NESTED_TASK
);
577 /* Handled, return from interrupt */
581 /* Unhandled: crash the system */
582 KiSystemFatalException(EXCEPTION_NMI
, NULL
);
588 KiTrap03Handler(IN PKTRAP_FRAME TrapFrame
)
590 /* Save trap frame */
591 KiEnterTrap(TrapFrame
);
593 /* Continue with the common handler */
594 KiDebugHandler(TrapFrame
, BREAKPOINT_BREAK
, 0, 0);
600 KiTrap04Handler(IN PKTRAP_FRAME TrapFrame
)
602 /* Save trap frame */
603 KiEnterTrap(TrapFrame
);
605 /* Check for VDM trap */
606 ASSERT(KiVdmTrap(TrapFrame
) == FALSE
);
608 /* Enable interrupts */
611 /* Dispatch the exception */
612 KiDispatchException0Args(STATUS_INTEGER_OVERFLOW
,
620 KiTrap05Handler(IN PKTRAP_FRAME TrapFrame
)
622 /* Save trap frame */
623 KiEnterTrap(TrapFrame
);
625 /* Check for VDM trap */
626 ASSERT(KiVdmTrap(TrapFrame
) == FALSE
);
628 /* Check for kernel-mode fault */
629 if (!KiUserTrap(TrapFrame
)) KiSystemFatalException(EXCEPTION_BOUND_CHECK
, TrapFrame
);
631 /* Enable interrupts */
634 /* Dispatch the exception */
635 KiDispatchException0Args(STATUS_ARRAY_BOUNDS_EXCEEDED
,
643 KiTrap06Handler(IN PKTRAP_FRAME TrapFrame
)
649 /* Check for V86 GPF */
650 if (__builtin_expect(KiV86Trap(TrapFrame
), 1))
653 KiEnterV86Trap(TrapFrame
);
655 /* Must be a VDM process */
656 if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects
, 0))
658 /* Enable interrupts */
661 /* Setup illegal instruction fault */
662 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION
,
667 /* Go to APC level */
668 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
672 if (!VdmDispatchBop(TrapFrame
))
674 /* Should only happen in VDM mode */
675 UNIMPLEMENTED_FATAL();
678 /* Bring IRQL back */
679 KeLowerIrql(OldIrql
);
682 /* Do a quick V86 exit if possible */
683 KiExitV86Trap(TrapFrame
);
686 /* Save trap frame */
687 KiEnterTrap(TrapFrame
);
689 /* Enable interrupts */
690 Instruction
= (PUCHAR
)TrapFrame
->Eip
;
693 /* Check for user trap */
694 if (KiUserTrap(TrapFrame
))
698 /* Scan next 4 opcodes */
699 for (i
= 0; i
< 4; i
++)
701 /* Check for LOCK instruction */
702 if (Instruction
[i
] == 0xF0)
704 /* Send invalid lock sequence exception */
705 KiDispatchException0Args(STATUS_INVALID_LOCK_SEQUENCE
,
711 /* FIXME: SEH ends here */
714 /* Kernel-mode or user-mode fault (but not LOCK) */
715 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION
,
724 KiTrap07Handler(IN PKTRAP_FRAME TrapFrame
)
726 PKTHREAD Thread
, NpxThread
;
727 PFX_SAVE_AREA SaveArea
, NpxSaveArea
;
730 /* Save trap frame */
731 KiEnterTrap(TrapFrame
);
733 /* Try to handle NPX delay load */
736 /* Get the current thread */
737 Thread
= KeGetCurrentThread();
739 /* Get the NPX frame */
740 SaveArea
= KiGetThreadNpxArea(Thread
);
742 /* Check if emulation is enabled */
743 if (SaveArea
->Cr0NpxState
& CR0_EM
)
745 /* Not implemented */
746 UNIMPLEMENTED_FATAL();
749 /* Save CR0 and check NPX state */
751 if (Thread
->NpxState
!= NPX_STATE_LOADED
)
754 Cr0
&= ~(CR0_MP
| CR0_EM
| CR0_TS
);
757 /* Get the NPX thread */
758 NpxThread
= KeGetCurrentPrcb()->NpxThread
;
761 /* Get the NPX frame */
762 NpxSaveArea
= KiGetThreadNpxArea(NpxThread
);
765 Ke386SaveFpuState(NpxSaveArea
);
767 /* Update NPX state */
768 NpxThread
->NpxState
= NPX_STATE_NOT_LOADED
;
772 Ke386LoadFpuState(SaveArea
);
774 /* Update NPX state */
775 Thread
->NpxState
= NPX_STATE_LOADED
;
776 KeGetCurrentPrcb()->NpxThread
= Thread
;
778 /* Enable interrupts */
781 /* Check if CR0 needs to be reloaded due to context switch */
782 if (!SaveArea
->Cr0NpxState
) KiEoiHelper(TrapFrame
);
784 /* Otherwise, we need to reload CR0, disable interrupts */
789 Cr0
|= SaveArea
->Cr0NpxState
;
792 /* Now restore interrupts and check for TS */
794 if (Cr0
& CR0_TS
) KiEoiHelper(TrapFrame
);
796 /* We're still here -- clear TS and try again */
797 __writecr0(__readcr0() &~ CR0_TS
);
802 /* This is an actual fault, not a lack of FPU state */
807 /* TS should not be set */
811 * If it's incorrectly set, then maybe the state is actually still valid
812 * but we could have lost track of that due to a BIOS call.
813 * Make sure MP is still set, which should verify the theory.
817 /* Indeed, the state is actually still valid, so clear TS */
818 __writecr0(__readcr0() &~ CR0_TS
);
819 KiEoiHelper(TrapFrame
);
822 /* Otherwise, something strange is going on */
823 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 2, Cr0
, 0, 0, TrapFrame
);
826 /* It's not a delayed load, so process this trap as an NPX fault */
827 KiNpxHandler(TrapFrame
, Thread
, SaveArea
);
833 KiTrap08Handler(IN PKTRAP_FRAME TrapFrame
)
835 /* FIXME: Not handled */
836 KiSystemFatalException(EXCEPTION_DOUBLE_FAULT
, TrapFrame
);
842 KiTrap09Handler(IN PKTRAP_FRAME TrapFrame
)
844 /* Save trap frame */
845 KiEnterTrap(TrapFrame
);
847 /* Enable interrupts and kill the system */
849 KiSystemFatalException(EXCEPTION_NPX_OVERRUN
, TrapFrame
);
855 KiTrap0AHandler(IN PKTRAP_FRAME TrapFrame
)
857 /* Save trap frame */
858 KiEnterTrap(TrapFrame
);
860 /* Check for VDM trap */
861 ASSERT(KiVdmTrap(TrapFrame
) == FALSE
);
863 /* Kill the system */
864 KiSystemFatalException(EXCEPTION_INVALID_TSS
, TrapFrame
);
870 KiTrap0BHandler(IN PKTRAP_FRAME TrapFrame
)
872 /* Save trap frame */
873 KiEnterTrap(TrapFrame
);
875 /* FIXME: Kill the system */
877 KiSystemFatalException(EXCEPTION_SEGMENT_NOT_PRESENT
, TrapFrame
);
883 KiTrap0CHandler(IN PKTRAP_FRAME TrapFrame
)
885 /* Save trap frame */
886 KiEnterTrap(TrapFrame
);
888 /* FIXME: Kill the system */
890 KiSystemFatalException(EXCEPTION_STACK_FAULT
, TrapFrame
);
896 KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame
)
899 BOOLEAN Privileged
= FALSE
;
901 UCHAR Instruction
= 0;
904 /* Check for V86 GPF */
905 if (__builtin_expect(KiV86Trap(TrapFrame
), 1))
908 KiEnterV86Trap(TrapFrame
);
910 /* Must be a VDM process */
911 if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects
, 0))
913 /* Enable interrupts */
916 /* Setup illegal instruction fault */
917 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION
,
922 /* Go to APC level */
923 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
926 /* Handle the V86 opcode */
927 if (__builtin_expect(Ki386HandleOpcodeV86(TrapFrame
) == 0xFF, 0))
929 /* Should only happen in VDM mode */
930 UNIMPLEMENTED_FATAL();
933 /* Bring IRQL back */
934 KeLowerIrql(OldIrql
);
937 /* Do a quick V86 exit if possible */
938 KiExitV86Trap(TrapFrame
);
941 /* Save trap frame */
942 KiEnterTrap(TrapFrame
);
944 /* Check for user-mode GPF */
945 if (KiUserTrap(TrapFrame
))
947 /* Should not be VDM */
948 ASSERT(KiVdmTrap(TrapFrame
) == FALSE
);
950 /* Enable interrupts and check error code */
952 if (!TrapFrame
->ErrCode
)
955 Instructions
= (PUCHAR
)TrapFrame
->Eip
;
957 /* Scan next 15 bytes */
958 for (i
= 0; i
< 15; i
++)
960 /* Skip prefix instructions */
961 for (j
= 0; j
< sizeof(KiTrapPrefixTable
); j
++)
963 /* Is this a prefix instruction? */
964 if (Instructions
[i
] == KiTrapPrefixTable
[j
])
971 /* Is this NOT any prefix instruction? */
972 if (j
== sizeof(KiTrapPrefixTable
))
974 /* We can go ahead and handle the fault now */
975 Instruction
= Instructions
[i
];
980 /* If all we found was prefixes, then this instruction is too long */
983 /* Setup illegal instruction fault */
984 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION
,
989 /* Check for privileged instructions */
990 DPRINT("Instruction (%lu) at fault: %lx %lx %lx %lx\n",
995 Instructions
[i
+ 3]);
996 if (Instruction
== 0xF4) // HLT
998 /* HLT is privileged */
1001 else if (Instruction
== 0x0F)
1003 /* Test if it's any of the privileged two-byte opcodes */
1004 if (((Instructions
[i
+ 1] == 0x00) && // LLDT or LTR
1005 (((Instructions
[i
+ 2] & 0x38) == 0x10) || // LLDT
1006 (Instructions
[i
+ 2] == 0x18))) || // LTR
1007 ((Instructions
[i
+ 1] == 0x01) && // LGDT or LIDT or LMSW
1008 (((Instructions
[i
+ 2] & 0x38) == 0x10) || // LGDT
1009 (Instructions
[i
+ 2] == 0x18) || // LIDT
1010 (Instructions
[i
+ 2] == 0x30))) || // LMSW
1011 (Instructions
[i
+ 1] == 0x08) || // INVD
1012 (Instructions
[i
+ 1] == 0x09) || // WBINVD
1013 (Instructions
[i
+ 1] == 0x35) || // SYSEXIT
1014 (Instructions
[i
+ 1] == 0x21) || // MOV DR, XXX
1015 (Instructions
[i
+ 1] == 0x06) || // CLTS
1016 (Instructions
[i
+ 1] == 0x20) || // MOV CR, XXX
1017 (Instructions
[i
+ 1] == 0x22) || // MOV XXX, CR
1018 (Instructions
[i
+ 1] == 0x23) || // MOV YYY, DR
1019 (Instructions
[i
+ 1] == 0x30) || // WRMSR
1020 (Instructions
[i
+ 1] == 0x33)) // RDPMC
1021 // INVLPG, INVLPGA, SYSRET
1023 /* These are all privileged */
1029 /* Get the IOPL and compare with the RPL mask */
1030 Iopl
= (TrapFrame
->EFlags
& EFLAGS_IOPL
) >> 12;
1031 if ((TrapFrame
->SegCs
& RPL_MASK
) > Iopl
)
1033 /* I/O privilege error -- check for known instructions */
1034 if ((Instruction
== 0xFA) || (Instruction
== 0xFB)) // CLI or STI
1036 /* These are privileged */
1041 /* Last hope: an IN/OUT instruction */
1042 for (j
= 0; j
< sizeof(KiTrapIoTable
); j
++)
1044 /* Is this an I/O instruction? */
1045 if (Instruction
== KiTrapIoTable
[j
])
1047 /* Then it's privileged */
1056 /* So now... was the instruction privileged or not? */
1059 /* Whew! We have a privileged instruction, so dispatch the fault */
1060 KiDispatchException0Args(STATUS_PRIVILEGED_INSTRUCTION
,
1066 /* If we got here, send an access violation */
1067 KiDispatchException2Args(STATUS_ACCESS_VIOLATION
,
1075 * Check for a fault during checking of the user instruction.
1077 * Note that the SEH handler will catch invalid EIP, but we could be dealing
1078 * with an invalid CS, which will generate another GPF instead.
1081 if (((PVOID
)TrapFrame
->Eip
>= (PVOID
)KiTrap0DHandler
) &&
1082 ((PVOID
)TrapFrame
->Eip
< (PVOID
)KiTrap0DHandler
))
1084 /* Not implemented */
1085 UNIMPLEMENTED_FATAL();
1089 * NOTE: The ASM trap exit code would restore segment registers by doing
1090 * a POP <SEG>, which could cause an invalid segment if someone had messed
1091 * with the segment values.
1093 * Another case is a bogus SS, which would hit a GPF when doing the iret.
1094 * This could only be done through a buggy or malicious driver, or perhaps
1095 * the kernel debugger.
1097 * The kernel normally restores the "true" segment if this happens.
1099 * However, since we're restoring in C, not ASM, we can't detect
1100 * POP <SEG> since the actual instructions will be different.
1102 * A better technique would be to check the EIP and somehow edit the
1103 * trap frame before restarting the instruction -- but we would need to
1104 * know the extract instruction that was used first.
1106 * We could force a special instrinsic to use stack instructions, or write
1107 * a simple instruction length checker.
1109 * Nevertheless, this is a lot of work for the purpose of avoiding a crash
1110 * when the user is purposedly trying to create one from kernel-mode, so
1111 * we should probably table this for now since it's not a "real" issue.
1115 * NOTE2: Another scenario is the IRET during a V8086 restore (BIOS Call)
1116 * which will cause a GPF since the trap frame is a total mess (on purpose)
1117 * as built in KiEnterV86Mode.
1119 * The idea is to scan for IRET, scan for the known EIP adress, validate CS
1120 * and then manually issue a jump to the V8086 return EIP.
1122 Instructions
= (PUCHAR
)TrapFrame
->Eip
;
1123 if (Instructions
[0] == 0xCF)
1126 * Some evil shit is going on here -- this is not the SS:ESP you're
1127 * looking for! Instead, this is actually CS:EIP you're looking at!
1128 * Why? Because part of the trap frame actually corresponds to the IRET
1129 * stack during the trap exit!
1131 if ((TrapFrame
->HardwareEsp
== (ULONG
)Ki386BiosCallReturnAddress
) &&
1132 (TrapFrame
->HardwareSegSs
== (KGDT_R0_CODE
| RPL_MASK
)))
1134 /* Exit the V86 trap! */
1135 Ki386BiosCallReturnAddress(TrapFrame
);
1139 /* Otherwise, this is another kind of IRET fault */
1140 UNIMPLEMENTED_FATAL();
1144 /* So since we're not dealing with the above case, check for RDMSR/WRMSR */
1145 if ((Instructions
[0] == 0xF) && // 2-byte opcode
1146 ((Instructions
[1] == 0x32) || // RDMSR
1147 (Instructions
[1] == 0x30))) // WRMSR
1149 /* Unknown CPU MSR, so raise an access violation */
1150 KiDispatchException0Args(STATUS_ACCESS_VIOLATION
,
1155 /* Check for lazy segment load */
1156 if (TrapFrame
->SegDs
!= (KGDT_R3_DATA
| RPL_MASK
))
1159 TrapFrame
->SegDs
= (KGDT_R3_DATA
| RPL_MASK
);
1161 else if (TrapFrame
->SegEs
!= (KGDT_R3_DATA
| RPL_MASK
))
1164 TrapFrame
->SegEs
= (KGDT_R3_DATA
| RPL_MASK
);
1168 /* Whatever it is, we can't handle it */
1169 KiSystemFatalException(EXCEPTION_GP_FAULT
, TrapFrame
);
1172 /* Return to where we came from */
1173 KiTrapReturn(TrapFrame
);
1179 KiTrap0EHandler(IN PKTRAP_FRAME TrapFrame
)
1182 BOOLEAN StoreInstruction
;
1186 /* Save trap frame */
1187 KiEnterTrap(TrapFrame
);
1189 /* Check if this is the base frame */
1190 Thread
= KeGetCurrentThread();
1191 if (KeGetTrapFrame(Thread
) != TrapFrame
)
1193 /* It isn't, check if this is a second nested frame */
1194 if (((ULONG_PTR
)KeGetTrapFrame(Thread
) - (ULONG_PTR
)TrapFrame
) <=
1195 FIELD_OFFSET(KTRAP_FRAME
, EFlags
))
1197 /* The stack is somewhere in between frames, we need to fix it */
1198 UNIMPLEMENTED_FATAL();
1205 /* Enable interrupts */
1208 /* Interpret the error code */
1209 StoreInstruction
= (TrapFrame
->ErrCode
& 2) != 0;
1211 /* Check if we came in with interrupts disabled */
1212 if (!(TrapFrame
->EFlags
& EFLAGS_INTERRUPT_MASK
))
1214 /* This is completely illegal, bugcheck the system */
1215 KeBugCheckWithTf(IRQL_NOT_LESS_OR_EQUAL
,
1223 /* Check for S-List fault
1225 Explanation: An S-List fault can occur due to a race condition between 2
1226 threads simultaneously trying to pop an element from the S-List. After
1227 thread 1 has read the pointer to the top element on the S-List it is
1228 preempted and thread 2 calls InterlockedPopEntrySlist on the same S-List,
1229 removing the top element and freeing it's memory. After that thread 1
1230 resumes and tries to read the address of the Next pointer from the top
1231 element, which it assumes will be the next top element.
1232 But since that memory has been freed, we get a page fault. To handle this
1233 race condition, we let thread 1 repeat the operation.
1234 We do NOT invoke the page fault handler in this case, since we do not
1235 want to trigger any side effects, like paging or a guard page fault.
1237 Sequence of operations:
1239 Thread 1 : mov eax, [ebp] <= eax now points to the first element
1240 Thread 1 : mov edx, [ebp + 4] <= edx is loaded with Depth and Sequence
1242 Thread 2 : calls InterlockedPopEntrySlist, changing the top element
1243 Thread 2 : frees the memory of the element that was popped
1245 Thread 1 : checks if eax is NULL
1246 Thread 1 : InterlockedPopEntrySListFault: mov ebx, [eax] <= faults
1248 To be sure that we are dealing with exactly the case described above, we
1249 check whether the ListHeader has changed. If Thread 2 only popped one
1250 entry, the Next field in the S-List-header has changed.
1251 If after thread 1 has faulted, thread 2 allocates a new element, by
1252 chance getting the same address as the previously freed element and
1253 pushes it on the list again, we will see the same top element, but the
1254 Sequence member of the S-List header has changed. Therefore we check
1255 both fields to make sure we catch any concurrent modification of the
1258 if ((TrapFrame
->Eip
== (ULONG_PTR
)ExpInterlockedPopEntrySListFault
) ||
1259 (TrapFrame
->Eip
== (ULONG_PTR
)KeUserPopEntrySListFault
))
1261 ULARGE_INTEGER SListHeader
;
1262 PVOID ResumeAddress
;
1264 /* Sanity check that the assembly is correct:
1265 This must be mov ebx, [eax]
1266 Followed by cmpxchg8b [ebp] */
1267 ASSERT((((UCHAR
*)TrapFrame
->Eip
)[0] == 0x8B) &&
1268 (((UCHAR
*)TrapFrame
->Eip
)[1] == 0x18) &&
1269 (((UCHAR
*)TrapFrame
->Eip
)[2] == 0x0F) &&
1270 (((UCHAR
*)TrapFrame
->Eip
)[3] == 0xC7) &&
1271 (((UCHAR
*)TrapFrame
->Eip
)[4] == 0x4D) &&
1272 (((UCHAR
*)TrapFrame
->Eip
)[5] == 0x00));
1274 /* Check if this is a user fault */
1275 if (TrapFrame
->Eip
== (ULONG_PTR
)KeUserPopEntrySListFault
)
1277 /* EBP points to the S-List-header. Copy it inside SEH, to protect
1278 against a bogus pointer from user mode */
1281 ProbeForRead((PVOID
)TrapFrame
->Ebp
,
1282 sizeof(ULARGE_INTEGER
),
1283 TYPE_ALIGNMENT(SLIST_HEADER
));
1284 SListHeader
= *(PULARGE_INTEGER
)TrapFrame
->Ebp
;
1286 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1288 /* The S-List pointer is not valid! */
1292 ResumeAddress
= KeUserPopEntrySListResume
;
1296 SListHeader
= *(PULARGE_INTEGER
)TrapFrame
->Ebp
;
1297 ResumeAddress
= ExpInterlockedPopEntrySListResume
;
1300 /* Check if either the Next pointer or the Sequence member in the
1301 S-List-header has changed. If any of these has changed, we restart
1302 the operation. Otherwise we only have a bogus pointer and let the
1303 page fault handler deal with it. */
1304 if ((SListHeader
.LowPart
!= TrapFrame
->Eax
) ||
1305 (SListHeader
.HighPart
!= TrapFrame
->Edx
))
1307 DPRINT1("*** Got an S-List-Fault ***\n");
1308 KeGetCurrentThread()->SListFaultCount
++;
1310 /* Restart the operation */
1311 TrapFrame
->Eip
= (ULONG_PTR
)ResumeAddress
;
1313 /* Continue execution */
1314 KiEoiHelper(TrapFrame
);
1319 /* Call the access fault handler */
1320 Status
= MmAccessFault(TrapFrame
->ErrCode
,
1322 KiUserTrap(TrapFrame
),
1324 if (NT_SUCCESS(Status
))
1327 /* Check whether the kernel debugger has owed breakpoints to be inserted */
1328 KdSetOwedBreakpoints();
1330 /* We succeeded, return */
1331 KiEoiHelper(TrapFrame
);
1334 /* Check for syscall fault */
1336 if ((TrapFrame
->Eip
== (ULONG_PTR
)CopyParams
) ||
1337 (TrapFrame
->Eip
== (ULONG_PTR
)ReadBatch
))
1339 /* Not yet implemented */
1340 UNIMPLEMENTED_FATAL();
1344 /* Check for VDM trap */
1345 if (KiVdmTrap(TrapFrame
))
1347 DPRINT1("VDM PAGE FAULT at %lx:%lx for address %lx\n",
1348 TrapFrame
->SegCs
, TrapFrame
->Eip
, Cr2
);
1349 if (VdmDispatchPageFault(TrapFrame
))
1351 /* Return and end VDM execution */
1352 DPRINT1("VDM page fault with status 0x%lx resolved\n", Status
);
1353 KiEoiHelper(TrapFrame
);
1355 DPRINT1("VDM page fault with status 0x%lx NOT resolved\n", Status
);
1358 /* Either kernel or user trap (non VDM) so dispatch exception */
1359 if (Status
== STATUS_ACCESS_VIOLATION
)
1361 /* This status code is repurposed so we can recognize it later */
1362 KiDispatchException2Args(KI_EXCEPTION_ACCESS_VIOLATION
,
1368 else if ((Status
== STATUS_GUARD_PAGE_VIOLATION
) ||
1369 (Status
== STATUS_STACK_OVERFLOW
))
1371 /* These faults only have two parameters */
1372 KiDispatchException2Args(Status
,
1379 /* Only other choice is an in-page error, with 3 parameters */
1380 KiDispatchExceptionFromTrapFrame(STATUS_IN_PAGE_ERROR
,
1393 KiTrap0FHandler(IN PKTRAP_FRAME TrapFrame
)
1395 /* Save trap frame */
1396 KiEnterTrap(TrapFrame
);
1398 /* FIXME: Kill the system */
1400 KiSystemFatalException(EXCEPTION_RESERVED_TRAP
, TrapFrame
);
1406 KiTrap10Handler(IN PKTRAP_FRAME TrapFrame
)
1409 PFX_SAVE_AREA SaveArea
;
1411 /* Save trap frame */
1412 KiEnterTrap(TrapFrame
);
1414 /* Check if this is the NPX thrad */
1415 Thread
= KeGetCurrentThread();
1416 SaveArea
= KiGetThreadNpxArea(Thread
);
1417 if (Thread
!= KeGetCurrentPrcb()->NpxThread
)
1419 /* It isn't, enable interrupts and set delayed error */
1421 SaveArea
->Cr0NpxState
|= CR0_TS
;
1424 KiEoiHelper(TrapFrame
);
1427 /* Otherwise, proceed with NPX fault handling */
1428 KiNpxHandler(TrapFrame
, Thread
, SaveArea
);
1434 KiTrap11Handler(IN PKTRAP_FRAME TrapFrame
)
1436 /* Save trap frame */
1437 KiEnterTrap(TrapFrame
);
1439 /* Enable interrupts and kill the system */
1441 KiSystemFatalException(EXCEPTION_ALIGNMENT_CHECK
, TrapFrame
);
1447 KiTrap13Handler(IN PKTRAP_FRAME TrapFrame
)
1450 PFX_SAVE_AREA SaveArea
;
1451 ULONG Cr0
, MxCsrMask
, Error
;
1453 /* Save trap frame */
1454 KiEnterTrap(TrapFrame
);
1456 /* Check if this is the NPX thrad */
1457 Thread
= KeGetCurrentThread();
1458 if (Thread
!= KeGetCurrentPrcb()->NpxThread
)
1460 /* It isn't, kill the system */
1461 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 13, (ULONG_PTR
)Thread
, 0, 0, TrapFrame
);
1464 /* Get the NPX frame */
1465 SaveArea
= KiGetThreadNpxArea(Thread
);
1467 /* Check for VDM trap */
1468 ASSERT(KiVdmTrap(TrapFrame
) == FALSE
);
1470 /* Check for user trap */
1471 if (!KiUserTrap(TrapFrame
))
1473 /* Kernel should not fault on XMMI */
1474 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 13, 0, 0, 2, TrapFrame
);
1479 Cr0
&= ~(CR0_MP
| CR0_EM
| CR0_TS
);
1482 /* Save FPU state */
1483 Ke386SaveFpuState(SaveArea
);
1485 /* Mark CR0 state dirty */
1486 Cr0
|= NPX_STATE_NOT_LOADED
;
1487 Cr0
|= SaveArea
->Cr0NpxState
;
1490 /* Update NPX state */
1491 Thread
->NpxState
= NPX_STATE_NOT_LOADED
;
1492 KeGetCurrentPrcb()->NpxThread
= NULL
;
1494 /* Clear the TS bit and re-enable interrupts */
1495 SaveArea
->Cr0NpxState
&= ~CR0_TS
;
1498 /* Now look at MxCsr to get the mask of errors we should care about */
1499 MxCsrMask
= ~((USHORT
)SaveArea
->U
.FxArea
.MXCsr
>> 7);
1501 /* Get legal exceptions that software should handle */
1502 Error
= (USHORT
)SaveArea
->U
.FxArea
.MXCsr
& (FSW_INVALID_OPERATION
|
1510 /* Now handle any of those legal errors */
1511 if (Error
& (FSW_INVALID_OPERATION
|
1518 /* By issuing an exception */
1519 KiDispatchException1Args(STATUS_FLOAT_MULTIPLE_TRAPS
,
1525 /* Unknown XMMI fault */
1526 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 13, 0, 0, 1, TrapFrame
);
1529 /* SOFTWARE SERVICES **********************************************************/
1533 KiRaiseSecurityCheckFailureHandler(IN PKTRAP_FRAME TrapFrame
)
1535 /* Save trap frame */
1536 KiEnterTrap(TrapFrame
);
1538 /* Decrement EIP to point to the INT29 instruction (2 bytes, not 1 like INT3) */
1539 TrapFrame
->Eip
-= 2;
1541 /* Check if this is a user trap */
1542 if (KiUserTrap(TrapFrame
))
1544 /* Dispatch exception to user mode */
1545 KiDispatchExceptionFromTrapFrame(STATUS_STACK_BUFFER_OVERRUN
,
1546 EXCEPTION_NONCONTINUABLE
,
1556 EXCEPTION_RECORD ExceptionRecord
;
1558 /* Bugcheck the system */
1559 ExceptionRecord
.ExceptionCode
= STATUS_STACK_BUFFER_OVERRUN
;
1560 ExceptionRecord
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
1561 ExceptionRecord
.ExceptionRecord
= NULL
;
1562 ExceptionRecord
.ExceptionAddress
= (PVOID
)TrapFrame
->Eip
;
1563 ExceptionRecord
.NumberParameters
= 1;
1564 ExceptionRecord
.ExceptionInformation
[0] = TrapFrame
->Ecx
;
1566 KeBugCheckWithTf(KERNEL_SECURITY_CHECK_FAILURE
,
1568 (ULONG_PTR
)TrapFrame
,
1569 (ULONG_PTR
)&ExceptionRecord
,
1577 KiGetTickCountHandler(IN PKTRAP_FRAME TrapFrame
)
1579 /* Save trap frame */
1580 KiEnterTrap(TrapFrame
);
1583 * Just fail the request
1585 DbgPrint("INT 0x2A attempted, returning 0 tick count\n");
1589 KiEoiHelper(TrapFrame
);
1594 KiCallbackReturnHandler(IN PKTRAP_FRAME TrapFrame
)
1599 /* Save the SEH chain, NtCallbackReturn will restore this */
1600 TrapFrame
->ExceptionList
= KeGetPcr()->NtTib
.ExceptionList
;
1602 /* Set thread fields */
1603 Thread
= KeGetCurrentThread();
1604 Thread
->TrapFrame
= TrapFrame
;
1605 Thread
->PreviousMode
= KiUserTrap(TrapFrame
);
1606 ASSERT(Thread
->PreviousMode
!= KernelMode
);
1608 /* Pass the register parameters to NtCallbackReturn.
1609 Result pointer is in ecx, result length in edx, status in eax */
1610 Status
= NtCallbackReturn((PVOID
)TrapFrame
->Ecx
,
1614 /* If we got here, something went wrong. Return an error to the caller */
1615 KiServiceExit(TrapFrame
, Status
);
1621 KiRaiseAssertionHandler(IN PKTRAP_FRAME TrapFrame
)
1623 /* Save trap frame */
1624 KiEnterTrap(TrapFrame
);
1626 /* Decrement EIP to point to the INT2C instruction (2 bytes, not 1 like INT3) */
1627 TrapFrame
->Eip
-= 2;
1629 /* Dispatch the exception */
1630 KiDispatchException0Args(STATUS_ASSERTION_FAILURE
,
1638 KiDebugServiceHandler(IN PKTRAP_FRAME TrapFrame
)
1640 /* Save trap frame */
1641 KiEnterTrap(TrapFrame
);
1643 /* Increment EIP to skip the INT3 instruction */
1646 /* Continue with the common handler */
1647 KiDebugHandler(TrapFrame
, TrapFrame
->Eax
, TrapFrame
->Ecx
, TrapFrame
->Edx
);
1653 KiDbgPreServiceHook(ULONG SystemCallNumber
, PULONG_PTR Arguments
)
1655 #if DBG && !defined(_WINKD_)
1656 if (SystemCallNumber
>= 0x1000 && KeWin32PreServiceHook
)
1657 KeWin32PreServiceHook(SystemCallNumber
, Arguments
);
1663 KiDbgPostServiceHook(ULONG SystemCallNumber
, ULONG_PTR Result
)
1665 #if DBG && !defined(_WINKD_)
1666 if (SystemCallNumber
>= 0x1000 && KeWin32PostServiceHook
)
1667 return KeWin32PostServiceHook(SystemCallNumber
, Result
);
1675 KiSystemServiceHandler(IN PKTRAP_FRAME TrapFrame
,
1679 PKSERVICE_TABLE_DESCRIPTOR DescriptorTable
;
1680 ULONG Id
, Offset
, StackBytes
;
1683 ULONG SystemCallNumber
= TrapFrame
->Eax
;
1685 /* Get the current thread */
1686 Thread
= KeGetCurrentThread();
1688 /* Set debug header */
1689 KiFillTrapFrameDebug(TrapFrame
);
1691 /* Chain trap frames */
1692 TrapFrame
->Edx
= (ULONG_PTR
)Thread
->TrapFrame
;
1695 TrapFrame
->ErrCode
= 0;
1697 /* Save previous mode */
1698 TrapFrame
->PreviousPreviousMode
= Thread
->PreviousMode
;
1700 /* Save the SEH chain and terminate it for now */
1701 TrapFrame
->ExceptionList
= KeGetPcr()->NtTib
.ExceptionList
;
1702 KeGetPcr()->NtTib
.ExceptionList
= EXCEPTION_CHAIN_END
;
1704 /* Default to debugging disabled */
1707 /* Check if the frame was from user mode */
1708 if (KiUserTrap(TrapFrame
))
1710 /* Check for active debugging */
1711 if (KeGetCurrentThread()->Header
.DebugActive
& 0xFF)
1713 /* Handle debug registers */
1714 KiHandleDebugRegistersOnTrapEntry(TrapFrame
);
1718 /* Set thread fields */
1719 Thread
->TrapFrame
= TrapFrame
;
1720 Thread
->PreviousMode
= KiUserTrap(TrapFrame
);
1722 /* Enable interrupts */
1725 /* Decode the system call number */
1726 Offset
= (SystemCallNumber
>> SERVICE_TABLE_SHIFT
) & SERVICE_TABLE_MASK
;
1727 Id
= SystemCallNumber
& SERVICE_NUMBER_MASK
;
1729 /* Get descriptor table */
1730 DescriptorTable
= (PVOID
)((ULONG_PTR
)Thread
->ServiceTable
+ Offset
);
1732 /* Validate the system call number */
1733 if (__builtin_expect(Id
>= DescriptorTable
->Limit
, 0))
1735 /* Check if this is a GUI call */
1736 if (!(Offset
& SERVICE_TABLE_TEST
))
1739 Status
= STATUS_INVALID_SYSTEM_SERVICE
;
1743 /* Convert us to a GUI thread -- must wrap in ASM to get new EBP */
1744 Status
= KiConvertToGuiThread();
1746 /* Reload trap frame and descriptor table pointer from new stack */
1747 TrapFrame
= *(volatile PVOID
*)&Thread
->TrapFrame
;
1748 DescriptorTable
= (PVOID
)(*(volatile ULONG_PTR
*)&Thread
->ServiceTable
+ Offset
);
1750 if (!NT_SUCCESS(Status
))
1752 /* Set the last error and fail */
1756 /* Validate the system call number again */
1757 if (Id
>= DescriptorTable
->Limit
)
1760 Status
= STATUS_INVALID_SYSTEM_SERVICE
;
1765 /* Check if this is a GUI call */
1766 if (__builtin_expect(Offset
& SERVICE_TABLE_TEST
, 0))
1768 /* Get the batch count and flush if necessary */
1769 if (NtCurrentTeb()->GdiBatchCount
) KeGdiFlushUserBatch();
1772 /* Increase system call count */
1773 KeGetCurrentPrcb()->KeSystemCalls
++;
1775 /* FIXME: Increase individual counts on debug systems */
1776 //KiIncreaseSystemCallCount(DescriptorTable, Id);
1778 /* Get stack bytes */
1779 StackBytes
= DescriptorTable
->Number
[Id
];
1781 /* Probe caller stack */
1782 if (__builtin_expect((Arguments
< (PVOID
)MmUserProbeAddress
) && !(KiUserTrap(TrapFrame
)), 0))
1784 /* Access violation */
1785 UNIMPLEMENTED_FATAL();
1788 /* Call pre-service debug hook */
1789 KiDbgPreServiceHook(SystemCallNumber
, Arguments
);
1791 /* Get the handler and make the system call */
1792 Handler
= (PVOID
)DescriptorTable
->Base
[Id
];
1793 Status
= KiSystemCallTrampoline(Handler
, Arguments
, StackBytes
);
1795 /* Call post-service debug hook */
1796 Status
= KiDbgPostServiceHook(SystemCallNumber
, Status
);
1798 /* Make sure we're exiting correctly */
1799 KiExitSystemCallDebugChecks(Id
, TrapFrame
);
1801 /* Restore the old trap frame */
1803 Thread
->TrapFrame
= (PKTRAP_FRAME
)TrapFrame
->Edx
;
1805 /* Exit from system call */
1806 KiServiceExit(TrapFrame
, Status
);
1811 KiCheckForSListAddress(IN PKTRAP_FRAME TrapFrame
)
1821 Kei386EoiHelper(VOID
)
1823 /* We should never see this call happening */
1824 KeBugCheck(MISMATCHED_HAL
);