git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			398 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			398 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*++
 | 
						|
 | 
						|
Copyright (c) 2006, Intel Corporation                                                         
 | 
						|
All rights reserved. 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.             
 | 
						|
 | 
						|
Module Name:
 | 
						|
 | 
						|
  BsDataHubStatusCode.c
 | 
						|
 | 
						|
Abstract:
 | 
						|
 | 
						|
  This implements a status code listener that logs status codes into the data
 | 
						|
  hub.  This is only active during non-runtime DXE.
 | 
						|
 | 
						|
--*/
 | 
						|
#include "BsDataHubStatusCode.h"
 | 
						|
 | 
						|
//
 | 
						|
// Globals only work at BootService Time. NOT at Runtime!
 | 
						|
//
 | 
						|
static EFI_DATA_HUB_PROTOCOL  *mDataHub;
 | 
						|
static LIST_ENTRY             mRecordBuffer;
 | 
						|
static INTN                   mRecordNum;
 | 
						|
static EFI_EVENT              mLogDataHubEvent;
 | 
						|
static EFI_LOCK               mStatusCodeReportLock;
 | 
						|
static BOOLEAN                mEventHandlerActive   = FALSE;
 | 
						|
 | 
						|
STATUS_CODE_RECORD_LIST *
 | 
						|
