Files
edk2/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/DataHubStatusCodeWorker.c
T

391 lines
11 KiB
C
Raw Normal View History

2007-06-29 03:38:49 +00:00
/** @file
Data Hub status code worker.
2007-06-29 03:38:49 +00:00
Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
2010-04-23 16:28:26 +00:00
This program and the accompanying materials
2007-06-29 03:38:49 +00:00
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 "StatusCodeRuntimeDxe.h"
2007-06-29 03:38:49 +00:00
//
// Initialize FIFO to cache records.
//
LIST_ENTRY mRecordsFifo = INITIALIZE_LIST_HEAD_VARIABLE (mRecordsFifo);
LIST_ENTRY mRecordsBuffer = INITIALIZE_LIST_HEAD_VARIABLE (mRecordsBuffer);
UINT32 mLogDataHubStatus = 0;
2007-06-29 03:38:49 +00:00
EFI_EVENT mLogDataHubEvent;
//
// Cache data hub protocol.
//
EFI_DATA_HUB_PROTOCOL *mDataHubProtocol = NULL;
2007-06-29 03:38:49 +00:00
/**
Retrieve one record of from free record buffer. This record is removed from
free record buffer.
2007-06-29 03:38:49 +00:00
This function retrieves one record from free record buffer.
If the pool has been exhausted, then new memory would be allocated for it.
2007-06-29 03:38:49 +00:00
@return Pointer to the free record.
NULL means failure to allocate new memeory for free record buffer.
2007-06-29 03:38:49 +00:00
**/
2007-07-13 06:15:56 +00:00
DATA_HUB_STATUS_CODE_DATA_RECORD *
2007-06-29 03:38:49 +00:00
AcquireRecordBuffer (
VOID
)
{
DATAHUB_STATUSCODE_RECORD *Record;
EFI_TPL CurrentTpl;
LIST_ENTRY *Node;
UINT32 Index;
CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
if (!IsListEmpty (&mRecordsBuffer)) {
//
// Strip one entry from free record buffer.
//
2007-06-29 03:38:49 +00:00
Node = GetFirstNode (&mRecordsBuffer);
RemoveEntryList (Node);
Record = BASE_CR (Node, DATAHUB_STATUSCODE_RECORD, Node);
2007-06-29 03:38:49 +00:00
} else {
if (CurrentTpl > TPL_NOTIFY) {
//
// Memory management should work at <=TPL_NOTIFY
//
2007-06-29 03:38:49 +00:00
gBS->RestoreTPL (CurrentTpl);
return NULL;
}
//
// If free record buffer is exhausted, then allocate 16 new records for it.
//
2007-06-29 03:38:49 +00:00
gBS->RestoreTPL (CurrentTpl);
Record = (DATAHUB_STATUSCODE_RECORD *) AllocateZeroPool (sizeof (DATAHUB_STATUSCODE_RECORD) * 16);
if (Record == NULL) {
2007-06-29 03:38:49 +00:00
return NULL;
}
CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
//
// Here we only insert 15 new records to the free record buffer, for the first record
// will be returned immediately.
//
2007-06-29 03:38:49 +00:00
for (Index = 1; Index < 16; Index++) {
InsertTailList (&mRecordsBuffer, &Record[Index].Node);
}
}
Record->Signature = DATAHUB_STATUS_CODE_SIGNATURE;
InsertTailList (&mRecordsFifo, &Record->Node);
gBS->RestoreTPL (CurrentTpl);
2007-07-13 06:15:56 +00:00
return (DATA_HUB_STATUS_CODE_DATA_RECORD *) (Record->Data);
2007-06-29 03:38:49 +00:00
}
/**
Retrieve one record from Records FIFO. The record would be removed from FIFO.
2007-06-29 03:38:49 +00:00
@return Point to record, which is ready to be logged.
NULL means the FIFO of record is empty.
2007-06-29 03:38:49 +00:00
**/
2007-07-13 06:15:56 +00:00
DATA_HUB_STATUS_CODE_DATA_RECORD *
2007-06-29 03:38:49 +00:00
RetrieveRecord (
VOID
)
{
DATA_HUB_STATUS_CODE_DATA_RECORD *RecordData;
2007-07-13 06:15:56 +00:00
DATAHUB_STATUSCODE_RECORD *Record;
LIST_ENTRY *Node;
EFI_TPL CurrentTpl;
2007-06-29 03:38:49 +00:00
RecordData = NULL;
2007-06-29 03:38:49 +00:00
CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
if (!IsListEmpty (&mRecordsFifo)) {
Node = GetFirstNode (&mRecordsFifo);
Record = CR (Node, DATAHUB_STATUSCODE_RECORD, Node, DATAHUB_STATUS_CODE_SIGNATURE);
ASSERT (Record != NULL);
2007-06-29 03:38:49 +00:00
RemoveEntryList (&Record->Node);
2007-07-13 06:15:56 +00:00
RecordData = (DATA_HUB_STATUS_CODE_DATA_RECORD *) Record->Data;
2007-06-29 03:38:49 +00:00
}
gBS->RestoreTPL (CurrentTpl);
2007-07-13 06:15:56 +00:00
return RecordData;
2007-06-29 03:38:49 +00:00
}
/**
Release given record and return it to free record buffer.
@param RecordData Pointer to the record to release.
**/
VOID
ReleaseRecord (
DATA_HUB_STATUS_CODE_DATA_RECORD *RecordData
)
{
DATAHUB_STATUSCODE_RECORD *Record;
EFI_TPL CurrentTpl;
Record = CR (RecordData, DATAHUB_STATUSCODE_RECORD, Data[0], DATAHUB_STATUS_CODE_SIGNATURE);
ASSERT (Record != NULL);
CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
InsertTailList (&mRecordsBuffer, &Record->Node);
Record->Signature = 0;
gBS->RestoreTPL (CurrentTpl);
}
2007-06-29 03:38:49 +00:00
/**
Report status code into DataHub.
@param CodeType Indicates the type of status code being reported.
@param Value Describes the current status of a hardware or software entity.
This included information about the class and subclass that is used to
classify the entity as well as an operation.
@param Instance The enumeration of a hardware or software entity within
the system. Valid instance numbers start with 1.
@param CallerId This optional parameter may be used to identify the caller.
This parameter allows the status code driver to apply different rules to
different callers.
@param Data This optional parameter may be used to pass additional data.
2007-06-29 03:38:49 +00:00
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_DEVICE_ERROR Function is reentered.
@retval EFI_DEVICE_ERROR Function is called at runtime.
@retval EFI_OUT_OF_RESOURCES Fail to allocate memory for free record buffer.
2007-06-29 03:38:49 +00:00
**/
EFI_STATUS
DataHubStatusCodeReportWorker (
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
)
{
2007-07-13 06:15:56 +00:00
DATA_HUB_STATUS_CODE_DATA_RECORD *Record;
UINT32 ErrorLevel;
BASE_LIST Marker;
2007-07-13 06:15:56 +00:00
CHAR8 *Format;
UINTN CharCount;
EFI_STATUS Status;
2007-06-29 03:38:49 +00:00
//
// Use atom operation to avoid the reentant of report.
// If current status is not zero, then the function is reentrancy.
//
if (InterlockedCompareExchange32 (&mLogDataHubStatus, 0, 0) == 1) {
return EFI_DEVICE_ERROR;
}
2007-06-29 03:38:49 +00:00
//
// See whether in runtime phase or not.
//
if (EfiAtRuntime ()) {
return EFI_DEVICE_ERROR;
}
if (mDataHubProtocol == NULL) {
Status = DataHubStatusCodeInitializeWorker ();
if (EFI_ERROR (Status)) {
return Status;
}
}
2007-06-29 03:38:49 +00:00
Record = AcquireRecordBuffer ();
if (Record == NULL) {
//
// There are no empty record buffer in private buffers
//
return EFI_OUT_OF_RESOURCES;
}
2007-07-13 06:15:56 +00:00
2007-06-29 03:38:49 +00:00
//
// Construct Data Hub Extended Data
//
Record->CodeType = CodeType;
Record->Value = Value;
Record->Instance = Instance;
if (CallerId != NULL) {
CopyMem (&Record->CallerId, CallerId, sizeof (EFI_GUID));
}
if (Data != NULL) {
if (ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) {
CharCount = UnicodeBSPrintAsciiFormat (
2007-07-13 06:15:56 +00:00
(CHAR16 *) (Record + 1),
2007-06-29 03:38:49 +00:00
EFI_STATUS_CODE_DATA_MAX_SIZE,
Format,
Marker
);
//
// Change record data type to DebugType.
2007-06-29 03:38:49 +00:00
//
2007-07-13 06:15:56 +00:00
CopyGuid (&Record->Data.Type, &gEfiStatusCodeDataTypeDebugGuid);
2007-06-29 03:38:49 +00:00
Record->Data.HeaderSize = Data->HeaderSize;
Record->Data.Size = (UINT16) ((CharCount + 1) * sizeof (CHAR16));
} else {
//
// Copy status code data header
//
CopyMem (&Record->Data, Data, sizeof (EFI_STATUS_CODE_DATA));
if (Data->Size > EFI_STATUS_CODE_DATA_MAX_SIZE) {
Record->Data.Size = EFI_STATUS_CODE_DATA_MAX_SIZE;
}
2007-07-13 06:15:56 +00:00
CopyMem ((VOID *) (Record + 1), Data + 1, Record->Data.Size);
2007-06-29 03:38:49 +00:00
}
}
gBS->SignalEvent (mLogDataHubEvent);
return EFI_SUCCESS;
}
/**
The Event handler which will be notified to log data in Data Hub.
@param Event Instance of the EFI_EVENT to signal whenever data is
available to be logged in the system.
@param Context Context of the event.
**/
VOID
EFIAPI
LogDataHubEventCallBack (
IN EFI_EVENT Event,
IN VOID *Context
)
{
2007-07-13 06:15:56 +00:00
DATA_HUB_STATUS_CODE_DATA_RECORD *Record;
2007-06-29 03:38:49 +00:00
UINT32 Size;
UINT64 DataRecordClass;
//
// Use atom operation to avoid the reentant of report.
// If current status is not zero, then the function is reentrancy.
//
if (InterlockedCompareExchange32 (&mLogDataHubStatus, 0, 1) == 1) {
return;
}
2007-06-29 03:38:49 +00:00
//
// Log DataRecord in Data Hub.
// Journal records fifo to find all record entry.
//
while (TRUE) {
//
// Retrieve record from record FIFO until no more record can be retrieved.
//
2007-06-29 03:38:49 +00:00
Record = RetrieveRecord ();
if (Record == NULL) {
break;
}
//
// Add in the size of the header we added.
//
2007-07-13 06:15:56 +00:00
Size = sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD) + (UINT32) Record->Data.Size;
2007-06-29 03:38:49 +00:00
if ((Record->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) {
DataRecordClass = EFI_DATA_RECORD_CLASS_PROGRESS_CODE;
} else if ((Record->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) {
DataRecordClass = EFI_DATA_RECORD_CLASS_ERROR;
} else if ((Record->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;
}
//
// Log DataRecord in Data Hub
//
mDataHubProtocol->LogData (
mDataHubProtocol,
&gEfiDataHubStatusCodeRecordGuid,
2007-06-29 03:38:49 +00:00
&gEfiStatusCodeRuntimeProtocolGuid,
DataRecordClass,
Record,
Size
);
ReleaseRecord (Record);
2007-06-29 03:38:49 +00:00
}
//
// Restore the nest status of report
//
InterlockedCompareExchange32 (&mLogDataHubStatus, 1, 0);
2007-06-29 03:38:49 +00:00
}
/**
Locate Data Hub Protocol and create event for logging data
as initialization for data hub status code worker.
2007-06-29 03:38:49 +00:00
@retval EFI_SUCCESS Initialization is successful.
2007-06-29 03:38:49 +00:00
**/
EFI_STATUS
DataHubStatusCodeInitializeWorker (
VOID
)
{
EFI_STATUS Status;
Status = gBS->LocateProtocol (
&gEfiDataHubProtocolGuid,
NULL,
(VOID **) &mDataHubProtocol
);
if (EFI_ERROR (Status)) {
mDataHubProtocol = NULL;
return Status;
}
2007-06-29 03:38:49 +00:00
//
// Create a Notify Event to log data in Data Hub
//
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
LogDataHubEventCallBack,
NULL,
&mLogDataHubEvent
);
ASSERT_EFI_ERROR (Status);
return EFI_SUCCESS;
}