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