GetRecordBuffer (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Returned buffer of length BYTES_PER_RECORD
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  None
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  Entry in mRecordBuffer or NULL if non available
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  STATUS_CODE_RECORD_LIST *Buffer;
 | 
						|
 | 
						|
  gBS->AllocatePool (EfiBootServicesData, sizeof (STATUS_CODE_RECORD_LIST), (VOID **) &Buffer);
 | 
						|
  if (Buffer == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  ZeroMem (Buffer, sizeof (STATUS_CODE_RECORD_LIST));
 | 
						|
  Buffer->Signature = BS_DATA_HUB_STATUS_CODE_SIGNATURE;
 | 
						|
 | 
						|
  return Buffer;
 | 
						|
}
 | 
						|
 | 
						|
DATA_HUB_STATUS_CODE_DATA_RECORD *
 | 
						|
AquireEmptyRecordBuffer (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Allocate a mRecordBuffer entry in the form of a pointer.
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  None
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  Pointer to new buffer. NULL if none exist.
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  STATUS_CODE_RECORD_LIST *DataBuffer;
 | 
						|
 | 
						|
  if (mRecordNum < MAX_RECORD_NUM) {
 | 
						|
    DataBuffer = GetRecordBuffer ();
 | 
						|
    if (DataBuffer != NULL) {
 | 
						|
      EfiAcquireLock (&mStatusCodeReportLock);
 | 
						|
      InsertTailList (&mRecordBuffer, &DataBuffer->Link);
 | 
						|
      mRecordNum++;
 | 
						|
      EfiReleaseLock (&mStatusCodeReportLock);
 | 
						|
      return (DATA_HUB_STATUS_CODE_DATA_RECORD *) DataBuffer->RecordBuffer;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
ReleaseRecordBuffer (
 | 
						|
  IN  STATUS_CODE_RECORD_LIST  *RecordBuffer
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Release a mRecordBuffer entry allocated by AquireEmptyRecordBuffer ().
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  RecordBuffer          - Data to free
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS           - If DataRecord is valid
 | 
						|
  EFI_UNSUPPORTED       - The record list has empty
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  ASSERT (RecordBuffer != NULL);
 | 
						|
  if (mRecordNum <= 0) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  EfiAcquireLock (&mStatusCodeReportLock);
 | 
						|
  RemoveEntryList (&RecordBuffer->Link);
 | 
						|
  mRecordNum--;
 | 
						|
  EfiReleaseLock (&mStatusCodeReportLock);
 | 
						|
  gBS->FreePool (RecordBuffer);
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
BsDataHubReportStatusCode (
 | 
						|
  IN EFI_STATUS_CODE_TYPE     CodeType,
 | 
						|
  IN EFI_STATUS_CODE_VALUE    Value,
 | 
						|
  IN UINT32                   Instance,
 | 
						|
  IN EFI_GUID                 * CallerId,
 | 
						|
  IN EFI_STATUS_CODE_DATA     * Data OPTIONAL
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Boot service report status code listener.  This function logs the status code
 | 
						|
  into the data hub.
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  Same as ReportStatusCode (See Tiano Runtime Specification)
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  None
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  DATA_HUB_STATUS_CODE_DATA_RECORD  *DataHub;
 | 
						|
  UINT32                            ErrorLevel;
 | 
						|
  VA_LIST                           Marker;
 | 
						|
  CHAR8                             *Format;
 | 
						|
  UINTN                             Index;
 | 
						|
  CHAR16                            FormatBuffer[BYTES_PER_RECORD];
 | 
						|
 | 
						|
  if (EfiAtRuntime ()) {
 | 
						|
    //
 | 
						|
    // For now all we do is post code at runtime
 | 
						|
    //
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // If we had an error while in our event handler, then do nothing so
 | 
						|
  // that we don't get in an endless loop.
 | 
						|
  //
 | 
						|
  if (mEventHandlerActive) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  DataHub = (DATA_HUB_STATUS_CODE_DATA_RECORD *) AquireEmptyRecordBuffer ();
 | 
						|
  if (DataHub == NULL) {
 | 
						|
    //
 | 
						|
    // There are no empty record buffer in private buffers
 | 
						|
    //
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Construct Data Hub Extended Data
 | 
						|
  //
 | 
						|
  DataHub->CodeType = CodeType;
 | 
						|
  DataHub->Value    = Value;
 | 
						|
  DataHub->Instance = Instance;
 | 
						|
 | 
						|
  if (CallerId != NULL) {
 | 
						|
    CopyMem (&DataHub->CallerId, CallerId, sizeof (EFI_GUID));
 | 
						|
  } else {
 | 
						|
    ZeroMem (&DataHub->CallerId, sizeof (EFI_GUID));
 | 
						|
  }
 | 
						|
 | 
						|
  if (Data == NULL) {
 | 
						|
    ZeroMem (&DataHub->Data, sizeof (EFI_STATUS_CODE_DATA));
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // Copy generic Header
 | 
						|
    //
 | 
						|
    CopyMem (&DataHub->Data, Data, sizeof (EFI_STATUS_CODE_DATA));
 | 
						|
 | 
						|
    if (ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) {
 | 
						|
      //
 | 
						|
      // Convert Ascii Format string to Unicode.
 | 
						|
      //
 | 
						|
      for (Index = 0; Format[Index] != '\0' && Index < (BYTES_PER_RECORD - 1); Index += 1) {
 | 
						|
        FormatBuffer[Index] = (CHAR16) Format[Index];
 | 
						|
      }
 | 
						|
 | 
						|
      FormatBuffer[Index] = L'\0';
 | 
						|
 | 
						|
      //
 | 
						|
      // Put processed string into the buffer
 | 
						|
      //
 | 
						|
      Index = UnicodeVSPrint (
 | 
						|
                (CHAR16 *) (DataHub + 1),
 | 
						|
                BYTES_PER_RECORD - (sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD)),
 | 
						|
                FormatBuffer,
 | 
						|
                Marker
 | 
						|
                );
 | 
						|
 | 
						|
      //
 | 
						|
      // DATA_HUB_STATUS_CODE_DATA_RECORD followed by VSPrint String Buffer
 | 
						|
      //
 | 
						|
      DataHub->Data.Size = (UINT16) (Index * sizeof (CHAR16));
 | 
						|
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // Default behavior is to copy optional data
 | 
						|
      //
 | 
						|
      if (Data->Size > (BYTES_PER_RECORD - sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD))) {
 | 
						|
        DataHub->Data.Size = (UINT16) (BYTES_PER_RECORD - sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD));
 | 
						|
      }
 | 
						|
 | 
						|
      CopyMem (DataHub + 1, Data + 1, DataHub->Data.Size);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  gBS->SignalEvent (mLogDataHubEvent);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
LogDataHubEventHandler (
 | 
						|
  IN  EFI_EVENT     Event,
 | 
						|
  IN  VOID          *Context
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  The Event handler which will be notified to log data in Data Hub.
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  Event     -   Instance of the EFI_EVENT to signal whenever data is
 | 
						|
                available to be logged in the system.
 | 
						|
  Context   -   Context of the event.
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  None.
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS                        Status;
 | 
						|
  DATA_HUB_STATUS_CODE_DATA_RECORD  *DataRecord;
 | 
						|
  UINTN                             Size;
 | 
						|
  UINT64                            DataRecordClass;
 | 
						|
  LIST_ENTRY                        *Link;
 | 
						|
  STATUS_CODE_RECORD_LIST           *BufferEntry;
 | 
						|
 | 
						|
  //
 | 
						|
  // Set our global flag so we don't recurse if we get an error here.
 | 
						|
  //
 | 
						|
  mEventHandlerActive = TRUE;
 | 
						|
 | 
						|
  //
 | 
						|
  // Log DataRecord in Data Hub.
 | 
						|
  // If there are multiple DataRecords, Log all of them.
 | 
						|
  //
 | 
						|
  for (Link = mRecordBuffer.ForwardLink; Link != &mRecordBuffer;) {
 | 
						|
    BufferEntry = CR (Link, STATUS_CODE_RECORD_LIST, Link, BS_DATA_HUB_STATUS_CODE_SIGNATURE);
 | 
						|
    DataRecord  = (DATA_HUB_STATUS_CODE_DATA_RECORD *) (BufferEntry->RecordBuffer);
 | 
						|
    Link        = Link->ForwardLink;
 | 
						|
 | 
						|
    //
 | 
						|
    // Add in the size of the header we added.
 | 
						|
    //
 | 
						|
    Size = sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD) + DataRecord->Data.Size;
 | 
						|
 | 
						|
    if ((DataRecord->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) {
 | 
						|
      DataRecordClass = EFI_DATA_RECORD_CLASS_PROGRESS_CODE;
 | 
						|
    } else if ((DataRecord->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) {
 | 
						|
      DataRecordClass = EFI_DATA_RECORD_CLASS_ERROR;
 | 
						|
    } else if ((DataRecord->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) {
 | 
						|
      DataRecordClass = EFI_DATA_RECORD_CLASS_DEBUG;
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // Should never get here.
 | 
						|
      //
 | 
						|
      DataRecordClass = EFI_DATA_RECORD_CLASS_DEBUG |
 | 
						|
        EFI_DATA_RECORD_CLASS_ERROR |
 | 
						|
        EFI_DATA_RECORD_CLASS_DATA |
 | 
						|
        EFI_DATA_RECORD_CLASS_PROGRESS_CODE;
 | 
						|
    }
 | 
						|
 | 
						|
    if (((DataRecord->Instance & EFI_D_ERROR) != 0) &&
 | 
						|
        (((DataRecord->Instance & EFI_D_POOL) != 0) || ((DataRecord->Instance & EFI_D_PAGE) != 0))
 | 
						|
        ) {
 | 
						|
      //
 | 
						|
      // If memory error, do not call LogData ().
 | 
						|
      //
 | 
						|
      DebugPrint ((UINTN)-1, "Memory Error\n");
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // Log DataRecord in Data Hub
 | 
						|
      //
 | 
						|
      Status = mDataHub->LogData (
 | 
						|
                          mDataHub,
 | 
						|
                          &gEfiStatusCodeGuid,
 | 
						|
                          &gEfiStatusCodeRuntimeProtocolGuid,
 | 
						|
                          DataRecordClass,
 | 
						|
                          DataRecord,
 | 
						|
                          (UINT32) Size
 | 
						|
                          );
 | 
						|
    }
 | 
						|
 | 
						|
    ReleaseRecordBuffer (BufferEntry);
 | 
						|
  }
 | 
						|
 | 
						|
  mEventHandlerActive = FALSE;
 | 
						|
 | 
						|
  return ;
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
BsDataHubStatusCodeInitialize (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Install a data hub listener.
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT)
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS - Logging Hub protocol installed
 | 
						|
  Other       - No protocol installed, unload driver.
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  Status = gBS->LocateProtocol (&gEfiDataHubProtocolGuid, NULL, (VOID **) &mDataHub);
 | 
						|
  //
 | 
						|
  // Should never fail due to dependency grammer
 | 
						|
  //
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize FIFO
 | 
						|
  //
 | 
						|
  InitializeListHead (&mRecordBuffer);
 | 
						|
  mRecordNum = 0;
 | 
						|
 | 
						|
  EfiInitializeLock (&mStatusCodeReportLock, EFI_TPL_HIGH_LEVEL);
 | 
						|
 | 
						|
  //
 | 
						|
  // Create a Notify Event to log data in Data Hub
 | 
						|
  //
 | 
						|
  Status = gBS->CreateEvent (
 | 
						|
                  EFI_EVENT_NOTIFY_SIGNAL,
 | 
						|
                  EFI_TPL_CALLBACK,
 | 
						|
                  LogDataHubEventHandler,
 | 
						|
                  NULL,
 | 
						|
                  &mLogDataHubEvent
 | 
						|
                  );
 | 
						|
 | 
						|
}
 |