/*++ Module Name: MCALOG.C Abstract: Sample Application for logging errors for Machine Check Architecture Author: Anil Aggarwal (10/12/98) Intel Corporation Revision History: --*/ #include #include #include #include #include #include #include "imca.h" // // Variables for parsing command line arguments // extern int opterr; extern int optind; extern char *optarg; // // Print the usage information for MCA logging application // VOID McaUsage( PCHAR Name ) { fprintf(stderr,"Usage\n\t%s: [-s] [-a]\n",Name); fprintf(stderr,"\n\t-s: Read Machine Check registers now\n"); fprintf(stderr,"\n\t-a: Post asynchronous request for errors\n"); ExitProcess(1); } // // This routine prints the Machine Check registers // #if defined(_AMD64_) VOID McaPrintLog( PMCA_EXCEPTION McaException ) { if (McaException->ExceptionType != HAL_MCA_RECORD) { fprintf(stderr, "Bad exception record type\n"); //ExitProcess(1); } printf("Processor Number = %d\n", McaException->ProcessorNumber); printf("Bank Number = %d\n", McaException->u.Mca.BankNumber); printf("Mci_Status %I64X\n", McaException->u.Mca.Status.QuadPart); printf("Mci_Address %I64X\n", McaException->u.Mca.Address.QuadPart); printf("Mci_Misc %I64X\n", McaException->u.Mca.Misc); } // McaPrintLog() #endif // _AMD64_ #if defined(_X86_) VOID PrintX86McaLog( PMCA_EXCEPTION McaException ) { if (McaException->ExceptionType != HAL_MCA_RECORD) { fprintf(stderr, "Bad exception record type\n"); //ExitProcess(1); } printf("Processor Number = %d\n", McaException->ProcessorNumber); printf("Bank Number = %d\n", (__int64)McaException->u.Mca.BankNumber); printf("Mci_Status %I64X\n", (__int64)McaException->u.Mca.Status.QuadPart); printf("Mci_Address %I64X\n", (__int64)McaException->u.Mca.Address.QuadPart); printf("Mci_Misc %I64X\n", (__int64)McaException->u.Mca.Misc); } // PrintX86McaLog() #define McaPrintLog PrintX86McaLog #endif // _X86_ #if defined(_IA64_) #define ERROR_RECORD_HEADER_FORMAT \ "MCA Error Record Header\n" \ "\tId : 0x%I64x\n" \ "\tRevision : 0x%x\n" \ "\t\tMajor : %x\n" \ "\t\tMinor : %x\n" \ "\tSeverity : 0x%x\n" \ "\tValid : 0x%x\n" \ "\t\tPlatformId: %x\n" \ "\tLength : 0x%x\n" \ "\tTimeStamp : 0x%I64x\n" \ "\t\tSeconds: %x\n" \ "\t\tMinutes: %x\n" \ "\t\tHours : %x\n" \ "\t\tDay : %x\n" \ "\t\tMonth : %x\n" \ "\t\tYear : %x\n" \ "\t\tCentury: %x\n" \ "\tPlatformId: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n" VOID PrintIa64ErrorRecordHeader( PERROR_RECORD_HEADER Header ) { printf( ERROR_RECORD_HEADER_FORMAT, (ULONGLONG) Header->Id, (ULONG) Header->Revision.Revision, (ULONG) Header->Revision.Major, (ULONG) Header->Revision.Minor, (ULONG) Header->ErrorSeverity, (ULONG) Header->Valid.Valid, (ULONG) Header->Valid.OemPlatformID, (ULONG) Header->Length, (ULONGLONG) Header->TimeStamp.TimeStamp, (ULONG) Header->TimeStamp.Seconds, (ULONG) Header->TimeStamp.Minutes, (ULONG) Header->TimeStamp.Hours, (ULONG) Header->TimeStamp.Day, (ULONG) Header->TimeStamp.Month, (ULONG) Header->TimeStamp.Year, (ULONG) Header->TimeStamp.Century, (ULONG) Header->OemPlatformId[0], (ULONG) Header->OemPlatformId[1], (ULONG) Header->OemPlatformId[2], (ULONG) Header->OemPlatformId[3], (ULONG) Header->OemPlatformId[4], (ULONG) Header->OemPlatformId[5], (ULONG) Header->OemPlatformId[6], (ULONG) Header->OemPlatformId[7], (ULONG) Header->OemPlatformId[8], (ULONG) Header->OemPlatformId[9], (ULONG) Header->OemPlatformId[10], (ULONG) Header->OemPlatformId[11], (ULONG) Header->OemPlatformId[12], (ULONG) Header->OemPlatformId[13], (ULONG) Header->OemPlatformId[14], (ULONG) Header->OemPlatformId[15] ); return; } // PrintIa64ErrorRecordHeader() VOID PrintIa64McaLog( PMCA_EXCEPTION McaException ) { // // Start by printing the record header. // PrintIa64ErrorRecordHeader( McaException ); // // Then print and/or process error device specific information here. // return; } // PrintIa64McaLog() #define McaPrintLog PrintIa64McaLog #endif // _IA64_ // // This routine prints a user friendly error message based on GetLastError() // VOID McaPrintError( VOID ) { LPVOID lpMsgBuf; DWORD Err = GetLastError(); if (FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, Err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &lpMsgBuf, 0, NULL )) { fprintf(stderr, "%s\n", lpMsgBuf); LocalFree( lpMsgBuf ); } else { fprintf(stderr, "%d\n", Err); } } // // Main entry point // int __cdecl main( int argc, char *argv[] ) { CHAR Option; BOOLEAN ReadBanks = FALSE; BOOLEAN PostAsyncRequest = FALSE; HANDLE McaDeviceHandle; HANDLE LogEvent; OVERLAPPED Overlap; BOOL ReturnStatus; DWORD ActualCount; DWORD WaitStatus; DWORD NumberOfBytes; MCA_EXCEPTION McaException; LONG i; // // Process the command line arguments // for (i=1; i < argc; i++) { if (!((argv[i][0] == '-') || (argv[i][2] != 0)) ) { McaUsage(argv[0]); } Option = argv[i][1]; switch (Option) { case 's': ReadBanks = TRUE; break; case 'a': PostAsyncRequest = TRUE; break; default: McaUsage(argv[0]); } } if ((ReadBanks != TRUE) && (PostAsyncRequest != TRUE)) { fprintf(stderr, "One of -s and -a options must be specified\n"); ExitProcess(1); } if ((ReadBanks == TRUE) && (PostAsyncRequest == TRUE)) { fprintf(stderr, "Only one of -s and -a options can be specified\n"); ExitProcess(1); } // // Open MCA device with overlap flag set // McaDeviceHandle = CreateFile( MCA_DEVICE_NAME_WIN32, GENERIC_READ|GENERIC_WRITE, 0, (LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, (HANDLE)NULL ); if (McaDeviceHandle == INVALID_HANDLE_VALUE) { fprintf(stderr, "%s: Error 0x%lx opening MCA device\n", argv[0], GetLastError()); ExitProcess(1); } if (ReadBanks == TRUE) { // // Read the error logs on all banks on all procs. // IOCTL_READ_BANKS will read only one error at a time. So // we need to keep issuing this ioctl till all the errors are read // do { ReturnStatus = DeviceIoControl( McaDeviceHandle, (ULONG)IOCTL_READ_BANKS, NULL, 0, &McaException, sizeof(MCA_EXCEPTION), &ActualCount, NULL ); if (ReturnStatus == 0) { // // Some error has occurred. Either there are no more machine // check errors present or the processor does not have // support for Intel Machine Check Architecture // if (GetLastError() == ERROR_NOT_FOUND) { fprintf(stderr, "No Machine Check errors present\n"); } else if (GetLastError() == ERROR_FILE_NOT_FOUND) { fprintf(stderr, "Intel Machine Check support not available\n"); ExitProcess(1); } else { fprintf(stderr, "%s: Error 0x%lx in DeviceIoControl\n", argv[0], GetLastError()); ExitProcess(1); } } else { // // Successfully read the error. Print it. // McaPrintLog(&McaException); } } while (ReturnStatus != 0); // // We are done // return 1; } // // If we are here, we are supposed to post asynchronous calls to MCA driver // // // Set up structures for asynchronous call for reading the log // Create the event object // LogEvent = CreateEvent( NULL, // No Security Attributes FALSE, // Auto Reset Event FALSE, // Initial State = non-signaled NULL // Unnamed object ); if (LogEvent == NULL) { fprintf(stderr, "%s: Error 0x%lx creating event\n", argv[0], GetLastError()); ExitProcess(1); } // // Initialize the overlap structure // Overlap.hEvent = LogEvent; // Specify event for overlapped object Overlap.Offset = 0; // Offset is zero for devices Overlap.OffsetHigh = 0; // OffsetHigh is zero for devices ReturnStatus = DeviceIoControl( McaDeviceHandle, (ULONG)IOCTL_READ_BANKS_ASYNC, NULL, 0, &McaException, sizeof(MCA_EXCEPTION), &ActualCount, &Overlap ); if ((ReturnStatus == 0) && (GetLastError() != ERROR_IO_PENDING)) { fprintf(stderr, "%s: Error 0x%lx in IOCTL_READ_BANKS_ASYNC\n", argv[0], GetLastError()); ExitProcess(1); } // // Either Ioctl was successful or IO is currently pending // If successful then display the log else wait for specified interval // if (ReturnStatus == TRUE) { // // Read log async returned succesfully. Display it // McaPrintLog(&McaException); } // // Wait forever to get an error // WaitStatus = WaitForSingleObject( LogEvent, INFINITE ); if (WaitStatus == WAIT_OBJECT_0) { // // The state of the event object is signalled // check if the I/O operation was successful // ReturnStatus = GetOverlappedResult( McaDeviceHandle, &Overlap, &NumberOfBytes, FALSE // Return immediately ); if (ReturnStatus == 0) { fprintf(stderr, "%s: Error 0x%lx in GetOverlappedResult\n", argv[0], GetLastError()); ExitProcess(1); } if (NumberOfBytes) { // // Print the results // McaPrintLog(&McaException); } else { // // Error as the I/O operation was signalled complete before // timeout but no data transferred // fprintf(stderr, "%s: No data from GetOverlappedResult\n", argv[0]); ExitProcess(1); } } else { // // We should not get any other return value // fprintf(stderr, "%s: Unexpected return value from WaitForSingleObject()\n", argv[0]); ExitProcess(1); } CloseHandle(McaDeviceHandle); return 1; }