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
;
51 /* TRAP EXIT CODE *************************************************************/
55 KiVdmTrap(IN PKTRAP_FRAME TrapFrame
)
57 /* Either the V8086 flag is on, or this is user-mode with a VDM */
58 return ((TrapFrame
->EFlags
& EFLAGS_V86_MASK
) ||
59 ((KiUserTrap(TrapFrame
)) && (PsGetCurrentProcess()->VdmObjects
)));
64 KiV86Trap(IN PKTRAP_FRAME TrapFrame
)
66 /* Check if the V8086 flag is on */
67 return ((TrapFrame
->EFlags
& EFLAGS_V86_MASK
) != 0);
72 KiIsFrameEdited(IN PKTRAP_FRAME TrapFrame
)
74 /* An edited frame changes esp. It is marked by clearing the bits
75 defined by FRAME_EDITED in the SegCs field of the trap frame */
76 return ((TrapFrame
->SegCs
& FRAME_EDITED
) == 0);
81 KiCommonExit(IN PKTRAP_FRAME TrapFrame
, const ULONG Flags
)
83 /* Disable interrupts until we return */
86 /* Check for APC delivery */
87 KiCheckForApcDelivery(TrapFrame
);
89 /* Debugging checks */
90 KiExitTrapDebugChecks(TrapFrame
, Flags
);
92 /* Restore the SEH handler chain */
93 KeGetPcr()->NtTib
.ExceptionList
= TrapFrame
->ExceptionList
;
95 /* Check if there are active debug registers */
96 if (__builtin_expect(TrapFrame
->Dr7
& ~DR7_RESERVED_MASK
, 0))
99 DbgPrint("Need Hardware Breakpoint Support!\n");
108 KiEoiHelper(IN PKTRAP_FRAME TrapFrame
)
110 /* Common trap exit code */
111 KiCommonExit(TrapFrame
, 0);
113 /* Check if this was a V8086 trap */
114 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
) KiTrapReturnNoSegments(TrapFrame
);
116 /* Check for user mode exit */
117 if (TrapFrame
->SegCs
& MODE_MASK
) KiTrapReturn(TrapFrame
);
119 /* Check for edited frame */
120 if (KiIsFrameEdited(TrapFrame
)) KiEditedTrapReturn(TrapFrame
);
122 /* Exit the trap to kernel mode */
123 KiTrapReturnNoSegments(TrapFrame
);
129 KiServiceExit(IN PKTRAP_FRAME TrapFrame
,
132 ASSERT((TrapFrame
->EFlags
& EFLAGS_V86_MASK
) == 0);
133 ASSERT(!KiIsFrameEdited(TrapFrame
));
135 /* Copy the status into EAX */
136 TrapFrame
->Eax
= Status
;
138 /* Common trap exit code */
139 KiCommonExit(TrapFrame
, 0);
141 /* Restore previous mode */
142 KeGetCurrentThread()->PreviousMode
= TrapFrame
->PreviousPreviousMode
;
144 /* Check for user mode exit */
145 if (TrapFrame
->SegCs
& MODE_MASK
)
147 /* Check if we were single stepping */
148 if (TrapFrame
->EFlags
& EFLAGS_TF
)
150 /* Must use the IRET handler */
151 KiSystemCallTrapReturn(TrapFrame
);
155 /* We can use the sysexit handler */
156 KiFastCallExitHandler(TrapFrame
);
160 /* Exit to kernel mode */
161 KiSystemCallReturn(TrapFrame
);
167 KiServiceExit2(IN PKTRAP_FRAME TrapFrame
)
169 /* Common trap exit code */
170 KiCommonExit(TrapFrame
, 0);
172 /* Restore previous mode */
173 KeGetCurrentThread()->PreviousMode
= TrapFrame
->PreviousPreviousMode
;
175 /* Check if this was a V8086 trap */
176 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
) KiTrapReturnNoSegments(TrapFrame
);
178 /* Check for user mode exit */
179 if (TrapFrame
->SegCs
& MODE_MASK
) KiTrapReturn(TrapFrame
);
181 /* Check for edited frame */
182 if (KiIsFrameEdited(TrapFrame
)) KiEditedTrapReturn(TrapFrame
);
184 /* Exit the trap to kernel mode */
185 KiTrapReturnNoSegments(TrapFrame
);
189 /* TRAP HANDLERS **************************************************************/
194 KiDebugHandler(IN PKTRAP_FRAME TrapFrame
,
199 /* Check for VDM trap */
200 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
202 /* Enable interrupts if the trap came from user-mode */
203 if (KiUserTrap(TrapFrame
)) _enable();
205 /* Dispatch the exception */
206 KiDispatchExceptionFromTrapFrame(STATUS_BREAKPOINT
,
218 KiNpxHandler(IN PKTRAP_FRAME TrapFrame
,
220 IN PFX_SAVE_AREA SaveArea
)
222 ULONG Cr0
, Mask
, Error
, ErrorOffset
, DataOffset
;
224 /* Check for VDM trap */
225 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
227 /* Check for kernel trap */
228 if (!KiUserTrap(TrapFrame
))
230 /* Kernel might've tripped a delayed error */
231 SaveArea
->Cr0NpxState
|= CR0_TS
;
233 /* Only valid if it happened during a restore */
234 //if ((PVOID)TrapFrame->Eip == FrRestore)
236 /* It did, so just skip the instruction */
237 //TrapFrame->Eip += 3; /* sizeof(FRSTOR) */
238 //KiEoiHelper(TrapFrame);
242 /* User or kernel trap -- get ready to issue an exception */
243 if (Thread
->NpxState
== NPX_STATE_NOT_LOADED
)
247 Cr0
&= ~(CR0_MP
| CR0_EM
| CR0_TS
);
251 //Ke386SaveFpuState(SaveArea);
253 /* Mark CR0 state dirty */
254 Cr0
|= NPX_STATE_NOT_LOADED
;
255 Cr0
|= SaveArea
->Cr0NpxState
;
258 /* Update NPX state */
259 Thread
->NpxState
= NPX_STATE_NOT_LOADED
;
260 KeGetCurrentPrcb()->NpxThread
= NULL
;
263 /* Clear the TS bit and re-enable interrupts */
264 SaveArea
->Cr0NpxState
&= ~CR0_TS
;
267 /* Check if we should get the FN or FX error */
268 if (KeI386FxsrPresent
)
271 Mask
= SaveArea
->U
.FxArea
.ControlWord
;
272 Error
= SaveArea
->U
.FxArea
.StatusWord
;
274 /* Get the FPU exception address too */
275 ErrorOffset
= SaveArea
->U
.FxArea
.ErrorOffset
;
276 DataOffset
= SaveArea
->U
.FxArea
.DataOffset
;
281 Mask
= SaveArea
->U
.FnArea
.ControlWord
;
282 Error
= SaveArea
->U
.FnArea
.StatusWord
;
284 /* Get the FPU exception address too */
285 ErrorOffset
= SaveArea
->U
.FnArea
.ErrorOffset
;
286 DataOffset
= SaveArea
->U
.FnArea
.DataOffset
;
289 /* Get legal exceptions that software should handle */
290 Error
&= (FSW_INVALID_OPERATION
|
298 if (Error
& FSW_STACK_FAULT
)
300 /* Issue stack check fault */
301 KiDispatchException2Args(STATUS_FLOAT_STACK_CHECK
,
308 /* Check for invalid operation */
309 if (Error
& FSW_INVALID_OPERATION
)
312 KiDispatchException1Args(STATUS_FLOAT_INVALID_OPERATION
,
318 /* Check for divide by zero */
319 if (Error
& FSW_ZERO_DIVIDE
)
322 KiDispatchException1Args(STATUS_FLOAT_DIVIDE_BY_ZERO
,
328 /* Check for denormal */
329 if (Error
& FSW_DENORMAL
)
332 KiDispatchException1Args(STATUS_FLOAT_INVALID_OPERATION
,
338 /* Check for overflow */
339 if (Error
& FSW_OVERFLOW
)
342 KiDispatchException1Args(STATUS_FLOAT_OVERFLOW
,
348 /* Check for underflow */
349 if (Error
& FSW_UNDERFLOW
)
352 KiDispatchException1Args(STATUS_FLOAT_UNDERFLOW
,
358 /* Check for precision fault */
359 if (Error
& FSW_PRECISION
)
362 KiDispatchException1Args(STATUS_FLOAT_INEXACT_RESULT
,
368 /* Unknown FPU fault */
369 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 1, Error
, 0, 0, TrapFrame
);
375 KiTrap00Handler(IN PKTRAP_FRAME TrapFrame
)
377 /* Save trap frame */
378 KiEnterTrap(TrapFrame
);
380 /* Check for VDM trap */
381 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
383 /* Enable interrupts */
386 /* Dispatch the exception */
387 KiDispatchException0Args(STATUS_INTEGER_DIVIDE_BY_ZERO
,
395 KiTrap01Handler(IN PKTRAP_FRAME TrapFrame
)
397 /* Save trap frame */
398 KiEnterTrap(TrapFrame
);
400 /* Check for VDM trap */
401 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
403 /* Enable interrupts if the trap came from user-mode */
404 if (KiUserTrap(TrapFrame
)) _enable();
406 /* Mask out trap flag and dispatch the exception */
407 TrapFrame
->EFlags
&= ~EFLAGS_TF
;
408 KiDispatchException0Args(STATUS_SINGLE_STEP
,
421 KTRAP_FRAME TrapFrame
;
425 // In some sort of strange recursion case, we might end up here with the IF
426 // flag incorrectly on the interrupt frame -- during a normal NMI this would
427 // normally already be set.
429 // For sanity's sake, make sure interrupts are disabled for sure.
430 // NMIs will already be since the CPU does it for us.
435 // Get the current TSS, thread, and process
438 Thread
= ((PKIPCR
)PCR
)->PrcbData
.CurrentThread
;
439 Process
= Thread
->ApcState
.Process
;
442 // Save data usually not in the TSS
444 Tss
->CR3
= Process
->DirectoryTableBase
[0];
445 Tss
->IoMapBase
= Process
->IopmOffset
;
446 Tss
->LDT
= Process
->LdtDescriptor
.LimitLow
? KGDT_LDT
: 0;
449 // Now get the base address of the NMI TSS
451 TssGdt
= &((PKIPCR
)KeGetPcr())->GDT
[KGDT_NMI_TSS
/ sizeof(KGDTENTRY
)];
452 NmiTss
= (PKTSS
)(ULONG_PTR
)(TssGdt
->BaseLow
|
453 TssGdt
->HighWord
.Bytes
.BaseMid
<< 16 |
454 TssGdt
->HighWord
.Bytes
.BaseHi
<< 24);
457 // Switch to it and activate it, masking off the nested flag
459 // Note that in reality, we are already on the NMI tss -- we just need to
460 // update the PCR to reflect this
463 __writeeflags(__readeflags() &~ EFLAGS_NESTED_TASK
);
464 TssGdt
->HighWord
.Bits
.Dpl
= 0;
465 TssGdt
->HighWord
.Bits
.Pres
= 1;
466 TssGdt
->HighWord
.Bits
.Type
= I386_TSS
;
469 // Now build the trap frame based on the original TSS
471 // The CPU does a hardware "Context switch" / task switch of sorts and so it
472 // takes care of saving our context in the normal TSS.
474 // We just have to go get the values...
476 RtlZeroMemory(&TrapFrame
, sizeof(KTRAP_FRAME
));
477 TrapFrame
.HardwareSegSs
= Tss
->Ss0
;
478 TrapFrame
.HardwareEsp
= Tss
->Esp0
;
479 TrapFrame
.EFlags
= Tss
->EFlags
;
480 TrapFrame
.SegCs
= Tss
->Cs
;
481 TrapFrame
.Eip
= Tss
->Eip
;
482 TrapFrame
.Ebp
= Tss
->Ebp
;
483 TrapFrame
.Ebx
= Tss
->Ebx
;
484 TrapFrame
.Esi
= Tss
->Esi
;
485 TrapFrame
.Edi
= Tss
->Edi
;
486 TrapFrame
.SegFs
= Tss
->Fs
;
487 TrapFrame
.ExceptionList
= PCR
->NtTib
.ExceptionList
;
488 TrapFrame
.PreviousPreviousMode
= -1;
489 TrapFrame
.Eax
= Tss
->Eax
;
490 TrapFrame
.Ecx
= Tss
->Ecx
;
491 TrapFrame
.Edx
= Tss
->Edx
;
492 TrapFrame
.SegDs
= Tss
->Ds
;
493 TrapFrame
.SegEs
= Tss
->Es
;
494 TrapFrame
.SegGs
= Tss
->Gs
;
495 TrapFrame
.DbgEip
= Tss
->Eip
;
496 TrapFrame
.DbgEbp
= Tss
->Ebp
;
499 // Store the trap frame in the KPRCB
501 KiSaveProcessorState(&TrapFrame
, NULL
);
504 // Call any registered NMI handlers and see if they handled it or not
509 // They did not, so call the platform HAL routine to bugcheck the system
511 // Make sure the HAL believes it's running at HIGH IRQL... we can't use
512 // the normal APIs here as playing with the IRQL could change the system
516 PCR
->Irql
= HIGH_LEVEL
;
522 // Although the CPU disabled NMIs, we just did a BIOS Call, which could've
523 // totally changed things.
525 // We have to make sure we're still in our original NMI -- a nested NMI
526 // will point back to the NMI TSS, and in that case we're hosed.
528 if (PCR
->TSS
->Backlink
!= KGDT_NMI_TSS
)
531 // Restore original TSS
536 // Set it back to busy
538 TssGdt
->HighWord
.Bits
.Dpl
= 0;
539 TssGdt
->HighWord
.Bits
.Pres
= 1;
540 TssGdt
->HighWord
.Bits
.Type
= I386_ACTIVE_TSS
;
543 // Restore nested flag
545 __writeeflags(__readeflags() | EFLAGS_NESTED_TASK
);
548 // Handled, return from interrupt
550 __asm__
__volatile__ ("iret\n");
554 // Unhandled: crash the system
556 KiSystemFatalException(EXCEPTION_NMI
, NULL
);
562 KiTrap03Handler(IN PKTRAP_FRAME TrapFrame
)
564 /* Save trap frame */
565 KiEnterTrap(TrapFrame
);
567 /* Continue with the common handler */
568 KiDebugHandler(TrapFrame
, BREAKPOINT_BREAK
, 0, 0);
574 KiTrap04Handler(IN PKTRAP_FRAME TrapFrame
)
576 /* Save trap frame */
577 KiEnterTrap(TrapFrame
);
579 /* Check for VDM trap */
580 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
582 /* Enable interrupts */
585 /* Dispatch the exception */
586 KiDispatchException0Args(STATUS_INTEGER_OVERFLOW
,
594 KiTrap05Handler(IN PKTRAP_FRAME TrapFrame
)
596 /* Save trap frame */
597 KiEnterTrap(TrapFrame
);
599 /* Check for VDM trap */
600 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
602 /* Check for kernel-mode fault */
603 if (!KiUserTrap(TrapFrame
)) KiSystemFatalException(EXCEPTION_BOUND_CHECK
, TrapFrame
);
605 /* Enable interrupts */
608 /* Dispatch the exception */
609 KiDispatchException0Args(STATUS_ARRAY_BOUNDS_EXCEEDED
,
617 KiTrap06Handler(IN PKTRAP_FRAME TrapFrame
)
623 /* Check for V86 GPF */
624 if (__builtin_expect(KiV86Trap(TrapFrame
), 1))
627 KiEnterV86Trap(TrapFrame
);
629 /* Must be a VDM process */
630 if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects
, 0))
632 /* Enable interrupts */
635 /* Setup illegal instruction fault */
636 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION
,
641 /* Go to APC level */
642 OldIrql
= KfRaiseIrql(APC_LEVEL
);
646 if (!VdmDispatchBop(TrapFrame
))
648 /* Should only happen in VDM mode */
653 /* Bring IRQL back */
654 KfLowerIrql(OldIrql
);
657 /* Do a quick V86 exit if possible */
658 KiExitV86Trap(TrapFrame
);
661 /* Save trap frame */
662 KiEnterTrap(TrapFrame
);
664 /* Enable interrupts */
665 Instruction
= (PUCHAR
)TrapFrame
->Eip
;
668 /* Check for user trap */
669 if (KiUserTrap(TrapFrame
))
673 /* Scan next 4 opcodes */
674 for (i
= 0; i
< 4; i
++)
676 /* Check for LOCK instruction */
677 if (Instruction
[i
] == 0xF0)
679 /* Send invalid lock sequence exception */
680 KiDispatchException0Args(STATUS_INVALID_LOCK_SEQUENCE
,
686 /* FIXME: SEH ends here */
689 /* Kernel-mode or user-mode fault (but not LOCK) */
690 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION
,
699 KiTrap07Handler(IN PKTRAP_FRAME TrapFrame
)
701 PKTHREAD Thread
, NpxThread
;
702 PFX_SAVE_AREA SaveArea
, NpxSaveArea
;
705 /* Save trap frame */
706 KiEnterTrap(TrapFrame
);
708 /* Try to handle NPX delay load */
711 /* Get the current thread */
712 Thread
= KeGetCurrentThread();
714 /* Get the NPX frame */
715 SaveArea
= KiGetThreadNpxArea(Thread
);
717 /* Check if emulation is enabled */
718 if (SaveArea
->Cr0NpxState
& CR0_EM
)
720 /* Not implemented */
725 /* Save CR0 and check NPX state */
727 if (Thread
->NpxState
!= NPX_STATE_LOADED
)
730 Cr0
&= ~(CR0_MP
| CR0_EM
| CR0_TS
);
733 /* Get the NPX thread */
734 NpxThread
= KeGetCurrentPrcb()->NpxThread
;
737 /* Get the NPX frame */
738 NpxSaveArea
= KiGetThreadNpxArea(NpxThread
);
741 //Ke386SaveFpuState(NpxSaveArea);
743 /* Update NPX state */
744 Thread
->NpxState
= NPX_STATE_NOT_LOADED
;
748 //Ke386LoadFpuState(SaveArea);
750 /* Update NPX state */
751 Thread
->NpxState
= NPX_STATE_LOADED
;
752 KeGetCurrentPrcb()->NpxThread
= Thread
;
754 /* Enable interrupts */
757 /* Check if CR0 needs to be reloaded due to context switch */
758 if (!SaveArea
->Cr0NpxState
) KiEoiHelper(TrapFrame
);
760 /* Otherwise, we need to reload CR0, disable interrupts */
765 Cr0
|= SaveArea
->Cr0NpxState
;
768 /* Now restore interrupts and check for TS */
770 if (Cr0
& CR0_TS
) KiEoiHelper(TrapFrame
);
772 /* We're still here -- clear TS and try again */
773 __writecr0(__readcr0() &~ CR0_TS
);
778 /* This is an actual fault, not a lack of FPU state */
783 /* TS should not be set */
787 * If it's incorrectly set, then maybe the state is actually still valid
788 * but we could've lock track of that due to a BIOS call.
789 * Make sure MP is still set, which should verify the theory.
793 /* Indeed, the state is actually still valid, so clear TS */
794 __writecr0(__readcr0() &~ CR0_TS
);
795 KiEoiHelper(TrapFrame
);
798 /* Otherwise, something strange is going on */
799 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 2, Cr0
, 0, 0, TrapFrame
);
802 /* It's not a delayed load, so process this trap as an NPX fault */
803 KiNpxHandler(TrapFrame
, Thread
, SaveArea
);
809 KiTrap08Handler(IN PKTRAP_FRAME TrapFrame
)
811 /* FIXME: Not handled */
812 KiSystemFatalException(EXCEPTION_DOUBLE_FAULT
, TrapFrame
);
818 KiTrap09Handler(IN PKTRAP_FRAME TrapFrame
)
820 /* Save trap frame */
821 KiEnterTrap(TrapFrame
);
823 /* Enable interrupts and kill the system */
825 KiSystemFatalException(EXCEPTION_NPX_OVERRUN
, TrapFrame
);
831 KiTrap0AHandler(IN PKTRAP_FRAME TrapFrame
)
833 /* Save trap frame */
834 KiEnterTrap(TrapFrame
);
836 /* Check for VDM trap */
837 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
839 /* Kill the system */
840 KiSystemFatalException(EXCEPTION_INVALID_TSS
, TrapFrame
);
846 KiTrap0BHandler(IN PKTRAP_FRAME TrapFrame
)
848 /* Save trap frame */
849 KiEnterTrap(TrapFrame
);
851 /* FIXME: Kill the system */
853 KiSystemFatalException(EXCEPTION_SEGMENT_NOT_PRESENT
, TrapFrame
);
859 KiTrap0CHandler(IN PKTRAP_FRAME TrapFrame
)
861 /* Save trap frame */
862 KiEnterTrap(TrapFrame
);
864 /* FIXME: Kill the system */
866 KiSystemFatalException(EXCEPTION_STACK_FAULT
, TrapFrame
);
872 KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame
)
875 BOOLEAN Privileged
= FALSE
;
877 UCHAR Instruction
= 0;
880 /* Check for V86 GPF */
881 if (__builtin_expect(KiV86Trap(TrapFrame
), 1))
884 KiEnterV86Trap(TrapFrame
);
886 /* Must be a VDM process */
887 if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects
, 0))
889 /* Enable interrupts */
892 /* Setup illegal instruction fault */
893 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION
,
898 /* Go to APC level */
899 OldIrql
= KfRaiseIrql(APC_LEVEL
);
902 /* Handle the V86 opcode */
903 if (__builtin_expect(Ki386HandleOpcodeV86(TrapFrame
) == 0xFF, 0))
905 /* Should only happen in VDM mode */
910 /* Bring IRQL back */
911 KfLowerIrql(OldIrql
);
914 /* Do a quick V86 exit if possible */
915 KiExitV86Trap(TrapFrame
);
918 /* Save trap frame */
919 KiEnterTrap(TrapFrame
);
921 /* Check for user-mode GPF */
922 if (KiUserTrap(TrapFrame
))
924 /* Should not be VDM */
925 ASSERT(KiVdmTrap(TrapFrame
) == FALSE
);
927 /* Enable interrupts and check error code */
929 if (!TrapFrame
->ErrCode
)
932 Instructions
= (PUCHAR
)TrapFrame
->Eip
;
934 /* Scan next 15 bytes */
935 for (i
= 0; i
< 15; i
++)
937 /* Skip prefix instructions */
938 for (j
= 0; j
< sizeof(KiTrapPrefixTable
); j
++)
940 /* Is this a prefix instruction? */
941 if (Instructions
[i
] == KiTrapPrefixTable
[j
])
948 /* Is this NOT any prefix instruction? */
949 if (j
== sizeof(KiTrapPrefixTable
))
951 /* We can go ahead and handle the fault now */
952 Instruction
= Instructions
[i
];
957 /* If all we found was prefixes, then this instruction is too long */
960 /* Setup illegal instruction fault */
961 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION
,
966 /* Check for privileged instructions */
967 if (Instruction
== 0xF4) // HLT
969 /* HLT is privileged */
972 else if (Instruction
== 0x0F)
974 /* Test if it's any of the privileged two-byte opcodes */
975 if (((Instructions
[i
+ 1] == 0x00) && // LLDT or LTR
976 (((Instructions
[i
+ 2] & 0x38) == 0x10) || // LLDT
977 (Instructions
[i
+ 2] == 0x18))) || // LTR
978 ((Instructions
[i
+ 1] == 0x01) && // LGDT or LIDT or LMSW
979 (((Instructions
[i
+ 2] & 0x38) == 0x10) || // LGDT
980 (Instructions
[i
+ 2] == 0x18) || // LIDT
981 (Instructions
[i
+ 2] == 0x30))) || // LMSW
982 (Instructions
[i
+ 1] == 0x08) || // INVD
983 (Instructions
[i
+ 1] == 0x09) || // WBINVD
984 (Instructions
[i
+ 1] == 0x35) || // SYSEXIT
985 (Instructions
[i
+ 1] == 0x26) || // MOV DR, XXX
986 (Instructions
[i
+ 1] == 0x06) || // CLTS
987 (Instructions
[i
+ 1] == 0x20) || // MOV CR, XXX
988 (Instructions
[i
+ 1] == 0x24) || // MOV YYY, DR
989 (Instructions
[i
+ 1] == 0x30) || // WRMSR
990 (Instructions
[i
+ 1] == 0x33)) // RDPMC
991 // INVLPG, INVLPGA, SYSRET
993 /* These are all privileged */
999 /* Get the IOPL and compare with the RPL mask */
1000 Iopl
= (TrapFrame
->EFlags
& EFLAGS_IOPL
) >> 12;
1001 if ((TrapFrame
->SegCs
& RPL_MASK
) > Iopl
)
1003 /* I/O privilege error -- check for known instructions */
1004 if ((Instruction
== 0xFA) || (Instruction
== 0xFB)) // CLI or STI
1006 /* These are privileged */
1011 /* Last hope: an IN/OUT instruction */
1012 for (j
= 0; j
< sizeof(KiTrapIoTable
); j
++)
1014 /* Is this an I/O instruction? */
1015 if (Instruction
== KiTrapIoTable
[j
])
1017 /* Then it's privileged */
1026 /* So now... was the instruction privileged or not? */
1029 /* Whew! We have a privileged instruction, so dispatch the fault */
1030 KiDispatchException0Args(STATUS_PRIVILEGED_INSTRUCTION
,
1036 /* If we got here, send an access violation */
1037 KiDispatchException2Args(STATUS_ACCESS_VIOLATION
,
1045 * Check for a fault during checking of the user instruction.
1047 * Note that the SEH handler will catch invalid EIP, but we could be dealing
1048 * with an invalid CS, which will generate another GPF instead.
1051 if (((PVOID
)TrapFrame
->Eip
>= (PVOID
)KiTrap0DHandler
) &&
1052 ((PVOID
)TrapFrame
->Eip
< (PVOID
)KiTrap0DHandler
))
1054 /* Not implemented */
1060 * NOTE: The ASM trap exit code would restore segment registers by doing
1061 * a POP <SEG>, which could cause an invalid segment if someone had messed
1062 * with the segment values.
1064 * Another case is a bogus SS, which would hit a GPF when doing the iret.
1065 * This could only be done through a buggy or malicious driver, or perhaps
1066 * the kernel debugger.
1068 * The kernel normally restores the "true" segment if this happens.
1070 * However, since we're restoring in C, not ASM, we can't detect
1071 * POP <SEG> since the actual instructions will be different.
1073 * A better technique would be to check the EIP and somehow edit the
1074 * trap frame before restarting the instruction -- but we would need to
1075 * know the extract instruction that was used first.
1077 * We could force a special instrinsic to use stack instructions, or write
1078 * a simple instruction length checker.
1080 * Nevertheless, this is a lot of work for the purpose of avoiding a crash
1081 * when the user is purposedly trying to create one from kernel-mode, so
1082 * we should probably table this for now since it's not a "real" issue.
1086 * NOTE2: Another scenario is the IRET during a V8086 restore (BIOS Call)
1087 * which will cause a GPF since the trap frame is a total mess (on purpose)
1088 * as built in KiEnterV86Mode.
1090 * The idea is to scan for IRET, scan for the known EIP adress, validate CS
1091 * and then manually issue a jump to the V8086 return EIP.
1093 Instructions
= (PUCHAR
)TrapFrame
->Eip
;
1094 if (Instructions
[0] == 0xCF)
1097 * Some evil shit is going on here -- this is not the SS:ESP you're
1098 * looking for! Instead, this is actually CS:EIP you're looking at!
1099 * Why? Because part of the trap frame actually corresponds to the IRET
1100 * stack during the trap exit!
1102 if ((TrapFrame
->HardwareEsp
== (ULONG
)Ki386BiosCallReturnAddress
) &&
1103 (TrapFrame
->HardwareSegSs
== (KGDT_R0_CODE
| RPL_MASK
)))
1105 /* Exit the V86 trap! */
1106 Ki386BiosCallReturnAddress(TrapFrame
);
1110 /* Otherwise, this is another kind of IRET fault */
1116 /* So since we're not dealing with the above case, check for RDMSR/WRMSR */
1117 if ((Instructions
[0] == 0xF) && // 2-byte opcode
1118 (((Instructions
[1] >> 8) == 0x30) || // RDMSR
1119 ((Instructions
[2] >> 8) == 0x32))) // WRMSR
1121 /* Unknown CPU MSR, so raise an access violation */
1122 KiDispatchException0Args(STATUS_ACCESS_VIOLATION
,
1127 /* Check for lazy segment load */
1128 if (TrapFrame
->SegDs
!= (KGDT_R3_DATA
| RPL_MASK
))
1131 TrapFrame
->SegDs
= (KGDT_R3_DATA
| RPL_MASK
);
1133 else if (TrapFrame
->SegEs
!= (KGDT_R3_DATA
| RPL_MASK
))
1136 TrapFrame
->SegEs
= (KGDT_R3_DATA
| RPL_MASK
);
1140 /* Whatever it is, we can't handle it */
1141 KiSystemFatalException(EXCEPTION_GP_FAULT
, TrapFrame
);
1144 /* Return to where we came from */
1145 KiTrapReturn(TrapFrame
);
1151 KiTrap0EHandler(IN PKTRAP_FRAME TrapFrame
)
1157 /* Save trap frame */
1158 KiEnterTrap(TrapFrame
);
1160 /* Check if this is the base frame */
1161 Thread
= KeGetCurrentThread();
1162 if (KeGetTrapFrame(Thread
) != TrapFrame
)
1164 /* It isn't, check if this is a second nested frame */
1165 if (((ULONG_PTR
)KeGetTrapFrame(Thread
) - (ULONG_PTR
)TrapFrame
) <=
1166 FIELD_OFFSET(KTRAP_FRAME
, EFlags
))
1168 /* The stack is somewhere in between frames, we need to fix it */
1177 /* Check for Pentium LOCK errata */
1178 if (KiI386PentiumLockErrataPresent
)
1180 /* Not yet implemented */
1185 /* HACK: Check if interrupts are disabled and enable them */
1186 if (!(TrapFrame
->EFlags
& EFLAGS_INTERRUPT_MASK
))
1188 /* Enable interupts */
1190 #ifdef HACK_ABOVE_FIXED
1191 if (!(TrapFrame
->EFlags
& EFLAGS_INTERRUPT_MASK
))
1193 /* This is illegal */
1194 KeBugCheckWithTf(IRQL_NOT_LESS_OR_EQUAL
,
1197 TrapFrame
->ErrCode
& 1,
1204 /* Call the access fault handler */
1205 Status
= MmAccessFault(TrapFrame
->ErrCode
& 1,
1207 TrapFrame
->SegCs
& MODE_MASK
,
1209 if (Status
== STATUS_SUCCESS
) KiEoiHelper(TrapFrame
);
1211 /* Check for S-LIST fault */
1212 if (TrapFrame
->Eip
== (ULONG_PTR
)ExpInterlockedPopEntrySListFault
)
1214 /* Not yet implemented */
1219 /* Check for syscall fault */
1221 if ((TrapFrame
->Eip
== (ULONG_PTR
)CopyParams
) ||
1222 (TrapFrame
->Eip
== (ULONG_PTR
)ReadBatch
))
1224 /* Not yet implemented */
1229 /* Check for VDM trap */
1230 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
1232 /* Either kernel or user trap (non VDM) so dispatch exception */
1233 if (Status
== STATUS_ACCESS_VIOLATION
)
1235 /* This status code is repurposed so we can recognize it later */
1236 KiDispatchException2Args(KI_EXCEPTION_ACCESS_VIOLATION
,
1238 TrapFrame
->ErrCode
& 1,
1242 else if ((Status
== STATUS_GUARD_PAGE_VIOLATION
) ||
1243 (Status
== STATUS_STACK_OVERFLOW
))
1245 /* These faults only have two parameters */
1246 KiDispatchException2Args(Status
,
1248 TrapFrame
->ErrCode
& 1,
1253 /* Only other choice is an in-page error, with 3 parameters */
1254 KiDispatchExceptionFromTrapFrame(STATUS_IN_PAGE_ERROR
,
1257 TrapFrame
->ErrCode
& 1,
1266 KiTrap0FHandler(IN PKTRAP_FRAME TrapFrame
)
1268 /* Save trap frame */
1269 KiEnterTrap(TrapFrame
);
1271 /* FIXME: Kill the system */
1273 KiSystemFatalException(EXCEPTION_RESERVED_TRAP
, TrapFrame
);
1279 KiTrap10Handler(IN PKTRAP_FRAME TrapFrame
)
1282 PFX_SAVE_AREA SaveArea
;
1284 /* Save trap frame */
1285 KiEnterTrap(TrapFrame
);
1287 /* Check if this is the NPX thrad */
1288 Thread
= KeGetCurrentThread();
1289 SaveArea
= KiGetThreadNpxArea(Thread
);
1290 if (Thread
!= KeGetCurrentPrcb()->NpxThread
)
1292 /* It isn't, enable interrupts and set delayed error */
1294 SaveArea
->Cr0NpxState
|= CR0_TS
;
1297 KiEoiHelper(TrapFrame
);
1300 /* Otherwise, proceed with NPX fault handling */
1301 KiNpxHandler(TrapFrame
, Thread
, SaveArea
);
1307 KiTrap11Handler(IN PKTRAP_FRAME TrapFrame
)
1309 /* Save trap frame */
1310 KiEnterTrap(TrapFrame
);
1312 /* Enable interrupts and kill the system */
1314 KiSystemFatalException(EXCEPTION_ALIGNMENT_CHECK
, TrapFrame
);
1320 KiTrap13Handler(IN PKTRAP_FRAME TrapFrame
)
1323 PFX_SAVE_AREA SaveArea
;
1324 ULONG Cr0
, MxCsrMask
, Error
;
1326 /* Save trap frame */
1327 KiEnterTrap(TrapFrame
);
1329 /* Check if this is the NPX thrad */
1330 Thread
= KeGetCurrentThread();
1331 if (Thread
!= KeGetCurrentPrcb()->NpxThread
)
1333 /* It isn't, kill the system */
1334 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 13, (ULONG_PTR
)Thread
, 0, 0, TrapFrame
);
1337 /* Get the NPX frame */
1338 SaveArea
= KiGetThreadNpxArea(Thread
);
1340 /* Check for VDM trap */
1341 ASSERT((KiVdmTrap(TrapFrame
)) == FALSE
);
1343 /* Check for user trap */
1344 if (!KiUserTrap(TrapFrame
))
1346 /* Kernel should not fault on XMMI */
1347 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 13, 0, 0, 2, TrapFrame
);
1352 Cr0
&= ~(CR0_MP
| CR0_EM
| CR0_TS
);
1355 /* Save FPU state */
1356 //Ke386SaveFpuState(SaveArea);
1358 /* Mark CR0 state dirty */
1359 Cr0
|= NPX_STATE_NOT_LOADED
;
1360 Cr0
|= SaveArea
->Cr0NpxState
;
1363 /* Update NPX state */
1364 Thread
->NpxState
= NPX_STATE_NOT_LOADED
;
1365 KeGetCurrentPrcb()->NpxThread
= NULL
;
1367 /* Clear the TS bit and re-enable interrupts */
1368 SaveArea
->Cr0NpxState
&= ~CR0_TS
;
1371 /* Now look at MxCsr to get the mask of errors we should care about */
1372 MxCsrMask
= ~((USHORT
)SaveArea
->U
.FxArea
.MXCsr
>> 7);
1374 /* Get legal exceptions that software should handle */
1375 Error
= (USHORT
)SaveArea
->U
.FxArea
.MXCsr
& (FSW_INVALID_OPERATION
|
1383 /* Now handle any of those legal errors */
1384 if (Error
& (FSW_INVALID_OPERATION
|
1391 /* By issuing an exception */
1392 KiDispatchException1Args(STATUS_FLOAT_MULTIPLE_TRAPS
,
1398 /* Unknown XMMI fault */
1399 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 13, 0, 0, 1, TrapFrame
);
1402 /* SOFTWARE SERVICES **********************************************************/
1406 KiGetTickCountHandler(IN PKTRAP_FRAME TrapFrame
)
1414 KiCallbackReturnHandler(IN PKTRAP_FRAME TrapFrame
)
1423 KiRaiseAssertionHandler(IN PKTRAP_FRAME TrapFrame
)
1425 /* Save trap frame */
1426 KiEnterTrap(TrapFrame
);
1428 /* Decrement EIP to point to the INT2C instruction (2 bytes, not 1 like INT3) */
1429 TrapFrame
->Eip
-= 2;
1431 /* Dispatch the exception */
1432 KiDispatchException0Args(STATUS_ASSERTION_FAILURE
,
1440 KiDebugServiceHandler(IN PKTRAP_FRAME TrapFrame
)
1442 /* Save trap frame */
1443 KiEnterTrap(TrapFrame
);
1445 /* Increment EIP to skip the INT3 instruction */
1448 /* Continue with the common handler */
1449 KiDebugHandler(TrapFrame
, TrapFrame
->Eax
, TrapFrame
->Ecx
, TrapFrame
->Edx
);
1455 KiSystemCall(IN PKTRAP_FRAME TrapFrame
,
1459 PKSERVICE_TABLE_DESCRIPTOR DescriptorTable
;
1460 ULONG Id
, Offset
, StackBytes
, Result
;
1462 ULONG SystemCallNumber
= TrapFrame
->Eax
;
1464 /* Get the current thread */
1465 Thread
= KeGetCurrentThread();
1467 /* Set debug header */
1468 KiFillTrapFrameDebug(TrapFrame
);
1470 /* Chain trap frames */
1471 TrapFrame
->Edx
= (ULONG_PTR
)Thread
->TrapFrame
;
1474 TrapFrame
->ErrCode
= 0;
1476 /* Save previous mode */
1477 TrapFrame
->PreviousPreviousMode
= Thread
->PreviousMode
;
1479 /* Save the SEH chain and terminate it for now */
1480 TrapFrame
->ExceptionList
= KeGetPcr()->NtTib
.ExceptionList
;
1481 KeGetPcr()->NtTib
.ExceptionList
= EXCEPTION_CHAIN_END
;
1483 /* Clear DR7 and check for debugging */
1485 if (__builtin_expect(Thread
->DispatcherHeader
.DebugActive
& 0xFF, 0))
1491 /* Set thread fields */
1492 Thread
->TrapFrame
= TrapFrame
;
1493 Thread
->PreviousMode
= KiUserTrap(TrapFrame
);
1495 /* Enable interrupts */
1498 /* Decode the system call number */
1499 Offset
= (SystemCallNumber
>> SERVICE_TABLE_SHIFT
) & SERVICE_TABLE_MASK
;
1500 Id
= SystemCallNumber
& SERVICE_NUMBER_MASK
;
1502 /* Get descriptor table */
1503 DescriptorTable
= (PVOID
)((ULONG_PTR
)Thread
->ServiceTable
+ Offset
);
1505 /* Validate the system call number */
1506 if (__builtin_expect(Id
>= DescriptorTable
->Limit
, 0))
1508 /* Check if this is a GUI call */
1509 if (!(Offset
& SERVICE_TABLE_TEST
))
1512 Result
= STATUS_INVALID_SYSTEM_SERVICE
;
1516 /* Convert us to a GUI thread -- must wrap in ASM to get new EBP */
1517 Result
= KiConvertToGuiThread();
1518 if (!NT_SUCCESS(Result
))
1520 /* Set the last error and fail */
1521 //SetLastWin32Error(RtlNtStatusToDosError(Result));
1525 /* Reload trap frame and descriptor table pointer from new stack */
1526 TrapFrame
= *(volatile PVOID
*)&Thread
->TrapFrame
;
1527 DescriptorTable
= (PVOID
)(*(volatile ULONG_PTR
*)&Thread
->ServiceTable
+ Offset
);
1529 /* Validate the system call number again */
1530 if (Id
>= DescriptorTable
->Limit
)
1533 Result
= STATUS_INVALID_SYSTEM_SERVICE
;
1538 /* Check if this is a GUI call */
1539 if (__builtin_expect(Offset
& SERVICE_TABLE_TEST
, 0))
1541 /* Get the batch count and flush if necessary */
1542 if (NtCurrentTeb()->GdiBatchCount
) KeGdiFlushUserBatch();
1545 /* Increase system call count */
1546 KeGetCurrentPrcb()->KeSystemCalls
++;
1548 /* FIXME: Increase individual counts on debug systems */
1549 //KiIncreaseSystemCallCount(DescriptorTable, Id);
1551 /* Get stack bytes */
1552 StackBytes
= DescriptorTable
->Number
[Id
];
1554 /* Probe caller stack */
1555 if (__builtin_expect((Arguments
< (PVOID
)MmUserProbeAddress
) && !(KiUserTrap(TrapFrame
)), 0))
1557 /* Access violation */
1562 /* Get the handler and make the system call */
1563 Handler
= (PVOID
)DescriptorTable
->Base
[Id
];
1564 Result
= KiSystemCallTrampoline(Handler
, Arguments
, StackBytes
);
1566 /* Make sure we're exiting correctly */
1567 KiExitSystemCallDebugChecks(Id
, TrapFrame
);
1569 /* Restore the old trap frame */
1571 Thread
->TrapFrame
= (PKTRAP_FRAME
)TrapFrame
->Edx
;
1573 /* Exit from system call */
1574 KiServiceExit(TrapFrame
, Result
);
1580 KiSystemServiceHandler(IN PKTRAP_FRAME TrapFrame
,
1583 /* Call the shared handler (inline) */
1584 KiSystemCall(TrapFrame
, Arguments
);
1590 KiFastCallEntryHandler(IN PKTRAP_FRAME TrapFrame
,
1593 /* Set up a fake INT Stack and enable interrupts */
1594 TrapFrame
->HardwareSegSs
= KGDT_R3_DATA
| RPL_MASK
;
1595 TrapFrame
->HardwareEsp
= (ULONG_PTR
)Arguments
;
1596 TrapFrame
->EFlags
= __readeflags() | EFLAGS_INTERRUPT_MASK
;
1597 TrapFrame
->SegCs
= KGDT_R3_CODE
| RPL_MASK
;
1598 TrapFrame
->Eip
= SharedUserData
->SystemCallReturn
;
1599 TrapFrame
->SegFs
= KGDT_R3_TEB
| RPL_MASK
;
1602 /* Arguments are actually 2 frames down (because of the double indirection) */
1603 Arguments
= (PVOID
)(TrapFrame
->HardwareEsp
+ 8);
1605 /* Call the shared handler (inline) */
1606 KiSystemCall(TrapFrame
, Arguments
);
1614 Kei386EoiHelper(VOID
)
1616 /* We should never see this call happening */
1617 DPRINT1("Mismatched NT/HAL version");