mirror of https://github.com/acidanthera/audk.git
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
|
|
);
|
|
|
|
}
|