mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
868 lines
20 KiB
868 lines
20 KiB
/*++
|
|
|
|
Module Name:
|
|
|
|
ixmca.c
|
|
|
|
Abstract:
|
|
|
|
HAL component of the Machine Check Architecture.
|
|
All exported MCA functionality is present in this file.
|
|
|
|
Author:
|
|
|
|
Srikanth Kambhatla (Intel)
|
|
|
|
Revision History:
|
|
|
|
Anil Aggarwal (Intel)
|
|
Changes incorporated as per design review with Microsoft
|
|
|
|
--*/
|
|
|
|
#include <bugcodes.h>
|
|
#include <halp.h>
|
|
|
|
//
|
|
// Structure to keep track of MCA features available on installed hardware
|
|
//
|
|
|
|
typedef struct _MCA_INFO {
|
|
FAST_MUTEX Mutex;
|
|
UCHAR NumBanks; // Number of Banks present
|
|
ULONGLONG Bank0Config; // Bank0 configuration setup by BIOS.
|
|
// This will be used as mask when
|
|
// setting up bank 0
|
|
MCA_DRIVER_INFO DriverInfo; // Info about registered driver
|
|
KDPC Dpc; // DPC object for MCA
|
|
|
|
} MCA_INFO, *PMCA_INFO;
|
|
|
|
|
|
//
|
|
// Default MCA Bank configuration
|
|
//
|
|
#define MCA_DEFAULT_BANK_CONF 0xFFFFFFFFFFFFFFFF
|
|
|
|
//
|
|
// MCA architecture related defines
|
|
//
|
|
|
|
#define MCA_NUM_REGS 4
|
|
#define MCA_CNT_MASK 0xFF
|
|
#define MCG_CTL_PRESENT 0x100
|
|
|
|
#define MCE_VALID 0x01
|
|
|
|
//
|
|
// MSR register addresses for MCA
|
|
//
|
|
|
|
#define MCG_CAP 0x179
|
|
#define MCG_STATUS 0x17a
|
|
#define MCG_CTL 0x17b
|
|
#define MC0_CTL 0x400
|
|
#define MC0_STATUS 0x401
|
|
#define MC0_ADDR 0x402
|
|
#define MC0_MISC 0x403
|
|
|
|
#define PENTIUM_MC_ADDR 0x0
|
|
#define PENTIUM_MC_TYPE 0x1
|
|
|
|
//
|
|
// Writing all 1's to MCG_CTL register enables logging.
|
|
//
|
|
#define MCA_MCGCTL_ENABLE_LOGGING 0xffffffff
|
|
|
|
//
|
|
// Bit interpretation of MCG_STATUS register
|
|
//
|
|
#define MCG_MC_INPROGRESS 0x4
|
|
#define MCG_EIP_VALID 0x2
|
|
#define MCG_RESTART_EIP_VALID 0x1
|
|
|
|
//
|
|
// For the function that reads the error reporting bank log, the type of error we
|
|
// are interested in
|
|
//
|
|
#define MCA_GET_ANY_ERROR 0x1
|
|
#define MCA_GET_NONRESTARTABLE_ERROR 0x2
|
|
|
|
|
|
//
|
|
// Global Varibles
|
|
//
|
|
|
|
MCA_INFO HalpMcaInfo;
|
|
extern KAFFINITY HalpActiveProcessors;
|
|
extern UCHAR HalpClockMcaQueueDpc;
|
|
|
|
extern UCHAR MsgMCEPending[];
|
|
extern WCHAR rgzSessionManager[];
|
|
extern WCHAR rgzEnableMCE[];
|
|
extern WCHAR rgzEnableMCA[];
|
|
|
|
|
|
//
|
|
// External prototypes
|
|
//
|
|
|
|
VOID
|
|
HalpMcaCurrentProcessorSetTSS (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
HalpSetCr4MCEBit (
|
|
VOID
|
|
);
|
|
|
|
//
|
|
// Internal prototypes
|
|
//
|
|
|
|
VOID
|
|
HalpMcaInit (
|
|
VOID
|
|
);
|
|
|
|
NTSTATUS
|
|
HalpMcaReadProcessorException (
|
|
OUT PMCA_EXCEPTION Exception,
|
|
IN BOOLEAN NonRestartableOnly
|
|
);
|
|
|
|
VOID
|
|
HalpMcaCurrentProcessorSetConfig (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
HalpMcaQueueDpc(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
HalpMcaGetConfiguration (
|
|
OUT PULONG MCEEnabled,
|
|
OUT PULONG MCAEnabled
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT, HalpMcaInit)
|
|
#pragma alloc_text(INIT, HalpMcaCurrentProcessorSetConfig)
|
|
#pragma alloc_text(INIT, HalpMcaGetConfiguration)
|
|
#pragma alloc_text(PAGE, HalpGetMcaLog)
|
|
#pragma alloc_text(PAGE, HalpMcaRegisterDriver)
|
|
#endif
|
|
|
|
|
|
//
|
|
// All the initialization code for MCA goes here
|
|
//
|
|
|
|
VOID
|
|
HalpMcaInit (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
This routine is called to do all the initialization work
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS if successful
|
|
error status otherwise
|
|
--*/
|
|
|
|
{
|
|
ULONGLONG MsrCapability;
|
|
KIRQL OldIrql;
|
|
PKTHREAD Thread;
|
|
KAFFINITY ActiveProcessors, CurrentAffinity;
|
|
ULONGLONG MsrMceType;
|
|
ULONG MCEEnabled;
|
|
ULONG MCAEnabled;
|
|
|
|
if ( (!(HalpFeatureBits & HAL_MCE_PRESENT)) &&
|
|
(!(HalpFeatureBits & HAL_MCA_PRESENT)) ) {
|
|
|
|
return; // nothing to do
|
|
}
|
|
|
|
HalpMcaGetConfiguration(&MCEEnabled, &MCAEnabled);
|
|
|
|
if ( (HalpFeatureBits & HAL_MCE_PRESENT) &&
|
|
(!(HalpFeatureBits & HAL_MCA_PRESENT)) ) {
|
|
|
|
if (MCEEnabled == FALSE) {
|
|
|
|
// User has not enabled MCE capability.
|
|
HalpFeatureBits &= ~(HAL_MCE_PRESENT | HAL_MCA_PRESENT);
|
|
|
|
return;
|
|
}
|
|
|
|
#if DBG
|
|
DbgPrint("MCE feature is enabled via registry\n");
|
|
#endif // DBG
|
|
|
|
MsrMceType = RDMSR(PENTIUM_MC_TYPE);
|
|
|
|
if (((PLARGE_INTEGER)(&MsrMceType))->LowPart & MCE_VALID) {
|
|
|
|
//
|
|
// On an AST PREMMIA MX machine we seem to have a Machine Check Pending
|
|
// always.
|
|
//
|
|
|
|
HalDisplayString(MsgMCEPending);
|
|
|
|
HalpFeatureBits &= ~(HAL_MCE_PRESENT | HAL_MCA_PRESENT);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If MCA is available, find out the number of banks available and
|
|
// also get the platform specific bank 0 configuration
|
|
//
|
|
|
|
if ( HalpFeatureBits & HAL_MCA_PRESENT ) {
|
|
|
|
if (MCAEnabled == FALSE) {
|
|
|
|
/* User has disabled MCA capability. */
|
|
#if DBG
|
|
DbgPrint("MCA feature is disabled via registry\n");
|
|
#endif // DBG
|
|
|
|
HalpFeatureBits &= ~(HAL_MCE_PRESENT | HAL_MCA_PRESENT);
|
|
return;
|
|
}
|
|
|
|
MsrCapability = RDMSR(MCG_CAP);
|
|
HalpMcaInfo.NumBanks = (UCHAR)(MsrCapability & MCA_CNT_MASK);
|
|
|
|
//
|
|
// Find out the Bank 0 configuration setup by BIOS. This will be used
|
|
// as a mask when writing to Bank 0
|
|
//
|
|
|
|
HalpMcaInfo.Bank0Config = RDMSR(MC0_CTL);
|
|
}
|
|
|
|
if ( (HalpFeatureBits & HAL_MCA_PRESENT) ||
|
|
(HalpFeatureBits & HAL_MCE_PRESENT) ) {
|
|
|
|
ASSERT(HalpFeatureBits & HAL_MCE_PRESENT);
|
|
|
|
//
|
|
// This lock synchronises access to the log area when we call the
|
|
// logger on multiple processors.
|
|
//
|
|
|
|
ExInitializeFastMutex (&HalpMcaInfo.Mutex);
|
|
|
|
//
|
|
// Initialize on each processor
|
|
//
|
|
|
|
Thread = KeGetCurrentThread ();
|
|
ActiveProcessors = HalpActiveProcessors;
|
|
for (CurrentAffinity = 1; ActiveProcessors; CurrentAffinity <<= 1) {
|
|
|
|
if (ActiveProcessors & CurrentAffinity) {
|
|
ActiveProcessors &= ~CurrentAffinity;
|
|
KeSetAffinityThread (Thread, CurrentAffinity);
|
|
|
|
//
|
|
// Initialize MCA support on this processor
|
|
//
|
|
|
|
OldIrql = KfRaiseIrql(HIGH_LEVEL);
|
|
|
|
HalpMcaCurrentProcessorSetTSS();
|
|
HalpMcaCurrentProcessorSetConfig();
|
|
|
|
KfLowerIrql(OldIrql);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Restore threads affinity
|
|
//
|
|
|
|
KeSetAffinityThread (Thread, HalpActiveProcessors);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
HalpMcaCurrentProcessorSetConfig (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets/modifies the configuration of the machine check
|
|
architecture on the current processor. Input is specification of
|
|
the control register MCi_CTL for each bank of the MCA architecture.
|
|
which controls the generation of machine check exceptions for errors
|
|
logged to that bank.
|
|
|
|
If MCA is not available on this processor, check if MCE is available.
|
|
If so, enable MCE in CR4
|
|
|
|
Arguments:
|
|
|
|
Context: Array of values of MCi_CTL for each bank of MCA.
|
|
If NULL, use MCA_DEFAULT_BANK_CONF values for each bank
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
ULONGLONG MciCtl;
|
|
ULONGLONG McgCap;
|
|
ULONGLONG McgCtl;
|
|
ULONG BankNum;
|
|
|
|
|
|
if (HalpFeatureBits & HAL_MCA_PRESENT) {
|
|
//
|
|
// MCA is available. Initialize MCG_CTL register if present
|
|
// Writing all 1's enable MCE or MCA Error Exceptions
|
|
//
|
|
|
|
McgCap = RDMSR(MCG_CAP);
|
|
|
|
if (McgCap & MCG_CTL_PRESENT) {
|
|
McgCtl = MCA_MCGCTL_ENABLE_LOGGING;
|
|
WRMSR(MCG_CTL, McgCtl);
|
|
}
|
|
|
|
//
|
|
// Enable all MCA errors
|
|
//
|
|
for ( BankNum = 0; BankNum < HalpMcaInfo.NumBanks; BankNum++ ) {
|
|
|
|
//
|
|
// Use MCA_DEFAULT_BANK_CONF for each bank
|
|
//
|
|
|
|
MciCtl = MCA_DEFAULT_BANK_CONF;
|
|
|
|
//
|
|
// If this is bank 0, use HalpMcaInfo.Bank0Config as a mask
|
|
//
|
|
if (BankNum == 0) {
|
|
MciCtl &= HalpMcaInfo.Bank0Config;
|
|
}
|
|
|
|
WRMSR(MC0_CTL + (BankNum * MCA_NUM_REGS), MciCtl);
|
|
|
|
//
|
|
// Clear the MCi_STATUS registers also
|
|
//
|
|
WRMSR(MC0_STATUS + (BankNum * MCA_NUM_REGS), 0x0);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Enable MCE bit in CR4
|
|
//
|
|
|
|
HalpSetCr4MCEBit();
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
HalpMcaRegisterDriver(
|
|
IN PMCA_DRIVER_INFO DriverInfo
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
This routine is called by the driver (via HalSetSystemInformation)
|
|
to register its presence. Only one driver can be registered at a time.
|
|
|
|
Arguments:
|
|
DriverInfo: Contains info about the callback routine and the DeviceObject
|
|
|
|
Return Value:
|
|
Unless a MCA driver is already registered OR one of the two callback
|
|
routines are NULL, this routine returns Success.
|
|
--*/
|
|
|
|
{
|
|
KIRQL OldIrql;
|
|
PVOID UnlockHandle;
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
|
|
if ((HalpFeatureBits & HAL_MCE_PRESENT) && DriverInfo->DpcCallback) {
|
|
|
|
ExAcquireFastMutex (&HalpMcaInfo.Mutex);
|
|
|
|
//
|
|
// Register driver
|
|
//
|
|
|
|
if (!HalpMcaInfo.DriverInfo.DpcCallback) {
|
|
|
|
// Initialize the DPC object
|
|
KeInitializeDpc(
|
|
&HalpMcaInfo.Dpc,
|
|
DriverInfo->DpcCallback,
|
|
DriverInfo->DeviceContext
|
|
);
|
|
|
|
// register driver
|
|
HalpMcaInfo.DriverInfo.ExceptionCallback = DriverInfo->ExceptionCallback;
|
|
HalpMcaInfo.DriverInfo.DpcCallback = DriverInfo->DpcCallback;
|
|
HalpMcaInfo.DriverInfo.DeviceContext = DriverInfo->DeviceContext;
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
ExReleaseFastMutex (&HalpMcaInfo.Mutex);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
HalpGetMcaLog (
|
|
OUT PMCA_EXCEPTION Exception,
|
|
OUT PULONG ReturnedLength
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
This is the entry point for driver to read the bank logs
|
|
Called by HaliQuerySystemInformation()
|
|
|
|
Arguments:
|
|
Buffer: into which the error is reported
|
|
BufferSize: Size of the passed buffer
|
|
Length: of this buffer
|
|
|
|
Return Value:
|
|
Success or failure
|
|
|
|
--*/
|
|
{
|
|
KAFFINITY ActiveProcessors, CurrentAffinity;
|
|
PKTHREAD Thread;
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (! (HalpFeatureBits & HAL_MCA_PRESENT)) {
|
|
return(STATUS_NO_SUCH_DEVICE);
|
|
}
|
|
|
|
|
|
Thread = KeGetCurrentThread ();
|
|
ActiveProcessors = HalpActiveProcessors;
|
|
Status = STATUS_NOT_FOUND;
|
|
|
|
ExAcquireFastMutex (&HalpMcaInfo.Mutex);
|
|
|
|
for (CurrentAffinity = 1; ActiveProcessors; CurrentAffinity <<= 1) {
|
|
|
|
if (ActiveProcessors & CurrentAffinity) {
|
|
|
|
ActiveProcessors &= ~CurrentAffinity;
|
|
KeSetAffinityThread (Thread, CurrentAffinity);
|
|
|
|
//
|
|
// Check this processor for an exception
|
|
//
|
|
|
|
Status = HalpMcaReadProcessorException (Exception, FALSE);
|
|
|
|
//
|
|
// If found, return current information
|
|
//
|
|
|
|
if (Status != STATUS_NOT_FOUND) {
|
|
ASSERT (Status != STATUS_SEVERITY_ERROR);
|
|
|
|
*ReturnedLength = sizeof(MCA_EXCEPTION);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Restore threads affinity, release mutex, and return
|
|
//
|
|
|
|
KeSetAffinityThread (Thread, HalpActiveProcessors);
|
|
ExReleaseFastMutex (&HalpMcaInfo.Mutex);
|
|
return Status;
|
|
}
|
|
|
|
|
|
#if DBG
|
|
//
|
|
// In checked build, we allocate 4K stack for ourselves and hence there is
|
|
// no need to switch to the stack of double fault handler. We can
|
|
// directly bugcheck without switching stack.
|
|
//
|
|
#define HalpMcaSwitchMcaExceptionStackAndBugCheck KeBugCheckEx
|
|
#else
|
|
NTKERNELAPI
|
|
VOID
|
|
HalpMcaSwitchMcaExceptionStackAndBugCheck(
|
|
IN ULONG BugCheckCode,
|
|
IN ULONG BugCheckParameter1,
|
|
IN ULONG BugCheckParameter2,
|
|
IN ULONG BugCheckParameter3,
|
|
IN ULONG BugCheckParameter4
|
|
);
|
|
#endif // DBG
|
|
|
|
// Set the following to check async capability
|
|
|
|
BOOLEAN NoMCABugCheck = FALSE;
|
|
|
|
VOID
|
|
HalpMcaExceptionHandler (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
This is the MCA exception handler.
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Return Value:
|
|
None
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
MCA_EXCEPTION BankLog;
|
|
ULONG p1, p2;
|
|
ULONGLONG McgStatus, p3;
|
|
|
|
BankLog.VersionNumber = 1;
|
|
|
|
if (!(HalpFeatureBits & HAL_MCA_PRESENT) ) {
|
|
|
|
//
|
|
// If we have ONLY MCE (and not MCA), read the MC_ADDR and MC_TYPE
|
|
// MSRs, print the values and bugcheck as the errors are not
|
|
// restartable.
|
|
//
|
|
|
|
BankLog.ExceptionType = HAL_MCE_RECORD;
|
|
BankLog.u.Mce.Address = RDMSR(PENTIUM_MC_ADDR);
|
|
BankLog.u.Mce.Type = RDMSR(PENTIUM_MC_TYPE);
|
|
Status = STATUS_SEVERITY_ERROR;
|
|
|
|
//
|
|
// Parameters for bugcheck
|
|
//
|
|
|
|
p1 = ((PLARGE_INTEGER)(&BankLog.u.Mce.Type))->LowPart;
|
|
p2 = 0;
|
|
p3 = BankLog.u.Mce.Address;
|
|
|
|
} else {
|
|
|
|
McgStatus = RDMSR(MCG_STATUS);
|
|
ASSERT( (McgStatus & MCG_MC_INPROGRESS) != 0);
|
|
|
|
Status = HalpMcaReadProcessorException (&BankLog, TRUE);
|
|
|
|
//
|
|
// Clear MCIP bit in MCG_STATUS register
|
|
//
|
|
|
|
McgStatus = 0;
|
|
WRMSR(MCG_STATUS, McgStatus);
|
|
|
|
//
|
|
// Parameters for bugcheck
|
|
//
|
|
|
|
p1 = BankLog.u.Mca.BankNumber;
|
|
p2 = BankLog.u.Mca.Address.Address;
|
|
p3 = BankLog.u.Mca.Status.QuadPart;
|
|
}
|
|
|
|
if (Status == STATUS_SEVERITY_ERROR) {
|
|
|
|
//
|
|
// Call the exception callback of the driver so that
|
|
// the error can be logged to NVRAM
|
|
//
|
|
|
|
if (HalpMcaInfo.DriverInfo.ExceptionCallback) {
|
|
HalpMcaInfo.DriverInfo.ExceptionCallback (
|
|
HalpMcaInfo.DriverInfo.DeviceContext,
|
|
&BankLog
|
|
);
|
|
}
|
|
|
|
if (!NoMCABugCheck) {
|
|
|
|
//
|
|
// Bugcheck
|
|
//
|
|
|
|
HalpMcaSwitchMcaExceptionStackAndBugCheck(
|
|
MACHINE_CHECK_EXCEPTION,
|
|
p1,
|
|
p2,
|
|
((PLARGE_INTEGER)(&p3))->HighPart,
|
|
((PLARGE_INTEGER)(&p3))->LowPart
|
|
);
|
|
|
|
// NOT REACHED
|
|
}
|
|
}
|
|
|
|
//
|
|
// Must be restartable. Indicate to the timer tick routine that a
|
|
// DPC needs queued for MCA driver.
|
|
//
|
|
|
|
if (HalpMcaInfo.DriverInfo.DpcCallback) {
|
|
HalpClockMcaQueueDpc = 1;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
HalpMcaQueueDpc(
|
|
VOID
|
|
)
|
|
/*++
|
|
Routine Description: Gets called from the timer tick to check if DPC
|
|
needs to be queued
|
|
|
|
--*/
|
|
|
|
{
|
|
KeInsertQueueDpc(
|
|
&HalpMcaInfo.Dpc,
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
HalpMcaReadProcessorException (
|
|
OUT PMCA_EXCEPTION Exception,
|
|
IN BOOLEAN NonRestartableOnly
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine logs the errors from the MCA banks on one processor.
|
|
Necessary checks for the restartability are performed. The routine
|
|
1> Checks for restartability, and for each bank identifies valid bank
|
|
entries and logs error.
|
|
2> If the error is not restartable provides additional information about
|
|
bank and the MCA registers.
|
|
3> Resets the Status registers for each bank
|
|
|
|
Arguments:
|
|
LogExcept: Into which we log the error if found
|
|
NonRestartableOnly: Get any error vs. look for error that is not-restartable
|
|
|
|
Return Values:
|
|
STATUS_SEVERITY_ERROR: Detected non-restartable error.
|
|
STATUS_SUCCESS: Successfully logged bank values
|
|
STATUS_NOT_FOUND: No error found on any bank
|
|
|
|
--*/
|
|
{
|
|
ULONGLONG McgStatus;
|
|
UCHAR BankNumber;
|
|
MCI_STATS istatus;
|
|
NTSTATUS ReturnStatus;
|
|
ULONG eflags;
|
|
|
|
//
|
|
// Read the global status register
|
|
//
|
|
|
|
McgStatus = RDMSR(MCG_STATUS);
|
|
|
|
//
|
|
// scan banks on current processor and log contents of first valid bank
|
|
// reporting error. Once we find a valid error, no need to read remaining
|
|
// banks. It is the application responsibility to read more errors.
|
|
//
|
|
|
|
ReturnStatus = STATUS_NOT_FOUND;
|
|
|
|
for (BankNumber = 0; BankNumber < HalpMcaInfo.NumBanks; BankNumber++) {
|
|
|
|
//
|
|
// Read the Status MSR of individual bank
|
|
//
|
|
|
|
istatus.QuadPart = RDMSR(MC0_STATUS + BankNumber * MCA_NUM_REGS);
|
|
|
|
|
|
if (istatus.MciStats.Valid == 0) {
|
|
// No error in this bank.
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
// When MCIP bit is set, the execution can be restarted when
|
|
// (MCi_STATUS.DAM == 0) && (MCG_STATUS.RIPV == 1)
|
|
//
|
|
|
|
if ((McgStatus & MCG_MC_INPROGRESS) &&
|
|
(!(McgStatus & MCG_RESTART_EIP_VALID) ||
|
|
istatus.MciStats.Damage)) {
|
|
|
|
ReturnStatus = STATUS_SEVERITY_ERROR;
|
|
|
|
} else if (NonRestartableOnly == FALSE) {
|
|
|
|
ReturnStatus = STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
// Not the desired type error available here
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Complete exception record
|
|
//
|
|
|
|
Exception->VersionNumber = 1;
|
|
Exception->ExceptionType = HAL_MCA_RECORD;
|
|
Exception->TimeStamp.QuadPart = 0;
|
|
Exception->u.Mca.Address.QuadPart = 0;
|
|
Exception->u.Mca.Misc = 0;
|
|
Exception->u.Mca.BankNumber = BankNumber;
|
|
Exception->u.Mca.Status = istatus;
|
|
|
|
Exception->ProcessorNumber = KeGetCurrentProcessorNumber();
|
|
|
|
if (KeGetCurrentIrql() != CLOCK2_LEVEL) {
|
|
KeQuerySystemTime(&Exception->TimeStamp);
|
|
}
|
|
|
|
if (istatus.MciStats.AddressValid) {
|
|
Exception->u.Mca.Address.QuadPart = RDMSR(MC0_ADDR + BankNumber * MCA_NUM_REGS);
|
|
}
|
|
|
|
if (istatus.MciStats.MiscValid) {
|
|
Exception->u.Mca.Misc = RDMSR(MC0_MISC + BankNumber * MCA_NUM_REGS);
|
|
}
|
|
|
|
if (ReturnStatus != STATUS_SEVERITY_ERROR) {
|
|
|
|
// Clear MCi_STATUS register (not a falal error)
|
|
|
|
WRMSR(MC0_STATUS + BankNumber * MCA_NUM_REGS, 0);
|
|
}
|
|
|
|
//
|
|
// When the Valid bit of status register is cleared, hardware may write
|
|
// a new buffered error report into the error reporting area. The
|
|
// serializing instruction is required to permit the update to complete
|
|
//
|
|
|
|
HalpSerialize ();
|
|
|
|
//
|
|
// Found entry, done
|
|
//
|
|
|
|
break;
|
|
}
|
|
|
|
return(ReturnStatus);
|
|
}
|
|
|
|
VOID
|
|
HalpMcaGetConfiguration (
|
|
OUT PULONG MCEEnabled,
|
|
OUT PULONG MCAEnabled
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine stores the Machine Check configuration information.
|
|
|
|
Arguments:
|
|
|
|
MCEEnabled - Pointer to the MCEEnabled indicator.
|
|
0 = False, 1 = True (0 if value not present in Registry).
|
|
|
|
MCAEnabled - Pointer to the MCAEnabled indicator.
|
|
0 = False, 1 = True (1 if value not present in Registry).
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
RTL_QUERY_REGISTRY_TABLE Parameters[3];
|
|
ULONG DefaultDataMCE;
|
|
ULONG DefaultDataMCA;
|
|
|
|
|
|
RtlZeroMemory(Parameters, sizeof(Parameters));
|
|
DefaultDataMCE = *MCEEnabled = FALSE;
|
|
DefaultDataMCA = *MCAEnabled = TRUE;
|
|
|
|
//
|
|
// Gather all of the "user specified" information from
|
|
// the registry.
|
|
//
|
|
|
|
Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
Parameters[0].Name = rgzEnableMCE;
|
|
Parameters[0].EntryContext = MCEEnabled;
|
|
Parameters[0].DefaultType = REG_DWORD;
|
|
Parameters[0].DefaultData = &DefaultDataMCE;
|
|
Parameters[0].DefaultLength = sizeof(ULONG);
|
|
|
|
Parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
Parameters[1].Name = rgzEnableMCA;
|
|
Parameters[1].EntryContext = MCAEnabled;
|
|
Parameters[1].DefaultType = REG_DWORD;
|
|
Parameters[1].DefaultData = &DefaultDataMCA;
|
|
Parameters[1].DefaultLength = sizeof(ULONG);
|
|
|
|
RtlQueryRegistryValues(
|
|
RTL_REGISTRY_CONTROL | RTL_REGISTRY_OPTIONAL,
|
|
rgzSessionManager,
|
|
Parameters,
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|