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 /* GLOBALS ********************************************************************/
17 UCHAR KiTrapPrefixTable
[] =
20 0xF3, /* REP INS/OUTS */
32 UCHAR KiTrapIoTable
[] =
48 PFAST_SYSTEM_CALL_EXIT KiFastCallExitHandler
;
49 #if DBG && !defined(_WINKD_)
50 PKDBG_PRESERVICEHOOK KeWin32PreServiceHook
= NULL
;
51 PKDBG_POSTSERVICEHOOK KeWin32PostServiceHook
= NULL
;
55 /* TRAP EXIT CODE *************************************************************/
59 KiVdmTrap(IN PKTRAP_FRAME TrapFrame
)
61 /* Either the V8086 flag is on, or this is user-mode with a VDM */
62 return ((TrapFrame
->EFlags
& EFLAGS_V86_MASK
) ||
63 ((KiUserTrap(TrapFrame
)) && (PsGetCurrentProcess()->VdmObjects
)));
68 KiV86Trap(IN PKTRAP_FRAME TrapFrame
)
70 /* Check if the V8086 flag is on */
71 return ((TrapFrame
->EFlags
& EFLAGS_V86_MASK
) != 0);
76 KiIsFrameEdited(IN PKTRAP_FRAME TrapFrame
)
78 /* An edited frame changes esp. It is marked by clearing the bits
79 defined by FRAME_EDITED in the SegCs field of the trap frame */
80 return ((TrapFrame
->SegCs
& FRAME_EDITED
) == 0);
85 KiCommonExit(IN PKTRAP_FRAME TrapFrame
, const ULONG Flags
)
87 /* Disable interrupts until we return */
90 /* Check for APC delivery */
91 KiCheckForApcDelivery(TrapFrame
);
93 /* Debugging checks */
94 KiExitTrapDebugChecks(TrapFrame
, Flags
);
96 /* Restore the SEH handler chain */
97 KeGetPcr()->NtTib
.ExceptionList
= TrapFrame
->ExceptionList
;
99 /* Check if there are active debug registers */
100 if (__builtin_expect(TrapFrame
->Dr7
& ~DR7_RESERVED_MASK
, 0))
102 /* Not handled yet */
103 DbgPrint("Need Hardware Breakpoint Support!\n");
112 KiEoiHelper(IN PKTRAP_FRAME TrapFrame
)
114 /* Common trap exit code */
115 KiCommonExit(TrapFrame
, 0);
117 /* Check if this was a V8086 trap */
118 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
) KiTrapReturnNoSegments(TrapFrame
);
120 /* Check for user mode exit */
121 if (TrapFrame
->SegCs
& MODE_MASK
) KiTrapReturn(TrapFrame
);
123 /* Check for edited frame */
124 if (KiIsFrameEdited(TrapFrame
)) KiEditedTrapReturn(TrapFrame
);
126 /* Exit the trap to kernel mode */
127 KiTrapReturnNoSegments(TrapFrame
);
133 KiServiceExit(IN PKTRAP_FRAME TrapFrame
,
136 ASSERT((TrapFrame
->EFlags
& EFLAGS_V86_MASK
) == 0);
137 ASSERT(!KiIsFrameEdited(TrapFrame
));
139 /* Copy the status into EAX */
140 TrapFrame
->Eax
= Status
;
142 /* Common trap exit code */
143 KiCommonExit(TrapFrame
, 0);
145 /* Restore previous mode */
146 KeGetCurrentThread()->PreviousMode
= TrapFrame
->PreviousPreviousMode
;
148 /* Check for user mode exit */
149 if (TrapFrame
->SegCs
& MODE_MASK
)
151 /* Check if we were single stepping */
152 if (TrapFrame
->EFlags
& EFLAGS_TF
)
154 /* Must use the IRET handler */
155 KiSystemCallTrapReturn(TrapFrame
);
159 /* We can use the sysexit handler */
160 KiFastCallExitHandler(TrapFrame
);
164 /* Exit to kernel mode */
165 KiSystemCallReturn(TrapFrame
);
171 KiServiceExit2(IN PKTRAP_FRAME TrapFrame
)
173 /* Common trap exit code */
174 KiCommonExit(TrapFrame
, 0);
176 /* Restore previous mode */
177 KeGetCurrentThread()->PreviousMode
= TrapFrame
->PreviousPreviousMode
;
179 /* Check if this was a V8086 trap */
180 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
) KiTrapReturnNoSegments(TrapFrame
);
182 /* Check for user mode exit */
183 if (TrapFrame
->SegCs
& MODE_MASK
) KiTrapReturn(TrapFrame
);
185 /* Check for edited frame */
186 if (KiIsFrameEdited(TrapFrame
)) KiEditedTrapReturn(TrapFrame
);
188 /* Exit the trap to kernel mode */
189 KiTrapReturnNoSegments(TrapFrame
);
193 /* TRAP HANDLERS **************************************************************/
198 KiDebugHandler(IN PKTRAP_FRAME TrapFrame
,
203 /* Check for VDM trap */
204 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
206 /* Enable interrupts if the trap came from user-mode */
207 if (KiUserTrap(TrapFrame
)) _enable();
209 /* Dispatch the exception */
210 KiDispatchExceptionFromTrapFrame(STATUS_BREAKPOINT
,
222 KiNpxHandler(IN PKTRAP_FRAME TrapFrame
,
224 IN PFX_SAVE_AREA SaveArea
)
226 ULONG Cr0
, Mask
, Error
, ErrorOffset
, DataOffset
;
228 /* Check for VDM trap */
229 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
231 /* Check for kernel trap */
232 if (!KiUserTrap(TrapFrame
))
234 /* Kernel might've tripped a delayed error */
235 SaveArea
->Cr0NpxState
|= CR0_TS
;
237 /* Only valid if it happened during a restore */
238 //if ((PVOID)TrapFrame->Eip == FrRestore)
240 /* It did, so just skip the instruction */
241 //TrapFrame->Eip += 3; /* sizeof(FRSTOR) */
242 //KiEoiHelper(TrapFrame);
246 /* User or kernel trap -- get ready to issue an exception */
247 //if (Thread->NpxState == NPX_STATE_NOT_LOADED)
251 Cr0
&= ~(CR0_MP
| CR0_EM
| CR0_TS
);
255 Ke386SaveFpuState(SaveArea
);
257 /* Mark CR0 state dirty */
258 Cr0
|= NPX_STATE_NOT_LOADED
;
259 Cr0
|= SaveArea
->Cr0NpxState
;
262 /* Update NPX state */
263 Thread
->NpxState
= NPX_STATE_NOT_LOADED
;
264 KeGetCurrentPrcb()->NpxThread
= NULL
;
267 /* Clear the TS bit and re-enable interrupts */
268 SaveArea
->Cr0NpxState
&= ~CR0_TS
;
271 /* Check if we should get the FN or FX error */
272 if (KeI386FxsrPresent
)
275 Mask
= SaveArea
->U
.FxArea
.ControlWord
;
276 Error
= SaveArea
->U
.FxArea
.StatusWord
;
278 /* Get the FPU exception address too */
279 ErrorOffset
= SaveArea
->U
.FxArea
.ErrorOffset
;
280 DataOffset
= SaveArea
->U
.FxArea
.DataOffset
;
285 Mask
= SaveArea
->U
.FnArea
.ControlWord
;
286 Error
= SaveArea
->U
.FnArea
.StatusWord
;
288 /* Get the FPU exception address too */
289 ErrorOffset
= SaveArea
->U
.FnArea
.ErrorOffset
;
290 DataOffset
= SaveArea
->U
.FnArea
.DataOffset
;
293 /* Get legal exceptions that software should handle */
294 Error
&= (FSW_INVALID_OPERATION
|
302 if (Error
& FSW_STACK_FAULT
)
304 /* Issue stack check fault */
305 KiDispatchException2Args(STATUS_FLOAT_STACK_CHECK
,
312 /* Check for invalid operation */
313 if (Error
& FSW_INVALID_OPERATION
)
316 KiDispatchException1Args(STATUS_FLOAT_INVALID_OPERATION
,
322 /* Check for divide by zero */
323 if (Error
& FSW_ZERO_DIVIDE
)
326 KiDispatchException1Args(STATUS_FLOAT_DIVIDE_BY_ZERO
,
332 /* Check for denormal */
333 if (Error
& FSW_DENORMAL
)
336 KiDispatchException1Args(STATUS_FLOAT_INVALID_OPERATION
,
342 /* Check for overflow */
343 if (Error
& FSW_OVERFLOW
)
346 KiDispatchException1Args(STATUS_FLOAT_OVERFLOW
,
352 /* Check for underflow */
353 if (Error
& FSW_UNDERFLOW
)
356 KiDispatchException1Args(STATUS_FLOAT_UNDERFLOW
,
362 /* Check for precision fault */
363 if (Error
& FSW_PRECISION
)
366 KiDispatchException1Args(STATUS_FLOAT_INEXACT_RESULT
,
372 /* Unknown FPU fault */
373 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 1, Error
, 0, 0, TrapFrame
);
379 KiTrap00Handler(IN PKTRAP_FRAME TrapFrame
)
381 /* Save trap frame */
382 KiEnterTrap(TrapFrame
);
384 /* Check for VDM trap */
385 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
387 /* Enable interrupts */
390 /* Dispatch the exception */
391 KiDispatchException0Args(STATUS_INTEGER_DIVIDE_BY_ZERO
,
399 KiTrap01Handler(IN PKTRAP_FRAME TrapFrame
)
401 /* Save trap frame */
402 KiEnterTrap(TrapFrame
);
404 /* Check for VDM trap */
405 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
407 /* Enable interrupts if the trap came from user-mode */
408 if (KiUserTrap(TrapFrame
)) _enable();
410 /* Mask out trap flag and dispatch the exception */
411 TrapFrame
->EFlags
&= ~EFLAGS_TF
;
412 KiDispatchException0Args(STATUS_SINGLE_STEP
,
426 KTRAP_FRAME TrapFrame
;
430 // In some sort of strange recursion case, we might end up here with the IF
431 // flag incorrectly on the interrupt frame -- during a normal NMI this would
432 // normally already be set.
434 // For sanity's sake, make sure interrupts are disabled for sure.
435 // NMIs will already be since the CPU does it for us.
440 // Get the current TSS, thread, and process
443 Thread
= ((PKIPCR
)PCR
)->PrcbData
.CurrentThread
;
444 Process
= Thread
->ApcState
.Process
;
447 // Save data usually not in the TSS
449 Tss
->CR3
= Process
->DirectoryTableBase
[0];
450 Tss
->IoMapBase
= Process
->IopmOffset
;
451 Tss
->LDT
= Process
->LdtDescriptor
.LimitLow
? KGDT_LDT
: 0;
454 // Now get the base address of the NMI TSS
456 TssGdt
= &((PKIPCR
)KeGetPcr())->GDT
[KGDT_NMI_TSS
/ sizeof(KGDTENTRY
)];
457 NmiTss
= (PKTSS
)(ULONG_PTR
)(TssGdt
->BaseLow
|
458 TssGdt
->HighWord
.Bytes
.BaseMid
<< 16 |
459 TssGdt
->HighWord
.Bytes
.BaseHi
<< 24);
462 // Switch to it and activate it, masking off the nested flag
464 // Note that in reality, we are already on the NMI tss -- we just need to
465 // update the PCR to reflect this
468 __writeeflags(__readeflags() &~ EFLAGS_NESTED_TASK
);
469 TssGdt
->HighWord
.Bits
.Dpl
= 0;
470 TssGdt
->HighWord
.Bits
.Pres
= 1;
471 TssGdt
->HighWord
.Bits
.Type
= I386_TSS
;
474 // Now build the trap frame based on the original TSS
476 // The CPU does a hardware "Context switch" / task switch of sorts and so it
477 // takes care of saving our context in the normal TSS.
479 // We just have to go get the values...
481 RtlZeroMemory(&TrapFrame
, sizeof(KTRAP_FRAME
));
482 TrapFrame
.HardwareSegSs
= Tss
->Ss0
;
483 TrapFrame
.HardwareEsp
= Tss
->Esp0
;
484 TrapFrame
.EFlags
= Tss
->EFlags
;
485 TrapFrame
.SegCs
= Tss
->Cs
;
486 TrapFrame
.Eip
= Tss
->Eip
;
487 TrapFrame
.Ebp
= Tss
->Ebp
;
488 TrapFrame
.Ebx
= Tss
->Ebx
;
489 TrapFrame
.Esi
= Tss
->Esi
;
490 TrapFrame
.Edi
= Tss
->Edi
;
491 TrapFrame
.SegFs
= Tss
->Fs
;
492 TrapFrame
.ExceptionList
= PCR
->NtTib
.ExceptionList
;
493 TrapFrame
.PreviousPreviousMode
= -1;
494 TrapFrame
.Eax
= Tss
->Eax
;
495 TrapFrame
.Ecx
= Tss
->Ecx
;
496 TrapFrame
.Edx
= Tss
->Edx
;
497 TrapFrame
.SegDs
= Tss
->Ds
;
498 TrapFrame
.SegEs
= Tss
->Es
;
499 TrapFrame
.SegGs
= Tss
->Gs
;
500 TrapFrame
.DbgEip
= Tss
->Eip
;
501 TrapFrame
.DbgEbp
= Tss
->Ebp
;
504 // Store the trap frame in the KPRCB
506 KiSaveProcessorState(&TrapFrame
, NULL
);
509 // Call any registered NMI handlers and see if they handled it or not
514 // They did not, so call the platform HAL routine to bugcheck the system
516 // Make sure the HAL believes it's running at HIGH IRQL... we can't use
517 // the normal APIs here as playing with the IRQL could change the system
521 PCR
->Irql
= HIGH_LEVEL
;
527 // Although the CPU disabled NMIs, we just did a BIOS Call, which could've
528 // totally changed things.
530 // We have to make sure we're still in our original NMI -- a nested NMI
531 // will point back to the NMI TSS, and in that case we're hosed.
533 if (PCR
->TSS
->Backlink
!= KGDT_NMI_TSS
)
536 // Restore original TSS
541 // Set it back to busy
543 TssGdt
->HighWord
.Bits
.Dpl
= 0;
544 TssGdt
->HighWord
.Bits
.Pres
= 1;
545 TssGdt
->HighWord
.Bits
.Type
= I386_ACTIVE_TSS
;
548 // Restore nested flag
550 __writeeflags(__readeflags() | EFLAGS_NESTED_TASK
);
553 // Handled, return from interrupt
559 // Unhandled: crash the system
561 KiSystemFatalException(EXCEPTION_NMI
, NULL
);
567 KiTrap03Handler(IN PKTRAP_FRAME TrapFrame
)
569 /* Save trap frame */
570 KiEnterTrap(TrapFrame
);
572 /* Continue with the common handler */
573 KiDebugHandler(TrapFrame
, BREAKPOINT_BREAK
, 0, 0);
579 KiTrap04Handler(IN PKTRAP_FRAME TrapFrame
)
581 /* Save trap frame */
582 KiEnterTrap(TrapFrame
);
584 /* Check for VDM trap */
585 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
587 /* Enable interrupts */
590 /* Dispatch the exception */
591 KiDispatchException0Args(STATUS_INTEGER_OVERFLOW
,
599 KiTrap05Handler(IN PKTRAP_FRAME TrapFrame
)
601 /* Save trap frame */
602 KiEnterTrap(TrapFrame
);
604 /* Check for VDM trap */
605 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
607 /* Check for kernel-mode fault */
608 if (!KiUserTrap(TrapFrame
)) KiSystemFatalException(EXCEPTION_BOUND_CHECK
, TrapFrame
);
610 /* Enable interrupts */
613 /* Dispatch the exception */
614 KiDispatchException0Args(STATUS_ARRAY_BOUNDS_EXCEEDED
,
622 KiTrap06Handler(IN PKTRAP_FRAME TrapFrame
)
628 /* Check for V86 GPF */
629 if (__builtin_expect(KiV86Trap(TrapFrame
), 1))
632 KiEnterV86Trap(TrapFrame
);
634 /* Must be a VDM process */
635 if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects
, 0))
637 /* Enable interrupts */
640 /* Setup illegal instruction fault */
641 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION
,
646 /* Go to APC level */
647 OldIrql
= KfRaiseIrql(APC_LEVEL
);
651 if (!VdmDispatchBop(TrapFrame
))
653 /* Should only happen in VDM mode */
658 /* Bring IRQL back */
659 KfLowerIrql(OldIrql
);
662 /* Do a quick V86 exit if possible */
663 KiExitV86Trap(TrapFrame
);
666 /* Save trap frame */
667 KiEnterTrap(TrapFrame
);
669 /* Enable interrupts */
670 Instruction
= (PUCHAR
)TrapFrame
->Eip
;
673 /* Check for user trap */
674 if (KiUserTrap(TrapFrame
))
678 /* Scan next 4 opcodes */
679 for (i
= 0; i
< 4; i
++)
681 /* Check for LOCK instruction */
682 if (Instruction
[i
] == 0xF0)
684 /* Send invalid lock sequence exception */
685 KiDispatchException0Args(STATUS_INVALID_LOCK_SEQUENCE
,
691 /* FIXME: SEH ends here */
694 /* Kernel-mode or user-mode fault (but not LOCK) */
695 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION
,
704 KiTrap07Handler(IN PKTRAP_FRAME TrapFrame
)
706 PKTHREAD Thread
, NpxThread
;
707 PFX_SAVE_AREA SaveArea
, NpxSaveArea
;
710 /* Save trap frame */
711 KiEnterTrap(TrapFrame
);
713 /* Try to handle NPX delay load */
716 /* Get the current thread */
717 Thread
= KeGetCurrentThread();
719 /* Get the NPX frame */
720 SaveArea
= KiGetThreadNpxArea(Thread
);
722 /* Check if emulation is enabled */
723 if (SaveArea
->Cr0NpxState
& CR0_EM
)
725 /* Not implemented */
730 /* Save CR0 and check NPX state */
732 if (Thread
->NpxState
!= NPX_STATE_LOADED
)
735 Cr0
&= ~(CR0_MP
| CR0_EM
| CR0_TS
);
738 /* Get the NPX thread */
739 NpxThread
= KeGetCurrentPrcb()->NpxThread
;
742 /* Get the NPX frame */
743 NpxSaveArea
= KiGetThreadNpxArea(NpxThread
);
746 DPRINT("FIXME: Save FPU state: %p\n", NpxSaveArea
);
747 //Ke386SaveFpuState(NpxSaveArea);
749 /* Update NPX state */
750 Thread
->NpxState
= NPX_STATE_NOT_LOADED
;
754 //Ke386LoadFpuState(SaveArea);
756 /* Update NPX state */
757 Thread
->NpxState
= NPX_STATE_LOADED
;
758 KeGetCurrentPrcb()->NpxThread
= Thread
;
760 /* Enable interrupts */
763 /* Check if CR0 needs to be reloaded due to context switch */
764 if (!SaveArea
->Cr0NpxState
) KiEoiHelper(TrapFrame
);
766 /* Otherwise, we need to reload CR0, disable interrupts */
771 Cr0
|= SaveArea
->Cr0NpxState
;
774 /* Now restore interrupts and check for TS */
776 if (Cr0
& CR0_TS
) KiEoiHelper(TrapFrame
);
778 /* We're still here -- clear TS and try again */
779 __writecr0(__readcr0() &~ CR0_TS
);
784 /* This is an actual fault, not a lack of FPU state */
789 /* TS should not be set */
793 * If it's incorrectly set, then maybe the state is actually still valid
794 * but we could've lock track of that due to a BIOS call.
795 * Make sure MP is still set, which should verify the theory.
799 /* Indeed, the state is actually still valid, so clear TS */
800 __writecr0(__readcr0() &~ CR0_TS
);
801 KiEoiHelper(TrapFrame
);
804 /* Otherwise, something strange is going on */
805 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 2, Cr0
, 0, 0, TrapFrame
);
808 /* It's not a delayed load, so process this trap as an NPX fault */
809 KiNpxHandler(TrapFrame
, Thread
, SaveArea
);
815 KiTrap08Handler(IN PKTRAP_FRAME TrapFrame
)
817 /* FIXME: Not handled */
818 KiSystemFatalException(EXCEPTION_DOUBLE_FAULT
, TrapFrame
);
824 KiTrap09Handler(IN PKTRAP_FRAME TrapFrame
)
826 /* Save trap frame */
827 KiEnterTrap(TrapFrame
);
829 /* Enable interrupts and kill the system */
831 KiSystemFatalException(EXCEPTION_NPX_OVERRUN
, TrapFrame
);
837 KiTrap0AHandler(IN PKTRAP_FRAME TrapFrame
)
839 /* Save trap frame */
840 KiEnterTrap(TrapFrame
);
842 /* Check for VDM trap */
843 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
845 /* Kill the system */
846 KiSystemFatalException(EXCEPTION_INVALID_TSS
, TrapFrame
);
852 KiTrap0BHandler(IN PKTRAP_FRAME TrapFrame
)
854 /* Save trap frame */
855 KiEnterTrap(TrapFrame
);
857 /* FIXME: Kill the system */
859 KiSystemFatalException(EXCEPTION_SEGMENT_NOT_PRESENT
, TrapFrame
);
865 KiTrap0CHandler(IN PKTRAP_FRAME TrapFrame
)
867 /* Save trap frame */
868 KiEnterTrap(TrapFrame
);
870 /* FIXME: Kill the system */
872 KiSystemFatalException(EXCEPTION_STACK_FAULT
, TrapFrame
);
878 KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame
)
881 BOOLEAN Privileged
= FALSE
;
883 UCHAR Instruction
= 0;
886 /* Check for V86 GPF */
887 if (__builtin_expect(KiV86Trap(TrapFrame
), 1))
890 KiEnterV86Trap(TrapFrame
);
892 /* Must be a VDM process */
893 if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects
, 0))
895 /* Enable interrupts */
898 /* Setup illegal instruction fault */
899 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION
,
904 /* Go to APC level */
905 OldIrql
= KfRaiseIrql(APC_LEVEL
);
908 /* Handle the V86 opcode */
909 if (__builtin_expect(Ki386HandleOpcodeV86(TrapFrame
) == 0xFF, 0))
911 /* Should only happen in VDM mode */
916 /* Bring IRQL back */
917 KfLowerIrql(OldIrql
);
920 /* Do a quick V86 exit if possible */
921 KiExitV86Trap(TrapFrame
);
924 /* Save trap frame */
925 KiEnterTrap(TrapFrame
);
927 /* Check for user-mode GPF */
928 if (KiUserTrap(TrapFrame
))
930 /* Should not be VDM */
931 ASSERT(KiVdmTrap(TrapFrame
) == FALSE
);
933 /* Enable interrupts and check error code */
935 if (!TrapFrame
->ErrCode
)
938 Instructions
= (PUCHAR
)TrapFrame
->Eip
;
940 /* Scan next 15 bytes */
941 for (i
= 0; i
< 15; i
++)
943 /* Skip prefix instructions */
944 for (j
= 0; j
< sizeof(KiTrapPrefixTable
); j
++)
946 /* Is this a prefix instruction? */
947 if (Instructions
[i
] == KiTrapPrefixTable
[j
])
954 /* Is this NOT any prefix instruction? */
955 if (j
== sizeof(KiTrapPrefixTable
))
957 /* We can go ahead and handle the fault now */
958 Instruction
= Instructions
[i
];
963 /* If all we found was prefixes, then this instruction is too long */
966 /* Setup illegal instruction fault */
967 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION
,
972 /* Check for privileged instructions */
973 if (Instruction
== 0xF4) // HLT
975 /* HLT is privileged */
978 else if (Instruction
== 0x0F)
980 /* Test if it's any of the privileged two-byte opcodes */
981 if (((Instructions
[i
+ 1] == 0x00) && // LLDT or LTR
982 (((Instructions
[i
+ 2] & 0x38) == 0x10) || // LLDT
983 (Instructions
[i
+ 2] == 0x18))) || // LTR
984 ((Instructions
[i
+ 1] == 0x01) && // LGDT or LIDT or LMSW
985 (((Instructions
[i
+ 2] & 0x38) == 0x10) || // LGDT
986 (Instructions
[i
+ 2] == 0x18) || // LIDT
987 (Instructions
[i
+ 2] == 0x30))) || // LMSW
988 (Instructions
[i
+ 1] == 0x08) || // INVD
989 (Instructions
[i
+ 1] == 0x09) || // WBINVD
990 (Instructions
[i
+ 1] == 0x35) || // SYSEXIT
991 (Instructions
[i
+ 1] == 0x26) || // MOV DR, XXX
992 (Instructions
[i
+ 1] == 0x06) || // CLTS
993 (Instructions
[i
+ 1] == 0x20) || // MOV CR, XXX
994 (Instructions
[i
+ 1] == 0x24) || // MOV YYY, DR
995 (Instructions
[i
+ 1] == 0x30) || // WRMSR
996 (Instructions
[i
+ 1] == 0x33)) // RDPMC
997 // INVLPG, INVLPGA, SYSRET
999 /* These are all privileged */
1005 /* Get the IOPL and compare with the RPL mask */
1006 Iopl
= (TrapFrame
->EFlags
& EFLAGS_IOPL
) >> 12;
1007 if ((TrapFrame
->SegCs
& RPL_MASK
) > Iopl
)
1009 /* I/O privilege error -- check for known instructions */
1010 if ((Instruction
== 0xFA) || (Instruction
== 0xFB)) // CLI or STI
1012 /* These are privileged */
1017 /* Last hope: an IN/OUT instruction */
1018 for (j
= 0; j
< sizeof(KiTrapIoTable
); j
++)
1020 /* Is this an I/O instruction? */
1021 if (Instruction
== KiTrapIoTable
[j
])
1023 /* Then it's privileged */
1032 /* So now... was the instruction privileged or not? */
1035 /* Whew! We have a privileged instruction, so dispatch the fault */
1036 KiDispatchException0Args(STATUS_PRIVILEGED_INSTRUCTION
,
1042 /* If we got here, send an access violation */
1043 KiDispatchException2Args(STATUS_ACCESS_VIOLATION
,
1051 * Check for a fault during checking of the user instruction.
1053 * Note that the SEH handler will catch invalid EIP, but we could be dealing
1054 * with an invalid CS, which will generate another GPF instead.
1057 if (((PVOID
)TrapFrame
->Eip
>= (PVOID
)KiTrap0DHandler
) &&
1058 ((PVOID
)TrapFrame
->Eip
< (PVOID
)KiTrap0DHandler
))
1060 /* Not implemented */
1066 * NOTE: The ASM trap exit code would restore segment registers by doing
1067 * a POP <SEG>, which could cause an invalid segment if someone had messed
1068 * with the segment values.
1070 * Another case is a bogus SS, which would hit a GPF when doing the iret.
1071 * This could only be done through a buggy or malicious driver, or perhaps
1072 * the kernel debugger.
1074 * The kernel normally restores the "true" segment if this happens.
1076 * However, since we're restoring in C, not ASM, we can't detect
1077 * POP <SEG> since the actual instructions will be different.
1079 * A better technique would be to check the EIP and somehow edit the
1080 * trap frame before restarting the instruction -- but we would need to
1081 * know the extract instruction that was used first.
1083 * We could force a special instrinsic to use stack instructions, or write
1084 * a simple instruction length checker.
1086 * Nevertheless, this is a lot of work for the purpose of avoiding a crash
1087 * when the user is purposedly trying to create one from kernel-mode, so
1088 * we should probably table this for now since it's not a "real" issue.
1092 * NOTE2: Another scenario is the IRET during a V8086 restore (BIOS Call)
1093 * which will cause a GPF since the trap frame is a total mess (on purpose)
1094 * as built in KiEnterV86Mode.
1096 * The idea is to scan for IRET, scan for the known EIP adress, validate CS
1097 * and then manually issue a jump to the V8086 return EIP.
1099 Instructions
= (PUCHAR
)TrapFrame
->Eip
;
1100 if (Instructions
[0] == 0xCF)
1103 * Some evil shit is going on here -- this is not the SS:ESP you're
1104 * looking for! Instead, this is actually CS:EIP you're looking at!
1105 * Why? Because part of the trap frame actually corresponds to the IRET
1106 * stack during the trap exit!
1108 if ((TrapFrame
->HardwareEsp
== (ULONG
)Ki386BiosCallReturnAddress
) &&
1109 (TrapFrame
->HardwareSegSs
== (KGDT_R0_CODE
| RPL_MASK
)))
1111 /* Exit the V86 trap! */
1112 Ki386BiosCallReturnAddress(TrapFrame
);
1116 /* Otherwise, this is another kind of IRET fault */
1122 /* So since we're not dealing with the above case, check for RDMSR/WRMSR */
1123 if ((Instructions
[0] == 0xF) && // 2-byte opcode
1124 (((Instructions
[1] >> 8) == 0x30) || // RDMSR
1125 ((Instructions
[2] >> 8) == 0x32))) // WRMSR
1127 /* Unknown CPU MSR, so raise an access violation */
1128 KiDispatchException0Args(STATUS_ACCESS_VIOLATION
,
1133 /* Check for lazy segment load */
1134 if (TrapFrame
->SegDs
!= (KGDT_R3_DATA
| RPL_MASK
))
1137 TrapFrame
->SegDs
= (KGDT_R3_DATA
| RPL_MASK
);
1139 else if (TrapFrame
->SegEs
!= (KGDT_R3_DATA
| RPL_MASK
))
1142 TrapFrame
->SegEs
= (KGDT_R3_DATA
| RPL_MASK
);
1146 /* Whatever it is, we can't handle it */
1147 KiSystemFatalException(EXCEPTION_GP_FAULT
, TrapFrame
);
1150 /* Return to where we came from */
1151 KiTrapReturn(TrapFrame
);
1157 KiTrap0EHandler(IN PKTRAP_FRAME TrapFrame
)
1163 /* Save trap frame */
1164 KiEnterTrap(TrapFrame
);
1166 /* Check if this is the base frame */
1167 Thread
= KeGetCurrentThread();
1168 if (KeGetTrapFrame(Thread
) != TrapFrame
)
1170 /* It isn't, check if this is a second nested frame */
1171 if (((ULONG_PTR
)KeGetTrapFrame(Thread
) - (ULONG_PTR
)TrapFrame
) <=
1172 FIELD_OFFSET(KTRAP_FRAME
, EFlags
))
1174 /* The stack is somewhere in between frames, we need to fix it */
1183 /* HACK: Check if interrupts are disabled and enable them */
1184 if (!(TrapFrame
->EFlags
& EFLAGS_INTERRUPT_MASK
))
1186 /* Enable interupts */
1188 #ifdef HACK_ABOVE_FIXED
1189 if (!(TrapFrame
->EFlags
& EFLAGS_INTERRUPT_MASK
))
1191 /* This is illegal */
1192 KeBugCheckWithTf(IRQL_NOT_LESS_OR_EQUAL
,
1195 TrapFrame
->ErrCode
& 1,
1202 /* Call the access fault handler */
1203 Status
= MmAccessFault(TrapFrame
->ErrCode
& 1,
1205 TrapFrame
->SegCs
& MODE_MASK
,
1207 if (NT_SUCCESS(Status
)) KiEoiHelper(TrapFrame
);
1209 /* Check for S-LIST fault */
1210 if (TrapFrame
->Eip
== (ULONG_PTR
)ExpInterlockedPopEntrySListFault
)
1212 /* Not yet implemented */
1217 /* Check for syscall fault */
1219 if ((TrapFrame
->Eip
== (ULONG_PTR
)CopyParams
) ||
1220 (TrapFrame
->Eip
== (ULONG_PTR
)ReadBatch
))
1222 /* Not yet implemented */
1227 /* Check for VDM trap */
1228 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
1230 /* Either kernel or user trap (non VDM) so dispatch exception */
1231 if (Status
== STATUS_ACCESS_VIOLATION
)
1233 /* This status code is repurposed so we can recognize it later */
1234 KiDispatchException2Args(KI_EXCEPTION_ACCESS_VIOLATION
,
1236 TrapFrame
->ErrCode
& 1,
1240 else if ((Status
== STATUS_GUARD_PAGE_VIOLATION
) ||
1241 (Status
== STATUS_STACK_OVERFLOW
))
1243 /* These faults only have two parameters */
1244 KiDispatchException2Args(Status
,
1246 TrapFrame
->ErrCode
& 1,
1251 /* Only other choice is an in-page error, with 3 parameters */
1252 KiDispatchExceptionFromTrapFrame(STATUS_IN_PAGE_ERROR
,
1255 TrapFrame
->ErrCode
& 1,
1264 KiTrap0FHandler(IN PKTRAP_FRAME TrapFrame
)
1266 /* Save trap frame */
1267 KiEnterTrap(TrapFrame
);
1269 /* FIXME: Kill the system */
1271 KiSystemFatalException(EXCEPTION_RESERVED_TRAP
, TrapFrame
);
1277 KiTrap10Handler(IN PKTRAP_FRAME TrapFrame
)
1280 PFX_SAVE_AREA SaveArea
;
1282 /* Save trap frame */
1283 KiEnterTrap(TrapFrame
);
1285 /* Check if this is the NPX thrad */
1286 Thread
= KeGetCurrentThread();
1287 SaveArea
= KiGetThreadNpxArea(Thread
);
1288 if (Thread
!= KeGetCurrentPrcb()->NpxThread
)
1290 /* It isn't, enable interrupts and set delayed error */
1292 SaveArea
->Cr0NpxState
|= CR0_TS
;
1295 KiEoiHelper(TrapFrame
);
1298 /* Otherwise, proceed with NPX fault handling */
1299 KiNpxHandler(TrapFrame
, Thread
, SaveArea
);
1305 KiTrap11Handler(IN PKTRAP_FRAME TrapFrame
)
1307 /* Save trap frame */
1308 KiEnterTrap(TrapFrame
);
1310 /* Enable interrupts and kill the system */
1312 KiSystemFatalException(EXCEPTION_ALIGNMENT_CHECK
, TrapFrame
);
1318 KiTrap13Handler(IN PKTRAP_FRAME TrapFrame
)
1321 PFX_SAVE_AREA SaveArea
;
1322 ULONG Cr0
, MxCsrMask
, Error
;
1324 /* Save trap frame */
1325 KiEnterTrap(TrapFrame
);
1327 /* Check if this is the NPX thrad */
1328 Thread
= KeGetCurrentThread();
1329 if (Thread
!= KeGetCurrentPrcb()->NpxThread
)
1331 /* It isn't, kill the system */
1332 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 13, (ULONG_PTR
)Thread
, 0, 0, TrapFrame
);
1335 /* Get the NPX frame */
1336 SaveArea
= KiGetThreadNpxArea(Thread
);
1338 /* Check for VDM trap */
1339 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
1341 /* Check for user trap */
1342 if (!KiUserTrap(TrapFrame
))
1344 /* Kernel should not fault on XMMI */
1345 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 13, 0, 0, 2, TrapFrame
);
1350 Cr0
&= ~(CR0_MP
| CR0_EM
| CR0_TS
);
1353 /* Save FPU state */
1354 Ke386SaveFpuState(SaveArea
);
1356 /* Mark CR0 state dirty */
1357 Cr0
|= NPX_STATE_NOT_LOADED
;
1358 Cr0
|= SaveArea
->Cr0NpxState
;
1361 /* Update NPX state */
1362 Thread
->NpxState
= NPX_STATE_NOT_LOADED
;
1363 KeGetCurrentPrcb()->NpxThread
= NULL
;
1365 /* Clear the TS bit and re-enable interrupts */
1366 SaveArea
->Cr0NpxState
&= ~CR0_TS
;
1369 /* Now look at MxCsr to get the mask of errors we should care about */
1370 MxCsrMask
= ~((USHORT
)SaveArea
->U
.FxArea
.MXCsr
>> 7);
1372 /* Get legal exceptions that software should handle */
1373 Error
= (USHORT
)SaveArea
->U
.FxArea
.MXCsr
& (FSW_INVALID_OPERATION
|
1381 /* Now handle any of those legal errors */
1382 if (Error
& (FSW_INVALID_OPERATION
|
1389 /* By issuing an exception */
1390 KiDispatchException1Args(STATUS_FLOAT_MULTIPLE_TRAPS
,
1396 /* Unknown XMMI fault */
1397 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 13, 0, 0, 1, TrapFrame
);
1400 /* SOFTWARE SERVICES **********************************************************/
1404 KiGetTickCountHandler(IN PKTRAP_FRAME TrapFrame
)
1412 KiCallbackReturnHandler(IN PKTRAP_FRAME TrapFrame
)
1421 KiRaiseAssertionHandler(IN PKTRAP_FRAME TrapFrame
)
1423 /* Save trap frame */
1424 KiEnterTrap(TrapFrame
);
1426 /* Decrement EIP to point to the INT2C instruction (2 bytes, not 1 like INT3) */
1427 TrapFrame
->Eip
-= 2;
1429 /* Dispatch the exception */
1430 KiDispatchException0Args(STATUS_ASSERTION_FAILURE
,
1438 KiDebugServiceHandler(IN PKTRAP_FRAME TrapFrame
)
1440 /* Save trap frame */
1441 KiEnterTrap(TrapFrame
);
1443 /* Increment EIP to skip the INT3 instruction */
1446 /* Continue with the common handler */
1447 KiDebugHandler(TrapFrame
, TrapFrame
->Eax
, TrapFrame
->Ecx
, TrapFrame
->Edx
);
1453 KiDbgPreServiceHook(ULONG SystemCallNumber
, PULONG_PTR Arguments
)
1455 #if DBG && !defined(_WINKD_)
1456 if (SystemCallNumber
>= 0x1000 && KeWin32PreServiceHook
)
1457 KeWin32PreServiceHook(SystemCallNumber
, Arguments
);
1463 KiDbgPostServiceHook(ULONG SystemCallNumber
, ULONG_PTR Result
)
1465 #if DBG && !defined(_WINKD_)
1466 if (SystemCallNumber
>= 0x1000 && KeWin32PostServiceHook
)
1467 return KeWin32PostServiceHook(SystemCallNumber
, Result
);
1475 KiSystemCall(IN PKTRAP_FRAME TrapFrame
,
1479 PKSERVICE_TABLE_DESCRIPTOR DescriptorTable
;
1480 ULONG Id
, Offset
, StackBytes
, Result
;
1482 ULONG SystemCallNumber
= TrapFrame
->Eax
;
1484 /* Get the current thread */
1485 Thread
= KeGetCurrentThread();
1487 /* Set debug header */
1488 KiFillTrapFrameDebug(TrapFrame
);
1490 /* Chain trap frames */
1491 TrapFrame
->Edx
= (ULONG_PTR
)Thread
->TrapFrame
;
1494 TrapFrame
->ErrCode
= 0;
1496 /* Save previous mode */
1497 TrapFrame
->PreviousPreviousMode
= Thread
->PreviousMode
;
1499 /* Save the SEH chain and terminate it for now */
1500 TrapFrame
->ExceptionList
= KeGetPcr()->NtTib
.ExceptionList
;
1501 KeGetPcr()->NtTib
.ExceptionList
= EXCEPTION_CHAIN_END
;
1503 /* Clear DR7 and check for debugging */
1505 if (__builtin_expect(Thread
->DispatcherHeader
.DebugActive
& 0xFF, 0))
1511 /* Set thread fields */
1512 Thread
->TrapFrame
= TrapFrame
;
1513 Thread
->PreviousMode
= KiUserTrap(TrapFrame
);
1515 /* Enable interrupts */
1518 /* Decode the system call number */
1519 Offset
= (SystemCallNumber
>> SERVICE_TABLE_SHIFT
) & SERVICE_TABLE_MASK
;
1520 Id
= SystemCallNumber
& SERVICE_NUMBER_MASK
;
1522 /* Get descriptor table */
1523 DescriptorTable
= (PVOID
)((ULONG_PTR
)Thread
->ServiceTable
+ Offset
);
1525 /* Validate the system call number */
1526 if (__builtin_expect(Id
>= DescriptorTable
->Limit
, 0))
1528 /* Check if this is a GUI call */
1529 if (!(Offset
& SERVICE_TABLE_TEST
))
1532 Result
= STATUS_INVALID_SYSTEM_SERVICE
;
1536 /* Convert us to a GUI thread -- must wrap in ASM to get new EBP */
1537 Result
= KiConvertToGuiThread();
1538 if (!NT_SUCCESS(Result
))
1540 /* Set the last error and fail */
1541 //SetLastWin32Error(RtlNtStatusToDosError(Result));
1545 /* Reload trap frame and descriptor table pointer from new stack */
1546 TrapFrame
= *(volatile PVOID
*)&Thread
->TrapFrame
;
1547 DescriptorTable
= (PVOID
)(*(volatile ULONG_PTR
*)&Thread
->ServiceTable
+ Offset
);
1549 /* Validate the system call number again */
1550 if (Id
>= DescriptorTable
->Limit
)
1553 Result
= STATUS_INVALID_SYSTEM_SERVICE
;
1558 /* Check if this is a GUI call */
1559 if (__builtin_expect(Offset
& SERVICE_TABLE_TEST
, 0))
1561 /* Get the batch count and flush if necessary */
1562 if (NtCurrentTeb()->GdiBatchCount
) KeGdiFlushUserBatch();
1565 /* Increase system call count */
1566 KeGetCurrentPrcb()->KeSystemCalls
++;
1568 /* FIXME: Increase individual counts on debug systems */
1569 //KiIncreaseSystemCallCount(DescriptorTable, Id);
1571 /* Get stack bytes */
1572 StackBytes
= DescriptorTable
->Number
[Id
];
1574 /* Probe caller stack */
1575 if (__builtin_expect((Arguments
< (PVOID
)MmUserProbeAddress
) && !(KiUserTrap(TrapFrame
)), 0))
1577 /* Access violation */
1582 /* Call pre-service debug hook */
1583 KiDbgPreServiceHook(SystemCallNumber
, Arguments
);
1585 /* Get the handler and make the system call */
1586 Handler
= (PVOID
)DescriptorTable
->Base
[Id
];
1587 Result
= KiSystemCallTrampoline(Handler
, Arguments
, StackBytes
);
1589 /* Call post-service debug hook */
1590 Result
= KiDbgPostServiceHook(SystemCallNumber
, Result
);
1592 /* Make sure we're exiting correctly */
1593 KiExitSystemCallDebugChecks(Id
, TrapFrame
);
1595 /* Restore the old trap frame */
1597 Thread
->TrapFrame
= (PKTRAP_FRAME
)TrapFrame
->Edx
;
1599 /* Exit from system call */
1600 KiServiceExit(TrapFrame
, Result
);
1606 KiSystemServiceHandler(IN PKTRAP_FRAME TrapFrame
,
1609 /* Call the shared handler (inline) */
1610 KiSystemCall(TrapFrame
, Arguments
);
1616 KiFastCallEntryHandler(IN PKTRAP_FRAME TrapFrame
,
1619 /* Set up a fake INT Stack and enable interrupts */
1620 TrapFrame
->HardwareSegSs
= KGDT_R3_DATA
| RPL_MASK
;
1621 TrapFrame
->HardwareEsp
= (ULONG_PTR
)Arguments
;
1622 TrapFrame
->EFlags
= __readeflags() | EFLAGS_INTERRUPT_MASK
;
1623 TrapFrame
->SegCs
= KGDT_R3_CODE
| RPL_MASK
;
1624 TrapFrame
->Eip
= SharedUserData
->SystemCallReturn
;
1625 TrapFrame
->SegFs
= KGDT_R3_TEB
| RPL_MASK
;
1628 /* Arguments are actually 2 frames down (because of the double indirection) */
1629 Arguments
= (PVOID
)(TrapFrame
->HardwareEsp
+ 8);
1631 /* Call the shared handler (inline) */
1632 KiSystemCall(TrapFrame
, Arguments
);
1640 Kei386EoiHelper(VOID
)
1642 /* We should never see this call happening */
1643 DPRINT1("Mismatched NT/HAL version");