* Sync up to trunk HEAD (r62502).
[reactos.git] / ntoskrnl / ke / i386 / traphdlr.c
1 /*
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
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS ********************************************************************/
16
17 UCHAR KiTrapPrefixTable[] =
18 {
19 0xF2, /* REP */
20 0xF3, /* REP INS/OUTS */
21 0x67, /* ADDR */
22 0xF0, /* LOCK */
23 0x66, /* OP */
24 0x2E, /* SEG */
25 0x3E, /* DS */
26 0x26, /* ES */
27 0x64, /* FS */
28 0x65, /* GS */
29 0x36, /* SS */
30 };
31
32 UCHAR KiTrapIoTable[] =
33 {
34 0xE4, /* IN */
35 0xE5, /* IN */
36 0xEC, /* IN */
37 0xED, /* IN */
38 0x6C, /* INS */
39 0x6D, /* INS */
40 0xE6, /* OUT */
41 0xE7, /* OUT */
42 0xEE, /* OUT */
43 0xEF, /* OUT */
44 0x6E, /* OUTS */
45 0x6F, /* OUTS */
46 };
47
48 PFAST_SYSTEM_CALL_EXIT KiFastCallExitHandler;
49 #if DBG && !defined(_WINKD_)
50 PKDBG_PRESERVICEHOOK KeWin32PreServiceHook = NULL;
51 PKDBG_POSTSERVICEHOOK KeWin32PostServiceHook = NULL;
52 #endif
53 #if TRAP_DEBUG
54 BOOLEAN StopChecking = FALSE;
55 #endif
56
57
58 /* TRAP EXIT CODE *************************************************************/
59
60 FORCEINLINE
61 BOOLEAN
62 KiVdmTrap(IN PKTRAP_FRAME TrapFrame)
63 {
64 /* Either the V8086 flag is on, or this is user-mode with a VDM */
65 return ((TrapFrame->EFlags & EFLAGS_V86_MASK) ||
66 ((KiUserTrap(TrapFrame)) && (PsGetCurrentProcess()->VdmObjects)));
67 }
68
69 FORCEINLINE
70 BOOLEAN
71 KiV86Trap(IN PKTRAP_FRAME TrapFrame)
72 {
73 /* Check if the V8086 flag is on */
74 return ((TrapFrame->EFlags & EFLAGS_V86_MASK) != 0);
75 }
76
77 FORCEINLINE
78 BOOLEAN
79 KiIsFrameEdited(IN PKTRAP_FRAME TrapFrame)
80 {
81 /* An edited frame changes esp. It is marked by clearing the bits
82 defined by FRAME_EDITED in the SegCs field of the trap frame */
83 return ((TrapFrame->SegCs & FRAME_EDITED) == 0);
84 }
85
86 FORCEINLINE
87 VOID
88 KiCommonExit(IN PKTRAP_FRAME TrapFrame, BOOLEAN SkipPreviousMode)
89 {
90 /* Disable interrupts until we return */
91 _disable();
92
93 /* Check for APC delivery */
94 KiCheckForApcDelivery(TrapFrame);
95
96 /* Restore the SEH handler chain */
97 KeGetPcr()->NtTib.ExceptionList = TrapFrame->ExceptionList;
98
99 /* Check if there are active debug registers */
100 if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0))
101 {
102 /* Check if the frame was from user mode or v86 mode */
103 if (KiUserTrap(TrapFrame) ||
104 (TrapFrame->EFlags & EFLAGS_V86_MASK))
105 {
106 /* Handle debug registers */
107 KiHandleDebugRegistersOnTrapExit(TrapFrame);
108 }
109 }
110
111 /* Debugging checks */
112 KiExitTrapDebugChecks(TrapFrame, SkipPreviousMode);
113 }
114
115 DECLSPEC_NORETURN
116 VOID
117 FASTCALL
118 KiEoiHelper(IN PKTRAP_FRAME TrapFrame)
119 {
120 /* Common trap exit code */
121 KiCommonExit(TrapFrame, TRUE);
122
123 /* Check if this was a V8086 trap */
124 if (TrapFrame->EFlags & EFLAGS_V86_MASK) KiTrapReturnNoSegments(TrapFrame);
125
126 /* Check for user mode exit */
127 if (KiUserTrap(TrapFrame)) KiTrapReturn(TrapFrame);
128
129 /* Check for edited frame */
130 if (KiIsFrameEdited(TrapFrame)) KiEditedTrapReturn(TrapFrame);
131
132 /* Check if we have single stepping enabled */
133 if (TrapFrame->EFlags & EFLAGS_TF) KiTrapReturnNoSegments(TrapFrame);
134
135 /* Exit the trap to kernel mode */
136 KiTrapReturnNoSegmentsRet8(TrapFrame);
137 }
138
139 DECLSPEC_NORETURN
140 VOID
141 FASTCALL
142 KiServiceExit(IN PKTRAP_FRAME TrapFrame,
143 IN NTSTATUS Status)
144 {
145 ASSERT((TrapFrame->EFlags & EFLAGS_V86_MASK) == 0);
146 ASSERT(!KiIsFrameEdited(TrapFrame));
147
148 /* Copy the status into EAX */
149 TrapFrame->Eax = Status;
150
151 /* Common trap exit code */
152 KiCommonExit(TrapFrame, FALSE);
153
154 /* Restore previous mode */
155 KeGetCurrentThread()->PreviousMode = (CCHAR)TrapFrame->PreviousPreviousMode;
156
157 /* Check for user mode exit */
158 if (KiUserTrap(TrapFrame))
159 {
160 /* Check if we were single stepping */
161 if (TrapFrame->EFlags & EFLAGS_TF)
162 {
163 /* Must use the IRET handler */
164 KiSystemCallTrapReturn(TrapFrame);
165 }
166 else
167 {
168 /* We can use the sysexit handler */
169 KiFastCallExitHandler(TrapFrame);
170 }
171 }
172
173 /* Exit to kernel mode */
174 KiSystemCallReturn(TrapFrame);
175 }
176
177 DECLSPEC_NORETURN
178 VOID
179 FASTCALL
180 KiServiceExit2(IN PKTRAP_FRAME TrapFrame)
181 {
182 /* Common trap exit code */
183 KiCommonExit(TrapFrame, FALSE);
184
185 /* Restore previous mode */
186 KeGetCurrentThread()->PreviousMode = (CCHAR)TrapFrame->PreviousPreviousMode;
187
188 /* Check if this was a V8086 trap */
189 if (TrapFrame->EFlags & EFLAGS_V86_MASK) KiTrapReturnNoSegments(TrapFrame);
190
191 /* Check for user mode exit */
192 if (KiUserTrap(TrapFrame)) KiTrapReturn(TrapFrame);
193
194 /* Check for edited frame */
195 if (KiIsFrameEdited(TrapFrame)) KiEditedTrapReturn(TrapFrame);
196
197 /* Check if we have single stepping enabled */
198 if (TrapFrame->EFlags & EFLAGS_TF) KiTrapReturnNoSegments(TrapFrame);
199
200 /* Exit the trap to kernel mode */
201 KiTrapReturnNoSegmentsRet8(TrapFrame);
202 }
203
204
205 /* TRAP HANDLERS **************************************************************/
206
207 DECLSPEC_NORETURN
208 VOID
209 FASTCALL
210 KiDebugHandler(IN PKTRAP_FRAME TrapFrame,
211 IN ULONG Parameter1,
212 IN ULONG Parameter2,
213 IN ULONG Parameter3)
214 {
215 /* Check for VDM trap */
216 ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
217
218 /* Enable interrupts if the trap came from user-mode */
219 if (KiUserTrap(TrapFrame)) _enable();
220
221 /* Dispatch the exception */
222 KiDispatchExceptionFromTrapFrame(STATUS_BREAKPOINT,
223 TrapFrame->Eip - 1,
224 3,
225 Parameter1,
226 Parameter2,
227 Parameter3,
228 TrapFrame);
229 }
230
231 DECLSPEC_NORETURN
232 VOID
233 FASTCALL
234 KiNpxHandler(IN PKTRAP_FRAME TrapFrame,
235 IN PKTHREAD Thread,
236 IN PFX_SAVE_AREA SaveArea)
237 {
238 ULONG Cr0, Mask, Error, ErrorOffset, DataOffset;
239
240 /* Check for VDM trap */
241 ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
242
243 /* Check for kernel trap */
244 if (!KiUserTrap(TrapFrame))
245 {
246 /* Kernel might've tripped a delayed error */
247 SaveArea->Cr0NpxState |= CR0_TS;
248
249 /* Only valid if it happened during a restore */
250 //if ((PVOID)TrapFrame->Eip == FrRestore)
251 {
252 /* It did, so just skip the instruction */
253 //TrapFrame->Eip += 3; /* sizeof(FRSTOR) */
254 //KiEoiHelper(TrapFrame);
255 }
256 }
257
258 /* User or kernel trap -- get ready to issue an exception */
259 //if (Thread->NpxState == NPX_STATE_NOT_LOADED)
260 {
261 /* Update CR0 */
262 Cr0 = __readcr0();
263 Cr0 &= ~(CR0_MP | CR0_EM | CR0_TS);
264 __writecr0(Cr0);
265
266 /* Save FPU state */
267 Ke386SaveFpuState(SaveArea);
268
269 /* Mark CR0 state dirty */
270 Cr0 |= NPX_STATE_NOT_LOADED;
271 Cr0 |= SaveArea->Cr0NpxState;
272 __writecr0(Cr0);
273
274 /* Update NPX state */
275 Thread->NpxState = NPX_STATE_NOT_LOADED;
276 KeGetCurrentPrcb()->NpxThread = NULL;
277 }
278
279 /* Clear the TS bit and re-enable interrupts */
280 SaveArea->Cr0NpxState &= ~CR0_TS;
281 _enable();
282
283 /* Check if we should get the FN or FX error */
284 if (KeI386FxsrPresent)
285 {
286 /* Get it from FX */
287 Mask = SaveArea->U.FxArea.ControlWord;
288 Error = SaveArea->U.FxArea.StatusWord;
289
290 /* Get the FPU exception address too */
291 ErrorOffset = SaveArea->U.FxArea.ErrorOffset;
292 DataOffset = SaveArea->U.FxArea.DataOffset;
293 }
294 else
295 {
296 /* Get it from FN */
297 Mask = SaveArea->U.FnArea.ControlWord;
298 Error = SaveArea->U.FnArea.StatusWord;
299
300 /* Get the FPU exception address too */
301 ErrorOffset = SaveArea->U.FnArea.ErrorOffset;
302 DataOffset = SaveArea->U.FnArea.DataOffset;
303 }
304
305 /* Get legal exceptions that software should handle */
306 /* We do this by first masking off from the Mask the bits we need, */
307 /* This is done so we can keep the FSW_STACK_FAULT bit in Error. */
308 Mask &= (FSW_INVALID_OPERATION |
309 FSW_DENORMAL |
310 FSW_ZERO_DIVIDE |
311 FSW_OVERFLOW |
312 FSW_UNDERFLOW |
313 FSW_PRECISION);
314 Error &= ~Mask;
315
316 /* Check for invalid operation */
317 if (Error & FSW_INVALID_OPERATION)
318 {
319 /* NOTE: Stack fault is handled differently than any other case. */
320 /* 1. It's only raised for invalid operation. */
321 /* 2. It's only raised if invalid operation is not masked. */
322 if (Error & FSW_STACK_FAULT)
323 {
324 /* Issue stack check fault */
325 KiDispatchException2Args(STATUS_FLOAT_STACK_CHECK,
326 ErrorOffset,
327 0,
328 DataOffset,
329 TrapFrame);
330 }
331
332 /* Issue fault */
333 KiDispatchException1Args(STATUS_FLOAT_INVALID_OPERATION,
334 ErrorOffset,
335 0,
336 TrapFrame);
337 }
338
339 /* Check for divide by zero */
340 if (Error & FSW_ZERO_DIVIDE)
341 {
342 /* Issue fault */
343 KiDispatchException1Args(STATUS_FLOAT_DIVIDE_BY_ZERO,
344 ErrorOffset,
345 0,
346 TrapFrame);
347 }
348
349 /* Check for denormal */
350 if (Error & FSW_DENORMAL)
351 {
352 /* Issue fault */
353 KiDispatchException1Args(STATUS_FLOAT_INVALID_OPERATION,
354 ErrorOffset,
355 0,
356 TrapFrame);
357 }
358
359 /* Check for overflow */
360 if (Error & FSW_OVERFLOW)
361 {
362 /* Issue fault */
363 KiDispatchException1Args(STATUS_FLOAT_OVERFLOW,
364 ErrorOffset,
365 0,
366 TrapFrame);
367 }
368
369 /* Check for underflow */
370 if (Error & FSW_UNDERFLOW)
371 {
372 /* Issue fault */
373 KiDispatchException1Args(STATUS_FLOAT_UNDERFLOW,
374 ErrorOffset,
375 0,
376 TrapFrame);
377 }
378
379 /* Check for precision fault */
380 if (Error & FSW_PRECISION)
381 {
382 /* Issue fault */
383 KiDispatchException1Args(STATUS_FLOAT_INEXACT_RESULT,
384 ErrorOffset,
385 0,
386 TrapFrame);
387 }
388
389 /* Unknown FPU fault */
390 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 1, Error, 0, 0, TrapFrame);
391 }
392
393 DECLSPEC_NORETURN
394 VOID
395 FASTCALL
396 KiTrap00Handler(IN PKTRAP_FRAME TrapFrame)
397 {
398 /* Save trap frame */
399 KiEnterTrap(TrapFrame);
400
401 /* Check for VDM trap */
402 ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
403
404 /* Enable interrupts */
405 _enable();
406
407 /* Dispatch the exception */
408 KiDispatchException0Args(STATUS_INTEGER_DIVIDE_BY_ZERO,
409 TrapFrame->Eip,
410 TrapFrame);
411 }
412
413 DECLSPEC_NORETURN
414 VOID
415 FASTCALL
416 KiTrap01Handler(IN PKTRAP_FRAME TrapFrame)
417 {
418 /* Save trap frame */
419 KiEnterTrap(TrapFrame);
420
421 /* Check for VDM trap */
422 ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
423
424 /* Enable interrupts if the trap came from user-mode */
425 if (KiUserTrap(TrapFrame)) _enable();
426
427 /* Mask out trap flag and dispatch the exception */
428 TrapFrame->EFlags &= ~EFLAGS_TF;
429 KiDispatchException0Args(STATUS_SINGLE_STEP,
430 TrapFrame->Eip,
431 TrapFrame);
432 }
433
434 DECLSPEC_NORETURN
435 VOID
436 __cdecl
437 KiTrap02(VOID)
438 {
439 PKTSS Tss, NmiTss;
440 PKTHREAD Thread;
441 PKPROCESS Process;
442 PKGDTENTRY TssGdt;
443 KTRAP_FRAME TrapFrame;
444 KIRQL OldIrql;
445
446 //
447 // In some sort of strange recursion case, we might end up here with the IF
448 // flag incorrectly on the interrupt frame -- during a normal NMI this would
449 // normally already be set.
450 //
451 // For sanity's sake, make sure interrupts are disabled for sure.
452 // NMIs will already be since the CPU does it for us.
453 //
454 _disable();
455
456 //
457 // Get the current TSS, thread, and process
458 //
459 Tss = PCR->TSS;
460 Thread = ((PKIPCR)PCR)->PrcbData.CurrentThread;
461 Process = Thread->ApcState.Process;
462
463 //
464 // Save data usually not in the TSS
465 //
466 Tss->CR3 = Process->DirectoryTableBase[0];
467 Tss->IoMapBase = Process->IopmOffset;
468 Tss->LDT = Process->LdtDescriptor.LimitLow ? KGDT_LDT : 0;
469
470 //
471 // Now get the base address of the NMI TSS
472 //
473 TssGdt = &((PKIPCR)KeGetPcr())->GDT[KGDT_NMI_TSS / sizeof(KGDTENTRY)];
474 NmiTss = (PKTSS)(ULONG_PTR)(TssGdt->BaseLow |
475 TssGdt->HighWord.Bytes.BaseMid << 16 |
476 TssGdt->HighWord.Bytes.BaseHi << 24);
477
478 //
479 // Switch to it and activate it, masking off the nested flag
480 //
481 // Note that in reality, we are already on the NMI tss -- we just need to
482 // update the PCR to reflect this
483 //
484 PCR->TSS = NmiTss;
485 __writeeflags(__readeflags() &~ EFLAGS_NESTED_TASK);
486 TssGdt->HighWord.Bits.Dpl = 0;
487 TssGdt->HighWord.Bits.Pres = 1;
488 TssGdt->HighWord.Bits.Type = I386_TSS;
489
490 //
491 // Now build the trap frame based on the original TSS
492 //
493 // The CPU does a hardware "Context switch" / task switch of sorts and so it
494 // takes care of saving our context in the normal TSS.
495 //
496 // We just have to go get the values...
497 //
498 RtlZeroMemory(&TrapFrame, sizeof(KTRAP_FRAME));
499 TrapFrame.HardwareSegSs = Tss->Ss0;
500 TrapFrame.HardwareEsp = Tss->Esp0;
501 TrapFrame.EFlags = Tss->EFlags;
502 TrapFrame.SegCs = Tss->Cs;
503 TrapFrame.Eip = Tss->Eip;
504 TrapFrame.Ebp = Tss->Ebp;
505 TrapFrame.Ebx = Tss->Ebx;
506 TrapFrame.Esi = Tss->Esi;
507 TrapFrame.Edi = Tss->Edi;
508 TrapFrame.SegFs = Tss->Fs;
509 TrapFrame.ExceptionList = PCR->NtTib.ExceptionList;
510 TrapFrame.PreviousPreviousMode = -1;
511 TrapFrame.Eax = Tss->Eax;
512 TrapFrame.Ecx = Tss->Ecx;
513 TrapFrame.Edx = Tss->Edx;
514 TrapFrame.SegDs = Tss->Ds;
515 TrapFrame.SegEs = Tss->Es;
516 TrapFrame.SegGs = Tss->Gs;
517 TrapFrame.DbgEip = Tss->Eip;
518 TrapFrame.DbgEbp = Tss->Ebp;
519
520 //
521 // Store the trap frame in the KPRCB
522 //
523 KiSaveProcessorState(&TrapFrame, NULL);
524
525 //
526 // Call any registered NMI handlers and see if they handled it or not
527 //
528 if (!KiHandleNmi())
529 {
530 //
531 // They did not, so call the platform HAL routine to bugcheck the system
532 //
533 // Make sure the HAL believes it's running at HIGH IRQL... we can't use
534 // the normal APIs here as playing with the IRQL could change the system
535 // state
536 //
537 OldIrql = PCR->Irql;
538 PCR->Irql = HIGH_LEVEL;
539 HalHandleNMI(NULL);
540 PCR->Irql = OldIrql;
541 }
542
543 //
544 // Although the CPU disabled NMIs, we just did a BIOS Call, which could've
545 // totally changed things.
546 //
547 // We have to make sure we're still in our original NMI -- a nested NMI
548 // will point back to the NMI TSS, and in that case we're hosed.
549 //
550 if (PCR->TSS->Backlink != KGDT_NMI_TSS)
551 {
552 //
553 // Restore original TSS
554 //
555 PCR->TSS = Tss;
556
557 //
558 // Set it back to busy
559 //
560 TssGdt->HighWord.Bits.Dpl = 0;
561 TssGdt->HighWord.Bits.Pres = 1;
562 TssGdt->HighWord.Bits.Type = I386_ACTIVE_TSS;
563
564 //
565 // Restore nested flag
566 //
567 __writeeflags(__readeflags() | EFLAGS_NESTED_TASK);
568
569 //
570 // Handled, return from interrupt
571 //
572 KiIret();
573 }
574
575 //
576 // Unhandled: crash the system
577 //
578 KiSystemFatalException(EXCEPTION_NMI, NULL);
579 }
580
581 DECLSPEC_NORETURN
582 VOID
583 FASTCALL
584 KiTrap03Handler(IN PKTRAP_FRAME TrapFrame)
585 {
586 /* Save trap frame */
587 KiEnterTrap(TrapFrame);
588
589 /* Continue with the common handler */
590 KiDebugHandler(TrapFrame, BREAKPOINT_BREAK, 0, 0);
591 }
592
593 DECLSPEC_NORETURN
594 VOID
595 FASTCALL
596 KiTrap04Handler(IN PKTRAP_FRAME TrapFrame)
597 {
598 /* Save trap frame */
599 KiEnterTrap(TrapFrame);
600
601 /* Check for VDM trap */
602 ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
603
604 /* Enable interrupts */
605 _enable();
606
607 /* Dispatch the exception */
608 KiDispatchException0Args(STATUS_INTEGER_OVERFLOW,
609 TrapFrame->Eip - 1,
610 TrapFrame);
611 }
612
613 DECLSPEC_NORETURN
614 VOID
615 FASTCALL
616 KiTrap05Handler(IN PKTRAP_FRAME TrapFrame)
617 {
618 /* Save trap frame */
619 KiEnterTrap(TrapFrame);
620
621 /* Check for VDM trap */
622 ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
623
624 /* Check for kernel-mode fault */
625 if (!KiUserTrap(TrapFrame)) KiSystemFatalException(EXCEPTION_BOUND_CHECK, TrapFrame);
626
627 /* Enable interrupts */
628 _enable();
629
630 /* Dispatch the exception */
631 KiDispatchException0Args(STATUS_ARRAY_BOUNDS_EXCEEDED,
632 TrapFrame->Eip,
633 TrapFrame);
634 }
635
636 DECLSPEC_NORETURN
637 VOID
638 FASTCALL
639 KiTrap06Handler(IN PKTRAP_FRAME TrapFrame)
640 {
641 PUCHAR Instruction;
642 ULONG i;
643 KIRQL OldIrql;
644
645 /* Check for V86 GPF */
646 if (__builtin_expect(KiV86Trap(TrapFrame), 1))
647 {
648 /* Enter V86 trap */
649 KiEnterV86Trap(TrapFrame);
650
651 /* Must be a VDM process */
652 if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects, 0))
653 {
654 /* Enable interrupts */
655 _enable();
656
657 /* Setup illegal instruction fault */
658 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION,
659 TrapFrame->Eip,
660 TrapFrame);
661 }
662
663 /* Go to APC level */
664 OldIrql = KfRaiseIrql(APC_LEVEL);
665 _enable();
666
667 /* Check for BOP */
668 if (!VdmDispatchBop(TrapFrame))
669 {
670 /* Should only happen in VDM mode */
671 UNIMPLEMENTED_FATAL();
672 }
673
674 /* Bring IRQL back */
675 KfLowerIrql(OldIrql);
676 _disable();
677
678 /* Do a quick V86 exit if possible */
679 KiExitV86Trap(TrapFrame);
680 }
681
682 /* Save trap frame */
683 KiEnterTrap(TrapFrame);
684
685 /* Enable interrupts */
686 Instruction = (PUCHAR)TrapFrame->Eip;
687 _enable();
688
689 /* Check for user trap */
690 if (KiUserTrap(TrapFrame))
691 {
692 /* FIXME: Use SEH */
693
694 /* Scan next 4 opcodes */
695 for (i = 0; i < 4; i++)
696 {
697 /* Check for LOCK instruction */
698 if (Instruction[i] == 0xF0)
699 {
700 /* Send invalid lock sequence exception */
701 KiDispatchException0Args(STATUS_INVALID_LOCK_SEQUENCE,
702 TrapFrame->Eip,
703 TrapFrame);
704 }
705 }
706
707 /* FIXME: SEH ends here */
708 }
709
710 /* Kernel-mode or user-mode fault (but not LOCK) */
711 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION,
712 TrapFrame->Eip,
713 TrapFrame);
714
715 }
716
717 DECLSPEC_NORETURN
718 VOID
719 FASTCALL
720 KiTrap07Handler(IN PKTRAP_FRAME TrapFrame)
721 {
722 PKTHREAD Thread, NpxThread;
723 PFX_SAVE_AREA SaveArea, NpxSaveArea;
724 ULONG Cr0;
725
726 /* Save trap frame */
727 KiEnterTrap(TrapFrame);
728
729 /* Try to handle NPX delay load */
730 while (TRUE)
731 {
732 /* Get the current thread */
733 Thread = KeGetCurrentThread();
734
735 /* Get the NPX frame */
736 SaveArea = KiGetThreadNpxArea(Thread);
737
738 /* Check if emulation is enabled */
739 if (SaveArea->Cr0NpxState & CR0_EM)
740 {
741 /* Not implemented */
742 UNIMPLEMENTED_FATAL();
743 }
744
745 /* Save CR0 and check NPX state */
746 Cr0 = __readcr0();
747 if (Thread->NpxState != NPX_STATE_LOADED)
748 {
749 /* Update CR0 */
750 Cr0 &= ~(CR0_MP | CR0_EM | CR0_TS);
751 __writecr0(Cr0);
752
753 /* Get the NPX thread */
754 NpxThread = KeGetCurrentPrcb()->NpxThread;
755 if (NpxThread)
756 {
757 /* Get the NPX frame */
758 NpxSaveArea = KiGetThreadNpxArea(NpxThread);
759
760 /* Save FPU state */
761 DPRINT("FIXME: Save FPU state: %p\n", NpxSaveArea);
762 //Ke386SaveFpuState(NpxSaveArea);
763
764 /* Update NPX state */
765 NpxThread->NpxState = NPX_STATE_NOT_LOADED;
766 }
767
768 /* Load FPU state */
769 //Ke386LoadFpuState(SaveArea);
770
771 /* Update NPX state */
772 Thread->NpxState = NPX_STATE_LOADED;
773 KeGetCurrentPrcb()->NpxThread = Thread;
774
775 /* Enable interrupts */
776 _enable();
777
778 /* Check if CR0 needs to be reloaded due to context switch */
779 if (!SaveArea->Cr0NpxState) KiEoiHelper(TrapFrame);
780
781 /* Otherwise, we need to reload CR0, disable interrupts */
782 _disable();
783
784 /* Reload CR0 */
785 Cr0 = __readcr0();
786 Cr0 |= SaveArea->Cr0NpxState;
787 __writecr0(Cr0);
788
789 /* Now restore interrupts and check for TS */
790 _enable();
791 if (Cr0 & CR0_TS) KiEoiHelper(TrapFrame);
792
793 /* We're still here -- clear TS and try again */
794 __writecr0(__readcr0() &~ CR0_TS);
795 _disable();
796 }
797 else
798 {
799 /* This is an actual fault, not a lack of FPU state */
800 break;
801 }
802 }
803
804 /* TS should not be set */
805 if (Cr0 & CR0_TS)
806 {
807 /*
808 * If it's incorrectly set, then maybe the state is actually still valid
809 * but we could've lock track of that due to a BIOS call.
810 * Make sure MP is still set, which should verify the theory.
811 */
812 if (Cr0 & CR0_MP)
813 {
814 /* Indeed, the state is actually still valid, so clear TS */
815 __writecr0(__readcr0() &~ CR0_TS);
816 KiEoiHelper(TrapFrame);
817 }
818
819 /* Otherwise, something strange is going on */
820 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 2, Cr0, 0, 0, TrapFrame);
821 }
822
823 /* It's not a delayed load, so process this trap as an NPX fault */
824 KiNpxHandler(TrapFrame, Thread, SaveArea);
825 }
826
827 DECLSPEC_NORETURN
828 VOID
829 FASTCALL
830 KiTrap08Handler(IN PKTRAP_FRAME TrapFrame)
831 {
832 /* FIXME: Not handled */
833 KiSystemFatalException(EXCEPTION_DOUBLE_FAULT, TrapFrame);
834 }
835
836 DECLSPEC_NORETURN
837 VOID
838 FASTCALL
839 KiTrap09Handler(IN PKTRAP_FRAME TrapFrame)
840 {
841 /* Save trap frame */
842 KiEnterTrap(TrapFrame);
843
844 /* Enable interrupts and kill the system */
845 _enable();
846 KiSystemFatalException(EXCEPTION_NPX_OVERRUN, TrapFrame);
847 }
848
849 DECLSPEC_NORETURN
850 VOID
851 FASTCALL
852 KiTrap0AHandler(IN PKTRAP_FRAME TrapFrame)
853 {
854 /* Save trap frame */
855 KiEnterTrap(TrapFrame);
856
857 /* Check for VDM trap */
858 ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
859
860 /* Kill the system */
861 KiSystemFatalException(EXCEPTION_INVALID_TSS, TrapFrame);
862 }
863
864 DECLSPEC_NORETURN
865 VOID
866 FASTCALL
867 KiTrap0BHandler(IN PKTRAP_FRAME TrapFrame)
868 {
869 /* Save trap frame */
870 KiEnterTrap(TrapFrame);
871
872 /* FIXME: Kill the system */
873 UNIMPLEMENTED;
874 KiSystemFatalException(EXCEPTION_SEGMENT_NOT_PRESENT, TrapFrame);
875 }
876
877 DECLSPEC_NORETURN
878 VOID
879 FASTCALL
880 KiTrap0CHandler(IN PKTRAP_FRAME TrapFrame)
881 {
882 /* Save trap frame */
883 KiEnterTrap(TrapFrame);
884
885 /* FIXME: Kill the system */
886 UNIMPLEMENTED;
887 KiSystemFatalException(EXCEPTION_STACK_FAULT, TrapFrame);
888 }
889
890 DECLSPEC_NORETURN
891 VOID
892 FASTCALL
893 KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame)
894 {
895 ULONG i, j, Iopl;
896 BOOLEAN Privileged = FALSE;
897 PUCHAR Instructions;
898 UCHAR Instruction = 0;
899 KIRQL OldIrql;
900
901 /* Check for V86 GPF */
902 if (__builtin_expect(KiV86Trap(TrapFrame), 1))
903 {
904 /* Enter V86 trap */
905 KiEnterV86Trap(TrapFrame);
906
907 /* Must be a VDM process */
908 if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects, 0))
909 {
910 /* Enable interrupts */
911 _enable();
912
913 /* Setup illegal instruction fault */
914 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION,
915 TrapFrame->Eip,
916 TrapFrame);
917 }
918
919 /* Go to APC level */
920 OldIrql = KfRaiseIrql(APC_LEVEL);
921 _enable();
922
923 /* Handle the V86 opcode */
924 if (__builtin_expect(Ki386HandleOpcodeV86(TrapFrame) == 0xFF, 0))
925 {
926 /* Should only happen in VDM mode */
927 UNIMPLEMENTED_FATAL();
928 }
929
930 /* Bring IRQL back */
931 KfLowerIrql(OldIrql);
932 _disable();
933
934 /* Do a quick V86 exit if possible */
935 KiExitV86Trap(TrapFrame);
936 }
937
938 /* Save trap frame */
939 KiEnterTrap(TrapFrame);
940
941 /* Check for user-mode GPF */
942 if (KiUserTrap(TrapFrame))
943 {
944 /* Should not be VDM */
945 ASSERT(KiVdmTrap(TrapFrame) == FALSE);
946
947 /* Enable interrupts and check error code */
948 _enable();
949 if (!TrapFrame->ErrCode)
950 {
951 /* FIXME: Use SEH */
952 Instructions = (PUCHAR)TrapFrame->Eip;
953
954 /* Scan next 15 bytes */
955 for (i = 0; i < 15; i++)
956 {
957 /* Skip prefix instructions */
958 for (j = 0; j < sizeof(KiTrapPrefixTable); j++)
959 {
960 /* Is this a prefix instruction? */
961 if (Instructions[i] == KiTrapPrefixTable[j])
962 {
963 /* Stop looking */
964 break;
965 }
966 }
967
968 /* Is this NOT any prefix instruction? */
969 if (j == sizeof(KiTrapPrefixTable))
970 {
971 /* We can go ahead and handle the fault now */
972 Instruction = Instructions[i];
973 break;
974 }
975 }
976
977 /* If all we found was prefixes, then this instruction is too long */
978 if (i == 15)
979 {
980 /* Setup illegal instruction fault */
981 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION,
982 TrapFrame->Eip,
983 TrapFrame);
984 }
985
986 /* Check for privileged instructions */
987 DPRINT("Instruction (%lu) at fault: %lx %lx %lx %lx\n",
988 i,
989 Instructions[i],
990 Instructions[i + 1],
991 Instructions[i + 2],
992 Instructions[i + 3]);
993 if (Instruction == 0xF4) // HLT
994 {
995 /* HLT is privileged */
996 Privileged = TRUE;
997 }
998 else if (Instruction == 0x0F)
999 {
1000 /* Test if it's any of the privileged two-byte opcodes */
1001 if (((Instructions[i + 1] == 0x00) && // LLDT or LTR
1002 (((Instructions[i + 2] & 0x38) == 0x10) || // LLDT
1003 (Instructions[i + 2] == 0x18))) || // LTR
1004 ((Instructions[i + 1] == 0x01) && // LGDT or LIDT or LMSW
1005 (((Instructions[i + 2] & 0x38) == 0x10) || // LGDT
1006 (Instructions[i + 2] == 0x18) || // LIDT
1007 (Instructions[i + 2] == 0x30))) || // LMSW
1008 (Instructions[i + 1] == 0x08) || // INVD
1009 (Instructions[i + 1] == 0x09) || // WBINVD
1010 (Instructions[i + 1] == 0x35) || // SYSEXIT
1011 (Instructions[i + 1] == 0x21) || // MOV DR, XXX
1012 (Instructions[i + 1] == 0x06) || // CLTS
1013 (Instructions[i + 1] == 0x20) || // MOV CR, XXX
1014 (Instructions[i + 1] == 0x22) || // MOV XXX, CR
1015 (Instructions[i + 1] == 0x23) || // MOV YYY, DR
1016 (Instructions[i + 1] == 0x30) || // WRMSR
1017 (Instructions[i + 1] == 0x33)) // RDPMC
1018 // INVLPG, INVLPGA, SYSRET
1019 {
1020 /* These are all privileged */
1021 Privileged = TRUE;
1022 }
1023 }
1024 else
1025 {
1026 /* Get the IOPL and compare with the RPL mask */
1027 Iopl = (TrapFrame->EFlags & EFLAGS_IOPL) >> 12;
1028 if ((TrapFrame->SegCs & RPL_MASK) > Iopl)
1029 {
1030 /* I/O privilege error -- check for known instructions */
1031 if ((Instruction == 0xFA) || (Instruction == 0xFB)) // CLI or STI
1032 {
1033 /* These are privileged */
1034 Privileged = TRUE;
1035 }
1036 else
1037 {
1038 /* Last hope: an IN/OUT instruction */
1039 for (j = 0; j < sizeof(KiTrapIoTable); j++)
1040 {
1041 /* Is this an I/O instruction? */
1042 if (Instruction == KiTrapIoTable[j])
1043 {
1044 /* Then it's privileged */
1045 Privileged = TRUE;
1046 break;
1047 }
1048 }
1049 }
1050 }
1051 }
1052
1053 /* So now... was the instruction privileged or not? */
1054 if (Privileged)
1055 {
1056 /* Whew! We have a privileged instruction, so dispatch the fault */
1057 KiDispatchException0Args(STATUS_PRIVILEGED_INSTRUCTION,
1058 TrapFrame->Eip,
1059 TrapFrame);
1060 }
1061 }
1062
1063 /* If we got here, send an access violation */
1064 KiDispatchException2Args(STATUS_ACCESS_VIOLATION,
1065 TrapFrame->Eip,
1066 0,
1067 0xFFFFFFFF,
1068 TrapFrame);
1069 }
1070
1071 /*
1072 * Check for a fault during checking of the user instruction.
1073 *
1074 * Note that the SEH handler will catch invalid EIP, but we could be dealing
1075 * with an invalid CS, which will generate another GPF instead.
1076 *
1077 */
1078 if (((PVOID)TrapFrame->Eip >= (PVOID)KiTrap0DHandler) &&
1079 ((PVOID)TrapFrame->Eip < (PVOID)KiTrap0DHandler))
1080 {
1081 /* Not implemented */
1082 UNIMPLEMENTED_FATAL();
1083 }
1084
1085 /*
1086 * NOTE: The ASM trap exit code would restore segment registers by doing
1087 * a POP <SEG>, which could cause an invalid segment if someone had messed
1088 * with the segment values.
1089 *
1090 * Another case is a bogus SS, which would hit a GPF when doing the iret.
1091 * This could only be done through a buggy or malicious driver, or perhaps
1092 * the kernel debugger.
1093 *
1094 * The kernel normally restores the "true" segment if this happens.
1095 *
1096 * However, since we're restoring in C, not ASM, we can't detect
1097 * POP <SEG> since the actual instructions will be different.
1098 *
1099 * A better technique would be to check the EIP and somehow edit the
1100 * trap frame before restarting the instruction -- but we would need to
1101 * know the extract instruction that was used first.
1102 *
1103 * We could force a special instrinsic to use stack instructions, or write
1104 * a simple instruction length checker.
1105 *
1106 * Nevertheless, this is a lot of work for the purpose of avoiding a crash
1107 * when the user is purposedly trying to create one from kernel-mode, so
1108 * we should probably table this for now since it's not a "real" issue.
1109 */
1110
1111 /*
1112 * NOTE2: Another scenario is the IRET during a V8086 restore (BIOS Call)
1113 * which will cause a GPF since the trap frame is a total mess (on purpose)
1114 * as built in KiEnterV86Mode.
1115 *
1116 * The idea is to scan for IRET, scan for the known EIP adress, validate CS
1117 * and then manually issue a jump to the V8086 return EIP.
1118 */
1119 Instructions = (PUCHAR)TrapFrame->Eip;
1120 if (Instructions[0] == 0xCF)
1121 {
1122 /*
1123 * Some evil shit is going on here -- this is not the SS:ESP you're
1124 * looking for! Instead, this is actually CS:EIP you're looking at!
1125 * Why? Because part of the trap frame actually corresponds to the IRET
1126 * stack during the trap exit!
1127 */
1128 if ((TrapFrame->HardwareEsp == (ULONG)Ki386BiosCallReturnAddress) &&
1129 (TrapFrame->HardwareSegSs == (KGDT_R0_CODE | RPL_MASK)))
1130 {
1131 /* Exit the V86 trap! */
1132 Ki386BiosCallReturnAddress(TrapFrame);
1133 }
1134 else
1135 {
1136 /* Otherwise, this is another kind of IRET fault */
1137 UNIMPLEMENTED_FATAL();
1138 }
1139 }
1140
1141 /* So since we're not dealing with the above case, check for RDMSR/WRMSR */
1142 if ((Instructions[0] == 0xF) && // 2-byte opcode
1143 ((Instructions[1] == 0x32) || // RDMSR
1144 (Instructions[1] == 0x30))) // WRMSR
1145 {
1146 /* Unknown CPU MSR, so raise an access violation */
1147 KiDispatchException0Args(STATUS_ACCESS_VIOLATION,
1148 TrapFrame->Eip,
1149 TrapFrame);
1150 }
1151
1152 /* Check for lazy segment load */
1153 if (TrapFrame->SegDs != (KGDT_R3_DATA | RPL_MASK))
1154 {
1155 /* Fix it */
1156 TrapFrame->SegDs = (KGDT_R3_DATA | RPL_MASK);
1157 }
1158 else if (TrapFrame->SegEs != (KGDT_R3_DATA | RPL_MASK))
1159 {
1160 /* Fix it */
1161 TrapFrame->SegEs = (KGDT_R3_DATA | RPL_MASK);
1162 }
1163 else
1164 {
1165 /* Whatever it is, we can't handle it */
1166 KiSystemFatalException(EXCEPTION_GP_FAULT, TrapFrame);
1167 }
1168
1169 /* Return to where we came from */
1170 KiTrapReturn(TrapFrame);
1171 }
1172
1173 DECLSPEC_NORETURN
1174 VOID
1175 FASTCALL
1176 KiTrap0EHandler(IN PKTRAP_FRAME TrapFrame)
1177 {
1178 PKTHREAD Thread;
1179 ULONG_PTR Cr2;
1180 NTSTATUS Status;
1181
1182 /* Save trap frame */
1183 KiEnterTrap(TrapFrame);
1184
1185 /* Check if this is the base frame */
1186 Thread = KeGetCurrentThread();
1187 if (KeGetTrapFrame(Thread) != TrapFrame)
1188 {
1189 /* It isn't, check if this is a second nested frame */
1190 if (((ULONG_PTR)KeGetTrapFrame(Thread) - (ULONG_PTR)TrapFrame) <=
1191 FIELD_OFFSET(KTRAP_FRAME, EFlags))
1192 {
1193 /* The stack is somewhere in between frames, we need to fix it */
1194 UNIMPLEMENTED_FATAL();
1195 }
1196 }
1197
1198 /* Save CR2 */
1199 Cr2 = __readcr2();
1200
1201 /* Enable interupts */
1202 _enable();
1203
1204 /* Check if we came in with interrupts disabled */
1205 if (!(TrapFrame->EFlags & EFLAGS_INTERRUPT_MASK))
1206 {
1207 /* This is completely illegal, bugcheck the system */
1208 KeBugCheckWithTf(IRQL_NOT_LESS_OR_EQUAL,
1209 Cr2,
1210 -1,
1211 TrapFrame->ErrCode & 2 ? TRUE : FALSE,
1212 TrapFrame->Eip,
1213 TrapFrame);
1214 }
1215
1216 /* Check for S-LIST fault in kernel mode */
1217 if (TrapFrame->Eip == (ULONG_PTR)ExpInterlockedPopEntrySListFault)
1218 {
1219 PSLIST_HEADER SListHeader;
1220
1221 /* Sanity check that the assembly is correct:
1222 This must be mov ebx, [eax]
1223 Followed by cmpxchg8b [ebp] */
1224 ASSERT((((UCHAR*)TrapFrame->Eip)[0] == 0x8B) &&
1225 (((UCHAR*)TrapFrame->Eip)[1] == 0x18) &&
1226 (((UCHAR*)TrapFrame->Eip)[2] == 0x0F) &&
1227 (((UCHAR*)TrapFrame->Eip)[3] == 0xC7) &&
1228 (((UCHAR*)TrapFrame->Eip)[4] == 0x4D) &&
1229 (((UCHAR*)TrapFrame->Eip)[5] == 0x00));
1230
1231 /* Get the pointer to the SLIST_HEADER */
1232 SListHeader = (PSLIST_HEADER)TrapFrame->Ebp;
1233
1234 /* Check if the Next member of the SLIST_HEADER was changed */
1235 if (SListHeader->Next.Next != (PSLIST_ENTRY)TrapFrame->Eax)
1236 {
1237 /* Restart the operation */
1238 TrapFrame->Eip = (ULONG_PTR)ExpInterlockedPopEntrySListResume;
1239
1240 /* Continue execution */
1241 KiEoiHelper(TrapFrame);
1242 }
1243 else
1244 {
1245 #if 0
1246 /* Do what windows does and issue an invalid access violation */
1247 KiDispatchException2Args(KI_EXCEPTION_ACCESS_VIOLATION,
1248 TrapFrame->Eip,
1249 TrapFrame->ErrCode & 2 ? TRUE : FALSE,
1250 Cr2,
1251 TrapFrame);
1252 #endif
1253 }
1254 }
1255
1256 /* Call the access fault handler */
1257 Status = MmAccessFault(TrapFrame->ErrCode & 1,
1258 (PVOID)Cr2,
1259 KiUserTrap(TrapFrame),
1260 TrapFrame);
1261 if (NT_SUCCESS(Status)) KiEoiHelper(TrapFrame);
1262
1263 /* Check for syscall fault */
1264 #if 0
1265 if ((TrapFrame->Eip == (ULONG_PTR)CopyParams) ||
1266 (TrapFrame->Eip == (ULONG_PTR)ReadBatch))
1267 {
1268 /* Not yet implemented */
1269 UNIMPLEMENTED_FATAL();
1270 }
1271 #endif
1272 /* Check for VDM trap */
1273 ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
1274
1275 /* Either kernel or user trap (non VDM) so dispatch exception */
1276 if (Status == STATUS_ACCESS_VIOLATION)
1277 {
1278 /* This status code is repurposed so we can recognize it later */
1279 KiDispatchException2Args(KI_EXCEPTION_ACCESS_VIOLATION,
1280 TrapFrame->Eip,
1281 TrapFrame->ErrCode & 2 ? TRUE : FALSE,
1282 Cr2,
1283 TrapFrame);
1284 }
1285 else if ((Status == STATUS_GUARD_PAGE_VIOLATION) ||
1286 (Status == STATUS_STACK_OVERFLOW))
1287 {
1288 /* These faults only have two parameters */
1289 KiDispatchException2Args(Status,
1290 TrapFrame->Eip,
1291 TrapFrame->ErrCode & 2 ? TRUE : FALSE,
1292 Cr2,
1293 TrapFrame);
1294 }
1295
1296 /* Only other choice is an in-page error, with 3 parameters */
1297 KiDispatchExceptionFromTrapFrame(STATUS_IN_PAGE_ERROR,
1298 TrapFrame->Eip,
1299 3,
1300 TrapFrame->ErrCode & 2 ? TRUE : FALSE,
1301 Cr2,
1302 Status,
1303 TrapFrame);
1304 }
1305
1306 DECLSPEC_NORETURN
1307 VOID
1308 FASTCALL
1309 KiTrap0FHandler(IN PKTRAP_FRAME TrapFrame)
1310 {
1311 /* Save trap frame */
1312 KiEnterTrap(TrapFrame);
1313
1314 /* FIXME: Kill the system */
1315 UNIMPLEMENTED;
1316 KiSystemFatalException(EXCEPTION_RESERVED_TRAP, TrapFrame);
1317 }
1318
1319 DECLSPEC_NORETURN
1320 VOID
1321 FASTCALL
1322 KiTrap10Handler(IN PKTRAP_FRAME TrapFrame)
1323 {
1324 PKTHREAD Thread;
1325 PFX_SAVE_AREA SaveArea;
1326
1327 /* Save trap frame */
1328 KiEnterTrap(TrapFrame);
1329
1330 /* Check if this is the NPX thrad */
1331 Thread = KeGetCurrentThread();
1332 SaveArea = KiGetThreadNpxArea(Thread);
1333 if (Thread != KeGetCurrentPrcb()->NpxThread)
1334 {
1335 /* It isn't, enable interrupts and set delayed error */
1336 _enable();
1337 SaveArea->Cr0NpxState |= CR0_TS;
1338
1339 /* End trap */
1340 KiEoiHelper(TrapFrame);
1341 }
1342
1343 /* Otherwise, proceed with NPX fault handling */
1344 KiNpxHandler(TrapFrame, Thread, SaveArea);
1345 }
1346
1347 DECLSPEC_NORETURN
1348 VOID
1349 FASTCALL
1350 KiTrap11Handler(IN PKTRAP_FRAME TrapFrame)
1351 {
1352 /* Save trap frame */
1353 KiEnterTrap(TrapFrame);
1354
1355 /* Enable interrupts and kill the system */
1356 _enable();
1357 KiSystemFatalException(EXCEPTION_ALIGNMENT_CHECK, TrapFrame);
1358 }
1359
1360 DECLSPEC_NORETURN
1361 VOID
1362 FASTCALL
1363 KiTrap13Handler(IN PKTRAP_FRAME TrapFrame)
1364 {
1365 PKTHREAD Thread;
1366 PFX_SAVE_AREA SaveArea;
1367 ULONG Cr0, MxCsrMask, Error;
1368
1369 /* Save trap frame */
1370 KiEnterTrap(TrapFrame);
1371
1372 /* Check if this is the NPX thrad */
1373 Thread = KeGetCurrentThread();
1374 if (Thread != KeGetCurrentPrcb()->NpxThread)
1375 {
1376 /* It isn't, kill the system */
1377 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, (ULONG_PTR)Thread, 0, 0, TrapFrame);
1378 }
1379
1380 /* Get the NPX frame */
1381 SaveArea = KiGetThreadNpxArea(Thread);
1382
1383 /* Check for VDM trap */
1384 ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
1385
1386 /* Check for user trap */
1387 if (!KiUserTrap(TrapFrame))
1388 {
1389 /* Kernel should not fault on XMMI */
1390 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 2, TrapFrame);
1391 }
1392
1393 /* Update CR0 */
1394 Cr0 = __readcr0();
1395 Cr0 &= ~(CR0_MP | CR0_EM | CR0_TS);
1396 __writecr0(Cr0);
1397
1398 /* Save FPU state */
1399 Ke386SaveFpuState(SaveArea);
1400
1401 /* Mark CR0 state dirty */
1402 Cr0 |= NPX_STATE_NOT_LOADED;
1403 Cr0 |= SaveArea->Cr0NpxState;
1404 __writecr0(Cr0);
1405
1406 /* Update NPX state */
1407 Thread->NpxState = NPX_STATE_NOT_LOADED;
1408 KeGetCurrentPrcb()->NpxThread = NULL;
1409
1410 /* Clear the TS bit and re-enable interrupts */
1411 SaveArea->Cr0NpxState &= ~CR0_TS;
1412 _enable();
1413
1414 /* Now look at MxCsr to get the mask of errors we should care about */
1415 MxCsrMask = ~((USHORT)SaveArea->U.FxArea.MXCsr >> 7);
1416
1417 /* Get legal exceptions that software should handle */
1418 Error = (USHORT)SaveArea->U.FxArea.MXCsr & (FSW_INVALID_OPERATION |
1419 FSW_DENORMAL |
1420 FSW_ZERO_DIVIDE |
1421 FSW_OVERFLOW |
1422 FSW_UNDERFLOW |
1423 FSW_PRECISION);
1424 Error &= MxCsrMask;
1425
1426 /* Now handle any of those legal errors */
1427 if (Error & (FSW_INVALID_OPERATION |
1428 FSW_DENORMAL |
1429 FSW_ZERO_DIVIDE |
1430 FSW_OVERFLOW |
1431 FSW_UNDERFLOW |
1432 FSW_PRECISION))
1433 {
1434 /* By issuing an exception */
1435 KiDispatchException1Args(STATUS_FLOAT_MULTIPLE_TRAPS,
1436 TrapFrame->Eip,
1437 0,
1438 TrapFrame);
1439 }
1440
1441 /* Unknown XMMI fault */
1442 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 1, TrapFrame);
1443 }
1444
1445 /* SOFTWARE SERVICES **********************************************************/
1446
1447 VOID
1448 FASTCALL
1449 KiGetTickCountHandler(IN PKTRAP_FRAME TrapFrame)
1450 {
1451 UNIMPLEMENTED_DBGBREAK();
1452 }
1453
1454 VOID
1455 FASTCALL
1456 KiCallbackReturnHandler(IN PKTRAP_FRAME TrapFrame)
1457 {
1458 NTSTATUS Status;
1459
1460 /* Pass the register parameters to NtCallbackReturn.
1461 Result pointer is in ecx, result length in edx, status in eax */
1462 Status = NtCallbackReturn((PVOID)TrapFrame->Ecx,
1463 TrapFrame->Edx,
1464 TrapFrame->Eax);
1465
1466 /* If we got here, something went wrong. Return an error to the caller */
1467 KiServiceExit(TrapFrame, Status);
1468 }
1469
1470 DECLSPEC_NORETURN
1471 VOID
1472 FASTCALL
1473 KiRaiseAssertionHandler(IN PKTRAP_FRAME TrapFrame)
1474 {
1475 /* Save trap frame */
1476 KiEnterTrap(TrapFrame);
1477
1478 /* Decrement EIP to point to the INT2C instruction (2 bytes, not 1 like INT3) */
1479 TrapFrame->Eip -= 2;
1480
1481 /* Dispatch the exception */
1482 KiDispatchException0Args(STATUS_ASSERTION_FAILURE,
1483 TrapFrame->Eip,
1484 TrapFrame);
1485 }
1486
1487 DECLSPEC_NORETURN
1488 VOID
1489 FASTCALL
1490 KiDebugServiceHandler(IN PKTRAP_FRAME TrapFrame)
1491 {
1492 /* Save trap frame */
1493 KiEnterTrap(TrapFrame);
1494
1495 /* Increment EIP to skip the INT3 instruction */
1496 TrapFrame->Eip++;
1497
1498 /* Continue with the common handler */
1499 KiDebugHandler(TrapFrame, TrapFrame->Eax, TrapFrame->Ecx, TrapFrame->Edx);
1500 }
1501
1502
1503 FORCEINLINE
1504 VOID
1505 KiDbgPreServiceHook(ULONG SystemCallNumber, PULONG_PTR Arguments)
1506 {
1507 #if DBG && !defined(_WINKD_)
1508 if (SystemCallNumber >= 0x1000 && KeWin32PreServiceHook)
1509 KeWin32PreServiceHook(SystemCallNumber, Arguments);
1510 #endif
1511 }
1512
1513 FORCEINLINE
1514 ULONG_PTR
1515 KiDbgPostServiceHook(ULONG SystemCallNumber, ULONG_PTR Result)
1516 {
1517 #if DBG && !defined(_WINKD_)
1518 if (SystemCallNumber >= 0x1000 && KeWin32PostServiceHook)
1519 return KeWin32PostServiceHook(SystemCallNumber, Result);
1520 #endif
1521 return Result;
1522 }
1523
1524 FORCEINLINE
1525 DECLSPEC_NORETURN
1526 VOID
1527 KiSystemCall(IN PKTRAP_FRAME TrapFrame,
1528 IN PVOID Arguments)
1529 {
1530 PKTHREAD Thread;
1531 PKSERVICE_TABLE_DESCRIPTOR DescriptorTable;
1532 ULONG Id, Offset, StackBytes, Result;
1533 PVOID Handler;
1534 ULONG SystemCallNumber = TrapFrame->Eax;
1535
1536 /* Get the current thread */
1537 Thread = KeGetCurrentThread();
1538
1539 /* Set debug header */
1540 KiFillTrapFrameDebug(TrapFrame);
1541
1542 /* Chain trap frames */
1543 TrapFrame->Edx = (ULONG_PTR)Thread->TrapFrame;
1544
1545 /* No error code */
1546 TrapFrame->ErrCode = 0;
1547
1548 /* Save previous mode */
1549 TrapFrame->PreviousPreviousMode = Thread->PreviousMode;
1550
1551 /* Save the SEH chain and terminate it for now */
1552 TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
1553 KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
1554
1555 /* Default to debugging disabled */
1556 TrapFrame->Dr7 = 0;
1557
1558 /* Check if the frame was from user mode */
1559 if (KiUserTrap(TrapFrame))
1560 {
1561 /* Check for active debugging */
1562 if (KeGetCurrentThread()->Header.DebugActive & 0xFF)
1563 {
1564 /* Handle debug registers */
1565 KiHandleDebugRegistersOnTrapEntry(TrapFrame);
1566 }
1567 }
1568
1569 /* Set thread fields */
1570 Thread->TrapFrame = TrapFrame;
1571 Thread->PreviousMode = KiUserTrap(TrapFrame);
1572
1573 /* Enable interrupts */
1574 _enable();
1575
1576 /* Decode the system call number */
1577 Offset = (SystemCallNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK;
1578 Id = SystemCallNumber & SERVICE_NUMBER_MASK;
1579
1580 /* Get descriptor table */
1581 DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset);
1582
1583 /* Validate the system call number */
1584 if (__builtin_expect(Id >= DescriptorTable->Limit, 0))
1585 {
1586 /* Check if this is a GUI call */
1587 if (!(Offset & SERVICE_TABLE_TEST))
1588 {
1589 /* Fail the call */
1590 Result = STATUS_INVALID_SYSTEM_SERVICE;
1591 goto ExitCall;
1592 }
1593
1594 /* Convert us to a GUI thread -- must wrap in ASM to get new EBP */
1595 Result = KiConvertToGuiThread();
1596
1597 /* Reload trap frame and descriptor table pointer from new stack */
1598 TrapFrame = *(volatile PVOID*)&Thread->TrapFrame;
1599 DescriptorTable = (PVOID)(*(volatile ULONG_PTR*)&Thread->ServiceTable + Offset);
1600
1601 if (!NT_SUCCESS(Result))
1602 {
1603 /* Set the last error and fail */
1604 //SetLastWin32Error(RtlNtStatusToDosError(Result));
1605 goto ExitCall;
1606 }
1607
1608 /* Validate the system call number again */
1609 if (Id >= DescriptorTable->Limit)
1610 {
1611 /* Fail the call */
1612 Result = STATUS_INVALID_SYSTEM_SERVICE;
1613 goto ExitCall;
1614 }
1615 }
1616
1617 /* Check if this is a GUI call */
1618 if (__builtin_expect(Offset & SERVICE_TABLE_TEST, 0))
1619 {
1620 /* Get the batch count and flush if necessary */
1621 if (NtCurrentTeb()->GdiBatchCount) KeGdiFlushUserBatch();
1622 }
1623
1624 /* Increase system call count */
1625 KeGetCurrentPrcb()->KeSystemCalls++;
1626
1627 /* FIXME: Increase individual counts on debug systems */
1628 //KiIncreaseSystemCallCount(DescriptorTable, Id);
1629
1630 /* Get stack bytes */
1631 StackBytes = DescriptorTable->Number[Id];
1632
1633 /* Probe caller stack */
1634 if (__builtin_expect((Arguments < (PVOID)MmUserProbeAddress) && !(KiUserTrap(TrapFrame)), 0))
1635 {
1636 /* Access violation */
1637 UNIMPLEMENTED_FATAL();
1638 }
1639
1640 /* Call pre-service debug hook */
1641 KiDbgPreServiceHook(SystemCallNumber, Arguments);
1642
1643 /* Get the handler and make the system call */
1644 Handler = (PVOID)DescriptorTable->Base[Id];
1645 Result = KiSystemCallTrampoline(Handler, Arguments, StackBytes);
1646
1647 /* Call post-service debug hook */
1648 Result = KiDbgPostServiceHook(SystemCallNumber, Result);
1649
1650 /* Make sure we're exiting correctly */
1651 KiExitSystemCallDebugChecks(Id, TrapFrame);
1652
1653 /* Restore the old trap frame */
1654 ExitCall:
1655 Thread->TrapFrame = (PKTRAP_FRAME)TrapFrame->Edx;
1656
1657 /* Exit from system call */
1658 KiServiceExit(TrapFrame, Result);
1659 }
1660
1661 DECLSPEC_NORETURN
1662 VOID
1663 FASTCALL
1664 KiSystemServiceHandler(IN PKTRAP_FRAME TrapFrame,
1665 IN PVOID Arguments)
1666 {
1667 /* Call the shared handler (inline) */
1668 KiSystemCall(TrapFrame, Arguments);
1669 }
1670
1671 DECLSPEC_NORETURN
1672 VOID
1673 FASTCALL
1674 KiFastCallEntryHandler(IN PKTRAP_FRAME TrapFrame,
1675 IN PVOID Arguments)
1676 {
1677 /* Set up a fake INT Stack and enable interrupts */
1678 TrapFrame->HardwareSegSs = KGDT_R3_DATA | RPL_MASK;
1679 TrapFrame->HardwareEsp = (ULONG_PTR)Arguments;
1680 TrapFrame->EFlags = __readeflags() | EFLAGS_INTERRUPT_MASK;
1681 TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK;
1682 TrapFrame->Eip = SharedUserData->SystemCallReturn;
1683 TrapFrame->SegFs = KGDT_R3_TEB | RPL_MASK;
1684 __writeeflags(0x2);
1685
1686 /* Arguments are actually 2 frames down (because of the double indirection) */
1687 Arguments = (PVOID)(TrapFrame->HardwareEsp + 8);
1688
1689 /* Call the shared handler (inline) */
1690 KiSystemCall(TrapFrame, Arguments);
1691 }
1692
1693 /*
1694 * @implemented
1695 */
1696 VOID
1697 NTAPI
1698 Kei386EoiHelper(VOID)
1699 {
1700 /* We should never see this call happening */
1701 ERROR_FATAL("Mismatched NT/HAL version");
1702 }
1703
1704 /* EOF */