--- /dev/null
+/** @file\r
+ Data Hub status code worker.\r
+\r
+ Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "DatahubStatusCodeHandlerDxe.h"\r
+\r
+//\r
+// Initialize FIFO to cache records.\r
+//\r
+LIST_ENTRY mRecordsFifo = INITIALIZE_LIST_HEAD_VARIABLE (mRecordsFifo);\r
+LIST_ENTRY mRecordsBuffer = INITIALIZE_LIST_HEAD_VARIABLE (mRecordsBuffer);\r
+UINT32 mLogDataHubStatus = 0;\r
+EFI_EVENT mLogDataHubEvent;\r
+//\r
+// Cache data hub protocol.\r
+//\r
+EFI_DATA_HUB_PROTOCOL *mDataHubProtocol = NULL;\r
+\r
+\r
+/**\r
+ Retrieve one record of from free record buffer. This record is removed from\r
+ free record buffer.\r
+\r
+ This function retrieves one record from free record buffer.\r
+ If the pool has been exhausted, then new memory would be allocated for it.\r
+\r
+ @return Pointer to the free record.\r
+ NULL means failure to allocate new memeory for free record buffer.\r
+\r
+**/\r
+DATA_HUB_STATUS_CODE_DATA_RECORD *\r
+AcquireRecordBuffer (\r
+ VOID\r
+ )\r
+{\r
+ DATAHUB_STATUSCODE_RECORD *Record;\r
+ EFI_TPL CurrentTpl;\r
+ LIST_ENTRY *Node;\r
+ UINT32 Index;\r
+\r
+ CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
+\r
+ if (!IsListEmpty (&mRecordsBuffer)) {\r
+ //\r
+ // Strip one entry from free record buffer.\r
+ //\r
+ Node = GetFirstNode (&mRecordsBuffer);\r
+ RemoveEntryList (Node);\r
+\r
+ Record = BASE_CR (Node, DATAHUB_STATUSCODE_RECORD, Node);\r
+ } else {\r
+ if (CurrentTpl > TPL_NOTIFY) {\r
+ //\r
+ // Memory management should work at <=TPL_NOTIFY\r
+ // \r
+ gBS->RestoreTPL (CurrentTpl);\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // If free record buffer is exhausted, then allocate 16 new records for it.\r
+ //\r
+ gBS->RestoreTPL (CurrentTpl);\r
+ Record = (DATAHUB_STATUSCODE_RECORD *) AllocateZeroPool (sizeof (DATAHUB_STATUSCODE_RECORD) * 16);\r
+ if (Record == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
+ //\r
+ // Here we only insert 15 new records to the free record buffer, for the first record\r
+ // will be returned immediately.\r
+ //\r
+ for (Index = 1; Index < 16; Index++) {\r
+ InsertTailList (&mRecordsBuffer, &Record[Index].Node);\r
+ }\r
+ }\r
+\r
+ Record->Signature = DATAHUB_STATUS_CODE_SIGNATURE;\r
+ InsertTailList (&mRecordsFifo, &Record->Node);\r
+\r
+ gBS->RestoreTPL (CurrentTpl);\r
+\r
+ return (DATA_HUB_STATUS_CODE_DATA_RECORD *) (Record->Data);\r
+}\r
+\r
+\r
+/**\r
+ Retrieve one record from Records FIFO. The record would be removed from FIFO.\r
+\r
+ @return Point to record, which is ready to be logged.\r
+ NULL means the FIFO of record is empty.\r
+\r
+**/\r
+DATA_HUB_STATUS_CODE_DATA_RECORD *\r
+RetrieveRecord (\r
+ VOID\r
+ )\r
+{\r
+ DATA_HUB_STATUS_CODE_DATA_RECORD *RecordData;\r
+ DATAHUB_STATUSCODE_RECORD *Record;\r
+ LIST_ENTRY *Node;\r
+ EFI_TPL CurrentTpl;\r
+\r
+ RecordData = NULL;\r
+\r
+ CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
+\r
+ if (!IsListEmpty (&mRecordsFifo)) {\r
+ Node = GetFirstNode (&mRecordsFifo);\r
+ Record = CR (Node, DATAHUB_STATUSCODE_RECORD, Node, DATAHUB_STATUS_CODE_SIGNATURE);\r
+ ASSERT (Record != NULL);\r
+\r
+ RemoveEntryList (&Record->Node);\r
+ RecordData = (DATA_HUB_STATUS_CODE_DATA_RECORD *) Record->Data;\r
+ }\r
+\r
+ gBS->RestoreTPL (CurrentTpl);\r
+\r
+ return RecordData;\r
+}\r
+\r
+/**\r
+ Release given record and return it to free record buffer.\r
+ \r
+ @param RecordData Pointer to the record to release.\r
+\r
+**/\r
+VOID\r
+ReleaseRecord (\r
+ DATA_HUB_STATUS_CODE_DATA_RECORD *RecordData\r
+ )\r
+{\r
+ DATAHUB_STATUSCODE_RECORD *Record;\r
+ EFI_TPL CurrentTpl;\r
+\r
+ Record = CR (RecordData, DATAHUB_STATUSCODE_RECORD, Data[0], DATAHUB_STATUS_CODE_SIGNATURE);\r
+ ASSERT (Record != NULL);\r
+\r
+ CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
+\r
+ InsertTailList (&mRecordsBuffer, &Record->Node);\r
+ Record->Signature = 0;\r
+\r
+ gBS->RestoreTPL (CurrentTpl);\r
+}\r
+\r
+/**\r
+ Report status code into DataHub.\r
+\r
+ @param CodeType Indicates the type of status code being reported.\r
+ @param Value Describes the current status of a hardware or software entity.\r
+ This included information about the class and subclass that is used to\r
+ classify the entity as well as an operation.\r
+ @param Instance The enumeration of a hardware or software entity within\r
+ the system. Valid instance numbers start with 1.\r
+ @param CallerId This optional parameter may be used to identify the caller.\r
+ This parameter allows the status code driver to apply different rules to\r
+ different callers.\r
+ @param Data This optional parameter may be used to pass additional data.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_DEVICE_ERROR Function is reentered.\r
+ @retval EFI_DEVICE_ERROR Function is called at runtime.\r
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate memory for free record buffer.\r
+\r
+**/\r
+EFI_STATUS\r
+DataHubStatusCodeReportWorker (\r
+ IN EFI_STATUS_CODE_TYPE CodeType,\r
+ IN EFI_STATUS_CODE_VALUE Value,\r
+ IN UINT32 Instance,\r
+ IN EFI_GUID *CallerId,\r
+ IN EFI_STATUS_CODE_DATA *Data OPTIONAL\r
+ )\r
+{\r
+ DATA_HUB_STATUS_CODE_DATA_RECORD *Record;\r
+ UINT32 ErrorLevel;\r
+ BASE_LIST Marker;\r
+ CHAR8 *Format;\r
+ UINTN CharCount;\r
+\r
+ //\r
+ // Use atom operation to avoid the reentant of report.\r
+ // If current status is not zero, then the function is reentrancy.\r
+ //\r
+ if (InterlockedCompareExchange32 (&mLogDataHubStatus, 0, 0) == 1) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Record = AcquireRecordBuffer ();\r
+ if (Record == NULL) {\r
+ //\r
+ // There are no empty record buffer in private buffers\r
+ //\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Construct Data Hub Extended Data\r
+ //\r
+ Record->CodeType = CodeType;\r
+ Record->Value = Value;\r
+ Record->Instance = Instance;\r
+\r
+ if (CallerId != NULL) {\r
+ CopyMem (&Record->CallerId, CallerId, sizeof (EFI_GUID));\r
+ }\r
+\r
+ if (Data != NULL) {\r
+ if (ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) {\r
+ CharCount = UnicodeBSPrintAsciiFormat (\r
+ (CHAR16 *) (Record + 1),\r
+ EFI_STATUS_CODE_DATA_MAX_SIZE,\r
+ Format,\r
+ Marker\r
+ );\r
+ //\r
+ // Change record data type to DebugType.\r
+ //\r
+ CopyGuid (&Record->Data.Type, &gEfiStatusCodeDataTypeDebugGuid);\r
+ Record->Data.HeaderSize = Data->HeaderSize;\r
+ Record->Data.Size = (UINT16) ((CharCount + 1) * sizeof (CHAR16));\r
+ } else {\r
+ //\r
+ // Copy status code data header\r
+ //\r
+ CopyMem (&Record->Data, Data, sizeof (EFI_STATUS_CODE_DATA));\r
+\r
+ if (Data->Size > EFI_STATUS_CODE_DATA_MAX_SIZE) {\r
+ Record->Data.Size = EFI_STATUS_CODE_DATA_MAX_SIZE;\r
+ }\r
+ CopyMem ((VOID *) (Record + 1), Data + 1, Record->Data.Size);\r
+ }\r
+ }\r
+\r
+ gBS->SignalEvent (mLogDataHubEvent);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ The Event handler which will be notified to log data in Data Hub.\r
+\r
+ @param Event Instance of the EFI_EVENT to signal whenever data is\r
+ available to be logged in the system.\r
+ @param Context Context of the event.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+LogDataHubEventCallBack (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ DATA_HUB_STATUS_CODE_DATA_RECORD *Record;\r
+ UINT32 Size;\r
+ UINT64 DataRecordClass;\r
+\r
+ //\r
+ // Use atom operation to avoid the reentant of report.\r
+ // If current status is not zero, then the function is reentrancy.\r
+ //\r
+ if (InterlockedCompareExchange32 (&mLogDataHubStatus, 0, 1) == 1) {\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Log DataRecord in Data Hub.\r
+ // Journal records fifo to find all record entry.\r
+ //\r
+ while (TRUE) {\r
+ //\r
+ // Retrieve record from record FIFO until no more record can be retrieved.\r
+ //\r
+ Record = RetrieveRecord ();\r
+ if (Record == NULL) {\r
+ break;\r
+ }\r
+ //\r
+ // Add in the size of the header we added.\r
+ //\r
+ Size = sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD) + (UINT32) Record->Data.Size;\r
+\r
+ if ((Record->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) {\r
+ DataRecordClass = EFI_DATA_RECORD_CLASS_PROGRESS_CODE;\r
+ } else if ((Record->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) {\r
+ DataRecordClass = EFI_DATA_RECORD_CLASS_ERROR;\r
+ } else if ((Record->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) {\r
+ DataRecordClass = EFI_DATA_RECORD_CLASS_DEBUG;\r
+ } else {\r
+ //\r
+ // Should never get here.\r
+ //\r
+ DataRecordClass = EFI_DATA_RECORD_CLASS_DEBUG |\r
+ EFI_DATA_RECORD_CLASS_ERROR |\r
+ EFI_DATA_RECORD_CLASS_DATA |\r
+ EFI_DATA_RECORD_CLASS_PROGRESS_CODE;\r
+ }\r
+\r
+ //\r
+ // Log DataRecord in Data Hub\r
+ //\r
+ mDataHubProtocol->LogData (\r
+ mDataHubProtocol,\r
+ &gEfiDataHubStatusCodeRecordGuid,\r
+ &gEfiStatusCodeRuntimeProtocolGuid,\r
+ DataRecordClass,\r
+ Record,\r
+ Size\r
+ );\r
+\r
+ ReleaseRecord (Record);\r
+ }\r
+\r
+ //\r
+ // Restore the nest status of report\r
+ //\r
+ InterlockedCompareExchange32 (&mLogDataHubStatus, 1, 0);\r
+}\r
+\r
+\r
+/**\r
+ Locate Data Hub Protocol and create event for logging data\r
+ as initialization for data hub status code worker.\r
+\r
+ @retval EFI_SUCCESS Initialization is successful.\r
+\r
+**/\r
+EFI_STATUS\r
+DataHubStatusCodeInitializeWorker (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiDataHubProtocolGuid, \r
+ NULL, \r
+ (VOID **) &mDataHubProtocol\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ mDataHubProtocol = NULL;\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Create a Notify Event to log data in Data Hub\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ LogDataHubEventCallBack,\r
+ NULL,\r
+ &mLogDataHubEvent\r
+ );\r
+\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
--- /dev/null
+/** @file\r
+ Status Code Handler Driver which produces datahub handler and hook it\r
+ onto the DXE status code router.\r
+\r
+ Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "DatahubStatusCodeHandlerDxe.h"\r
+\r
+EFI_EVENT mExitBootServicesEvent = NULL;\r
+EFI_RSC_HANDLER_PROTOCOL *mRscHandlerProtocol = NULL;\r
+\r
+/**\r
+ Unregister status code callback functions only available at boot time from\r
+ report status code router when exiting boot services.\r
+\r
+ @param Event Event whose notification function is being invoked.\r
+ @param Context Pointer to the notification function's context, which is\r
+ always zero in current implementation.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+UnregisterBootTimeHandlers (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ mRscHandlerProtocol->Unregister (DataHubStatusCodeReportWorker);\r
+}\r
+\r
+/**\r
+ Entry point of DXE Status Code Driver.\r
+\r
+ This function is the entry point of this DXE Status Code Driver.\r
+ It initializes registers status code handlers, and registers event for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.\r
+\r
+ @param ImageHandle The firmware allocated handle for the EFI image.\r
+ @param SystemTable A pointer to the EFI System Table.\r
+ \r
+ @retval EFI_SUCCESS The entry point is executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DatahubStatusCodeHandlerDxeEntry (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if (FeaturePcdGet (PcdStatusCodeUseDataHub)) {\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiRscHandlerProtocolGuid,\r
+ NULL,\r
+ (VOID **) &mRscHandlerProtocol\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Dispatch initialization request to supported devices\r
+ //\r
+ DataHubStatusCodeInitializeWorker ();\r
+\r
+ mRscHandlerProtocol->Register (DataHubStatusCodeReportWorker, TPL_HIGH_LEVEL);\r
+\r
+ Status = gBS->CreateEventEx (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ UnregisterBootTimeHandlers,\r
+ NULL,\r
+ &gEfiEventExitBootServicesGuid,\r
+ &mExitBootServicesEvent\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file\r
+ Internal include file for Datahub Status Code Handler Driver.\r
+\r
+ Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __DATAHUB_STATUS_CODE_HANDLER_DXE_H__\r
+#define __DATAHUB_STATUS_CODE_HANDLER_DXE_H__\r
+\r
+#include <Protocol/ReportStatusCodeHandler.h>\r
+#include <Protocol/DataHub.h>\r
+#include <Protocol/StatusCode.h>\r
+\r
+#include <Guid/StatusCodeDataTypeId.h>\r
+#include <Guid/StatusCodeDataTypeDebug.h>\r
+#include <Guid/DataHubStatusCodeRecord.h>\r
+#include <Guid/EventGroup.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/SynchronizationLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/ReportStatusCodeLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+//\r
+// Data hub worker definition\r
+//\r
+#define DATAHUB_STATUS_CODE_SIGNATURE SIGNATURE_32 ('B', 'D', 'H', 'S')\r
+\r
+typedef struct {\r
+ UINTN Signature;\r
+ LIST_ENTRY Node;\r
+ UINT8 Data[sizeof(DATA_HUB_STATUS_CODE_DATA_RECORD) + EFI_STATUS_CODE_DATA_MAX_SIZE];\r
+} DATAHUB_STATUSCODE_RECORD;\r
+\r
+/**\r
+ Report status code into DataHub.\r
+\r
+ @param CodeType Indicates the type of status code being reported.\r
+ @param Value Describes the current status of a hardware or software entity.\r
+ This included information about the class and subclass that is used to\r
+ classify the entity as well as an operation.\r
+ @param Instance The enumeration of a hardware or software entity within\r
+ the system. Valid instance numbers start with 1.\r
+ @param CallerId This optional parameter may be used to identify the caller.\r
+ This parameter allows the status code driver to apply different rules to\r
+ different callers.\r
+ @param Data This optional parameter may be used to pass additional data.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_DEVICE_ERROR Function is reentered.\r
+ @retval EFI_DEVICE_ERROR Function is called at runtime.\r
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate memory for free record buffer.\r
+\r
+**/\r
+EFI_STATUS\r
+DataHubStatusCodeReportWorker (\r
+ IN EFI_STATUS_CODE_TYPE CodeType,\r
+ IN EFI_STATUS_CODE_VALUE Value,\r
+ IN UINT32 Instance,\r
+ IN EFI_GUID *CallerId,\r
+ IN EFI_STATUS_CODE_DATA *Data OPTIONAL\r
+ );\r
+\r
+/**\r
+ Locate Data Hub Protocol and create event for logging data\r
+ as initialization for data hub status code worker.\r
+\r
+ @retval EFI_SUCCESS Initialization is successful.\r
+\r
+**/\r
+EFI_STATUS\r
+DataHubStatusCodeInitializeWorker (\r
+ VOID\r
+ );\r
+\r
+#endif\r