git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10446 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			328 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			328 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Library that helps implement monolithic PEI
 | |
| 
 | |
|   Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
 | |
|   
 | |
|   This program and the accompanying materials
 | |
|   are licensed and made available under the terms and conditions of the BSD License
 | |
|   which accompanies this distribution.  The full text of the license may be found at
 | |
|   http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
|   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
|   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include <PrePi.h>
 | |
| #include <Library/ReportStatusCodeLib.h>
 | |
| #include <Library/SerialPortLib.h>
 | |
| #include <Library/PrintLib.h>
 | |
| 
 | |
| #include <Protocol/StatusCode.h>
 | |
| #include <Guid/StatusCodeDataTypeId.h>
 | |
| #include <Guid/StatusCodeDataTypeDebug.h>
 | |
| #include <FrameworkPei.h>
 | |
| 
 | |
| #define EFI_STATUS_CODE_DATA_MAX_SIZE 200
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| SerialReportStatusCode (
 | |
|   IN EFI_STATUS_CODE_TYPE             CodeType,
 | |
|   IN EFI_STATUS_CODE_VALUE            Value,
 | |
|   IN UINT32                           Instance,
 | |
|   IN CONST EFI_GUID                   *CallerId,
 | |
|   IN CONST EFI_STATUS_CODE_DATA       *Data OPTIONAL
 | |
|   );
 | |
| 
 | |
| 
 | |
| EFI_STATUS_CODE_PROTOCOL gStatusCode = { 
 | |
|   (EFI_REPORT_STATUS_CODE)SerialReportStatusCode 
 | |
| };
 | |
| 
 | |
