VOID NTAPI PopShutdownHandler(VOID) { PUCHAR Logo1, Logo2; ULONG i; /* Stop all interrupts */ KeRaiseIrqlToDpcLevel(); _disable(); /* Do we have boot video */ if (InbvIsBootDriverInstalled()) { /* Yes we do, cleanup for shutdown screen */ if (!InbvCheckDisplayOwnership()) InbvAcquireDisplayOwnership(); InbvResetDisplay(); InbvSolidColorFill(0, 0, 639, 479, 0); InbvEnableDisplayString(TRUE); InbvSetScrollRegion(0, 0, 639, 479); /* Display shutdown logo and message */ Logo1 = InbvGetResourceAddress(IDB_SHUTDOWN_MSG); Logo2 = InbvGetResourceAddress(IDB_DEFAULT_LOGO); if ((Logo1) && (Logo2)) { InbvBitBlt(Logo1, 220, 352); InbvBitBlt(Logo2, 222, 111); } } else { /* Do it in text-mode */ for (i = 0; i < 25; i++) InbvDisplayString("\r\n"); InbvDisplayString(" "); InbvDisplayString("The system may be powered off now.\r\n"); } /* Hang the system */ for (;;) HalHaltSystem(); }
/* * @implemented */ VOID NTAPI HalDisplayString(IN PCH String) { /* Call the Inbv driver */ InbvDisplayString(String); }
BOOLEAN KeGetBugMessageText( IN ULONG MessageId, IN PANSI_STRING ReturnedString OPTIONAL ) { ULONG i; PUCHAR s; PMESSAGE_RESOURCE_BLOCK MessageBlock; PUCHAR Buffer; BOOLEAN Result; Result = FALSE; try { if (KiBugCodeMessages != NULL) { MmMakeKernelResourceSectionWritable (); MessageBlock = &KiBugCodeMessages->Blocks[0]; for (i = KiBugCodeMessages->NumberOfBlocks; i; i -= 1) { if (MessageId >= MessageBlock->LowId && MessageId <= MessageBlock->HighId) { s = (PCHAR)KiBugCodeMessages + MessageBlock->OffsetToEntries; for (i = MessageId - MessageBlock->LowId; i; i -= 1) { s += ((PMESSAGE_RESOURCE_ENTRY)s)->Length; } Buffer = ((PMESSAGE_RESOURCE_ENTRY)s)->Text; i = strlen(Buffer) - 1; while (i > 0 && (Buffer[i] == '\n' || Buffer[i] == '\r' || Buffer[i] == 0 ) ) { if (!ARGUMENT_PRESENT( ReturnedString )) { Buffer[i] = 0; } i -= 1; } if (!ARGUMENT_PRESENT( ReturnedString )) { InbvDisplayString(Buffer); } else { ReturnedString->Buffer = Buffer; ReturnedString->Length = (USHORT)(i+1); ReturnedString->MaximumLength = (USHORT)(i+1); } Result = TRUE; break; } MessageBlock += 1; } } } except ( EXCEPTION_EXECUTE_HANDLER ) { ; } return Result; }
NTSTATUS NTAPI NtDisplayString(IN PUNICODE_STRING DisplayString) { OEM_STRING OemString; /* Convert the string to OEM and display it */ RtlUnicodeStringToOemString(&OemString, DisplayString, TRUE); InbvDisplayString(OemString.Buffer); RtlFreeOemString(&OemString); /* Return success */ return STATUS_SUCCESS; }
void hal_print(char *format, ...) { char dbg_msg[MAX_PATH]; va_list args; va_start(args, format); _vsnprintf( dbg_msg, sizeof(dbg_msg), format, args); va_end(args); InbvDisplayString(dbg_msg); if (KeGetCurrentIrql() < DISPATCH_LEVEL) { dc_delay(500); } }
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; }
VOID KiDumpParameterImages( IN PCHAR Buffer, IN PULONG_PTR BugCheckParameters, IN ULONG NumberOfParameters, IN PKE_BUGCHECK_UNICODE_TO_ANSI UnicodeToAnsiRoutine ) /*++ Routine Description: This function formats and displays the image names of boogcheck parameters that happen to match an address in an image. Arguments: Buffer - Supplies a pointer to a buffer to be used to output machine state information. BugCheckParameters - Supplies additional bugcheck information. NumberOfParameters - sizeof BugCheckParameters array. UnicodeToAnsiRoutine - Supplies a pointer to a routine to convert Unicode strings to Ansi strings without touching paged translation tables. Return Value: None. --*/ { PUNICODE_STRING BugCheckDriver; PLIST_ENTRY ModuleListHead; PLIST_ENTRY Next; ULONG i; PLDR_DATA_TABLE_ENTRY DataTableEntry; PVOID ImageBase; UCHAR AnsiBuffer[ 32 ]; ULONG DateStamp; PIMAGE_NT_HEADERS NtHeaders; BOOLEAN FirstPrint = TRUE; BOOLEAN InKernelOrHal; // // At this point the context record contains the machine state at the // call to bug check. // // Put out the system version and the title line with the PSR and FSR. // // // Check to see if any BugCheckParameters are valid code addresses. // If so, print them for the user. // for (i = 0; i < NumberOfParameters; i += 1) { ImageBase = KiPcToFileHeader((PVOID) BugCheckParameters[i], &DataTableEntry, FALSE, &InKernelOrHal); if (ImageBase == NULL) { BugCheckDriver = MmLocateUnloadedDriver ((PVOID)BugCheckParameters[i]); if (BugCheckDriver == NULL) { continue; } ImageBase = (PVOID)BugCheckParameters[i]; DateStamp = 0; (*UnicodeToAnsiRoutine) (BugCheckDriver, AnsiBuffer, sizeof (AnsiBuffer)); } else { if (MmDbgReadCheck(DataTableEntry->DllBase) != NULL) { NtHeaders = RtlImageNtHeader(DataTableEntry->DllBase); DateStamp = NtHeaders->FileHeader.TimeDateStamp; } else { DateStamp = 0; } (*UnicodeToAnsiRoutine)( &DataTableEntry->BaseDllName, AnsiBuffer, sizeof( AnsiBuffer )); } sprintf (Buffer, "%s** Address %p base at %p, DateStamp %08lx - %-12.12s\n", FirstPrint ? "\n*":"*", BugCheckParameters[i], ImageBase, DateStamp, AnsiBuffer); InbvDisplayString(Buffer); FirstPrint = FALSE; } return; }
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); }
VOID NTAPI KiDisplayBlueScreen(IN ULONG MessageId, IN BOOLEAN IsHardError, IN PCHAR HardErrCaption OPTIONAL, IN PCHAR HardErrMessage OPTIONAL, IN PCHAR Message) { CHAR AnsiName[75]; /* Check if bootvid is installed */ if (InbvIsBootDriverInstalled()) { /* Acquire ownership and reset the display */ InbvAcquireDisplayOwnership(); InbvResetDisplay(); /* Display blue screen */ InbvSolidColorFill(0, 0, 639, 479, 4); InbvSetTextColor(15); InbvInstallDisplayStringFilter(NULL); InbvEnableDisplayString(TRUE); InbvSetScrollRegion(0, 0, 639, 479); } /* Check if this is a hard error */ if (IsHardError) { /* Display caption and message */ if (HardErrCaption) InbvDisplayString(HardErrCaption); if (HardErrMessage) InbvDisplayString(HardErrMessage); } /* Begin the display */ InbvDisplayString("\r\n"); /* Print out initial message */ KeGetBugMessageText(BUGCHECK_MESSAGE_INTRO, NULL); InbvDisplayString("\r\n\r\n"); /* Check if we have a driver */ if (KiBugCheckDriver) { /* Print out into to driver name */ KeGetBugMessageText(BUGCODE_ID_DRIVER, NULL); /* Convert and print out driver name */ KeBugCheckUnicodeToAnsi(KiBugCheckDriver, AnsiName, sizeof(AnsiName)); InbvDisplayString(" "); InbvDisplayString(AnsiName); InbvDisplayString("\r\n\r\n"); } /* Check if this is the generic message */ if (MessageId == BUGCODE_PSS_MESSAGE) { /* It is, so get the bug code string as well */ KeGetBugMessageText((ULONG)KiBugCheckData[0], NULL); InbvDisplayString("\r\n\r\n"); } /* Print second introduction message */ KeGetBugMessageText(PSS_MESSAGE_INTRO, NULL); InbvDisplayString("\r\n\r\n"); /* Get the bug code string */ KeGetBugMessageText(MessageId, NULL); InbvDisplayString("\r\n\r\n"); /* Print message for technical information */ KeGetBugMessageText(BUGCHECK_TECH_INFO, NULL); /* Show the technical Data */ sprintf(AnsiName, "\r\n\r\n*** STOP: 0x%08lX (0x%p,0x%p,0x%p,0x%p)\r\n\r\n", KiBugCheckData[0], (PVOID)KiBugCheckData[1], (PVOID)KiBugCheckData[2], (PVOID)KiBugCheckData[3], (PVOID)KiBugCheckData[4]); InbvDisplayString(AnsiName); /* Check if we have a driver*/ if (KiBugCheckDriver) { /* Display technical driver data */ InbvDisplayString(Message); } else { /* Dump parameter information */ KiDumpParameterImages(Message, (PVOID)&KiBugCheckData[1], 4, KeBugCheckUnicodeToAnsi); } }
VOID NTAPI KiDumpParameterImages(IN PCHAR Message, IN PULONG_PTR Parameters, IN ULONG ParameterCount, IN PKE_BUGCHECK_UNICODE_TO_ANSI ConversionRoutine) { ULONG i; BOOLEAN InSystem; PLDR_DATA_TABLE_ENTRY LdrEntry; PVOID ImageBase; PUNICODE_STRING DriverName; CHAR AnsiName[32]; PIMAGE_NT_HEADERS NtHeader; ULONG TimeStamp; BOOLEAN FirstRun = TRUE; /* Loop parameters */ for (i = 0; i < ParameterCount; i++) { /* Get the base for this parameter */ ImageBase = KiPcToFileHeader((PVOID)Parameters[i], &LdrEntry, FALSE, &InSystem); if (!ImageBase) { /* FIXME: Add code to check for unloaded drivers */ DPRINT1("Potentially unloaded driver!\n"); continue; } else { /* Get the NT Headers and Timestamp */ NtHeader = RtlImageNtHeader(LdrEntry->DllBase); TimeStamp = NtHeader->FileHeader.TimeDateStamp; /* Convert the driver name */ DriverName = &LdrEntry->BaseDllName; ConversionRoutine(&LdrEntry->BaseDllName, AnsiName, sizeof(AnsiName)); } /* Format driver name */ sprintf(Message, "%s** %12s - Address %p base at %p, DateStamp %08lx\r\n", FirstRun ? "\r\n*":"*", AnsiName, (PVOID)Parameters[i], ImageBase, TimeStamp); /* Check if we only had one parameter */ if (ParameterCount <= 1) { /* Then just save the name */ KiBugCheckDriver = DriverName; } else { /* Otherwise, display the message */ InbvDisplayString(Message); } /* Loop again */ FirstRun = FALSE; } }
BOOLEAN NTAPI KeGetBugMessageText(IN ULONG BugCheckCode, OUT PANSI_STRING OutputString OPTIONAL) { ULONG i, j; ULONG IdOffset; ULONG_PTR MessageEntry; PCHAR BugCode; BOOLEAN Result = FALSE; USHORT Length; /* Make sure we're not bugchecking too early */ if (!KiBugCodeMessages) return Result; /* Find the message. This code is based on RtlFindMesssage */ for (i = 0; i < KiBugCodeMessages->NumberOfBlocks; i++) { /* Check if the ID Matches */ if ((BugCheckCode >= KiBugCodeMessages->Blocks[i].LowId) && (BugCheckCode <= KiBugCodeMessages->Blocks[i].HighId)) { /* Get Offset to Entry */ MessageEntry = KiBugCodeMessages->Blocks[i].OffsetToEntries + (ULONG_PTR)KiBugCodeMessages; IdOffset = BugCheckCode - KiBugCodeMessages->Blocks[i].LowId; /* Get offset to ID */ for (j = 0; j < IdOffset; j++) { /* Advance in the Entries */ MessageEntry += ((PMESSAGE_RESOURCE_ENTRY)MessageEntry)-> Length; } /* Get the final Code */ BugCode = (PCHAR)((PMESSAGE_RESOURCE_ENTRY)MessageEntry)->Text; Length = (USHORT)strlen(BugCode); /* Handle trailing newlines */ while ((Length > 0) && ((BugCode[Length] == '\n') || (BugCode[Length] == '\r') || (BugCode[Length] == ANSI_NULL))) { /* Check if we have a string to return */ if (!OutputString) BugCode[Length] = ANSI_NULL; Length--; } /* Check if caller wants an output string */ if (OutputString) { /* Return it in the OutputString */ OutputString->Buffer = BugCode; OutputString->Length = Length + 1; OutputString->MaximumLength = Length + 1; } else { /* Direct Output to Screen */ InbvDisplayString(BugCode); InbvDisplayString("\r"); } /* We're done */ Result = TRUE; break; } } /* Return the result */ return Result; }