xref: /reactos/ntoskrnl/ke/i386/exp.c (revision 99a6667b)
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
KeInitExceptions(VOID)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
KiUpdateDr7(IN ULONG Dr7)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
KiRecordDr7(OUT PULONG Dr7Ptr,OUT PULONG DrMask)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
KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame)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
KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame,IN ULONG Esp)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
KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame)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
KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame,IN ULONG Ss)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
KiTagWordFnsaveToFxsave(USHORT TagWord)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
Ki386AdjustEsp0(IN PKTRAP_FRAME TrapFrame)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
KeContextToTrapFrame(IN PCONTEXT Context,IN OUT PKEXCEPTION_FRAME ExceptionFrame,IN OUT PKTRAP_FRAME TrapFrame,IN ULONG ContextFlags,IN KPROCESSOR_MODE PreviousMode)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         /* Flush the NPX State */
438         KiFlushNPXState(NULL);
439 
440         /* Copy the FX State */
441         RtlCopyMemory(&FxSaveArea->U.FxArea,
442                       &Context->ExtendedRegisters[0],
443                       MAXIMUM_SUPPORTED_EXTENSION);
444 
445         /* Remove reserved bits from MXCSR */
446         FxSaveArea->U.FxArea.MXCsr &= KiMXCsrMask;
447 
448         /* Mask out any invalid flags */
449         FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS);
450 
451         /* Check if this is a VDM app */
452         if (PsGetCurrentProcess()->VdmObjects)
453         {
454             /* Allow the EM flag */
455             FxSaveArea->Cr0NpxState |= Context->FloatSave.Cr0NpxState & (CR0_EM | CR0_MP);
456         }
457     }
458 
459     /* Handle the floating point state */
460     if (((ContextFlags & CONTEXT_FLOATING_POINT) ==
461         CONTEXT_FLOATING_POINT) && KiUserTrap(TrapFrame))
462     {
463         /* Get the FX Area */
464         FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
465 
466         /* Flush the NPX State */
467         KiFlushNPXState(NULL);
468 
469         /* Check if we have Fxsr support */
470         if (KeI386FxsrPresent)
471         {
472             /* Convert the Fn Floating Point state to Fx */
473             FxSaveArea->U.FxArea.ControlWord = (USHORT)Context->FloatSave.ControlWord;
474             FxSaveArea->U.FxArea.StatusWord = (USHORT)Context->FloatSave.StatusWord;
475             FxSaveArea->U.FxArea.TagWord =
476                 KiTagWordFnsaveToFxsave((USHORT)Context->FloatSave.TagWord);
477             FxSaveArea->U.FxArea.ErrorOpcode =
478                 (USHORT)((Context->FloatSave.ErrorSelector >> 16) & 0xFFFF);
479             FxSaveArea->U.FxArea.ErrorOffset = Context->FloatSave.ErrorOffset;
480             FxSaveArea->U.FxArea.ErrorSelector = Context->FloatSave.ErrorSelector & 0xFFFF;
481             FxSaveArea->U.FxArea.DataOffset = Context->FloatSave.DataOffset;
482             FxSaveArea->U.FxArea.DataSelector = Context->FloatSave.DataSelector;
483 
484             /* Clear out the Register Area */
485             RtlZeroMemory(&FxSaveArea->U.FxArea.RegisterArea[0], SIZE_OF_FX_REGISTERS);
486 
487             /* Loop the 8 floating point registers */
488             for (i = 0; i < 8; i++)
489             {
490                 /* Copy from Fn to Fx */
491                 RtlCopyMemory(FxSaveArea->U.FxArea.RegisterArea + (i * 16),
492                               Context->FloatSave.RegisterArea + (i * 10),
493                               10);
494             }
495         }
496         else
497         {
498             /* Copy the structure */
499             FxSaveArea->U.FnArea.ControlWord = Context->FloatSave.ControlWord;
500             FxSaveArea->U.FnArea.StatusWord = Context->FloatSave.StatusWord;
501             FxSaveArea->U.FnArea.TagWord = Context->FloatSave.TagWord;
502             FxSaveArea->U.FnArea.ErrorOffset = Context->FloatSave.ErrorOffset;
503             FxSaveArea->U.FnArea.ErrorSelector = Context->FloatSave.ErrorSelector;
504             FxSaveArea->U.FnArea.DataOffset = Context->FloatSave.DataOffset;
505             FxSaveArea->U.FnArea.DataSelector = Context->FloatSave.DataSelector;
506 
507             /* Loop registers */
508             for (i = 0; i < SIZE_OF_80387_REGISTERS; i++)
509             {
510                 /* Copy registers */
511                 FxSaveArea->U.FnArea.RegisterArea[i] = Context->FloatSave.RegisterArea[i];
512             }
513         }
514 
515         /* Mask out any invalid flags */
516         FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS);
517 
518         /* Check if this is a VDM app */
519         if (PsGetCurrentProcess()->VdmObjects)
520         {
521             /* Allow the EM flag */
522             FxSaveArea->Cr0NpxState |= Context->FloatSave.Cr0NpxState & (CR0_EM | CR0_MP);
523         }
524     }
525 
526     /* Handle the Debug Registers */
527     if ((ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
528     {
529         /* Copy Dr0 - Dr4 */
530         TrapFrame->Dr0 = Context->Dr0;
531         TrapFrame->Dr1 = Context->Dr1;
532         TrapFrame->Dr2 = Context->Dr2;
533         TrapFrame->Dr3 = Context->Dr3;
534 
535         /* If we're in user-mode */
536         if (PreviousMode != KernelMode)
537         {
538             /* Make sure, no Dr address is above user space */
539             if (Context->Dr0 > (ULONG)MmHighestUserAddress) TrapFrame->Dr0 = 0;
540             if (Context->Dr1 > (ULONG)MmHighestUserAddress) TrapFrame->Dr1 = 0;
541             if (Context->Dr2 > (ULONG)MmHighestUserAddress) TrapFrame->Dr2 = 0;
542             if (Context->Dr3 > (ULONG)MmHighestUserAddress) TrapFrame->Dr3 = 0;
543         }
544 
545         /* Now sanitize and save DR6 */
546         TrapFrame->Dr6 = Context->Dr6 & DR6_LEGAL;
547 
548         /* Update the Dr active mask */
549         if (TrapFrame->Dr0) DrMask |= DR_MASK(0);
550         if (TrapFrame->Dr1) DrMask |= DR_MASK(1);
551         if (TrapFrame->Dr2) DrMask |= DR_MASK(2);
552         if (TrapFrame->Dr3) DrMask |= DR_MASK(3);
553         if (TrapFrame->Dr6) DrMask |= DR_MASK(6);
554 
555         /* Sanitize and save DR7 */
556         TrapFrame->Dr7 = Context->Dr7 & DR7_LEGAL;
557         KiRecordDr7(&TrapFrame->Dr7, &DrMask);
558 
559         /* If we're in user-mode */
560         if (PreviousMode != KernelMode)
561         {
562             /* Save the mask */
563             KeGetCurrentThread()->Header.DebugActive = (UCHAR)DrMask;
564         }
565     }
566 
567     /* Check if thread has IOPL and force it enabled if so */
568     if (KeGetCurrentThread()->Iopl) TrapFrame->EFlags |= EFLAGS_IOPL;
569 
570     /* Restore IRQL */
571     if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
572 }
573 
574 VOID
575 NTAPI
KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame,IN PKEXCEPTION_FRAME ExceptionFrame,IN OUT PCONTEXT Context)576 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame,
577                      IN PKEXCEPTION_FRAME ExceptionFrame,
578                      IN OUT PCONTEXT Context)
579 {
580     PFX_SAVE_AREA FxSaveArea;
581     struct _AlignHack
582     {
583         UCHAR Hack[15];
584         FLOATING_SAVE_AREA UnalignedArea;
585     } FloatSaveBuffer;
586     FLOATING_SAVE_AREA *FloatSaveArea;
587     KIRQL OldIrql;
588     ULONG i;
589 
590     /* Do this at APC_LEVEL */
591     OldIrql = KeGetCurrentIrql();
592     if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
593 
594     /* Start with the Control flags */
595     if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
596     {
597         /* EBP, EIP and EFLAGS */
598         Context->Ebp = TrapFrame->Ebp;
599         Context->Eip = TrapFrame->Eip;
600         Context->EFlags = TrapFrame->EFlags;
601 
602         /* Return the correct CS */
603         if (!(TrapFrame->SegCs & FRAME_EDITED) &&
604             !(TrapFrame->EFlags & EFLAGS_V86_MASK))
605         {
606             /* Get it from the Temp location */
607             Context->SegCs = TrapFrame->TempSegCs & 0xFFFF;
608         }
609         else
610         {
611             /* Return it directly */
612             Context->SegCs = TrapFrame->SegCs & 0xFFFF;
613         }
614 
615         /* Get the Ss and ESP */
616         Context->SegSs = KiSsFromTrapFrame(TrapFrame);
617         Context->Esp = KiEspFromTrapFrame(TrapFrame);
618     }
619 
620     /* Handle the Segments */
621     if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
622     {
623         /* Do V86 Mode first */
624         if (TrapFrame->EFlags & EFLAGS_V86_MASK)
625         {
626             /* Return from the V86 location */
627             Context->SegGs = TrapFrame->V86Gs & 0xFFFF;
628             Context->SegFs = TrapFrame->V86Fs & 0xFFFF;
629             Context->SegEs = TrapFrame->V86Es & 0xFFFF;
630             Context->SegDs = TrapFrame->V86Ds & 0xFFFF;
631         }
632         else
633         {
634             /* Check if this was a Kernel Trap */
635             if (TrapFrame->SegCs == KGDT_R0_CODE)
636             {
637                 /* Set valid selectors */
638                 TrapFrame->SegGs = 0;
639                 TrapFrame->SegFs = KGDT_R0_PCR;
640                 TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK;
641                 TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK;
642             }
643 
644             /* Return the segments */
645             Context->SegGs = TrapFrame->SegGs & 0xFFFF;
646             Context->SegFs = TrapFrame->SegFs & 0xFFFF;
647             Context->SegEs = TrapFrame->SegEs & 0xFFFF;
648             Context->SegDs = TrapFrame->SegDs & 0xFFFF;
649         }
650     }
651 
652     /* Handle the simple registers */
653     if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
654     {
655         /* Return them directly */
656         Context->Eax = TrapFrame->Eax;
657         Context->Ebx = TrapFrame->Ebx;
658         Context->Ecx = TrapFrame->Ecx;
659         Context->Edx = TrapFrame->Edx;
660         Context->Esi = TrapFrame->Esi;
661         Context->Edi = TrapFrame->Edi;
662     }
663 
664     /* Handle extended registers */
665     if (((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) ==
666         CONTEXT_EXTENDED_REGISTERS) && KiUserTrap(TrapFrame))
667     {
668         /* Get the FX Save Area */
669         FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
670 
671         /* Flush the NPX State */
672         KiFlushNPXState(NULL);
673 
674         /* Copy the registers */
675         RtlCopyMemory(&Context->ExtendedRegisters[0],
676                       &FxSaveArea->U.FxArea,
677                       MAXIMUM_SUPPORTED_EXTENSION);
678     }
679 
680     /* Handle Floating Point */
681     if (((Context->ContextFlags & CONTEXT_FLOATING_POINT) ==
682         CONTEXT_FLOATING_POINT) && KiUserTrap(TrapFrame))
683     {
684         /* Get the FX Save Area */
685         FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
686 
687         /* Check if we have Fxsr support */
688         if (KeI386FxsrPresent)
689         {
690             /* Align the floating area to 16-bytes */
691             FloatSaveArea = (FLOATING_SAVE_AREA*)((ULONG_PTR)&FloatSaveBuffer.UnalignedArea &~ 0xF);
692 
693             /* Get the State */
694             KiFlushNPXState(FloatSaveArea);
695         }
696         else
697         {
698             /* We don't, use the FN area and flush the NPX State */
699             FloatSaveArea = (FLOATING_SAVE_AREA*)&FxSaveArea->U.FnArea;
700             KiFlushNPXState(NULL);
701         }
702 
703         /* Copy structure */
704         Context->FloatSave.ControlWord = FloatSaveArea->ControlWord;
705         Context->FloatSave.StatusWord = FloatSaveArea->StatusWord;
706         Context->FloatSave.TagWord = FloatSaveArea->TagWord;
707         Context->FloatSave.ErrorOffset = FloatSaveArea->ErrorOffset;
708         Context->FloatSave.ErrorSelector = FloatSaveArea->ErrorSelector;
709         Context->FloatSave.DataOffset = FloatSaveArea->DataOffset;
710         Context->FloatSave.DataSelector = FloatSaveArea->DataSelector;
711         Context->FloatSave.Cr0NpxState = FxSaveArea->Cr0NpxState;
712 
713         /* Loop registers */
714         for (i = 0; i < SIZE_OF_80387_REGISTERS; i++)
715         {
716             /* Copy them */
717             Context->FloatSave.RegisterArea[i] = FloatSaveArea->RegisterArea[i];
718         }
719     }
720 
721     /* Handle debug registers */
722     if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) ==
723         CONTEXT_DEBUG_REGISTERS)
724     {
725         /* Make sure DR7 is valid */
726         if (TrapFrame->Dr7 & ~DR7_RESERVED_MASK)
727         {
728             /* Copy the debug registers */
729             Context->Dr0 = TrapFrame->Dr0;
730             Context->Dr1 = TrapFrame->Dr1;
731             Context->Dr2 = TrapFrame->Dr2;
732             Context->Dr3 = TrapFrame->Dr3;
733             Context->Dr6 = TrapFrame->Dr6;
734 
735             /* Update DR7 */
736             Context->Dr7 = KiUpdateDr7(TrapFrame->Dr7);
737         }
738         else
739         {
740             /* Otherwise clear DR registers */
741             Context->Dr0 =
742             Context->Dr1 =
743             Context->Dr2 =
744             Context->Dr3 =
745             Context->Dr6 =
746             Context->Dr7 = 0;
747         }
748     }
749 
750     /* Restore IRQL */
751     if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
752 }
753 
754 BOOLEAN
755 FASTCALL
KeInvalidAccessAllowed(IN PVOID TrapInformation OPTIONAL)756 KeInvalidAccessAllowed(IN PVOID TrapInformation OPTIONAL)
757 {
758     ULONG Eip;
759     PKTRAP_FRAME TrapFrame = TrapInformation;
760     VOID NTAPI ExpInterlockedPopEntrySListFault(VOID);
761 
762     /* Don't do anything if we didn't get a trap frame */
763     if (!TrapInformation) return FALSE;
764 
765     /* Check where we came from */
766     switch (TrapFrame->SegCs)
767     {
768         /* Kernel mode */
769         case KGDT_R0_CODE:
770 
771             /* Allow S-LIST Routine to fail */
772             Eip = (ULONG)&ExpInterlockedPopEntrySListFault;
773             break;
774 
775         /* User code */
776         case KGDT_R3_CODE | RPL_MASK:
777 
778             /* Allow S-LIST Routine to fail */
779             //Eip = (ULONG)KeUserPopEntrySListFault;
780             Eip = 0;
781             break;
782 
783         default:
784 
785             /* Anything else gets a bugcheck */
786             Eip = 0;
787     }
788 
789     /* Return TRUE if we want to keep the system up */
790     return (TrapFrame->Eip == Eip) ? TRUE : FALSE;
791 }
792 
793 VOID
794 NTAPI
KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,IN PKEXCEPTION_FRAME ExceptionFrame,IN PKTRAP_FRAME TrapFrame,IN KPROCESSOR_MODE PreviousMode,IN BOOLEAN FirstChance)795 KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
796                     IN PKEXCEPTION_FRAME ExceptionFrame,
797                     IN PKTRAP_FRAME TrapFrame,
798                     IN KPROCESSOR_MODE PreviousMode,
799                     IN BOOLEAN FirstChance)
800 {
801     CONTEXT Context;
802     EXCEPTION_RECORD LocalExceptRecord;
803 
804     /* Increase number of Exception Dispatches */
805     KeGetCurrentPrcb()->KeExceptionDispatchCount++;
806 
807     /* Set the context flags */
808     Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
809 
810     /* Check if User Mode or if the kernel debugger is enabled */
811     if ((PreviousMode == UserMode) || (KeGetPcr()->KdVersionBlock))
812     {
813         /* Add the FPU Flag */
814         Context.ContextFlags |= CONTEXT_FLOATING_POINT;
815 
816         /* Check for NPX Support */
817         if (KeI386FxsrPresent)
818         {
819             /* Save those too */
820             Context.ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
821         }
822     }
823 
824     /* Get a Context */
825     KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
826 
827     /* Look at our exception code */
828     switch (ExceptionRecord->ExceptionCode)
829     {
830         /* Breakpoint */
831         case STATUS_BREAKPOINT:
832 
833             /* Decrement EIP by one */
834             Context.Eip--;
835             break;
836 
837         /* Internal exception */
838         case KI_EXCEPTION_ACCESS_VIOLATION:
839 
840             /* Set correct code */
841             ExceptionRecord->ExceptionCode = STATUS_ACCESS_VIOLATION;
842             if (PreviousMode == UserMode)
843             {
844                 /* FIXME: Handle no execute */
845             }
846             break;
847     }
848 
849     /* Sanity check */
850     ASSERT(!((PreviousMode == KernelMode) &&
851              (Context.EFlags & EFLAGS_V86_MASK)));
852 
853     /* Handle kernel-mode first, it's simpler */
854     if (PreviousMode == KernelMode)
855     {
856         /* Check if this is a first-chance exception */
857         if (FirstChance != FALSE)
858         {
859             /* Break into the debugger for the first time */
860             if (KiDebugRoutine(TrapFrame,
861                                ExceptionFrame,
862                                ExceptionRecord,
863                                &Context,
864                                PreviousMode,
865                                FALSE))
866             {
867                 /* Exception was handled */
868                 goto Handled;
869             }
870 
871             /* If the Debugger couldn't handle it, dispatch the exception */
872             if (RtlDispatchException(ExceptionRecord, &Context)) goto Handled;
873         }
874 
875         /* This is a second-chance exception, only for the debugger */
876         if (KiDebugRoutine(TrapFrame,
877                            ExceptionFrame,
878                            ExceptionRecord,
879                            &Context,
880                            PreviousMode,
881                            TRUE))
882         {
883             /* Exception was handled */
884             goto Handled;
885         }
886 
887         /* Third strike; you're out */
888         KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
889                      ExceptionRecord->ExceptionCode,
890                      (ULONG_PTR)ExceptionRecord->ExceptionAddress,
891                      (ULONG_PTR)TrapFrame,
892                      0);
893     }
894     else
895     {
896         /* User mode exception, was it first-chance? */
897         if (FirstChance)
898         {
899             /*
900              * Break into the kernel debugger unless a user mode debugger
901              * is present or user mode exceptions are ignored, except if this
902              * is a debug service which we must always pass to KD
903              */
904             if ((!(PsGetCurrentProcess()->DebugPort) &&
905                  !(KdIgnoreUmExceptions)) ||
906                  (KdIsThisAKdTrap(ExceptionRecord,
907                                   &Context,
908                                   PreviousMode)))
909             {
910                 /* Call the kernel debugger */
911                 if (KiDebugRoutine(TrapFrame,
912                                    ExceptionFrame,
913                                    ExceptionRecord,
914                                    &Context,
915                                    PreviousMode,
916                                    FALSE))
917                 {
918                     /* Exception was handled */
919                     goto Handled;
920                 }
921             }
922 
923             /* Forward exception to user mode debugger */
924             if (DbgkForwardException(ExceptionRecord, TRUE, FALSE)) return;
925 
926             /* Set up the user-stack */
927 DispatchToUser:
928             _SEH2_TRY
929             {
930                 ULONG Size;
931                 ULONG_PTR Stack, NewStack;
932 
933                 /* Make sure we have a valid SS and that this isn't V86 mode */
934                 if ((TrapFrame->HardwareSegSs != (KGDT_R3_DATA | RPL_MASK)) ||
935                     (TrapFrame->EFlags & EFLAGS_V86_MASK))
936                 {
937                     /* Raise an exception instead */
938                     LocalExceptRecord.ExceptionCode = STATUS_ACCESS_VIOLATION;
939                     LocalExceptRecord.ExceptionFlags = 0;
940                     LocalExceptRecord.NumberParameters = 0;
941                     RtlRaiseException(&LocalExceptRecord);
942                 }
943 
944                 /* Align context size and get stack pointer */
945                 Size = (sizeof(CONTEXT) + 3) & ~3;
946                 Stack = (Context.Esp & ~3) - Size;
947 
948                 /* Probe stack and copy Context */
949                 ProbeForWrite((PVOID)Stack, Size, sizeof(ULONG));
950                 RtlCopyMemory((PVOID)Stack, &Context, sizeof(CONTEXT));
951 
952                 /* Align exception record size and get stack pointer */
953                 Size = (sizeof(EXCEPTION_RECORD) -
954                        (EXCEPTION_MAXIMUM_PARAMETERS -
955                         ExceptionRecord->NumberParameters) *
956                        sizeof(ULONG) + 3) & ~3;
957                 NewStack = Stack - Size;
958 
959                 /* Probe stack and copy exception record */
960                 ProbeForWrite((PVOID)(NewStack - 2 * sizeof(ULONG_PTR)),
961                               Size +  2 * sizeof(ULONG_PTR),
962                               sizeof(ULONG));
963                 RtlCopyMemory((PVOID)NewStack, ExceptionRecord, Size);
964 
965                 /* Now write the two params for the user-mode dispatcher */
966                 *(PULONG_PTR)(NewStack - 1 * sizeof(ULONG_PTR)) = Stack;
967                 *(PULONG_PTR)(NewStack - 2 * sizeof(ULONG_PTR)) = NewStack;
968 
969                 /* Set new Stack Pointer */
970                 KiSsToTrapFrame(TrapFrame, KGDT_R3_DATA);
971                 KiEspToTrapFrame(TrapFrame, NewStack - 2 * sizeof(ULONG_PTR));
972 
973                 /* Force correct segments */
974                 TrapFrame->SegCs = Ke386SanitizeSeg(KGDT_R3_CODE, PreviousMode);
975                 TrapFrame->SegDs = Ke386SanitizeSeg(KGDT_R3_DATA, PreviousMode);
976                 TrapFrame->SegEs = Ke386SanitizeSeg(KGDT_R3_DATA, PreviousMode);
977                 TrapFrame->SegFs = Ke386SanitizeSeg(KGDT_R3_TEB,  PreviousMode);
978                 TrapFrame->SegGs = 0;
979 
980                 /* Set EIP to the User-mode Dispatcher */
981                 TrapFrame->Eip = (ULONG)KeUserExceptionDispatcher;
982 
983                 /* Dispatch exception to user-mode */
984                 _SEH2_YIELD(return);
985             }
986             _SEH2_EXCEPT((RtlCopyMemory(&LocalExceptRecord, _SEH2_GetExceptionInformation()->ExceptionRecord, sizeof(EXCEPTION_RECORD)), EXCEPTION_EXECUTE_HANDLER))
987             {
988                 /* Check if we got a stack overflow and raise that instead */
989                 if ((NTSTATUS)LocalExceptRecord.ExceptionCode ==
990                     STATUS_STACK_OVERFLOW)
991                 {
992                     /* Copy the exception address and record */
993                     LocalExceptRecord.ExceptionAddress =
994                         ExceptionRecord->ExceptionAddress;
995                     RtlCopyMemory(ExceptionRecord,
996                                   (PVOID)&LocalExceptRecord,
997                                   sizeof(EXCEPTION_RECORD));
998 
999                     /* Do the exception again */
1000                     _SEH2_YIELD(goto DispatchToUser);
1001                 }
1002             }
1003             _SEH2_END;
1004 
1005             DPRINT("First chance exception in %.16s, ExceptionCode: %lx, ExceptionAddress: %p, P0: %lx, P1: %lx\n",
1006                    PsGetCurrentProcess()->ImageFileName,
1007                    ExceptionRecord->ExceptionCode,
1008                    ExceptionRecord->ExceptionAddress,
1009                    ExceptionRecord->ExceptionInformation[0],
1010                    ExceptionRecord->ExceptionInformation[1]);
1011         }
1012 
1013         /* Try second chance */
1014         if (DbgkForwardException(ExceptionRecord, TRUE, TRUE))
1015         {
1016             /* Handled, get out */
1017             return;
1018         }
1019         else if (DbgkForwardException(ExceptionRecord, FALSE, TRUE))
1020         {
1021             /* Handled, get out */
1022             return;
1023         }
1024 
1025         /* 3rd strike, kill the process */
1026         DPRINT1("Kill %.16s, ExceptionCode: %lx, ExceptionAddress: %p, BaseAddress: %p, P0: %lx, P1: %lx\n",
1027                 PsGetCurrentProcess()->ImageFileName,
1028                 ExceptionRecord->ExceptionCode,
1029                 ExceptionRecord->ExceptionAddress,
1030                 PsGetCurrentProcess()->SectionBaseAddress,
1031                 ExceptionRecord->ExceptionInformation[0],
1032                 ExceptionRecord->ExceptionInformation[1]);
1033 
1034         ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord->ExceptionCode);
1035         KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
1036                      ExceptionRecord->ExceptionCode,
1037                      (ULONG_PTR)ExceptionRecord->ExceptionAddress,
1038                      (ULONG_PTR)TrapFrame,
1039                      0);
1040     }
1041 
1042 Handled:
1043     /* Convert the context back into Trap/Exception Frames */
1044     KeContextToTrapFrame(&Context,
1045                          ExceptionFrame,
1046                          TrapFrame,
1047                          Context.ContextFlags,
1048                          PreviousMode);
1049     return;
1050 }
1051 
1052 DECLSPEC_NORETURN
1053 VOID
1054 NTAPI
KiDispatchExceptionFromTrapFrame(IN NTSTATUS Code,IN ULONG Flags,IN ULONG_PTR Address,IN ULONG ParameterCount,IN ULONG_PTR Parameter1,IN ULONG_PTR Parameter2,IN ULONG_PTR Parameter3,IN PKTRAP_FRAME TrapFrame)1055 KiDispatchExceptionFromTrapFrame(IN NTSTATUS Code,
1056                                  IN ULONG Flags,
1057                                  IN ULONG_PTR Address,
1058                                  IN ULONG ParameterCount,
1059                                  IN ULONG_PTR Parameter1,
1060                                  IN ULONG_PTR Parameter2,
1061                                  IN ULONG_PTR Parameter3,
1062                                  IN PKTRAP_FRAME TrapFrame)
1063 {
1064     EXCEPTION_RECORD ExceptionRecord;
1065 
1066     /* Build the exception record */
1067     ExceptionRecord.ExceptionCode = Code;
1068     ExceptionRecord.ExceptionFlags = Flags;
1069     ExceptionRecord.ExceptionRecord = NULL;
1070     ExceptionRecord.ExceptionAddress = (PVOID)Address;
1071     ExceptionRecord.NumberParameters = ParameterCount;
1072     if (ParameterCount)
1073     {
1074         /* Copy extra parameters */
1075         ExceptionRecord.ExceptionInformation[0] = Parameter1;
1076         ExceptionRecord.ExceptionInformation[1] = Parameter2;
1077         ExceptionRecord.ExceptionInformation[2] = Parameter3;
1078     }
1079 
1080     /* Now go dispatch the exception */
1081     KiDispatchException(&ExceptionRecord,
1082                         NULL,
1083                         TrapFrame,
1084                         TrapFrame->EFlags & EFLAGS_V86_MASK ?
1085                         -1 : KiUserTrap(TrapFrame),
1086                         TRUE);
1087 
1088     /* Return from this trap */
1089     KiEoiHelper(TrapFrame);
1090 }
1091 
1092 DECLSPEC_NORETURN
1093 VOID
1094 FASTCALL
KiSystemFatalException(IN ULONG ExceptionCode,IN PKTRAP_FRAME TrapFrame)1095 KiSystemFatalException(IN ULONG ExceptionCode,
1096                        IN PKTRAP_FRAME TrapFrame)
1097 {
1098     /* Bugcheck the system */
1099     KeBugCheckWithTf(UNEXPECTED_KERNEL_MODE_TRAP,
1100                      ExceptionCode,
1101                      0,
1102                      0,
1103                      0,
1104                      TrapFrame);
1105 }
1106 
1107 /* PUBLIC FUNCTIONS ***********************************************************/
1108 
1109 /*
1110  * @implemented
1111  */
1112 NTSTATUS
1113 NTAPI
KeRaiseUserException(IN NTSTATUS ExceptionCode)1114 KeRaiseUserException(IN NTSTATUS ExceptionCode)
1115 {
1116     ULONG OldEip;
1117     PTEB Teb = KeGetCurrentThread()->Teb;
1118     PKTRAP_FRAME TrapFrame = KeGetCurrentThread()->TrapFrame;
1119 
1120     /* Make sure we can access the TEB */
1121     _SEH2_TRY
1122     {
1123         /* Set the exception code */
1124         Teb->ExceptionCode = ExceptionCode;
1125     }
1126     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1127     {
1128         /* Return the exception code */
1129         _SEH2_YIELD(return _SEH2_GetExceptionCode());
1130     }
1131     _SEH2_END;
1132 
1133     /* Get the old EIP */
1134     OldEip = TrapFrame->Eip;
1135 
1136     /* Change it to the user-mode dispatcher */
1137     TrapFrame->Eip = (ULONG_PTR)KeRaiseUserExceptionDispatcher;
1138 
1139     /* Return the old EIP */
1140     return (NTSTATUS)OldEip;
1141 }
1142