Fixed irq problems.
[reactos.git] / reactos / ntoskrnl / ke / catch.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2000 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 /* $Id: catch.c,v 1.19 2002/05/02 23:45:33 dwelch Exp $
20 *
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/ke/catch.c
23 * PURPOSE: Exception handling
24 * PROGRAMMER: David Welch (welch@mcmail.com)
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include <ddk/ntddk.h>
30 #include <roscfg.h>
31 #include <internal/ke.h>
32 #include <internal/ldr.h>
33 #include <internal/ps.h>
34 #include <internal/kd.h>
35
36 #define NDEBUG
37 #include <internal/debug.h>
38
39 /* FUNCTIONS ****************************************************************/
40
41 EXCEPTION_DISPOSITION
42 RtlpExecuteHandlerForException(
43 PEXCEPTION_RECORD ExceptionRecord,
44 PEXCEPTION_REGISTRATION ExceptionRegistration,
45 PCONTEXT Context,
46 PVOID DispatcherContext,
47 PEXCEPTION_HANDLER Handler);
48
49
50 #ifndef NDEBUG
51
52 VOID RtlpDumpExceptionRegistrations(VOID)
53 {
54 PEXCEPTION_REGISTRATION Current;
55 PKTHREAD Thread;
56
57 DbgPrint("Dumping exception registrations:\n");
58
59 Thread = KeGetCurrentThread();
60
61 assert(Thread);
62 assert(Thread->TrapFrame);
63
64 Current = Thread->TrapFrame->ExceptionList;
65
66 if ((ULONG_PTR)Current != -1)
67 {
68 while ((ULONG_PTR)Current != -1)
69 {
70 DbgPrint(" (0x%08X) HANDLER (0x%08X)\n", Current, Current->handler);
71 Current = Current->prev;
72 }
73 DbgPrint(" End-Of-List\n");
74 } else {
75 DbgPrint(" No exception registrations exists.\n");
76 }
77 }
78
79 #endif /* NDEBUG */
80
81 EXCEPTION_DISPOSITION
82 RtlpDispatchException(
83 PEXCEPTION_RECORD ExceptionRecord,
84 PCONTEXT Context)
85 {
86 PEXCEPTION_REGISTRATION RegistrationFrame;
87 DWORD DispatcherContext;
88 DWORD ReturnValue;
89 PKPCR KPCR;
90 PKTHREAD Thread;
91
92 DPRINT("RtlpDispatchException() called\n");
93 #ifndef NDEBUG
94 RtlpDumpExceptionRegistrations();
95 #endif /* NDEBUG */
96 Thread = KeGetCurrentThread();
97
98 DPRINT("Thread is 0x%X\n", Thread);
99
100 KPCR = KeGetCurrentKPCR();
101
102 RegistrationFrame = Thread->TrapFrame->ExceptionList;
103
104 DPRINT("RegistrationFrame is 0x%X\n", RegistrationFrame);
105
106 while ((ULONG_PTR)RegistrationFrame != -1)
107 {
108 EXCEPTION_RECORD ExceptionRecord2;
109 DWORD Temp = 0;
110 //PVOID RegistrationFrameEnd = (PVOID)RegistrationFrame + 8;
111
112 // Make sure the registration frame is located within the stack
113
114 DPRINT("Error checking\n");
115 #if 0
116 if (Thread->KernelStack > RegistrationFrameEnd)
117 {
118 ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
119 return ExceptionDismiss;
120 }
121 // FIXME: Correct?
122 if (Thread->StackLimit < RegistrationFrameEnd)
123 {
124 ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
125 return ExceptionDismiss;
126 }
127
128 // Make sure stack is DWORD aligned
129 if ((ULONG_PTR)RegistrationFrame & 3)
130 {
131 ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
132 return ExceptionDismiss;
133 }
134 #endif
135
136 DPRINT("Calling handler at 0x%X\n", RegistrationFrame->handler);
137
138 ReturnValue = RtlpExecuteHandlerForException(
139 ExceptionRecord,
140 RegistrationFrame,
141 Context,
142 &DispatcherContext,
143 RegistrationFrame->handler);
144
145 if (RegistrationFrame == NULL)
146 {
147 ExceptionRecord->ExceptionFlags &= ~EXCEPTION_NESTED_CALL; // Turn off flag
148 }
149
150 if (ReturnValue == ExceptionContinueExecution)
151 {
152 /* Copy the changed context back to the trap frame and return */
153 NtContinue(Context, FALSE);
154 return ExceptionContinueExecution;
155 }
156 else if (ReturnValue == ExceptionDismiss)
157 {
158 if (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
159 {
160 ExceptionRecord2.ExceptionRecord = ExceptionRecord;
161 ExceptionRecord2.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION;
162 ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
163 ExceptionRecord2.NumberParameters = 0;
164 RtlRaiseException(&ExceptionRecord2);
165 }
166 /* Else continue search */
167 }
168 else if (ReturnValue == ExceptionNestedException)
169 {
170 ExceptionRecord->ExceptionFlags |= EXCEPTION_EXIT_UNWIND;
171 if (DispatcherContext > Temp)
172 Temp = DispatcherContext;
173 }
174 else if (ReturnValue == ExceptionCollidedUnwind)
175 {
176 ExceptionRecord2.ExceptionRecord = ExceptionRecord;
177 ExceptionRecord2.ExceptionCode = STATUS_INVALID_DISPOSITION;
178 ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
179 ExceptionRecord2.NumberParameters = 0;
180 RtlRaiseException(&ExceptionRecord2);
181 }
182
183 RegistrationFrame = RegistrationFrame->prev; // Go to previous frame
184 }
185
186 /* No exception handler will handle this exception */
187
188 return ExceptionDismiss;
189 }
190
191
192 VOID
193 KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
194 PCONTEXT Context,
195 PKTRAP_FRAME Tf,
196 KPROCESSOR_MODE PreviousMode,
197 BOOLEAN SearchFrames)
198 {
199 EXCEPTION_DISPOSITION Value;
200 CONTEXT TContext;
201
202 DPRINT("KiDispatchException() called\n");
203 /* PCR->KeExceptionDispatchCount++; */
204
205 if (Context == NULL)
206 {
207 TContext.ContextFlags = CONTEXT_FULL;
208 if (PreviousMode == UserMode)
209 {
210 TContext.ContextFlags = TContext.ContextFlags | CONTEXT_DEBUGGER;
211 }
212
213 KeTrapFrameToContext(Tf, &TContext);
214
215 Context = &TContext;
216 }
217 #if 0
218 if (ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT)
219 {
220 Context->Eip--;
221 }
222 #endif
223 if (PreviousMode == UserMode)
224 {
225 if (SearchFrames)
226 {
227 PULONG Stack;
228 ULONG CDest;
229
230 /* FIXME: Give the kernel debugger a chance */
231
232 /* FIXME: Forward exception to user mode debugger */
233
234 /* FIXME: Check user mode stack for enough space */
235
236
237 /*
238 * Let usermode try and handle the exception
239 */
240 Tf->Esp = Tf->Esp -
241 (12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT));
242 Stack = (PULONG)Tf->Esp;
243 CDest = 3 + (ROUND_UP(sizeof(EXCEPTION_RECORD), 4) / 4);
244 /* Return address */
245 Stack[0] = 0;
246 /* Pointer to EXCEPTION_RECORD structure */
247 Stack[1] = (ULONG)&Stack[3];
248 /* Pointer to CONTEXT structure */
249 Stack[2] = (ULONG)&Stack[CDest];
250 memcpy(&Stack[3], ExceptionRecord, sizeof(EXCEPTION_RECORD));
251 memcpy(&Stack[CDest], Context, sizeof(CONTEXT));
252
253 Tf->Eip = (ULONG)LdrpGetSystemDllExceptionDispatcher();
254 return;
255 }
256
257 /* FIXME: Forward the exception to the debugger */
258
259 /* FIXME: Forward the exception to the process exception port */
260
261 /* Terminate the offending thread */
262 ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode);
263
264 /* If that fails then bugcheck */
265 DbgPrint("Could not terminate thread\n");
266 KeBugCheck(KMODE_EXCEPTION_NOT_HANDLED);
267 }
268 else
269 {
270 KD_CONTINUE_TYPE Action;
271
272 /* PreviousMode == KernelMode */
273
274 if (!KdDebuggerEnabled || KdDebugType != GdbDebug)
275 {
276 /* FIXME: Get ExceptionNr and CR2 */
277 KeBugCheckWithTf (KMODE_EXCEPTION_NOT_HANDLED, 0, 0, 0, 0, Tf);
278 }
279
280 Action = KdEnterDebuggerException (ExceptionRecord, Context, Tf);
281 if (Action != kdHandleException)
282 {
283 Value = RtlpDispatchException (ExceptionRecord, Context);
284
285 DPRINT("RtlpDispatchException() returned with 0x%X\n", Value);
286 /*
287 * If RtlpDispatchException() does not handle the exception then
288 * bugcheck
289 */
290 if (Value != ExceptionContinueExecution)
291 {
292 KeBugCheck (KMODE_EXCEPTION_NOT_HANDLED);
293 }
294 }
295 else
296 {
297 KeContextToTrapFrame (Context, KeGetCurrentThread()->TrapFrame);
298 }
299 }
300 }
301
302 VOID STDCALL
303 ExRaiseAccessViolation (VOID)
304 {
305 ExRaiseStatus (STATUS_ACCESS_VIOLATION);
306 }
307
308 VOID STDCALL
309 ExRaiseDatatypeMisalignment (VOID)
310 {
311 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
312 }
313
314 VOID STDCALL
315 ExRaiseStatus (IN NTSTATUS Status)
316 {
317 EXCEPTION_RECORD ExceptionRecord;
318
319 DPRINT("ExRaiseStatus(%x)\n", Status);
320
321 ExceptionRecord.ExceptionRecord = NULL;
322 ExceptionRecord.NumberParameters = 0;
323 ExceptionRecord.ExceptionCode = Status;
324 ExceptionRecord.ExceptionFlags = 0;
325
326 RtlRaiseException(&ExceptionRecord);
327 }
328
329
330 NTSTATUS STDCALL
331 NtRaiseException (IN PEXCEPTION_RECORD ExceptionRecord,
332 IN PCONTEXT Context,
333 IN BOOLEAN SearchFrames)
334 {
335 KiDispatchException(ExceptionRecord,
336 Context,
337 PsGetCurrentThread()->Tcb.TrapFrame,
338 ExGetPreviousMode(),
339 SearchFrames);
340 return(STATUS_SUCCESS);
341 }
342
343
344 VOID STDCALL
345 RtlRaiseException(PEXCEPTION_RECORD ExceptionRecord)
346 {
347 ZwRaiseException(ExceptionRecord, NULL, TRUE);
348 }
349
350
351 inline
352 EXCEPTION_DISPOSITION
353 RtlpExecuteHandler(
354 PEXCEPTION_RECORD ExceptionRecord,
355 PEXCEPTION_REGISTRATION ExceptionRegistration,
356 PCONTEXT Context,
357 PVOID DispatcherContext,
358 PEXCEPTION_HANDLER Handler,
359 PEXCEPTION_HANDLER RawHandler)
360 {
361 EXCEPTION_DISPOSITION Value;
362
363 // Set up an EXCEPTION_REGISTRATION
364 __asm__ ("pushl %0;pushl %%fs:0;movl %%esp,%%fs:0;" : : "g" (RawHandler));
365
366 // Invoke the exception callback function
367 Value = Handler(
368 ExceptionRecord,
369 ExceptionRegistration,
370 Context,
371 DispatcherContext);
372
373 // Remove the minimal EXCEPTION_REGISTRATION frame
374 //__asm__ ("movl %fs:0,%esp; popl %fs:0");
375
376 __asm__ ("movl (%%esp),%%eax;movl %%eax,%%fs:0;addl $8,%%esp;" : : : "%eax");
377
378 return Value;
379 }
380
381
382 EXCEPTION_DISPOSITION
383 RtlpExceptionHandler(
384 PEXCEPTION_RECORD ExceptionRecord,
385 PEXCEPTION_REGISTRATION ExceptionRegistration,
386 PCONTEXT Context,
387 PVOID DispatcherContext)
388 {
389 // If unwind flag set, return DISPOSITION_CONTINUE_SEARCH, else
390 // assign DispatcherContext context and return DISPOSITION_NESTED_EXCEPTION
391
392 if (ExceptionRecord->ExceptionFlags & EXCEPTION_UNWINDING)
393 {
394 DPRINT("RtlpExceptionHandler(). Returning ExceptionContinueSearch\n");
395 return ExceptionContinueSearch;
396 }
397 else
398 {
399 DPRINT("RtlpExceptionHandler(). Returning ExceptionNestedException\n");
400 *(PEXCEPTION_REGISTRATION*)DispatcherContext = ExceptionRegistration->prev;
401 return ExceptionNestedException;
402 }
403 }
404
405
406 EXCEPTION_DISPOSITION
407 RtlpUnwindHandler(
408 PEXCEPTION_RECORD ExceptionRecord,
409 PEXCEPTION_REGISTRATION ExceptionRegistration,
410 PCONTEXT Context,
411 PVOID DispatcherContext)
412 {
413 // If unwind flag set, return DISPOSITION_CONTINUE_SEARCH, else
414 // assign DispatcherContext and return DISPOSITION_COLLIDED_UNWIND
415
416 if (ExceptionRecord->ExceptionFlags & EXCEPTION_UNWINDING)
417 {
418 DPRINT("RtlpUnwindHandler(). Returning ExceptionContinueSearch\n");
419 return ExceptionContinueSearch;
420 }
421 else
422 {
423 DPRINT("RtlpUnwindHandler(). Returning ExceptionCollidedUnwind\n");
424 *(PEXCEPTION_REGISTRATION*)DispatcherContext = ExceptionRegistration->prev;
425 return ExceptionCollidedUnwind;
426 }
427 }
428
429
430 EXCEPTION_DISPOSITION
431 RtlpExecuteHandlerForException(
432 PEXCEPTION_RECORD ExceptionRecord,
433 PEXCEPTION_REGISTRATION ExceptionRegistration,
434 PCONTEXT Context,
435 PVOID DispatcherContext,
436 PEXCEPTION_HANDLER Handler)
437 {
438 return RtlpExecuteHandler(
439 ExceptionRecord,
440 ExceptionRegistration,
441 Context,
442 DispatcherContext,
443 Handler,
444 RtlpExceptionHandler);
445 }
446
447
448 EXCEPTION_DISPOSITION
449 RtlpExecuteHandlerForUnwind(
450 PEXCEPTION_RECORD ExceptionRecord,
451 PEXCEPTION_REGISTRATION ExceptionRegistration,
452 PCONTEXT Context,
453 PVOID DispatcherContext,
454 PEXCEPTION_HANDLER Handler)
455 {
456 return RtlpExecuteHandler(
457 ExceptionRecord,
458 ExceptionRegistration,
459 Context,
460 DispatcherContext,
461 Handler,
462 RtlpUnwindHandler);
463 }
464
465
466 VOID STDCALL
467 RtlUnwind(
468 PEXCEPTION_REGISTRATION RegistrationFrame,
469 PVOID ReturnAddress,
470 PEXCEPTION_RECORD ExceptionRecord,
471 DWORD EaxValue)
472 {
473 PEXCEPTION_REGISTRATION ERHead;
474 PEXCEPTION_RECORD pExceptRec;
475 EXCEPTION_RECORD TempER;
476 CONTEXT Context;
477 //PVOID Stack;
478 PKTHREAD Thread;
479
480 DPRINT("RtlUnwind() called. RegistrationFrame 0x%X\n", RegistrationFrame);
481 #ifndef NDEBUG
482 RtlpDumpExceptionRegistrations();
483 #endif /* NDEBUG */
484 Thread = KeGetCurrentThread();
485
486 ERHead = Thread->TrapFrame->ExceptionList;
487
488 if (ExceptionRecord == NULL) // The normal case
489 {
490 pExceptRec = &TempER;
491
492 pExceptRec->ExceptionFlags = 0;
493 pExceptRec->ExceptionCode = STATUS_UNWIND;
494 pExceptRec->ExceptionRecord = NULL;
495 // FIXME: Find out if NT retrieves the return address from the stack instead
496 pExceptRec->ExceptionAddress = ReturnAddress;
497 //pExceptRec->ExceptionInformation[0] = 0;
498 }
499
500 if (RegistrationFrame)
501 pExceptRec->ExceptionFlags |= EXCEPTION_UNWINDING;
502 else
503 pExceptRec->ExceptionFlags |= (EXCEPTION_UNWINDING|EXCEPTION_EXIT_UNWIND);
504
505 Context.ContextFlags =
506 (CONTEXT_i386 | CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS);
507
508 KeTrapFrameToContext(Thread->TrapFrame, &Context);
509
510 Context.Esp += 0x10;
511 Context.Eax = EaxValue;
512
513 // Begin traversing the list of EXCEPTION_REGISTRATION
514 while ((ULONG_PTR)ERHead != -1)
515 {
516 EXCEPTION_RECORD er2;
517
518 DPRINT("ERHead 0x%X\n", ERHead);
519
520 if (ERHead == RegistrationFrame)
521 {
522 DPRINT("Continueing execution\n");
523 NtContinue(&Context, FALSE);
524 return;
525 }
526 else
527 {
528 // If there's an exception frame, but it's lower on the stack
529 // then the head of the exception list, something's wrong!
530 if (RegistrationFrame && (RegistrationFrame <= ERHead))
531 {
532 DPRINT("The exception frame is bad\n");
533
534 // Generate an exception to bail out
535 er2.ExceptionRecord = pExceptRec;
536 er2.NumberParameters = 0;
537 er2.ExceptionCode = STATUS_INVALID_UNWIND_TARGET;
538 er2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
539
540 RtlRaiseException(&er2);
541 }
542 }
543
544 #if 0
545 Stack = ERHead + sizeof(EXCEPTION_REGISTRATION);
546 if ( (KPCR->StackBase <= (PVOID)ERHead ) // Make sure that ERHead
547 && (KPCR->StackLimit >= (PVOID)Stack ) // is in range, and a multiple
548 && (0 == ((ULONG_PTR)ERHead & 3)) ) // of 4 (i.e., sane)
549 {
550 #else
551 if (1) {
552 #endif
553 PEXCEPTION_REGISTRATION NewERHead;
554 PEXCEPTION_REGISTRATION pCurrExceptReg;
555 EXCEPTION_DISPOSITION ReturnValue;
556
557 DPRINT("Executing handler at 0x%X for unwind\n", ERHead->handler);
558
559 ReturnValue = RtlpExecuteHandlerForUnwind(
560 pExceptRec,
561 ERHead,
562 &Context,
563 &NewERHead,
564 ERHead->handler);
565
566 DPRINT("Handler at 0x%X returned 0x%X\n", ERHead->handler, ReturnValue);
567
568 if (ReturnValue != ExceptionContinueSearch)
569 {
570 if (ReturnValue != ExceptionCollidedUnwind)
571 {
572 DPRINT("Bad return value\n");
573
574 er2.ExceptionRecord = pExceptRec;
575 er2.NumberParameters = 0;
576 er2.ExceptionCode = STATUS_INVALID_DISPOSITION;
577 er2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
578
579 RtlRaiseException(&er2);
580 } else
581 ERHead = NewERHead;
582 }
583
584 pCurrExceptReg = ERHead;
585 ERHead = ERHead->prev;
586
587 DPRINT("New ERHead is 0x%X\n", ERHead);
588
589 DPRINT("Setting exception registration at 0x%X as current\n",
590 RegistrationFrame->prev);
591
592 // Unlink the exception handler
593 KeGetCurrentKPCR()->ExceptionList = RegistrationFrame->prev;
594 }
595 else // The stack looks goofy! Raise an exception to bail out
596 {
597 DPRINT("Bad stack\n");
598
599 er2.ExceptionRecord = pExceptRec;
600 er2.NumberParameters = 0;
601 er2.ExceptionCode = STATUS_BAD_STACK;
602 er2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
603
604 RtlRaiseException(&er2);
605 }
606 }
607
608 // If we get here, we reached the end of the EXCEPTION_REGISTRATION list.
609 // This shouldn't happen normally.
610
611 DPRINT("Ran out of exception registrations. RegistrationFrame is (0x%X)\n",
612 RegistrationFrame);
613
614 if ((ULONG_PTR)RegistrationFrame == -1)
615 NtContinue(&Context, FALSE);
616 else
617 NtRaiseException(pExceptRec, &Context, 0);
618 }
619
620 /* EOF */