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