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