- Fix critical bugs in exception handling: Unwinding was completely broken, using...
[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_ACTIVE_MASK)
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 &= 0x7F;
137 if (NewMask & DR_REG_MASK)
138 {
139 /* Set the active mask */
140 NewMask |= DR_ACTIVE_MASK;
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_ACTIVE_MASK;
158 NewMask |= 0x80;
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 ULONG Previous = KiEspFromTrapFrame(TrapFrame);
214
215 /* Check if this is user-mode or V86 */
216 if ((TrapFrame->SegCs & MODE_MASK) || (TrapFrame->EFlags & EFLAGS_V86_MASK))
217 {
218 /* Write it directly */
219 TrapFrame->HardwareEsp = Esp;
220 }
221 else
222 {
223 /* Don't allow ESP to be lowered, this is illegal */
224 if (Esp < Previous) KeBugCheck(SET_OF_INVALID_CONTEXT);
225
226 /* Create an edit frame, check if it was alrady */
227 if (!(TrapFrame->SegCs & FRAME_EDITED))
228 {
229 /* Update the value */
230 TrapFrame->TempEsp = Esp;
231 }
232 else
233 {
234 /* Check if ESP changed */
235 if (Previous != Esp)
236 {
237 /* Save CS */
238 TrapFrame->TempSegCs = TrapFrame->SegCs;
239 TrapFrame->SegCs &= ~FRAME_EDITED;
240
241 /* Save ESP */
242 TrapFrame->TempEsp = Esp;
243 }
244 }
245 }
246 }
247
248 ULONG
249 NTAPI
250 KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame)
251 {
252 /* 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 /* Usermode, 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 KeContextToTrapFrame(IN PCONTEXT Context,
311 IN OUT PKEXCEPTION_FRAME ExceptionFrame,
312 IN OUT PKTRAP_FRAME TrapFrame,
313 IN ULONG ContextFlags,
314 IN KPROCESSOR_MODE PreviousMode)
315 {
316 PFX_SAVE_AREA FxSaveArea;
317 ULONG i;
318 BOOLEAN V86Switch = FALSE;
319 KIRQL OldIrql = APC_LEVEL;
320 ULONG DrMask = 0;
321 PVOID SafeDr;
322
323 /* Do this at APC_LEVEL */
324 if (KeGetCurrentIrql() < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
325
326 /* Start with the basic Registers */
327 if ((ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
328 {
329 /* Check if we went through a V86 switch */
330 if ((Context->EFlags & EFLAGS_V86_MASK) !=
331 (TrapFrame->EFlags & EFLAGS_V86_MASK))
332 {
333 /* We did, remember this for later */
334 V86Switch = TRUE;
335 }
336
337 /* Copy EFLAGS and sanitize them*/
338 TrapFrame->EFlags = Ke386SanitizeFlags(Context->EFlags, PreviousMode);
339
340 /* Copy EBP and EIP */
341 TrapFrame->Ebp = Context->Ebp;
342 TrapFrame->Eip = Context->Eip;
343
344 /* Check if we were in V86 Mode */
345 if (TrapFrame->EFlags & EFLAGS_V86_MASK)
346 {
347 /* Simply copy the CS value */
348 TrapFrame->SegCs = Context->SegCs;
349 }
350 else
351 {
352 /* We weren't in V86, so sanitize the CS */
353 TrapFrame->SegCs = Ke386SanitizeSeg(Context->SegCs, PreviousMode);
354
355 /* Don't let it under 8, that's invalid */
356 if ((PreviousMode != KernelMode) && (TrapFrame->SegCs < 8))
357 {
358 /* Force it to User CS */
359 TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK;
360 }
361 }
362
363 /* Handle SS Specially for validation */
364 KiSsToTrapFrame(TrapFrame, Context->SegSs);
365
366 /* Write ESP back; take into account Edited Trap Frames */
367 KiEspToTrapFrame(TrapFrame, Context->Esp);
368
369 /* Handle our V86 Bias if we went through a switch */
370 if (V86Switch) Ki386AdjustEsp0(TrapFrame);
371 }
372
373 /* Process the Integer Registers */
374 if ((ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
375 {
376 /* Copy them manually */
377 TrapFrame->Eax = Context->Eax;
378 TrapFrame->Ebx = Context->Ebx;
379 TrapFrame->Ecx = Context->Ecx;
380 TrapFrame->Edx = Context->Edx;
381 TrapFrame->Esi = Context->Esi;
382 TrapFrame->Edi = Context->Edi;
383 }
384
385 /* Process the Context Segments */
386 if ((ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
387 {
388 /* Check if we were in V86 Mode */
389 if (TrapFrame->EFlags & EFLAGS_V86_MASK)
390 {
391 /* Copy the V86 Segments directly */
392 TrapFrame->V86Ds = Context->SegDs;
393 TrapFrame->V86Es = Context->SegEs;
394 TrapFrame->V86Fs = Context->SegFs;
395 TrapFrame->V86Gs = Context->SegGs;
396 }
397 else if (!(TrapFrame->SegCs & MODE_MASK))
398 {
399 /* For kernel mode, write the standard values */
400 TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK;
401 TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK;
402 TrapFrame->SegFs = Ke386SanitizeSeg(Context->SegFs, PreviousMode);
403 TrapFrame->SegGs = 0;
404 }
405 else
406 {
407 /* For user mode, return the values directly */
408 TrapFrame->SegDs = Context->SegDs;
409 TrapFrame->SegEs = Context->SegEs;
410 TrapFrame->SegFs = Context->SegFs;
411
412 /* Handle GS specially */
413 if (TrapFrame->SegCs == (KGDT_R3_CODE | RPL_MASK))
414 {
415 /* Don't use it, if user */
416 TrapFrame->SegGs = 0;
417 }
418 else
419 {
420 /* Copy it if kernel */
421 TrapFrame->SegGs = Context->SegGs;
422 }
423 }
424 }
425
426 /* Handle the extended registers */
427 if (((ContextFlags & CONTEXT_EXTENDED_REGISTERS) ==
428 CONTEXT_EXTENDED_REGISTERS) && (TrapFrame->SegCs & MODE_MASK))
429 {
430 /* Get the FX Area */
431 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
432
433 /* Check if NPX is present */
434 if (KeI386NpxPresent)
435 {
436 /* Flush the NPX State */
437 KiFlushNPXState(NULL);
438
439 /* Copy the FX State */
440 RtlCopyMemory(&FxSaveArea->U.FxArea,
441 &Context->ExtendedRegisters[0],
442 MAXIMUM_SUPPORTED_EXTENSION);
443
444 /* Remove reserved bits from MXCSR */
445 FxSaveArea->U.FxArea.MXCsr &= ~0xFFBF;
446
447 /* Mask out any invalid flags */
448 FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS);
449
450 /* Check if this is a VDM app */
451 if (PsGetCurrentProcess()->VdmObjects)
452 {
453 /* Allow the EM flag */
454 FxSaveArea->Cr0NpxState |= Context->FloatSave.Cr0NpxState &
455 (CR0_EM | CR0_MP);
456 }
457 }
458 }
459
460 /* Handle the floating point state */
461 if (((ContextFlags & CONTEXT_FLOATING_POINT) ==
462 CONTEXT_FLOATING_POINT) && (TrapFrame->SegCs & MODE_MASK))
463 {
464 /* Get the FX Area */
465 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
466
467 /* Check if NPX is present */
468 if (KeI386NpxPresent)
469 {
470 /* Flush the NPX State */
471 KiFlushNPXState(NULL);
472
473 /* Check if we have Fxsr support */
474 if (KeI386FxsrPresent)
475 {
476 /* Convert the Fn Floating Point state to Fx */
477 FxSaveArea->U.FxArea.ControlWord =
478 (USHORT)Context->FloatSave.ControlWord;
479 FxSaveArea->U.FxArea.StatusWord =
480 (USHORT)Context->FloatSave.StatusWord;
481 FxSaveArea->U.FxArea.TagWord =
482 KiTagWordFnsaveToFxsave((USHORT)Context->FloatSave.TagWord);
483 FxSaveArea->U.FxArea.ErrorOpcode =
484 (USHORT)((Context->FloatSave.ErrorSelector >> 16) & 0xFFFF);
485 FxSaveArea->U.FxArea.ErrorOffset =
486 Context->FloatSave.ErrorOffset;
487 FxSaveArea->U.FxArea.ErrorSelector =
488 Context->FloatSave.ErrorSelector & 0xFFFF;
489 FxSaveArea->U.FxArea.DataOffset =
490 Context->FloatSave.DataOffset;
491 FxSaveArea->U.FxArea.DataSelector =
492 Context->FloatSave.DataSelector;
493
494 /* Clear out the Register Area */
495 RtlZeroMemory(&FxSaveArea->U.FxArea.RegisterArea[0],
496 SIZE_OF_FX_REGISTERS);
497
498 /* Loop the 8 floating point registers */
499 for (i = 0; i < 8; i++)
500 {
501 /* Copy from Fn to Fx */
502 RtlCopyMemory(FxSaveArea->U.FxArea.RegisterArea + (i * 16),
503 Context->FloatSave.RegisterArea + (i * 10),
504 10);
505 }
506 }
507 else
508 {
509 /* Copy the structure */
510 FxSaveArea->U.FnArea.ControlWord = Context->FloatSave.
511 ControlWord;
512 FxSaveArea->U.FnArea.StatusWord = Context->FloatSave.
513 StatusWord;
514 FxSaveArea->U.FnArea.TagWord = Context->FloatSave.TagWord;
515 FxSaveArea->U.FnArea.ErrorOffset = Context->FloatSave.
516 ErrorOffset;
517 FxSaveArea->U.FnArea.ErrorSelector = Context->FloatSave.
518 ErrorSelector;
519 FxSaveArea->U.FnArea.DataOffset = Context->FloatSave.
520 DataOffset;
521 FxSaveArea->U.FnArea.DataSelector = Context->FloatSave.
522 DataSelector;
523
524 /* Loop registers */
525 for (i = 0; i < SIZE_OF_80387_REGISTERS; i++)
526 {
527 /* Copy registers */
528 FxSaveArea->U.FnArea.RegisterArea[i] =
529 Context->FloatSave.RegisterArea[i];
530 }
531 }
532
533 /* Mask out any invalid flags */
534 FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS);
535
536 /* Check if this is a VDM app */
537 if (PsGetCurrentProcess()->VdmObjects)
538 {
539 /* Allow the EM flag */
540 FxSaveArea->Cr0NpxState |= Context->FloatSave.Cr0NpxState &
541 (CR0_EM | CR0_MP);
542 }
543 }
544 else
545 {
546 /* FIXME: Handle FPU Emulation */
547 ASSERT(FALSE);
548 }
549 }
550
551 /* Handle the Debug Registers */
552 if ((ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
553 {
554 /* Loop DR registers */
555 for (i = 0; i < 4; i++)
556 {
557 /* Sanitize the context DR Address */
558 SafeDr = Ke386SanitizeDr(KiDrFromContext(i, Context), PreviousMode);
559
560 /* Save it in the trap frame */
561 *KiDrFromTrapFrame(i, TrapFrame) = SafeDr;
562
563 /* Check if this DR address is active and add it in the DR mask */
564 if (SafeDr) DrMask |= DR_MASK(i);
565 }
566
567 /* Now save and sanitize DR6 */
568 TrapFrame->Dr6 = Context->Dr6 & DR6_LEGAL;
569 if (TrapFrame->Dr6) DrMask |= DR_MASK(6);
570
571 /* Save and sanitize DR7 */
572 TrapFrame->Dr7 = Context->Dr7 & DR7_LEGAL;
573 KiRecordDr7(&TrapFrame->Dr7, &DrMask);
574
575 /* If we're in user-mode */
576 if (PreviousMode != KernelMode)
577 {
578 /* FIXME: Save the mask */
579 //KeGetCurrentThread()->DispatcherHeader.DebugActive = DrMask;
580 }
581 }
582
583 /* Check if thread has IOPL and force it enabled if so */
584 if (KeGetCurrentThread()->Iopl) TrapFrame->EFlags |= 0x3000;
585
586 /* Restore IRQL */
587 if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
588 }
589
590 VOID
591 NTAPI
592 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame,
593 IN PKEXCEPTION_FRAME ExceptionFrame,
594 IN OUT PCONTEXT Context)
595 {
596 PFX_SAVE_AREA FxSaveArea;
597 struct _AlignHack
598 {
599 UCHAR Hack[15];
600 FLOATING_SAVE_AREA UnalignedArea;
601 } FloatSaveBuffer;
602 FLOATING_SAVE_AREA *FloatSaveArea;
603 KIRQL OldIrql = APC_LEVEL;
604 ULONG i;
605
606 /* Do this at APC_LEVEL */
607 if (KeGetCurrentIrql() < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
608
609 /* Start with the Control flags */
610 if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
611 {
612 /* EBP, EIP and EFLAGS */
613 Context->Ebp = TrapFrame->Ebp;
614 Context->Eip = TrapFrame->Eip;
615 Context->EFlags = TrapFrame->EFlags;
616
617 /* Return the correct CS */
618 if (!(TrapFrame->SegCs & FRAME_EDITED) &&
619 !(TrapFrame->EFlags & EFLAGS_V86_MASK))
620 {
621 /* Get it from the Temp location */
622 Context->SegCs = TrapFrame->TempSegCs & 0xFFFF;
623 }
624 else
625 {
626 /* Return it directly */
627 Context->SegCs = TrapFrame->SegCs & 0xFFFF;
628 }
629
630 /* Get the Ss and ESP */
631 Context->SegSs = KiSsFromTrapFrame(TrapFrame);
632 Context->Esp = KiEspFromTrapFrame(TrapFrame);
633 }
634
635 /* Handle the Segments */
636 if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
637 {
638 /* Do V86 Mode first */
639 if (TrapFrame->EFlags & EFLAGS_V86_MASK)
640 {
641 /* Return from the V86 location */
642 Context->SegGs = TrapFrame->V86Gs & 0xFFFF;
643 Context->SegFs = TrapFrame->V86Fs & 0xFFFF;
644 Context->SegEs = TrapFrame->V86Es & 0xFFFF;
645 Context->SegDs = TrapFrame->V86Ds & 0xFFFF;
646 }
647 else
648 {
649 /* Check if this was a Kernel Trap */
650 if (TrapFrame->SegCs == KGDT_R0_CODE)
651 {
652 /* Set valid selectors */
653 TrapFrame->SegGs = 0;
654 TrapFrame->SegFs = KGDT_R0_PCR;
655 TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK;
656 TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK;
657 }
658
659 /* Return the segments */
660 Context->SegGs = TrapFrame->SegGs & 0xFFFF;
661 Context->SegFs = TrapFrame->SegFs & 0xFFFF;
662 Context->SegEs = TrapFrame->SegEs & 0xFFFF;
663 Context->SegDs = TrapFrame->SegDs & 0xFFFF;
664 }
665 }
666
667 /* Handle the simple registers */
668 if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
669 {
670 /* Return them directly */
671 Context->Eax = TrapFrame->Eax;
672 Context->Ebx = TrapFrame->Ebx;
673 Context->Ecx = TrapFrame->Ecx;
674 Context->Edx = TrapFrame->Edx;
675 Context->Esi = TrapFrame->Esi;
676 Context->Edi = TrapFrame->Edi;
677 }
678
679 /* Handle extended registers */
680 if (((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) ==
681 CONTEXT_EXTENDED_REGISTERS) && (TrapFrame->SegCs & MODE_MASK))
682 {
683 /* Get the FX Save Area */
684 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
685
686 /* Make sure NPX is present */
687 if (KeI386NpxPresent)
688 {
689 /* Flush the NPX State */
690 KiFlushNPXState(NULL);
691
692 /* Copy the registers */
693 RtlCopyMemory(&Context->ExtendedRegisters[0],
694 &FxSaveArea->U.FxArea,
695 MAXIMUM_SUPPORTED_EXTENSION);
696 }
697 }
698
699 /* Handle Floating Point */
700 if (((Context->ContextFlags & CONTEXT_FLOATING_POINT) ==
701 CONTEXT_FLOATING_POINT) && (TrapFrame->SegCs & MODE_MASK))
702 {
703 /* Get the FX Save Area */
704 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
705
706 /* Make sure we have an NPX */
707 if (KeI386NpxPresent)
708 {
709 /* Check if we have Fxsr support */
710 if (KeI386FxsrPresent)
711 {
712 /* Align the floating area to 16-bytes */
713 FloatSaveArea = (FLOATING_SAVE_AREA*)
714 ((ULONG_PTR)&FloatSaveBuffer.UnalignedArea &~ 0xF);
715
716 /* Get the State */
717 KiFlushNPXState(FloatSaveArea);
718 }
719 else
720 {
721 /* We don't, use the FN area and flush the NPX State */
722 FloatSaveArea = (FLOATING_SAVE_AREA*)&FxSaveArea->U.FnArea;
723 KiFlushNPXState(NULL);
724 }
725
726 /* Copy structure */
727 Context->FloatSave.ControlWord = FloatSaveArea->ControlWord;
728 Context->FloatSave.StatusWord = FloatSaveArea->StatusWord;
729 Context->FloatSave.TagWord = FloatSaveArea->TagWord;
730 Context->FloatSave.ErrorOffset = FloatSaveArea->ErrorOffset;
731 Context->FloatSave.ErrorSelector = FloatSaveArea->ErrorSelector;
732 Context->FloatSave.DataOffset = FloatSaveArea->DataOffset;
733 Context->FloatSave.DataSelector = FloatSaveArea->DataSelector;
734 Context->FloatSave.Cr0NpxState = FxSaveArea->Cr0NpxState;
735
736 /* Loop registers */
737 for (i = 0; i < SIZE_OF_80387_REGISTERS; i++)
738 {
739 /* Copy them */
740 Context->FloatSave.RegisterArea[i] =
741 FloatSaveArea->RegisterArea[i];
742 }
743 }
744 else
745 {
746 /* FIXME: Handle Emulation */
747 ASSERT(FALSE);
748 }
749 }
750
751 /* Handle debug registers */
752 if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) ==
753 CONTEXT_DEBUG_REGISTERS)
754 {
755 /* Make sure DR7 is valid */
756 if (TrapFrame->Dr7 & ~DR7_RESERVED_MASK)
757 {
758 /* Copy the debug registers */
759 Context->Dr0 = TrapFrame->Dr0;
760 Context->Dr1 = TrapFrame->Dr1;
761 Context->Dr2 = TrapFrame->Dr2;
762 Context->Dr3 = TrapFrame->Dr3;
763 Context->Dr6 = TrapFrame->Dr6;
764
765 /* Update DR7 */
766 //Context->Dr7 = KiUpdateDr7(TrapFrame->Dr7);
767 }
768 else
769 {
770 /* Otherwise clear DR registers */
771 Context->Dr0 =
772 Context->Dr1 =
773 Context->Dr3 =
774 Context->Dr6 =
775 Context->Dr7 = 0;
776 }
777 }
778
779 /* Restore IRQL */
780 if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
781 }
782
783 VOID
784 NTAPI
785 KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
786 IN PKEXCEPTION_FRAME ExceptionFrame,
787 IN PKTRAP_FRAME TrapFrame,
788 IN KPROCESSOR_MODE PreviousMode,
789 IN BOOLEAN FirstChance)
790 {
791 CONTEXT Context;
792 ULONG_PTR Stack, NewStack;
793 ULONG Size;
794 EXCEPTION_RECORD LocalExceptRecord;
795 _SEH_DECLARE_LOCALS(KiCopyInfo);
796
797 /* Increase number of Exception Dispatches */
798 KeGetCurrentPrcb()->KeExceptionDispatchCount++;
799
800 /* Set the context flags */
801 Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
802
803 /* Check if User Mode or if the debugger isenabled */
804 if ((PreviousMode == UserMode) || (KdDebuggerEnabled))
805 {
806 /* Add the FPU Flag */
807 Context.ContextFlags |= CONTEXT_FLOATING_POINT;
808
809 /* Check for NPX Support */
810 if (KeI386FxsrPresent)
811 {
812 /* Save those too */
813 Context.ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
814 }
815 }
816
817 /* Get a Context */
818 KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
819
820 /* Fix up EIP */
821 if (ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT)
822 {
823 /* Decrement EIP by one */
824 Context.Eip--;
825 }
826
827 /* Sanity check */
828 ASSERT(!((PreviousMode == KernelMode) &&
829 (Context.EFlags & EFLAGS_V86_MASK)));
830
831 /* Handle kernel-mode first, it's simpler */
832 if (PreviousMode == KernelMode)
833 {
834 /* Check if this is a first-chance exception */
835 if (FirstChance == TRUE)
836 {
837 /* Break into the debugger for the first time */
838 if (KiDebugRoutine(TrapFrame,
839 ExceptionFrame,
840 ExceptionRecord,
841 &Context,
842 PreviousMode,
843 FALSE))
844 {
845 /* Exception was handled */
846 goto Handled;
847 }
848
849 /* HACK: GDB Entry */
850 if (KdpCallGdb(TrapFrame, ExceptionRecord, &Context)) goto Handled;
851
852 /* If the Debugger couldn't handle it, dispatch the exception */
853 if (RtlDispatchException(ExceptionRecord, &Context)) goto Handled;
854 }
855
856 /* This is a second-chance exception, only for the debugger */
857 if (KiDebugRoutine(TrapFrame,
858 ExceptionFrame,
859 ExceptionRecord,
860 &Context,
861 PreviousMode,
862 TRUE))
863 {
864 /* Exception was handled */
865 goto Handled;
866 }
867
868 /* Third strike; you're out */
869 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
870 ExceptionRecord->ExceptionCode,
871 (ULONG_PTR)ExceptionRecord->ExceptionAddress,
872 ExceptionRecord->ExceptionInformation[0],
873 ExceptionRecord->ExceptionInformation[1]);
874 }
875 else
876 {
877 /* User mode exception, was it first-chance? */
878 if (FirstChance)
879 {
880 /* Enter Debugger if available */
881 if (PsGetCurrentProcess()->DebugPort)
882 {
883 /* FIXME : TODO */
884 //KEBUGCHECK(0);
885 }
886 else if (KiDebugRoutine(TrapFrame,
887 ExceptionFrame,
888 ExceptionRecord,
889 &Context,
890 PreviousMode,
891 FALSE))
892 {
893 /* Exception was handled */
894 goto Handled;
895 }
896
897 /* HACK: GDB Entry */
898 if (KdpCallGdb(TrapFrame, ExceptionRecord, &Context)) goto Handled;
899
900 /* Forward exception to user mode debugger */
901 if (DbgkForwardException(ExceptionRecord, TRUE, FALSE)) goto Exit;
902
903 /* Set up the user-stack */
904 DispatchToUser:
905 _SEH_TRY
906 {
907 /* Make sure we have a valid SS and that this isn't V86 mode */
908 if ((TrapFrame->HardwareSegSs != (KGDT_R3_DATA | RPL_MASK)) ||
909 (TrapFrame->EFlags & EFLAGS_V86_MASK))
910 {
911 /* Raise an exception instead */
912 LocalExceptRecord.ExceptionCode = STATUS_ACCESS_VIOLATION;
913 LocalExceptRecord.ExceptionFlags = 0;
914 LocalExceptRecord.NumberParameters = 0;
915 RtlRaiseException(&LocalExceptRecord);
916 }
917
918 /* Align context size and get stack pointer */
919 Size = (sizeof(CONTEXT) + 3) & ~3;
920 Stack = (Context.Esp & ~3) - Size;
921
922 /* Probe stack and copy Context */
923 ProbeForWrite((PVOID)Stack, Size, sizeof(ULONG));
924 RtlCopyMemory((PVOID)Stack, &Context, sizeof(CONTEXT));
925
926 /* Align exception record size and get stack pointer */
927 Size = (sizeof(EXCEPTION_RECORD) -
928 (EXCEPTION_MAXIMUM_PARAMETERS -
929 ExceptionRecord->NumberParameters) *
930 sizeof(ULONG) + 3) & ~3;
931 NewStack = Stack - Size;
932
933 /* Probe stack and copy exception record */
934 ProbeForWrite((PVOID)(NewStack - 2 * sizeof(ULONG_PTR)),
935 Size + 2 * sizeof(ULONG_PTR),
936 sizeof(ULONG));
937 RtlCopyMemory((PVOID)NewStack, ExceptionRecord, Size);
938
939 /* Now write the two params for the user-mode dispatcher */
940 *(PULONG_PTR)(NewStack - 1 * sizeof(ULONG_PTR)) = Stack;
941 *(PULONG_PTR)(NewStack - 2 * sizeof(ULONG_PTR)) = NewStack;
942
943 /* Set new Stack Pointer */
944 KiSsToTrapFrame(TrapFrame, KGDT_R3_DATA);
945 KiEspToTrapFrame(TrapFrame, NewStack - 2 * sizeof(ULONG_PTR));
946
947 /* Force correct segments */
948 TrapFrame->SegCs = Ke386SanitizeSeg(KGDT_R3_CODE, PreviousMode);
949 TrapFrame->SegDs = Ke386SanitizeSeg(KGDT_R3_DATA, PreviousMode);
950 TrapFrame->SegEs = Ke386SanitizeSeg(KGDT_R3_DATA, PreviousMode);
951 TrapFrame->SegFs = Ke386SanitizeSeg(KGDT_R3_TEB, PreviousMode);
952 TrapFrame->SegGs = 0;
953
954 /* Set EIP to the User-mode Dispatcher */
955 TrapFrame->Eip = (ULONG)KeUserExceptionDispatcher;
956 _SEH_LEAVE;
957 }
958 _SEH_EXCEPT(KiCopyInformation)
959 {
960 /* Check if we got a stack overflow and raise that instead */
961 if (_SEH_VAR(SehExceptRecord).ExceptionCode ==
962 STATUS_STACK_OVERFLOW)
963 {
964 /* Copy the exception address and record */
965 _SEH_VAR(SehExceptRecord).ExceptionAddress =
966 ExceptionRecord->ExceptionAddress;
967 RtlCopyMemory(ExceptionRecord,
968 (PVOID)&_SEH_VAR(SehExceptRecord),
969 sizeof(EXCEPTION_RECORD));
970
971 /* Do the exception again */
972 goto DispatchToUser;
973 }
974 }
975 _SEH_END;
976
977 /* Dispatch exception to user-mode */
978 return;
979 }
980
981 /* Try second chance */
982 if (DbgkForwardException(ExceptionRecord, TRUE, FALSE))
983 {
984 /* Handled, get out */
985 goto Exit;
986 }
987 else if (DbgkForwardException(ExceptionRecord, FALSE, TRUE))
988 {
989 /* Handled, get out */
990 goto Exit;
991 }
992
993 /* 3rd strike, kill the process */
994 ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord->ExceptionCode);
995 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
996 ExceptionRecord->ExceptionCode,
997 (ULONG_PTR)ExceptionRecord->ExceptionAddress,
998 ExceptionRecord->ExceptionInformation[0],
999 ExceptionRecord->ExceptionInformation[1]);
1000 }
1001
1002 Handled:
1003 /* Convert the context back into Trap/Exception Frames */
1004 KeContextToTrapFrame(&Context,
1005 ExceptionFrame,
1006 TrapFrame,
1007 Context.ContextFlags,
1008 PreviousMode);
1009 Exit:
1010 return;
1011 }
1012
1013 /*
1014 * @implemented
1015 */
1016 NTSTATUS
1017 NTAPI
1018 KeRaiseUserException(IN NTSTATUS ExceptionCode)
1019 {
1020 NTSTATUS Status = STATUS_SUCCESS;
1021 ULONG OldEip;
1022 PTEB Teb = KeGetCurrentThread()->Teb;
1023 PKTRAP_FRAME TrapFrame = KeGetCurrentThread()->TrapFrame;
1024
1025 /* Make sure we can access the TEB */
1026 _SEH_TRY
1027 {
1028 /* Set the exception code */
1029 Teb->ExceptionCode = ExceptionCode;
1030 }
1031 _SEH_HANDLE
1032 {
1033 /* Save exception code */
1034 Status = ExceptionCode;
1035 }
1036 _SEH_END;
1037 if (!NT_SUCCESS(Status)) return Status;
1038
1039 /* Get the old EIP */
1040 OldEip = TrapFrame->Eip;
1041
1042 /* Change it to the user-mode dispatcher */
1043 TrapFrame->Eip = (ULONG_PTR)KeRaiseUserExceptionDispatcher;
1044
1045 /* Return the old EIP */
1046 return (NTSTATUS)OldEip;
1047 }
1048