//** Copyright (C) 1996-2000 Intel Corporation. All rights reserved. //** //** The information and source code contained herein is the exclusive //** property of Intel Corporation and may not be disclosed, examined //** or reproduced in whole or in part without explicit written authorization //** from the company. //** //########################################################################### //----------------------------------------------------------------------------- // Version control information follows. // // // 10 Jun 1999 Bugcheck Bernard Lint // M. Jayakumar (Muthurajan.Jayakumar@intel.com) // Thierry Fevrier /////////////////////////////////////////////////////////////////////////////// // // Module Name: OSMCA.C - Merced OS Machine Check Handler // // Description: // This module has OS Machine Check Handler Reference Code. // // Contents: HalpOsMcaInit() // HalpCmcHandler() // HalpMcaHandler() // HalpMcRzHandlr() // HalpMcWkupHandlr() // HalpProcMcaHndlr() // HalpPlatMcaHndlr() // // // Target Platform: Merced // // Reuse: None // ////////////////////////////////////////////////////////////////////////////M// #include "halp.h" #include "nthal.h" #include "arc.h" #include "i64fw.h" #include "check.h" #include "iosapic.h" #include "inbv.h" #include "osmca.h" // pmdata.c: CPE definitions. extern ULONG HalpMaxCPEImplemented; extern ULONG HalpCPEIntIn[]; // i64fw.c: HAL Private Data structure for SAL/PAL extern HALP_SAL_PAL_DATA HalpSalPalData; // i64fwasm.s: low-level protection data structures extern KSPIN_LOCK HalpMcaSpinLock; extern KSPIN_LOCK HalpCmcSpinLock; extern KSPIN_LOCK HalpCpeSpinLock; // // IA64 MCE Info structures to keep track of MCE features // available on installed hardware. // HALP_MCA_INFO HalpMcaInfo; HALP_CMC_INFO HalpCmcInfo; HALP_CPE_INFO HalpCpeInfo; KERNEL_MCE_DELIVERY HalpMceKernelDelivery; volatile ULONG HalpOsMcaInProgress = 0; // // SAL_MC_SET_PARAMS.time_out // ULONGLONG HalpMcRendezTimeOut = HALP_DEFAULT_MC_RENDEZ_TIMEOUT; // // HalpProcessorMcaRecords: // // Number of MCA records pre-allocated per processor. // ULONGLONG HalpProcessorMcaRecords = HALP_DEFAULT_PROCESSOR_MCA_RECORDS; // // HalpProcessorInitRecords: // // Number of INIT records pre-allocated per processor. // ULONGLONG HalpProcessorInitRecords = HALP_DEFAULT_PROCESSOR_INIT_RECORDS; // // HalpMceLogsMaxCount: // // Maximum number of saved logs. // ULONG HalpMceLogsMaxCount = HALP_MCELOGS_MAXCOUNT; // // HAL Private Error Device GUIDs: // [useful for kdexts] // ERROR_DEVICE_GUID HalpErrorProcessorGuid = ERROR_PROCESSOR_GUID; ERROR_DEVICE_GUID HalpErrorMemoryGuid = ERROR_MEMORY_GUID; ERROR_DEVICE_GUID HalpErrorPciBusGuid = ERROR_PCI_BUS_GUID; ERROR_DEVICE_GUID HalpErrorPciComponentGuid = ERROR_PCI_COMPONENT_GUID; ERROR_DEVICE_GUID HalpErrorSystemEventLogGuid = ERROR_SYSTEM_EVENT_LOG_GUID; ERROR_DEVICE_GUID HalpErrorSmbiosGuid = ERROR_SMBIOS_GUID; ERROR_DEVICE_GUID HalpErrorPlatformSpecificGuid = ERROR_PLATFORM_SPECIFIC_GUID; ERROR_DEVICE_GUID HalpErrorPlatformBusGuid = ERROR_PLATFORM_BUS_GUID; ERROR_DEVICE_GUID HalpErrorPlatformHostControllerGuid = ERROR_PLATFORM_HOST_CONTROLLER_GUID; // // HAL Private Error Definitions: // [useful for kdexts] // Actually in this case, the typed pointers allow also the inclusion of the symbols definitions // without the data structures sizes. // PERROR_MODINFO HalpPErrorModInfo; PERROR_PROCESSOR_CPUID_INFO HalpPErrorProcessorCpuIdInfo; PERROR_PROCESSOR HalpPErrorProcessor; PERROR_PROCESSOR_STATIC_INFO HalpPErrorProcessorStaticInfo; PERROR_MEMORY HalpPErrorMemory; PERROR_PCI_BUS HalpPErrorPciBus; PERROR_PCI_COMPONENT HalpPErrorPciComponent; PERROR_SYSTEM_EVENT_LOG HalpPErrorSystemEventLog; PERROR_SMBIOS HalpPErrorSmbios; PERROR_PLATFORM_SPECIFIC HalpPErrorPlatformSpecific; PERROR_PLATFORM_BUS HalpPErrorPlatformBus; PERROR_PLATFORM_HOST_CONTROLLER HalpPErrorPlatformHostController; // // MCA/CMC/CPE state catchers // ERROR_SEVERITY HalpMcaProcessLog( PMCA_EXCEPTION McaLog ); BOOLEAN HalpPreAllocateMceTypeRecords( ULONG EventType, ULONG Number ); VOID HalpMcaBugCheck( ULONG McaBugCheckType, PMCA_EXCEPTION McaLog, ULONGLONG McaAllocatedLogSize, ULONGLONG Arg4 ); #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT, HalpInitializeOSMCA) #pragma alloc_text(INIT, HalpAllocateMceStacks) #pragma alloc_text(INIT, HalpPreAllocateMceRecords) #pragma alloc_text(INIT, HalpPreAllocateMceTypeRecords) #pragma alloc_text(PAGELK, HalpMcaHandler) #pragma alloc_text(PAGELK, HalpMcaProcessLog) #pragma alloc_text(PAGELK, HalpMcaBugCheck) #pragma alloc_text(PAGELK, HalpGetErrLog) #pragma alloc_text(PAGELK, HalpClrErrLog) #pragma alloc_text(PAGE, HalpGetMceInformation) #endif // ALLOC_PRAGMA BOOLEAN HalpSaveEventLog( PSINGLE_LIST_ENTRY HeadList, PERROR_RECORD_HEADER RecordHeader, ULONG Tag, POOL_TYPE PoolType, PKSPIN_LOCK SpinLock ) { PSINGLE_LIST_ENTRY entry, previousEntry; SIZE_T logSize; PERROR_RECORD_HEADER savedLog; KIRQL oldIrql; // // Allocate and Initialize the new entry // logSize = RecordHeader->Length; if ( !logSize ) { HalDebugPrint(( HAL_ERROR, "HAL!HalpSaveEventLog: record length is zeroed.\n" )); return FALSE; } entry = (PSINGLE_LIST_ENTRY)ExAllocatePoolWithTag( PoolType, sizeof(*entry) + logSize, Tag ); if ( entry == NULL ) { HalDebugPrint(( HAL_ERROR, "HAL!HalpSaveEventLog: Event log allocation failed.\n" )); return FALSE; } entry->Next = NULL; savedLog = (PERROR_RECORD_HEADER)((ULONG_PTR)entry + sizeof(*entry)); RtlCopyMemory( savedLog, RecordHeader, logSize ); // // Insert the new entry with protection. // KeRaiseIrql( HIGH_LEVEL, &oldIrql ); KiAcquireSpinLock( SpinLock ); previousEntry = HeadList; while( previousEntry->Next != NULL ) { previousEntry = previousEntry->Next; } previousEntry->Next = entry; KiReleaseSpinLock( SpinLock ); KeLowerIrql( oldIrql ); return TRUE; } // HalpSaveEventLog() #define HalpSaveCorrectedMcaLog( _McaLog ) \ HalpSaveEventLog( &HalpMcaInfo.CorrectedLogs, (PERROR_RECORD_HEADER)(_McaLog), 'CacM', NonPagedPool, &HalpMcaSpinLock ) NTSTATUS HalpCheckForMcaLogs( VOID ) /*++ Routine Description: This routine checks the FW early during boot if a MCA event log is present. The log is considered as "previous". This routine is called at phase 1 on BSP and APs, from HalpPreAllocateMceRecords(). it is executed on the standard kernel stacks. Arguments: None Return Value: STATUS_NO_MEMORY if mca log allocation failed. STATUS_SUCCESS otherwise, regardless of FW interfaces failures. --*/ { NTSTATUS status; PERROR_RECORD_HEADER log; log = ExAllocatePoolWithTag( NonPagedPool, HalpMcaInfo.Stats.MaxLogSize, 'PacM' ); if ( !log ) { return( STATUS_NO_MEMORY ); } status = HalpGetFwMceLog( MCA_EVENT, log, &HalpMcaInfo.Stats, HALP_FWMCE_DONOT_CLEAR_LOG ); if ( status != STATUS_NOT_FOUND ) { // // Successful log collection or invalid record or unsuccessful FW Interface calls // are considered as a trigger for the MCA log consumers to collect them from the FW. // InterlockedIncrement( &HalpMcaInfo.Stats.McaPreviousCount ); } ExFreePoolWithTag( log, 'PacM' ); return( STATUS_SUCCESS ); } // HalpCheckForMcaLogs() BOOLEAN HalpPreAllocateMceTypeRecords( ULONG EventType, ULONG Number ) { SAL_PAL_RETURN_VALUES rv = {0}; ULONGLONG defaultEventRecords; PVOID log; SIZE_T logSize; PHYSICAL_ADDRESS physicalAddr; if ( (EventType != MCA_EVENT) && (EventType != INIT_EVENT) ) { ASSERTMSG( "HAL!HalpPreAllocateMceTypeRecords: unknown event type!\n", FALSE ); return FALSE; } // // On BSP only, call SAL to get maximum size of EventType record // if ( Number == 0 ) { rv = HalpGetStateInfoSize( EventType ); if ( !SAL_SUCCESSFUL(rv) ) { HalDebugPrint(( HAL_ERROR, "HAL!HalpPreAllocateMceTypeRecords: SAL_GET_STATE_INFO_SIZE failed...\n" )); return FALSE; } logSize = rv.ReturnValues[1]; } if ( EventType == MCA_EVENT ) { if ( Number == 0 ) { // Update HalpMcaInfo, without protection. This is not required. HalpMcaInfo.Stats.MaxLogSize = (ULONG)logSize; } else { logSize = (SIZE_T)HalpMcaInfo.Stats.MaxLogSize; } defaultEventRecords = HalpProcessorMcaRecords; } else { ASSERTMSG( "HAL!HalpPreAllocateMceTypeRecords: invalid event type!\n", EventType == INIT_EVENT ); if ( Number == 0 ) { // Update HalpInitInfo, without protection. This is not required. HalpInitInfo.MaxLogSize = (ULONG)logSize; } else { logSize = (SIZE_T)HalpInitInfo.MaxLogSize; } defaultEventRecords = HalpProcessorInitRecords; } // Determine size of allocation logSize = ROUND_TO_PAGES( (logSize * defaultEventRecords) ); // // Allocate Event Records buffer // physicalAddr.QuadPart = 0xffffffffffffffffI64; log = MmAllocateContiguousMemory( logSize, physicalAddr ); if ( log == NULL ) { HalDebugPrint(( HAL_ERROR, "HAL!HalpPreAllocateMceTypeRecords: SAL %s Event Records allocation failed (0x%Ix)...\n", ( EventType == MCA_EVENT ) ? "MCA" : "INIT", logSize )); return FALSE; } // // Update KPCR entry. // { volatile KPCR * const pcr = KeGetPcr(); PSAL_EVENT_RESOURCES eventResources; if ( EventType == MCA_EVENT ) { eventResources = pcr->OsMcaResourcePtr; } eventResources->EventPool = log; eventResources->EventPoolSize = (ULONG) logSize; } return TRUE; } // HalpPreAllocateMceTypeRecords() BOOLEAN HalpPreAllocateMceRecords( IN ULONG Number ) { NTSTATUS status; // // Pre-Allocate MCA records // if ( !HalpPreAllocateMceTypeRecords( MCA_EVENT , Number ) ) { return FALSE; } // // Check for MCA logs. // These might be logs related to previous boot sessions. // status = HalpCheckForMcaLogs(); if ( !NT_SUCCESS( status ) ) { return FALSE; } return TRUE; } // HalpPreAllocateMceRecords() BOOLEAN HalpAllocateMceStacks( IN ULONG Number ) { PHYSICAL_ADDRESS physicalAddr; PVOID mem; PVOID mcaStateDump, mcaBackStore, mcaStack; ULONGLONG mcaStateDumpPhysical; ULONGLONG mcaBackStoreLimit, mcaStackLimit; ULONG length; // // Allocate MCA/INIT stacks // length = HALP_MCA_STATEDUMP_SIZE + HALP_MCA_BACKSTORE_SIZE + HALP_MCA_STACK_SIZE; physicalAddr.QuadPart = 0xffffffffffffffffI64; mem = MmAllocateContiguousMemory( length, physicalAddr ); if ( mem == NULL ) { HalDebugPrint(( HAL_ERROR, "HAL!HalpAllocateMceStacks: MCA State Dump allocation failed (0x%Ix)...\n", length )); return FALSE; } // // The layout in memory by increasing addresses is: // // Bottom of stack // . // . // . // Initial Stack // State Dump Area // . // . // Initial BSP // . // . // . // BSP Limit // mcaStack = mem; mcaStackLimit = (ULONGLONG)mem + HALP_MCA_STACK_SIZE; mem = (PCHAR) mem + HALP_MCA_STACK_SIZE; mcaStateDump = mem; mcaStateDumpPhysical = MmGetPhysicalAddress(mem).QuadPart; mem = (PCHAR) mem + HALP_MCA_STATEDUMP_SIZE; mcaBackStore = mem; mcaBackStoreLimit = (ULONGLONG)mem + (ULONGLONG)(ULONG)HALP_MCA_BACKSTORE_SIZE; // // Update PCR MCA, INIT stacks // { volatile KPCR * const pcr = KeGetPcr(); PSAL_EVENT_RESOURCES eventResources; eventResources = pcr->OsMcaResourcePtr; eventResources->StateDump = mcaStateDump; eventResources->StateDumpPhysical = mcaStateDumpPhysical; eventResources->BackStore = mcaBackStore; eventResources->BackStoreLimit = mcaBackStoreLimit; eventResources->Stack = (PCHAR) mcaStackLimit; eventResources->StackLimit = (ULONGLONG) mcaStack; } return TRUE; } // HalpPreAllocateMceRecords() //++ // Name: HalpInitializeOSMCA() // // Routine Description: // // This routine registers MCA init's // // Arguments On Entry: // arg0 = Function ID // // Success/Failure (0/!0) //-- BOOLEAN HalpInitializeOSMCA( IN ULONG Number ) { SAL_PAL_RETURN_VALUES rv = {0}; ULONGLONG gp_reg; // // Register SAL_MC_RendezVous parameters with SAL // rv = HalpSalSetParams(0, RendzType, IntrVecType, MC_RZ_VECTOR, HalpMcRendezTimeOut); if ( !SAL_SUCCESSFUL(rv) ) { HalDebugPrint(( HAL_ERROR, "HAL!HalpInitializeOSMCA: SAL_MC_SET_PARAMS.rendezvous vector failed...\n" )); return FALSE; } // // Register WakeUp parameters with SAL // rv = HalpSalSetParams(0, WakeUpType, IntrVecType, MC_WKUP_VECTOR,0); if ( !SAL_SUCCESSFUL(rv) ) { HalDebugPrint(( HAL_ERROR, "HAL!HalpInitializeOSMCA: SAL_MC_SET_PARAMS.wakeup vector failed...\n" )); return FALSE; } // // Allocate MCA, INIT stacks // if ( !HalpAllocateMceStacks( Number ) ) { return FALSE; } // // Pre-Allocate desired number of MCA,INIT records // HalpMcaInfo.KernelToken = (PVOID)(ULONG_PTR)HALP_KERNEL_TOKEN; if ( !HalpPreAllocateMceRecords( Number ) ) { return FALSE; } // // Initialize HAL private CMC, CPE structures. // rv = HalpGetStateInfoSize( CMC_EVENT ); if ( !SAL_SUCCESSFUL( rv ) ) { HalDebugPrint(( HAL_ERROR, "HAL!HalpInitializeOSMCA: SAL_GET_STATE_INFO_SIZE.CMC failed...\n" )); return FALSE; } HalpCmcInfo.Stats.MaxLogSize = (ULONG)rv.ReturnValues[1]; HalpCmcInfo.KernelToken = (PVOID)(ULONG_PTR)HALP_KERNEL_TOKEN; HalpCmcInfo.KernelLogs.MaxCount = HalpMceLogsMaxCount; HalpCmcInfo.DriverLogs.MaxCount = HalpMceLogsMaxCount; HalpCmcInfo.Stats.PollingInterval = HAL_CMC_INTERRUPTS_BASED; rv = HalpGetStateInfoSize( CPE_EVENT ); if ( !SAL_SUCCESSFUL( rv ) ) { HalDebugPrint(( HAL_ERROR, "HAL!HalpInitializeOSMCA: SAL_GET_STATE_INFO_SIZE.CPE failed...\n" )); return FALSE; } HalpCpeInfo.Stats.MaxLogSize = (ULONG)rv.ReturnValues[1]; HalpCpeInfo.KernelToken = (PVOID)(ULONG_PTR)HALP_KERNEL_TOKEN; HalpCpeInfo.KernelLogs.MaxCount = HalpMceLogsMaxCount; HalpCpeInfo.DriverLogs.MaxCount = HalpMceLogsMaxCount; // // Register OsMcaDispatch (OS_MCA) physical address with SAL // gp_reg = GetGp(); rv = HalpSalSetVectors(0, MchkEvent, MmGetPhysicalAddress((fptr)(((PLabel*)HalpOsMcaDispatch1)->fPtr)), gp_reg,0); if ( !SAL_SUCCESSFUL(rv) ) { HalDebugPrint(( HAL_ERROR, "HAL!HalpInitializeOSMCA: SAL_SET_VECTOR.MCA vector failed...\n" )); return FALSE; } // // Register OsInitDispatch physical address with SAL // rv = HalpSalSetVectors(0, InitEvent, MmGetPhysicalAddress((fptr)(((PLabel*)HalpOsInitDispatch)->fPtr)), gp_reg,0); if ( !SAL_SUCCESSFUL(rv) ) { HalDebugPrint(( HAL_ERROR, "HAL!HalpInitializeOSMCA: SAL_SET_VECTOR.INIT vector failed...\n" )); return FALSE; } return TRUE; } // HalpInitializeOSMCA() //EndProc////////////////////////////////////////////////////////////////////// VOID HalpMcaBugCheck( ULONG McaBugCheckType, PMCA_EXCEPTION McaLog, ULONGLONG McaAllocatedLogSize, ULONGLONG SalStatus ) //++ // Name: HalpMcaBugCheck() // // Routine Description: // // This function is called to bugcheck the system in a case of a fatal MCA // or fatal FW interface errors. The OS must guarantee as much as possible // error containment in this path. // With the current implementation, this function should be only called from // the OS_MCA path. For other MCA specific wrappers of KeBugCheckEx, one should // HalpMcaKeBugCheckEx(). // // Arguments On Entry: // ULONG McaBugCheckType // PMCA_EXCEPTION McaLog // ULONGLONG McaAllocatedLogSize // ULONGLONG SalStatus // // Return: // None. // // Implementation notes: // This code CANNOT [as default rules - at least entry and through fatal MCAs handling] // - make any system call // - attempt to acquire any spinlock used by any code outside the MCA handler // - change the interrupt state. // Passing data to non-MCA code must be done using manual semaphore instructions. // This code should minimize the path and the global or memory allocated data accesses. // This code should only access MCA-namespace structures. // This code is called under the MP protection of HalpMcaSpinLock and with the flag // HalpOsMcaInProgress set. // //-- { if ( HalpOsMcaInProgress ) { // // 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 } HalDisplayString (MSG_MCA_HARDWARE_ERROR); HalDisplayString (MSG_HARDWARE_ERROR2); // // Thierry 09/2000: // // - if desired, process the MCA log HERE... // // and use HalDisplayString() to dump info for the field or hardware vendor. // The processing could be based on processor or platform independent record definitions. // HalDisplayString( MSG_HALT ); if ( HalpMcaInfo.NoBugCheck == 0 ) { KeBugCheckEx( MACHINE_CHECK_EXCEPTION, (ULONG_PTR)McaBugCheckType, (ULONG_PTR)McaLog, (ULONG_PTR)McaAllocatedLogSize, (ULONG_PTR)SalStatus ); } } if ( ((*KdDebuggerNotPresent) == FALSE) && ((*KdDebuggerEnabled) != FALSE) ) { KeEnterKernelDebugger(); } while( TRUE ) { // ; // Simply sit here so the MCA HARDWARE ERROR screen does not get corrupted... // } // noreturn } // HalpMcaBugCheck() ERROR_SEVERITY HalpMcaProcessLog( PMCA_EXCEPTION McaLog ) //++ // Name: HalpMcaProcessLog() // // Routine Description: // // This function is called to process the MCA event log in the OS_MCA path. // // Arguments On Entry: // PMCA_EXCEPTION McaLog - Pointer to the MCA event log. // // Return: // ERROR_SEVERITY // // Implementation notes: // This code CANNOT [as default rules] // - make any system call // - attempt to acquire any spinlock used by any code outside the MCA handler // - change the interrupt state. // Passing data to non-MCA code must be done using manual semaphore instructions. // This code should minimize the path and the global or memory allocated data accesses. // This code should only access MCA-namespace structures. // This code is called under the MP protection of HalpMcaSpinLock and with the flag // HalpOsMcaInProgress set. // //-- { ERROR_SEVERITY mcaSeverity; mcaSeverity = McaLog->ErrorSeverity; switch( mcaSeverity ) { case ErrorFatal: break; case ErrorRecoverable: // // Thierry - FIXFIX 08/2000: // /////////////////////////////////////////////////////////////// // // Call to kernel supported recovery will be here.... // /////////////////////////////////////////////////////////////// // // However, for now we do not recover so flag it as ErrorFatal. mcaSeverity = ErrorFatal; break; case ErrorCorrected: default: // // These ERRROR_SEVERITY values have no HAL MCA specific handling. // As specified by the SAL Specs July 2000, we should not get these values in this path. // break; } // // If OEM driver has registered an exception callback for MCA event, // call it here and save returned error severity value. // if ( HalpMcaInfo.DriverInfo.ExceptionCallback ) { mcaSeverity = HalpMcaInfo.DriverInfo.ExceptionCallback( HalpMcaInfo.DriverInfo.DeviceContext, McaLog ); } // // Save corrected log for future kernel notification. // if ( (HalpMcaInfo.KernelDelivery) && (mcaSeverity == ErrorCorrected) ) { InterlockedIncrement( &HalpMcaInfo.Stats.McaCorrectedCount ); #if 0 // // Thierry - 09/16/2000: ToBeDone. // Saving the corrected MCA log records requires careful rendez-vous configuration // handling, possible OS_MCA monarch selection, MCA logs (pre-)allocations and // special locking in case a consumer accesses the logs queue on another processor. // // The kernel-WMI and/or OEM MCA driver notification is done in HalpMcaHandler(). // if ( !HalpSaveCorrectedMcaLog( McaLog ) ) { InterlockedIncrement( &HalpMcaInfo.CorrectedLogsLost ); } #endif // 0 // // The kernel-WMI and/or OEM MCA driver notification for corrected MCA event // is done in HalpMcaHandler(). // } // // Thierry 10/17/2000 BUGBUG // // The FW does not save the MCA log in NVRAM and we have no official date from Intel // when the SAL will be doing it. // So for now, return as ErrorFatal and let dump the log through the debugger. // // Before Sal Rev , the error logs were completely erroneous... // if ( HalpSalPalData.SalRevision.Revision < HALP_SAL_REVISION_MAX ) { return( ErrorFatal ); } else { return( mcaSeverity ); } } // HalpMcaProcessLog() SAL_PAL_RETURN_VALUES HalpMcaHandler( ULONG64 RendezvousState, PPAL_MINI_SAVE_AREA Pmsa ) //++ // Name: HalpMcaHandler() // // Routine Description: // // This is the OsMca handler for firmware uncorrected errors // It is our option to run this in physical or virtual mode. // // Arguments On Entry: // None. // // Conditions On Entry: 09/2000 implementation. // - PSR state: at least, // PSR.dt = 1, PSR.it = 1, PSR.rt = 1 - virtual mode. // PSR.ic = 1, PSR.i = 0 - Interruption resources collection enabled, // Interrupts off. // PSR.mc = 1 - MCA masked for this processor. // - SalToOsHndOff initialized. // - s0 = MinStatePtr. // - s1 = IA64 PAL Processor State Parameter. // - s2 = PALE_CHECK return address. // - Processor registers state saved in myStateDump[] by osmcaProcStateDump(). // - myStackFrame[0] = ar.rsc // - myStackFrame[1] = ar.pfs // - myStackFrame[2] = ar.ifs // - myStackFrame[3] = ar.bspstore // - myStackFrame[4] = ar.rnat // - myStackFrame[5] = ar.bsp - ar.bspstore // - ar.bspstore = myBspStore // - sp = &mySp[sizeof(mySp[])] // // Return: // rtn0=Success/Failure (0/!0) // rtn1=Alternate MinState Pointer if any else NULL // // Implementation notes: // This code CANNOT [as default rules - at least entry and through fatal MCAs handling] // - make any system call // - attempt to acquire any spinlock used by any code outside the MCA handler // - change the interrupt state. // Passing data to non-MCA code must be done using manual semaphore instructions. // This code should minimize the path and the global or memory allocated data accesses. // This code should only access MCA-namespace structures and should not access globals // until it is safe. // //-- { SAL_PAL_RETURN_VALUES rv; LONGLONG salStatus; BOOLEAN mcWakeUp; PMCA_EXCEPTION mcaLog; ULONGLONG mcaAllocatedLogSize; PSAL_EVENT_RESOURCES mcaResources; KIRQL oldIrql; volatile KPCR * const pcr = KeGetPcr(); // // Acquire MCA spinlock protecting OS_MCA resources. // // Thierry 10/06/2000: FIXFIX. // we will move this MP synchronization in HalpOsMcaDispatch after current discussions // with Intel about MP MCA handling are completed. // Expecting responses from Intel about these. // KeRaiseIrql(HIGH_LEVEL, &oldIrql); HalpAcquireMcaSpinLock( &HalpMcaSpinLock ); HalpOsMcaInProgress++; // // Save OsToSal minimum state // mcaResources = pcr->OsMcaResourcePtr; mcaResources->OsToSalHandOff.SalReturnAddress = mcaResources->SalToOsHandOff.SalReturnAddress; mcaResources->OsToSalHandOff.SalGlobalPointer = mcaResources->SalToOsHandOff.SalGlobalPointer; // // update local variables with pre-initialized MCA log data. // mcaLog = (PMCA_EXCEPTION)(mcaResources->EventPool); mcaAllocatedLogSize = mcaResources->EventPoolSize; if ( !mcaLog || !mcaAllocatedLogSize ) { // // The following code should never happen or the implementation of the HAL MCA logs // pre-allocation failed miserably. This would be a development error. // HalpMcaBugCheck( (ULONG_PTR)HAL_BUGCHECK_MCA_ASSERT, mcaLog, mcaAllocatedLogSize, (ULONGLONG)0 ); } // // Get the MCA logs // salStatus = (LONGLONG)0; while( salStatus >= 0 ) { ERROR_SEVERITY errorSeverity; rv = HalpGetStateInfo( MCA_EVENT, mcaLog ); salStatus = rv.ReturnValues[0]; switch( salStatus ) { case SAL_STATUS_SUCCESS: errorSeverity = HalpMcaProcessLog( mcaLog ); if ( errorSeverity == ErrorFatal ) { // // We are now going down with a MACHINE_CHECK_EXCEPTION. // No return... // HalpMcaBugCheck( HAL_BUGCHECK_MCA_FATAL, mcaLog, mcaAllocatedLogSize, 0 ); } rv = HalpClearStateInfo( MCA_EVENT ); if ( !SAL_SUCCESSFUL(rv) ) { // // Current consideration for this implementation - 08/2000: // if clearing the event fails, we assume that FW has a real problem; // continuing will be dangerous. We bugcheck. // HalpMcaBugCheck( HAL_BUGCHECK_MCA_CLEAR_STATEINFO, mcaLog, mcaAllocatedLogSize, rv.ReturnValues[0] ); } // SAL_STATUS_SUCCESS, SAL_STATUS_SUCCESS_MORE_RECORDS ... and // ErrorSeverity != ErrorFatal. // // Call the registered kernel handler. // // Thierry 08/2000 - FIXFIX: // The errorSeverity check is under comments. It should not be commented for the // final version. However, we wanted to have kernel notification if we are getting // log error severity != ErrorFatal or != ErrorRecoverable. if ( /* (errorSeverity == ErrorCorrected) && */ ( HalpMcaInfo.KernelDelivery || HalpMcaInfo.DriverInfo.DpcCallback ) ) { InterlockedExchange( &HalpMcaInfo.DpcNotification, 1 ); } break; case SAL_STATUS_NO_INFORMATION_AVAILABLE: // // The salStatus value will break the salStatus loop. // rv.ReturnValues[0] = SAL_STATUS_SUCCESS; break; case SAL_STATUS_SUCCESS_WITH_OVERFLOW: case SAL_STATUS_INVALID_ARGUMENT: case SAL_STATUS_ERROR: case SAL_STATUS_VA_NOT_REGISTERED: default: // Thierry 08/00: WARNING - SAL July 2000 - v2.90. // default includes possible unknown positive salStatus values. HalpMcaBugCheck( HAL_BUGCHECK_MCA_GET_STATEINFO, mcaLog, mcaAllocatedLogSize, salStatus ); break; } } // // Currently 08/2000, we do not support the modification of the minstate. // mcaResources->OsToSalHandOff.MinStateSavePtr = mcaResources->SalToOsHandOff.MinStateSavePtr; mcaResources->OsToSalHandOff.Result = rv.ReturnValues[0]; // // If error was corrected and MCA non-monarch processors are in rendez vous, // we will have to wake them up. // mcWakeUp = ( (rv.ReturnValues[0] == SAL_STATUS_SUCCESS) && HalpSalRendezVousSucceeded( mcaResources->SalToOsHandOff ) ); // // Release MCA spinlock protecting OS_MCA resources. // HalpOsMcaInProgress = 0; HalpReleaseMcaSpinLock( &HalpMcaSpinLock ); // // If required, let's wake MCA non-monarch processors up. // if ( mcWakeUp ) { HalpMcWakeUp(); } return( rv ); } // HalpMcaHandler() //++ // Name: HalpGetErrLogSize() // // Routine Description: // // This is a wrapper that will call SAL_GET_STATE_INFO_SIZE // // Arguments On Entry: // arg0 = Reserved // arg1 = Event Type (MCA,INIT,CMC,CPE) // // Returns // rtn0=Success/Failure (0/!0) // rtn1=Size //-- SAL_PAL_RETURN_VALUES HalpGetErrLogSize( ULONGLONG Res, ULONGLONG eType ) { SAL_PAL_RETURN_VALUES rv = {0}; HalpSalCall(SAL_GET_STATE_INFO_SIZE, eType, 0,0,0,0,0,0, &rv); return(rv); } //EndProc////////////////////////////////////////////////////////////////////// //++ // Name: HalpGetErrLog() // // Routine Description: // // This is a wrapper that will call SAL_GET_STATE_INFO // // Arguments On Entry: // arg0 = Reserved // arg1 = Event Type (MCA,INIT,CMC) // arg3 = pBuffer // // Success/Failure (0/!0) //-- SAL_PAL_RETURN_VALUES HalpGetErrLog( ULONGLONG Res, ULONGLONG eType, ULONGLONG* pBuff ) { SAL_PAL_RETURN_VALUES rv={0}; HalpSalCall(SAL_GET_STATE_INFO, eType, 0, (ULONGLONG)pBuff, 0,0,0,0, &rv); // // Regardless of the call success or failure, fix the record to store // the processor number the SAL_PROC was executed on. // This feature is requested by WMI. // HalpSetFwMceLogProcessorNumber( (PERROR_RECORD_HEADER)pBuff ); return(rv); } //EndProc////////////////////////////////////////////////////////////////////// //++ // Name: HalpClrErrLog() // // Routine Description: // // This is a wrapper that will call SAL_CLEAR_STATE_INFO // // Arguments On Entry: // arg0 = Reserved // arg1 = Event Type (MCA,INIT,CMC,CPE) // // Success/Failure (0/!0) //-- SAL_PAL_RETURN_VALUES HalpClrErrLog( ULONGLONG Res, ULONGLONG eType ) { SAL_PAL_RETURN_VALUES rv={0}; HalpSalCall( SAL_CLEAR_STATE_INFO, eType, 0,0,0,0,0,0, &rv ); return(rv); } //EndProc////////////////////////////////////////////////////////////////////// //++ // Name: HalpSalSetParams() // // Routine Description: // // This is a wrapper that will call SAL_MC_SET_PARAMS // // Arguments On Entry: // arg0 = Reserved // arg1 = Parameter Type (rendz. or wakeup) // arg2 = Event Type (interrupt/semaphore) // arg3 = Interrupt Vector or Memory Address // arg4 = Timeout value for rendezvous // // Success/Failure (0/!0) //-- SAL_PAL_RETURN_VALUES HalpSalSetParams(ULONGLONG Res, ULONGLONG pType, ULONGLONG eType, ULONGLONG VecAdd, ULONGLONG tValue) { SAL_PAL_RETURN_VALUES rv={0}; HalpSalCall(SAL_MC_SET_PARAMS, pType, eType, VecAdd,tValue,0,0,0,&rv); return(rv); } //EndProc////////////////////////////////////////////////////////////////////// //++ // Name: HalpSalSetVectors() // // Routine Description: // // This is a wrapper that will call SAL_SET_VECTORS // // Arguments On Entry: // arg0 = Reserved // arg1 = Event Type (MCA, INIT..) // arg2 = Physical Address of handler // arg3 = gp // arg4 = length of event handler in bytes // // Success/Failure (0/!0) //-- SAL_PAL_RETURN_VALUES HalpSalSetVectors( ULONGLONG Res, ULONGLONG eType, PHYSICAL_ADDRESS Addr, ULONGLONG gpValue, ULONGLONG szHndlr) { SAL_PAL_RETURN_VALUES rv={0}; if ( eType == InitEvent ) { // // Thierry 08/2000: // Current implementation assumes that OS decides the monarch inside OS_INIT. // This implies handler_2, gp_2, length_2 are identical to handler_1, gp_1, length_1. // HalpSalCall(SAL_SET_VECTORS, eType, (ULONGLONG)Addr.QuadPart, gpValue, szHndlr, (ULONGLONG)Addr.QuadPart, gpValue, szHndlr, &rv); } else { HalpSalCall(SAL_SET_VECTORS, eType, (ULONGLONG)Addr.QuadPart, gpValue,szHndlr,0,0,0,&rv); } return(rv); } //EndProc////////////////////////////////////////////////////////////////////// //++ // Name: HalpSalRendz() // // Routine Description: // // This is a wrapper that will call SAL_MC_RENDEZ // // Arguments On Entry: // arg0 = Reserved // // Success/Failure (0/!0) //-- SAL_PAL_RETURN_VALUES HalpSalRendz(void) { SAL_PAL_RETURN_VALUES rv={0}; HalpSalCall(SAL_MC_RENDEZ, 0, 0, 0,0,0,0,0,&rv); return(rv); } VOID HalpMcWakeUp( VOID ) /*++ Routine Description: This function does IPI to wakeup the MC non-monarch processors. Arguments: None. Return Value: None. Remarks: This function is assumed to be executed on the MC monarch processor. --*/ { USHORT LogicalCpu; USHORT ProcessorID; USHORT monarchID; // // Scan the processor set and request an interprocessor interrupt on // each of the specified targets. // monarchID = (USHORT)PCR->HalReserved[PROCESSOR_ID_INDEX]; for (LogicalCpu = 0; LogicalCpu < HalpMpInfo.ProcessorCount; LogicalCpu++) { // // Only IPI processors that are started. // if (HalpActiveProcessors & (1 << HalpProcessorInfo[LogicalCpu].NtProcessorNumber)) { ProcessorID = HalpProcessorInfo[LogicalCpu].LocalApicID; // // Request interprocessor interrupt on target physicalCpu. // if ( ProcessorID != monarchID ) { HalpSendIPI(ProcessorID, MC_WKUP_VECTOR); } } } } // HalpMcWakeUp() VOID HalpCMCEnable( VOID ) /*++ Routine Description: This routine sets the processor CMCV register with CMCI_VECTOR. Arguments: None. Return Value: None. --*/ { if ( HalpFeatureBits & HAL_CMC_PRESENT ) { HalpWriteCMCVector( CMCI_VECTOR ); } return; } // HalpCMCEnable() VOID HalpCMCDisable( VOID ) /*++ Routine Description: This routine resets the processor CMCV register. Arguments: None Return Value: None --*/ { HalpWriteCMCVector( 0x10000ui64 ); return; } // HalpCMCDisable() ULONG_PTR HalpSetCMCVector( IN ULONG_PTR CmcVector ) /*++ Routine Description: This routine sets the processor CMCV register with specified vector. This function is the broadcast function for HalpCMCDisableForAllProcessors(). Arguments: CmcVector: CMC Vector value. Value: STATUS_SUCCESS --*/ { HalpWriteCMCVector( (ULONG64)CmcVector ); return((ULONG_PTR)(ULONG)(STATUS_SUCCESS)); } // HalpSetCmcVector() VOID HalpCMCDisableForAllProcessors( VOID ) /*++ Routine Description: This routine disables processor CMC on every processor in the host configuration by executing HalpSetCmcVector( 0ui64 ) on every processor in a synchronous manner. Arguments: None. Value: None. --*/ { // // Can not do an IPI if the processors are above IPI level such // as we are in the kernel debugger. // if (KeGetCurrentIrql() < IPI_LEVEL) { (VOID)KiIpiGenericCall( HalpSetCMCVector, (ULONG_PTR)0x10000ui64 ); } else { HalpSetCMCVector(0x10000ui64); } return; } // HalpCMCDisableForAllProcessors() VOID HalpCMCIHandler ( IN PKINTERRUPT_ROUTINE Interrupt, IN PKTRAP_FRAME TrapFrame ) /*++ Routine Description: Processor Interrupt routine for CMC interrupts. Arguments: TrapFrame - Captured trap frame address. Return Parameters: None. Notes: Thierry 08/2000: This function does not do much, it flags the PCR InOsCmc field and calls the second-level handler: HalpCmcHandler(). However, this was implmented this way so this function abstracts the standard interrupts resources from the purely CMC processing in HalpCmcHandler(). --*/ { volatile KPCR * const pcr = KeGetPcr(); pcr->InOsCmc = TRUE; HalpCmcHandler(); pcr->InOsCmc = FALSE; return; } // HalpCMCIHandler() VOID HalpCmcProcessLog( PCMC_EXCEPTION CmcLog ) /*++ Routine Description: This function does a simple processing check a IA64 CMC log. Arguments: CmcLog - Provides CMC log address Return Parameters: None. Notes: Currently simply checking and outputing log contents for checked hal only. --*/ { #if DBG // // Simple log processing for first debugging... // GUID processorDeviceGuid = ERROR_PROCESSOR_GUID; BOOLEAN processorDeviceFound; PERROR_RECORD_HEADER header = (PERROR_RECORD_HEADER)CmcLog; PERROR_SECTION_HEADER section, sectionMax; if ( header->ErrorSeverity != ErrorCorrected ) { HalDebugPrint(( HAL_ERROR, "HAL!HalpCmcProcessLog: CMC record with severity [%d] != corrected!!!\n", header->ErrorSeverity )); } // // SAL spec BUGBUG 08/2000: we should have put the length of the header in the definition. // Same for section header. // processorDeviceFound = FALSE; section = (PERROR_SECTION_HEADER)((ULONG_PTR)header + sizeof(*header)); sectionMax = (PERROR_SECTION_HEADER)((ULONG_PTR)header + header->Length); while( section < sectionMax ) { if ( IsEqualGUID( §ion->Guid, &processorDeviceGuid ) ) { PERROR_PROCESSOR processorRecord = (PERROR_PROCESSOR)section; processorDeviceFound = TRUE; // // Minimum processing here. This will enhance with testing and most common // occurences. // if ( processorRecord->Valid.StateParameter ) { ULONGLONG stateParameter = processorRecord->StateParameter.StateParameter; // // At any time more than one error could be valid // if((stateParameter >> ERROR_PROCESSOR_STATE_PARAMETER_CACHE_CHECK_SHIFT) & ERROR_PROCESSOR_STATE_PARAMETER_CACHE_CHECK_MASK) { // // cache error // HalDebugPrint(( HAL_INFO, "HAL!HalpCmcProcessLog: Corrected Processor CACHE Machine Check error\n" )); } if((stateParameter >> ERROR_PROCESSOR_STATE_PARAMETER_TLB_CHECK_SHIFT) & ERROR_PROCESSOR_STATE_PARAMETER_TLB_CHECK_MASK) { // // tlb error // HalDebugPrint(( HAL_INFO, "HAL!HalpCmcProcessLog: Corrected Processor TLB Machine Check error\n" )); } if((stateParameter >> ERROR_PROCESSOR_STATE_PARAMETER_BUS_CHECK_SHIFT) & ERROR_PROCESSOR_STATE_PARAMETER_BUS_CHECK_MASK) { // // bus error // HalDebugPrint(( HAL_INFO, "HAL!HalpCmcProcessLog: Corrected Processor BUS Machine Check error\n" )); } if((stateParameter >> ERROR_PROCESSOR_STATE_PARAMETER_UNKNOWN_CHECK_SHIFT) & ERROR_PROCESSOR_STATE_PARAMETER_UNKNOWN_CHECK_MASK) { // // unknown error // HalDebugPrint(( HAL_INFO, "HAL!HalpCmcProcessLog: Corrected Processor UNKNOWN Machine Check error\n" )); } } } } if ( !processorDeviceFound ) { HalDebugPrint(( HAL_ERROR, "HAL!HalpCmcProcessLog: CMC log without processor device record!!!\n")); } #endif // DBG return; } // HalpCmcProcessLog() //++ // Name: HalpCmcHandler() // // Routine Description: // // This is the second level CMC Interrupt Handler for FW corrected errors. // // Arguments On Entry: // None. // // Return. // None. // // Notes: // This function calls the kernel notification and inserts the OEM CMC driver dpc if // registered. // Accessing the CMC logs at this level could be inacceptable because of the possible // large size of the logs and the time required to collect them. // The collection of the logs is delayed until the work item calls // HalQuerySystemInformation.HalCmcLogInformation. //-- VOID HalpCmcHandler( VOID ) { // // Internal housekeeping. // InterlockedIncrement( &HalpCmcInfo.Stats.CmcInterruptCount ); // // Notify the kernel if registered. // if ( HalpCmcInfo.KernelDelivery ) { if ( !HalpCmcInfo.KernelDelivery( HalpCmcInfo.KernelToken, NULL ) ) { InterlockedIncrement( &HalpCmcInfo.Stats.KernelDeliveryFails ); } } // // Notify the OEM CMC driver if registered. // if ( HalpCmcInfo.DriverInfo.DpcCallback ) { if ( !KeInsertQueueDpc( &HalpCmcInfo.DriverDpc, NULL, NULL ) ) { InterlockedIncrement( &HalpCmcInfo.Stats.DriverDpcQueueFails ); } } return; } // HalpCmcHandler() //EndProc////////////////////////////////////////////////////////////////////// //++ // Name: HalpCpeHandler() // // Routine Description: // // This is the second level CPE Interrupt Handler for Platform corrected errors. // // Arguments On Entry: // None. // // Return. // None. // // Notes: // This function calls the kernel notification and inserts the OEM CPE driver dpc if // registered. // Accessing the CPE logs at this level could be inacceptable because of the possible // large size of the logs and the time required to collect them. // The collection of the logs is delayed until the work item calls // HalQuerySystemInformation.HalCpeLogInformation. //-- VOID HalpCpeHandler( VOID ) { // // Internal housekeeping. // InterlockedIncrement( &HalpCpeInfo.Stats.CpeInterruptCount ); // // Notify the kernel if registered. // if ( HalpCpeInfo.KernelDelivery ) { if ( !HalpCpeInfo.KernelDelivery( HalpCpeInfo.KernelToken, NULL ) ) { InterlockedIncrement( &HalpCpeInfo.Stats.KernelDeliveryFails ); } } // // Notify the OEM CPE driver if registered. // if ( HalpCpeInfo.DriverInfo.DpcCallback ) { if ( !KeInsertQueueDpc( &HalpCpeInfo.DriverDpc, NULL, NULL ) ) { InterlockedIncrement( &HalpCpeInfo.Stats.DriverDpcQueueFails ); } } return; } // HalpCpeHandler() //EndProc////////////////////////////////////////////////////////////////////// VOID HalpMcRzHandler ( IN PKINTERRUPT_ROUTINE Interrupt, IN PKTRAP_FRAME TrapFrame ) /*++ Routine Description: Arguements: Return Parameters: --*/ { SAL_PAL_RETURN_VALUES rv={0}; HalpDisableInterrupts(); rv=HalpSalRendz(); HalpEnableInterrupts(); // do any Isr clean up and re-enable the interrupts & MC's return; } //EndProc////////////////////////////////////////////////////////////////////// VOID HalpMcWkupHandler ( IN PKINTERRUPT_ROUTINE Interrupt, IN PKTRAP_FRAME TrapFrame ) /*++ Routine Description: Arguements: Return Parameters: --*/ { return; } //EndProc////////////////////////////////////////////////////////////////////// VOID HalpCPEIHandler ( IN PKINTERRUPT_ROUTINE Interrupt, IN PKTRAP_FRAME TrapFrame ) /*++ Routine Description: Processor Interrupt routine for CPE interrupts. Arguments: TrapFrame - Captured trap frame address. Return Parameters: None. Notes: Thierry 08/2000: This function does not do much, it flags the PCR InOsCpe field and calls the second-level handler: HalpCpeHandler(). However, this was implmented this way so this function abstracts the standard interrupts resources from the purely CPE processing in HalpCpeHandler(). --*/ { volatile KPCR * const pcr = KeGetPcr(); pcr->InOsCpe = TRUE; HalpCpeHandler(); pcr->InOsCpe = FALSE; return; } // HalpCPEIHandler() VOID HalpCPEEnable ( VOID ) /*++ Routine Description: This routine sets the default HAL CPE handling regardless of the user specified registry setting. It enables the supported Platform Interrupt sources and exposes the initial interrupt/polling based mode used for CPE. The user specified registry setting is handled via HalpMcaInit() at the end of phase 1. Arguments: None. Return Parameters: None. Implementation Notes: The following implementation assumes that this code is executed on BSP. --*/ { ULONG i; if ( HalpFeatureBits & HAL_CPE_PRESENT ) { ULONG maxCPE = HalpMaxCPEImplemented; if ( maxCPE ) { // // Pick up the information from HalpCPEIntIn, HalpCPEDestination, HalpCPEVectorFlags, // HalpCPEIoSapicVector. // for (i=0 ; i != maxCPE; i++ ) { HalpEnableRedirEntry( HalpCPEIntIn[i] ); } // // Initialize the remaining fields of HAL private CPE info structure. // HalpCpeInfo.Stats.PollingInterval = HAL_CPE_INTERRUPTS_BASED; } else { // // We will implement Polling model. // // // Thierry 03/11/2001: WARNING WARNING // Do not enable xxhal.c HAL_CPE_PRESENT if HalpMaxCPEImplemented == 0. // We bugcheck with the current BigSur SAL/FW (<= build 99) at SAL_GET_STATE_INFO calls, // the FW assuming that we are calling the SAL MC related functions in physical mode. // With the Lion SAL/FW (<= build 75), we bugcheck after getting MCA logs at boot time, // the FW having some virtualization issues. // Intel is committed to provide working FWs soon (< 2 weeks...). // HalpCpeInfo.Stats.PollingInterval = HALP_CPE_DEFAULT_POLLING_INTERVAL; } } else { HalpCpeInfo.Stats.PollingInterval = HAL_CPE_DISABLED; } return; } // HalpCPEEnable() VOID HalpCPEDisable ( VOID ) /*++ Routine Description: This routine disables the SAPIC Platform Interrupt Sources. Note that if HalpMaxCPEImplemented is 0, the function does nothing. Arguments: None. Return Parameters: None. --*/ { // // Pick up the information from HalpCPEIntIn, HalpCPEDestination, HalpCPEVectorFlags, // HalpCPEIoSapicVector int i; for (i=0;i != HalpMaxCPEImplemented;i++) { HalpDisableRedirEntry(HalpCPEIntIn[i]); } return; } // HalpCPEDisable() VOID HalpMCADisable( VOID ) { PHYSICAL_ADDRESS NULL_PHYSICAL_ADDRESS = {0}; SAL_PAL_RETURN_VALUES rv = {0}; char Lid; ULONGLONG gp_reg = GetGp(); // Disable CMCs HalpCMCDisableForAllProcessors(); // Disable CPE Interrupts HalpCPEDisable(); //DeRegister Rendez. Paramters with SAL #define NULL_VECTOR 0xF rv = HalpSalSetParams(0,RendzType, IntrVecType, NULL_VECTOR, HalpMcRendezTimeOut ); // Deregister WakeUp parameters with SAL rv=HalpSalSetParams(0, WakeUpType, IntrVecType, NULL_VECTOR,0); // Deregister OsMcaDispatch (OS_MCA) physical address with SAL rv=HalpSalSetVectors(0, MchkEvent, NULL_PHYSICAL_ADDRESS, gp_reg,0); // Deregister OsInitDispatch physical address with SAL rv=HalpSalSetVectors(0, InitEvent, NULL_PHYSICAL_ADDRESS, gp_reg,0); return; } // HalpMCADisable() NTSTATUS HalpGetMceInformation( PHAL_ERROR_INFO ErrorInfo, PULONG ErrorInfoLength ) /*++ Routine Description: This routine is called by HaliQuerySystemInformation for the HalErrorInformation class. Arguments: ErrorInfo : pointer to HAL_ERROR_INFO structure. ErrorInfoLength : size of the valid memory structure pointed by ErrorInfo. Return Value: STATUS_SUCCESS if successful error status otherwise --*/ { NTSTATUS status; ULONG cpePollingInterval; PAGED_CODE(); ASSERT( ErrorInfo ); ASSERT( ErrorInfoLength ); // // Backward compatibility only. // if ( !ErrorInfo->Version || ( ErrorInfo->Version > HAL_ERROR_INFO_VERSION ) ) { return( STATUS_REVISION_MISMATCH ); } // // Zero Reserved field. // ErrorInfo->Reserved = 0; // // Collect MCA info under protection if required. // ErrorInfo->McaMaxSize = HalpMcaInfo.Stats.MaxLogSize; ErrorInfo->McaPreviousEventsCount = HalpMcaInfo.Stats.McaPreviousCount; ErrorInfo->McaCorrectedEventsCount = HalpMcaInfo.Stats.McaCorrectedCount; // approximation. ErrorInfo->McaKernelDeliveryFails = HalpMcaInfo.Stats.KernelDeliveryFails; // approximation. ErrorInfo->McaDriverDpcQueueFails = HalpMcaInfo.Stats.DriverDpcQueueFails; // approximation. ErrorInfo->McaReserved = 0; // // Collect CMC info under protection if required. // ErrorInfo->CmcMaxSize = HalpCmcInfo.Stats.MaxLogSize; ErrorInfo->CmcPollingInterval = HalpCmcInfo.Stats.PollingInterval; ErrorInfo->CmcInterruptsCount = HalpCmcInfo.Stats.CmcInterruptCount; // approximation. ErrorInfo->CmcKernelDeliveryFails = HalpCmcInfo.Stats.KernelDeliveryFails; // approximation. ErrorInfo->CmcDriverDpcQueueFails = HalpCmcInfo.Stats.DriverDpcQueueFails; // approximation. HalpAcquireCmcMutex(); ErrorInfo->CmcGetStateFails = HalpCmcInfo.Stats.GetStateFails; ErrorInfo->CmcClearStateFails = HalpCmcInfo.Stats.ClearStateFails; ErrorInfo->CmcLogId = HalpCmcInfo.Stats.LogId; HalpReleaseCmcMutex(); ErrorInfo->CmcReserved = 0; // // Collect CPE info under protection if required. // ErrorInfo->CpeMaxSize = HalpCpeInfo.Stats.MaxLogSize; ErrorInfo->CpePollingInterval = HalpCpeInfo.Stats.PollingInterval; ErrorInfo->CpeInterruptsCount = HalpCpeInfo.Stats.CpeInterruptCount; // approximation. ErrorInfo->CpeKernelDeliveryFails = HalpCpeInfo.Stats.KernelDeliveryFails; // approximation. ErrorInfo->CpeDriverDpcQueueFails = HalpCpeInfo.Stats.DriverDpcQueueFails; // approximation. HalpAcquireCpeMutex(); ErrorInfo->CpeGetStateFails = HalpCpeInfo.Stats.GetStateFails; ErrorInfo->CpeClearStateFails = HalpCpeInfo.Stats.ClearStateFails; ErrorInfo->CpeLogId = HalpCpeInfo.Stats.LogId; HalpReleaseCpeMutex(); // CpeInterruptSources: Number of SAPIC Platform Interrup Sources supported by HAL. ErrorInfo->CpeInterruptSources = HalpMaxCPEImplemented; // // Update KernelTokens // ErrorInfo->McaKernelToken = (ULONGLONG) HalpMcaInfo.KernelToken; ErrorInfo->CmcKernelToken = (ULONGLONG) HalpCmcInfo.KernelToken; ErrorInfo->CpeKernelToken = (ULONGLONG) HalpCpeInfo.KernelToken; ErrorInfo->KernelReserved[3] = (ULONGLONG) 0; *ErrorInfoLength = sizeof(*ErrorInfo); return( STATUS_SUCCESS ); } // HalpGetMceInformation()