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