/*++ Copyright (c) 1991 Microsoft Corporation Module Name: harderr.c Abstract: This module implements NT Hard Error APIs Author: Mark Lucovsky (markl) 04-Jul-1991 Revision History: --*/ #include "exp.h" extern ULONG KiBugCheckData[5]; extern ULONG KeBugCheckCount; NTSTATUS ExpRaiseHardError( IN NTSTATUS ErrorStatus, IN ULONG NumberOfParameters, IN ULONG UnicodeStringParameterMask, IN PULONG Parameters, IN ULONG ValidResponseOptions, OUT PULONG Response ); VOID ExpSystemErrorHandler( IN NTSTATUS ErrorStatus, IN ULONG NumberOfParameters, IN ULONG UnicodeStringParameterMask, IN PULONG Parameters, IN BOOLEAN CallShutdown ); #if defined(ALLOC_PRAGMA) #pragma alloc_text(PAGE, NtRaiseHardError) #pragma alloc_text(PAGE, NtSetDefaultHardErrorPort) #pragma alloc_text(PAGE, ExRaiseHardError) #pragma alloc_text(PAGE, ExpRaiseHardError) #pragma alloc_text(PAGELK, ExpSystemErrorHandler) #endif #define HARDERROR_MSG_OVERHEAD (sizeof(HARDERROR_MSG) - sizeof(PORT_MESSAGE)) #define HARDERROR_API_MSG_LENGTH \ sizeof(HARDERROR_MSG)<<16 | (HARDERROR_MSG_OVERHEAD) PEPROCESS ExpDefaultErrorPortProcess; BOOLEAN ExReadyForErrors = FALSE; BOOLEAN ExpTooLateForErrors = FALSE; HANDLE ExpDefaultErrorPort; extern PVOID PsSystemDllDllBase; VOID ExpSystemErrorHandler( IN NTSTATUS ErrorStatus, IN ULONG NumberOfParameters, IN ULONG UnicodeStringParameterMask, IN PULONG Parameters, IN BOOLEAN CallShutdown ) { ULONG Counter; ANSI_STRING AnsiString; NTSTATUS Status; ULONG ParameterVector[MAXIMUM_HARDERROR_PARAMETERS]; CHAR DefaultFormatBuffer[32]; CHAR ExpSystemErrorBuffer[256]; PMESSAGE_RESOURCE_ENTRY MessageEntry; PSZ ErrorCaption; PSZ ErrorFormatString; ANSI_STRING Astr; UNICODE_STRING Ustr; OEM_STRING Ostr; PSZ OemCaption; PSZ OemMessage; PSZ UnknownHardError = "Unknown Hard Error"; PVOID UnlockHandle; CONTEXT ContextSave; // // This handler is called whenever a hard error occurs before the // default handler has been installed. // // This is done regardless of whether or not the process has chosen // default hard error processing. // // // 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. // // this code is here only for crash dumps RtlCaptureContext(&KeGetCurrentPrcb()->ProcessorState.ContextFrame); KiSaveProcessorControlState(&KeGetCurrentPrcb()->ProcessorState); ContextSave = KeGetCurrentPrcb()->ProcessorState.ContextFrame; DefaultFormatBuffer[0] = '\0'; RtlZeroMemory(ParameterVector,sizeof(ParameterVector)); for(Counter=0;Counter < NumberOfParameters;Counter++){ ParameterVector[Counter] = Parameters[Counter]; } for(Counter=0;Counter < NumberOfParameters;Counter++){ if ( UnicodeStringParameterMask & 1<Text)+16); strcpy(ErrorCaption,MessageEntry->Text); ErrorFormatString = ErrorCaption; while ( *ErrorFormatString >= ' ' ) { ErrorFormatString++; } *ErrorFormatString++ = '\0'; while ( *ErrorFormatString && *ErrorFormatString <= ' ') { *ErrorFormatString++; } } } except ( EXCEPTION_EXECUTE_HANDLER ) { ErrorFormatString = UnknownHardError; ErrorCaption = UnknownHardError; } } else { ErrorFormatString = DefaultFormatBuffer; ErrorCaption = UnknownHardError; } try { _snprintf( ExpSystemErrorBuffer, sizeof( ExpSystemErrorBuffer ), "\nSTOP: %lx %s\n", ErrorStatus,ErrorCaption); } except(EXCEPTION_EXECUTE_HANDLER) { _snprintf( ExpSystemErrorBuffer, sizeof( ExpSystemErrorBuffer ), "\nHardError %lx\n", ErrorStatus); } UnlockHandle = MmLockPagableCodeSection((PVOID)ExpSystemErrorHandler); ASSERT(UnlockHandle); if (CallShutdown) { ZwShutdownSystem( FALSE ); } // // take the caption and convert it to OEM // OemCaption = UnknownHardError; OemMessage = UnknownHardError; RtlInitAnsiString(&Astr,ExpSystemErrorBuffer); Status = RtlAnsiStringToUnicodeString(&Ustr,&Astr,TRUE); if ( !NT_SUCCESS(Status) ) { goto punt1; } Status = RtlUnicodeStringToOemString(&Ostr,&Ustr,TRUE); if ( !NT_SUCCESS(Status) ) { goto punt1; } OemCaption = Ostr.Buffer; // // Can't do much of anything after calling HalDisplayString... // punt1:; try { _snprintf( ExpSystemErrorBuffer, sizeof( ExpSystemErrorBuffer ), ErrorFormatString, ParameterVector[0], ParameterVector[1], ParameterVector[2], ParameterVector[3] ); } except(EXCEPTION_EXECUTE_HANDLER) { _snprintf( ExpSystemErrorBuffer, sizeof( ExpSystemErrorBuffer ), "Exception Processing Message %lx Parameters %lx %lx %lx %lx", ErrorStatus, ParameterVector[0], ParameterVector[1], ParameterVector[2], ParameterVector[3] ); } RtlInitAnsiString(&Astr,ExpSystemErrorBuffer); Status = RtlAnsiStringToUnicodeString(&Ustr,&Astr,TRUE); if ( !NT_SUCCESS(Status) ) { goto punt2; } Status = RtlUnicodeStringToOemString(&Ostr,&Ustr,TRUE); if ( !NT_SUCCESS(Status) ) { goto punt2; } OemMessage = Ostr.Buffer; punt2:; HalDisplayString( OemCaption ); HalDisplayString( OemMessage ); if (CallShutdown) { #if DBG DbgPrint( "EX: Typing go from this breakpoint will shutdown and restart the system.\n" ); DbgBreakPoint(); DbgUnLoadImageSymbols( NULL, (PVOID)-1, 0 ); HalReturnToFirmware( HalRebootRoutine ); #endif } ASSERT(sizeof(PVOID) == sizeof(ULONG)); ASSERT(sizeof(ULONG) == sizeof(NTSTATUS)); // // We don't come back from here. // KeBugCheckEx( FATAL_UNHANDLED_HARD_ERROR, (ULONG)ErrorStatus, (ULONG)&(ParameterVector[0]), 0, 0 ); } NTSTATUS ExpRaiseHardError( IN NTSTATUS ErrorStatus, IN ULONG NumberOfParameters, IN ULONG UnicodeStringParameterMask, IN PULONG Parameters, IN ULONG ValidResponseOptions, OUT PULONG Response ) { PEPROCESS Process; HARDERROR_MSG m; NTSTATUS Status; HANDLE ErrorPort; KPROCESSOR_MODE PreviousMode; PAGED_CODE(); PreviousMode = KeGetPreviousMode(); if (ValidResponseOptions == OptionShutdownSystem) { // // Check to see if the caller has the privilege to make this // call. // if (!SeSinglePrivilegeCheck( SeShutdownPrivilege, PreviousMode )) { return STATUS_PRIVILEGE_NOT_HELD; } ExReadyForErrors = FALSE; } Process = PsGetCurrentProcess(); // // If the default handler is not installed, then // call the fatal hard error handler if the error // status is error // // Let GDI override this since it does not want to crash the machine // when a bad driver was loaded via MmLoadSystemImage. // if ( !(PsGetCurrentThread()->HardErrorsAreDisabled) ) { if (ExReadyForErrors == FALSE && NT_ERROR(ErrorStatus)){ ExpSystemErrorHandler( ErrorStatus, NumberOfParameters, UnicodeStringParameterMask, Parameters, (BOOLEAN)((PreviousMode != KernelMode) ? TRUE : FALSE) ); } } // // If the process has an error port, then if it wants default // handling, use its port. If it disabled default handling, then // return the error to the caller. If the process does not // have a port, then use the registered default handler. // if ( Process->ExceptionPort ) { if ( Process->DefaultHardErrorProcessing & 1 ) { ErrorPort = Process->ExceptionPort; } else { // // if error processing is disabled, check the error override // status // if ( ErrorStatus & 0x10000000 ) { ErrorPort = Process->ExceptionPort; } else { ErrorPort = NULL; } } } else { if ( Process->DefaultHardErrorProcessing & 1 ) { ErrorPort = ExpDefaultErrorPort; } else { // // if error processing is disabled, check the error override // status // if ( ErrorStatus & 0x10000000 ) { ErrorPort = ExpDefaultErrorPort; } else { ErrorPort = NULL; } ErrorPort = NULL; } } if ( PsGetCurrentThread()->HardErrorsAreDisabled ) { ErrorPort = NULL; } if ( !IS_SYSTEM_THREAD(PsGetCurrentThread()) ) { try { PTEB Teb; Teb = (PTEB)PsGetCurrentThread()->Tcb.Teb; if ( Teb->HardErrorsAreDisabled ) { ErrorPort = NULL; } } except (EXCEPTION_EXECUTE_HANDLER) { ; } } if ( ErrorPort ) { if ( Process == ExpDefaultErrorPortProcess ) { if ( NT_ERROR(ErrorStatus) ) { ExpSystemErrorHandler( ErrorStatus, NumberOfParameters, UnicodeStringParameterMask, Parameters, (BOOLEAN)((PreviousMode != KernelMode) ? TRUE : FALSE) ); } *Response = (ULONG)ResponseReturnToCaller; Status = STATUS_SUCCESS; return Status; } m.h.u1.Length = HARDERROR_API_MSG_LENGTH; m.h.u2.ZeroInit = LPC_ERROR_EVENT; m.Status = ErrorStatus & 0xefffffff; m.ValidResponseOptions = ValidResponseOptions; m.UnicodeStringParameterMask = UnicodeStringParameterMask; m.NumberOfParameters = NumberOfParameters; if ( Parameters ) { RtlMoveMemory(&m.Parameters,Parameters, sizeof(ULONG)*NumberOfParameters); } KeQuerySystemTime(&m.ErrorTime); Status = LpcRequestWaitReplyPort( ErrorPort, (PPORT_MESSAGE) &m, (PPORT_MESSAGE) &m ); if ( NT_SUCCESS(Status) ) { switch ( m.Response ) { case ResponseReturnToCaller : case ResponseNotHandled : case ResponseAbort : case ResponseCancel : case ResponseIgnore : case ResponseNo : case ResponseOk : case ResponseRetry : case ResponseYes : break; default: m.Response = (ULONG)ResponseReturnToCaller; break; } *Response = m.Response; } } else { *Response = (ULONG)ResponseReturnToCaller; Status = STATUS_SUCCESS; } return Status; } NTSTATUS NtRaiseHardError( IN NTSTATUS ErrorStatus, IN ULONG NumberOfParameters, IN ULONG UnicodeStringParameterMask, IN PULONG Parameters, IN ULONG ValidResponseOptions, OUT PULONG Response ) { NTSTATUS Status; PULONG CapturedParameters; KPROCESSOR_MODE PreviousMode; ULONG LocalResponse; UNICODE_STRING CapturedString; ULONG Counter; PAGED_CODE(); if ( NumberOfParameters > MAXIMUM_HARDERROR_PARAMETERS ) { return STATUS_INVALID_PARAMETER_2; } PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { switch ( ValidResponseOptions ) { case OptionAbortRetryIgnore : case OptionOk : case OptionOkCancel : case OptionRetryCancel : case OptionYesNo : case OptionYesNoCancel : case OptionShutdownSystem : break; default : return STATUS_INVALID_PARAMETER_4; } CapturedParameters = NULL; try { ProbeForWriteUlong(Response); if ( ARGUMENT_PRESENT(Parameters) ) { ProbeForRead( Parameters, sizeof(ULONG)*NumberOfParameters, sizeof(ULONG) ); CapturedParameters = ExAllocatePool(PagedPool,sizeof(ULONG)*NumberOfParameters); if ( !CapturedParameters ) { return STATUS_NO_MEMORY; } RtlMoveMemory(CapturedParameters,Parameters,sizeof(ULONG)*NumberOfParameters); // // probe all strings // if ( UnicodeStringParameterMask ) { for(Counter=0;Counter < NumberOfParameters;Counter++){ // // if there is a string in this position, // then probe and capture the string // if ( UnicodeStringParameterMask & 1<