VOID KeBugCheckEx ( IN ULONG BugCheckCode, IN ULONG_PTR BugCheckParameter1, IN ULONG_PTR BugCheckParameter2, IN ULONG_PTR BugCheckParameter3, IN ULONG_PTR BugCheckParameter4 ) /*++ Routine Description: This function crashes the system in a controlled manner. Arguments: BugCheckCode - Supplies the reason for the bug check. BugCheckParameter1-4 - Supplies additional bug check information Return Value: None. --*/ { UCHAR Buffer[100]; ULONG_PTR BugCheckParameters[4]; CONTEXT ContextSave; ULONG PssMessage; PCHAR HardErrorCaption; PCHAR HardErrorMessage; KIRQL OldIrql; PKTRAP_FRAME TrapInformation; PVOID ExecutionAddress; PVOID ImageBase; PVOID VirtualAddress; PLDR_DATA_TABLE_ENTRY DataTableEntry; UCHAR AnsiBuffer[32]; PKTHREAD Thread; BOOLEAN InKernelOrHal; BOOLEAN DontCare; #if !defined(NT_UP) ULONG TargetSet; #endif BOOLEAN hardErrorCalled; // // Try to simulate a power failure for Cluster testing // if (BugCheckCode == POWER_FAILURE_SIMULATE) { KiScanBugCheckCallbackList(); HalReturnToFirmware(HalRebootRoutine); } // // Capture the callers context as closely as possible into the debugger's // processor state area of the Prcb. // // N.B. There may be some prologue code that shuffles registers such that // they get destroyed. // #if defined(i386) KiSetHardwareTrigger(); #else KiHardwareTrigger = 1; #endif RtlCaptureContext(&KeGetCurrentPrcb()->ProcessorState.ContextFrame); KiSaveProcessorControlState(&KeGetCurrentPrcb()->ProcessorState); // // This is necessary on machines where the virtual unwind that happens // during KeDumpMachineState() destroys the context record. // ContextSave = KeGetCurrentPrcb()->ProcessorState.ContextFrame; // // If we are called by hard error then we don't want to dump the // processor state on the machine. // // We know that we are called by hard error because the bug check // code will be FATAL_UNHANDLED_HARD_ERROR. If this is so then the // error status passed to harderr is the first parameter, and a pointer // to the parameter array from hard error is passed as the second // argument. // // The third argument is the OemCaption to be printed. // The last argument is the OemMessage to be printed. // if (BugCheckCode == FATAL_UNHANDLED_HARD_ERROR) { PULONG_PTR parameterArray; hardErrorCalled = TRUE; HardErrorCaption = (PCHAR)BugCheckParameter3; HardErrorMessage = (PCHAR)BugCheckParameter4; parameterArray = (PULONG_PTR)BugCheckParameter2; BugCheckCode = (ULONG)BugCheckParameter1; BugCheckParameter1 = parameterArray[0]; BugCheckParameter2 = parameterArray[1]; BugCheckParameter3 = parameterArray[2]; BugCheckParameter4 = parameterArray[3]; } else { hardErrorCalled = FALSE; switch (BugCheckCode) { case IRQL_NOT_LESS_OR_EQUAL: ExecutionAddress = (PVOID)BugCheckParameter4; if (ExecutionAddress >= ExPoolCodeStart && ExecutionAddress < ExPoolCodeEnd) { BugCheckCode = DRIVER_CORRUPTED_EXPOOL; } else if (ExecutionAddress >= MmPoolCodeStart && ExecutionAddress < MmPoolCodeEnd) { BugCheckCode = DRIVER_CORRUPTED_MMPOOL; } else if (ExecutionAddress >= MmPteCodeStart && ExecutionAddress < MmPteCodeEnd) { BugCheckCode = DRIVER_CORRUPTED_SYSPTES; } else { ImageBase = KiPcToFileHeader (ExecutionAddress, &DataTableEntry, FALSE, &InKernelOrHal); if (InKernelOrHal == TRUE) { // // The kernel faulted at raised IRQL. Quite often this // is a driver that has unloaded without deleting its // lookaside lists or other resources. Or its resources // are marked pagable and shouldn't be. Detect both // cases here and identify the offending driver // whenever possible. // VirtualAddress = (PVOID)BugCheckParameter1; ImageBase = KiPcToFileHeader (VirtualAddress, &DataTableEntry, TRUE, &InKernelOrHal); if (ImageBase != NULL) { KiBugCheckDriver = &DataTableEntry->BaseDllName; BugCheckCode = DRIVER_PORTION_MUST_BE_NONPAGED; } else { KiBugCheckDriver = MmLocateUnloadedDriver (VirtualAddress); if (KiBugCheckDriver != NULL) { BugCheckCode = SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD; } } } else { BugCheckCode = DRIVER_IRQL_NOT_LESS_OR_EQUAL; } } break; case ATTEMPTED_WRITE_TO_READONLY_MEMORY: KiBugCheckDriver = NULL; TrapInformation = (PKTRAP_FRAME)BugCheckParameter3; // // Extract the execution address from the trap frame to // identify the component. // if (TrapInformation != NULL) { ExecutionAddress = (PVOID)PROGRAM_COUNTER (TrapInformation); ImageBase = KiPcToFileHeader (ExecutionAddress, &DataTableEntry, TRUE, &InKernelOrHal); if (ImageBase != NULL) { KiBugCheckDriver = &DataTableEntry->BaseDllName; } } break; case DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS: ExecutionAddress = (PVOID)BugCheckParameter1; ImageBase = KiPcToFileHeader (ExecutionAddress, &DataTableEntry, TRUE, &InKernelOrHal); if (ImageBase != NULL) { KiBugCheckDriver = &DataTableEntry->BaseDllName; } else { KiBugCheckDriver = MmLocateUnloadedDriver (ExecutionAddress); } BugCheckParameter4 = (ULONG_PTR)KiBugCheckDriver; break; case DRIVER_USED_EXCESSIVE_PTES: DataTableEntry = (PLDR_DATA_TABLE_ENTRY)BugCheckParameter1; KiBugCheckDriver = &DataTableEntry->BaseDllName; break; case PAGE_FAULT_IN_NONPAGED_AREA: ExecutionAddress = NULL; KiBugCheckDriver = NULL; VirtualAddress = (PVOID)BugCheckParameter1; TrapInformation = (PKTRAP_FRAME)BugCheckParameter3; // // Extract the execution address from the trap frame to // identify the component. // if (TrapInformation != NULL) { ExecutionAddress = (PVOID)PROGRAM_COUNTER (TrapInformation); BugCheckParameter3 = (ULONG_PTR)ExecutionAddress; KiPcToFileHeader (ExecutionAddress, &DataTableEntry, FALSE, &InKernelOrHal); ImageBase = KiPcToFileHeader (ExecutionAddress, &DataTableEntry, TRUE, &DontCare); if (ImageBase != NULL) { KiBugCheckDriver = &DataTableEntry->BaseDllName; } } else { // // No trap frame, so no execution address either. // BugCheckParameter3 = 0; } Thread = KeGetCurrentThread(); if ((VirtualAddress >= MmSpecialPoolStart) && (VirtualAddress < MmSpecialPoolEnd)) { // // Update the bugcheck number so the administrator gets // useful feedback that enabling special pool has enabled // the system to locate the corruptor. // if (MmIsSpecialPoolAddressFree (VirtualAddress) == TRUE) { if (InKernelOrHal == TRUE) { BugCheckCode = PAGE_FAULT_IN_FREED_SPECIAL_POOL; } else { BugCheckCode = DRIVER_PAGE_FAULT_IN_FREED_SPECIAL_POOL; } } else { if (InKernelOrHal == TRUE) { BugCheckCode = PAGE_FAULT_BEYOND_END_OF_ALLOCATION; } else { BugCheckCode = DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION; } } } else if ((ExecutionAddress == VirtualAddress) && (MmIsHydraAddress (VirtualAddress) == TRUE) && ((Thread->Teb == NULL) || (IS_SYSTEM_ADDRESS(Thread->Teb)))) { // // This is a driver reference to session space from a // worker thread. Since the system process has no session // space this is illegal and the driver must be fixed. // BugCheckCode = TERMINAL_SERVER_DRIVER_MADE_INCORRECT_MEMORY_REFERENCE; } else { KiBugCheckDriver = MmLocateUnloadedDriver (VirtualAddress); if (KiBugCheckDriver != NULL) { BugCheckCode = DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS; } } break; default: break; } } if (KiBugCheckDriver != NULL) { KeBugCheckUnicodeToAnsi (KiBugCheckDriver, AnsiBuffer, sizeof (AnsiBuffer)); } KiBugCheckData[0] = BugCheckCode; KiBugCheckData[1] = BugCheckParameter1; KiBugCheckData[2] = BugCheckParameter2; KiBugCheckData[3] = BugCheckParameter3; KiBugCheckData[4] = BugCheckParameter4; BugCheckParameters[0] = BugCheckParameter1; BugCheckParameters[1] = BugCheckParameter2; BugCheckParameters[2] = BugCheckParameter3; BugCheckParameters[3] = BugCheckParameter4; if (KdPitchDebugger == FALSE ) { KdDebuggerDataBlock.SavedContext = (ULONG_PTR) &ContextSave; } // // If the user manually crashed the machine, skips the DbgPrints and // go to the crashdump. // Trying to do DbgPrint causes us to reeeter the debugger which causes // some problems. // // Otherwise, if the debugger is enabled, print out the information and // stop. // if ((BugCheckCode != MANUALLY_INITIATED_CRASH) && (KdDebuggerEnabled)) { DbgPrint("\n*** Fatal System Error: 0x%08lx\n" " (0x%p,0x%p,0x%p,0x%p)\n\n", BugCheckCode, BugCheckParameter1, BugCheckParameter2, BugCheckParameter3, BugCheckParameter4); // // If the debugger is not actually connected, or the user manually // crashed the machine by typing .crash in the debugger, proceed to // "blue screen" the system. // // The call to DbgPrint above will have set the state of // KdDebuggerNotPresent if the debugger has become disconnected // since the system was booted. // if (KdDebuggerNotPresent == FALSE) { if (KiBugCheckDriver != NULL) { DbgPrint("The %s driver may be at fault.\n", AnsiBuffer); } if (hardErrorCalled != FALSE) { if (HardErrorCaption) { DbgPrint(HardErrorCaption); } if (HardErrorMessage) { DbgPrint(HardErrorMessage); } } KiBugCheckDebugBreak (DBG_STATUS_BUGCHECK_FIRST); } } // // Freeze execution of the system by disabling interrupts and looping. // KiDisableInterrupts(); KeRaiseIrql(HIGH_LEVEL, &OldIrql); // // Don't attempt to display message more than once. // if (InterlockedDecrement (&KeBugCheckCount) == 0) { #if !defined(NT_UP) // // Attempt to get the other processors frozen now, but don't wait // for them to freeze (in case someone is stuck). // TargetSet = KeActiveProcessors & ~KeGetCurrentPrcb()->SetMember; if (TargetSet != 0) { KiIpiSend((KAFFINITY) TargetSet, IPI_FREEZE); // // Give the other processors one second to flush their data caches. // // N.B. This cannot be synchronized since the reason for the bug // may be one of the other processors failed. // KeStallExecutionProcessor(1000 * 1000); } #endif // // Enable InbvDisplayString calls to make it through to bootvid driver. // if (InbvIsBootDriverInstalled()) { InbvAcquireDisplayOwnership(); InbvResetDisplay(); InbvSolidColorFill(0,0,639,479,4); // make the screen blue InbvSetTextColor(15); InbvInstallDisplayStringFilter((INBV_DISPLAY_STRING_FILTER)NULL); InbvEnableDisplayString(TRUE); // enable display string InbvSetScrollRegion(0,0,639,479); // set to use entire screen } if (!hardErrorCalled) { sprintf((char *)Buffer, "\n*** STOP: 0x%08lX (0x%p,0x%p,0x%p,0x%p)\n", BugCheckCode, BugCheckParameter1, BugCheckParameter2, BugCheckParameter3, BugCheckParameter4 ); InbvDisplayString((char *)Buffer); KeGetBugMessageText(BugCheckCode, NULL); InbvDisplayString("\n"); if (KiBugCheckDriver != NULL) { // // Output the driver name. // KeGetBugMessageText(BUGCODE_ID_DRIVER, NULL); InbvDisplayString(AnsiBuffer); InbvDisplayString("\n"); } } else { if (HardErrorCaption) { InbvDisplayString(HardErrorCaption); } if (HardErrorMessage) { InbvDisplayString(HardErrorMessage); } } // // Process the bug check callback list. // KiScanBugCheckCallbackList(); // // If the debugger is not enabled, then dump the machine state and // attempt to enable the debugger. // if (!hardErrorCalled) { KiDumpParameterImages( (char *)Buffer, BugCheckParameters, 4, KeBugCheckUnicodeToAnsi); } if (KdDebuggerEnabled == FALSE && KdPitchDebugger == FALSE ) { KdInitSystem(NULL, FALSE); } else { InbvDisplayString("\n"); } // // Write a crash dump and optionally reboot if the system has been // so configured. // KeGetCurrentPrcb()->ProcessorState.ContextFrame = ContextSave; if (!IoWriteCrashDump(BugCheckCode, BugCheckParameter1, BugCheckParameter2, BugCheckParameter3, BugCheckParameter4, &ContextSave )) { // // If no crashdump take, display the PSS message. // switch ( BugCheckCode ) { case IRQL_NOT_LESS_OR_EQUAL: case DRIVER_IRQL_NOT_LESS_OR_EQUAL: case DRIVER_CORRUPTED_EXPOOL: case DRIVER_CORRUPTED_MMPOOL: case DRIVER_PORTION_MUST_BE_NONPAGED: case SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD: PssMessage = BUGCODE_PSS_MESSAGE_A; break; case KMODE_EXCEPTION_NOT_HANDLED: PssMessage = BUGCODE_PSS_MESSAGE_1E; break; case FAT_FILE_SYSTEM: case NTFS_FILE_SYSTEM: PssMessage = BUGCODE_PSS_MESSAGE_23; break; case DATA_BUS_ERROR: PssMessage = BUGCODE_PSS_MESSAGE_2E; break; case NO_MORE_SYSTEM_PTES: PssMessage = BUGCODE_PSS_MESSAGE_3F; break; case INACCESSIBLE_BOOT_DEVICE: PssMessage = BUGCODE_PSS_MESSAGE_7B; break; case UNEXPECTED_KERNEL_MODE_TRAP: PssMessage = BUGCODE_PSS_MESSAGE_7F; break; case STATUS_SYSTEM_IMAGE_BAD_SIGNATURE: PssMessage = BUGCODE_PSS_MESSAGE_SIGNATURE; break; case ACPI_BIOS_ERROR: PssMessage = BUGCODE_PSS_MESSAGE_A5; break; case ACPI_BIOS_FATAL_ERROR: PssMessage = ACPI_BIOS_FATAL_ERROR; break; default: PssMessage = BUGCODE_PSS_MESSAGE; break; } KeGetBugMessageText(PssMessage, NULL); } } // // Attempt to enter the kernel debugger. // KiBugCheckDebugBreak (DBG_STATUS_BUGCHECK_SECOND); return; }
/* * @implemented */ BOOLEAN NTAPI KeInsertQueueDpc(IN PKDPC Dpc, IN PVOID SystemArgument1, IN PVOID SystemArgument2) { KIRQL OldIrql; PKPRCB Prcb, CurrentPrcb; ULONG Cpu; PKDPC_DATA DpcData; BOOLEAN DpcConfigured = FALSE, DpcInserted = FALSE; ASSERT_DPC(Dpc); /* Check IRQL and Raise it to HIGH_LEVEL */ KeRaiseIrql(HIGH_LEVEL, &OldIrql); CurrentPrcb = KeGetCurrentPrcb(); /* Check if the DPC has more then the maximum number of CPUs */ if (Dpc->Number >= MAXIMUM_PROCESSORS) { /* Then substract the maximum and get that PRCB. */ Cpu = Dpc->Number - MAXIMUM_PROCESSORS; Prcb = KiProcessorBlock[Cpu]; } else { /* Use the current one */ Prcb = CurrentPrcb; Cpu = Prcb->Number; } /* ROS Sanity Check */ ASSERT(Prcb == CurrentPrcb); /* Check if this is a threaded DPC and threaded DPCs are enabled */ if ((Dpc->Type == ThreadedDpcObject) && (Prcb->ThreadDpcEnable)) { /* Then use the threaded data */ DpcData = &Prcb->DpcData[DPC_THREADED]; } else { /* Otherwise, use the regular data */ DpcData = &Prcb->DpcData[DPC_NORMAL]; } /* Acquire the DPC lock */ KiAcquireSpinLock(&DpcData->DpcLock); /* Get the DPC Data */ if (!InterlockedCompareExchangePointer(&Dpc->DpcData, DpcData, NULL)) { /* Now we can play with the DPC safely */ Dpc->SystemArgument1 = SystemArgument1; Dpc->SystemArgument2 = SystemArgument2; DpcData->DpcQueueDepth++; DpcData->DpcCount++; DpcConfigured = TRUE; /* Check if this is a high importance DPC */ if (Dpc->Importance == HighImportance) { /* Pre-empty other DPCs */ InsertHeadList(&DpcData->DpcListHead, &Dpc->DpcListEntry); } else { /* Add it at the end */ InsertTailList(&DpcData->DpcListHead, &Dpc->DpcListEntry); } /* Check if this is the DPC on the threaded list */ if (&Prcb->DpcData[DPC_THREADED] == DpcData) { /* Make sure a threaded DPC isn't already active */ if (!(Prcb->DpcThreadActive) && !(Prcb->DpcThreadRequested)) { /* FIXME: Setup Threaded DPC */ DPRINT1("Threaded DPC not supported\n"); while (TRUE); } } else { /* Make sure a DPC isn't executing already */ if (!(Prcb->DpcRoutineActive) && !(Prcb->DpcInterruptRequested)) { /* Check if this is the same CPU */ if (Prcb != CurrentPrcb) { /* * Check if the DPC is of high importance or above the * maximum depth. If it is, then make sure that the CPU * isn't idle, or that it's sleeping. */ if (((Dpc->Importance == HighImportance) || (DpcData->DpcQueueDepth >= Prcb->MaximumDpcQueueDepth)) && (!(AFFINITY_MASK(Cpu) & KiIdleSummary) || (Prcb->Sleeping))) { /* Set interrupt requested */ Prcb->DpcInterruptRequested = TRUE; /* Set DPC inserted */ DpcInserted = TRUE; } } else { /* Check if the DPC is of anything but low importance */ if ((Dpc->Importance != LowImportance) || (DpcData->DpcQueueDepth >= Prcb->MaximumDpcQueueDepth) || (Prcb->DpcRequestRate < Prcb->MinimumDpcRate)) { /* Set interrupt requested */ Prcb->DpcInterruptRequested = TRUE; /* Set DPC inserted */ DpcInserted = TRUE; } } } } } /* Release the lock */ KiReleaseSpinLock(&DpcData->DpcLock); /* Check if the DPC was inserted */ if (DpcInserted) { /* Check if this was SMP */ if (Prcb != CurrentPrcb) { /* It was, request and IPI */ KiIpiSend(AFFINITY_MASK(Cpu), IPI_DPC); } else { /* It wasn't, request an interrupt from HAL */ HalRequestSoftwareInterrupt(DISPATCH_LEVEL); } } /* Lower IRQL */ KeLowerIrql(OldIrql); return DpcConfigured; }
VOID NTAPI KeBugCheckWithTf(IN ULONG BugCheckCode, IN ULONG_PTR BugCheckParameter1, IN ULONG_PTR BugCheckParameter2, IN ULONG_PTR BugCheckParameter3, IN ULONG_PTR BugCheckParameter4, IN PKTRAP_FRAME TrapFrame) { PKPRCB Prcb = KeGetCurrentPrcb(); CONTEXT Context; ULONG MessageId; CHAR AnsiName[128]; BOOLEAN IsSystem, IsHardError = FALSE, Reboot = FALSE; PCHAR HardErrCaption = NULL, HardErrMessage = NULL; PVOID Pc = NULL, Memory; PVOID DriverBase; PLDR_DATA_TABLE_ENTRY LdrEntry; PULONG_PTR HardErrorParameters; KIRQL OldIrql; #ifdef CONFIG_SMP LONG i = 0; #endif /* Set active bugcheck */ KeBugCheckActive = TRUE; KiBugCheckDriver = NULL; /* Check if this is power failure simulation */ if (BugCheckCode == POWER_FAILURE_SIMULATE) { /* Call the Callbacks and reboot */ KiDoBugCheckCallbacks(); HalReturnToFirmware(HalRebootRoutine); } /* Save the IRQL and set hardware trigger */ Prcb->DebuggerSavedIRQL = KeGetCurrentIrql(); InterlockedIncrement((PLONG)&KiHardwareTrigger); /* Capture the CPU Context */ RtlCaptureContext(&Prcb->ProcessorState.ContextFrame); KiSaveProcessorControlState(&Prcb->ProcessorState); Context = Prcb->ProcessorState.ContextFrame; /* FIXME: Call the Watchdog if it's registered */ /* Check which bugcode this is */ switch (BugCheckCode) { /* These bug checks already have detailed messages, keep them */ case UNEXPECTED_KERNEL_MODE_TRAP: case DRIVER_CORRUPTED_EXPOOL: case ACPI_BIOS_ERROR: case ACPI_BIOS_FATAL_ERROR: case THREAD_STUCK_IN_DEVICE_DRIVER: case DATA_BUS_ERROR: case FAT_FILE_SYSTEM: case NO_MORE_SYSTEM_PTES: case INACCESSIBLE_BOOT_DEVICE: /* Keep the same code */ MessageId = BugCheckCode; break; /* Check if this is a kernel-mode exception */ case KERNEL_MODE_EXCEPTION_NOT_HANDLED: case SYSTEM_THREAD_EXCEPTION_NOT_HANDLED: case KMODE_EXCEPTION_NOT_HANDLED: /* Use the generic text message */ MessageId = KMODE_EXCEPTION_NOT_HANDLED; break; /* File-system errors */ case NTFS_FILE_SYSTEM: /* Use the generic message for FAT */ MessageId = FAT_FILE_SYSTEM; break; /* Check if this is a coruption of the Mm's Pool */ case DRIVER_CORRUPTED_MMPOOL: /* Use generic corruption message */ MessageId = DRIVER_CORRUPTED_EXPOOL; break; /* Check if this is a signature check failure */ case STATUS_SYSTEM_IMAGE_BAD_SIGNATURE: /* Use the generic corruption message */ MessageId = BUGCODE_PSS_MESSAGE_SIGNATURE; break; /* All other codes */ default: /* Use the default bugcheck message */ MessageId = BUGCODE_PSS_MESSAGE; break; } /* Save bugcheck data */ KiBugCheckData[0] = BugCheckCode; KiBugCheckData[1] = BugCheckParameter1; KiBugCheckData[2] = BugCheckParameter2; KiBugCheckData[3] = BugCheckParameter3; KiBugCheckData[4] = BugCheckParameter4; /* Now check what bugcheck this is */ switch (BugCheckCode) { /* Invalid access to R/O memory or Unhandled KM Exception */ case KERNEL_MODE_EXCEPTION_NOT_HANDLED: case ATTEMPTED_WRITE_TO_READONLY_MEMORY: case ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY: /* Check if we have a trap frame */ if (!TrapFrame) { /* Use parameter 3 as a trap frame, if it exists */ if (BugCheckParameter3) TrapFrame = (PVOID)BugCheckParameter3; } /* Check if we got one now and if we need to get the Program Counter */ if ((TrapFrame) && (BugCheckCode != KERNEL_MODE_EXCEPTION_NOT_HANDLED)) { /* Get the Program Counter */ Pc = (PVOID)KeGetTrapFramePc(TrapFrame); } break; /* Wrong IRQL */ case IRQL_NOT_LESS_OR_EQUAL: /* * The NT kernel has 3 special sections: * MISYSPTE, POOLMI and POOLCODE. The bug check code can * determine in which of these sections this bugcode happened * and provide a more detailed analysis. For now, we don't. */ /* Program Counter is in parameter 4 */ Pc = (PVOID)BugCheckParameter4; /* Get the driver base */ DriverBase = KiPcToFileHeader(Pc, &LdrEntry, FALSE, &IsSystem); if (IsSystem) { /* * The error happened inside the kernel or HAL. * Get the memory address that was being referenced. */ Memory = (PVOID)BugCheckParameter1; /* Find to which driver it belongs */ DriverBase = KiPcToFileHeader(Memory, &LdrEntry, TRUE, &IsSystem); if (DriverBase) { /* Get the driver name and update the bug code */ KiBugCheckDriver = &LdrEntry->BaseDllName; KiBugCheckData[0] = DRIVER_PORTION_MUST_BE_NONPAGED; } else { /* Find the driver that unloaded at this address */ KiBugCheckDriver = NULL; // FIXME: ROS can't locate /* Check if the cause was an unloaded driver */ if (KiBugCheckDriver) { /* Update bug check code */ KiBugCheckData[0] = SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD; } } } else { /* Update the bug check code */ KiBugCheckData[0] = DRIVER_IRQL_NOT_LESS_OR_EQUAL; } /* Clear Pc so we don't look it up later */ Pc = NULL; break; /* Hard error */ case FATAL_UNHANDLED_HARD_ERROR: /* Copy bug check data from hard error */ HardErrorParameters = (PULONG_PTR)BugCheckParameter2; KiBugCheckData[0] = BugCheckParameter1; KiBugCheckData[1] = HardErrorParameters[0]; KiBugCheckData[2] = HardErrorParameters[1]; KiBugCheckData[3] = HardErrorParameters[2]; KiBugCheckData[4] = HardErrorParameters[3]; /* Remember that this is hard error and set the caption/message */ IsHardError = TRUE; HardErrCaption = (PCHAR)BugCheckParameter3; HardErrMessage = (PCHAR)BugCheckParameter4; break; /* Page fault */ case PAGE_FAULT_IN_NONPAGED_AREA: /* Assume no driver */ DriverBase = NULL; /* Check if we have a trap frame */ if (!TrapFrame) { /* We don't, use parameter 3 if possible */ if (BugCheckParameter3) TrapFrame = (PVOID)BugCheckParameter3; } /* Check if we have a frame now */ if (TrapFrame) { /* Get the Program Counter */ Pc = (PVOID)KeGetTrapFramePc(TrapFrame); KiBugCheckData[3] = (ULONG_PTR)Pc; /* Find out if was in the kernel or drivers */ DriverBase = KiPcToFileHeader(Pc, &LdrEntry, FALSE, &IsSystem); } else { /* Can't blame a driver, assume system */ IsSystem = TRUE; } /* FIXME: Check for session pool in addition to special pool */ /* Special pool has its own bug check codes */ if (MmIsSpecialPoolAddress((PVOID)BugCheckParameter1)) { if (MmIsSpecialPoolAddressFree((PVOID)BugCheckParameter1)) { KiBugCheckData[0] = IsSystem ? PAGE_FAULT_IN_FREED_SPECIAL_POOL : DRIVER_PAGE_FAULT_IN_FREED_SPECIAL_POOL; } else { KiBugCheckData[0] = IsSystem ? PAGE_FAULT_BEYOND_END_OF_ALLOCATION : DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION; } } else if (!DriverBase) { /* Find the driver that unloaded at this address */ KiBugCheckDriver = NULL; // FIXME: ROS can't locate /* Check if the cause was an unloaded driver */ if (KiBugCheckDriver) { KiBugCheckData[0] = DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS; } } break; /* Check if the driver forgot to unlock pages */ case DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS: /* Program Counter is in parameter 1 */ Pc = (PVOID)BugCheckParameter1; break; /* Check if the driver consumed too many PTEs */ case DRIVER_USED_EXCESSIVE_PTES: /* Loader entry is in parameter 1 */ LdrEntry = (PVOID)BugCheckParameter1; KiBugCheckDriver = &LdrEntry->BaseDllName; break; /* Check if the driver has a stuck thread */ case THREAD_STUCK_IN_DEVICE_DRIVER: /* The name is in Parameter 3 */ KiBugCheckDriver = (PVOID)BugCheckParameter3; break; /* Anything else */ default: break; } /* Do we have a driver name? */ if (KiBugCheckDriver) { /* Convert it to ANSI */ KeBugCheckUnicodeToAnsi(KiBugCheckDriver, AnsiName, sizeof(AnsiName)); } else { /* Do we have a Program Counter? */ if (Pc) { /* Dump image name */ KiDumpParameterImages(AnsiName, (PULONG_PTR)&Pc, 1, KeBugCheckUnicodeToAnsi); } } /* Check if we need to save the context for KD */ #ifdef _WINKD_ if (!KdPitchDebugger) KdDebuggerDataBlock.SavedContext = (ULONG_PTR)&Context; #endif /* Check if a debugger is connected */ if ((BugCheckCode != MANUALLY_INITIATED_CRASH) && (KdDebuggerEnabled)) { /* Crash on the debugger console */ DbgPrint("\n*** Fatal System Error: 0x%08lx\n" " (0x%p,0x%p,0x%p,0x%p)\n\n", KiBugCheckData[0], KiBugCheckData[1], KiBugCheckData[2], KiBugCheckData[3], KiBugCheckData[4]); /* Check if the debugger isn't currently connected */ if (!KdDebuggerNotPresent) { /* Check if we have a driver to blame */ if (KiBugCheckDriver) { /* Dump it */ DbgPrint("Driver at fault: %s.\n", AnsiName); } /* Check if this was a hard error */ if (IsHardError) { /* Print caption and message */ if (HardErrCaption) DbgPrint(HardErrCaption); if (HardErrMessage) DbgPrint(HardErrMessage); } /* Break in the debugger */ KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_FIRST); } else { /* * ROS HACK. * Ok, so debugging is enabled, but KDBG isn't there. * We'll manually dump the stack for the user. */ KeRosDumpStackFrames(NULL, 0); /* ROS HACK 2: Generate something useful for Bugzilla */ KeRosDumpTriageForBugZillaReport(); } } /* Raise IRQL to HIGH_LEVEL */ _disable(); KeRaiseIrql(HIGH_LEVEL, &OldIrql); /* Avoid recursion */ if (!InterlockedDecrement((PLONG)&KeBugCheckCount)) { #ifdef CONFIG_SMP /* Set CPU that is bug checking now */ KeBugCheckOwner = Prcb->Number; /* Freeze the other CPUs */ for (i = 0; i < KeNumberProcessors; i++) { if (i != (LONG)KeGetCurrentProcessorNumber()) { /* Send the IPI and give them one second to catch up */ KiIpiSend(1 << i, IPI_FREEZE); KeStallExecutionProcessor(1000000); } } #endif /* Display the BSOD */ KiDisplayBlueScreen(MessageId, IsHardError, HardErrCaption, HardErrMessage, AnsiName); /* Check if the debugger is disabled but we can enable it */ if (!(KdDebuggerEnabled) && !(KdPitchDebugger)) { /* Enable it */ #ifdef _WINKD_ KdEnableDebuggerWithLock(FALSE); #endif } else { /* Otherwise, print the last line */ InbvDisplayString("\r\n"); } /* Save the context */ Prcb->ProcessorState.ContextFrame = Context; /* FIXME: Support Triage Dump */ /* FIXME: Write the crash dump */ } else { /* Increase recursion count */ KeBugCheckOwnerRecursionCount++; if (KeBugCheckOwnerRecursionCount == 2) { /* Break in the debugger */ KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND); } else if (KeBugCheckOwnerRecursionCount > 2) { /* Halt execution */ while (TRUE); } } /* Call the Callbacks */ KiDoBugCheckCallbacks(); /* FIXME: Call Watchdog if enabled */ /* Check if we have to reboot */ if (Reboot) { /* Unload symbols */ DbgUnLoadImageSymbols(NULL, (PVOID)MAXULONG_PTR, 0); HalReturnToFirmware(HalRebootRoutine); } /* Attempt to break in the debugger (otherwise halt CPU) */ KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND); /* Shouldn't get here */ ASSERT(FALSE); while (TRUE); }
BOOLEAN KeFreezeExecution ( IN PKTRAP_FRAME TrapFrame, IN PKEXCEPTION_FRAME ExceptionFrame ) /*++ Routine Description: This function freezes the execution of all other processors in the host configuration and then returns to the caller. Arguments: TrapFrame - Supplies a pointer to a trap frame that describes the trap. ExceptionFrame - Supplies a pointer to an exception frame that describes the trap. Return Value: Previous interrupt enable. --*/ { BOOLEAN Enable; #if !defined(NT_UP) BOOLEAN Flag; PKPRCB Prcb; ULONG TargetSet; ULONG BitNumber; KIRQL OldIrql; #if IDBG ULONG Count = 30000; #endif #endif // // Disable interrupts. // Enable = KiDisableInterrupts(); KiFreezeFlag = FREEZE_FROZEN; #if !defined(NT_UP) // // Raise IRQL to HIGH_LEVEL. // KeRaiseIrql(HIGH_LEVEL, &OldIrql); if (FrozenState(KeGetCurrentPrcb()->IpiFrozen) == FREEZE_OWNER) { // // This processor already owns the freeze lock. // Return without trying to re-acquire lock or without // trying to IPI the other processors again // return Enable; } // // Try to acquire the KiFreezeExecutionLock before sending the request. // To prevent deadlock from occurring, we need to accept and process // incoming FreexeExecution requests while we are waiting to acquire // the FreezeExecutionFlag. // while (KiTryToAcquireSpinLock (&KiFreezeExecutionLock) == FALSE) { // // FreezeExecutionLock is busy. Another processor may be trying // to IPI us - go service any IPI. // KiRestoreInterrupts(Enable); Flag = KiIpiServiceRoutine((PVOID)TrapFrame, (PVOID)ExceptionFrame); KiDisableInterrupts(); #if IDBG if (Flag != FALSE) { Count = 30000; continue; } KeStallExecutionProcessor (100); if (!Count--) { Count = 30000; if (KiTryToAcquireSpinLock (&KiFreezeLockBackup) == TRUE) { KiFreezeFlag |= FREEZE_BACKUP; break; } } #endif } // // After acquiring the lock flag, we send Freeze request to each processor // in the system (other than us) and wait for it to become frozen. // Prcb = KeGetCurrentPrcb(); // Do this after spinlock is acquired. TargetSet = KeActiveProcessors & ~(1 << Prcb->Number); if (TargetSet) { #if IDBG Count = 400; #endif KiFreezeOwner = Prcb; Prcb->IpiFrozen = FREEZE_OWNER | FREEZE_ACTIVE; Prcb->SkipTick = TRUE; KiIpiSend((KAFFINITY) TargetSet, IPI_FREEZE); while (TargetSet != 0) { BitNumber = KeFindFirstSetRightMember(TargetSet); ClearMember(BitNumber, TargetSet); Prcb = KiProcessorBlock[BitNumber]; #if IDBG while (Prcb->IpiFrozen != TARGET_FROZEN) { if (Count == 0) { KiFreezeFlag |= FREEZE_SKIPPED_PROCESSOR; break; } KeStallExecutionProcessor (10000); Count--; } #else while (Prcb->IpiFrozen != TARGET_FROZEN) { KeYieldProcessor(); } #endif } } // // Save the old IRQL and return whether interrupts were previous enabled. // KiOldIrql = OldIrql; #endif // !defined(NT_UP) return Enable; }
VOID FASTCALL KiDeferredReadyThread(IN PKTHREAD Thread) { PKPRCB Prcb; BOOLEAN Preempted; ULONG Processor = 0; KPRIORITY OldPriority; PKTHREAD NextThread; /* Sanity checks */ ASSERT(Thread->State == DeferredReady); ASSERT((Thread->Priority >= 0) && (Thread->Priority <= HIGH_PRIORITY)); /* Check if we have any adjusts to do */ if (Thread->AdjustReason == AdjustBoost) { /* Lock the thread */ KiAcquireThreadLock(Thread); /* Check if the priority is low enough to qualify for boosting */ if ((Thread->Priority <= Thread->AdjustIncrement) && (Thread->Priority < (LOW_REALTIME_PRIORITY - 3)) && !(Thread->DisableBoost)) { /* Calculate the new priority based on the adjust increment */ OldPriority = min(Thread->AdjustIncrement + 1, LOW_REALTIME_PRIORITY - 3); /* Make sure we're not decreasing outside of the priority range */ ASSERT((Thread->PriorityDecrement >= 0) && (Thread->PriorityDecrement <= Thread->Priority)); /* Calculate the new priority decrement based on the boost */ Thread->PriorityDecrement += ((SCHAR)OldPriority - Thread->Priority); /* Again verify that this decrement is valid */ ASSERT((Thread->PriorityDecrement >= 0) && (Thread->PriorityDecrement <= OldPriority)); /* Set the new priority */ Thread->Priority = (SCHAR)OldPriority; } /* We need 4 quanta, make sure we have them, then decrease by one */ if (Thread->Quantum < 4) Thread->Quantum = 4; Thread->Quantum--; /* Make sure the priority is still valid */ ASSERT((Thread->Priority >= 0) && (Thread->Priority <= HIGH_PRIORITY)); /* Release the lock and clear the adjust reason */ KiReleaseThreadLock(Thread); Thread->AdjustReason = AdjustNone; } else if (Thread->AdjustReason == AdjustUnwait) { /* Acquire the thread lock and check if this is a real-time thread */ KiAcquireThreadLock(Thread); if (Thread->Priority < LOW_REALTIME_PRIORITY) { /* It's not real time, but is it time critical? */ if (Thread->BasePriority >= (LOW_REALTIME_PRIORITY - 2)) { /* It is, so simply reset its quantum */ Thread->Quantum = Thread->QuantumReset; } else { /* Has the priority been adjusted previously? */ if (!(Thread->PriorityDecrement) && (Thread->AdjustIncrement)) { /* Yes, reset its quantum */ Thread->Quantum = Thread->QuantumReset; } /* Wait code already handles quantum adjustment during APCs */ if (Thread->WaitStatus != STATUS_KERNEL_APC) { /* Decrease the quantum by one and check if we're out */ if (--Thread->Quantum <= 0) { /* We are, reset the quantum and get a new priority */ Thread->Quantum = Thread->QuantumReset; Thread->Priority = KiComputeNewPriority(Thread, 1); } } } /* Now check if we have no decrement and boosts are enabled */ if (!(Thread->PriorityDecrement) && !(Thread->DisableBoost)) { /* Make sure we have an increment */ ASSERT(Thread->AdjustIncrement >= 0); /* Calculate the new priority after the increment */ OldPriority = Thread->BasePriority + Thread->AdjustIncrement; /* Check if this new priority is higher */ if (OldPriority > Thread->Priority) { /* Make sure we don't go into the real time range */ if (OldPriority >= LOW_REALTIME_PRIORITY) { /* Normalize it back down one notch */ OldPriority = LOW_REALTIME_PRIORITY - 1; } /* Check if the priority is higher then the boosted base */ if (OldPriority > (Thread->BasePriority + Thread->AdjustIncrement)) { /* Setup a priority decrement to nullify the boost */ Thread->PriorityDecrement = ((SCHAR)OldPriority - Thread->BasePriority - Thread->AdjustIncrement); } /* Make sure that the priority decrement is valid */ ASSERT((Thread->PriorityDecrement >= 0) && (Thread->PriorityDecrement <= OldPriority)); /* Set this new priority */ Thread->Priority = (SCHAR)OldPriority; } } } else { /* It's a real-time thread, so just reset its quantum */ Thread->Quantum = Thread->QuantumReset; } /* Make sure the priority makes sense */ ASSERT((Thread->Priority >= 0) && (Thread->Priority <= HIGH_PRIORITY)); /* Release the thread lock and reset the adjust reason */ KiReleaseThreadLock(Thread); Thread->AdjustReason = AdjustNone; } /* Clear thread preemption status and save current values */ Preempted = Thread->Preempted; OldPriority = Thread->Priority; Thread->Preempted = FALSE; /* Queue the thread on CPU 0 and get the PRCB and lock it */ Thread->NextProcessor = 0; Prcb = KiProcessorBlock[0]; KiAcquirePrcbLock(Prcb); /* Check if we have an idle summary */ if (KiIdleSummary) { /* Clear it and set this thread as the next one */ KiIdleSummary = 0; Thread->State = Standby; Prcb->NextThread = Thread; /* Unlock the PRCB and return */ KiReleasePrcbLock(Prcb); return; } /* Set the CPU number */ Thread->NextProcessor = (UCHAR)Processor; /* Get the next scheduled thread */ NextThread = Prcb->NextThread; if (NextThread) { /* Sanity check */ ASSERT(NextThread->State == Standby); /* Check if priority changed */ if (OldPriority > NextThread->Priority) { /* Preempt the thread */ NextThread->Preempted = TRUE; /* Put this one as the next one */ Thread->State = Standby; Prcb->NextThread = Thread; /* Set it in deferred ready mode */ NextThread->State = DeferredReady; NextThread->DeferredProcessor = Prcb->Number; KiReleasePrcbLock(Prcb); KiDeferredReadyThread(NextThread); return; } } else { /* Set the next thread as the current thread */ NextThread = Prcb->CurrentThread; if (OldPriority > NextThread->Priority) { /* Preempt it if it's already running */ if (NextThread->State == Running) NextThread->Preempted = TRUE; /* Set the thread on standby and as the next thread */ Thread->State = Standby; Prcb->NextThread = Thread; /* Release the lock */ KiReleasePrcbLock(Prcb); /* Check if we're running on another CPU */ if (KeGetCurrentProcessorNumber() != Thread->NextProcessor) { /* We are, send an IPI */ KiIpiSend(AFFINITY_MASK(Thread->NextProcessor), IPI_DPC); } return; } } /* Sanity check */ ASSERT((OldPriority >= 0) && (OldPriority <= HIGH_PRIORITY)); /* Set this thread as ready */ Thread->State = Ready; Thread->WaitTime = KeTickCount.LowPart; /* Insert this thread in the appropriate order */ Preempted ? InsertHeadList(&Prcb->DispatcherReadyListHead[OldPriority], &Thread->WaitListEntry) : InsertTailList(&Prcb->DispatcherReadyListHead[OldPriority], &Thread->WaitListEntry); /* Update the ready summary */ Prcb->ReadySummary |= PRIORITY_MASK(OldPriority); /* Sanity check */ ASSERT(OldPriority == Thread->Priority); /* Release the lock */ KiReleasePrcbLock(Prcb); }
VOID FASTCALL KiSetPriorityThread(IN PKTHREAD Thread, IN KPRIORITY Priority) { PKPRCB Prcb; ULONG Processor; BOOLEAN RequestInterrupt = FALSE; KPRIORITY OldPriority; PKTHREAD NewThread; ASSERT((Priority >= 0) && (Priority <= HIGH_PRIORITY)); /* Check if priority changed */ if (Thread->Priority != Priority) { /* Loop priority setting in case we need to start over */ for (;;) { /* Choose action based on thread's state */ if (Thread->State == Ready) { /* Make sure we're not on the ready queue */ if (!Thread->ProcessReadyQueue) { /* Get the PRCB for the thread and lock it */ Processor = Thread->NextProcessor; Prcb = KiProcessorBlock[Processor]; KiAcquirePrcbLock(Prcb); /* Make sure the thread is still ready and on this CPU */ if ((Thread->State == Ready) && (Thread->NextProcessor == Prcb->Number)) { /* Sanity check */ ASSERT((Prcb->ReadySummary & PRIORITY_MASK(Thread->Priority))); /* Remove it from the current queue */ if (RemoveEntryList(&Thread->WaitListEntry)) { /* Update the ready summary */ Prcb->ReadySummary ^= PRIORITY_MASK(Thread-> Priority); } /* Update priority */ Thread->Priority = (SCHAR)Priority; /* Re-insert it at its current priority */ KiInsertDeferredReadyList(Thread); /* Release the PRCB Lock */ KiReleasePrcbLock(Prcb); } else { /* Release the lock and loop again */ KiReleasePrcbLock(Prcb); continue; } } else { /* It's already on the ready queue, just update priority */ Thread->Priority = (SCHAR)Priority; } } else if (Thread->State == Standby) { /* Get the PRCB for the thread and lock it */ Processor = Thread->NextProcessor; Prcb = KiProcessorBlock[Processor]; KiAcquirePrcbLock(Prcb); /* Check if we're still the next thread to run */ if (Thread == Prcb->NextThread) { /* Get the old priority and update ours */ OldPriority = Thread->Priority; Thread->Priority = (SCHAR)Priority; /* Check if there was a change */ if (Priority < OldPriority) { /* Find a new thread */ NewThread = KiSelectReadyThread(Priority + 1, Prcb); if (NewThread) { /* Found a new one, set it on standby */ NewThread->State = Standby; Prcb->NextThread = NewThread; /* Dispatch our thread */ KiInsertDeferredReadyList(Thread); } } /* Release the PRCB lock */ KiReleasePrcbLock(Prcb); } else { /* Release the lock and try again */ KiReleasePrcbLock(Prcb); continue; } } else if (Thread->State == Running) { /* Get the PRCB for the thread and lock it */ Processor = Thread->NextProcessor; Prcb = KiProcessorBlock[Processor]; KiAcquirePrcbLock(Prcb); /* Check if we're still the current thread running */ if (Thread == Prcb->CurrentThread) { /* Get the old priority and update ours */ OldPriority = Thread->Priority; Thread->Priority = (SCHAR)Priority; /* Check if there was a change and there's no new thread */ if ((Priority < OldPriority) && !(Prcb->NextThread)) { /* Find a new thread */ NewThread = KiSelectReadyThread(Priority + 1, Prcb); if (NewThread) { /* Found a new one, set it on standby */ NewThread->State = Standby; Prcb->NextThread = NewThread; /* Request an interrupt */ RequestInterrupt = TRUE; } } /* Release the lock and check if we need an interrupt */ KiReleasePrcbLock(Prcb); if (RequestInterrupt) { /* Check if we're running on another CPU */ if (KeGetCurrentProcessorNumber() != Processor) { /* We are, send an IPI */ KiIpiSend(AFFINITY_MASK(Processor), IPI_DPC); } } } else { /* Thread changed, release lock and restart */ KiReleasePrcbLock(Prcb); continue; } } else if (Thread->State == DeferredReady) { /* FIXME: TODO */ DPRINT1("Deferred state not yet supported\n"); ASSERT(FALSE); } else { /* Any other state, just change priority */ Thread->Priority = (SCHAR)Priority; } /* If we got here, then thread state was consistent, so bail out */ break; } } }