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.
811 lines
25 KiB
811 lines
25 KiB
/*++
|
|
|
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
Common.cpp
|
|
|
|
Abstract:
|
|
|
|
This module encapsulates the common routines that are used
|
|
during both fatal and corrected error retrieval.
|
|
|
|
Author:
|
|
|
|
Abdullah Ustuner (AUstuner) 26-August-2002
|
|
|
|
--*/
|
|
|
|
#include "mca.h"
|
|
|
|
IWbemServices *gPIWbemServices = NULL;
|
|
IWbemLocator *gPIWbemLocator = NULL;
|
|
|
|
|
|
BOOL
|
|
MCAExtractErrorRecord(
|
|
IN IWbemClassObject *PObject,
|
|
OUT PUCHAR *PRecordBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function retrieves embedded objects from the error record
|
|
(obtained from WMI) that contain both the record data and other
|
|
information about the record (such as length). The data is saved
|
|
into the output buffer provided.
|
|
|
|
Arguments:
|
|
|
|
PObject - Event object retrieved from WMI.
|
|
PRecordBuffer - Pointer to a buffer to save the MCA error record.
|
|
|
|
Return Value:
|
|
|
|
TRUE - Successful.
|
|
FALSE - Unsuccessful.
|
|
|
|
--*/
|
|
{
|
|
IWbemClassObject *pRecordsObject = NULL;
|
|
VARIANT recordsPropertyVariant;
|
|
VARIANT countPropertyVariant;
|
|
VARIANT recordLengthVariant;
|
|
VARIANT recordDataVariant;
|
|
HRESULT hResult = WBEM_S_NO_ERROR;
|
|
IUnknown *punk = NULL;
|
|
LONG mcaRecordByte = 0, index = 0;
|
|
UCHAR recordDataByte;
|
|
BOOL isSuccess = TRUE;
|
|
|
|
//
|
|
// Retrieve the "Records" property value of the event object.
|
|
//
|
|
hResult = PObject->Get(L"Records",
|
|
0,
|
|
&recordsPropertyVariant,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (FAILED(hResult)) {
|
|
|
|
isSuccess = FALSE;
|
|
|
|
wprintf(L"ERROR: \"Records\" property value couldn't be retrieved!\n");
|
|
|
|
goto CleanUp;
|
|
|
|
}
|
|
|
|
//
|
|
// Retrieve the "Count" property value of the event object.
|
|
//
|
|
hResult = PObject->Get(L"Count",
|
|
0,
|
|
&countPropertyVariant,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (FAILED(hResult)) {
|
|
|
|
isSuccess = FALSE;
|
|
|
|
wprintf(L"ERROR: \"Count\" property value couldn't be retrieved!\n");
|
|
|
|
goto CleanUp;
|
|
|
|
}
|
|
|
|
//
|
|
// Check the "Count" property to ensure that it is not zero.
|
|
//
|
|
if (countPropertyVariant.lVal < 1) {
|
|
|
|
isSuccess = FALSE;
|
|
|
|
wprintf(L"ERROR: \"Count\" is less than 1!\n");
|
|
|
|
goto CleanUp;
|
|
|
|
}
|
|
|
|
//
|
|
// The Records Property Variant.parray should contain a
|
|
// pointer to an array of pointers. However, MCA should only
|
|
// place one pointer in this array. Use the Safearray APIs to
|
|
// get that pointer.
|
|
//
|
|
hResult = SafeArrayGetElement(recordsPropertyVariant.parray,
|
|
&index,
|
|
&punk
|
|
);
|
|
|
|
if(FAILED(hResult)){
|
|
|
|
isSuccess = FALSE;
|
|
|
|
wprintf(L"ERROR: Couldn't retrieve array pointer!\n");
|
|
|
|
goto CleanUp;
|
|
|
|
}
|
|
|
|
//
|
|
// Punk should contain an object of type IWbemClassObject. This should
|
|
// be the MCA record object that will contain "Length" and "Data" elements.
|
|
//
|
|
hResult = (punk->QueryInterface(IID_IWbemClassObject,
|
|
(PVOID*)&pRecordsObject)
|
|
);
|
|
|
|
if (FAILED(hResult)) {
|
|
|
|
isSuccess = FALSE;
|
|
|
|
wprintf(L"ERROR: Interface pointer couldn't be retrieved!\n");
|
|
|
|
goto CleanUp;
|
|
|
|
}
|
|
|
|
//
|
|
// Obtain the length of the error record.
|
|
//
|
|
hResult = pRecordsObject->Get(L"Length",
|
|
0,
|
|
&recordLengthVariant,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (FAILED(hResult)) {
|
|
|
|
isSuccess = FALSE;
|
|
|
|
wprintf(L"\"Length\" property value couldn't be retrieved!\n");
|
|
|
|
goto CleanUp;
|
|
|
|
}
|
|
|
|
//
|
|
// Obtain the actual data from the records object. This should contain a parray
|
|
// that points to the actual MCA data we are looking for.
|
|
//
|
|
hResult = pRecordsObject->Get(L"Data",
|
|
0,
|
|
&recordDataVariant,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (FAILED(hResult)) {
|
|
|
|
isSuccess = FALSE;
|
|
|
|
wprintf(L"\"Data\" property value couldn't be retrieved!\n");
|
|
|
|
goto CleanUp;
|
|
|
|
}
|
|
|
|
//
|
|
// Check if the "Data" field in the record contains any data.
|
|
//
|
|
if (recordDataVariant.parray == NULL) {
|
|
|
|
isSuccess = FALSE;
|
|
|
|
wprintf(L"ERROR: Error record contains to data!\n");
|
|
|
|
goto CleanUp;
|
|
|
|
}
|
|
|
|
PUCHAR PTempBuffer = NULL;
|
|
|
|
//
|
|
// Allocate memory for the error record buffer. The size of the memory should be
|
|
// equal to the size of the MCA error record data field.
|
|
//
|
|
if ((*PRecordBuffer) == NULL) {
|
|
|
|
*PRecordBuffer = (PUCHAR)(calloc(recordLengthVariant.lVal, sizeof(UINT8)));
|
|
|
|
if((*PRecordBuffer) == NULL) {
|
|
|
|
isSuccess = FALSE;
|
|
|
|
wprintf(L"ERROR: Memory allocation for record buffer failed!\n");
|
|
|
|
goto CleanUp;
|
|
|
|
}
|
|
|
|
} else{
|
|
|
|
PTempBuffer = (PUCHAR)(realloc(*PRecordBuffer, (recordLengthVariant.lVal * sizeof(UINT8))));
|
|
|
|
//
|
|
// If reallocation of memory for the buffer failed, then display error message and return.
|
|
//
|
|
if (PTempBuffer == NULL) {
|
|
|
|
isSuccess = FALSE;
|
|
|
|
wprintf(L"ERROR: Memory reallocation for record buffer failed!\n");
|
|
|
|
goto CleanUp;
|
|
|
|
} else {
|
|
|
|
*PRecordBuffer = PTempBuffer;
|
|
|
|
ZeroMemory(*PRecordBuffer, recordLengthVariant.lVal * sizeof(**PRecordBuffer));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Get the MCA error record data byte by byte and save it into the allocated buffer.
|
|
//
|
|
for (mcaRecordByte = 0; mcaRecordByte < recordLengthVariant.lVal; mcaRecordByte++){
|
|
|
|
recordDataByte = 0;
|
|
|
|
hResult = SafeArrayGetElement(recordDataVariant.parray,
|
|
&mcaRecordByte,
|
|
&recordDataByte
|
|
);
|
|
|
|
if (FAILED(hResult)) {
|
|
|
|
isSuccess = FALSE;
|
|
|
|
wprintf(L"ERROR: Error record data couldn't be read!\n");
|
|
|
|
goto CleanUp;
|
|
}
|
|
|
|
// Copy error record data byte into buffer.
|
|
*((*PRecordBuffer) + (mcaRecordByte * sizeof(UINT8))) = recordDataByte;
|
|
|
|
}
|
|
|
|
CleanUp:
|
|
|
|
VariantClear(&recordDataVariant);
|
|
|
|
VariantClear(&recordLengthVariant);
|
|
|
|
VariantClear(&recordsPropertyVariant);
|
|
|
|
VariantClear(&countPropertyVariant);
|
|
|
|
return isSuccess;
|
|
}
|
|
|
|
|
|
BOOL
|
|
MCAInitialize(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function accomplishes the required initialization tasks required by
|
|
both fatal and corrected error retrieval.
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
TRUE - Successful.
|
|
FALSE - Unsuccessful.
|
|
|
|
--*/
|
|
{
|
|
BOOL isSuccess = TRUE;
|
|
|
|
//
|
|
// Initialize COM Library
|
|
//
|
|
if (!MCAInitializeCOMLibrary()) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
//
|
|
// Set Security
|
|
//
|
|
if(!MCAInitializeWMISecurity()){
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return isSuccess;
|
|
}
|
|
|
|
|
|
BOOL
|
|
MCAInitializeCOMLibrary(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes the COM library.
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
TRUE - Successful.
|
|
FALSE - Unsuccessful.
|
|
|
|
--*/
|
|
{
|
|
HRESULT hResult = 0;
|
|
|
|
hResult = CoInitializeEx(0, COINIT_MULTITHREADED);
|
|
|
|
if (FAILED(hResult)) {
|
|
|
|
wprintf(L"ERROR: COM library initialization failed!\n");
|
|
|
|
wprintf(L"ERROR: Result: 0x%x\n", hResult);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
wprintf(L"INFO: COM library initialization is successfully completed.\n");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
MCAInitializeWMISecurity(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes the required security settings and establishes
|
|
the connection to the WMI server on the local system.
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
TRUE - Successful.
|
|
FALSE - Unsuccessful.
|
|
|
|
--*/
|
|
{
|
|
HRESULT hResult = 0;
|
|
LPWSTR pNamespace = L"ROOT\\WMI";
|
|
|
|
//
|
|
// Register security and set the security values for the current process.
|
|
//
|
|
hResult = CoInitializeSecurity(NULL,
|
|
-1,
|
|
NULL,
|
|
NULL,
|
|
RPC_C_AUTHN_LEVEL_CONNECT,
|
|
RPC_C_IMP_LEVEL_IDENTIFY,
|
|
NULL,
|
|
EOAC_NONE,
|
|
NULL
|
|
);
|
|
|
|
if (FAILED(hResult)) {
|
|
|
|
wprintf(L"ERROR: Security initialization failed!\n");
|
|
|
|
wprintf(L"ERROR: Result: 0x%x\n", hResult);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
//
|
|
// Create a single uninitialized object of class IWbemLocator on the local system.
|
|
//
|
|
hResult = CoCreateInstance(CLSID_WbemLocator,
|
|
0,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IWbemLocator,
|
|
(LPVOID *) &gPIWbemLocator
|
|
);
|
|
|
|
if (FAILED(hResult)) {
|
|
|
|
wprintf(L"ERROR: IWbemLocator instance creation failed!\n");
|
|
|
|
wprintf(L"ERROR: Result: 0x%x\n", hResult);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
BSTR bNamespace = SysAllocString(pNamespace);
|
|
|
|
if (bNamespace == NULL) {
|
|
|
|
wprintf(L"ERROR: Memory allocation for string failed!\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
//
|
|
// Connect to the root\wmi namespace with the current user.
|
|
//
|
|
hResult = (gPIWbemLocator)->ConnectServer(bNamespace,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&gPIWbemServices
|
|
);
|
|
|
|
if (FAILED(hResult)) {
|
|
|
|
wprintf(L"ERROR: Could not connect to the WMI Server!\n");
|
|
|
|
wprintf(L"ERROR: Result: 0x%x\n", hResult);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
//
|
|
// Set the authentication information on the specified proxy such that
|
|
// impersonation of the client occurs.
|
|
//
|
|
hResult = CoSetProxyBlanket(gPIWbemServices,
|
|
RPC_C_AUTHN_WINNT,
|
|
RPC_C_AUTHZ_NONE,
|
|
NULL,
|
|
RPC_C_AUTHN_LEVEL_CALL,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
NULL,
|
|
EOAC_NONE
|
|
);
|
|
|
|
if (FAILED(hResult)) {
|
|
|
|
wprintf(L"ERROR: Could not set proxy blanket!\n");
|
|
|
|
wprintf(L"ERROR: Result: 0x%x\n", hResult);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
wprintf(L"INFO: WMI security is initialized successfully.\n");
|
|
|
|
//
|
|
// Free the string allocated for storing the namespace.
|
|
//
|
|
if (bNamespace != NULL) {
|
|
|
|
SysFreeString(bNamespace);
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#if defined(_X86_)
|
|
|
|
VOID
|
|
MCAPrintErrorRecordX86(
|
|
PUCHAR PErrorData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function displays the machine check exception information on X86
|
|
systems to the standard output (console screen).
|
|
|
|
Arguments:
|
|
|
|
PErrorData - Buffer containing the machine check exception information.
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
|
|
PMCA_EXCEPTION pMCAException = NULL;
|
|
|
|
pMCAException = (PMCA_EXCEPTION)PErrorData;
|
|
|
|
wprintf(L"\n");
|
|
|
|
wprintf(L"**************************************************\n");
|
|
wprintf(L"* X86 MCA EXCEPTION *\n");
|
|
wprintf(L"**************************************************\n");
|
|
wprintf(L"* VersionNumber : 0x%08x\n", (ULONG) pMCAException->VersionNumber);
|
|
wprintf(L"* ExceptionType : 0x%08x\n", (INT) pMCAException->ExceptionType);
|
|
wprintf(L"* TimeStamp \n");
|
|
wprintf(L"* LowPart : 0x%08x\n",(ULONG) pMCAException->TimeStamp.LowPart);
|
|
wprintf(L"* HighPart: 0x%08x\n", (LONG) pMCAException->TimeStamp.HighPart);
|
|
wprintf(L"* ProcessorNumber : 0x%08x\n", (ULONG) pMCAException->ProcessorNumber);
|
|
wprintf(L"* Reserved1 : 0x%08x\n", (ULONG) pMCAException->Reserved1);
|
|
|
|
if (pMCAException->ExceptionType == HAL_MCE_RECORD) {
|
|
|
|
wprintf(L"* Mce \n");
|
|
wprintf(L"* Address : 0x%016I64x\n", (ULONGLONG) pMCAException->u.Mce.Address);
|
|
wprintf(L"* Type : 0x%016I64x\n", (ULONGLONG) pMCAException->u.Mce.Type);
|
|
|
|
} else {
|
|
|
|
wprintf(L"* Mca \n");
|
|
wprintf(L"* BankNumber : 0x%02x\n", (UCHAR) pMCAException->u.Mca.BankNumber);
|
|
|
|
for (int index = 0 ; index < 7 ; index++) {
|
|
|
|
wprintf(L"* Reserved2[%d]: 0x%02x\n", index, (UCHAR) pMCAException->u.Mca.Reserved2[index]);
|
|
|
|
}
|
|
|
|
wprintf(L"* MciStats \n");
|
|
wprintf(L"* McaCod : 0x%04x\n", (USHORT) pMCAException->u.Mca.Status.MciStats.McaCod);
|
|
wprintf(L"* MsCod : 0x%04x\n", (USHORT) pMCAException->u.Mca.Status.MciStats.MsCod);
|
|
wprintf(L"* OtherInfo : 0x%01x\n", (ULONG) pMCAException->u.Mca.Status.MciStats.OtherInfo);
|
|
wprintf(L"* Damage : 0x%01x\n", (ULONG) pMCAException->u.Mca.Status.MciStats.Damage);
|
|
wprintf(L"* AddressValid: 0x%01x\n", (ULONG) pMCAException->u.Mca.Status.MciStats.AddressValid);
|
|
wprintf(L"* MiscValid : 0x%01x\n", (ULONG) pMCAException->u.Mca.Status.MciStats.MiscValid);
|
|
wprintf(L"* Enabled : 0x%01x\n", (ULONG) pMCAException->u.Mca.Status.MciStats.Enabled);
|
|
wprintf(L"* UnCorrected : 0x%01x\n", (ULONG) pMCAException->u.Mca.Status.MciStats.UnCorrected);
|
|
wprintf(L"* OverFlow : 0x%01x\n", (ULONG) pMCAException->u.Mca.Status.MciStats.OverFlow);
|
|
wprintf(L"* Valid : 0x%01x\n", (ULONG) pMCAException->u.Mca.Status.MciStats.Valid);
|
|
wprintf(L"* Address \n");
|
|
wprintf(L"* Address : 0x%08x\n", (ULONG) pMCAException->u.Mca.Address.Address);
|
|
wprintf(L"* Reserved: 0x%08x\n", (ULONG) pMCAException->u.Mca.Address.Reserved);
|
|
wprintf(L"* Misc : 0x%016I64x\n", (ULONGLONG) pMCAException->u.Mca.Misc);
|
|
|
|
}
|
|
|
|
wprintf(L"* ExtCnt : 0x%08x\n", (ULONG) pMCAException->ExtCnt);
|
|
wprintf(L"* Reserved3 : 0x%08x\n", (ULONG) pMCAException->Reserved3);
|
|
|
|
for (int index = 0 ; index < MCA_EXTREG_V2MAX ; index++) {
|
|
|
|
wprintf(L"* ExtReg[%2d] : 0x%016I64x\n" , index, (ULONGLONG) pMCAException->ExtReg[index]);
|
|
|
|
}
|
|
|
|
wprintf(L"*********************************************\n\n");
|
|
}
|
|
|
|
#endif // _X86_
|
|
|
|
#if defined(_AMD64_)
|
|
|
|
VOID
|
|
MCAPrintErrorRecordAMD64(
|
|
PUCHAR PErrorData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function displays the machine check exception information on AMD64
|
|
systems to the standard output (console screen).
|
|
|
|
Arguments:
|
|
|
|
PErrorData - Buffer containing the machine check exception information.
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
PMCA_EXCEPTION pMCAException = NULL;
|
|
|
|
pMCAException = (PMCA_EXCEPTION)PErrorData;
|
|
|
|
wprintf(L"\n");
|
|
|
|
wprintf(L"*********************************************\n");
|
|
wprintf(L"* X86-64 MCA EXCEPTION *\n");
|
|
wprintf(L"*********************************************\n");
|
|
wprintf(L"* VersionNumber : 0x%08x\n", (ULONG) pMCAException->VersionNumber);
|
|
wprintf(L"* ExceptionType : 0x%08x\n", (INT) pMCAException->ExceptionType);
|
|
wprintf(L"* TimeStamp \n");
|
|
wprintf(L"* LowPart : 0x%08x\n", (ULONG) pMCAException->TimeStamp.LowPart);
|
|
wprintf(L"* HighPart: 0x%08x\n", (LONG) pMCAException->TimeStamp.HighPart);
|
|
wprintf(L"* ProcessorNumber : 0x%08x\n", (ULONG) pMCAException->ProcessorNumber);
|
|
wprintf(L"* Reserved1 : 0x%08x\n", (ULONG) pMCAException->Reserved1);
|
|
|
|
if (pMCAException->ExceptionType == HAL_MCE_RECORD) {
|
|
|
|
wprintf(L"* Mce \n");
|
|
|
|
wprintf(L"* Address : 0x%016I64x\n", (ULONGLONG) pMCAException->u.Mce.Address);
|
|
wprintf(L"* Type : 0x%016I64x\n", (ULONGLONG) pMCAException->u.Mce.Type);
|
|
|
|
} else {
|
|
|
|
wprintf(L"* Mca \n");
|
|
|
|
wprintf(L"* BankNumber : 0x%02x\n", (UCHAR) pMCAException->u.Mca.BankNumber);
|
|
|
|
for (int index = 0 ; index < 7 ; index++) {
|
|
|
|
wprintf(L"* Reserved2[%d]: 0x%02x\n", index, (UCHAR) pMCAException->u.Mca.Reserved2[index]);
|
|
|
|
}
|
|
|
|
wprintf(L"* MciStatus\n");
|
|
wprintf(L"* McaErrorCode : 0x%04x\n", (USHORT) pMCAException->u.Mca.Status.MciStatus.McaErrorCode);
|
|
wprintf(L"* ModelErrorCode : 0x%04x\n", (USHORT) pMCAException->u.Mca.Status.MciStatus.ModelErrorCode);
|
|
wprintf(L"* OtherInformation: 0x%01x\n", (ULONG) pMCAException->u.Mca.Status.MciStatus.OtherInformation);
|
|
wprintf(L"* ContextCorrupt : 0x%01x\n", (ULONG) pMCAException->u.Mca.Status.MciStatus.ContextCorrupt);
|
|
wprintf(L"* AddressValid : 0x%01x\n", (ULONG) pMCAException->u.Mca.Status.MciStatus.AddressValid);
|
|
wprintf(L"* MiscValid : 0x%01x\n", (ULONG) pMCAException->u.Mca.Status.MciStatus.MiscValid);
|
|
wprintf(L"* ErrorEnabled : 0x%01x\n", (ULONG) pMCAException->u.Mca.Status.MciStatus.ErrorEnabled);
|
|
wprintf(L"* UncorrectedError: 0x%01x\n", (ULONG) pMCAException->u.Mca.Status.MciStatus.UncorrectedError);
|
|
wprintf(L"* StatusOverFlow : 0x%01x\n", (ULONG) pMCAException->u.Mca.Status.MciStatus.StatusOverFlow);
|
|
wprintf(L"* Valid : 0x%01x\n", (ULONG) pMCAException->u.Mca.Status.MciStatus.Valid);
|
|
wprintf(L"* Address \n");
|
|
wprintf(L"* Address : 0x%08x\n", (ULONG) pMCAException->u.Mca.Address.Address);
|
|
wprintf(L"* Reserved: 0x%08x\n", (ULONG) pMCAException->u.Mca.Address.Reserved);
|
|
wprintf(L"* Misc : 0x%016I64x\n", (ULONGLONG) pMCAException->u.Mca.Misc);
|
|
|
|
}
|
|
|
|
wprintf(L"*********************************************\n\n");
|
|
}
|
|
|
|
#endif // _AMD64_
|
|
|
|
#if defined(_IA64_)
|
|
|
|
VOID
|
|
MCAPrintErrorRecordIA64(
|
|
PUCHAR PErrorData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function displays the headers of the provided MCA error
|
|
record on IA64 systems to the standard output (console screen).
|
|
The Error Record Header and Section Headers are displayed in
|
|
a formatted manner.
|
|
|
|
Arguments:
|
|
|
|
PErrorData - Buffer containing the MCA error record.
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
PERROR_RECORD_HEADER pErrorRecordHeader = NULL;
|
|
PERROR_SECTION_HEADER pErrorSectionHeader = NULL;
|
|
ULONG sectionOffset = 0;
|
|
INT sectionNumber = 0;
|
|
|
|
//
|
|
// The record header must be at the top of the record buffer.
|
|
//
|
|
pErrorRecordHeader = (PERROR_RECORD_HEADER)PErrorData;
|
|
|
|
wprintf(L"\n");
|
|
|
|
wprintf(L"***************************************************************************\n");
|
|
wprintf(L"* IA64 MCA ERROR *\n");
|
|
wprintf(L"***************************************************************************\n");
|
|
wprintf(L"* Error Record Header *\n");
|
|
wprintf(L"*-------------------------------------------------------------------------*\n");
|
|
wprintf(L"* ID : 0x%I64x\n", (ULONGLONG)pErrorRecordHeader->Id);
|
|
wprintf(L"* Revision : 0x%x\n" , (ULONG) pErrorRecordHeader->Revision.Revision);
|
|
wprintf(L"* Major : %x\n" , (ULONG) pErrorRecordHeader->Revision.Major);
|
|
wprintf(L"* Minor : %x\n" , (ULONG) pErrorRecordHeader->Revision.Minor);
|
|
wprintf(L"* Severity : 0x%x\n" , (ULONG) pErrorRecordHeader->ErrorSeverity);
|
|
wprintf(L"* Validity : 0x%x\n" , (ULONG) pErrorRecordHeader->Valid.Valid);
|
|
wprintf(L"* OEMPlatformID : %x\n", (ULONG) pErrorRecordHeader->Valid.OemPlatformID);
|
|
wprintf(L"* Length : 0x%x\n" , (ULONG) pErrorRecordHeader->Length);
|
|
wprintf(L"* TimeStamp : 0x%I64x\n", (ULONGLONG) pErrorRecordHeader->TimeStamp.TimeStamp);
|
|
wprintf(L"* Seconds : %x\n" , (ULONG) pErrorRecordHeader->TimeStamp.Seconds);
|
|
wprintf(L"* Minutes : %x\n" , (ULONG) pErrorRecordHeader->TimeStamp.Minutes);
|
|
wprintf(L"* Hours : %x\n" , (ULONG) pErrorRecordHeader->TimeStamp.Hours);
|
|
wprintf(L"* Day : %x\n" , (ULONG) pErrorRecordHeader->TimeStamp.Day);
|
|
wprintf(L"* Month : %x\n" , (ULONG) pErrorRecordHeader->TimeStamp.Month);
|
|
wprintf(L"* Year : %x\n" , (ULONG) pErrorRecordHeader->TimeStamp.Year);
|
|
wprintf(L"* Century : %x\n" , (ULONG) pErrorRecordHeader->TimeStamp.Century);
|
|
wprintf(L"* OEMPlatformID: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
|
|
(ULONG) pErrorRecordHeader->OemPlatformId[0],
|
|
(ULONG) pErrorRecordHeader->OemPlatformId[1],
|
|
(ULONG) pErrorRecordHeader->OemPlatformId[2],
|
|
(ULONG) pErrorRecordHeader->OemPlatformId[3],
|
|
(ULONG) pErrorRecordHeader->OemPlatformId[4],
|
|
(ULONG) pErrorRecordHeader->OemPlatformId[5],
|
|
(ULONG) pErrorRecordHeader->OemPlatformId[6],
|
|
(ULONG) pErrorRecordHeader->OemPlatformId[7],
|
|
(ULONG) pErrorRecordHeader->OemPlatformId[8],
|
|
(ULONG) pErrorRecordHeader->OemPlatformId[9],
|
|
(ULONG) pErrorRecordHeader->OemPlatformId[10],
|
|
(ULONG) pErrorRecordHeader->OemPlatformId[11],
|
|
(ULONG) pErrorRecordHeader->OemPlatformId[12],
|
|
(ULONG) pErrorRecordHeader->OemPlatformId[13],
|
|
(ULONG) pErrorRecordHeader->OemPlatformId[14],
|
|
(ULONG) pErrorRecordHeader->OemPlatformId[15]);
|
|
|
|
//
|
|
// Now display each of the section headers in the error record.
|
|
//
|
|
sectionOffset = sizeof(ERROR_RECORD_HEADER);
|
|
|
|
while (sectionOffset < pErrorRecordHeader->Length) {
|
|
|
|
pErrorSectionHeader = (PERROR_SECTION_HEADER)(PErrorData + sectionOffset);
|
|
|
|
wprintf(L"***************************************************************************\n");
|
|
wprintf(L"* Section Header *\n");
|
|
wprintf(L"***************************************************************************\n");
|
|
wprintf(L"* GUID: 0x%x, 0x%x, 0x%x, \n",
|
|
pErrorSectionHeader->Guid.Data1,
|
|
pErrorSectionHeader->Guid.Data2,
|
|
pErrorSectionHeader->Guid.Data3);
|
|
|
|
wprintf(L"* { 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x }\n",
|
|
pErrorSectionHeader->Guid.Data4[0],
|
|
pErrorSectionHeader->Guid.Data4[1],
|
|
pErrorSectionHeader->Guid.Data4[2],
|
|
pErrorSectionHeader->Guid.Data4[3],
|
|
pErrorSectionHeader->Guid.Data4[4],
|
|
pErrorSectionHeader->Guid.Data4[5],
|
|
pErrorSectionHeader->Guid.Data4[6],
|
|
pErrorSectionHeader->Guid.Data4[7]);
|
|
|
|
wprintf(L"* Revision: 0x%x\n", pErrorSectionHeader->Revision);
|
|
wprintf(L"* Major : %x\n" , (ULONG) pErrorSectionHeader->Revision.Major);
|
|
wprintf(L"* Minor : %x\n" , (ULONG) pErrorSectionHeader->Revision.Minor);
|
|
wprintf(L"* Recovery: 0x%x\n", (UCHAR)pErrorSectionHeader->RecoveryInfo.RecoveryInfo);
|
|
wprintf(L"* Reserved: 0x%x\n", (UCHAR)pErrorSectionHeader->Reserved);
|
|
wprintf(L"* Length : 0x%x\n", (ULONG)pErrorSectionHeader->Length);
|
|
|
|
sectionOffset += pErrorSectionHeader->Length;
|
|
|
|
sectionNumber++;
|
|
|
|
}
|
|
|
|
wprintf(L"***************************************************************************\n\n");
|
|
}
|
|
|
|
#endif // _IA64_
|