Fix the issue that callback function with TPL lower than TPL_HIGH_LEVEL cannot handle status code at TPL_HIGH_LEVEL.

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@9568 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
xli24 2009-12-16 04:50:57 +00:00
parent 8a1dc102d9
commit cfc2ba61e4
3 changed files with 132 additions and 55 deletions

View File

@ -34,6 +34,49 @@ EFI_RSC_HANDLER_PROTOCOL mRscHandlerProtocol = {
Unregister
};
/**
Event callback function to invoke status code handler in list.
@param Event Event whose notification function is being invoked.
@param Context Pointer to the notification function's context, which is
always zero in current implementation.
**/
VOID
EFIAPI
RscHandlerNotification (
IN EFI_EVENT Event,
IN VOID *Context
)
{
RSC_HANDLER_CALLBACK_ENTRY *CallbackEntry;
EFI_PHYSICAL_ADDRESS Address;
RSC_DATA_ENTRY *RscData;
CallbackEntry = (RSC_HANDLER_CALLBACK_ENTRY *) Context;
//
// Traverse the status code data buffer to parse all
// data to report.
//
Address = CallbackEntry->StatusCodeDataBuffer;
while (Address < CallbackEntry->EndPointer) {
RscData = (RSC_DATA_ENTRY *) (UINTN) Address;
CallbackEntry->RscHandlerCallback (
RscData->Type,
RscData->Value,
RscData->Instance,
&RscData->CallerId,
&RscData->Data
);
Address += (sizeof (RSC_DATA_ENTRY) + RscData->Data.Size);
Address = ALIGN_VARIABLE (Address);
}
CallbackEntry->EndPointer = CallbackEntry->StatusCodeDataBuffer;
}
/**
Register the callback function for ReportStatusCode() notification.
@ -69,6 +112,7 @@ Register (
IN EFI_TPL Tpl
)
{
EFI_STATUS Status;
LIST_ENTRY *Link;
RSC_HANDLER_CALLBACK_ENTRY *CallbackEntry;
@ -86,13 +130,35 @@ Register (
}
}
CallbackEntry = AllocatePool (sizeof (RSC_HANDLER_CALLBACK_ENTRY));
CallbackEntry = AllocateZeroPool (sizeof (RSC_HANDLER_CALLBACK_ENTRY));
ASSERT (CallbackEntry != NULL);
CallbackEntry->Signature = RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE;
CallbackEntry->RscHandlerCallback = Callback;
CallbackEntry->Tpl = Tpl;
//
// If TPL of registered callback funtion is not TPL_HIGH_LEVEL, then event should be created
// for it, and related buffer for status code data should be prepared.
// Here the data buffer must be prepared in advance, because Report Status Code Protocol might
// be invoked under TPL_HIGH_LEVEL and no memory allocation is allowed then.
// If TPL is TPL_HIGH_LEVEL, then all status code will be reported immediately, without data
// buffer and event trigger.
//
if (Tpl != TPL_HIGH_LEVEL) {
CallbackEntry->StatusCodeDataBuffer = (EFI_PHYSICAL_ADDRESS) AllocatePool (EFI_PAGE_SIZE);
CallbackEntry->BufferSize = EFI_PAGE_SIZE;
CallbackEntry->EndPointer = CallbackEntry->StatusCodeDataBuffer;
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
Tpl,
RscHandlerNotification,
CallbackEntry,
&CallbackEntry->Event
);
ASSERT_EFI_ERROR (Status);
}
InsertTailList (&mCallbackListHead, &CallbackEntry->Node);
return EFI_SUCCESS;
@ -131,6 +197,10 @@ Unregister (
//
// If the function is found in list, delete it and return.
//
if (CallbackEntry->Tpl != TPL_HIGH_LEVEL) {
FreePool ((VOID *) (UINTN) CallbackEntry->StatusCodeDataBuffer);
gBS->CloseEvent (CallbackEntry->Event);
}
RemoveEntryList (&CallbackEntry->Node);
FreePool (CallbackEntry);
return EFI_SUCCESS;
@ -140,34 +210,6 @@ Unregister (
return EFI_NOT_FOUND;
}
/**
Event callback function to invoke status code handler in list.
@param Event Event whose notification function is being invoked.
@param Context Pointer to the notification function's context, which is
always zero in current implementation.
**/
VOID
EFIAPI
RscHandlerNotification (
IN EFI_EVENT Event,
IN VOID *Context
)
{
RSC_EVENT_CONTEXT *RscContext;
RscContext = (RSC_EVENT_CONTEXT *) Context;
RscContext->RscHandlerCallback (
RscContext->Type,
RscContext->Value,
RscContext->Instance,
RscContext->CallerId,
RscContext->Data
);
}
/**
Provides an interface that a software module can call to report a status code.
@ -198,9 +240,9 @@ ReportDispatcher (
{
LIST_ENTRY *Link;
RSC_HANDLER_CALLBACK_ENTRY *CallbackEntry;
RSC_EVENT_CONTEXT Context;
EFI_EVENT Event;
RSC_DATA_ENTRY *RscData;
EFI_STATUS Status;
VOID *NewBuffer;
//
// Use atom operation to avoid the reentant of report.
@ -224,26 +266,53 @@ ReportDispatcher (
continue;
}
Context.RscHandlerCallback = CallbackEntry->RscHandlerCallback;
Context.Type = Type;
Context.Value = Value;
Context.Instance = Instance;
Context.CallerId = CallerId;
Context.Data = Data;
//
// If callback is registered with TPL lower than TPL_HIGH_LEVEL, event must be signaled at boot time to possibly wait for
// allowed TPL to report status code. Related data should also be stored in data buffer.
//
CallbackEntry->EndPointer = ALIGN_VARIABLE (CallbackEntry->EndPointer);
RscData = (RSC_DATA_ENTRY *) (UINTN) CallbackEntry->EndPointer;
CallbackEntry->EndPointer += sizeof (RSC_DATA_ENTRY);
if (Data != NULL) {
CallbackEntry->EndPointer += Data->Size;
}
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
CallbackEntry->Tpl,
RscHandlerNotification,
&Context,
&Event
);
ASSERT_EFI_ERROR (Status);
//
// 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.
//
if (CallbackEntry->EndPointer > (CallbackEntry->StatusCodeDataBuffer + (CallbackEntry->BufferSize / 8) * 7)) {
if (EfiGetCurrentTpl () < TPL_HIGH_LEVEL) {
NewBuffer = ReallocatePool (
CallbackEntry->BufferSize,
CallbackEntry->BufferSize * 2,
(VOID *) (UINTN) CallbackEntry->StatusCodeDataBuffer
);
if (NewBuffer != NULL) {
CallbackEntry->EndPointer = (EFI_PHYSICAL_ADDRESS) NewBuffer + (CallbackEntry->EndPointer - CallbackEntry->StatusCodeDataBuffer);
CallbackEntry->StatusCodeDataBuffer = (EFI_PHYSICAL_ADDRESS) NewBuffer;
CallbackEntry->BufferSize *= 2;
}
}
}
Status = gBS->SignalEvent (Event);
ASSERT_EFI_ERROR (Status);
//
// If data buffer is used up, do not report for this time.
//
if (CallbackEntry->EndPointer > (CallbackEntry->StatusCodeDataBuffer + CallbackEntry->BufferSize)) {
continue;
}
Status = gBS->CloseEvent (Event);
RscData->Type = Type;
RscData->Value = Value;
RscData->Instance = Instance;
if (CallerId != NULL) {
CopyGuid (&RscData->CallerId, CallerId);
}
if (Data != NULL) {
CopyMem (&RscData->Data, Data, Data->HeaderSize + Data->Size);
}
Status = gBS->SignalEvent (CallbackEntry->Event);
ASSERT_EFI_ERROR (Status);
}

View File

@ -29,7 +29,9 @@
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiRuntimeLib.h>
#include "Library/UefiLib.h"
#define RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE SIGNATURE_32 ('r', 'h', 'c', 'e')
@ -37,17 +39,21 @@ typedef struct {
UINTN Signature;
EFI_RSC_HANDLER_CALLBACK RscHandlerCallback;
EFI_TPL Tpl;
EFI_EVENT Event;
EFI_PHYSICAL_ADDRESS StatusCodeDataBuffer;
UINTN BufferSize;
EFI_PHYSICAL_ADDRESS EndPointer;
LIST_ENTRY Node;
} RSC_HANDLER_CALLBACK_ENTRY;
typedef struct {
EFI_RSC_HANDLER_CALLBACK RscHandlerCallback;
EFI_STATUS_CODE_TYPE Type;
EFI_STATUS_CODE_VALUE Value;
UINT32 Instance;
EFI_GUID *CallerId;
EFI_STATUS_CODE_DATA *Data;
} RSC_EVENT_CONTEXT;
EFI_STATUS_CODE_TYPE Type;
EFI_STATUS_CODE_VALUE Value;
UINT32 Instance;
UINT32 Reserved;
EFI_GUID CallerId;
EFI_STATUS_CODE_DATA Data;
} RSC_DATA_ENTRY;
/**
Register the callback function for ReportStatusCode() notification.

View File

@ -39,6 +39,7 @@
[LibraryClasses]
UefiRuntimeLib
MemoryAllocationLib
BaseMemoryLib
UefiBootServicesTableLib
UefiDriverEntryPoint
HobLib
@ -46,6 +47,7 @@
DebugLib
BaseLib
SynchronizationLib
UefiLib
[Guids]
gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event