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