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