| /**
 | |
|   Extracts ASSERT() information from a status code structure.
 | |
| 
 | |
|   Converts the status code specified by CodeType, Value, and Data to the ASSERT()
 | |
|   arguments specified by Filename, Description, and LineNumber.  If CodeType is
 | |
|   an EFI_ERROR_CODE, and CodeType has a severity of EFI_ERROR_UNRECOVERED, and
 | |
|   Value has an operation mask of EFI_SW_EC_ILLEGAL_SOFTWARE_STATE, extract
 | |
|   Filename, Description, and LineNumber from the optional data area of the
 | |
|   status code buffer specified by Data.  The optional data area of Data contains
 | |
|   a Null-terminated ASCII string for the FileName, followed by a Null-terminated
 | |
|   ASCII string for the Description, followed by a 32-bit LineNumber.  If the
 | |
|   ASSERT() information could be extracted from Data, then return TRUE.
 | |
|   Otherwise, FALSE is returned.
 | |
| 
 | |
|   If Data is NULL, then ASSERT().
 | |
|   If Filename is NULL, then ASSERT().
 | |
|   If Description is NULL, then ASSERT().
 | |
|   If LineNumber is NULL, then ASSERT().
 | |
| 
 | |
|   @param  CodeType     The type of status code being converted.
 | |
|   @param  Value        The status code value being converted.
 | |
|   @param  Data         Pointer to status code data buffer.
 | |
|   @param  Filename     Pointer to the source file name that generated the ASSERT().
 | |
|   @param  Description  Pointer to the description of the ASSERT().
 | |
|   @param  LineNumber   Pointer to source line number that generated the ASSERT().
 | |
| 
 | |
|   @retval  TRUE   The status code specified by CodeType, Value, and Data was
 | |
|                   converted ASSERT() arguments specified by Filename, Description,
 | |
|                   and LineNumber.
 | |
|   @retval  FALSE  The status code specified by CodeType, Value, and Data could
 | |
|                   not be converted to ASSERT() arguments.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| EFIAPI
 | |
| ReportStatusCodeExtractAssertInfo (
 | |
|   IN EFI_STATUS_CODE_TYPE        CodeType,
 | |
|   IN EFI_STATUS_CODE_VALUE       Value,
 | |
|   IN CONST EFI_STATUS_CODE_DATA  *Data,
 | |
|   OUT CHAR8                      **Filename,
 | |
|   OUT CHAR8                      **Description,
 | |
|   OUT UINT32                     *LineNumber
 | |
|   )
 | |
| {
 | |
|   EFI_DEBUG_ASSERT_DATA  *AssertData;
 | |
| 
 | |
|   ASSERT (Data        != NULL);
 | |
|   ASSERT (Filename    != NULL);
 | |
|   ASSERT (Description != NULL);
 | |
|   ASSERT (LineNumber  != NULL);
 | |
| 
 | |
|   if (((CodeType & EFI_STATUS_CODE_TYPE_MASK)      == EFI_ERROR_CODE) &&
 | |
|       ((CodeType & EFI_STATUS_CODE_SEVERITY_MASK)  == EFI_ERROR_UNRECOVERED) &&
 | |
|       ((Value    & EFI_STATUS_CODE_OPERATION_MASK) == EFI_SW_EC_ILLEGAL_SOFTWARE_STATE)) {
 | |
|     AssertData   = (EFI_DEBUG_ASSERT_DATA *)(Data + 1);
 | |
|     *Filename    = (CHAR8 *)(AssertData + 1);
 | |
|     *Description = *Filename + AsciiStrLen (*Filename) + 1;
 | |
|     *LineNumber  = AssertData->LineNumber;
 | |
|     return TRUE;
 | |
|   }
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Extracts DEBUG() information from a status code structure.
 | |
| 
 | |
|   Converts the status code specified by Data to the DEBUG() arguments specified
 | |
|   by ErrorLevel, Marker, and Format.  If type GUID in Data is
 | |
|   EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID, then extract ErrorLevel, Marker, and
 | |
|   Format from the optional data area of the status code buffer specified by Data.
 | |
|   The optional data area of Data contains a 32-bit ErrorLevel followed by Marker
 | |
|   which is 12 UINTN parameters, followed by a Null-terminated ASCII string for
 | |
|   the Format.  If the DEBUG() information could be extracted from Data, then
 | |
|   return TRUE.  Otherwise, FALSE is returned.
 | |
| 
 | |
|   If Data is NULL, then ASSERT().
 | |
|   If ErrorLevel is NULL, then ASSERT().
 | |
|   If Marker is NULL, then ASSERT().
 | |
|   If Format is NULL, then ASSERT().
 | |
| 
 | |
|   @param  Data        Pointer to status code data buffer.
 | |
|   @param  ErrorLevel  Pointer to error level mask for a debug message.
 | |
|   @param  Marker      Pointer to the variable argument list associated with Format.
 | |
|   @param  Format      Pointer to a Null-terminated ASCII format string of a
 | |
|                       debug message.
 | |
| 
 | |
|   @retval  TRUE   The status code specified by Data was converted DEBUG() arguments
 | |
|                   specified by ErrorLevel, Marker, and Format.
 | |
|   @retval  FALSE  The status code specified by Data could not be converted to
 | |
|                   DEBUG() arguments.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| EFIAPI
 | |
| ReportStatusCodeExtractDebugInfo (
 | |
|   IN CONST EFI_STATUS_CODE_DATA  *Data,
 | |
|   OUT UINT32                     *ErrorLevel,
 | |
|   OUT BASE_LIST                  *Marker,
 | |
|   OUT CHAR8                      **Format
 | |
|   )
 | |
| {
 | |
|   EFI_DEBUG_INFO  *DebugInfo;
 | |
| 
 | |
|   ASSERT (Data          != NULL);
 | |
|   ASSERT (ErrorLevel    != NULL);
 | |
|   ASSERT (Marker     != NULL);
 | |
|   ASSERT (Format     != NULL);
 | |
| 
 | |
|   //
 | |
|   // If the GUID type is not EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID then return FALSE
 | |
|   //
 | |
|   if (!CompareGuid (&Data->Type, &gEfiStatusCodeDataTypeDebugGuid)) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Retrieve the debug information from the status code record
 | |
|   //
 | |
|   DebugInfo = (EFI_DEBUG_INFO *)(Data + 1);
 | |
| 
 | |
|   *ErrorLevel = DebugInfo->ErrorLevel;
 | |
| 
 | |
|   //
 | |
|   // The first 12 * UINTN bytes of the string are really an
 | |
|   // argument stack to support varargs on the Format string.
 | |
|   //
 | |
|   *Marker = (BASE_LIST) (DebugInfo + 1);
 | |
|   *Format = (CHAR8 *)(((UINT64 *)*Marker) + 12);
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| SerialReportStatusCode (
 | |
|   IN EFI_STATUS_CODE_TYPE             CodeType,
 | |
|   IN EFI_STATUS_CODE_VALUE            Value,
 | |
|   IN UINT32                           Instance,
 | |
|   IN CONST EFI_GUID                   *CallerId,
 | |
|   IN CONST EFI_STATUS_CODE_DATA       *Data OPTIONAL
 | |
|   )
 | |
| {
 | |
|   CHAR8           *Filename;
 | |
|   CHAR8           *Description;
 | |
|   CHAR8           *Format;
 | |
|   CHAR8           Buffer[EFI_STATUS_CODE_DATA_MAX_SIZE];
 | |
|   UINT32          ErrorLevel;
 | |
|   UINT32          LineNumber;
 | |
|   UINTN           CharCount;
 | |
|   BASE_LIST       Marker;
 | |
|   EFI_DEBUG_INFO  *DebugInfo;
 | |
| 
 | |
|   Buffer[0] = '\0';
 | |
| 
 | |
| 
 | |
|   if (Data != NULL &&
 | |
|     ReportStatusCodeExtractAssertInfo (CodeType, Value, Data, &Filename, &Description, &LineNumber)) {
 | |
| 
 | |
|     //
 | |
|     // Print ASSERT() information into output buffer.
 | |
|     //
 | |
|     CharCount = AsciiSPrint (
 | |
|                   Buffer,
 | |
|                   EFI_STATUS_CODE_DATA_MAX_SIZE,
 | |
|                   "\n\rASSERT!: %a (%d): %a\n\r",
 | |
|                   Filename,
 | |
|                   LineNumber,
 | |
|                   Description
 | |
|                   );
 | |
| 
 | |
| 
 | |
|     //
 | |
|     // Callout to standard output.
 | |
|     //
 | |
|     SerialPortWrite ((UINT8 *)Buffer, CharCount);
 | |
|     return EFI_SUCCESS;
 | |
| 
 | |
|   } else if (Data != NULL &&
 | |
|     ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) {
 | |
|     
 | |
|     //
 | |
|     // Print DEBUG() information into output buffer.
 | |
|     //
 | |
|     CharCount = AsciiBSPrint (
 | |
|                   Buffer,
 | |
|                   EFI_STATUS_CODE_DATA_MAX_SIZE,
 | |
|                   Format,
 | |
|                   Marker
 | |
|                   );
 | |
| 
 | |
|   } else if (Data != NULL &&
 | |
|              CompareGuid (&Data->Type, &gEfiStatusCodeSpecificDataGuid) &&
 | |
|              (CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) {
 | |
| 
 | |
|     //
 | |
|     // Print specific data into output buffer.
 | |
|     //
 | |
|     DebugInfo = (EFI_DEBUG_INFO *) (Data + 1);
 | |
|     Marker    = (BASE_LIST) (DebugInfo + 1);
 | |
|     Format    = (CHAR8 *) (((UINT64 *) (DebugInfo + 1)) + 12);
 | |
| 
 | |
|     CharCount = AsciiBSPrint (Buffer, EFI_STATUS_CODE_DATA_MAX_SIZE, Format, Marker);
 | |
| 
 | |
|   } else if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) {
 | |
|     //
 | |
|     // Print ERROR information into output buffer.
 | |
|     //
 | |
| 
 | |
|     CharCount = AsciiSPrint (
 | |
|                   Buffer,
 | |
|                   EFI_STATUS_CODE_DATA_MAX_SIZE,
 | |
|                   "ERROR: C%x:V%x I%x",
 | |
|                   CodeType,
 | |
|                   Value,
 | |
|                   Instance
 | |
|                   );
 | |
| 
 | |
|     //
 | |
|     // Make sure we don't try to print values that weren't intended to be printed, especially NULL GUID pointers.
 | |
|     //
 | |
|     if (CallerId != NULL) {
 | |
|       CharCount += AsciiSPrint (
 | |
|                      &Buffer[CharCount - 1],
 | |
|                      (EFI_STATUS_CODE_DATA_MAX_SIZE - (sizeof (Buffer[0]) * CharCount)),
 | |
|                      " %g",
 | |
|                      CallerId
 | |
|                      );
 | |
|     }
 | |
| 
 | |
|     if (Data != NULL) {
 | |
|       CharCount += AsciiSPrint (
 | |
|                      &Buffer[CharCount - 1],
 | |
|                      (EFI_STATUS_CODE_DATA_MAX_SIZE - (sizeof (Buffer[0]) * CharCount)),
 | |
|                      " %x",
 | |
|                      Data
 | |
|                      );
 | |
| 
 | |
|     }
 | |
| 
 | |
| 
 | |
|     CharCount += AsciiSPrint (
 | |
|                    &Buffer[CharCount - 1],
 | |
|                    (EFI_STATUS_CODE_DATA_MAX_SIZE - (sizeof (Buffer[0]) * CharCount)),
 | |
|                    "\n\r"
 | |
|                    );
 | |
| 
 | |
|   } else if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) {
 | |
|     CharCount = AsciiSPrint (
 | |
|                   Buffer,
 | |
|                   EFI_STATUS_CODE_DATA_MAX_SIZE,
 | |
|                   "PROGRESS CODE: V%x I%x\n\r",
 | |
|                   Value,
 | |
|                   Instance
 | |
|                   );
 | |
|   } else {
 | |
|     CharCount = AsciiSPrint (
 | |
|                   Buffer,
 | |
|                   EFI_STATUS_CODE_DATA_MAX_SIZE,
 | |
|                   "Undefined: C%x:V%x I%x\n\r",
 | |
|                   CodeType,
 | |
|                   Value,
 | |
|                   Instance
 | |
|                   );
 | |
| 
 | |
|   }
 | |
| 
 | |
|   SerialPortWrite ((UINT8 *)Buffer, CharCount);
 | |
|   return EFI_SUCCESS;
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| VOID
 | |
| EFIAPI
 | |
| AddDxeCoreReportStatusCodeCallback (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   BuildGuidDataHob (&gEfiStatusCodeRuntimeProtocolGuid, &gStatusCode, sizeof(VOID *));
 | |
| }
 | |
| 
 |