+/** @file\r
+ Data Hub status code worker in DXE.\r
+\r
+ Copyright (c) 2006, Intel Corporation\r
+ All rights reserved. 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
+ Module Name: DataHubStatusCodeWorker.c\r
+\r
+**/\r
+//\r
+// Include common header file for this module.\r
+//\r
+#include "CommonHeader.h"\r
+\r
+#include "DxeStatusCode.h"\r
+\r
+//\r
+// Initialize FIFO to cache records.\r
+//\r
+STATIC\r
+LIST_ENTRY mRecordsFifo = INITIALIZE_LIST_HEAD_VARIABLE (mRecordsFifo);\r
+STATIC\r
+LIST_ENTRY mRecordsBuffer = INITIALIZE_LIST_HEAD_VARIABLE (mRecordsBuffer);\r
+STATIC\r
+EFI_EVENT mLogDataHubEvent;\r
+//\r
+// Cache data hub protocol.\r
+//\r
+STATIC\r
+EFI_DATA_HUB_PROTOCOL *mDataHubProtocol;\r
+\r
+\r
+/**\r
+ Return one DATAHUB_STATUSCODE_RECORD space.\r
+ The size of free record pool would be extend, if the pool is empty.\r
+\r
+\r
+ @retval NULL Can not allocate free memeory for record.\r
+ @retval !NULL Point to buffer of record.\r
+\r
+**/\r
+STATIC\r
+DATAHUB_STATUSCODE_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
+ Node = GetFirstNode (&mRecordsBuffer);\r
+ RemoveEntryList (Node);\r
+\r
+ Record = _CR (Node, DATAHUB_STATUSCODE_RECORD, Node);\r
+ } else {\r
+ if (CurrentTpl > TPL_NOTIFY) {\r
+ gBS->RestoreTPL (CurrentTpl);\r
+ return NULL;\r
+ }\r
+\r
+ gBS->RestoreTPL (CurrentTpl);\r
+ Record = (DATAHUB_STATUSCODE_RECORD *) AllocateZeroPool (sizeof (DATAHUB_STATUSCODE_RECORD) * 16);\r
+ if (NULL == Record) {\r
+ return NULL;\r
+ }\r
+\r
+ CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\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 Record;\r
+}\r
+\r
+\r
+/**\r
+ Retrieve one record from Records FIFO. The record would be removed from FIFO and\r
+ release to free record buffer.\r
+\r
+ @return !NULL Point to record, which is ready to be logged.\r
+ @return NULL the FIFO of record is empty.\r
+\r
+**/\r
+STATIC\r
+DATAHUB_STATUSCODE_RECORD *\r
+RetrieveRecord (\r
+ VOID\r
+ )\r
+{\r
+ DATAHUB_STATUSCODE_RECORD *Record = NULL;\r
+ LIST_ENTRY *Node;\r
+ EFI_TPL CurrentTpl;\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
+\r
+ RemoveEntryList (&Record->Node);\r
+ InsertTailList (&mRecordsBuffer, &Record->Node);\r
+ Record->Signature = 0;\r
+ }\r
+\r
+ gBS->RestoreTPL (CurrentTpl);\r
+\r
+ return Record;\r
+}\r
+\r
+\r
+/**\r
+ Report status code into DataHub.\r
+\r
+ @param CodeType Indicates the type of status code being reported. Type EFI_STATUS_CODE_TYPE is defined in "Related Definitions" below.\r
+\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 classify the entity\r
+ as well as an operation. For progress codes, the operation is the current activity.\r
+ For error codes, it is the exception. For debug codes, it is not defined at this time.\r
+ Type EFI_STATUS_CODE_VALUE is defined in "Related Definitions" below.\r
+ Specific values are discussed in the Intel? Platform Innovation Framework for EFI Status Code Specification.\r
+\r
+ @param Instance The enumeration of a hardware or software entity within the system.\r
+ A system may contain multiple entities that match a class/subclass pairing.\r
+ The instance differentiates between them. An instance of 0 indicates that instance information is unavailable,\r
+ not meaningful, or not relevant. Valid instance numbers start with 1.\r
+\r
+\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 different callers.\r
+ Type EFI_GUID is defined in InstallProtocolInterface() in the EFI 1.10 Specification.\r
+\r
+\r
+ @param Data This optional parameter may be used to pass additional data\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Can not acquire record buffer.\r
+ @retval EFI_DEVICE_ERROR EFI serial device can not work after ExitBootService() is called .\r
+ @retval EFI_SUCCESS Success to cache status code and signal log data event.\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
+ DATAHUB_STATUSCODE_RECORD *Record;\r
+ UINT32 ErrorLevel;\r
+ VA_LIST Marker;\r
+ CHAR8 *Format;\r
+ UINTN CharCount;\r
+\r
+ //\r
+ // See whether in runtime phase or not.\r
+ //\r
+ if (EfiAtRuntime ()) {\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
+ // 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 = UnicodeVSPrintAsciiFormat (\r
+ (CHAR16 *) Record->ExtendData,\r
+ EFI_STATUS_CODE_DATA_MAX_SIZE,\r
+ Format,\r
+ Marker\r
+ );\r
+ //\r
+ // Change record data type from DebugType to String Type.\r
+ //\r
+ CopyGuid (&Record->Data.Type, &gEfiStatusCodeDataTypeStringGuid);\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 (Record->ExtendData, 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
+STATIC\r
+VOID\r
+EFIAPI\r
+LogDataHubEventCallBack (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ DATAHUB_STATUSCODE_RECORD *Record;\r
+ UINT32 Size;\r
+ UINT64 DataRecordClass;\r
+\r
+ //\r
+ // Log DataRecord in Data Hub.\r
+ // Journal records fifo to find all record entry.\r
+ //\r
+ while (1) {\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 (DATAHUB_STATUSCODE_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
+\r
+ mDataHubProtocol->LogData (\r
+ mDataHubProtocol,\r
+ &gEfiStatusCodeGuid,\r
+ &gEfiStatusCodeRuntimeProtocolGuid,\r
+ DataRecordClass,\r
+ Record,\r
+ Size\r
+ );\r
+\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Initialize data hubstatus code.\r
+ Create a data hub listener.\r
+\r
+ @return The function always return EFI_SUCCESS\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
+ ASSERT_EFI_ERROR (Status);\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