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