ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

except.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS Kernel
00003  * LICENSE:         GPL - See COPYING in the top level directory
00004  * FILE:            ntoskrnl/ke/amd64/except.c
00005  * PURPOSE:         Exception Dispatching for amd64
00006  * PROGRAMMER:      Timo Kreuzer (timo.kreuzer@reactos.org)
00007  *                  Alex Ionescu (alex.ionescu@reactos.org)
00008  */
00009 
00010 /* INCLUDES ******************************************************************/
00011 
00012 #include <ntoskrnl.h>
00013 #define NDEBUG
00014 #include <debug.h>
00015 
00016 extern KI_INTERRUPT_DISPATCH_ENTRY KiUnexpectedRange[256];
00017 
00018 /* GLOBALS *******************************************************************/
00019 
00020 KIDT_INIT KiInterruptInitTable[] =
00021 {
00022   /* Id,   Dpl,  IST,  ServiceRoutine */
00023     {0x00, 0x00, 0x00, KiDivideErrorFault},
00024     {0x01, 0x00, 0x00, KiDebugTrapOrFault},
00025     {0x02, 0x00, 0x03, KiNmiInterrupt},
00026     {0x03, 0x03, 0x00, KiBreakpointTrap},
00027     {0x04, 0x03, 0x00, KiOverflowTrap},
00028     {0x05, 0x00, 0x00, KiBoundFault},
00029     {0x06, 0x00, 0x00, KiInvalidOpcodeFault},
00030     {0x07, 0x00, 0x00, KiNpxNotAvailableFault},
00031     {0x08, 0x00, 0x01, KiDoubleFaultAbort},
00032     {0x09, 0x00, 0x00, KiNpxSegmentOverrunAbort},
00033     {0x0A, 0x00, 0x00, KiInvalidTssFault},
00034     {0x0B, 0x00, 0x00, KiSegmentNotPresentFault},
00035     {0x0C, 0x00, 0x00, KiStackFault},
00036     {0x0D, 0x00, 0x00, KiGeneralProtectionFault},
00037     {0x0E, 0x00, 0x00, KiPageFault},
00038     {0x10, 0x00, 0x00, KiFloatingErrorFault},
00039     {0x11, 0x00, 0x00, KiAlignmentFault},
00040     {0x12, 0x00, 0x02, KiMcheckAbort},
00041     {0x13, 0x00, 0x00, KiXmmException},
00042     {0x1F, 0x00, 0x00, KiApcInterrupt},
00043     {0x2C, 0x03, 0x00, KiRaiseAssertion},
00044     {0x2D, 0x03, 0x00, KiDebugServiceTrap},
00045     {0x2F, 0x00, 0x00, KiDpcInterrupt},
00046     {0xE1, 0x00, 0x00, KiIpiInterrupt},
00047     {0, 0, 0, 0}
00048 };
00049 
00050 KIDTENTRY64 KiIdt[256];
00051 KDESCRIPTOR KiIdtDescriptor = {{0}, sizeof(KiIdt) - 1, KiIdt};
00052 
00053 
00054 /* FUNCTIONS *****************************************************************/
00055 
00056 VOID
00057 INIT_FUNCTION
00058 NTAPI
00059 KeInitExceptions(VOID)
00060 {
00061     int i, j;
00062 
00063     /* Initialize the Idt */
00064     for (j = i = 0; i < 256; i++)
00065     {
00066         ULONG64 Offset;
00067 
00068         if (KiInterruptInitTable[j].InterruptId == i)
00069         {
00070             Offset = (ULONG64)KiInterruptInitTable[j].ServiceRoutine;
00071             KiIdt[i].Dpl = KiInterruptInitTable[j].Dpl;
00072             KiIdt[i].IstIndex = KiInterruptInitTable[j].IstIndex;
00073             j++;
00074         }
00075         else
00076         {
00077             Offset = (ULONG64)&KiUnexpectedRange[i]._Op_push;
00078             KiIdt[i].Dpl = 0;
00079             KiIdt[i].IstIndex = 0;
00080         }
00081         KiIdt[i].OffsetLow = Offset & 0xffff;
00082         KiIdt[i].Selector = KGDT64_R0_CODE;
00083         KiIdt[i].Type = 0x0e;
00084         KiIdt[i].Reserved0 = 0;
00085         KiIdt[i].Present = 1;
00086         KiIdt[i].OffsetMiddle = (Offset >> 16) & 0xffff;
00087         KiIdt[i].OffsetHigh = (Offset >> 32);
00088         KiIdt[i].Reserved1 = 0;
00089     }
00090 
00091     KeGetPcr()->IdtBase = KiIdt;
00092     __lidt(&KiIdtDescriptor.Limit);
00093 }
00094 
00095 static
00096 VOID
00097 KiDispatchExceptionToUser(
00098     IN PKTRAP_FRAME TrapFrame,
00099     IN PCONTEXT Context,
00100     IN PEXCEPTION_RECORD ExceptionRecord)
00101 {
00102     EXCEPTION_RECORD LocalExceptRecord;
00103     ULONG Size;
00104     ULONG64 UserRsp;
00105     PCONTEXT UserContext;
00106     PEXCEPTION_RECORD UserExceptionRecord;
00107 
00108     /* Make sure we have a valid SS */
00109     if (TrapFrame->SegSs != (KGDT64_R3_DATA | RPL_MASK))
00110     {
00111         /* Raise an access violation instead */
00112         LocalExceptRecord.ExceptionCode = STATUS_ACCESS_VIOLATION;
00113         LocalExceptRecord.ExceptionFlags = 0;
00114         LocalExceptRecord.NumberParameters = 0;
00115         ExceptionRecord = &LocalExceptRecord;
00116     }
00117 
00118     /* Calculate the size of the exception record */
00119     Size = FIELD_OFFSET(EXCEPTION_RECORD, ExceptionInformation) +
00120            ExceptionRecord->NumberParameters * sizeof(ULONG64);
00121 
00122     /* Get new stack pointer and align it to 16 bytes */
00123     UserRsp = (Context->Rsp - Size - sizeof(CONTEXT)) & ~15;
00124 
00125     /* Get pointers to the usermode context and exception record */
00126     UserContext = (PVOID)UserRsp;
00127     UserExceptionRecord = (PVOID)(UserRsp + sizeof(CONTEXT));
00128 
00129     /* Set up the user-stack */
00130     _SEH2_TRY
00131     {
00132         /* Probe stack and copy Context */
00133         ProbeForWrite(UserContext, sizeof(CONTEXT), sizeof(ULONG64));
00134         *UserContext = *Context;
00135 
00136         /* Probe stack and copy exception record */
00137         ProbeForWrite(UserExceptionRecord, Size, sizeof(ULONG64));
00138         *UserExceptionRecord = *ExceptionRecord;
00139     }
00140     _SEH2_EXCEPT((LocalExceptRecord = *_SEH2_GetExceptionInformation()->ExceptionRecord),
00141                  EXCEPTION_EXECUTE_HANDLER)
00142     {
00143         // FIXNE: handle stack overflow
00144 
00145         /* Nothing we can do here */
00146         _SEH2_YIELD(return);
00147     }
00148     _SEH2_END;
00149 
00150     /* Now set the two params for the user-mode dispatcher */
00151     TrapFrame->Rcx = (ULONG64)UserContext;
00152     TrapFrame->Rdx = (ULONG64)UserExceptionRecord;
00153 
00154     /* Set new Stack Pointer */
00155     TrapFrame->Rsp = UserRsp;
00156 
00157     /* Force correct segments */
00158     TrapFrame->SegCs = KGDT64_R3_CODE | RPL_MASK;
00159     TrapFrame->SegDs = KGDT64_R3_DATA | RPL_MASK;
00160     TrapFrame->SegEs = KGDT64_R3_DATA | RPL_MASK;
00161     TrapFrame->SegFs = KGDT64_R3_CMTEB | RPL_MASK;
00162     TrapFrame->SegGs = KGDT64_R3_DATA | RPL_MASK;
00163     TrapFrame->SegSs = KGDT64_R3_DATA | RPL_MASK;
00164 
00165     /* Set RIP to the User-mode Dispatcher */
00166     TrapFrame->Rip = (ULONG64)KeUserExceptionDispatcher;
00167 
00168     /* Exit to usermode */
00169     KiServiceExit2(TrapFrame);
00170 }
00171 
00172 static
00173 VOID
00174 KiPageInDirectory(PVOID ImageBase, USHORT Directory)
00175 {
00176     volatile CHAR *Pointer;
00177     ULONG Size;
00178 
00179    /* Get a pointer to the debug directory */
00180     Pointer = RtlImageDirectoryEntryToData(ImageBase, 1, Directory, &Size);
00181     if (!Pointer) return;
00182 
00183     /* Loop all pages */
00184     while ((LONG)Size > 0)
00185     {
00186         /* Touch it, to page it in */
00187         (void)*Pointer;
00188         Pointer += PAGE_SIZE;
00189         Size -= PAGE_SIZE;
00190     }
00191 }
00192 
00193 VOID
00194 KiPrepareUserDebugData(void)
00195 {
00196     PLDR_DATA_TABLE_ENTRY LdrEntry;
00197     PPEB_LDR_DATA PebLdr;
00198     PLIST_ENTRY ListEntry;
00199     PTEB Teb;
00200 
00201     /* Get the Teb for this process */
00202     Teb = KeGetCurrentThread()->Teb;
00203     if (!Teb) return;
00204 
00205     _SEH2_TRY
00206     {
00207         /* Get a pointer to the loader data */
00208         PebLdr = Teb->ProcessEnvironmentBlock->Ldr;
00209         if (!PebLdr) _SEH2_YIELD(return);
00210 
00211         /* Now loop all entries in the module list */
00212         for (ListEntry = PebLdr->InLoadOrderModuleList.Flink;
00213              ListEntry != &PebLdr->InLoadOrderModuleList;
00214              ListEntry = ListEntry->Flink)
00215         {
00216             /* Get the loader entry */
00217             LdrEntry = CONTAINING_RECORD(ListEntry,
00218                                          LDR_DATA_TABLE_ENTRY,
00219                                          InLoadOrderLinks);
00220 
00221             KiPageInDirectory((PVOID)LdrEntry->DllBase,
00222                               IMAGE_DIRECTORY_ENTRY_DEBUG);
00223 
00224             KiPageInDirectory((PVOID)LdrEntry->DllBase,
00225                               IMAGE_DIRECTORY_ENTRY_EXCEPTION);
00226         }
00227 
00228     }
00229     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00230     {
00231     }
00232     _SEH2_END
00233 }
00234 
00235 VOID
00236 NTAPI
00237 KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
00238                     IN PKEXCEPTION_FRAME ExceptionFrame,
00239                     IN PKTRAP_FRAME TrapFrame,
00240                     IN KPROCESSOR_MODE PreviousMode,
00241                     IN BOOLEAN FirstChance)
00242 {
00243     CONTEXT Context;
00244 
00245     /* Increase number of Exception Dispatches */
00246     KeGetCurrentPrcb()->KeExceptionDispatchCount++;
00247 
00248     /* Set the context flags */
00249     Context.ContextFlags = CONTEXT_ALL;
00250 
00251     /* Get a Context */
00252     KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
00253 
00254     /* Look at our exception code */
00255     switch (ExceptionRecord->ExceptionCode)
00256     {
00257         /* Breakpoint */
00258         case STATUS_BREAKPOINT:
00259 
00260             /* Decrement RIP by one */
00261             Context.Rip--;
00262             break;
00263 
00264         /* Internal exception */
00265         case KI_EXCEPTION_ACCESS_VIOLATION:
00266 
00267             /* Set correct code */
00268             ExceptionRecord->ExceptionCode = STATUS_ACCESS_VIOLATION;
00269             if (PreviousMode == UserMode)
00270             {
00271                 /* FIXME: Handle no execute */
00272             }
00273             break;
00274     }
00275 
00276     /* Handle kernel-mode first, it's simpler */
00277     if (PreviousMode == KernelMode)
00278     {
00279         /* Check if this is a first-chance exception */
00280         if (FirstChance == TRUE)
00281         {
00282             /* Break into the debugger for the first time */
00283             if (KiDebugRoutine(TrapFrame,
00284                                ExceptionFrame,
00285                                ExceptionRecord,
00286                                &Context,
00287                                PreviousMode,
00288                                FALSE))
00289             {
00290                 /* Exception was handled */
00291                 goto Handled;
00292             }
00293 
00294             /* If the Debugger couldn't handle it, dispatch the exception */
00295             if (RtlDispatchException(ExceptionRecord, &Context)) goto Handled;
00296         }
00297 
00298         /* This is a second-chance exception, only for the debugger */
00299         if (KiDebugRoutine(TrapFrame,
00300                            ExceptionFrame,
00301                            ExceptionRecord,
00302                            &Context,
00303                            PreviousMode,
00304                            TRUE))
00305         {
00306             /* Exception was handled */
00307             goto Handled;
00308         }
00309 
00310         /* Third strike; you're out */
00311         KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
00312                      ExceptionRecord->ExceptionCode,
00313                      (ULONG_PTR)ExceptionRecord->ExceptionAddress,
00314                      (ULONG_PTR)TrapFrame,
00315                      0);
00316     }
00317     else
00318     {
00319         /* User mode exception, was it first-chance? */
00320         if (FirstChance)
00321         {
00322             /*
00323              * Break into the kernel debugger unless a user mode debugger
00324              * is present or user mode exceptions are ignored, except if this
00325              * is a debug service which we must always pass to KD
00326              */
00327             if ((!(PsGetCurrentProcess()->DebugPort) &&
00328                  !(KdIgnoreUmExceptions)) ||
00329                  (KdIsThisAKdTrap(ExceptionRecord, &Context, PreviousMode)))
00330             {
00331                 /* Make sure the debugger can access debug directories */
00332                 KiPrepareUserDebugData();
00333 
00334                 /* Call the kernel debugger */
00335                 if (KiDebugRoutine(TrapFrame,
00336                                    ExceptionFrame,
00337                                    ExceptionRecord,
00338                                    &Context,
00339                                    PreviousMode,
00340                                    FALSE))
00341                 {
00342                     /* Exception was handled */
00343                     goto Handled;
00344                 }
00345             }
00346 
00347             /* Forward exception to user mode debugger */
00348             if (DbgkForwardException(ExceptionRecord, TRUE, FALSE)) return;
00349 
00350             //KiDispatchExceptionToUser()
00351             __debugbreak();
00352         }
00353 
00354         /* Try second chance */
00355         if (DbgkForwardException(ExceptionRecord, TRUE, TRUE))
00356         {
00357             /* Handled, get out */
00358             return;
00359         }
00360         else if (DbgkForwardException(ExceptionRecord, FALSE, TRUE))
00361         {
00362             /* Handled, get out */
00363             return;
00364         }
00365 
00366         /* 3rd strike, kill the process */
00367         DPRINT1("Kill %.16s, ExceptionCode: %lx, ExceptionAddress: %lx, BaseAddress: %lx\n",
00368                 PsGetCurrentProcess()->ImageFileName,
00369                 ExceptionRecord->ExceptionCode,
00370                 ExceptionRecord->ExceptionAddress,
00371                 PsGetCurrentProcess()->SectionBaseAddress);
00372 
00373         ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord->ExceptionCode);
00374         KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
00375                      ExceptionRecord->ExceptionCode,
00376                      (ULONG_PTR)ExceptionRecord->ExceptionAddress,
00377                      (ULONG_PTR)TrapFrame,
00378                      0);
00379     }
00380 
00381 Handled:
00382     /* Convert the context back into Trap/Exception Frames */
00383     KeContextToTrapFrame(&Context,
00384                          ExceptionFrame,
00385                          TrapFrame,
00386                          Context.ContextFlags,
00387                          PreviousMode);
00388     return;
00389 }
00390 
00391 NTSTATUS
00392 NTAPI
00393 KeRaiseUserException(IN NTSTATUS ExceptionCode)
00394 {
00395     UNIMPLEMENTED;
00396     return STATUS_UNSUCCESSFUL;
00397 }
00398 
00399 
00400 VOID
00401 DECLSPEC_NORETURN
00402 KiSystemFatalException(IN ULONG ExceptionCode,
00403                        IN PKTRAP_FRAME TrapFrame)
00404 {
00405     /* Bugcheck the system */
00406     KeBugCheckWithTf(UNEXPECTED_KERNEL_MODE_TRAP,
00407                      ExceptionCode,
00408                      0,
00409                      0,
00410                      0,
00411                      TrapFrame);
00412 }
00413 
00414 NTSTATUS
00415 NTAPI
00416 KiNpxNotAvailableFaultHandler(
00417     IN PKTRAP_FRAME TrapFrame)
00418 {
00419     UNIMPLEMENTED;
00420     KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 1, TrapFrame);
00421     return -1;
00422 }
00423 
00424 
00425 NTSTATUS
00426 NTAPI
00427 KiGeneralProtectionFaultHandler(
00428     IN PKTRAP_FRAME TrapFrame)
00429 {
00430     PUCHAR Instructions;
00431 
00432     /* Check for user-mode GPF */
00433     if (TrapFrame->SegCs & 3)
00434     {
00435         UNIMPLEMENTED;
00436         ASSERT(FALSE);
00437     }
00438 
00439     /* Check for lazy segment load */
00440     if (TrapFrame->SegDs != (KGDT64_R3_DATA | RPL_MASK))
00441     {
00442         /* Fix it */
00443         TrapFrame->SegDs = (KGDT64_R3_DATA | RPL_MASK);
00444         return STATUS_SUCCESS;
00445     }
00446     else if (TrapFrame->SegEs != (KGDT64_R3_DATA | RPL_MASK))
00447     {
00448         /* Fix it */
00449         TrapFrame->SegEs = (KGDT64_R3_DATA | RPL_MASK);
00450         return STATUS_SUCCESS;
00451     }
00452 
00453     /* Check for nested exception */
00454     if ((TrapFrame->Rip >= (ULONG64)KiGeneralProtectionFaultHandler) &&
00455         (TrapFrame->Rip < (ULONG64)KiGeneralProtectionFaultHandler))
00456     {
00457         /* Not implemented */
00458         UNIMPLEMENTED;
00459         ASSERT(FALSE);
00460     }
00461 
00462     /* Get Instruction Pointer */
00463     Instructions = (PUCHAR)TrapFrame->Rip;
00464 
00465     /* Check for IRET */
00466     if (Instructions[0] == 0x48 && Instructions[1] == 0xCF)
00467     {
00468         /* Not implemented */
00469         UNIMPLEMENTED;
00470         ASSERT(FALSE);
00471     }
00472 
00473     /* Check for RDMSR/WRMSR */
00474     if ((Instructions[0] == 0xF) &&            // 2-byte opcode
00475         ((Instructions[1] == 0x30) ||        // RDMSR
00476          (Instructions[1] == 0x32)))         // WRMSR
00477     {
00478         /* Unknown CPU MSR, so raise an access violation */
00479         return STATUS_ACCESS_VIOLATION;
00480     }
00481 
00482     ASSERT(FALSE);
00483     return STATUS_UNSUCCESSFUL;
00484 }
00485 
00486 NTSTATUS
00487 NTAPI
00488 KiXmmExceptionHandler(
00489     IN PKTRAP_FRAME TrapFrame)
00490 {
00491     UNIMPLEMENTED;
00492     KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 1, TrapFrame);
00493     return -1;
00494 }

Generated on Sat May 26 2012 04:22:57 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.