xref: /reactos/ntoskrnl/ke/i386/exp.c (revision 53221834)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            ntoskrnl/ke/i386/exp.c
5  * PURPOSE:         Exception Dispatching and Context<->Trap Frame Conversion
6  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
7  *                  Gregor Anich
8  *                  Skywing (skywing@valhallalegends.com)
9  */
10 
11 /* INCLUDES ******************************************************************/
12 
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16 
17 
18 /* FUNCTIONS *****************************************************************/
19 
20 CODE_SEG("INIT")
21 VOID
22 NTAPI
23 KeInitExceptions(VOID)
24 {
25     ULONG i;
26     USHORT FlippedSelector;
27 
28     /* Loop the IDT */
29     for (i = 0; i <= MAXIMUM_IDTVECTOR; i++)
30     {
31         /* Save the current Selector */
32         FlippedSelector = KiIdt[i].Selector;
33 
34         /* Flip Selector and Extended Offset */
35         KiIdt[i].Selector = KiIdt[i].ExtendedOffset;
36         KiIdt[i].ExtendedOffset = FlippedSelector;
37     }
38 }
39 
40 ULONG
41 FASTCALL
42 KiUpdateDr7(IN ULONG Dr7)
43 {
44     ULONG DebugMask = KeGetCurrentThread()->Header.DebugActive;
45 
46     /* Check if debugging is enabled */
47     if (DebugMask & DR_MASK(DR7_OVERRIDE_V))
48     {
49         /* Sanity checks */
50         ASSERT((DebugMask & DR_REG_MASK) != 0);
51         ASSERT((Dr7 & ~DR7_RESERVED_MASK) == DR7_OVERRIDE_MASK);
52         return 0;
53     }
54 
55     /* Return DR7 itself */
56     return Dr7;
57 }
58 
59 BOOLEAN
60 FASTCALL
61 KiRecordDr7(OUT PULONG Dr7Ptr,
62             OUT PULONG DrMask)
63 {
64     ULONG NewMask, Mask;
65     UCHAR Result;
66 
67     /* Check if the caller gave us a mask */
68     if (!DrMask)
69     {
70         /* He didn't, use the one from the thread */
71         Mask = KeGetCurrentThread()->Header.DebugActive;
72     }
73     else
74     {
75         /* He did, read it */
76         Mask = *DrMask;
77     }
78 
79     /* Sanity check */
80     ASSERT((*Dr7Ptr & DR7_RESERVED_MASK) == 0);
81 
82     /* Check if DR7 is empty */
83     NewMask = Mask;
84     if (!(*Dr7Ptr))
85     {
86         /* Assume failure */
87         Result = FALSE;
88 
89         /* Check the DR mask */
90         NewMask &= ~(DR_MASK(7));
91         if (NewMask & DR_REG_MASK)
92         {
93             /* Set the active mask */
94             NewMask |= DR_MASK(DR7_OVERRIDE_V);
95 
96             /* Set DR7 override */
97             *Dr7Ptr |= DR7_OVERRIDE_MASK;
98         }
99         else
100         {
101             /* Sanity check */
102             ASSERT(NewMask == 0);
103         }
104     }
105     else
106     {
107         /* Check if we have a mask or not */
108         Result = NewMask ? TRUE: FALSE;
109 
110         /* Update the mask to disable debugging */
111         NewMask &= ~(DR_MASK(DR7_OVERRIDE_V));
112         NewMask |= DR_MASK(7);
113     }
114 
115     /* Check if caller wants the new mask */
116     if (DrMask)
117     {
118         /* Update it */
119         *DrMask = NewMask;
120     }
121     else
122     {
123         /* Check if the mask changed */
124         if (Mask != NewMask)
125         {
126             /* Update it */
127             KeGetCurrentThread()->Header.DebugActive = (UCHAR)NewMask;
128         }
129     }
130 
131     /* Return the result */
132     return Result;
133 }
134 
135 ULONG
136 NTAPI
137 KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame)
138 {
139     /* Check if this is user-mode or V86 */
140     if (KiUserTrap(TrapFrame) ||
141         (TrapFrame->EFlags & EFLAGS_V86_MASK))
142     {
143         /* Return it directly */
144         return TrapFrame->HardwareEsp;
145     }
146     else
147     {
148         /* Edited frame */
149         if (!(TrapFrame->SegCs & FRAME_EDITED))
150         {
151             /* Return edited value */
152             return TrapFrame->TempEsp;
153         }
154         else
155         {
156             /* Virgin frame, calculate */
157             return (ULONG)&TrapFrame->HardwareEsp;
158         }
159     }
160 }
161 
162 VOID
163 NTAPI
164 KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame,
165                  IN ULONG Esp)
166 {
167     KIRQL OldIrql;
168     ULONG Previous;
169 
170     /* Raise to APC_LEVEL if needed */
171     OldIrql = KeGetCurrentIrql();
172     if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
173 
174     /* Get the old ESP */
175     Previous = KiEspFromTrapFrame(TrapFrame);
176 
177     /* Check if this is user-mode or V86 */
178     if (KiUserTrap(TrapFrame) ||
179         (TrapFrame->EFlags & EFLAGS_V86_MASK))
180     {
181         /* Write it directly */
182         TrapFrame->HardwareEsp = Esp;
183     }
184     else
185     {
186         /* Don't allow ESP to be lowered, this is illegal */
187         if (Esp < Previous) KeBugCheckEx(SET_OF_INVALID_CONTEXT,
188                                          Esp,
189                                          Previous,
190                                          (ULONG_PTR)TrapFrame,
191                                          0);
192 
193         /* Create an edit frame, check if it was alrady */
194         if (!(TrapFrame->SegCs & FRAME_EDITED))
195         {
196             /* Update the value */
197             TrapFrame->TempEsp = Esp;
198         }
199         else
200         {
201             /* Check if ESP changed */
202             if (Previous != Esp)
203             {
204                 /* Save CS */
205                 TrapFrame->TempSegCs = TrapFrame->SegCs;
206                 TrapFrame->SegCs &= ~FRAME_EDITED;
207 
208                 /* Save ESP */
209                 TrapFrame->TempEsp = Esp;
210             }
211         }
212     }
213 
214     /* Restore IRQL */
215     if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
216 }
217 
218 ULONG
219 NTAPI
220 KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame)
221 {
222     /* Check if this was V86 Mode */
223     if (TrapFrame->EFlags & EFLAGS_V86_MASK)
224     {
225         /* Just return it */
226         return TrapFrame->HardwareSegSs;
227     }
228     else if (KiUserTrap(TrapFrame))
229     {
230         /* User mode, return the User SS */
231         return TrapFrame->HardwareSegSs | RPL_MASK;
232     }
233     else
234     {
235         /* Kernel mode */
236         return KGDT_R0_DATA;
237     }
238 }
239 
240 VOID
241 NTAPI
242 KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame,
243                 IN ULONG Ss)
244 {
245     /* Remove the high-bits */
246     Ss &= 0xFFFF;
247 
248     /* If this was V86 Mode */
249     if (TrapFrame->EFlags & EFLAGS_V86_MASK)
250     {
251         /* Just write it */
252         TrapFrame->HardwareSegSs = Ss;
253     }
254     else if (KiUserTrap(TrapFrame))
255     {
256         /* Usermode, save the User SS */
257         TrapFrame->HardwareSegSs = Ss | RPL_MASK;
258     }
259 }
260 
261 USHORT
262 NTAPI
263 KiTagWordFnsaveToFxsave(USHORT TagWord)
264 {
265     INT FxTagWord = ~TagWord;
266 
267     /*
268      * Empty is now 00, any 2 bits containing 1 mean valid
269      * Now convert the rest (11->0 and the rest to 1)
270      */
271     FxTagWord = (FxTagWord | (FxTagWord >> 1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
272     FxTagWord = (FxTagWord | (FxTagWord >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
273     FxTagWord = (FxTagWord | (FxTagWord >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
274     FxTagWord = (FxTagWord | (FxTagWord >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
275     return FxTagWord;
276 }
277 
278 VOID
279 NTAPI
280 Ki386AdjustEsp0(IN PKTRAP_FRAME TrapFrame)
281 {
282     PKTHREAD Thread;
283     ULONG_PTR Stack;
284     ULONG EFlags;
285 
286     /* Get the current thread's stack */
287     Thread = KeGetCurrentThread();
288     Stack = (ULONG_PTR)Thread->InitialStack;
289 
290     /* Check if we are in V8086 mode */
291     if (!(TrapFrame->EFlags & EFLAGS_V86_MASK))
292     {
293         /* Bias the stack for the V86 segments */
294         Stack -= sizeof(KTRAP_FRAME) -
295                  FIELD_OFFSET(KTRAP_FRAME, V86Es);
296     }
297 
298     /* Bias the stack for the FPU area */
299     Stack -= sizeof(FX_SAVE_AREA);
300 
301     /* Disable interrupts */
302     EFlags = __readeflags();
303     _disable();
304 
305     /* Set new ESP0 value in the TSS */
306     KeGetPcr()->TSS->Esp0 = Stack;
307 
308     /* Restore old interrupt state */
309     __writeeflags(EFlags);
310 }
311 
312 VOID
313 NTAPI
314 KeContextToTrapFrame(IN PCONTEXT Context,
315                      IN OUT PKEXCEPTION_FRAME ExceptionFrame,
316                      IN OUT PKTRAP_FRAME TrapFrame,
317                      IN ULONG ContextFlags,
318                      IN KPROCESSOR_MODE PreviousMode)
319 {
320     PFX_SAVE_AREA FxSaveArea;
321     ULONG i;
322     BOOLEAN V86Switch = FALSE;
323     KIRQL OldIrql;
324     ULONG DrMask = 0;
325 
326     /* Do this at APC_LEVEL */
327     OldIrql = KeGetCurrentIrql();
328     if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
329 
330     /* Start with the basic Registers */
331     if ((ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
332     {
333         /* Check if we went through a V86 switch */
334         if ((Context->EFlags & EFLAGS_V86_MASK) !=
335             (TrapFrame->EFlags & EFLAGS_V86_MASK))
336         {
337             /* We did, remember this for later */
338             V86Switch = TRUE;
339         }
340 
341         /* Copy EFLAGS and sanitize them*/
342         TrapFrame->EFlags = Ke386SanitizeFlags(Context->EFlags, PreviousMode);
343 
344         /* Copy EBP and EIP */
345         TrapFrame->Ebp = Context->Ebp;
346         TrapFrame->Eip = Context->Eip;
347 
348         /* Check if we were in V86 Mode */
349         if (TrapFrame->EFlags & EFLAGS_V86_MASK)
350         {
351             /* Simply copy the CS value */
352             TrapFrame->SegCs = Context->SegCs;
353         }
354         else
355         {
356             /* We weren't in V86, so sanitize the CS */
357             TrapFrame->SegCs = Ke386SanitizeSeg(Context->SegCs, PreviousMode);
358 
359             /* Don't let it under 8, that's invalid */
360             if ((PreviousMode != KernelMode) && (TrapFrame->SegCs < 8))
361             {
362                 /* Force it to User CS */
363                 TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK;
364             }
365         }
366 
367         /* Handle SS Specially for validation */
368         KiSsToTrapFrame(TrapFrame, Context->SegSs);
369 
370         /* Write ESP back; take into account Edited Trap Frames */
371         KiEspToTrapFrame(TrapFrame, Context->Esp);
372 
373         /* Handle our V86 Bias if we went through a switch */
374         if (V86Switch) Ki386AdjustEsp0(TrapFrame);
375     }
376 
377     /* Process the Integer Registers */
378     if ((ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
379     {
380         /* Copy them manually */
381         TrapFrame->Eax = Context->Eax;
382         TrapFrame->Ebx = Context->Ebx;
383         TrapFrame->Ecx = Context->Ecx;
384         TrapFrame->Edx = Context->Edx;
385         TrapFrame->Esi = Context->Esi;
386         TrapFrame->Edi = Context->Edi;
387     }
388 
389     /* Process the Context Segments */
390     if ((ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
391     {
392         /* Check if we were in V86 Mode */
393         if (TrapFrame->EFlags & EFLAGS_V86_MASK)
394         {
395             /* Copy the V86 Segments directly */
396             TrapFrame->V86Ds = Context->SegDs;
397             TrapFrame->V86Es = Context->SegEs;
398             TrapFrame->V86Fs = Context->SegFs;
399             TrapFrame->V86Gs = Context->SegGs;
400         }
401         else if (!KiUserTrap(TrapFrame))
402         {
403             /* For kernel mode, write the standard values */
404             TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK;
405             TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK;
406             TrapFrame->SegFs = Ke386SanitizeSeg(Context->SegFs, PreviousMode);
407             TrapFrame->SegGs = 0;
408         }
409         else
410         {
411             /* For user mode, return the values directly */
412             TrapFrame->SegDs = Context->SegDs;
413             TrapFrame->SegEs = Context->SegEs;
414             TrapFrame->SegFs = Context->SegFs;
415 
416             /* Handle GS specially */
417             if (TrapFrame->SegCs == (KGDT_R3_CODE | RPL_MASK))
418             {
419                 /* Don't use it, if user */
420                 TrapFrame->SegGs = 0;
421             }
422             else
423             {
424                 /* Copy it if kernel */
425                 TrapFrame->SegGs = Context->SegGs;
426             }
427         }
428     }
429 
430     /* Handle the extended registers */
431     if (((ContextFlags & CONTEXT_EXTENDED_REGISTERS) ==
432         CONTEXT_EXTENDED_REGISTERS) && KiUserTrap(TrapFrame))
433     {
434         /* Get the FX Area */
435         FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
436 
437         /* Check if NPX is present */
438         if (KeI386NpxPresent)
439         {
440             /* Flush the NPX State */
441             KiFlushNPXState(NULL);
442 
443             /* Copy the FX State */
444             RtlCopyMemory(&FxSaveArea->U.FxArea,
445                           &Context->ExtendedRegisters[0],
446                           MAXIMUM_SUPPORTED_EXTENSION);
447 
448             /* Remove reserved bits from MXCSR */
449             FxSaveArea->U.FxArea.MXCsr &= KiMXCsrMask;
450 
451             /* Mask out any invalid flags */
452             FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS);
453 
454             /* Check if this is a VDM app */
455             if (PsGetCurrentProcess()->VdmObjects)
456             {
457                 /* Allow the EM flag */
458                 FxSaveArea->Cr0NpxState |= Context->FloatSave.Cr0NpxState &
459                                            (CR0_EM | CR0_MP);
460             }
461         }
462     }
463 
464     /* Handle the floating point state */
465     if (((ContextFlags & CONTEXT_FLOATING_POINT) ==
466         CONTEXT_FLOATING_POINT) && KiUserTrap(TrapFrame))
467     {
468         /* Get the FX Area */
469         FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
470 
471         /* Check if NPX is present */
472         if (KeI386NpxPresent)
473         {
474             /* Flush the NPX State */
475             KiFlushNPXState(NULL);
476 
477             /* Check if we have Fxsr support */
478             if (KeI386FxsrPresent)
479             {
480                 /* Convert the Fn Floating Point state to Fx */
481                 FxSaveArea->U.FxArea.ControlWord =
482                     (USHORT)Context->FloatSave.ControlWord;
483                 FxSaveArea->U.FxArea.StatusWord =
484                     (USHORT)Context->FloatSave.StatusWord;
485                 FxSaveArea->U.FxArea.TagWord =
486                     KiTagWordFnsaveToFxsave((USHORT)Context->FloatSave.TagWord);
487                 FxSaveArea->U.FxArea.ErrorOpcode =
488                     (USHORT)((Context->FloatSave.ErrorSelector >> 16) & 0xFFFF);
489                 FxSaveArea->U.FxArea.ErrorOffset =
490                     Context->FloatSave.ErrorOffset;
491                 FxSaveArea->U.FxArea.ErrorSelector =
492                     Context->FloatSave.ErrorSelector & 0xFFFF;
493                 FxSaveArea->U.FxArea.DataOffset =
494                     Context->FloatSave.DataOffset;
495                 FxSaveArea->U.FxArea.DataSelector =
496                     Context->FloatSave.DataSelector;
497 
498                 /* Clear out the Register Area */
499                 RtlZeroMemory(&FxSaveArea->U.FxArea.RegisterArea[0],
500                               SIZE_OF_FX_REGISTERS);
501 
502                 /* Loop the 8 floating point registers */
503                 for (i = 0; i < 8; i++)
504                 {
505                     /* Copy from Fn to Fx */
506                     RtlCopyMemory(FxSaveArea->U.FxArea.RegisterArea + (i * 16),
507                                   Context->FloatSave.RegisterArea + (i * 10),
508                                   10);
509                 }
510             }
511             else
512             {
513                 /* Copy the structure */
514                 FxSaveArea->U.FnArea.ControlWord = Context->FloatSave.
515                                                    ControlWord;
516                 FxSaveArea->U.FnArea.StatusWord = Context->FloatSave.
517                                                   StatusWord;
518                 FxSaveArea->U.FnArea.TagWord = Context->FloatSave.TagWord;
519                 FxSaveArea->U.FnArea.ErrorOffset = Context->FloatSave.
520                                                    ErrorOffset;
521                 FxSaveArea->U.FnArea.ErrorSelector = Context->FloatSave.
522                                                      ErrorSelector;
523                 FxSaveArea->U.FnArea.DataOffset = Context->FloatSave.
524                                                   DataOffset;
525                 FxSaveArea->U.FnArea.DataSelector = Context->FloatSave.
526                                                     DataSelector;
527 
528                 /* Loop registers */
529                 for (i = 0; i < SIZE_OF_80387_REGISTERS; i++)
530                 {
531                     /* Copy registers */
532                     FxSaveArea->U.FnArea.RegisterArea[i] =
533                         Context->FloatSave.RegisterArea[i];
534                 }
535             }
536 
537             /* Mask out any invalid flags */
538             FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS);
539 
540             /* Check if this is a VDM app */
541             if (PsGetCurrentProcess()->VdmObjects)
542             {
543                 /* Allow the EM flag */
544                 FxSaveArea->Cr0NpxState |= Context->FloatSave.Cr0NpxState &
545                     (CR0_EM | CR0_MP);
546             }
547         }
548         else
549         {
550             /* FIXME: Handle FPU Emulation */
551             //ASSERT(FALSE);
552             UNIMPLEMENTED;
553         }
554     }
555 
556     /* Handle the Debug Registers */
557     if ((ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
558     {
559         /* Copy Dr0 - Dr4 */
560         TrapFrame->Dr0 = Context->Dr0;
561         TrapFrame->Dr1 = Context->Dr1;
562         TrapFrame->Dr2 = Context->Dr2;
563         TrapFrame->Dr3 = Context->Dr3;
564 
565         /* If we're in user-mode */
566         if (PreviousMode != KernelMode)
567         {
568             /* Make sure, no Dr address is above user space */
569             if (Context->Dr0 > (ULONG)MmHighestUserAddress) TrapFrame->Dr0 = 0;
570             if (Context->Dr1 > (ULONG)MmHighestUserAddress) TrapFrame->Dr1 = 0;
571             if (Context->Dr2 > (ULONG)MmHighestUserAddress) TrapFrame->Dr2 = 0;
572             if (Context->Dr3 > (ULONG)MmHighestUserAddress) TrapFrame->Dr3 = 0;
573         }
574 
575         /* Now sanitize and save DR6 */
576         TrapFrame->Dr6 = Context->Dr6 & DR6_LEGAL;
577 
578         /* Update the Dr active mask */
579         if (TrapFrame->Dr0) DrMask |= DR_MASK(0);
580         if (TrapFrame->Dr1) DrMask |= DR_MASK(1);
581         if (TrapFrame->Dr2) DrMask |= DR_MASK(2);
582         if (TrapFrame->Dr3) DrMask |= DR_MASK(3);
583         if (TrapFrame->Dr6) DrMask |= DR_MASK(6);
584 
585         /* Sanitize and save DR7 */
586         TrapFrame->Dr7 = Context->Dr7 & DR7_LEGAL;
587         KiRecordDr7(&TrapFrame->Dr7, &DrMask);
588 
589         /* If we're in user-mode */
590         if (PreviousMode != KernelMode)
591         {
592             /* Save the mask */
593             KeGetCurrentThread()->Header.DebugActive = (UCHAR)DrMask;
594         }
595     }
596 
597     /* Check if thread has IOPL and force it enabled if so */
598     if (KeGetCurrentThread()->Iopl) TrapFrame->EFlags |= EFLAGS_IOPL;
599 
600     /* Restore IRQL */
601     if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
602 }
603 
604 VOID
605 NTAPI
606 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame,
607                      IN PKEXCEPTION_FRAME ExceptionFrame,
608                      IN OUT PCONTEXT Context)
609 {
610     PFX_SAVE_AREA FxSaveArea;
611     struct _AlignHack
612     {
613         UCHAR Hack[15];
614         FLOATING_SAVE_AREA UnalignedArea;
615     } FloatSaveBuffer;
616     FLOATING_SAVE_AREA *FloatSaveArea;
617     KIRQL OldIrql;
618     ULONG i;
619 
620     /* Do this at APC_LEVEL */
621     OldIrql = KeGetCurrentIrql();
622     if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
623 
624     /* Start with the Control flags */
625     if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
626     {
627         /* EBP, EIP and EFLAGS */
628         Context->Ebp = TrapFrame->Ebp;
629         Context->Eip = TrapFrame->Eip;
630         Context->EFlags = TrapFrame->EFlags;
631 
632         /* Return the correct CS */
633         if (!(TrapFrame->SegCs & FRAME_EDITED) &&
634             !(TrapFrame->EFlags & EFLAGS_V86_MASK))
635         {
636             /* Get it from the Temp location */
637             Context->SegCs = TrapFrame->TempSegCs & 0xFFFF;
638         }
639         else
640         {
641             /* Return it directly */
642             Context->SegCs = TrapFrame->SegCs & 0xFFFF;
643         }
644 
645         /* Get the Ss and ESP */
646         Context->SegSs = KiSsFromTrapFrame(TrapFrame);
647         Context->Esp = KiEspFromTrapFrame(TrapFrame);
648     }
649 
650     /* Handle the Segments */
651     if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
652     {
653         /* Do V86 Mode first */
654         if (TrapFrame->EFlags & EFLAGS_V86_MASK)
655         {
656             /* Return from the V86 location */
657             Context->SegGs = TrapFrame->V86Gs & 0xFFFF;
658             Context->SegFs = TrapFrame->V86Fs & 0xFFFF;
659             Context->SegEs = TrapFrame->V86Es & 0xFFFF;
660             Context->SegDs = TrapFrame->V86Ds & 0xFFFF;
661         }
662         else
663         {
664             /* Check if this was a Kernel Trap */
665             if (TrapFrame->SegCs == KGDT_R0_CODE)
666             {
667                 /* Set valid selectors */
668                 TrapFrame->SegGs = 0;
669                 TrapFrame->SegFs = KGDT_R0_PCR;
670                 TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK;
671                 TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK;
672             }
673 
674             /* Return the segments */
675             Context->SegGs = TrapFrame->SegGs & 0xFFFF;
676             Context->SegFs = TrapFrame->SegFs & 0xFFFF;
677             Context->SegEs = TrapFrame->SegEs & 0xFFFF;
678             Context->SegDs = TrapFrame->SegDs & 0xFFFF;
679         }
680     }
681 
682     /* Handle the simple registers */
683     if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
684     {
685         /* Return them directly */
686         Context->Eax = TrapFrame->Eax;
687         Context->Ebx = TrapFrame->Ebx;
688         Context->Ecx = TrapFrame->Ecx;
689         Context->Edx = TrapFrame->Edx;
690         Context->Esi = TrapFrame->Esi;
691         Context->Edi = TrapFrame->Edi;
692     }
693 
694     /* Handle extended registers */
695     if (((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) ==
696         CONTEXT_EXTENDED_REGISTERS) && KiUserTrap(TrapFrame))
697     {
698         /* Get the FX Save Area */
699         FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
700 
701         /* Make sure NPX is present */
702         if (KeI386NpxPresent)
703         {
704             /* Flush the NPX State */
705             KiFlushNPXState(NULL);
706 
707             /* Copy the registers */
708             RtlCopyMemory(&Context->ExtendedRegisters[0],
709                           &FxSaveArea->U.FxArea,
710                           MAXIMUM_SUPPORTED_EXTENSION);
711         }
712     }
713 
714     /* Handle Floating Point */
715     if (((Context->ContextFlags & CONTEXT_FLOATING_POINT) ==
716         CONTEXT_FLOATING_POINT) && KiUserTrap(TrapFrame))
717     {
718         /* Get the FX Save Area */
719         FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
720 
721         /* Make sure we have an NPX */
722         if (KeI386NpxPresent)
723          {
724             /* Check if we have Fxsr support */
725             if (KeI386FxsrPresent)
726             {
727                 /* Align the floating area to 16-bytes */
728                 FloatSaveArea = (FLOATING_SAVE_AREA*)
729                                 ((ULONG_PTR)&FloatSaveBuffer.UnalignedArea &~ 0xF);
730 
731                 /* Get the State */
732                 KiFlushNPXState(FloatSaveArea);
733             }
734             else
735             {
736                 /* We don't, use the FN area and flush the NPX State */
737                 FloatSaveArea = (FLOATING_SAVE_AREA*)&FxSaveArea->U.FnArea;
738                 KiFlushNPXState(NULL);
739             }
740 
741             /* Copy structure */
742             Context->FloatSave.ControlWord = FloatSaveArea->ControlWord;
743             Context->FloatSave.StatusWord = FloatSaveArea->StatusWord;
744             Context->FloatSave.TagWord = FloatSaveArea->TagWord;
745             Context->FloatSave.ErrorOffset = FloatSaveArea->ErrorOffset;
746             Context->FloatSave.ErrorSelector = FloatSaveArea->ErrorSelector;
747             Context->FloatSave.DataOffset = FloatSaveArea->DataOffset;
748             Context->FloatSave.DataSelector = FloatSaveArea->DataSelector;
749             Context->FloatSave.Cr0NpxState = FxSaveArea->Cr0NpxState;
750 
751             /* Loop registers */
752             for (i = 0; i < SIZE_OF_80387_REGISTERS; i++)
753             {
754                 /* Copy them */
755                 Context->FloatSave.RegisterArea[i] =
756                     FloatSaveArea->RegisterArea[i];
757             }
758          }
759          else
760          {
761             /* FIXME: Handle Emulation */
762             ASSERT(FALSE);
763          }
764     }
765 
766     /* Handle debug registers */
767     if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) ==
768         CONTEXT_DEBUG_REGISTERS)
769     {
770         /* Make sure DR7 is valid */
771         if (TrapFrame->Dr7 & ~DR7_RESERVED_MASK)
772         {
773             /* Copy the debug registers */
774             Context->Dr0 = TrapFrame->Dr0;
775             Context->Dr1 = TrapFrame->Dr1;
776             Context->Dr2 = TrapFrame->Dr2;
777             Context->Dr3 = TrapFrame->Dr3;
778             Context->Dr6 = TrapFrame->Dr6;
779 
780             /* Update DR7 */
781             Context->Dr7 = KiUpdateDr7(TrapFrame->Dr7);
782         }
783         else
784         {
785             /* Otherwise clear DR registers */
786             Context->Dr0 =
787             Context->Dr1 =
788             Context->Dr2 =
789             Context->Dr3 =
790             Context->Dr6 =
791             Context->Dr7 = 0;
792         }
793     }
794 
795     /* Restore IRQL */
796     if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
797 }
798 
799 BOOLEAN
800 FASTCALL
801 KeInvalidAccessAllowed(IN PVOID TrapInformation OPTIONAL)
802 {
803     ULONG Eip;
804     PKTRAP_FRAME TrapFrame = TrapInformation;
805     VOID NTAPI ExpInterlockedPopEntrySListFault(VOID);
806 
807     /* Don't do anything if we didn't get a trap frame */
808     if (!TrapInformation) return FALSE;
809 
810     /* Check where we came from */
811     switch (TrapFrame->SegCs)
812     {
813         /* Kernel mode */
814         case KGDT_R0_CODE:
815 
816             /* Allow S-LIST Routine to fail */
817             Eip = (ULONG)&ExpInterlockedPopEntrySListFault;
818             break;
819 
820         /* User code */
821         case KGDT_R3_CODE | RPL_MASK:
822 
823             /* Allow S-LIST Routine to fail */
824             //Eip = (ULONG)KeUserPopEntrySListFault;
825             Eip = 0;
826             break;
827 
828         default:
829 
830             /* Anything else gets a bugcheck */
831             Eip = 0;
832     }
833 
834     /* Return TRUE if we want to keep the system up */
835     return (TrapFrame->Eip == Eip) ? TRUE : FALSE;
836 }
837 
838 VOID
839 NTAPI
840 KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
841                     IN PKEXCEPTION_FRAME ExceptionFrame,
842                     IN PKTRAP_FRAME TrapFrame,
843                     IN KPROCESSOR_MODE PreviousMode,
844                     IN BOOLEAN FirstChance)
845 {
846     CONTEXT Context;
847     EXCEPTION_RECORD LocalExceptRecord;
848 
849     /* Increase number of Exception Dispatches */
850     KeGetCurrentPrcb()->KeExceptionDispatchCount++;
851 
852     /* Set the context flags */
853     Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
854 
855     /* Check if User Mode or if the kernel debugger is enabled */
856     if ((PreviousMode == UserMode) || (KeGetPcr()->KdVersionBlock))
857     {
858         /* Add the FPU Flag */
859         Context.ContextFlags |= CONTEXT_FLOATING_POINT;
860 
861         /* Check for NPX Support */
862         if (KeI386FxsrPresent)
863         {
864             /* Save those too */
865             Context.ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
866         }
867     }
868 
869     /* Get a Context */
870     KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
871 
872     /* Look at our exception code */
873     switch (ExceptionRecord->ExceptionCode)
874     {
875         /* Breakpoint */
876         case STATUS_BREAKPOINT:
877 
878             /* Decrement EIP by one */
879             Context.Eip--;
880             break;
881 
882         /* Internal exception */
883         case KI_EXCEPTION_ACCESS_VIOLATION:
884 
885             /* Set correct code */
886             ExceptionRecord->ExceptionCode = STATUS_ACCESS_VIOLATION;
887             if (PreviousMode == UserMode)
888             {
889                 /* FIXME: Handle no execute */
890             }
891             break;
892     }
893 
894     /* Sanity check */
895     ASSERT(!((PreviousMode == KernelMode) &&
896              (Context.EFlags & EFLAGS_V86_MASK)));
897 
898     /* Handle kernel-mode first, it's simpler */
899     if (PreviousMode == KernelMode)
900     {
901         /* Check if this is a first-chance exception */
902         if (FirstChance != FALSE)
903         {
904             /* Break into the debugger for the first time */
905             if (KiDebugRoutine(TrapFrame,
906                                ExceptionFrame,
907                                ExceptionRecord,
908                                &Context,
909                                PreviousMode,
910                                FALSE))
911             {
912                 /* Exception was handled */
913                 goto Handled;
914             }
915 
916             /* If the Debugger couldn't handle it, dispatch the exception */
917             if (RtlDispatchException(ExceptionRecord, &Context)) goto Handled;
918         }
919 
920         /* This is a second-chance exception, only for the debugger */
921         if (KiDebugRoutine(TrapFrame,
922                            ExceptionFrame,
923                            ExceptionRecord,
924                            &Context,
925                            PreviousMode,
926                            TRUE))
927         {
928             /* Exception was handled */
929             goto Handled;
930         }
931 
932         /* Third strike; you're out */
933         KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
934                      ExceptionRecord->ExceptionCode,
935                      (ULONG_PTR)ExceptionRecord->ExceptionAddress,
936                      (ULONG_PTR)TrapFrame,
937                      0);
938     }
939     else
940     {
941         /* User mode exception, was it first-chance? */
942         if (FirstChance)
943         {
944             /*
945              * Break into the kernel debugger unless a user mode debugger
946              * is present or user mode exceptions are ignored, except if this
947              * is a debug service which we must always pass to KD
948              */
949             if ((!(PsGetCurrentProcess()->DebugPort) &&
950                  !(KdIgnoreUmExceptions)) ||
951                  (KdIsThisAKdTrap(ExceptionRecord,
952                                   &Context,
953                                   PreviousMode)))
954             {
955                 /* Call the kernel debugger */
956                 if (KiDebugRoutine(TrapFrame,
957                                    ExceptionFrame,
958                                    ExceptionRecord,
959                                    &Context,
960                                    PreviousMode,
961                                    FALSE))
962                 {
963                     /* Exception was handled */
964                     goto Handled;
965                 }
966             }
967 
968             /* Forward exception to user mode debugger */
969             if (DbgkForwardException(ExceptionRecord, TRUE, FALSE)) return;
970 
971             /* Set up the user-stack */
972 DispatchToUser:
973             _SEH2_TRY
974             {
975                 ULONG Size;
976                 ULONG_PTR Stack, NewStack;
977 
978                 /* Make sure we have a valid SS and that this isn't V86 mode */
979                 if ((TrapFrame->HardwareSegSs != (KGDT_R3_DATA | RPL_MASK)) ||
980                     (TrapFrame->EFlags & EFLAGS_V86_MASK))
981                 {
982                     /* Raise an exception instead */
983                     LocalExceptRecord.ExceptionCode = STATUS_ACCESS_VIOLATION;
984                     LocalExceptRecord.ExceptionFlags = 0;
985                     LocalExceptRecord.NumberParameters = 0;
986                     RtlRaiseException(&LocalExceptRecord);
987                 }
988 
989                 /* Align context size and get stack pointer */
990                 Size = (sizeof(CONTEXT) + 3) & ~3;
991                 Stack = (Context.Esp & ~3) - Size;
992 
993                 /* Probe stack and copy Context */
994                 ProbeForWrite((PVOID)Stack, Size, sizeof(ULONG));
995                 RtlCopyMemory((PVOID)Stack, &Context, sizeof(CONTEXT));
996 
997                 /* Align exception record size and get stack pointer */
998                 Size = (sizeof(EXCEPTION_RECORD) -
999                        (EXCEPTION_MAXIMUM_PARAMETERS -
1000                         ExceptionRecord->NumberParameters) *
1001                        sizeof(ULONG) + 3) & ~3;
1002                 NewStack = Stack - Size;
1003 
1004                 /* Probe stack and copy exception record */
1005                 ProbeForWrite((PVOID)(NewStack - 2 * sizeof(ULONG_PTR)),
1006                               Size +  2 * sizeof(ULONG_PTR),
1007                               sizeof(ULONG));
1008                 RtlCopyMemory((PVOID)NewStack, ExceptionRecord, Size);
1009 
1010                 /* Now write the two params for the user-mode dispatcher */
1011                 *(PULONG_PTR)(NewStack - 1 * sizeof(ULONG_PTR)) = Stack;
1012                 *(PULONG_PTR)(NewStack - 2 * sizeof(ULONG_PTR)) = NewStack;
1013 
1014                 /* Set new Stack Pointer */
1015                 KiSsToTrapFrame(TrapFrame, KGDT_R3_DATA);
1016                 KiEspToTrapFrame(TrapFrame, NewStack - 2 * sizeof(ULONG_PTR));
1017 
1018                 /* Force correct segments */
1019                 TrapFrame->SegCs = Ke386SanitizeSeg(KGDT_R3_CODE, PreviousMode);
1020                 TrapFrame->SegDs = Ke386SanitizeSeg(KGDT_R3_DATA, PreviousMode);
1021                 TrapFrame->SegEs = Ke386SanitizeSeg(KGDT_R3_DATA, PreviousMode);
1022                 TrapFrame->SegFs = Ke386SanitizeSeg(KGDT_R3_TEB,  PreviousMode);
1023                 TrapFrame->SegGs = 0;
1024 
1025                 /* Set EIP to the User-mode Dispatcher */
1026                 TrapFrame->Eip = (ULONG)KeUserExceptionDispatcher;
1027 
1028                 /* Dispatch exception to user-mode */
1029                 _SEH2_YIELD(return);
1030             }
1031             _SEH2_EXCEPT((RtlCopyMemory(&LocalExceptRecord, _SEH2_GetExceptionInformation()->ExceptionRecord, sizeof(EXCEPTION_RECORD)), EXCEPTION_EXECUTE_HANDLER))
1032             {
1033                 /* Check if we got a stack overflow and raise that instead */
1034                 if ((NTSTATUS)LocalExceptRecord.ExceptionCode ==
1035                     STATUS_STACK_OVERFLOW)
1036                 {
1037                     /* Copy the exception address and record */
1038                     LocalExceptRecord.ExceptionAddress =
1039                         ExceptionRecord->ExceptionAddress;
1040                     RtlCopyMemory(ExceptionRecord,
1041                                   (PVOID)&LocalExceptRecord,
1042                                   sizeof(EXCEPTION_RECORD));
1043 
1044                     /* Do the exception again */
1045                     _SEH2_YIELD(goto DispatchToUser);
1046                 }
1047             }
1048             _SEH2_END;
1049 
1050             DPRINT("First chance exception in %.16s, ExceptionCode: %lx, ExceptionAddress: %p, P0: %lx, P1: %lx\n",
1051                    PsGetCurrentProcess()->ImageFileName,
1052                    ExceptionRecord->ExceptionCode,
1053                    ExceptionRecord->ExceptionAddress,
1054                    ExceptionRecord->ExceptionInformation[0],
1055                    ExceptionRecord->ExceptionInformation[1]);
1056         }
1057 
1058         /* Try second chance */
1059         if (DbgkForwardException(ExceptionRecord, TRUE, TRUE))
1060         {
1061             /* Handled, get out */
1062             return;
1063         }
1064         else if (DbgkForwardException(ExceptionRecord, FALSE, TRUE))
1065         {
1066             /* Handled, get out */
1067             return;
1068         }
1069 
1070         /* 3rd strike, kill the process */
1071         DPRINT1("Kill %.16s, ExceptionCode: %lx, ExceptionAddress: %p, BaseAddress: %p, P0: %lx, P1: %lx\n",
1072                 PsGetCurrentProcess()->ImageFileName,
1073                 ExceptionRecord->ExceptionCode,
1074                 ExceptionRecord->ExceptionAddress,
1075                 PsGetCurrentProcess()->SectionBaseAddress,
1076                 ExceptionRecord->ExceptionInformation[0],
1077                 ExceptionRecord->ExceptionInformation[1]);
1078 
1079         ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord->ExceptionCode);
1080         KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
1081                      ExceptionRecord->ExceptionCode,
1082                      (ULONG_PTR)ExceptionRecord->ExceptionAddress,
1083                      (ULONG_PTR)TrapFrame,
1084                      0);
1085     }
1086 
1087 Handled:
1088     /* Convert the context back into Trap/Exception Frames */
1089     KeContextToTrapFrame(&Context,
1090                          ExceptionFrame,
1091                          TrapFrame,
1092                          Context.ContextFlags,
1093                          PreviousMode);
1094     return;
1095 }
1096 
1097 DECLSPEC_NORETURN
1098 VOID
1099 NTAPI
1100 KiDispatchExceptionFromTrapFrame(IN NTSTATUS Code,
1101                                  IN ULONG Flags,
1102                                  IN ULONG_PTR Address,
1103                                  IN ULONG ParameterCount,
1104                                  IN ULONG_PTR Parameter1,
1105                                  IN ULONG_PTR Parameter2,
1106                                  IN ULONG_PTR Parameter3,
1107                                  IN PKTRAP_FRAME TrapFrame)
1108 {
1109     EXCEPTION_RECORD ExceptionRecord;
1110 
1111     /* Build the exception record */
1112     ExceptionRecord.ExceptionCode = Code;
1113     ExceptionRecord.ExceptionFlags = Flags;
1114     ExceptionRecord.ExceptionRecord = NULL;
1115     ExceptionRecord.ExceptionAddress = (PVOID)Address;
1116     ExceptionRecord.NumberParameters = ParameterCount;
1117     if (ParameterCount)
1118     {
1119         /* Copy extra parameters */
1120         ExceptionRecord.ExceptionInformation[0] = Parameter1;
1121         ExceptionRecord.ExceptionInformation[1] = Parameter2;
1122         ExceptionRecord.ExceptionInformation[2] = Parameter3;
1123     }
1124 
1125     /* Now go dispatch the exception */
1126     KiDispatchException(&ExceptionRecord,
1127                         NULL,
1128                         TrapFrame,
1129                         TrapFrame->EFlags & EFLAGS_V86_MASK ?
1130                         -1 : KiUserTrap(TrapFrame),
1131                         TRUE);
1132 
1133     /* Return from this trap */
1134     KiEoiHelper(TrapFrame);
1135 }
1136 
1137 DECLSPEC_NORETURN
1138 VOID
1139 FASTCALL
1140 KiSystemFatalException(IN ULONG ExceptionCode,
1141                        IN PKTRAP_FRAME TrapFrame)
1142 {
1143     /* Bugcheck the system */
1144     KeBugCheckWithTf(UNEXPECTED_KERNEL_MODE_TRAP,
1145                      ExceptionCode,
1146                      0,
1147                      0,
1148                      0,
1149                      TrapFrame);
1150 }
1151 
1152 /* PUBLIC FUNCTIONS ***********************************************************/
1153 
1154 /*
1155  * @implemented
1156  */
1157 NTSTATUS
1158 NTAPI
1159 KeRaiseUserException(IN NTSTATUS ExceptionCode)
1160 {
1161     ULONG OldEip;
1162     PTEB Teb = KeGetCurrentThread()->Teb;
1163     PKTRAP_FRAME TrapFrame = KeGetCurrentThread()->TrapFrame;
1164 
1165     /* Make sure we can access the TEB */
1166     _SEH2_TRY
1167     {
1168         /* Set the exception code */
1169         Teb->ExceptionCode = ExceptionCode;
1170     }
1171     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1172     {
1173         /* Return the exception code */
1174         _SEH2_YIELD(return _SEH2_GetExceptionCode());
1175     }
1176     _SEH2_END;
1177 
1178     /* Get the old EIP */
1179     OldEip = TrapFrame->Eip;
1180 
1181     /* Change it to the user-mode dispatcher */
1182     TrapFrame->Eip = (ULONG_PTR)KeRaiseUserExceptionDispatcher;
1183 
1184     /* Return the old EIP */
1185     return (NTSTATUS)OldEip;
1186 }
1187