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