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
,
460 KiTrap02Handler(VOID
)
466 KTRAP_FRAME TrapFrame
;
470 * In some sort of strange recursion case, we might end up here with the IF
471 * flag incorrectly on the interrupt frame -- during a normal NMI this would
472 * normally already be set.
474 * For sanity's sake, make sure interrupts are disabled for sure.
475 * NMIs will already be since the CPU does it for us.
479 /* Get the current TSS, thread, and process */
481 Thread
= ((PKIPCR
)PCR
)->PrcbData
.CurrentThread
;
482 Process
= Thread
->ApcState
.Process
;
484 /* Save data usually not present in the TSS */
485 Tss
->CR3
= Process
->DirectoryTableBase
[0];
486 Tss
->IoMapBase
= Process
->IopmOffset
;
487 Tss
->LDT
= Process
->LdtDescriptor
.LimitLow
? KGDT_LDT
: 0;
489 /* Now get the base address of the NMI TSS */
490 TssGdt
= &((PKIPCR
)KeGetPcr())->GDT
[KGDT_NMI_TSS
/ sizeof(KGDTENTRY
)];
491 NmiTss
= (PKTSS
)(ULONG_PTR
)(TssGdt
->BaseLow
|
492 TssGdt
->HighWord
.Bytes
.BaseMid
<< 16 |
493 TssGdt
->HighWord
.Bytes
.BaseHi
<< 24);
496 * Switch to it and activate it, masking off the nested flag.
498 * Note that in reality, we are already on the NMI TSS -- we just
499 * need to update the PCR to reflect this.
502 __writeeflags(__readeflags() &~ EFLAGS_NESTED_TASK
);
503 TssGdt
->HighWord
.Bits
.Dpl
= 0;
504 TssGdt
->HighWord
.Bits
.Pres
= 1;
505 TssGdt
->HighWord
.Bits
.Type
= I386_TSS
;
508 * Now build the trap frame based on the original TSS.
510 * The CPU does a hardware "Context switch" / task switch of sorts
511 * and so it takes care of saving our context in the normal TSS.
513 * We just have to go get the values...
515 RtlZeroMemory(&TrapFrame
, sizeof(KTRAP_FRAME
));
516 TrapFrame
.HardwareSegSs
= Tss
->Ss0
;
517 TrapFrame
.HardwareEsp
= Tss
->Esp0
;
518 TrapFrame
.EFlags
= Tss
->EFlags
;
519 TrapFrame
.SegCs
= Tss
->Cs
;
520 TrapFrame
.Eip
= Tss
->Eip
;
521 TrapFrame
.Ebp
= Tss
->Ebp
;
522 TrapFrame
.Ebx
= Tss
->Ebx
;
523 TrapFrame
.Esi
= Tss
->Esi
;
524 TrapFrame
.Edi
= Tss
->Edi
;
525 TrapFrame
.SegFs
= Tss
->Fs
;
526 TrapFrame
.ExceptionList
= PCR
->NtTib
.ExceptionList
;
527 TrapFrame
.PreviousPreviousMode
= (ULONG
)-1;
528 TrapFrame
.Eax
= Tss
->Eax
;
529 TrapFrame
.Ecx
= Tss
->Ecx
;
530 TrapFrame
.Edx
= Tss
->Edx
;
531 TrapFrame
.SegDs
= Tss
->Ds
;
532 TrapFrame
.SegEs
= Tss
->Es
;
533 TrapFrame
.SegGs
= Tss
->Gs
;
534 TrapFrame
.DbgEip
= Tss
->Eip
;
535 TrapFrame
.DbgEbp
= Tss
->Ebp
;
537 /* Store the trap frame in the KPRCB */
538 KiSaveProcessorState(&TrapFrame
, NULL
);
540 /* Call any registered NMI handlers and see if they handled it or not */
544 * They did not, so call the platform HAL routine to bugcheck the system
546 * Make sure the HAL believes it's running at HIGH IRQL... we can't use
547 * the normal APIs here as playing with the IRQL could change the system
551 PCR
->Irql
= HIGH_LEVEL
;
557 * Although the CPU disabled NMIs, we just did a BIOS call, which could've
558 * totally changed things.
560 * We have to make sure we're still in our original NMI -- a nested NMI
561 * will point back to the NMI TSS, and in that case we're hosed.
563 if (PCR
->TSS
->Backlink
== KGDT_NMI_TSS
)
565 /* Unhandled: crash the system */
566 KiSystemFatalException(EXCEPTION_NMI
, NULL
);
569 /* Restore original TSS */
572 /* Set it back to busy */
573 TssGdt
->HighWord
.Bits
.Dpl
= 0;
574 TssGdt
->HighWord
.Bits
.Pres
= 1;
575 TssGdt
->HighWord
.Bits
.Type
= I386_ACTIVE_TSS
;
577 /* Restore nested flag */
578 __writeeflags(__readeflags() | EFLAGS_NESTED_TASK
);
580 /* Handled, return from interrupt */
586 KiTrap03Handler(IN PKTRAP_FRAME TrapFrame
)
588 /* Save trap frame */
589 KiEnterTrap(TrapFrame
);
591 /* Continue with the common handler */
592 KiDebugHandler(TrapFrame
, BREAKPOINT_BREAK
, 0, 0);
598 KiTrap04Handler(IN PKTRAP_FRAME TrapFrame
)
600 /* Save trap frame */
601 KiEnterTrap(TrapFrame
);
603 /* Check for VDM trap */
604 ASSERT(KiVdmTrap(TrapFrame
) == FALSE
);
606 /* Enable interrupts */
609 /* Dispatch the exception */
610 KiDispatchException0Args(STATUS_INTEGER_OVERFLOW
,
618 KiTrap05Handler(IN PKTRAP_FRAME TrapFrame
)
620 /* Save trap frame */
621 KiEnterTrap(TrapFrame
);
623 /* Check for VDM trap */
624 ASSERT(KiVdmTrap(TrapFrame
) == FALSE
);
626 /* Check for kernel-mode fault */
627 if (!KiUserTrap(TrapFrame
)) KiSystemFatalException(EXCEPTION_BOUND_CHECK
, TrapFrame
);
629 /* Enable interrupts */
632 /* Dispatch the exception */
633 KiDispatchException0Args(STATUS_ARRAY_BOUNDS_EXCEEDED
,
641 KiTrap06Handler(IN PKTRAP_FRAME TrapFrame
)
647 /* Check for V86 GPF */
648 if (__builtin_expect(KiV86Trap(TrapFrame
), 1))
651 KiEnterV86Trap(TrapFrame
);
653 /* Must be a VDM process */
654 if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects
, 0))
656 /* Enable interrupts */
659 /* Setup illegal instruction fault */
660 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION
,
665 /* Go to APC level */
666 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
670 if (!VdmDispatchBop(TrapFrame
))
672 /* Should only happen in VDM mode */
673 UNIMPLEMENTED_FATAL();
676 /* Bring IRQL back */
677 KeLowerIrql(OldIrql
);
680 /* Do a quick V86 exit if possible */
681 KiExitV86Trap(TrapFrame
);
684 /* Save trap frame */
685 KiEnterTrap(TrapFrame
);
687 /* Enable interrupts */
688 Instruction
= (PUCHAR
)TrapFrame
->Eip
;
691 /* Check for user trap */
692 if (KiUserTrap(TrapFrame
))
696 /* Scan next 4 opcodes */
697 for (i
= 0; i
< 4; i
++)
699 /* Check for LOCK instruction */
700 if (Instruction
[i
] == 0xF0)
702 /* Send invalid lock sequence exception */
703 KiDispatchException0Args(STATUS_INVALID_LOCK_SEQUENCE
,
709 /* FIXME: SEH ends here */
712 /* Kernel-mode or user-mode fault (but not LOCK) */
713 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION
,
722 KiTrap07Handler(IN PKTRAP_FRAME TrapFrame
)
724 PKTHREAD Thread
, NpxThread
;
725 PFX_SAVE_AREA SaveArea
, NpxSaveArea
;
728 /* Save trap frame */
729 KiEnterTrap(TrapFrame
);
731 /* Try to handle NPX delay load */
734 /* Get the current thread */
735 Thread
= KeGetCurrentThread();
737 /* Get the NPX frame */
738 SaveArea
= KiGetThreadNpxArea(Thread
);
740 /* Check if emulation is enabled */
741 if (SaveArea
->Cr0NpxState
& CR0_EM
)
743 /* Not implemented */
744 UNIMPLEMENTED_FATAL();
747 /* Save CR0 and check NPX state */
749 if (Thread
->NpxState
!= NPX_STATE_LOADED
)
752 Cr0
&= ~(CR0_MP
| CR0_EM
| CR0_TS
);
755 /* Get the NPX thread */
756 NpxThread
= KeGetCurrentPrcb()->NpxThread
;
759 /* Get the NPX frame */
760 NpxSaveArea
= KiGetThreadNpxArea(NpxThread
);
763 Ke386SaveFpuState(NpxSaveArea
);
765 /* Update NPX state */
766 NpxThread
->NpxState
= NPX_STATE_NOT_LOADED
;
770 Ke386LoadFpuState(SaveArea
);
772 /* Update NPX state */
773 Thread
->NpxState
= NPX_STATE_LOADED
;
774 KeGetCurrentPrcb()->NpxThread
= Thread
;
776 /* Enable interrupts */
779 /* Check if CR0 needs to be reloaded due to context switch */
780 if (!SaveArea
->Cr0NpxState
) KiEoiHelper(TrapFrame
);
782 /* Otherwise, we need to reload CR0, disable interrupts */
787 Cr0
|= SaveArea
->Cr0NpxState
;
790 /* Now restore interrupts and check for TS */
792 if (Cr0
& CR0_TS
) KiEoiHelper(TrapFrame
);
794 /* We're still here -- clear TS and try again */
795 __writecr0(__readcr0() &~ CR0_TS
);
800 /* This is an actual fault, not a lack of FPU state */
805 /* TS should not be set */
809 * If it's incorrectly set, then maybe the state is actually still valid
810 * but we could have lost track of that due to a BIOS call.
811 * Make sure MP is still set, which should verify the theory.
815 /* Indeed, the state is actually still valid, so clear TS */
816 __writecr0(__readcr0() &~ CR0_TS
);
817 KiEoiHelper(TrapFrame
);
820 /* Otherwise, something strange is going on */
821 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 2, Cr0
, 0, 0, TrapFrame
);
824 /* It's not a delayed load, so process this trap as an NPX fault */
825 KiNpxHandler(TrapFrame
, Thread
, SaveArea
);
831 KiTrap08Handler(VOID
)
838 /* For sanity's sake, make sure interrupts are disabled */
841 /* Get the current TSS, thread, and process */
842 Tss
= KeGetPcr()->TSS
;
843 Thread
= ((PKIPCR
)KeGetPcr())->PrcbData
.CurrentThread
;
844 Process
= Thread
->ApcState
.Process
;
846 /* Save data usually not present in the TSS */
847 Tss
->CR3
= Process
->DirectoryTableBase
[0];
848 Tss
->IoMapBase
= Process
->IopmOffset
;
849 Tss
->LDT
= Process
->LdtDescriptor
.LimitLow
? KGDT_LDT
: 0;
851 /* Now get the base address of the double-fault TSS */
852 TssGdt
= &((PKIPCR
)KeGetPcr())->GDT
[KGDT_DF_TSS
/ sizeof(KGDTENTRY
)];
853 DfTss
= (PKTSS
)(ULONG_PTR
)(TssGdt
->BaseLow
|
854 TssGdt
->HighWord
.Bytes
.BaseMid
<< 16 |
855 TssGdt
->HighWord
.Bytes
.BaseHi
<< 24);
858 * Switch to it and activate it, masking off the nested flag.
860 * Note that in reality, we are already on the double-fault TSS
861 * -- we just need to update the PCR to reflect this.
863 KeGetPcr()->TSS
= DfTss
;
864 __writeeflags(__readeflags() &~ EFLAGS_NESTED_TASK
);
865 TssGdt
->HighWord
.Bits
.Dpl
= 0;
866 TssGdt
->HighWord
.Bits
.Pres
= 1;
867 // TssGdt->HighWord.Bits.Type &= ~0x2; /* I386_ACTIVE_TSS --> I386_TSS */
868 TssGdt
->HighWord
.Bits
.Type
= I386_TSS
; // Busy bit cleared in the TSS selector.
870 /* Bugcheck the system */
871 KeBugCheckWithTf(UNEXPECTED_KERNEL_MODE_TRAP
,
872 EXCEPTION_DOUBLE_FAULT
,
882 KiTrap09Handler(IN PKTRAP_FRAME TrapFrame
)
884 /* Save trap frame */
885 KiEnterTrap(TrapFrame
);
887 /* Enable interrupts and kill the system */
889 KiSystemFatalException(EXCEPTION_NPX_OVERRUN
, TrapFrame
);
895 KiTrap0AHandler(IN PKTRAP_FRAME TrapFrame
)
897 /* Save trap frame */
898 KiEnterTrap(TrapFrame
);
900 /* Check for VDM trap */
901 ASSERT(KiVdmTrap(TrapFrame
) == FALSE
);
903 /* Kill the system */
904 KiSystemFatalException(EXCEPTION_INVALID_TSS
, TrapFrame
);
910 KiTrap0BHandler(IN PKTRAP_FRAME TrapFrame
)
912 /* Save trap frame */
913 KiEnterTrap(TrapFrame
);
915 /* FIXME: Kill the system */
917 KiSystemFatalException(EXCEPTION_SEGMENT_NOT_PRESENT
, TrapFrame
);
923 KiTrap0CHandler(IN PKTRAP_FRAME TrapFrame
)
925 /* Save trap frame */
926 KiEnterTrap(TrapFrame
);
928 /* FIXME: Kill the system */
930 KiSystemFatalException(EXCEPTION_STACK_FAULT
, TrapFrame
);
936 KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame
)
939 BOOLEAN Privileged
= FALSE
;
941 UCHAR Instruction
= 0;
944 /* Check for V86 GPF */
945 if (__builtin_expect(KiV86Trap(TrapFrame
), 1))
948 KiEnterV86Trap(TrapFrame
);
950 /* Must be a VDM process */
951 if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects
, 0))
953 /* Enable interrupts */
956 /* Setup illegal instruction fault */
957 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION
,
962 /* Go to APC level */
963 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
966 /* Handle the V86 opcode */
967 if (__builtin_expect(Ki386HandleOpcodeV86(TrapFrame
) == 0xFF, 0))
969 /* Should only happen in VDM mode */
970 UNIMPLEMENTED_FATAL();
973 /* Bring IRQL back */
974 KeLowerIrql(OldIrql
);
977 /* Do a quick V86 exit if possible */
978 KiExitV86Trap(TrapFrame
);
981 /* Save trap frame */
982 KiEnterTrap(TrapFrame
);
984 /* Check for user-mode GPF */
985 if (KiUserTrap(TrapFrame
))
987 /* Should not be VDM */
988 ASSERT(KiVdmTrap(TrapFrame
) == FALSE
);
990 /* Enable interrupts and check error code */
992 if (!TrapFrame
->ErrCode
)
995 Instructions
= (PUCHAR
)TrapFrame
->Eip
;
997 /* Scan next 15 bytes */
998 for (i
= 0; i
< 15; i
++)
1000 /* Skip prefix instructions */
1001 for (j
= 0; j
< sizeof(KiTrapPrefixTable
); j
++)
1003 /* Is this a prefix instruction? */
1004 if (Instructions
[i
] == KiTrapPrefixTable
[j
])
1011 /* Is this NOT any prefix instruction? */
1012 if (j
== sizeof(KiTrapPrefixTable
))
1014 /* We can go ahead and handle the fault now */
1015 Instruction
= Instructions
[i
];
1020 /* If all we found was prefixes, then this instruction is too long */
1023 /* Setup illegal instruction fault */
1024 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION
,
1029 /* Check for privileged instructions */
1030 DPRINT("Instruction (%lu) at fault: %lx %lx %lx %lx\n",
1033 Instructions
[i
+ 1],
1034 Instructions
[i
+ 2],
1035 Instructions
[i
+ 3]);
1036 if (Instruction
== 0xF4) // HLT
1038 /* HLT is privileged */
1041 else if (Instruction
== 0x0F)
1043 /* Test if it's any of the privileged two-byte opcodes */
1044 if (((Instructions
[i
+ 1] == 0x00) && // LLDT or LTR
1045 (((Instructions
[i
+ 2] & 0x38) == 0x10) || // LLDT
1046 (Instructions
[i
+ 2] == 0x18))) || // LTR
1047 ((Instructions
[i
+ 1] == 0x01) && // LGDT or LIDT or LMSW
1048 (((Instructions
[i
+ 2] & 0x38) == 0x10) || // LGDT
1049 (Instructions
[i
+ 2] == 0x18) || // LIDT
1050 (Instructions
[i
+ 2] == 0x30))) || // LMSW
1051 (Instructions
[i
+ 1] == 0x08) || // INVD
1052 (Instructions
[i
+ 1] == 0x09) || // WBINVD
1053 (Instructions
[i
+ 1] == 0x35) || // SYSEXIT
1054 (Instructions
[i
+ 1] == 0x21) || // MOV DR, XXX
1055 (Instructions
[i
+ 1] == 0x06) || // CLTS
1056 (Instructions
[i
+ 1] == 0x20) || // MOV CR, XXX
1057 (Instructions
[i
+ 1] == 0x22) || // MOV XXX, CR
1058 (Instructions
[i
+ 1] == 0x23) || // MOV YYY, DR
1059 (Instructions
[i
+ 1] == 0x30) || // WRMSR
1060 (Instructions
[i
+ 1] == 0x33)) // RDPMC
1061 // INVLPG, INVLPGA, SYSRET
1063 /* These are all privileged */
1069 /* Get the IOPL and compare with the RPL mask */
1070 Iopl
= (TrapFrame
->EFlags
& EFLAGS_IOPL
) >> 12;
1071 if ((TrapFrame
->SegCs
& RPL_MASK
) > Iopl
)
1073 /* I/O privilege error -- check for known instructions */
1074 if ((Instruction
== 0xFA) || (Instruction
== 0xFB)) // CLI or STI
1076 /* These are privileged */
1081 /* Last hope: an IN/OUT instruction */
1082 for (j
= 0; j
< sizeof(KiTrapIoTable
); j
++)
1084 /* Is this an I/O instruction? */
1085 if (Instruction
== KiTrapIoTable
[j
])
1087 /* Then it's privileged */
1096 /* So now... was the instruction privileged or not? */
1099 /* Whew! We have a privileged instruction, so dispatch the fault */
1100 KiDispatchException0Args(STATUS_PRIVILEGED_INSTRUCTION
,
1106 /* If we got here, send an access violation */
1107 KiDispatchException2Args(STATUS_ACCESS_VIOLATION
,
1115 * Check for a fault during checking of the user instruction.
1117 * Note that the SEH handler will catch invalid EIP, but we could be dealing
1118 * with an invalid CS, which will generate another GPF instead.
1121 if (((PVOID
)TrapFrame
->Eip
>= (PVOID
)KiTrap0DHandler
) &&
1122 ((PVOID
)TrapFrame
->Eip
< (PVOID
)KiTrap0DHandler
))
1124 /* Not implemented */
1125 UNIMPLEMENTED_FATAL();
1129 * NOTE: The ASM trap exit code would restore segment registers by doing
1130 * a POP <SEG>, which could cause an invalid segment if someone had messed
1131 * with the segment values.
1133 * Another case is a bogus SS, which would hit a GPF when doing the iret.
1134 * This could only be done through a buggy or malicious driver, or perhaps
1135 * the kernel debugger.
1137 * The kernel normally restores the "true" segment if this happens.
1139 * However, since we're restoring in C, not ASM, we can't detect
1140 * POP <SEG> since the actual instructions will be different.
1142 * A better technique would be to check the EIP and somehow edit the
1143 * trap frame before restarting the instruction -- but we would need to
1144 * know the extract instruction that was used first.
1146 * We could force a special instrinsic to use stack instructions, or write
1147 * a simple instruction length checker.
1149 * Nevertheless, this is a lot of work for the purpose of avoiding a crash
1150 * when the user is purposedly trying to create one from kernel-mode, so
1151 * we should probably table this for now since it's not a "real" issue.
1155 * NOTE2: Another scenario is the IRET during a V8086 restore (BIOS Call)
1156 * which will cause a GPF since the trap frame is a total mess (on purpose)
1157 * as built in KiEnterV86Mode.
1159 * The idea is to scan for IRET, scan for the known EIP adress, validate CS
1160 * and then manually issue a jump to the V8086 return EIP.
1162 Instructions
= (PUCHAR
)TrapFrame
->Eip
;
1163 if (Instructions
[0] == 0xCF)
1166 * Some evil shit is going on here -- this is not the SS:ESP you're
1167 * looking for! Instead, this is actually CS:EIP you're looking at!
1168 * Why? Because part of the trap frame actually corresponds to the IRET
1169 * stack during the trap exit!
1171 if ((TrapFrame
->HardwareEsp
== (ULONG
)Ki386BiosCallReturnAddress
) &&
1172 (TrapFrame
->HardwareSegSs
== (KGDT_R0_CODE
| RPL_MASK
)))
1174 /* Exit the V86 trap! */
1175 Ki386BiosCallReturnAddress(TrapFrame
);
1179 /* Otherwise, this is another kind of IRET fault */
1180 UNIMPLEMENTED_FATAL();
1184 /* So since we're not dealing with the above case, check for RDMSR/WRMSR */
1185 if ((Instructions
[0] == 0xF) && // 2-byte opcode
1186 ((Instructions
[1] == 0x32) || // RDMSR
1187 (Instructions
[1] == 0x30))) // WRMSR
1189 /* Unknown CPU MSR, so raise an access violation */
1190 KiDispatchException0Args(STATUS_ACCESS_VIOLATION
,
1195 /* Check for lazy segment load */
1196 if (TrapFrame
->SegDs
!= (KGDT_R3_DATA
| RPL_MASK
))
1199 TrapFrame
->SegDs
= (KGDT_R3_DATA
| RPL_MASK
);
1201 else if (TrapFrame
->SegEs
!= (KGDT_R3_DATA
| RPL_MASK
))
1204 TrapFrame
->SegEs
= (KGDT_R3_DATA
| RPL_MASK
);
1208 /* Whatever it is, we can't handle it */
1209 KiSystemFatalException(EXCEPTION_GP_FAULT
, TrapFrame
);
1212 /* Return to where we came from */
1213 KiTrapReturn(TrapFrame
);
1219 KiTrap0EHandler(IN PKTRAP_FRAME TrapFrame
)
1222 BOOLEAN StoreInstruction
;
1226 /* Save trap frame */
1227 KiEnterTrap(TrapFrame
);
1229 /* Check if this is the base frame */
1230 Thread
= KeGetCurrentThread();
1231 if (KeGetTrapFrame(Thread
) != TrapFrame
)
1233 /* It isn't, check if this is a second nested frame */
1234 if (((ULONG_PTR
)KeGetTrapFrame(Thread
) - (ULONG_PTR
)TrapFrame
) <=
1235 FIELD_OFFSET(KTRAP_FRAME
, EFlags
))
1237 /* The stack is somewhere in between frames, we need to fix it */
1238 UNIMPLEMENTED_FATAL();
1245 /* Enable interrupts */
1248 /* Interpret the error code */
1249 StoreInstruction
= (TrapFrame
->ErrCode
& 2) != 0;
1251 /* Check if we came in with interrupts disabled */
1252 if (!(TrapFrame
->EFlags
& EFLAGS_INTERRUPT_MASK
))
1254 /* This is completely illegal, bugcheck the system */
1255 KeBugCheckWithTf(IRQL_NOT_LESS_OR_EQUAL
,
1263 /* Check for S-List fault
1265 Explanation: An S-List fault can occur due to a race condition between 2
1266 threads simultaneously trying to pop an element from the S-List. After
1267 thread 1 has read the pointer to the top element on the S-List it is
1268 preempted and thread 2 calls InterlockedPopEntrySlist on the same S-List,
1269 removing the top element and freeing it's memory. After that thread 1
1270 resumes and tries to read the address of the Next pointer from the top
1271 element, which it assumes will be the next top element.
1272 But since that memory has been freed, we get a page fault. To handle this
1273 race condition, we let thread 1 repeat the operation.
1274 We do NOT invoke the page fault handler in this case, since we do not
1275 want to trigger any side effects, like paging or a guard page fault.
1277 Sequence of operations:
1279 Thread 1 : mov eax, [ebp] <= eax now points to the first element
1280 Thread 1 : mov edx, [ebp + 4] <= edx is loaded with Depth and Sequence
1282 Thread 2 : calls InterlockedPopEntrySlist, changing the top element
1283 Thread 2 : frees the memory of the element that was popped
1285 Thread 1 : checks if eax is NULL
1286 Thread 1 : InterlockedPopEntrySListFault: mov ebx, [eax] <= faults
1288 To be sure that we are dealing with exactly the case described above, we
1289 check whether the ListHeader has changed. If Thread 2 only popped one
1290 entry, the Next field in the S-List-header has changed.
1291 If after thread 1 has faulted, thread 2 allocates a new element, by
1292 chance getting the same address as the previously freed element and
1293 pushes it on the list again, we will see the same top element, but the
1294 Sequence member of the S-List header has changed. Therefore we check
1295 both fields to make sure we catch any concurrent modification of the
1298 if ((TrapFrame
->Eip
== (ULONG_PTR
)ExpInterlockedPopEntrySListFault
) ||
1299 (TrapFrame
->Eip
== (ULONG_PTR
)KeUserPopEntrySListFault
))
1301 ULARGE_INTEGER SListHeader
;
1302 PVOID ResumeAddress
;
1304 /* Sanity check that the assembly is correct:
1305 This must be mov ebx, [eax]
1306 Followed by cmpxchg8b [ebp] */
1307 ASSERT((((UCHAR
*)TrapFrame
->Eip
)[0] == 0x8B) &&
1308 (((UCHAR
*)TrapFrame
->Eip
)[1] == 0x18) &&
1309 (((UCHAR
*)TrapFrame
->Eip
)[2] == 0x0F) &&
1310 (((UCHAR
*)TrapFrame
->Eip
)[3] == 0xC7) &&
1311 (((UCHAR
*)TrapFrame
->Eip
)[4] == 0x4D) &&
1312 (((UCHAR
*)TrapFrame
->Eip
)[5] == 0x00));
1314 /* Check if this is a user fault */
1315 if (TrapFrame
->Eip
== (ULONG_PTR
)KeUserPopEntrySListFault
)
1317 /* EBP points to the S-List-header. Copy it inside SEH, to protect
1318 against a bogus pointer from user mode */
1321 ProbeForRead((PVOID
)TrapFrame
->Ebp
,
1322 sizeof(ULARGE_INTEGER
),
1323 TYPE_ALIGNMENT(SLIST_HEADER
));
1324 SListHeader
= *(PULARGE_INTEGER
)TrapFrame
->Ebp
;
1326 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1328 /* The S-List pointer is not valid! */
1332 ResumeAddress
= KeUserPopEntrySListResume
;
1336 SListHeader
= *(PULARGE_INTEGER
)TrapFrame
->Ebp
;
1337 ResumeAddress
= ExpInterlockedPopEntrySListResume
;
1340 /* Check if either the Next pointer or the Sequence member in the
1341 S-List-header has changed. If any of these has changed, we restart
1342 the operation. Otherwise we only have a bogus pointer and let the
1343 page fault handler deal with it. */
1344 if ((SListHeader
.LowPart
!= TrapFrame
->Eax
) ||
1345 (SListHeader
.HighPart
!= TrapFrame
->Edx
))
1347 DPRINT1("*** Got an S-List-Fault ***\n");
1348 KeGetCurrentThread()->SListFaultCount
++;
1350 /* Restart the operation */
1351 TrapFrame
->Eip
= (ULONG_PTR
)ResumeAddress
;
1353 /* Continue execution */
1354 KiEoiHelper(TrapFrame
);
1359 /* Call the access fault handler */
1360 Status
= MmAccessFault(TrapFrame
->ErrCode
,
1362 KiUserTrap(TrapFrame
),
1364 if (NT_SUCCESS(Status
))
1367 /* Check whether the kernel debugger has owed breakpoints to be inserted */
1368 KdSetOwedBreakpoints();
1370 /* We succeeded, return */
1371 KiEoiHelper(TrapFrame
);
1374 /* Check for syscall fault */
1376 if ((TrapFrame
->Eip
== (ULONG_PTR
)CopyParams
) ||
1377 (TrapFrame
->Eip
== (ULONG_PTR
)ReadBatch
))
1379 /* Not yet implemented */
1380 UNIMPLEMENTED_FATAL();
1384 /* Check for VDM trap */
1385 if (KiVdmTrap(TrapFrame
))
1387 DPRINT1("VDM PAGE FAULT at %lx:%lx for address %lx\n",
1388 TrapFrame
->SegCs
, TrapFrame
->Eip
, Cr2
);
1389 if (VdmDispatchPageFault(TrapFrame
))
1391 /* Return and end VDM execution */
1392 DPRINT1("VDM page fault with status 0x%lx resolved\n", Status
);
1393 KiEoiHelper(TrapFrame
);
1395 DPRINT1("VDM page fault with status 0x%lx NOT resolved\n", Status
);
1398 /* Either kernel or user trap (non VDM) so dispatch exception */
1399 if (Status
== STATUS_ACCESS_VIOLATION
)
1401 /* This status code is repurposed so we can recognize it later */
1402 KiDispatchException2Args(KI_EXCEPTION_ACCESS_VIOLATION
,
1408 else if ((Status
== STATUS_GUARD_PAGE_VIOLATION
) ||
1409 (Status
== STATUS_STACK_OVERFLOW
))
1411 /* These faults only have two parameters */
1412 KiDispatchException2Args(Status
,
1419 /* Only other choice is an in-page error, with 3 parameters */
1420 KiDispatchExceptionFromTrapFrame(STATUS_IN_PAGE_ERROR
,
1433 KiTrap0FHandler(IN PKTRAP_FRAME TrapFrame
)
1435 /* Save trap frame */
1436 KiEnterTrap(TrapFrame
);
1438 /* FIXME: Kill the system */
1440 KiSystemFatalException(EXCEPTION_RESERVED_TRAP
, TrapFrame
);
1446 KiTrap10Handler(IN PKTRAP_FRAME TrapFrame
)
1449 PFX_SAVE_AREA SaveArea
;
1451 /* Save trap frame */
1452 KiEnterTrap(TrapFrame
);
1454 /* Check if this is the NPX thrad */
1455 Thread
= KeGetCurrentThread();
1456 SaveArea
= KiGetThreadNpxArea(Thread
);
1457 if (Thread
!= KeGetCurrentPrcb()->NpxThread
)
1459 /* It isn't, enable interrupts and set delayed error */
1461 SaveArea
->Cr0NpxState
|= CR0_TS
;
1464 KiEoiHelper(TrapFrame
);
1467 /* Otherwise, proceed with NPX fault handling */
1468 KiNpxHandler(TrapFrame
, Thread
, SaveArea
);
1474 KiTrap11Handler(IN PKTRAP_FRAME TrapFrame
)
1476 /* Save trap frame */
1477 KiEnterTrap(TrapFrame
);
1479 /* Enable interrupts and kill the system */
1481 KiSystemFatalException(EXCEPTION_ALIGNMENT_CHECK
, TrapFrame
);
1487 KiTrap13Handler(IN PKTRAP_FRAME TrapFrame
)
1490 PFX_SAVE_AREA SaveArea
;
1491 ULONG Cr0
, MxCsrMask
, Error
;
1493 /* Save trap frame */
1494 KiEnterTrap(TrapFrame
);
1496 /* Check if this is the NPX thrad */
1497 Thread
= KeGetCurrentThread();
1498 if (Thread
!= KeGetCurrentPrcb()->NpxThread
)
1500 /* It isn't, kill the system */
1501 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 13, (ULONG_PTR
)Thread
, 0, 0, TrapFrame
);
1504 /* Get the NPX frame */
1505 SaveArea
= KiGetThreadNpxArea(Thread
);
1507 /* Check for VDM trap */
1508 ASSERT(KiVdmTrap(TrapFrame
) == FALSE
);
1510 /* Check for user trap */
1511 if (!KiUserTrap(TrapFrame
))
1513 /* Kernel should not fault on XMMI */
1514 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 13, 0, 0, 2, TrapFrame
);
1519 Cr0
&= ~(CR0_MP
| CR0_EM
| CR0_TS
);
1522 /* Save FPU state */
1523 Ke386SaveFpuState(SaveArea
);
1525 /* Mark CR0 state dirty */
1526 Cr0
|= NPX_STATE_NOT_LOADED
;
1527 Cr0
|= SaveArea
->Cr0NpxState
;
1530 /* Update NPX state */
1531 Thread
->NpxState
= NPX_STATE_NOT_LOADED
;
1532 KeGetCurrentPrcb()->NpxThread
= NULL
;
1534 /* Clear the TS bit and re-enable interrupts */
1535 SaveArea
->Cr0NpxState
&= ~CR0_TS
;
1538 /* Now look at MxCsr to get the mask of errors we should care about */
1539 MxCsrMask
= ~((USHORT
)SaveArea
->U
.FxArea
.MXCsr
>> 7);
1541 /* Get legal exceptions that software should handle */
1542 Error
= (USHORT
)SaveArea
->U
.FxArea
.MXCsr
& (FSW_INVALID_OPERATION
|
1550 /* Now handle any of those legal errors */
1551 if (Error
& (FSW_INVALID_OPERATION
|
1558 /* By issuing an exception */
1559 KiDispatchException1Args(STATUS_FLOAT_MULTIPLE_TRAPS
,
1565 /* Unknown XMMI fault */
1566 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 13, 0, 0, 1, TrapFrame
);
1569 /* SOFTWARE SERVICES **********************************************************/
1573 KiRaiseSecurityCheckFailureHandler(IN PKTRAP_FRAME TrapFrame
)
1575 /* Save trap frame */
1576 KiEnterTrap(TrapFrame
);
1578 /* Decrement EIP to point to the INT29 instruction (2 bytes, not 1 like INT3) */
1579 TrapFrame
->Eip
-= 2;
1581 /* Check if this is a user trap */
1582 if (KiUserTrap(TrapFrame
))
1584 /* Dispatch exception to user mode */
1585 KiDispatchExceptionFromTrapFrame(STATUS_STACK_BUFFER_OVERRUN
,
1586 EXCEPTION_NONCONTINUABLE
,
1596 EXCEPTION_RECORD ExceptionRecord
;
1598 /* Bugcheck the system */
1599 ExceptionRecord
.ExceptionCode
= STATUS_STACK_BUFFER_OVERRUN
;
1600 ExceptionRecord
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
1601 ExceptionRecord
.ExceptionRecord
= NULL
;
1602 ExceptionRecord
.ExceptionAddress
= (PVOID
)TrapFrame
->Eip
;
1603 ExceptionRecord
.NumberParameters
= 1;
1604 ExceptionRecord
.ExceptionInformation
[0] = TrapFrame
->Ecx
;
1606 KeBugCheckWithTf(KERNEL_SECURITY_CHECK_FAILURE
,
1608 (ULONG_PTR
)TrapFrame
,
1609 (ULONG_PTR
)&ExceptionRecord
,
1617 KiGetTickCountHandler(IN PKTRAP_FRAME TrapFrame
)
1619 /* Save trap frame */
1620 KiEnterTrap(TrapFrame
);
1623 * Just fail the request
1625 DbgPrint("INT 0x2A attempted, returning 0 tick count\n");
1629 KiEoiHelper(TrapFrame
);
1634 KiCallbackReturnHandler(IN PKTRAP_FRAME TrapFrame
)
1639 /* Save the SEH chain, NtCallbackReturn will restore this */
1640 TrapFrame
->ExceptionList
= KeGetPcr()->NtTib
.ExceptionList
;
1642 /* Set thread fields */
1643 Thread
= KeGetCurrentThread();
1644 Thread
->TrapFrame
= TrapFrame
;
1645 Thread
->PreviousMode
= KiUserTrap(TrapFrame
);
1646 ASSERT(Thread
->PreviousMode
!= KernelMode
);
1648 /* Pass the register parameters to NtCallbackReturn.
1649 Result pointer is in ecx, result length in edx, status in eax */
1650 Status
= NtCallbackReturn((PVOID
)TrapFrame
->Ecx
,
1654 /* If we got here, something went wrong. Return an error to the caller */
1655 KiServiceExit(TrapFrame
, Status
);
1661 KiRaiseAssertionHandler(IN PKTRAP_FRAME TrapFrame
)
1663 /* Save trap frame */
1664 KiEnterTrap(TrapFrame
);
1666 /* Decrement EIP to point to the INT2C instruction (2 bytes, not 1 like INT3) */
1667 TrapFrame
->Eip
-= 2;
1669 /* Dispatch the exception */
1670 KiDispatchException0Args(STATUS_ASSERTION_FAILURE
,
1678 KiDebugServiceHandler(IN PKTRAP_FRAME TrapFrame
)
1680 /* Save trap frame */
1681 KiEnterTrap(TrapFrame
);
1683 /* Increment EIP to skip the INT3 instruction */
1686 /* Continue with the common handler */
1687 KiDebugHandler(TrapFrame
, TrapFrame
->Eax
, TrapFrame
->Ecx
, TrapFrame
->Edx
);
1693 KiDbgPreServiceHook(ULONG SystemCallNumber
, PULONG_PTR Arguments
)
1695 #if DBG && !defined(_WINKD_)
1696 if (SystemCallNumber
>= 0x1000 && KeWin32PreServiceHook
)
1697 KeWin32PreServiceHook(SystemCallNumber
, Arguments
);
1703 KiDbgPostServiceHook(ULONG SystemCallNumber
, ULONG_PTR Result
)
1705 #if DBG && !defined(_WINKD_)
1706 if (SystemCallNumber
>= 0x1000 && KeWin32PostServiceHook
)
1707 return KeWin32PostServiceHook(SystemCallNumber
, Result
);
1715 KiSystemServiceHandler(IN PKTRAP_FRAME TrapFrame
,
1719 PKSERVICE_TABLE_DESCRIPTOR DescriptorTable
;
1720 ULONG Id
, Offset
, StackBytes
;
1723 ULONG SystemCallNumber
= TrapFrame
->Eax
;
1725 /* Get the current thread */
1726 Thread
= KeGetCurrentThread();
1728 /* Set debug header */
1729 KiFillTrapFrameDebug(TrapFrame
);
1731 /* Chain trap frames */
1732 TrapFrame
->Edx
= (ULONG_PTR
)Thread
->TrapFrame
;
1735 TrapFrame
->ErrCode
= 0;
1737 /* Save previous mode */
1738 TrapFrame
->PreviousPreviousMode
= Thread
->PreviousMode
;
1740 /* Save the SEH chain and terminate it for now */
1741 TrapFrame
->ExceptionList
= KeGetPcr()->NtTib
.ExceptionList
;
1742 KeGetPcr()->NtTib
.ExceptionList
= EXCEPTION_CHAIN_END
;
1744 /* Default to debugging disabled */
1747 /* Check if the frame was from user mode */
1748 if (KiUserTrap(TrapFrame
))
1750 /* Check for active debugging */
1751 if (KeGetCurrentThread()->Header
.DebugActive
& 0xFF)
1753 /* Handle debug registers */
1754 KiHandleDebugRegistersOnTrapEntry(TrapFrame
);
1758 /* Set thread fields */
1759 Thread
->TrapFrame
= TrapFrame
;
1760 Thread
->PreviousMode
= KiUserTrap(TrapFrame
);
1762 /* Enable interrupts */
1765 /* Decode the system call number */
1766 Offset
= (SystemCallNumber
>> SERVICE_TABLE_SHIFT
) & SERVICE_TABLE_MASK
;
1767 Id
= SystemCallNumber
& SERVICE_NUMBER_MASK
;
1769 /* Get descriptor table */
1770 DescriptorTable
= (PVOID
)((ULONG_PTR
)Thread
->ServiceTable
+ Offset
);
1772 /* Validate the system call number */
1773 if (__builtin_expect(Id
>= DescriptorTable
->Limit
, 0))
1775 /* Check if this is a GUI call */
1776 if (!(Offset
& SERVICE_TABLE_TEST
))
1779 Status
= STATUS_INVALID_SYSTEM_SERVICE
;
1783 /* Convert us to a GUI thread -- must wrap in ASM to get new EBP */
1784 Status
= KiConvertToGuiThread();
1786 /* Reload trap frame and descriptor table pointer from new stack */
1787 TrapFrame
= *(volatile PVOID
*)&Thread
->TrapFrame
;
1788 DescriptorTable
= (PVOID
)(*(volatile ULONG_PTR
*)&Thread
->ServiceTable
+ Offset
);
1790 if (!NT_SUCCESS(Status
))
1792 /* Set the last error and fail */
1796 /* Validate the system call number again */
1797 if (Id
>= DescriptorTable
->Limit
)
1800 Status
= STATUS_INVALID_SYSTEM_SERVICE
;
1805 /* Check if this is a GUI call */
1806 if (__builtin_expect(Offset
& SERVICE_TABLE_TEST
, 0))
1808 /* Get the batch count and flush if necessary */
1809 if (NtCurrentTeb()->GdiBatchCount
) KeGdiFlushUserBatch();
1812 /* Increase system call count */
1813 KeGetCurrentPrcb()->KeSystemCalls
++;
1815 /* FIXME: Increase individual counts on debug systems */
1816 //KiIncreaseSystemCallCount(DescriptorTable, Id);
1818 /* Get stack bytes */
1819 StackBytes
= DescriptorTable
->Number
[Id
];
1821 /* Probe caller stack */
1822 if (__builtin_expect((Arguments
< (PVOID
)MmUserProbeAddress
) && !(KiUserTrap(TrapFrame
)), 0))
1824 /* Access violation */
1825 UNIMPLEMENTED_FATAL();
1828 /* Call pre-service debug hook */
1829 KiDbgPreServiceHook(SystemCallNumber
, Arguments
);
1831 /* Get the handler and make the system call */
1832 Handler
= (PVOID
)DescriptorTable
->Base
[Id
];
1833 Status
= KiSystemCallTrampoline(Handler
, Arguments
, StackBytes
);
1835 /* Call post-service debug hook */
1836 Status
= KiDbgPostServiceHook(SystemCallNumber
, Status
);
1838 /* Make sure we're exiting correctly */
1839 KiExitSystemCallDebugChecks(Id
, TrapFrame
);
1841 /* Restore the old trap frame */
1843 Thread
->TrapFrame
= (PKTRAP_FRAME
)TrapFrame
->Edx
;
1845 /* Exit from system call */
1846 KiServiceExit(TrapFrame
, Status
);
1851 KiCheckForSListAddress(IN PKTRAP_FRAME TrapFrame
)
1861 Kei386EoiHelper(VOID
)
1863 /* We should never see this call happening */
1864 KeBugCheck(MISMATCHED_HAL
);