SYSENTER support, INT2E Optimization, new Syscall Table/Stub generator and svn:ignore...
[reactos.git] / reactos / ntoskrnl / ke / i386 / exp.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /*
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/ke/i386/exp.c
22 * PURPOSE: Handling exceptions
23 * PROGRAMMERS: David Welch (welch@cwcom.net)
24 * Skywing (skywing@valhallalegends.com)
25 * REVISION HISTORY:
26 * ??/??/??: Created
27 * 09/12/03: KeRaiseUserException added (Skywing).
28 */
29
30 /* INCLUDES *****************************************************************/
31
32 #include <ntoskrnl.h>
33 #include <pseh.h>
34 #define NDEBUG
35 #include <internal/debug.h>
36
37 /* GLOBALS *****************************************************************/
38
39 #define FLAG_IF (1<<9)
40
41 #define _STR(x) #x
42 #define STR(x) _STR(x)
43
44 #ifndef ARRAY_SIZE
45 # define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0]))
46 #endif
47
48 extern void KiSystemService(void);
49 extern void interrupt_handler2d(void);
50
51 extern VOID KiTrap0(VOID);
52 extern VOID KiTrap1(VOID);
53 extern VOID KiTrap2(VOID);
54 extern VOID KiTrap3(VOID);
55 extern VOID KiTrap4(VOID);
56 extern VOID KiTrap5(VOID);
57 extern VOID KiTrap6(VOID);
58 extern VOID KiTrap7(VOID);
59 extern VOID KiTrap8(VOID);
60 extern VOID KiTrap9(VOID);
61 extern VOID KiTrap10(VOID);
62 extern VOID KiTrap11(VOID);
63 extern VOID KiTrap12(VOID);
64 extern VOID KiTrap13(VOID);
65 extern VOID KiTrap14(VOID);
66 extern VOID KiTrap15(VOID);
67 extern VOID KiTrap16(VOID);
68 extern VOID KiTrap17(VOID);
69 extern VOID KiTrap18(VOID);
70 extern VOID KiTrap19(VOID);
71 extern VOID KiTrapUnknown(VOID);
72
73 extern ULONG init_stack;
74 extern ULONG init_stack_top;
75
76 extern BOOLEAN Ke386NoExecute;
77
78 static char *ExceptionTypeStrings[] =
79 {
80 "Divide Error",
81 "Debug Trap",
82 "NMI",
83 "Breakpoint",
84 "Overflow",
85 "BOUND range exceeded",
86 "Invalid Opcode",
87 "No Math Coprocessor",
88 "Double Fault",
89 "Unknown(9)",
90 "Invalid TSS",
91 "Segment Not Present",
92 "Stack Segment Fault",
93 "General Protection",
94 "Page Fault",
95 "Reserved(15)",
96 "Math Fault",
97 "Alignment Check",
98 "Machine Check",
99 "SIMD Fault"
100 };
101
102 NTSTATUS ExceptionToNtStatus[] =
103 {
104 STATUS_INTEGER_DIVIDE_BY_ZERO,
105 STATUS_SINGLE_STEP,
106 STATUS_ACCESS_VIOLATION,
107 STATUS_BREAKPOINT,
108 STATUS_INTEGER_OVERFLOW,
109 STATUS_ARRAY_BOUNDS_EXCEEDED,
110 STATUS_ILLEGAL_INSTRUCTION,
111 STATUS_FLOAT_INVALID_OPERATION,
112 STATUS_ACCESS_VIOLATION,
113 STATUS_ACCESS_VIOLATION,
114 STATUS_ACCESS_VIOLATION,
115 STATUS_ACCESS_VIOLATION,
116 STATUS_STACK_OVERFLOW,
117 STATUS_ACCESS_VIOLATION,
118 STATUS_ACCESS_VIOLATION,
119 STATUS_ACCESS_VIOLATION, /* RESERVED */
120 STATUS_FLOAT_INVALID_OPERATION, /* Should not be used, the FPU can give more specific info */
121 STATUS_DATATYPE_MISALIGNMENT,
122 STATUS_ACCESS_VIOLATION,
123 STATUS_FLOAT_MULTIPLE_TRAPS,
124 };
125
126 /* FUNCTIONS ****************************************************************/
127
128 #if defined(DBG) || defined(KDBG)
129 BOOLEAN STDCALL
130 KeRosPrintAddress(PVOID address)
131 {
132 return KdbSymPrintAddress(address);
133 }
134 #else /* KDBG */
135 BOOLEAN STDCALL
136 KeRosPrintAddress(PVOID address)
137 {
138 PLIST_ENTRY current_entry;
139 MODULE_TEXT_SECTION* current;
140 extern LIST_ENTRY ModuleTextListHead;
141 ULONG_PTR RelativeAddress;
142
143 current_entry = ModuleTextListHead.Flink;
144
145 while (current_entry != &ModuleTextListHead &&
146 current_entry != NULL)
147 {
148 current =
149 CONTAINING_RECORD(current_entry, MODULE_TEXT_SECTION, ListEntry);
150
151 if (address >= (PVOID)current->Base &&
152 address < (PVOID)(current->Base + current->Length))
153 {
154 RelativeAddress = (ULONG_PTR) address - current->Base;
155 DbgPrint("<%ws: %x>", current->Name, RelativeAddress);
156 return(TRUE);
157 }
158 current_entry = current_entry->Flink;
159 }
160 return(FALSE);
161 }
162 #endif /* KDBG */
163
164 ULONG
165 KiKernelTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr, PVOID Cr2)
166 {
167 EXCEPTION_RECORD Er;
168
169 Er.ExceptionFlags = 0;
170 Er.ExceptionRecord = NULL;
171 Er.ExceptionAddress = (PVOID)Tf->Eip;
172
173 if (ExceptionNr == 14)
174 {
175 Er.ExceptionCode = STATUS_ACCESS_VIOLATION;
176 Er.NumberParameters = 2;
177 Er.ExceptionInformation[0] = Tf->ErrorCode & 0x1;
178 Er.ExceptionInformation[1] = (ULONG)Cr2;
179 }
180 else
181 {
182 if (ExceptionNr < ARRAY_SIZE(ExceptionToNtStatus))
183 {
184 Er.ExceptionCode = ExceptionToNtStatus[ExceptionNr];
185 }
186 else
187 {
188 Er.ExceptionCode = STATUS_ACCESS_VIOLATION;
189 }
190 Er.NumberParameters = 0;
191 }
192
193 /* FIXME: Which exceptions are noncontinuable? */
194 Er.ExceptionFlags = 0;
195
196 KiDispatchException(&Er, 0, Tf, KernelMode, TRUE);
197
198 return(0);
199 }
200
201 ULONG
202 KiDoubleFaultHandler(VOID)
203 {
204 unsigned int cr2;
205 ULONG StackLimit;
206 ULONG StackBase;
207 ULONG Esp0;
208 ULONG ExceptionNr = 8;
209 KTSS* OldTss;
210 PULONG Frame;
211 ULONG OldCr3;
212 #if 0
213 ULONG i, j;
214 static PVOID StackTrace[MM_STACK_SIZE / sizeof(PVOID)];
215 static ULONG StackRepeatCount[MM_STACK_SIZE / sizeof(PVOID)];
216 static ULONG StackRepeatLength[MM_STACK_SIZE / sizeof(PVOID)];
217 ULONG TraceLength;
218 BOOLEAN FoundRepeat;
219 #endif
220
221 OldTss = KeGetCurrentKPCR()->TSS;
222 Esp0 = OldTss->Esp;
223
224 /* Get CR2 */
225 cr2 = Ke386GetCr2();
226 if (PsGetCurrentThread() != NULL &&
227 PsGetCurrentThread()->ThreadsProcess != NULL)
228 {
229 OldCr3 = (ULONG)
230 PsGetCurrentThread()->ThreadsProcess->Pcb.DirectoryTableBase.QuadPart;
231 }
232 else
233 {
234 OldCr3 = 0xBEADF0AL;
235 }
236
237 /*
238 * Check for stack underflow
239 */
240 if (PsGetCurrentThread() != NULL &&
241 Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
242 {
243 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
244 Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit);
245 ExceptionNr = 12;
246 }
247
248 /*
249 * Print out the CPU registers
250 */
251 if (ExceptionNr < ARRAY_SIZE(ExceptionTypeStrings))
252 {
253 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
254 ExceptionNr, 0);
255 }
256 else
257 {
258 DbgPrint("Exception: %d(%x)\n", ExceptionNr, 0);
259 }
260 DbgPrint("CS:EIP %x:%x ", OldTss->Cs, OldTss->Eip);
261 KeRosPrintAddress((PVOID)OldTss->Eip);
262 DbgPrint("\n");
263 DbgPrint("cr2 %x cr3 %x ", cr2, OldCr3);
264 DbgPrint("Proc: %x ",PsGetCurrentProcess());
265 if (PsGetCurrentProcess() != NULL)
266 {
267 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
268 DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName);
269 }
270 if (PsGetCurrentThread() != NULL)
271 {
272 DbgPrint("Thrd: %x Tid: %x",
273 PsGetCurrentThread(),
274 PsGetCurrentThread()->Cid.UniqueThread);
275 }
276 DbgPrint("\n");
277 DbgPrint("DS %x ES %x FS %x GS %x\n", OldTss->Ds, OldTss->Es,
278 OldTss->Fs, OldTss->Gs);
279 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", OldTss->Eax, OldTss->Ebx,
280 OldTss->Ecx);
281 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\n ESP: %.8x", OldTss->Edx,
282 OldTss->Ebp, OldTss->Esi, Esp0);
283 DbgPrint("EDI: %.8x EFLAGS: %.8x ", OldTss->Edi, OldTss->Eflags);
284 if (OldTss->Cs == KERNEL_CS)
285 {
286 DbgPrint("kESP %.8x ", Esp0);
287 if (PsGetCurrentThread() != NULL)
288 {
289 DbgPrint("kernel stack base %x\n",
290 PsGetCurrentThread()->Tcb.StackLimit);
291
292 }
293 }
294 else
295 {
296 DbgPrint("User ESP %.8x\n", OldTss->Esp);
297 }
298 if ((OldTss->Cs & 0xffff) == KERNEL_CS)
299 {
300 if (PsGetCurrentThread() != NULL)
301 {
302 StackLimit = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
303 StackBase = (ULONG)PsGetCurrentThread()->Tcb.StackLimit;
304 }
305 else
306 {
307 StackLimit = (ULONG)&init_stack_top;
308 StackBase = (ULONG)&init_stack;
309 }
310
311 /*
312 Change to an #if 0 to reduce the amount of information printed on
313 a recursive stack trace.
314 */
315 #if 1
316 DbgPrint("Frames: ");
317 Frame = (PULONG)OldTss->Ebp;
318 while (Frame != NULL && (ULONG)Frame >= StackBase)
319 {
320 KeRosPrintAddress((PVOID)Frame[1]);
321 Frame = (PULONG)Frame[0];
322 DbgPrint("\n");
323 }
324 #else
325 DbgPrint("Frames: ");
326 i = 0;
327 Frame = (PULONG)OldTss->Ebp;
328 while (Frame != NULL && (ULONG)Frame >= StackBase)
329 {
330 StackTrace[i] = (PVOID)Frame[1];
331 Frame = (PULONG)Frame[0];
332 i++;
333 }
334 TraceLength = i;
335
336 i = 0;
337 while (i < TraceLength)
338 {
339 StackRepeatCount[i] = 0;
340 j = i + 1;
341 FoundRepeat = FALSE;
342 while ((j - i) <= (TraceLength - j) && FoundRepeat == FALSE)
343 {
344 if (memcmp(&StackTrace[i], &StackTrace[j],
345 (j - i) * sizeof(PVOID)) == 0)
346 {
347 StackRepeatCount[i] = 2;
348 StackRepeatLength[i] = j - i;
349 FoundRepeat = TRUE;
350 }
351 else
352 {
353 j++;
354 }
355 }
356 if (FoundRepeat == FALSE)
357 {
358 i++;
359 continue;
360 }
361 j = j + StackRepeatLength[i];
362 while ((TraceLength - j) >= StackRepeatLength[i] &&
363 FoundRepeat == TRUE)
364 {
365 if (memcmp(&StackTrace[i], &StackTrace[j],
366 StackRepeatLength[i] * sizeof(PVOID)) == 0)
367 {
368 StackRepeatCount[i]++;
369 j = j + StackRepeatLength[i];
370 }
371 else
372 {
373 FoundRepeat = FALSE;
374 }
375 }
376 i = j;
377 }
378
379 i = 0;
380 while (i < TraceLength)
381 {
382 if (StackRepeatCount[i] == 0)
383 {
384 KeRosPrintAddress(StackTrace[i]);
385 i++;
386 }
387 else
388 {
389 DbgPrint("{");
390 if (StackRepeatLength[i] == 0)
391 {
392 for(;;);
393 }
394 for (j = 0; j < StackRepeatLength[i]; j++)
395 {
396 KeRosPrintAddress(StackTrace[i + j]);
397 }
398 DbgPrint("}*%d", StackRepeatCount[i]);
399 i = i + StackRepeatLength[i] * StackRepeatCount[i];
400 }
401 }
402 #endif
403 }
404
405 DbgPrint("\n");
406 for(;;);
407 return 0;
408 }
409
410 VOID
411 KiDumpTrapFrame(PKTRAP_FRAME Tf, ULONG Parameter1, ULONG Parameter2)
412 {
413 ULONG cr3_;
414 ULONG i;
415 ULONG StackLimit;
416 PULONG Frame;
417 ULONG Esp0;
418 ULONG ExceptionNr = (ULONG)Tf->DebugArgMark;
419 ULONG cr2 = (ULONG)Tf->DebugPointer;
420
421 Esp0 = (ULONG)Tf;
422
423 /*
424 * Print out the CPU registers
425 */
426 if (ExceptionNr < ARRAY_SIZE(ExceptionTypeStrings))
427 {
428 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
429 ExceptionNr, Tf->ErrorCode&0xffff);
430 }
431 else
432 {
433 DbgPrint("Exception: %d(%x)\n", ExceptionNr, Tf->ErrorCode&0xffff);
434 }
435 DbgPrint("Processor: %d CS:EIP %x:%x ", KeGetCurrentProcessorNumber(),
436 Tf->Cs&0xffff, Tf->Eip);
437 KeRosPrintAddress((PVOID)Tf->Eip);
438 DbgPrint("\n");
439 Ke386GetPageTableDirectory(cr3_);
440 DbgPrint("cr2 %x cr3 %x ", cr2, cr3_);
441 DbgPrint("Proc: %x ",PsGetCurrentProcess());
442 if (PsGetCurrentProcess() != NULL)
443 {
444 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
445 DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName);
446 }
447 if (PsGetCurrentThread() != NULL)
448 {
449 DbgPrint("Thrd: %x Tid: %x",
450 PsGetCurrentThread(),
451 PsGetCurrentThread()->Cid.UniqueThread);
452 }
453 DbgPrint("\n");
454 DbgPrint("DS %x ES %x FS %x GS %x\n", Tf->Ds&0xffff, Tf->Es&0xffff,
455 Tf->Fs&0xffff, Tf->Gs&0xfff);
456 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", Tf->Eax, Tf->Ebx, Tf->Ecx);
457 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x ESP: %.8x\n", Tf->Edx,
458 Tf->Ebp, Tf->Esi, Esp0);
459 DbgPrint("EDI: %.8x EFLAGS: %.8x ", Tf->Edi, Tf->Eflags);
460 if ((Tf->Cs&0xffff) == KERNEL_CS)
461 {
462 DbgPrint("kESP %.8x ", Esp0);
463 if (PsGetCurrentThread() != NULL)
464 {
465 DbgPrint("kernel stack base %x\n",
466 PsGetCurrentThread()->Tcb.StackLimit);
467
468 }
469 }
470
471 if (PsGetCurrentThread() != NULL)
472 {
473 StackLimit = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
474 }
475 else
476 {
477 StackLimit = (ULONG)&init_stack_top;
478 }
479
480 /*
481 * Dump the stack frames
482 */
483 DbgPrint("Frames: ");
484 /* Change to an #if 0 if no frames are printed because of fpo. */
485 #if 1
486 i = 1;
487 Frame = (PULONG)Tf->Ebp;
488 while (Frame != NULL)
489 {
490 NTSTATUS Status;
491 PVOID Eip;
492 Status = MmSafeCopyFromUser(&Eip, Frame + 1, sizeof(Eip));
493 if (!NT_SUCCESS(Status))
494 {
495 DbgPrint("<INVALID>");
496 break;
497 }
498 if (!KeRosPrintAddress(Eip))
499 {
500 DbgPrint("<%X>", Eip);
501 }
502 Status = MmSafeCopyFromUser(&Frame, Frame, sizeof(Frame));
503 if (!NT_SUCCESS(Status))
504 {
505 break;
506 }
507 i++;
508 DbgPrint(" ");
509 }
510 #else
511 i = 1;
512 Frame = (PULONG)((ULONG_PTR)Esp0 + KTRAP_FRAME_EFLAGS);
513 while (Frame < (PULONG)PsGetCurrentThread()->Tcb.StackBase && i < 50)
514 {
515 ULONG Address = *Frame;
516 if (KeRosPrintAddress((PVOID)Address))
517 {
518 i++;
519 }
520 Frame++;
521 }
522 #endif
523 }
524
525 ULONG
526 KiTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr)
527 /*
528 * FUNCTION: Called by the lowlevel execption handlers to print an amusing
529 * message and halt the computer
530 * ARGUMENTS:
531 * Complete CPU context
532 */
533 {
534 unsigned int cr2;
535 NTSTATUS Status;
536 ULONG Esp0;
537
538 /* Store the exception number in an unused field in the trap frame. */
539 Tf->DebugArgMark = (PVOID)ExceptionNr;
540
541 /* Use the address of the trap frame as approximation to the ring0 esp */
542 Esp0 = (ULONG)&Tf->Eip;
543
544 /* Get CR2 */
545 cr2 = Ke386GetCr2();
546 Tf->DebugPointer = (PVOID)cr2;
547
548 if (ExceptionNr == 14 && Tf->Eflags & FLAG_IF)
549 {
550 Ke386EnableInterrupts();
551 }
552
553 /*
554 * If this was a V86 mode exception then handle it specially
555 */
556 if (Tf->Eflags & (1 << 17))
557 {
558 return(KeV86Exception(ExceptionNr, Tf, cr2));
559 }
560
561 /*
562 * Check for stack underflow, this may be obsolete
563 */
564 if (PsGetCurrentThread() != NULL &&
565 Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
566 {
567 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
568 Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit);
569 ExceptionNr = 12;
570 }
571
572 /*
573 * Maybe handle the page fault and return
574 */
575 if (ExceptionNr == 14)
576 {
577 if (Ke386NoExecute && Tf->ErrorCode & 0x10 && cr2 >= KERNEL_BASE)
578 {
579 KEBUGCHECKWITHTF(ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY, 0, 0, 0, 0, Tf);
580 }
581 Status = MmPageFault(Tf->Cs&0xffff,
582 &Tf->Eip,
583 &Tf->Eax,
584 cr2,
585 Tf->ErrorCode);
586 if (NT_SUCCESS(Status))
587 {
588 return(0);
589 }
590 }
591
592 /*
593 * Check for a breakpoint that was only for the attention of the debugger.
594 */
595 if (ExceptionNr == 3 && Tf->Eip == ((ULONG)DbgBreakPointNoBugCheck) + 1)
596 {
597 /*
598 EIP is already adjusted by the processor to point to the instruction
599 after the breakpoint.
600 */
601 return(0);
602 }
603
604 /*
605 * Try to handle device-not-present, math-fault and xmm-fault exceptions.
606 */
607 if (ExceptionNr == 7 || ExceptionNr == 16 || ExceptionNr == 19)
608 {
609 Status = KiHandleFpuFault(Tf, ExceptionNr);
610 if (NT_SUCCESS(Status))
611 {
612 return(0);
613 }
614 }
615
616 /*
617 * Handle user exceptions differently
618 */
619 if ((Tf->Cs & 0xFFFF) == USER_CS)
620 {
621 return(KiUserTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
622 }
623 else
624 {
625 return(KiKernelTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
626 }
627 }
628
629 VOID
630 KeDumpStackFrames(PULONG Frame)
631 {
632 PULONG StackBase, StackEnd;
633 MEMORY_BASIC_INFORMATION mbi;
634 ULONG ResultLength = sizeof(mbi);
635 NTSTATUS Status;
636
637 DbgPrint("Frames: ");
638 _SEH_TRY
639 {
640 Status = MiQueryVirtualMemory (
641 (HANDLE)-1,
642 Frame,
643 MemoryBasicInformation,
644 &mbi,
645 sizeof(mbi),
646 &ResultLength );
647 if ( !NT_SUCCESS(Status) )
648 {
649 DPRINT1("Can't dump stack frames: NtQueryVirtualMemory() failed: %x\n", Status );
650 return;
651 }
652
653 StackBase = Frame;
654 StackEnd = mbi.BaseAddress + mbi.RegionSize;
655
656 while ( Frame >= StackBase && Frame < StackEnd )
657 {
658 ULONG Addr = Frame[1];
659 if (!KeRosPrintAddress((PVOID)Addr))
660 DbgPrint("<%X>", Addr);
661 if ( Addr == 0 || Addr == 0xDEADBEEF )
662 break;
663 StackBase = Frame;
664 Frame = (PULONG)Frame[0];
665 DbgPrint("\n");
666 }
667 }
668 _SEH_HANDLE
669 {
670 }
671 _SEH_END;
672 DbgPrint("\n");
673 }
674
675 VOID STDCALL
676 KeRosDumpStackFrames ( PULONG Frame, ULONG FrameCount )
677 {
678 ULONG i=0;
679 PULONG StackBase, StackEnd;
680 MEMORY_BASIC_INFORMATION mbi;
681 ULONG ResultLength = sizeof(mbi);
682 NTSTATUS Status;
683
684 DbgPrint("Frames: ");
685 _SEH_TRY
686 {
687 if ( !Frame )
688 {
689 #if defined __GNUC__
690 __asm__("mov %%ebp, %%ebx" : "=b" (Frame) : );
691 #elif defined(_MSC_VER)
692 __asm mov [Frame], ebp
693 #endif
694 //Frame = (PULONG)Frame[0]; // step out of KeRosDumpStackFrames
695 }
696
697 Status = MiQueryVirtualMemory (
698 (HANDLE)-1,
699 Frame,
700 MemoryBasicInformation,
701 &mbi,
702 sizeof(mbi),
703 &ResultLength );
704 if ( !NT_SUCCESS(Status) )
705 {
706 DPRINT1("Can't dump stack frames: NtQueryVirtualMemory() failed: %x\n", Status );
707 return;
708 }
709
710 StackBase = Frame;
711 StackEnd = mbi.BaseAddress + mbi.RegionSize;
712
713 while ( Frame >= StackBase && Frame < StackEnd && i++ < FrameCount )
714 {
715 ULONG Addr = Frame[1];
716 if (!KeRosPrintAddress((PVOID)Addr))
717 DbgPrint("<%X>", Addr);
718 if ( Addr == 0 || Addr == 0xDEADBEEF )
719 break;
720 StackBase = Frame;
721 Frame = (PULONG)Frame[0];
722 DbgPrint(" ");
723 }
724 }
725 _SEH_HANDLE
726 {
727 }
728 _SEH_END;
729 DbgPrint("\n");
730 }
731
732 ULONG STDCALL
733 KeRosGetStackFrames ( PULONG Frames, ULONG FrameCount )
734 {
735 ULONG Count = 0;
736 PULONG StackBase, StackEnd, Frame;
737 MEMORY_BASIC_INFORMATION mbi;
738 ULONG ResultLength = sizeof(mbi);
739 NTSTATUS Status;
740
741 _SEH_TRY
742 {
743 #if defined __GNUC__
744 __asm__("mov %%ebp, %%ebx" : "=b" (Frame) : );
745 #elif defined(_MSC_VER)
746 __asm mov [Frame], ebp
747 #endif
748
749 Status = MiQueryVirtualMemory (
750 (HANDLE)-1,
751 Frame,
752 MemoryBasicInformation,
753 &mbi,
754 sizeof(mbi),
755 &ResultLength );
756 if ( !NT_SUCCESS(Status) )
757 {
758 DPRINT1("Can't get stack frames: NtQueryVirtualMemory() failed: %x\n", Status );
759 return 0;
760 }
761
762 StackBase = Frame;
763 StackEnd = mbi.BaseAddress + mbi.RegionSize;
764
765 while ( Count < FrameCount && Frame >= StackBase && Frame < StackEnd )
766 {
767 Frames[Count++] = Frame[1];
768 StackBase = Frame;
769 Frame = (PULONG)Frame[0];
770 }
771 }
772 _SEH_HANDLE
773 {
774 }
775 _SEH_END;
776 return Count;
777 }
778
779 static void
780 set_system_call_gate(unsigned int sel, unsigned int func)
781 {
782 DPRINT("sel %x %d\n",sel,sel);
783 KiIdt[sel].a = (((int)func)&0xffff) +
784 (KERNEL_CS << 16);
785 KiIdt[sel].b = 0xef00 + (((int)func)&0xffff0000);
786 DPRINT("idt[sel].b %x\n",KiIdt[sel].b);
787 }
788
789 static void set_interrupt_gate(unsigned int sel, unsigned int func)
790 {
791 DPRINT("set_interrupt_gate(sel %d, func %x)\n",sel,func);
792 KiIdt[sel].a = (((int)func)&0xffff) +
793 (KERNEL_CS << 16);
794 KiIdt[sel].b = 0x8e00 + (((int)func)&0xffff0000);
795 }
796
797 static void set_trap_gate(unsigned int sel, unsigned int func, unsigned int dpl)
798 {
799 DPRINT("set_trap_gate(sel %d, func %x, dpl %d)\n",sel, func, dpl);
800 ASSERT(dpl <= 3);
801 KiIdt[sel].a = (((int)func)&0xffff) +
802 (KERNEL_CS << 16);
803 KiIdt[sel].b = 0x8f00 + (dpl << 13) + (((int)func)&0xffff0000);
804 }
805
806 static void
807 set_task_gate(unsigned int sel, unsigned task_sel)
808 {
809 KiIdt[sel].a = task_sel << 16;
810 KiIdt[sel].b = 0x8500;
811 }
812
813 VOID INIT_FUNCTION
814 KeInitExceptions(VOID)
815 /*
816 * FUNCTION: Initalize CPU exception handling
817 */
818 {
819 int i;
820
821 DPRINT("KeInitExceptions()\n");
822
823 /*
824 * Set up the other gates
825 */
826 set_trap_gate(0, (ULONG)KiTrap0, 0);
827 set_trap_gate(1, (ULONG)KiTrap1, 0);
828 set_trap_gate(2, (ULONG)KiTrap2, 0);
829 set_trap_gate(3, (ULONG)KiTrap3, 3);
830 set_trap_gate(4, (ULONG)KiTrap4, 0);
831 set_trap_gate(5, (ULONG)KiTrap5, 0);
832 set_trap_gate(6, (ULONG)KiTrap6, 0);
833 set_trap_gate(7, (ULONG)KiTrap7, 0);
834 set_task_gate(8, TRAP_TSS_SELECTOR);
835 set_trap_gate(9, (ULONG)KiTrap9, 0);
836 set_trap_gate(10, (ULONG)KiTrap10, 0);
837 set_trap_gate(11, (ULONG)KiTrap11, 0);
838 set_trap_gate(12, (ULONG)KiTrap12, 0);
839 set_trap_gate(13, (ULONG)KiTrap13, 0);
840 set_interrupt_gate(14, (ULONG)KiTrap14);
841 set_trap_gate(15, (ULONG)KiTrap15, 0);
842 set_trap_gate(16, (ULONG)KiTrap16, 0);
843 set_trap_gate(17, (ULONG)KiTrap17, 0);
844 set_trap_gate(18, (ULONG)KiTrap18, 0);
845 set_trap_gate(19, (ULONG)KiTrap19, 0);
846
847 for (i = 20; i < 256; i++)
848 {
849 set_trap_gate(i,(int)KiTrapUnknown, 0);
850 }
851
852 set_system_call_gate(0x2d,(int)interrupt_handler2d);
853 set_system_call_gate(0x2e,(int)KiSystemService);
854 }
855
856 /*
857 * @implemented
858 */
859 NTSTATUS STDCALL
860 KeRaiseUserException(IN NTSTATUS ExceptionCode)
861 {
862 ULONG OldEip;
863 PKTHREAD Thread = KeGetCurrentThread();
864
865 _SEH_TRY {
866 Thread->Teb->ExceptionCode = ExceptionCode;
867 } _SEH_HANDLE {
868 return(ExceptionCode);
869 } _SEH_END;
870
871 OldEip = Thread->TrapFrame->Eip;
872 Thread->TrapFrame->Eip = (ULONG_PTR)LdrpGetSystemDllRaiseExceptionDispatcher();
873 return((NTSTATUS)OldEip);
874 }
875
876 /*
877 * @implemented
878 */
879 NTSTATUS
880 STDCALL
881 NtRaiseException (
882 IN PEXCEPTION_RECORD ExceptionRecord,
883 IN PCONTEXT Context,
884 IN BOOLEAN SearchFrames)
885 {
886 PKTHREAD Thread = KeGetCurrentThread();
887 PKTRAP_FRAME TrapFrame = Thread->TrapFrame;
888 PKTRAP_FRAME PrevTrapFrame = (PKTRAP_FRAME)TrapFrame->Edx;
889
890 KeGetCurrentKPCR()->Tib.ExceptionList = TrapFrame->ExceptionList;
891
892 KiDispatchException(ExceptionRecord,
893 Context,
894 TrapFrame,
895 KeGetPreviousMode(),
896 SearchFrames);
897
898 /* Restore the user context */
899 Thread->TrapFrame = PrevTrapFrame;
900 __asm__("mov %%ebx, %%esp;\n" "jmp _KiServiceExit": : "b" (TrapFrame));
901
902 /* We never get here */
903 return(STATUS_SUCCESS);
904 }