Unregister\r
};\r
\r
+/**\r
+ Event callback function to invoke status code handler in list.\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
+RscHandlerNotification (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ RSC_HANDLER_CALLBACK_ENTRY *CallbackEntry;\r
+ EFI_PHYSICAL_ADDRESS Address;\r
+ RSC_DATA_ENTRY *RscData;\r
+\r
+ CallbackEntry = (RSC_HANDLER_CALLBACK_ENTRY *) Context;\r
+\r
+ //\r
+ // Traverse the status code data buffer to parse all\r
+ // data to report.\r
+ //\r
+ Address = CallbackEntry->StatusCodeDataBuffer;\r
+ while (Address < CallbackEntry->EndPointer) {\r
+ RscData = (RSC_DATA_ENTRY *) (UINTN) Address;\r
+ CallbackEntry->RscHandlerCallback (\r
+ RscData->Type,\r
+ RscData->Value,\r
+ RscData->Instance,\r
+ &RscData->CallerId,\r
+ &RscData->Data\r
+ );\r
+\r
+ Address += (sizeof (RSC_DATA_ENTRY) + RscData->Data.Size);\r
+ Address = ALIGN_VARIABLE (Address);\r
+ }\r
+\r
+ CallbackEntry->EndPointer = CallbackEntry->StatusCodeDataBuffer;\r
+}\r
+\r
/**\r
Register the callback function for ReportStatusCode() notification.\r
\r
IN EFI_TPL Tpl\r
)\r
{\r
+ EFI_STATUS Status;\r
LIST_ENTRY *Link;\r
RSC_HANDLER_CALLBACK_ENTRY *CallbackEntry;\r
\r
}\r
}\r
\r
- CallbackEntry = AllocatePool (sizeof (RSC_HANDLER_CALLBACK_ENTRY));\r
+ CallbackEntry = AllocateZeroPool (sizeof (RSC_HANDLER_CALLBACK_ENTRY));\r
ASSERT (CallbackEntry != NULL);\r
\r
CallbackEntry->Signature = RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE;\r
CallbackEntry->RscHandlerCallback = Callback;\r
CallbackEntry->Tpl = Tpl;\r
\r
+ //\r
+ // If TPL of registered callback funtion is not TPL_HIGH_LEVEL, then event should be created\r
+ // for it, and related buffer for status code data should be prepared.\r
+ // Here the data buffer must be prepared in advance, because Report Status Code Protocol might\r
+ // be invoked under TPL_HIGH_LEVEL and no memory allocation is allowed then.\r
+ // If TPL is TPL_HIGH_LEVEL, then all status code will be reported immediately, without data\r
+ // buffer and event trigger.\r
+ //\r
+ if (Tpl != TPL_HIGH_LEVEL) {\r
+ CallbackEntry->StatusCodeDataBuffer = (EFI_PHYSICAL_ADDRESS) AllocatePool (EFI_PAGE_SIZE);\r
+ CallbackEntry->BufferSize = EFI_PAGE_SIZE;\r
+ CallbackEntry->EndPointer = CallbackEntry->StatusCodeDataBuffer;\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ Tpl,\r
+ RscHandlerNotification,\r
+ CallbackEntry,\r
+ &CallbackEntry->Event\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
InsertTailList (&mCallbackListHead, &CallbackEntry->Node);\r
\r
return EFI_SUCCESS;\r
//\r
// If the function is found in list, delete it and return.\r
//\r
+ if (CallbackEntry->Tpl != TPL_HIGH_LEVEL) {\r
+ FreePool ((VOID *) (UINTN) CallbackEntry->StatusCodeDataBuffer);\r
+ gBS->CloseEvent (CallbackEntry->Event);\r
+ }\r
RemoveEntryList (&CallbackEntry->Node);\r
FreePool (CallbackEntry);\r
return EFI_SUCCESS;\r
return EFI_NOT_FOUND;\r
}\r
\r
-/**\r
- Event callback function to invoke status code handler in list.\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
-RscHandlerNotification (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
- )\r
-{\r
- RSC_EVENT_CONTEXT *RscContext;\r
-\r
- RscContext = (RSC_EVENT_CONTEXT *) Context;\r
-\r
- RscContext->RscHandlerCallback (\r
- RscContext->Type,\r
- RscContext->Value,\r
- RscContext->Instance,\r
- RscContext->CallerId,\r
- RscContext->Data\r
- );\r
-}\r
-\r
/**\r
Provides an interface that a software module can call to report a status code.\r
\r
{\r
LIST_ENTRY *Link;\r
RSC_HANDLER_CALLBACK_ENTRY *CallbackEntry;\r
- RSC_EVENT_CONTEXT Context;\r
- EFI_EVENT Event;\r
+ RSC_DATA_ENTRY *RscData;\r
EFI_STATUS Status;\r
+ VOID *NewBuffer;\r
\r
//\r
// Use atom operation to avoid the reentant of report.\r
continue;\r
}\r
\r
- Context.RscHandlerCallback = CallbackEntry->RscHandlerCallback;\r
- Context.Type = Type;\r
- Context.Value = Value;\r
- Context.Instance = Instance;\r
- Context.CallerId = CallerId;\r
- Context.Data = Data;\r
+ //\r
+ // If callback is registered with TPL lower than TPL_HIGH_LEVEL, event must be signaled at boot time to possibly wait for\r
+ // allowed TPL to report status code. Related data should also be stored in data buffer.\r
+ //\r
+ CallbackEntry->EndPointer = ALIGN_VARIABLE (CallbackEntry->EndPointer);\r
+ RscData = (RSC_DATA_ENTRY *) (UINTN) CallbackEntry->EndPointer;\r
+ CallbackEntry->EndPointer += sizeof (RSC_DATA_ENTRY);\r
+ if (Data != NULL) {\r
+ CallbackEntry->EndPointer += Data->Size;\r
+ }\r
\r
- Status = gBS->CreateEvent (\r
- EVT_NOTIFY_SIGNAL,\r
- CallbackEntry->Tpl,\r
- RscHandlerNotification,\r
- &Context,\r
- &Event\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
+ //\r
+ // If data buffer is about to be used up (7/8 here), try to reallocate a buffer with double size, if not at TPL_HIGH_LEVEL.\r
+ //\r
+ if (CallbackEntry->EndPointer > (CallbackEntry->StatusCodeDataBuffer + (CallbackEntry->BufferSize / 8) * 7)) {\r
+ if (EfiGetCurrentTpl () < TPL_HIGH_LEVEL) {\r
+ NewBuffer = ReallocatePool (\r
+ CallbackEntry->BufferSize,\r
+ CallbackEntry->BufferSize * 2,\r
+ (VOID *) (UINTN) CallbackEntry->StatusCodeDataBuffer\r
+ );\r
+ if (NewBuffer != NULL) {\r
+ CallbackEntry->EndPointer = (EFI_PHYSICAL_ADDRESS) NewBuffer + (CallbackEntry->EndPointer - CallbackEntry->StatusCodeDataBuffer);\r
+ CallbackEntry->StatusCodeDataBuffer = (EFI_PHYSICAL_ADDRESS) NewBuffer;\r
+ CallbackEntry->BufferSize *= 2;\r
+ }\r
+ }\r
+ }\r
\r
- Status = gBS->SignalEvent (Event);\r
- ASSERT_EFI_ERROR (Status);\r
+ //\r
+ // If data buffer is used up, do not report for this time.\r
+ //\r
+ if (CallbackEntry->EndPointer > (CallbackEntry->StatusCodeDataBuffer + CallbackEntry->BufferSize)) {\r
+ continue;\r
+ }\r
+\r
+ RscData->Type = Type;\r
+ RscData->Value = Value;\r
+ RscData->Instance = Instance;\r
+ if (CallerId != NULL) {\r
+ CopyGuid (&RscData->CallerId, CallerId);\r
+ }\r
+ if (Data != NULL) {\r
+ CopyMem (&RscData->Data, Data, Data->HeaderSize + Data->Size);\r
+ }\r
\r
- Status = gBS->CloseEvent (Event);\r
+ Status = gBS->SignalEvent (CallbackEntry->Event);\r
ASSERT_EFI_ERROR (Status);\r
}\r
\r