/** @file
CapsuleRuntimeDxe - UEFI Capsule Runtime Driver
This DXE driver produces the UEFI Runtime Capsule services:
- UpdateCapsule
- QueryCapsuleCapabilities
It also registers VirtualAddressChange and ExitBootServices
notification events to transition runtime services properly.
Source: HR650X BIOS, CapsuleRuntimeDxe.efi (Index 0104)
Module GUID: (from AutoGen.c)
Build: DEBUG_VS2015 X64
File: CapsuleRuntimeDxe.efi.i64
MD5: 24e107efaaec61d3574c53c6a4e84b56
SHA256: 8a14945ce1115188ee9c525ecd703c467bae7d6a5a96788cf619959c3ae43b85
**/
#include "CapsuleRuntimeDxe.h"
//
// Global data - boot-time only references
//
EFI_HANDLE gImageHandle = NULL;
EFI_SYSTEM_TABLE *gST = NULL;
EFI_BOOT_SERVICES *gBS = NULL;
EFI_RUNTIME_SERVICES *gRT = NULL;
//
// Saved copies for runtime transition
// (BootServices_0 used by VirtualAddressChange to NULL out gBS)
//
EFI_BOOT_SERVICES *gBS_Runtime = NULL;
EFI_RUNTIME_SERVICES *gRT_Runtime = NULL;
//
// Capsule configuration globals
//
UINT64 gCapsuleMaxSize = 104857600; // 100 MB
UINT64 gCapsuleMaxSizeNonCapsule = 34603008; // 33 MB
UINT8 gCapsuleInRuntime = 0;
//
// Runtime services function table (obtained via gBS->LocateProtocol)
// and the protocol GUID.
//
STATIC VOID *mCapsuleRuntimeProtocol = NULL;
EFI_EVENT mVirtualAddressChangeEvent = NULL;
STATIC VOID *mHobList = NULL;
// EFI_GUID {0x...} for the capsule runtime protocol (placeholder)
// unk_3020 and unk_3030 are GUID structures used for GUID comparison
// unk_3070 is a GUID table used by capsule type detection
//
// Function prototypes (forward declarations for local functions)
//
EFI_STATUS
EFIAPI
CapsuleRuntimeDxeDriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
);
EFI_STATUS
EFIAPI
CapsuleUpdateCapsule (
IN EFI_CAPSULE_HEADER **CapsuleHeaderArray,
IN UINT64 CapsuleCount,
IN EFI_PHYSICAL_ADDRESS ScatterGatherList OPTIONAL
);
EFI_STATUS
EFIAPI
CapsuleQueryCapsuleCapabilities (
IN EFI_CAPSULE_HEADER **CapsuleHeaderArray,
IN UINT64 CapsuleCount,
OUT UINT64 *MaxCapsuleSize,
OUT EFI_STATUS *ResetType
);
BOOLEAN
EFIAPI
IsCapspaceGuidEqual (
IN EFI_GUID *Guid1,
IN EFI_GUID *Guid2
);
UINT64
ReadUnaligned64 (
IN UINT64 *Buffer
);
EFI_STATUS
EFIAPI
CheckCapsuleType (
IN EFI_CAPSULE_HEADER *CapsuleHeader
);
STATIC
EFI_STATUS
GetCapsuleRuntimeProtocol (
VOID
);
//
// -- 16 functions total --
//
/**
_ModuleEntryPoint - DXE driver entry point.
Initializes the UEFI Boot Services Table Library, Runtime Services Table
Library, and Runtime Library; installs the capsule runtime protocol and
registers the CapsuleUpdateCapsule / QueryCapsuleCapabilities runtime
services; registers VirtualAddressChange and ExitBootServices events.
@param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The entry point is executed successfully.
@retval other Some error occurs when executing this entry point.
**/
EFI_STATUS
EFIAPI
ModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
//
// Initialize UEFI Boot/Runtime Services Library state
// and register the capsule runtime protocol.
//
CapsuleRuntimeDxeDriverEntryPoint (ImageHandle, SystemTable);
//
// Install the capsule runtime protocol.
// NOTE: In the real source this is installed via UefiRuntimeProtocolLib
// or gBS->InstallMultipleProtocolInterfaces. Here we approximate the
// call that sets up gRT->UpdateCapsule / gRT->QueryCapsuleCapabilities.
//
// The decompiled code writes:
// RuntimeServices[112 / 8] = CapsuleUpdateCapsule; // offset 14
// RuntimeServices[120 / 8] = CapsuleQueryCapsuleCapabilities; // offset 15
//
gRT->UpdateCapsule = CapsuleUpdateCapsule;
gRT->QueryCapsuleCapabilities = CapsuleQueryCapsuleCapabilities;
gCapsuleMaxSize = 104857600;
gCapsuleMaxSizeNonCapsule = 34603008;
//
// Locate and install the capsule runtime protocol
// (equivalent to InstallMultipleProtocolInterfaces)
//
Status = gBS->InstallMultipleProtocolInterfaces (
&gImageHandle,
&gEfiCapsuleRuntimeProtocolGuid,
NULL,
NULL
);
if (EFI_ERROR (Status)) {
//
// Assert on failure (debug builds only)
//
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (FALSE);
CpuDeadLoop ();
}
return Status;
}
/**
CapsuleRuntimeDxeDriverEntryPoint (sub_1194)
Initializes global state: saves ImageHandle, SystemTable, BootServices,
RuntimeServices; creates VirtualAddressChange and ExitBootServices events;
initializes the HOB list pointer and registers runtime capsule events.
This corresponds to the UefiBootServicesTableLib, UefiRuntimeServicesTableLib,
and UefiRuntimeLib initialization sequence.
@param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The driver data was initialized successfully.
@retval other An error occurred during initialization.
**/
EFI_STATUS
EFIAPI
CapsuleRuntimeDxeDriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
//
// UefiBootServicesTableLib constructor
//
gImageHandle = ImageHandle;
ASSERT (gImageHandle != NULL);
gST = SystemTable;
ASSERT (gST != NULL);
gBS = SystemTable->BootServices;
ASSERT (gBS != NULL);
//
// UefiRuntimeServicesTableLib constructor
//
gRT = SystemTable->RuntimeServices;
ASSERT (gRT != NULL);
//
// Save copies for VirtualAddressChange event
//
gBS_Runtime = gBS;
gRT_Runtime = gRT;
//
// Create VirtualAddressChange event (TPL_NOTIFY, EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)
//
Status = gBS->CreateEvent (
EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
TPL_NOTIFY,
VirtualAddressChangeEvent,
NULL,
&mVirtualAddressChangeEvent
);
ASSERT_EFI_ERROR (Status);
//
// Create ExitBootServices event (TPL_CALLBACK, EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES)
//
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
ExitBootServicesEvent,
NULL,
&gEfiEventExitBootServicesGuid,
&mVirtualAddressChangeEvent
);
ASSERT_EFI_ERROR (Status);
//
// UefiRuntimeLib constructor: initialize HOB list and register runtime capsule event
//
if (gRT == NULL) {
ASSERT (gRT != NULL);
}
if (gBS == NULL) {
ASSERT (gBS != NULL);
}
//
// Create event for runtime capsule update notification
//
Status = gBS->CreateEvent (
EVT_NOTIFY_WAIT,
TPL_CALLBACK,
RuntimeCapsuleEvent,
NULL
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (FALSE);
}
//
// Create runtime event for capsule variable (EfiRuntimeServicesData)
//
Status = gBS->CreateEvent (
EVT_NOTIFY_WAIT,
TPL_CALLBACK,
CapsuleRuntimeVariableEvent,
NULL,
NULL,
&mCapsuleRuntimeProtocol
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (FALSE);
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (FALSE);
}
return Status;
}
// ---------------------------------------------------------------------------
// CapsuleUpdateCapsule (sub_14FC)
// ---------------------------------------------------------------------------
/**
The UpdateCapsule runtime service.
@param[in] CapsuleHeaderArray Virtual pointer to an array of virtual
pointers to the capsules being passed
into update capsule.
@param[in] CapsuleCount Number of pointers in the array.
@param[in] ScatterGatherList Physical pointer to a set of
EFI_CAPSULE_BLOCK_DESCRIPTOR that
describes the physical location of a
set of capsules.
@retval EFI_SUCCESS Valid capsule was passed.
@retval EFI_INVALID_PARAMETER CapsuleCount is 0.
@retval EFI_UNSUPPORTED Capsule type is not supported on
this platform.
@retval EFI_WRITE_PROTECTED The capsule is for runtime update
but the capsule runtime protocol is
not available.
**/
EFI_STATUS
EFIAPI
CapsuleUpdateCapsule (
IN EFI_CAPSULE_HEADER **CapsuleHeaderArray,
IN UINT64 CapsuleCount,
IN EFI_PHYSICAL_ADDRESS ScatterGatherList OPTIONAL
)
{
UINT64 Index;
EFI_STATUS Status;
UINT64 CheckIndex;
UINT64 ReturnValue;
if (CapsuleCount == 0) {
return EFI_INVALID_PARAMETER;
}
Index = 0;
for (Index = 0; Index < CapsuleCount; Index++) {
EFI_CAPSULE_HEADER *ThisCapsule = CapsuleHeaderArray[Index];
//
// Check capsule flags:
// CapsuleFlag bit 17 (0x20000) = POPULATE_SYSTEM_TABLE
// CapsuleFlag bit 18 (0x40000) = INITIATE_RESET
// Combined bit 17+18 (0x30000) mask
// Combined bit 18+19 (0x50000) mask
//
// If both bits 17 and 18 are clear (0x20000 check) or
// bit 18 is set and bit 17 is clear (0x40000 check), this
// capsule needs runtime protocol validation.
//
if (((ThisCapsule->Flags & 0x30000) == 0x20000) ||
((ThisCapsule->Flags & 0x50000) == 0x40000) ||
(IsCapspaceGuidEqual (ThisCapsule->CapsuleGuid, &gEfiCapsuleGuid) &&
(ThisCapsule->Flags & 0x20000) != 0)) {
//
// Populate system table capsule - break out and process below
//
break;
}
if ((ThisCapsule->Flags & 0x20000) == 0) {
//
// Not a populate-system-table capsule; capsule type check required
//
Status = CheckCapsuleType (ThisCapsule);
if (EFI_ERROR (Status)) {
return Status;
}
}
}
if (Index >= CapsuleCount) {
//
// All capsules processed, check if any need reset populate
//
if (CapsuleCount == 0) {
return EFI_SUCCESS;
}
CheckIndex = 0;
while ((CapsuleHeaderArray[CheckIndex]->Flags & 0x10000) != 0) {
CheckIndex++;
if (CheckIndex >= CapsuleCount) {
//
// All capsules have bit 16 set - need a reset capsule
//
ReturnValue = (UINT64)EFI_UNSUPPORTED;
if (ScatterGatherList != NULL) {
ReturnValue |= 1;
}
return ReturnValue;
}
}
//
// Found a capsule without bit 16 set
//
ReturnValue = (UINT64)EFI_INVALID_PARAMETER;
if (gCapsuleInRuntime) {
ReturnValue |= 6;
}
return ReturnValue;
}
//
// If we broke out above (populate system table capsule found),
// fall through to success path
//
return EFI_SUCCESS;
}
// ---------------------------------------------------------------------------
// CapsuleQueryCapsuleCapabilities (sub_1608)
// ---------------------------------------------------------------------------
/**
The QueryCapsuleCapabilities runtime service.
@param[in] CapsuleHeaderArray Virtual pointer to an array of virtual
pointers to the capsules being passed
into update capsule.
@param[in] CapsuleCount Number of pointers in the array.
@param[out] MaxCapsuleSize Returns the maximum size of the capsule
the platform supports.
@param[out] ResetType Returns the type of reset needed for the
capsule update. EFI_STATUS return of 0
means no reset needed. Non-zero means
reset required of the given type.
@retval EFI_SUCCESS Valid capsule was passed.
@retval EFI_INVALID_PARAMETER MaxCapsuleSize is NULL, or ResetType is NULL,
or CapsuleCount is 0.
@retval EFI_UNSUPPORTED Capsule type is not supported on this platform.
**/
EFI_STATUS
EFIAPI
CapsuleQueryCapsuleCapabilities (
IN EFI_CAPSULE_HEADER **CapsuleHeaderArray,
IN UINT64 CapsuleCount,
OUT UINT64 *MaxCapsuleSize,
OUT EFI_STATUS *ResetType
)
{
UINT64 Index;
EFI_STATUS Status;
UINT64 CheckIndex;
if (!CapsuleCount || !MaxCapsuleSize || !ResetType) {
return EFI_INVALID_PARAMETER;
}
for (Index = 0; Index < CapsuleCount; Index++) {
EFI_CAPSULE_HEADER *ThisCapsule = CapsuleHeaderArray[Index];
//
// Same capsule flag checks as UpdateCapsule
//
if (((ThisCapsule->Flags & 0x30000) == 0x20000) ||
((ThisCapsule->Flags & 0x50000) == 0x40000) ||
(IsCapspaceGuidEqual (ThisCapsule->CapsuleGuid, &gEfiCapsuleGuid) &&
(ThisCapsule->Flags & 0x20000) != 0)) {
break;
}
if ((ThisCapsule->Flags & 0x20000) == 0) {
Status = CheckCapsuleType (ThisCapsule);
if (EFI_ERROR (Status)) {
return Status;
}
}
}
if (Index >= CapsuleCount) {
CheckIndex = 0;
if (CapsuleCount > 0) {
while ((CapsuleHeaderArray[CheckIndex]->Flags & 0x10000) == 0) {
CheckIndex++;
if (CheckIndex >= CapsuleCount) {
goto SetOutput;
}
}
return EFI_UNSUPPORTED;
}
}
SetOutput:
*ResetType = 0;
*MaxCapsuleSize = gCapsuleMaxSizeNonCapsule;
return EFI_SUCCESS;
}
// ---------------------------------------------------------------------------
// IsCapspaceGuidEqual (sub_1710)
// ---------------------------------------------------------------------------
/**
Compares two EFI_GUIDs for equality using 64-bit unaligned reads.
@param[in] Guid1 Pointer to the first GUID.
@param[in] Guid2 Pointer to the second GUID.
@retval TRUE The GUIDs are equal.
@retval FALSE The GUIDs are not equal.
**/
BOOLEAN
EFIAPI
IsCapspaceGuidEqual (
IN EFI_GUID *Guid1,
IN EFI_GUID *Guid2
)
{
UINT64 Guid1Part1;
UINT64 Guid1Part2;
Guid1Part1 = ReadUnaligned64 ((UINT64 *)Guid1);
Guid2->Data1 = (UINT32)ReadUnaligned64 ((UINT64 *)Guid2);
Guid1Part2 = ReadUnaligned64 ((UINT64 *)Guid1 + 1);
Guid2->Data2 = (UINT16)ReadUnaligned64 ((UINT64 *)Guid2 + 1);
return (BOOLEAN)(Guid1Part1 == Guid2->Data1 && Guid1Part2 == Guid2->Data2);
}
// ---------------------------------------------------------------------------
// ReadUnaligned64 (sub_1778)
// ---------------------------------------------------------------------------
/**
Reads a 64-bit value from an unaligned address.
@param[in] Buffer Pointer to the unaligned 64-bit value.
@return The 64-bit value read from Buffer.
**/
UINT64
ReadUnaligned64 (
IN UINT64 *Buffer
)
{
ASSERT (Buffer != NULL);
return *Buffer;
}
// ---------------------------------------------------------------------------
// GetCapsuleRuntimeProtocol (sub_17A8)
// ---------------------------------------------------------------------------
/**
Retrieves the capsule runtime protocol interface.
Uses gBS->LocateProtocol to find the protocol. Caches the result.
@return Pointer to the capsule runtime protocol interface, or NULL
if not found or if we are not in boot services.
**/
STATIC
EFI_STATUS
GetCapsuleRuntimeProtocol (
VOID
)
{
EFI_STATUS Status;
if (mCapsuleRuntimeProtocol != NULL) {
return EFI_SUCCESS;
}
if (gBS_Runtime != NULL) {
UINTN HobSize;
//
// Check if HOB list has room (<= 16 bytes header)
//
HobSize = gBS->GetHobListSize ();
if (HobSize <= sizeof (EFI_HOB_GENERIC_HEADER)) {
Status = gBS->LocateProtocol (
&gEfiCapsuleRuntimeProtocolGuid,
NULL,
&mCapsuleRuntimeProtocol
);
if (EFI_ERROR (Status)) {
mCapsuleRuntimeProtocol = NULL;
}
return mCapsuleRuntimeProtocol;
}
}
return NULL;
}
// ---------------------------------------------------------------------------
// DebugAssert (sub_1830)
// ---------------------------------------------------------------------------
/**
Internal debug ASSERT primitive with port 0x70/0x71 CMOS debug level
filtering.
Reads the current debug level from CMOS (port 0x70 index 0x4B), clamps
to 0-3, then checks if the given error severity passes the debug mask.
If so, calls into the registered debug print function.
@param[in] ErrorLevel Error severity (EFI_D_* bitmask).
@param[in] Format Format string.
@param[in] ... Variable arguments.
**/
VOID
DebugAssertInternal (
IN UINT64 ErrorLevel,
IN CONST CHAR8 *Format,
...
)
{
VA_LIST VaList;
DEBUG_PRINT_FUNCTION DebugPrint;
UINT8 DebugLevel;
UINT64 ErrorMask;
DebugPrint = (DEBUG_PRINT_FUNCTION)GetCapsuleRuntimeProtocol ();
ErrorMask = 0;
if (DebugPrint != NULL) {
//
// Read debug level from CMOS
//
DebugLevel = IoRead8 (0x70);
IoWrite8 (0x70, (DebugLevel & 0x80) | 0x4B);
DebugLevel = IoRead8 (0x71);
if (DebugLevel > 3) {
DebugLevel = 3;
}
//
// Map debug level to severity mask
//
switch (DebugLevel) {
case 1:
ErrorMask = EFI_D_ERROR;
break;
case 2:
ErrorMask = EFI_D_INFO;
break;
case 3:
default:
ErrorMask = EFI_D_VERBOSE;
break;
}
if ((ErrorMask & ErrorLevel) != 0) {
VA_START (VaList, Format);
DebugPrint (ErrorLevel, Format, VaList);
VA_END (VaList);
}
}
}
// ---------------------------------------------------------------------------
// DebugPrint (sub_18B0)
// ---------------------------------------------------------------------------
/**
Debug print wrapper using the capsule runtime protocol.
@param[in] FileName Source file name string.
@param[in] LineNumber Line number in the source file.
@param[in] Format Format string.
@param[in] ... Variable arguments.
@return Status from the protocol print function, or EFI_UNSUPPORTED
if the protocol is not available.
**/
UINT64
DebugPrint (
IN UINT64 FileName,
IN UINT64 LineNumber,
IN UINT64 Format,
...
)
{
DEBUG_PRINT_FUNCTION DebugPrint;
DebugPrint = (DEBUG_PRINT_FUNCTION)GetCapsuleRuntimeProtocol ();
if (DebugPrint != NULL) {
return DebugPrint (FileName, LineNumber, Format);
}
return EFI_UNSUPPORTED;
}
// ---------------------------------------------------------------------------
// VirtualAddressChangeEvent (sub_18F0)
// ---------------------------------------------------------------------------
/**
Virtual Address Change event notification handler.
Sets the boot services pointer to NULL so that runtime code does not
accidentally call boot services after SetVirtualAddressMap.
@param[in] Event Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context.
**/
VOID
EFIAPI
VirtualAddressChangeEvent (
IN EFI_EVENT Event,
IN VOID *Context
)
{
gBS_Runtime = NULL;
}
// ---------------------------------------------------------------------------
// ExitBootServicesEvent (sub_18FC)
// ---------------------------------------------------------------------------
/**
Exit Boot Services event notification handler.
Frees the capsule runtime protocol reference so it cannot be used
after boot services are exited.
@param[in] Event Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context.
**/
VOID
EFIAPI
ExitBootServicesEvent (
IN EFI_EVENT Event,
IN VOID *Context
)
{
if (mCapsuleRuntimeProtocol != NULL) {
gRT_Runtime->FreePages (0, (UINTN)&mCapsuleRuntimeProtocol);
}
}
// ---------------------------------------------------------------------------
// GetHobList (sub_1924)
// ---------------------------------------------------------------------------
/**
Returns the pointer to the HOB list.
Locates the HOB list from the System Table configuration table using
the HOB list GUID. Caches the result.
@return Pointer to the HOB list.
**/
VOID *
GetHobList (
VOID
)
{
EFI_STATUS Status;
UINTN Index;
EFI_CONFIGURATION_TABLE *ConfigTable;
if (mHobList != NULL) {
return mHobList;
}
mHobList = NULL;
if (gST->NumberOfTableEntries > 0) {
ConfigTable = gST->ConfigurationTable;
for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
if (IsCapspaceGuidEqual (
(EFI_GUID *)&gEfiHobListGuid,
(EFI_GUID *)((UINT8 *)ConfigTable + Index * sizeof (EFI_CONFIGURATION_TABLE))
)) {
mHobList = (VOID *)ConfigTable[Index].VendorTable;
break;
}
}
}
if (mHobList == NULL) {
Status = EFI_NOT_FOUND;
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (FALSE);
}
if (mHobList == NULL) {
DEBUG ((EFI_D_ERROR, "mHobList != ((void *) 0)\n"));
ASSERT (mHobList != NULL);
}
return mHobList;
}
// ---------------------------------------------------------------------------
// CheckCapsuleType (sub_1A04)
// ---------------------------------------------------------------------------
/**
Determines whether a capsule is of a recognized type by comparing its
GUID against a known table.
@param[in] CapsuleHeader Pointer to the capsule header to check.
@retval EFI_SUCCESS The capsule type is recognized.
@retval EFI_UNSUPPORTED The capsule type is not recognized.
@retval EFI_INVALID_PARAMETER CapsuleHeader is NULL.
**/
EFI_STATUS
EFIAPI
CheckCapsuleType (
IN EFI_CAPSULE_HEADER *CapsuleHeader
)
{
UINT32 TableIndex;
UINT64 GuidIndex;
//
// First check against 2 known capsule GUIDs in the local table
//
for (TableIndex = 0; TableIndex < 2; TableIndex++) {
if (IsCapspaceGuidEqual (CapsuleHeader->CapsuleGuid, &mCapsuleGuidTable[TableIndex])) {
return EFI_SUCCESS;
}
}
//
// Then check against the extern capsule GUID list
//
if (&gExternCapsuleGuidList == NULL) {
return EFI_UNSUPPORTED;
}
GuidIndex = 0;
while (gExternCapsuleGuidList[GuidIndex] != NULL) {
if (IsCapspaceGuidEqual (gExternCapsuleGuidList[GuidIndex], CapsuleHeader->CapsuleGuid)) {
return EFI_SUCCESS;
}
GuidIndex++;
}
return EFI_UNSUPPORTED;
}
// ---------------------------------------------------------------------------
// RuntimeCapsuleEvent (sub_1A94)
// ---------------------------------------------------------------------------
/**
Runtime capsule event notification.
Used as a notification function for a wait event that is created
during driver entry.
@param[in] Event Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context.
**/
VOID
EFIAPI
RuntimeCapsuleEvent (
IN EFI_EVENT Event,
IN VOID *Context
)
{
gRT_Runtime->FreePages (0, (UINTN)&mCapsuleRuntimeProtocol);
}
// ---------------------------------------------------------------------------
// CapsuleRuntimeVariableEvent (sub_1A8C)
// ---------------------------------------------------------------------------
/**
Capsule runtime variable event notification handler.
Marks that we are now in runtime phase (ExitBootServices has been signaled).
@param[in] Event Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context.
**/
VOID
EFIAPI
CapsuleRuntimeVariableEvent (
IN EFI_EVENT Event,
IN VOID *Context
)
{
gCapsuleInRuntime = 1;
}
// ---------------------------------------------------------------------------
// AsmCpuid (sub_1020)
// ---------------------------------------------------------------------------
/**
Executes the CPUID instruction.
@param[in] Index The CPUID leaf (EAX input).
@param[out] Eax CPUID return value for EAX.
@param[out] Ebx CPUID return value for EBX.
@param[out] Ecx CPUID return value for ECX.
@param[out] Edx CPUID return value for EDX.
@return The CPUID Index (EAX).
**/
UINT64
AsmCpuid (
IN UINT32 Index,
OUT UINT32 *Eax OPTIONAL,
OUT UINT32 *Ebx OPTIONAL,
OUT UINT32 *Ecx OPTIONAL,
OUT UINT32 *Edx OPTIONAL
)
{
UINT64 RetValue;
RetValue = Index;
__asm {
mov eax, Index
cpuid
mov RetValue, rax
}
if (Ecx != NULL) {
*Ecx = _RCX;
}
if (Eax != NULL) {
*Eax = _RAX;
}
if (Ebx != NULL) {
*Ebx = _RBX;
}
if (Edx != NULL) {
*Edx = _RDX;
}
return RetValue;
}