[ntos]
[reactos.git] / reactos / 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 //Ke386SaveFpuState(NpxSaveArea);
743
744 /* Update NPX state */
745 Thread->NpxState = NPX_STATE_NOT_LOADED;
746 }
747
748 /* Load FPU state */
749 //Ke386LoadFpuState(SaveArea);
750
751 /* Update NPX state */
752 Thread->NpxState = NPX_STATE_LOADED;
753 KeGetCurrentPrcb()->NpxThread = Thread;
754
755 /* Enable interrupts */
756 _enable();
757
758 /* Check if CR0 needs to be reloaded due to context switch */
759 if (!SaveArea->Cr0NpxState) KiEoiHelper(TrapFrame);
760
761 /* Otherwise, we need to reload CR0, disable interrupts */
762 _disable();
763
764 /* Reload CR0 */
765 Cr0 = __readcr0();
766 Cr0 |= SaveArea->Cr0NpxState;
767 __writecr0(Cr0);
768
769 /* Now restore interrupts and check for TS */
770 _enable();
771 if (Cr0 & CR0_TS) KiEoiHelper(TrapFrame);
772
773 /* We're still here -- clear TS and try again */
774 __writecr0(__readcr0() &~ CR0_TS);
775 _disable();
776 }
777 else
778 {
779 /* This is an actual fault, not a lack of FPU state */
780 break;
781 }
782 }
783
784 /* TS should not be set */
785 if (Cr0 & CR0_TS)
786 {
787 /*
788 * If it's incorrectly set, then maybe the state is actually still valid
789 * but we could've lock track of that due to a BIOS call.
790 * Make sure MP is still set, which should verify the theory.
791 */
792 if (Cr0 & CR0_MP)
793 {
794 /* Indeed, the state is actually still valid, so clear TS */
795 __writecr0(__readcr0() &~ CR0_TS);
796 KiEoiHelper(TrapFrame);
797 }
798
799 /* Otherwise, something strange is going on */
800 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 2, Cr0, 0, 0, TrapFrame);
801 }
802
803 /* It's not a delayed load, so process this trap as an NPX fault */
804 KiNpxHandler(TrapFrame, Thread, SaveArea);
805 }
806
807 DECLSPEC_NORETURN
808 VOID
809 FASTCALL
810 KiTrap08Handler(IN PKTRAP_FRAME TrapFrame)
811 {
812 /* FIXME: Not handled */
813 KiSystemFatalException(EXCEPTION_DOUBLE_FAULT, TrapFrame);
814 }
815
816 DECLSPEC_NORETURN
817 VOID
818 FASTCALL
819 KiTrap09Handler(IN PKTRAP_FRAME TrapFrame)
820 {
821 /* Save trap frame */
822 KiEnterTrap(TrapFrame);
823
824 /* Enable interrupts and kill the system */
825 _enable();
826 KiSystemFatalException(EXCEPTION_NPX_OVERRUN, TrapFrame);
827 }
828
829 DECLSPEC_NORETURN
830 VOID
831 FASTCALL
832 KiTrap0AHandler(IN PKTRAP_FRAME TrapFrame)
833 {
834 /* Save trap frame */
835 KiEnterTrap(TrapFrame);
836
837 /* Check for VDM trap */
838 ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
839
840 /* Kill the system */
841 KiSystemFatalException(EXCEPTION_INVALID_TSS, TrapFrame);
842 }
843
844 DECLSPEC_NORETURN
845 VOID
846 FASTCALL
847 KiTrap0BHandler(IN PKTRAP_FRAME TrapFrame)
848 {
849 /* Save trap frame */
850 KiEnterTrap(TrapFrame);
851
852 /* FIXME: Kill the system */
853 UNIMPLEMENTED;
854 KiSystemFatalException(EXCEPTION_SEGMENT_NOT_PRESENT, TrapFrame);
855 }
856
857 DECLSPEC_NORETURN
858 VOID
859 FASTCALL
860 KiTrap0CHandler(IN PKTRAP_FRAME TrapFrame)
861 {
862 /* Save trap frame */
863 KiEnterTrap(TrapFrame);
864
865 /* FIXME: Kill the system */
866 UNIMPLEMENTED;
867 KiSystemFatalException(EXCEPTION_STACK_FAULT, TrapFrame);
868 }
869
870 DECLSPEC_NORETURN
871 VOID
872 FASTCALL
873 KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame)
874 {
875 ULONG i, j, Iopl;
876 BOOLEAN Privileged = FALSE;
877 PUCHAR Instructions;
878 UCHAR Instruction = 0;
879 KIRQL OldIrql;
880
881 /* Check for V86 GPF */
882 if (__builtin_expect(KiV86Trap(TrapFrame), 1))
883 {
884 /* Enter V86 trap */
885 KiEnterV86Trap(TrapFrame);
886
887 /* Must be a VDM process */
888 if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects, 0))
889 {
890 /* Enable interrupts */
891 _enable();
892
893 /* Setup illegal instruction fault */
894 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION,
895 TrapFrame->Eip,
896 TrapFrame);
897 }
898
899 /* Go to APC level */
900 OldIrql = KfRaiseIrql(APC_LEVEL);
901 _enable();
902
903 /* Handle the V86 opcode */
904 if (__builtin_expect(Ki386HandleOpcodeV86(TrapFrame) == 0xFF, 0))
905 {
906 /* Should only happen in VDM mode */
907 UNIMPLEMENTED;
908 while (TRUE);
909 }
910
911 /* Bring IRQL back */
912 KfLowerIrql(OldIrql);
913 _disable();
914
915 /* Do a quick V86 exit if possible */
916 KiExitV86Trap(TrapFrame);
917 }
918
919 /* Save trap frame */
920 KiEnterTrap(TrapFrame);
921
922 /* Check for user-mode GPF */
923 if (KiUserTrap(TrapFrame))
924 {
925 /* Should not be VDM */
926 ASSERT(KiVdmTrap(TrapFrame) == FALSE);
927
928 /* Enable interrupts and check error code */
929 _enable();
930 if (!TrapFrame->ErrCode)
931 {
932 /* FIXME: Use SEH */
933 Instructions = (PUCHAR)TrapFrame->Eip;
934
935 /* Scan next 15 bytes */
936 for (i = 0; i < 15; i++)
937 {
938 /* Skip prefix instructions */
939 for (j = 0; j < sizeof(KiTrapPrefixTable); j++)
940 {
941 /* Is this a prefix instruction? */
942 if (Instructions[i] == KiTrapPrefixTable[j])
943 {
944 /* Stop looking */
945 break;
946 }
947 }
948
949 /* Is this NOT any prefix instruction? */
950 if (j == sizeof(KiTrapPrefixTable))
951 {
952 /* We can go ahead and handle the fault now */
953 Instruction = Instructions[i];
954 break;
955 }
956 }
957
958 /* If all we found was prefixes, then this instruction is too long */
959 if (i == 15)
960 {
961 /* Setup illegal instruction fault */
962 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION,
963 TrapFrame->Eip,
964 TrapFrame);
965 }
966
967 /* Check for privileged instructions */
968 if (Instruction == 0xF4) // HLT
969 {
970 /* HLT is privileged */
971 Privileged = TRUE;
972 }
973 else if (Instruction == 0x0F)
974 {
975 /* Test if it's any of the privileged two-byte opcodes */
976 if (((Instructions[i + 1] == 0x00) && // LLDT or LTR
977 (((Instructions[i + 2] & 0x38) == 0x10) || // LLDT
978 (Instructions[i + 2] == 0x18))) || // LTR
979 ((Instructions[i + 1] == 0x01) && // LGDT or LIDT or LMSW
980 (((Instructions[i + 2] & 0x38) == 0x10) || // LGDT
981 (Instructions[i + 2] == 0x18) || // LIDT
982 (Instructions[i + 2] == 0x30))) || // LMSW
983 (Instructions[i + 1] == 0x08) || // INVD
984 (Instructions[i + 1] == 0x09) || // WBINVD
985 (Instructions[i + 1] == 0x35) || // SYSEXIT
986 (Instructions[i + 1] == 0x26) || // MOV DR, XXX
987 (Instructions[i + 1] == 0x06) || // CLTS
988 (Instructions[i + 1] == 0x20) || // MOV CR, XXX
989 (Instructions[i + 1] == 0x24) || // MOV YYY, DR
990 (Instructions[i + 1] == 0x30) || // WRMSR
991 (Instructions[i + 1] == 0x33)) // RDPMC
992 // INVLPG, INVLPGA, SYSRET
993 {
994 /* These are all privileged */
995 Privileged = TRUE;
996 }
997 }
998 else
999 {
1000 /* Get the IOPL and compare with the RPL mask */
1001 Iopl = (TrapFrame->EFlags & EFLAGS_IOPL) >> 12;
1002 if ((TrapFrame->SegCs & RPL_MASK) > Iopl)
1003 {
1004 /* I/O privilege error -- check for known instructions */
1005 if ((Instruction == 0xFA) || (Instruction == 0xFB)) // CLI or STI
1006 {
1007 /* These are privileged */
1008 Privileged = TRUE;
1009 }
1010 else
1011 {
1012 /* Last hope: an IN/OUT instruction */
1013 for (j = 0; j < sizeof(KiTrapIoTable); j++)
1014 {
1015 /* Is this an I/O instruction? */
1016 if (Instruction == KiTrapIoTable[j])
1017 {
1018 /* Then it's privileged */
1019 Privileged = TRUE;
1020 break;
1021 }
1022 }
1023 }
1024 }
1025 }
1026
1027 /* So now... was the instruction privileged or not? */
1028 if (Privileged)
1029 {
1030 /* Whew! We have a privileged instruction, so dispatch the fault */
1031 KiDispatchException0Args(STATUS_PRIVILEGED_INSTRUCTION,
1032 TrapFrame->Eip,
1033 TrapFrame);
1034 }
1035 }
1036
1037 /* If we got here, send an access violation */
1038 KiDispatchException2Args(STATUS_ACCESS_VIOLATION,
1039 TrapFrame->Eip,
1040 0,
1041 0xFFFFFFFF,
1042 TrapFrame);
1043 }
1044
1045 /*
1046 * Check for a fault during checking of the user instruction.
1047 *
1048 * Note that the SEH handler will catch invalid EIP, but we could be dealing
1049 * with an invalid CS, which will generate another GPF instead.
1050 *
1051 */
1052 if (((PVOID)TrapFrame->Eip >= (PVOID)KiTrap0DHandler) &&
1053 ((PVOID)TrapFrame->Eip < (PVOID)KiTrap0DHandler))
1054 {
1055 /* Not implemented */
1056 UNIMPLEMENTED;
1057 while (TRUE);
1058 }
1059
1060 /*
1061 * NOTE: The ASM trap exit code would restore segment registers by doing
1062 * a POP <SEG>, which could cause an invalid segment if someone had messed
1063 * with the segment values.
1064 *
1065 * Another case is a bogus SS, which would hit a GPF when doing the iret.
1066 * This could only be done through a buggy or malicious driver, or perhaps
1067 * the kernel debugger.
1068 *
1069 * The kernel normally restores the "true" segment if this happens.
1070 *
1071 * However, since we're restoring in C, not ASM, we can't detect
1072 * POP <SEG> since the actual instructions will be different.
1073 *
1074 * A better technique would be to check the EIP and somehow edit the
1075 * trap frame before restarting the instruction -- but we would need to
1076 * know the extract instruction that was used first.
1077 *
1078 * We could force a special instrinsic to use stack instructions, or write
1079 * a simple instruction length checker.
1080 *
1081 * Nevertheless, this is a lot of work for the purpose of avoiding a crash
1082 * when the user is purposedly trying to create one from kernel-mode, so
1083 * we should probably table this for now since it's not a "real" issue.
1084 */
1085
1086 /*
1087 * NOTE2: Another scenario is the IRET during a V8086 restore (BIOS Call)
1088 * which will cause a GPF since the trap frame is a total mess (on purpose)
1089 * as built in KiEnterV86Mode.
1090 *
1091 * The idea is to scan for IRET, scan for the known EIP adress, validate CS
1092 * and then manually issue a jump to the V8086 return EIP.
1093 */
1094 Instructions = (PUCHAR)TrapFrame->Eip;
1095 if (Instructions[0] == 0xCF)
1096 {
1097 /*
1098 * Some evil shit is going on here -- this is not the SS:ESP you're
1099 * looking for! Instead, this is actually CS:EIP you're looking at!
1100 * Why? Because part of the trap frame actually corresponds to the IRET
1101 * stack during the trap exit!
1102 */
1103 if ((TrapFrame->HardwareEsp == (ULONG)Ki386BiosCallReturnAddress) &&
1104 (TrapFrame->HardwareSegSs == (KGDT_R0_CODE | RPL_MASK)))
1105 {
1106 /* Exit the V86 trap! */
1107 Ki386BiosCallReturnAddress(TrapFrame);
1108 }
1109 else
1110 {
1111 /* Otherwise, this is another kind of IRET fault */
1112 UNIMPLEMENTED;
1113 while (TRUE);
1114 }
1115 }
1116
1117 /* So since we're not dealing with the above case, check for RDMSR/WRMSR */
1118 if ((Instructions[0] == 0xF) && // 2-byte opcode
1119 (((Instructions[1] >> 8) == 0x30) || // RDMSR
1120 ((Instructions[2] >> 8) == 0x32))) // WRMSR
1121 {
1122 /* Unknown CPU MSR, so raise an access violation */
1123 KiDispatchException0Args(STATUS_ACCESS_VIOLATION,
1124 TrapFrame->Eip,
1125 TrapFrame);
1126 }
1127
1128 /* Check for lazy segment load */
1129 if (TrapFrame->SegDs != (KGDT_R3_DATA | RPL_MASK))
1130 {
1131 /* Fix it */
1132 TrapFrame->SegDs = (KGDT_R3_DATA | RPL_MASK);
1133 }
1134 else if (TrapFrame->SegEs != (KGDT_R3_DATA | RPL_MASK))
1135 {
1136 /* Fix it */
1137 TrapFrame->SegEs = (KGDT_R3_DATA | RPL_MASK);
1138 }
1139 else
1140 {
1141 /* Whatever it is, we can't handle it */
1142 KiSystemFatalException(EXCEPTION_GP_FAULT, TrapFrame);
1143 }
1144
1145 /* Return to where we came from */
1146 KiTrapReturn(TrapFrame);
1147 }
1148
1149 DECLSPEC_NORETURN
1150 VOID
1151 FASTCALL
1152 KiTrap0EHandler(IN PKTRAP_FRAME TrapFrame)
1153 {
1154 PKTHREAD Thread;
1155 ULONG_PTR Cr2;
1156 NTSTATUS Status;
1157
1158 /* Save trap frame */
1159 KiEnterTrap(TrapFrame);
1160
1161 /* Check if this is the base frame */
1162 Thread = KeGetCurrentThread();
1163 if (KeGetTrapFrame(Thread) != TrapFrame)
1164 {
1165 /* It isn't, check if this is a second nested frame */
1166 if (((ULONG_PTR)KeGetTrapFrame(Thread) - (ULONG_PTR)TrapFrame) <=
1167 FIELD_OFFSET(KTRAP_FRAME, EFlags))
1168 {
1169 /* The stack is somewhere in between frames, we need to fix it */
1170 UNIMPLEMENTED;
1171 while (TRUE);
1172 }
1173 }
1174
1175 /* Save CR2 */
1176 Cr2 = __readcr2();
1177
1178 /* Check for Pentium LOCK errata */
1179 if (KiI386PentiumLockErrataPresent)
1180 {
1181 /* Not yet implemented */
1182 UNIMPLEMENTED;
1183 while (TRUE);
1184 }
1185
1186 /* HACK: Check if interrupts are disabled and enable them */
1187 if (!(TrapFrame->EFlags & EFLAGS_INTERRUPT_MASK))
1188 {
1189 /* Enable interupts */
1190 _enable();
1191 #ifdef HACK_ABOVE_FIXED
1192 if (!(TrapFrame->EFlags & EFLAGS_INTERRUPT_MASK))
1193 {
1194 /* This is illegal */
1195 KeBugCheckWithTf(IRQL_NOT_LESS_OR_EQUAL,
1196 Cr2,
1197 -1,
1198 TrapFrame->ErrCode & 1,
1199 TrapFrame->Eip,
1200 TrapFrame);
1201 }
1202 #endif
1203 }
1204
1205 /* Call the access fault handler */
1206 Status = MmAccessFault(TrapFrame->ErrCode & 1,
1207 (PVOID)Cr2,
1208 TrapFrame->SegCs & MODE_MASK,
1209 TrapFrame);
1210 if (NT_SUCCESS(Status)) KiEoiHelper(TrapFrame);
1211
1212 /* Check for S-LIST fault */
1213 if (TrapFrame->Eip == (ULONG_PTR)ExpInterlockedPopEntrySListFault)
1214 {
1215 /* Not yet implemented */
1216 UNIMPLEMENTED;
1217 while (TRUE);
1218 }
1219
1220 /* Check for syscall fault */
1221 #if 0
1222 if ((TrapFrame->Eip == (ULONG_PTR)CopyParams) ||
1223 (TrapFrame->Eip == (ULONG_PTR)ReadBatch))
1224 {
1225 /* Not yet implemented */
1226 UNIMPLEMENTED;
1227 while (TRUE);
1228 }
1229 #endif
1230 /* Check for VDM trap */
1231 ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
1232
1233 /* Either kernel or user trap (non VDM) so dispatch exception */
1234 if (Status == STATUS_ACCESS_VIOLATION)
1235 {
1236 /* This status code is repurposed so we can recognize it later */
1237 KiDispatchException2Args(KI_EXCEPTION_ACCESS_VIOLATION,
1238 TrapFrame->Eip,
1239 TrapFrame->ErrCode & 1,
1240 Cr2,
1241 TrapFrame);
1242 }
1243 else if ((Status == STATUS_GUARD_PAGE_VIOLATION) ||
1244 (Status == STATUS_STACK_OVERFLOW))
1245 {
1246 /* These faults only have two parameters */
1247 KiDispatchException2Args(Status,
1248 TrapFrame->Eip,
1249 TrapFrame->ErrCode & 1,
1250 Cr2,
1251 TrapFrame);
1252 }
1253
1254 /* Only other choice is an in-page error, with 3 parameters */
1255 KiDispatchExceptionFromTrapFrame(STATUS_IN_PAGE_ERROR,
1256 TrapFrame->Eip,
1257 3,
1258 TrapFrame->ErrCode & 1,
1259 Cr2,
1260 Status,
1261 TrapFrame);
1262 }
1263
1264 DECLSPEC_NORETURN
1265 VOID
1266 FASTCALL
1267 KiTrap0FHandler(IN PKTRAP_FRAME TrapFrame)
1268 {
1269 /* Save trap frame */
1270 KiEnterTrap(TrapFrame);
1271
1272 /* FIXME: Kill the system */
1273 UNIMPLEMENTED;
1274 KiSystemFatalException(EXCEPTION_RESERVED_TRAP, TrapFrame);
1275 }
1276
1277 DECLSPEC_NORETURN
1278 VOID
1279 FASTCALL
1280 KiTrap10Handler(IN PKTRAP_FRAME TrapFrame)
1281 {
1282 PKTHREAD Thread;
1283 PFX_SAVE_AREA SaveArea;
1284
1285 /* Save trap frame */
1286 KiEnterTrap(TrapFrame);
1287
1288 /* Check if this is the NPX thrad */
1289 Thread = KeGetCurrentThread();
1290 SaveArea = KiGetThreadNpxArea(Thread);
1291 if (Thread != KeGetCurrentPrcb()->NpxThread)
1292 {
1293 /* It isn't, enable interrupts and set delayed error */
1294 _enable();
1295 SaveArea->Cr0NpxState |= CR0_TS;
1296
1297 /* End trap */
1298 KiEoiHelper(TrapFrame);
1299 }
1300
1301 /* Otherwise, proceed with NPX fault handling */
1302 KiNpxHandler(TrapFrame, Thread, SaveArea);
1303 }
1304
1305 DECLSPEC_NORETURN
1306 VOID
1307 FASTCALL
1308 KiTrap11Handler(IN PKTRAP_FRAME TrapFrame)
1309 {
1310 /* Save trap frame */
1311 KiEnterTrap(TrapFrame);
1312
1313 /* Enable interrupts and kill the system */
1314 _enable();
1315 KiSystemFatalException(EXCEPTION_ALIGNMENT_CHECK, TrapFrame);
1316 }
1317
1318 DECLSPEC_NORETURN
1319 VOID
1320 FASTCALL
1321 KiTrap13Handler(IN PKTRAP_FRAME TrapFrame)
1322 {
1323 PKTHREAD Thread;
1324 PFX_SAVE_AREA SaveArea;
1325 ULONG Cr0, MxCsrMask, Error;
1326
1327 /* Save trap frame */
1328 KiEnterTrap(TrapFrame);
1329
1330 /* Check if this is the NPX thrad */
1331 Thread = KeGetCurrentThread();
1332 if (Thread != KeGetCurrentPrcb()->NpxThread)
1333 {
1334 /* It isn't, kill the system */
1335 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, (ULONG_PTR)Thread, 0, 0, TrapFrame);
1336 }
1337
1338 /* Get the NPX frame */
1339 SaveArea = KiGetThreadNpxArea(Thread);
1340
1341 /* Check for VDM trap */
1342 ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
1343
1344 /* Check for user trap */
1345 if (!KiUserTrap(TrapFrame))
1346 {
1347 /* Kernel should not fault on XMMI */
1348 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 2, TrapFrame);
1349 }
1350
1351 /* Update CR0 */
1352 Cr0 = __readcr0();
1353 Cr0 &= ~(CR0_MP | CR0_EM | CR0_TS);
1354 __writecr0(Cr0);
1355
1356 /* Save FPU state */
1357 Ke386SaveFpuState(SaveArea);
1358
1359 /* Mark CR0 state dirty */
1360 Cr0 |= NPX_STATE_NOT_LOADED;
1361 Cr0 |= SaveArea->Cr0NpxState;
1362 __writecr0(Cr0);
1363
1364 /* Update NPX state */
1365 Thread->NpxState = NPX_STATE_NOT_LOADED;
1366 KeGetCurrentPrcb()->NpxThread = NULL;
1367
1368 /* Clear the TS bit and re-enable interrupts */
1369 SaveArea->Cr0NpxState &= ~CR0_TS;
1370 _enable();
1371
1372 /* Now look at MxCsr to get the mask of errors we should care about */
1373 MxCsrMask = ~((USHORT)SaveArea->U.FxArea.MXCsr >> 7);
1374
1375 /* Get legal exceptions that software should handle */
1376 Error = (USHORT)SaveArea->U.FxArea.MXCsr & (FSW_INVALID_OPERATION |
1377 FSW_DENORMAL |
1378 FSW_ZERO_DIVIDE |
1379 FSW_OVERFLOW |
1380 FSW_UNDERFLOW |
1381 FSW_PRECISION);
1382 Error &= MxCsrMask;
1383
1384 /* Now handle any of those legal errors */
1385 if (Error & (FSW_INVALID_OPERATION |
1386 FSW_DENORMAL |
1387 FSW_ZERO_DIVIDE |
1388 FSW_OVERFLOW |
1389 FSW_UNDERFLOW |
1390 FSW_PRECISION))
1391 {
1392 /* By issuing an exception */
1393 KiDispatchException1Args(STATUS_FLOAT_MULTIPLE_TRAPS,
1394 TrapFrame->Eip,
1395 0,
1396 TrapFrame);
1397 }
1398
1399 /* Unknown XMMI fault */
1400 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 1, TrapFrame);
1401 }
1402
1403 /* SOFTWARE SERVICES **********************************************************/
1404
1405 VOID
1406 FASTCALL
1407 KiGetTickCountHandler(IN PKTRAP_FRAME TrapFrame)
1408 {
1409 UNIMPLEMENTED;
1410 while (TRUE);
1411 }
1412
1413 VOID
1414 FASTCALL
1415 KiCallbackReturnHandler(IN PKTRAP_FRAME TrapFrame)
1416 {
1417 UNIMPLEMENTED;
1418 while (TRUE);
1419 }
1420
1421 DECLSPEC_NORETURN
1422 VOID
1423 FASTCALL
1424 KiRaiseAssertionHandler(IN PKTRAP_FRAME TrapFrame)
1425 {
1426 /* Save trap frame */
1427 KiEnterTrap(TrapFrame);
1428
1429 /* Decrement EIP to point to the INT2C instruction (2 bytes, not 1 like INT3) */
1430 TrapFrame->Eip -= 2;
1431
1432 /* Dispatch the exception */
1433 KiDispatchException0Args(STATUS_ASSERTION_FAILURE,
1434 TrapFrame->Eip,
1435 TrapFrame);
1436 }
1437
1438 DECLSPEC_NORETURN
1439 VOID
1440 FASTCALL
1441 KiDebugServiceHandler(IN PKTRAP_FRAME TrapFrame)
1442 {
1443 /* Save trap frame */
1444 KiEnterTrap(TrapFrame);
1445
1446 /* Increment EIP to skip the INT3 instruction */
1447 TrapFrame->Eip++;
1448
1449 /* Continue with the common handler */
1450 KiDebugHandler(TrapFrame, TrapFrame->Eax, TrapFrame->Ecx, TrapFrame->Edx);
1451 }
1452
1453 DECLSPEC_NORETURN
1454 VOID
1455 FORCEINLINE
1456 KiSystemCall(IN PKTRAP_FRAME TrapFrame,
1457 IN PVOID Arguments)
1458 {
1459 PKTHREAD Thread;
1460 PKSERVICE_TABLE_DESCRIPTOR DescriptorTable;
1461 ULONG Id, Offset, StackBytes, Result;
1462 PVOID Handler;
1463 ULONG SystemCallNumber = TrapFrame->Eax;
1464
1465 /* Get the current thread */
1466 Thread = KeGetCurrentThread();
1467
1468 /* Set debug header */
1469 KiFillTrapFrameDebug(TrapFrame);
1470
1471 /* Chain trap frames */
1472 TrapFrame->Edx = (ULONG_PTR)Thread->TrapFrame;
1473
1474 /* No error code */
1475 TrapFrame->ErrCode = 0;
1476
1477 /* Save previous mode */
1478 TrapFrame->PreviousPreviousMode = Thread->PreviousMode;
1479
1480 /* Save the SEH chain and terminate it for now */
1481 TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
1482 KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
1483
1484 /* Clear DR7 and check for debugging */
1485 TrapFrame->Dr7 = 0;
1486 if (__builtin_expect(Thread->DispatcherHeader.DebugActive & 0xFF, 0))
1487 {
1488 UNIMPLEMENTED;
1489 while (TRUE);
1490 }
1491
1492 /* Set thread fields */
1493 Thread->TrapFrame = TrapFrame;
1494 Thread->PreviousMode = KiUserTrap(TrapFrame);
1495
1496 /* Enable interrupts */
1497 _enable();
1498
1499 /* Decode the system call number */
1500 Offset = (SystemCallNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK;
1501 Id = SystemCallNumber & SERVICE_NUMBER_MASK;
1502
1503 /* Get descriptor table */
1504 DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset);
1505
1506 /* Validate the system call number */
1507 if (__builtin_expect(Id >= DescriptorTable->Limit, 0))
1508 {
1509 /* Check if this is a GUI call */
1510 if (!(Offset & SERVICE_TABLE_TEST))
1511 {
1512 /* Fail the call */
1513 Result = STATUS_INVALID_SYSTEM_SERVICE;
1514 goto ExitCall;
1515 }
1516
1517 /* Convert us to a GUI thread -- must wrap in ASM to get new EBP */
1518 Result = KiConvertToGuiThread();
1519 if (!NT_SUCCESS(Result))
1520 {
1521 /* Set the last error and fail */
1522 //SetLastWin32Error(RtlNtStatusToDosError(Result));
1523 goto ExitCall;
1524 }
1525
1526 /* Reload trap frame and descriptor table pointer from new stack */
1527 TrapFrame = *(volatile PVOID*)&Thread->TrapFrame;
1528 DescriptorTable = (PVOID)(*(volatile ULONG_PTR*)&Thread->ServiceTable + Offset);
1529
1530 /* Validate the system call number again */
1531 if (Id >= DescriptorTable->Limit)
1532 {
1533 /* Fail the call */
1534 Result = STATUS_INVALID_SYSTEM_SERVICE;
1535 goto ExitCall;
1536 }
1537 }
1538
1539 /* Check if this is a GUI call */
1540 if (__builtin_expect(Offset & SERVICE_TABLE_TEST, 0))
1541 {
1542 /* Get the batch count and flush if necessary */
1543 if (NtCurrentTeb()->GdiBatchCount) KeGdiFlushUserBatch();
1544 }
1545
1546 /* Increase system call count */
1547 KeGetCurrentPrcb()->KeSystemCalls++;
1548
1549 /* FIXME: Increase individual counts on debug systems */
1550 //KiIncreaseSystemCallCount(DescriptorTable, Id);
1551
1552 /* Get stack bytes */
1553 StackBytes = DescriptorTable->Number[Id];
1554
1555 /* Probe caller stack */
1556 if (__builtin_expect((Arguments < (PVOID)MmUserProbeAddress) && !(KiUserTrap(TrapFrame)), 0))
1557 {
1558 /* Access violation */
1559 UNIMPLEMENTED;
1560 while (TRUE);
1561 }
1562
1563 /* Get the handler and make the system call */
1564 Handler = (PVOID)DescriptorTable->Base[Id];
1565 Result = KiSystemCallTrampoline(Handler, Arguments, StackBytes);
1566
1567 /* Make sure we're exiting correctly */
1568 KiExitSystemCallDebugChecks(Id, TrapFrame);
1569
1570 /* Restore the old trap frame */
1571 ExitCall:
1572 Thread->TrapFrame = (PKTRAP_FRAME)TrapFrame->Edx;
1573
1574 /* Exit from system call */
1575 KiServiceExit(TrapFrame, Result);
1576 }
1577
1578 DECLSPEC_NORETURN
1579 VOID
1580 FASTCALL
1581 KiSystemServiceHandler(IN PKTRAP_FRAME TrapFrame,
1582 IN PVOID Arguments)
1583 {
1584 /* Call the shared handler (inline) */
1585 KiSystemCall(TrapFrame, Arguments);
1586 }
1587
1588 DECLSPEC_NORETURN
1589 VOID
1590 FASTCALL
1591 KiFastCallEntryHandler(IN PKTRAP_FRAME TrapFrame,
1592 IN PVOID Arguments)
1593 {
1594 /* Set up a fake INT Stack and enable interrupts */
1595 TrapFrame->HardwareSegSs = KGDT_R3_DATA | RPL_MASK;
1596 TrapFrame->HardwareEsp = (ULONG_PTR)Arguments;
1597 TrapFrame->EFlags = __readeflags() | EFLAGS_INTERRUPT_MASK;
1598 TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK;
1599 TrapFrame->Eip = SharedUserData->SystemCallReturn;
1600 TrapFrame->SegFs = KGDT_R3_TEB | RPL_MASK;
1601 __writeeflags(0x2);
1602
1603 /* Arguments are actually 2 frames down (because of the double indirection) */
1604 Arguments = (PVOID)(TrapFrame->HardwareEsp + 8);
1605
1606 /* Call the shared handler (inline) */
1607 KiSystemCall(TrapFrame, Arguments);
1608 }
1609
1610 /*
1611 * @implemented
1612 */
1613 VOID
1614 NTAPI
1615 Kei386EoiHelper(VOID)
1616 {
1617 /* We should never see this call happening */
1618 DPRINT1("Mismatched NT/HAL version");
1619 while (TRUE);
1620 }
1621
1622 /* EOF */