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:
@ -34,6 +34,49 @@ EFI_RSC_HANDLER_PROTOCOL mRscHandlerProtocol = {
|
|||||||
Unregister
|
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.
|
Register the callback function for ReportStatusCode() notification.
|
||||||
|
|
||||||
@ -69,6 +112,7 @@ Register (
|
|||||||
IN EFI_TPL Tpl
|
IN EFI_TPL Tpl
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
LIST_ENTRY *Link;
|
LIST_ENTRY *Link;
|
||||||
RSC_HANDLER_CALLBACK_ENTRY *CallbackEntry;
|
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);
|
ASSERT (CallbackEntry != NULL);
|
||||||
|
|
||||||
CallbackEntry->Signature = RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE;
|
CallbackEntry->Signature = RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE;
|
||||||
CallbackEntry->RscHandlerCallback = Callback;
|
CallbackEntry->RscHandlerCallback = Callback;
|
||||||
CallbackEntry->Tpl = Tpl;
|
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);
|
InsertTailList (&mCallbackListHead, &CallbackEntry->Node);
|
||||||
|
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
@ -131,6 +197,10 @@ Unregister (
|
|||||||
//
|
//
|
||||||
// If the function is found in list, delete it and return.
|
// 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);
|
RemoveEntryList (&CallbackEntry->Node);
|
||||||
FreePool (CallbackEntry);
|
FreePool (CallbackEntry);
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
@ -140,34 +210,6 @@ Unregister (
|
|||||||
return EFI_NOT_FOUND;
|
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.
|
Provides an interface that a software module can call to report a status code.
|
||||||
|
|
||||||
@ -198,9 +240,9 @@ ReportDispatcher (
|
|||||||
{
|
{
|
||||||
LIST_ENTRY *Link;
|
LIST_ENTRY *Link;
|
||||||
RSC_HANDLER_CALLBACK_ENTRY *CallbackEntry;
|
RSC_HANDLER_CALLBACK_ENTRY *CallbackEntry;
|
||||||
RSC_EVENT_CONTEXT Context;
|
RSC_DATA_ENTRY *RscData;
|
||||||
EFI_EVENT Event;
|
|
||||||
EFI_STATUS Status;
|
EFI_STATUS Status;
|
||||||
|
VOID *NewBuffer;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Use atom operation to avoid the reentant of report.
|
// Use atom operation to avoid the reentant of report.
|
||||||
@ -224,26 +266,53 @@ ReportDispatcher (
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Context.RscHandlerCallback = CallbackEntry->RscHandlerCallback;
|
//
|
||||||
Context.Type = Type;
|
// If callback is registered with TPL lower than TPL_HIGH_LEVEL, event must be signaled at boot time to possibly wait for
|
||||||
Context.Value = Value;
|
// allowed TPL to report status code. Related data should also be stored in data buffer.
|
||||||
Context.Instance = Instance;
|
//
|
||||||
Context.CallerId = CallerId;
|
CallbackEntry->EndPointer = ALIGN_VARIABLE (CallbackEntry->EndPointer);
|
||||||
Context.Data = Data;
|
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,
|
// 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.
|
||||||
CallbackEntry->Tpl,
|
//
|
||||||
RscHandlerNotification,
|
if (CallbackEntry->EndPointer > (CallbackEntry->StatusCodeDataBuffer + (CallbackEntry->BufferSize / 8) * 7)) {
|
||||||
&Context,
|
if (EfiGetCurrentTpl () < TPL_HIGH_LEVEL) {
|
||||||
&Event
|
NewBuffer = ReallocatePool (
|
||||||
);
|
CallbackEntry->BufferSize,
|
||||||
ASSERT_EFI_ERROR (Status);
|
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);
|
ASSERT_EFI_ERROR (Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,9 @@
|
|||||||
#include <Library/UefiDriverEntryPoint.h>
|
#include <Library/UefiDriverEntryPoint.h>
|
||||||
#include <Library/UefiBootServicesTableLib.h>
|
#include <Library/UefiBootServicesTableLib.h>
|
||||||
#include <Library/MemoryAllocationLib.h>
|
#include <Library/MemoryAllocationLib.h>
|
||||||
|
#include <Library/BaseMemoryLib.h>
|
||||||
#include <Library/UefiRuntimeLib.h>
|
#include <Library/UefiRuntimeLib.h>
|
||||||
|
#include "Library/UefiLib.h"
|
||||||
|
|
||||||
#define RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE SIGNATURE_32 ('r', 'h', 'c', 'e')
|
#define RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE SIGNATURE_32 ('r', 'h', 'c', 'e')
|
||||||
|
|
||||||
@ -37,17 +39,21 @@ typedef struct {
|
|||||||
UINTN Signature;
|
UINTN Signature;
|
||||||
EFI_RSC_HANDLER_CALLBACK RscHandlerCallback;
|
EFI_RSC_HANDLER_CALLBACK RscHandlerCallback;
|
||||||
EFI_TPL Tpl;
|
EFI_TPL Tpl;
|
||||||
|
EFI_EVENT Event;
|
||||||
|
EFI_PHYSICAL_ADDRESS StatusCodeDataBuffer;
|
||||||
|
UINTN BufferSize;
|
||||||
|
EFI_PHYSICAL_ADDRESS EndPointer;
|
||||||
LIST_ENTRY Node;
|
LIST_ENTRY Node;
|
||||||
} RSC_HANDLER_CALLBACK_ENTRY;
|
} RSC_HANDLER_CALLBACK_ENTRY;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
EFI_RSC_HANDLER_CALLBACK RscHandlerCallback;
|
EFI_STATUS_CODE_TYPE Type;
|
||||||
EFI_STATUS_CODE_TYPE Type;
|
EFI_STATUS_CODE_VALUE Value;
|
||||||
EFI_STATUS_CODE_VALUE Value;
|
UINT32 Instance;
|
||||||
UINT32 Instance;
|
UINT32 Reserved;
|
||||||
EFI_GUID *CallerId;
|
EFI_GUID CallerId;
|
||||||
EFI_STATUS_CODE_DATA *Data;
|
EFI_STATUS_CODE_DATA Data;
|
||||||
} RSC_EVENT_CONTEXT;
|
} RSC_DATA_ENTRY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Register the callback function for ReportStatusCode() notification.
|
Register the callback function for ReportStatusCode() notification.
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
[LibraryClasses]
|
[LibraryClasses]
|
||||||
UefiRuntimeLib
|
UefiRuntimeLib
|
||||||
MemoryAllocationLib
|
MemoryAllocationLib
|
||||||
|
BaseMemoryLib
|
||||||
UefiBootServicesTableLib
|
UefiBootServicesTableLib
|
||||||
UefiDriverEntryPoint
|
UefiDriverEntryPoint
|
||||||
HobLib
|
HobLib
|
||||||
@ -46,6 +47,7 @@
|
|||||||
DebugLib
|
DebugLib
|
||||||
BaseLib
|
BaseLib
|
||||||
SynchronizationLib
|
SynchronizationLib
|
||||||
|
UefiLib
|
||||||
|
|
||||||
[Guids]
|
[Guids]
|
||||||
gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
|
gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
|
||||||
|
Reference in New Issue
Block a user