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