87405e6032f3ce80efcdd791eedd8eb3a03f67b0
[reactos.git] / 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 (KiUserTrap(TrapFrame) ||
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 (KiUserTrap(TrapFrame) ||
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 (KiUserTrap(TrapFrame))
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 (KiUserTrap(TrapFrame))
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 -= sizeof(KTRAP_FRAME) -
295 FIELD_OFFSET(KTRAP_FRAME, V86Es);
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 (!KiUserTrap(TrapFrame))
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) && KiUserTrap(TrapFrame))
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) && KiUserTrap(TrapFrame))
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 UNIMPLEMENTED;
553 }
554 }
555
556 /* Handle the Debug Registers */
557 if ((ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
558 {
559 /* Copy Dr0 - Dr4 */
560 TrapFrame->Dr0 = Context->Dr0;
561 TrapFrame->Dr1 = Context->Dr1;
562 TrapFrame->Dr2 = Context->Dr2;
563 TrapFrame->Dr3 = Context->Dr3;
564
565 /* If we're in user-mode */
566 if (PreviousMode != KernelMode)
567 {
568 /* Make sure, no Dr address is above user space */
569 if (Context->Dr0 > (ULONG)MmHighestUserAddress) TrapFrame->Dr0 = 0;
570 if (Context->Dr1 > (ULONG)MmHighestUserAddress) TrapFrame->Dr1 = 0;
571 if (Context->Dr2 > (ULONG)MmHighestUserAddress) TrapFrame->Dr2 = 0;
572 if (Context->Dr3 > (ULONG)MmHighestUserAddress) TrapFrame->Dr3 = 0;
573 }
574
575 /* Now sanitize and save DR6 */
576 TrapFrame->Dr6 = Context->Dr6 & DR6_LEGAL;
577
578 /* Update the Dr active mask */
579 if (TrapFrame->Dr0) DrMask |= DR_MASK(0);
580 if (TrapFrame->Dr1) DrMask |= DR_MASK(1);
581 if (TrapFrame->Dr2) DrMask |= DR_MASK(2);
582 if (TrapFrame->Dr3) DrMask |= DR_MASK(3);
583 if (TrapFrame->Dr6) DrMask |= DR_MASK(6);
584
585 /* Sanitize and save DR7 */
586 TrapFrame->Dr7 = Context->Dr7 & DR7_LEGAL;
587 KiRecordDr7(&TrapFrame->Dr7, &DrMask);
588
589 /* If we're in user-mode */
590 if (PreviousMode != KernelMode)
591 {
592 /* Save the mask */
593 KeGetCurrentThread()->Header.DebugActive = (UCHAR)DrMask;
594 }
595 }
596
597 /* Check if thread has IOPL and force it enabled if so */
598 if (KeGetCurrentThread()->Iopl) TrapFrame->EFlags |= EFLAGS_IOPL;
599
600 /* Restore IRQL */
601 if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
602 }
603
604 VOID
605 NTAPI
606 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame,
607 IN PKEXCEPTION_FRAME ExceptionFrame,
608 IN OUT PCONTEXT Context)
609 {
610 PFX_SAVE_AREA FxSaveArea;
611 struct _AlignHack
612 {
613 UCHAR Hack[15];
614 FLOATING_SAVE_AREA UnalignedArea;
615 } FloatSaveBuffer;
616 FLOATING_SAVE_AREA *FloatSaveArea;
617 KIRQL OldIrql;
618 ULONG i;
619
620 /* Do this at APC_LEVEL */
621 OldIrql = KeGetCurrentIrql();
622 if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
623
624 /* Start with the Control flags */
625 if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
626 {
627 /* EBP, EIP and EFLAGS */
628 Context->Ebp = TrapFrame->Ebp;
629 Context->Eip = TrapFrame->Eip;
630 Context->EFlags = TrapFrame->EFlags;
631
632 /* Return the correct CS */
633 if (!(TrapFrame->SegCs & FRAME_EDITED) &&
634 !(TrapFrame->EFlags & EFLAGS_V86_MASK))
635 {
636 /* Get it from the Temp location */
637 Context->SegCs = TrapFrame->TempSegCs & 0xFFFF;
638 }
639 else
640 {
641 /* Return it directly */
642 Context->SegCs = TrapFrame->SegCs & 0xFFFF;
643 }
644
645 /* Get the Ss and ESP */
646 Context->SegSs = KiSsFromTrapFrame(TrapFrame);
647 Context->Esp = KiEspFromTrapFrame(TrapFrame);
648 }
649
650 /* Handle the Segments */
651 if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
652 {
653 /* Do V86 Mode first */
654 if (TrapFrame->EFlags & EFLAGS_V86_MASK)
655 {
656 /* Return from the V86 location */
657 Context->SegGs = TrapFrame->V86Gs & 0xFFFF;
658 Context->SegFs = TrapFrame->V86Fs & 0xFFFF;
659 Context->SegEs = TrapFrame->V86Es & 0xFFFF;
660 Context->SegDs = TrapFrame->V86Ds & 0xFFFF;
661 }
662 else
663 {
664 /* Check if this was a Kernel Trap */
665 if (TrapFrame->SegCs == KGDT_R0_CODE)
666 {
667 /* Set valid selectors */
668 TrapFrame->SegGs = 0;
669 TrapFrame->SegFs = KGDT_R0_PCR;
670 TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK;
671 TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK;
672 }
673
674 /* Return the segments */
675 Context->SegGs = TrapFrame->SegGs & 0xFFFF;
676 Context->SegFs = TrapFrame->SegFs & 0xFFFF;
677 Context->SegEs = TrapFrame->SegEs & 0xFFFF;
678 Context->SegDs = TrapFrame->SegDs & 0xFFFF;
679 }
680 }
681
682 /* Handle the simple registers */
683 if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
684 {
685 /* Return them directly */
686 Context->Eax = TrapFrame->Eax;
687 Context->Ebx = TrapFrame->Ebx;
688 Context->Ecx = TrapFrame->Ecx;
689 Context->Edx = TrapFrame->Edx;
690 Context->Esi = TrapFrame->Esi;
691 Context->Edi = TrapFrame->Edi;
692 }
693
694 /* Handle extended registers */
695 if (((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) ==
696 CONTEXT_EXTENDED_REGISTERS) && KiUserTrap(TrapFrame))
697 {
698 /* Get the FX Save Area */
699 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
700
701 /* Make sure NPX is present */
702 if (KeI386NpxPresent)
703 {
704 /* Flush the NPX State */
705 KiFlushNPXState(NULL);
706
707 /* Copy the registers */
708 RtlCopyMemory(&Context->ExtendedRegisters[0],
709 &FxSaveArea->U.FxArea,
710 MAXIMUM_SUPPORTED_EXTENSION);
711 }
712 }
713
714 /* Handle Floating Point */
715 if (((Context->ContextFlags & CONTEXT_FLOATING_POINT) ==
716 CONTEXT_FLOATING_POINT) && KiUserTrap(TrapFrame))
717 {
718 /* Get the FX Save Area */
719 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
720
721 /* Make sure we have an NPX */
722 if (KeI386NpxPresent)
723 {
724 /* Check if we have Fxsr support */
725 if (KeI386FxsrPresent)
726 {
727 /* Align the floating area to 16-bytes */
728 FloatSaveArea = (FLOATING_SAVE_AREA*)
729 ((ULONG_PTR)&FloatSaveBuffer.UnalignedArea &~ 0xF);
730
731 /* Get the State */
732 KiFlushNPXState(FloatSaveArea);
733 }
734 else
735 {
736 /* We don't, use the FN area and flush the NPX State */
737 FloatSaveArea = (FLOATING_SAVE_AREA*)&FxSaveArea->U.FnArea;
738 KiFlushNPXState(NULL);
739 }
740
741 /* Copy structure */
742 Context->FloatSave.ControlWord = FloatSaveArea->ControlWord;
743 Context->FloatSave.StatusWord = FloatSaveArea->StatusWord;
744 Context->FloatSave.TagWord = FloatSaveArea->TagWord;
745 Context->FloatSave.ErrorOffset = FloatSaveArea->ErrorOffset;
746 Context->FloatSave.ErrorSelector = FloatSaveArea->ErrorSelector;
747 Context->FloatSave.DataOffset = FloatSaveArea->DataOffset;
748 Context->FloatSave.DataSelector = FloatSaveArea->DataSelector;
749 Context->FloatSave.Cr0NpxState = FxSaveArea->Cr0NpxState;
750
751 /* Loop registers */
752 for (i = 0; i < SIZE_OF_80387_REGISTERS; i++)
753 {
754 /* Copy them */
755 Context->FloatSave.RegisterArea[i] =
756 FloatSaveArea->RegisterArea[i];
757 }
758 }
759 else
760 {
761 /* FIXME: Handle Emulation */
762 ASSERT(FALSE);
763 }
764 }
765
766 /* Handle debug registers */
767 if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) ==
768 CONTEXT_DEBUG_REGISTERS)
769 {
770 /* Make sure DR7 is valid */
771 if (TrapFrame->Dr7 & ~DR7_RESERVED_MASK)
772 {
773 /* Copy the debug registers */
774 Context->Dr0 = TrapFrame->Dr0;
775 Context->Dr1 = TrapFrame->Dr1;
776 Context->Dr2 = TrapFrame->Dr2;
777 Context->Dr3 = TrapFrame->Dr3;
778 Context->Dr6 = TrapFrame->Dr6;
779
780 /* Update DR7 */
781 Context->Dr7 = KiUpdateDr7(TrapFrame->Dr7);
782 }
783 else
784 {
785 /* Otherwise clear DR registers */
786 Context->Dr0 =
787 Context->Dr1 =
788 Context->Dr2 =
789 Context->Dr3 =
790 Context->Dr6 =
791 Context->Dr7 = 0;
792 }
793 }
794
795 /* Restore IRQL */
796 if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
797 }
798
799 BOOLEAN
800 FASTCALL
801 KeInvalidAccessAllowed(IN PVOID TrapInformation OPTIONAL)
802 {
803 ULONG Eip;
804 PKTRAP_FRAME TrapFrame = TrapInformation;
805 VOID NTAPI ExpInterlockedPopEntrySListFault(VOID);
806
807 /* Don't do anything if we didn't get a trap frame */
808 if (!TrapInformation) return FALSE;
809
810 /* Check where we came from */
811 switch (TrapFrame->SegCs)
812 {
813 /* Kernel mode */
814 case KGDT_R0_CODE:
815
816 /* Allow S-LIST Routine to fail */
817 Eip = (ULONG)&ExpInterlockedPopEntrySListFault;
818 break;
819
820 /* User code */
821 case KGDT_R3_CODE | RPL_MASK:
822
823 /* Allow S-LIST Routine to fail */
824 //Eip = (ULONG)KeUserPopEntrySListFault;
825 Eip = 0;
826 break;
827
828 default:
829
830 /* Anything else gets a bugcheck */
831 Eip = 0;
832 }
833
834 /* Return TRUE if we want to keep the system up */
835 return (TrapFrame->Eip == Eip) ? TRUE : FALSE;
836 }
837
838 VOID
839 NTAPI
840 KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
841 IN PKEXCEPTION_FRAME ExceptionFrame,
842 IN PKTRAP_FRAME TrapFrame,
843 IN KPROCESSOR_MODE PreviousMode,
844 IN BOOLEAN FirstChance)
845 {
846 CONTEXT Context;
847 EXCEPTION_RECORD LocalExceptRecord;
848
849 /* Increase number of Exception Dispatches */
850 KeGetCurrentPrcb()->KeExceptionDispatchCount++;
851
852 /* Set the context flags */
853 Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
854
855 /* Check if User Mode or if the kernel debugger is enabled */
856 if ((PreviousMode == UserMode) || (KeGetPcr()->KdVersionBlock))
857 {
858 /* Add the FPU Flag */
859 Context.ContextFlags |= CONTEXT_FLOATING_POINT;
860
861 /* Check for NPX Support */
862 if (KeI386FxsrPresent)
863 {
864 /* Save those too */
865 Context.ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
866 }
867 }
868
869 /* Get a Context */
870 KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
871
872 /* Look at our exception code */
873 switch (ExceptionRecord->ExceptionCode)
874 {
875 /* Breakpoint */
876 case STATUS_BREAKPOINT:
877
878 /* Decrement EIP by one */
879 Context.Eip--;
880 break;
881
882 /* Internal exception */
883 case KI_EXCEPTION_ACCESS_VIOLATION:
884
885 /* Set correct code */
886 ExceptionRecord->ExceptionCode = STATUS_ACCESS_VIOLATION;
887 if (PreviousMode == UserMode)
888 {
889 /* FIXME: Handle no execute */
890 }
891 break;
892 }
893
894 /* Sanity check */
895 ASSERT(!((PreviousMode == KernelMode) &&
896 (Context.EFlags & EFLAGS_V86_MASK)));
897
898 /* Handle kernel-mode first, it's simpler */
899 if (PreviousMode == KernelMode)
900 {
901 /* Check if this is a first-chance exception */
902 if (FirstChance != FALSE)
903 {
904 /* Break into the debugger for the first time */
905 if (KiDebugRoutine(TrapFrame,
906 ExceptionFrame,
907 ExceptionRecord,
908 &Context,
909 PreviousMode,
910 FALSE))
911 {
912 /* Exception was handled */
913 goto Handled;
914 }
915
916 /* If the Debugger couldn't handle it, dispatch the exception */
917 if (RtlDispatchException(ExceptionRecord, &Context)) goto Handled;
918 }
919
920 /* This is a second-chance exception, only for the debugger */
921 if (KiDebugRoutine(TrapFrame,
922 ExceptionFrame,
923 ExceptionRecord,
924 &Context,
925 PreviousMode,
926 TRUE))
927 {
928 /* Exception was handled */
929 goto Handled;
930 }
931
932 /* Third strike; you're out */
933 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
934 ExceptionRecord->ExceptionCode,
935 (ULONG_PTR)ExceptionRecord->ExceptionAddress,
936 (ULONG_PTR)TrapFrame,
937 0);
938 }
939 else
940 {
941 /* User mode exception, was it first-chance? */
942 if (FirstChance)
943 {
944 /*
945 * Break into the kernel debugger unless a user mode debugger
946 * is present or user mode exceptions are ignored, except if this
947 * is a debug service which we must always pass to KD
948 */
949 if ((!(PsGetCurrentProcess()->DebugPort) &&
950 !(KdIgnoreUmExceptions)) ||
951 (KdIsThisAKdTrap(ExceptionRecord,
952 &Context,
953 PreviousMode)))
954 {
955 /* Call the kernel debugger */
956 if (KiDebugRoutine(TrapFrame,
957 ExceptionFrame,
958 ExceptionRecord,
959 &Context,
960 PreviousMode,
961 FALSE))
962 {
963 /* Exception was handled */
964 goto Handled;
965 }
966 }
967
968 /* Forward exception to user mode debugger */
969 if (DbgkForwardException(ExceptionRecord, TRUE, FALSE)) return;
970
971 /* Set up the user-stack */
972 DispatchToUser:
973 _SEH2_TRY
974 {
975 ULONG Size;
976 ULONG_PTR Stack, NewStack;
977
978 /* Make sure we have a valid SS and that this isn't V86 mode */
979 if ((TrapFrame->HardwareSegSs != (KGDT_R3_DATA | RPL_MASK)) ||
980 (TrapFrame->EFlags & EFLAGS_V86_MASK))
981 {
982 /* Raise an exception instead */
983 LocalExceptRecord.ExceptionCode = STATUS_ACCESS_VIOLATION;
984 LocalExceptRecord.ExceptionFlags = 0;
985 LocalExceptRecord.NumberParameters = 0;
986 RtlRaiseException(&LocalExceptRecord);
987 }
988
989 /* Align context size and get stack pointer */
990 Size = (sizeof(CONTEXT) + 3) & ~3;
991 Stack = (Context.Esp & ~3) - Size;
992
993 /* Probe stack and copy Context */
994 ProbeForWrite((PVOID)Stack, Size, sizeof(ULONG));
995 RtlCopyMemory((PVOID)Stack, &Context, sizeof(CONTEXT));
996
997 /* Align exception record size and get stack pointer */
998 Size = (sizeof(EXCEPTION_RECORD) -
999 (EXCEPTION_MAXIMUM_PARAMETERS -
1000 ExceptionRecord->NumberParameters) *
1001 sizeof(ULONG) + 3) & ~3;
1002 NewStack = Stack - Size;
1003
1004 /* Probe stack and copy exception record */
1005 ProbeForWrite((PVOID)(NewStack - 2 * sizeof(ULONG_PTR)),
1006 Size + 2 * sizeof(ULONG_PTR),
1007 sizeof(ULONG));
1008 RtlCopyMemory((PVOID)NewStack, ExceptionRecord, Size);
1009
1010 /* Now write the two params for the user-mode dispatcher */
1011 *(PULONG_PTR)(NewStack - 1 * sizeof(ULONG_PTR)) = Stack;
1012 *(PULONG_PTR)(NewStack - 2 * sizeof(ULONG_PTR)) = NewStack;
1013
1014 /* Set new Stack Pointer */
1015 KiSsToTrapFrame(TrapFrame, KGDT_R3_DATA);
1016 KiEspToTrapFrame(TrapFrame, NewStack - 2 * sizeof(ULONG_PTR));
1017
1018 /* Force correct segments */
1019 TrapFrame->SegCs = Ke386SanitizeSeg(KGDT_R3_CODE, PreviousMode);
1020 TrapFrame->SegDs = Ke386SanitizeSeg(KGDT_R3_DATA, PreviousMode);
1021 TrapFrame->SegEs = Ke386SanitizeSeg(KGDT_R3_DATA, PreviousMode);
1022 TrapFrame->SegFs = Ke386SanitizeSeg(KGDT_R3_TEB, PreviousMode);
1023 TrapFrame->SegGs = 0;
1024
1025 /* Set EIP to the User-mode Dispatcher */
1026 TrapFrame->Eip = (ULONG)KeUserExceptionDispatcher;
1027
1028 /* Dispatch exception to user-mode */
1029 _SEH2_YIELD(return);
1030 }
1031 _SEH2_EXCEPT((RtlCopyMemory(&LocalExceptRecord, _SEH2_GetExceptionInformation()->ExceptionRecord, sizeof(EXCEPTION_RECORD)), EXCEPTION_EXECUTE_HANDLER))
1032 {
1033 /* Check if we got a stack overflow and raise that instead */
1034 if ((NTSTATUS)LocalExceptRecord.ExceptionCode ==
1035 STATUS_STACK_OVERFLOW)
1036 {
1037 /* Copy the exception address and record */
1038 LocalExceptRecord.ExceptionAddress =
1039 ExceptionRecord->ExceptionAddress;
1040 RtlCopyMemory(ExceptionRecord,
1041 (PVOID)&LocalExceptRecord,
1042 sizeof(EXCEPTION_RECORD));
1043
1044 /* Do the exception again */
1045 _SEH2_YIELD(goto DispatchToUser);
1046 }
1047 }
1048 _SEH2_END;
1049
1050 DPRINT("First chance exception in %.16s, ExceptionCode: %lx, ExceptionAddress: %p, P0: %lx, P1: %lx\n",
1051 PsGetCurrentProcess()->ImageFileName,
1052 ExceptionRecord->ExceptionCode,
1053 ExceptionRecord->ExceptionAddress,
1054 ExceptionRecord->ExceptionInformation[0],
1055 ExceptionRecord->ExceptionInformation[1]);
1056 }
1057
1058 /* Try second chance */
1059 if (DbgkForwardException(ExceptionRecord, TRUE, TRUE))
1060 {
1061 /* Handled, get out */
1062 return;
1063 }
1064 else if (DbgkForwardException(ExceptionRecord, FALSE, TRUE))
1065 {
1066 /* Handled, get out */
1067 return;
1068 }
1069
1070 /* 3rd strike, kill the process */
1071 DPRINT1("Kill %.16s, ExceptionCode: %lx, ExceptionAddress: %p, BaseAddress: %p, P0: %lx, P1: %lx\n",
1072 PsGetCurrentProcess()->ImageFileName,
1073 ExceptionRecord->ExceptionCode,
1074 ExceptionRecord->ExceptionAddress,
1075 PsGetCurrentProcess()->SectionBaseAddress,
1076 ExceptionRecord->ExceptionInformation[0],
1077 ExceptionRecord->ExceptionInformation[1]);
1078
1079 ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord->ExceptionCode);
1080 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
1081 ExceptionRecord->ExceptionCode,
1082 (ULONG_PTR)ExceptionRecord->ExceptionAddress,
1083 (ULONG_PTR)TrapFrame,
1084 0);
1085 }
1086
1087 Handled:
1088 /* Convert the context back into Trap/Exception Frames */
1089 KeContextToTrapFrame(&Context,
1090 ExceptionFrame,
1091 TrapFrame,
1092 Context.ContextFlags,
1093 PreviousMode);
1094 return;
1095 }
1096
1097 DECLSPEC_NORETURN
1098 VOID
1099 NTAPI
1100 KiDispatchExceptionFromTrapFrame(IN NTSTATUS Code,
1101 IN ULONG Flags,
1102 IN ULONG_PTR Address,
1103 IN ULONG ParameterCount,
1104 IN ULONG_PTR Parameter1,
1105 IN ULONG_PTR Parameter2,
1106 IN ULONG_PTR Parameter3,
1107 IN PKTRAP_FRAME TrapFrame)
1108 {
1109 EXCEPTION_RECORD ExceptionRecord;
1110
1111 /* Build the exception record */
1112 ExceptionRecord.ExceptionCode = Code;
1113 ExceptionRecord.ExceptionFlags = Flags;
1114 ExceptionRecord.ExceptionRecord = NULL;
1115 ExceptionRecord.ExceptionAddress = (PVOID)Address;
1116 ExceptionRecord.NumberParameters = ParameterCount;
1117 if (ParameterCount)
1118 {
1119 /* Copy extra parameters */
1120 ExceptionRecord.ExceptionInformation[0] = Parameter1;
1121 ExceptionRecord.ExceptionInformation[1] = Parameter2;
1122 ExceptionRecord.ExceptionInformation[2] = Parameter3;
1123 }
1124
1125 /* Now go dispatch the exception */
1126 KiDispatchException(&ExceptionRecord,
1127 NULL,
1128 TrapFrame,
1129 TrapFrame->EFlags & EFLAGS_V86_MASK ?
1130 -1 : KiUserTrap(TrapFrame),
1131 TRUE);
1132
1133 /* Return from this trap */
1134 KiEoiHelper(TrapFrame);
1135 }
1136
1137 DECLSPEC_NORETURN
1138 VOID
1139 FASTCALL
1140 KiSystemFatalException(IN ULONG ExceptionCode,
1141 IN PKTRAP_FRAME TrapFrame)
1142 {
1143 /* Bugcheck the system */
1144 KeBugCheckWithTf(UNEXPECTED_KERNEL_MODE_TRAP,
1145 ExceptionCode,
1146 0,
1147 0,
1148 0,
1149 TrapFrame);
1150 }
1151
1152 /* PUBLIC FUNCTIONS ***********************************************************/
1153
1154 /*
1155 * @implemented
1156 */
1157 NTSTATUS
1158 NTAPI
1159 KeRaiseUserException(IN NTSTATUS ExceptionCode)
1160 {
1161 ULONG OldEip;
1162 PTEB Teb = KeGetCurrentThread()->Teb;
1163 PKTRAP_FRAME TrapFrame = KeGetCurrentThread()->TrapFrame;
1164
1165 /* Make sure we can access the TEB */
1166 _SEH2_TRY
1167 {
1168 /* Set the exception code */
1169 Teb->ExceptionCode = ExceptionCode;
1170 }
1171 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1172 {
1173 /* Return the exception code */
1174 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1175 }
1176 _SEH2_END;
1177
1178 /* Get the old EIP */
1179 OldEip = TrapFrame->Eip;
1180
1181 /* Change it to the user-mode dispatcher */
1182 TrapFrame->Eip = (ULONG_PTR)KeRaiseUserExceptionDispatcher;
1183
1184 /* Return the old EIP */
1185 return (NTSTATUS)OldEip;
1186 }