/** @file | |
This file deals with Architecture Protocol (AP) registration in | |
the Dxe Core. The mArchProtocols[] array represents a list of | |
events that represent the Architectural Protocols. | |
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "DxeMain.h" | |
// | |
// DXE Core Global Variables for all of the Architectural Protocols. | |
// If a protocol is installed mArchProtocols[].Present will be TRUE. | |
// | |
// CoreNotifyOnArchProtocolInstallation () fills in mArchProtocols[].Event | |
// and mArchProtocols[].Registration as it creates events for every array | |
// entry. | |
// | |
EFI_CORE_PROTOCOL_NOTIFY_ENTRY mArchProtocols[] = { | |
{ &gEfiSecurityArchProtocolGuid, (VOID **)&gSecurity, NULL, NULL, FALSE }, | |
{ &gEfiCpuArchProtocolGuid, (VOID **)&gCpu, NULL, NULL, FALSE }, | |
{ &gEfiMetronomeArchProtocolGuid, (VOID **)&gMetronome, NULL, NULL, FALSE }, | |
{ &gEfiTimerArchProtocolGuid, (VOID **)&gTimer, NULL, NULL, FALSE }, | |
{ &gEfiBdsArchProtocolGuid, (VOID **)&gBds, NULL, NULL, FALSE }, | |
{ &gEfiWatchdogTimerArchProtocolGuid, (VOID **)&gWatchdogTimer, NULL, NULL, FALSE }, | |
{ &gEfiRuntimeArchProtocolGuid, (VOID **)&gRuntime, NULL, NULL, FALSE }, | |
{ &gEfiVariableArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE }, | |
{ &gEfiVariableWriteArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE }, | |
{ &gEfiCapsuleArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE }, | |
{ &gEfiMonotonicCounterArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE }, | |
{ &gEfiResetArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE }, | |
{ &gEfiRealTimeClockArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE }, | |
{ NULL, (VOID **)NULL, NULL, NULL, FALSE } | |
}; | |
// | |
// Optional protocols that the DXE Core will use if they are present | |
// | |
EFI_CORE_PROTOCOL_NOTIFY_ENTRY mOptionalProtocols[] = { | |
{ &gEfiSecurity2ArchProtocolGuid, (VOID **)&gSecurity2, NULL, NULL, FALSE }, | |
{ &gEfiSmmBase2ProtocolGuid, (VOID **)&gSmmBase2, NULL, NULL, FALSE }, | |
{ NULL, (VOID **)NULL, NULL, NULL, FALSE } | |
}; | |
// | |
// Following is needed to display missing architectural protocols in debug builds | |
// | |
typedef struct { | |
EFI_GUID *ProtocolGuid; | |
CHAR8 *GuidString; | |
} GUID_TO_STRING_PROTOCOL_ENTRY; | |
GLOBAL_REMOVE_IF_UNREFERENCED CONST GUID_TO_STRING_PROTOCOL_ENTRY mMissingProtocols[] = { | |
{ &gEfiSecurityArchProtocolGuid, "Security" }, | |
{ &gEfiCpuArchProtocolGuid, "CPU" }, | |
{ &gEfiMetronomeArchProtocolGuid, "Metronome" }, | |
{ &gEfiTimerArchProtocolGuid, "Timer" }, | |
{ &gEfiBdsArchProtocolGuid, "Bds" }, | |
{ &gEfiWatchdogTimerArchProtocolGuid, "Watchdog Timer" }, | |
{ &gEfiRuntimeArchProtocolGuid, "Runtime" }, | |
{ &gEfiVariableArchProtocolGuid, "Variable" }, | |
{ &gEfiVariableWriteArchProtocolGuid, "Variable Write" }, | |
{ &gEfiCapsuleArchProtocolGuid, "Capsule" }, | |
{ &gEfiMonotonicCounterArchProtocolGuid, "Monotonic Counter" }, | |
{ &gEfiResetArchProtocolGuid, "Reset" }, | |
{ &gEfiRealTimeClockArchProtocolGuid, "Real Time Clock" }, | |
{ NULL, "" } | |
}; | |
/** | |
Return TRUE if all AP services are available. | |
@retval EFI_SUCCESS All AP services are available | |
@retval EFI_NOT_FOUND At least one AP service is not available | |
**/ | |
EFI_STATUS | |
CoreAllEfiServicesAvailable ( | |
VOID | |
) | |
{ | |
EFI_CORE_PROTOCOL_NOTIFY_ENTRY *Entry; | |
for (Entry = mArchProtocols; Entry->ProtocolGuid != NULL; Entry++) { | |
if (!Entry->Present) { | |
return EFI_NOT_FOUND; | |
} | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Notification event handler registered by CoreNotifyOnArchProtocolInstallation (). | |
This notify function is registered for every architectural protocol. This handler | |
updates mArchProtocol[] array entry with protocol instance data and sets it's | |
present flag to TRUE. If any constructor is required it is executed. The EFI | |
System Table headers are updated. | |
@param Event The Event that is being processed, not used. | |
@param Context Event Context, not used. | |
**/ | |
VOID | |
EFIAPI | |
GenericProtocolNotify ( | |
IN EFI_EVENT Event, | |
IN VOID *Context | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_CORE_PROTOCOL_NOTIFY_ENTRY *Entry; | |
VOID *Protocol; | |
LIST_ENTRY *Link; | |
LIST_ENTRY TempLinkNode; | |
Protocol = NULL; | |
// | |
// Get Entry from Context | |
// | |
Entry = (EFI_CORE_PROTOCOL_NOTIFY_ENTRY *)Context; | |
// | |
// See if the expected protocol is present in the handle database | |
// | |
Status = CoreLocateProtocol (Entry->ProtocolGuid, Entry->Registration, &Protocol); | |
if (EFI_ERROR (Status)) { | |
return; | |
} | |
// | |
// Mark the protocol as present | |
// | |
Entry->Present = TRUE; | |
// | |
// Update protocol global variable if one exists. Entry->Protocol points to a global variable | |
// if one exists in the DXE core for this Architectural Protocol | |
// | |
if (Entry->Protocol != NULL) { | |
*(Entry->Protocol) = Protocol; | |
} | |
// | |
// Do special operations for Architectural Protocols | |
// | |
if (CompareGuid (Entry->ProtocolGuid, &gEfiTimerArchProtocolGuid)) { | |
// | |
// Register the Core timer tick handler with the Timer AP | |
// | |
gTimer->RegisterHandler (gTimer, CoreTimerTick); | |
} | |
if (CompareGuid (Entry->ProtocolGuid, &gEfiRuntimeArchProtocolGuid)) { | |
// | |
// When runtime architectural protocol is available, updates CRC32 in the Debug Table | |
// | |
CoreUpdateDebugTableCrc32 (); | |
// | |
// Update the Runtime Architectural protocol with the template that the core was | |
// using so there would not need to be a dependency on the Runtime AP | |
// | |
// | |
// Copy all the registered Image to new gRuntime protocol | |
// | |
for (Link = gRuntimeTemplate.ImageHead.ForwardLink; Link != &gRuntimeTemplate.ImageHead; Link = TempLinkNode.ForwardLink) { | |
CopyMem (&TempLinkNode, Link, sizeof (LIST_ENTRY)); | |
InsertTailList (&gRuntime->ImageHead, Link); | |
} | |
// | |
// Copy all the registered Event to new gRuntime protocol | |
// | |
for (Link = gRuntimeTemplate.EventHead.ForwardLink; Link != &gRuntimeTemplate.EventHead; Link = TempLinkNode.ForwardLink) { | |
CopyMem (&TempLinkNode, Link, sizeof (LIST_ENTRY)); | |
InsertTailList (&gRuntime->EventHead, Link); | |
} | |
// | |
// Clean up gRuntimeTemplate | |
// | |
gRuntimeTemplate.ImageHead.ForwardLink = &gRuntimeTemplate.ImageHead; | |
gRuntimeTemplate.ImageHead.BackLink = &gRuntimeTemplate.ImageHead; | |
gRuntimeTemplate.EventHead.ForwardLink = &gRuntimeTemplate.EventHead; | |
gRuntimeTemplate.EventHead.BackLink = &gRuntimeTemplate.EventHead; | |
} | |
// | |
// It's over kill to do them all every time, but it saves a lot of code. | |
// | |
CalculateEfiHdrCrc (&gDxeCoreRT->Hdr); | |
CalculateEfiHdrCrc (&gBS->Hdr); | |
CalculateEfiHdrCrc (&gDxeCoreST->Hdr); | |
CalculateEfiHdrCrc (&gDxeCoreDS->Hdr); | |
} | |
/** | |
Creates an event for each entry in a table that is fired everytime a Protocol | |
of a specific type is installed. | |
@param Entry Pointer to EFI_CORE_PROTOCOL_NOTIFY_ENTRY. | |
**/ | |
VOID | |
CoreNotifyOnProtocolEntryTable ( | |
EFI_CORE_PROTOCOL_NOTIFY_ENTRY *Entry | |
) | |
{ | |
EFI_STATUS Status; | |
for ( ; Entry->ProtocolGuid != NULL; Entry++) { | |
// | |
// Create the event | |
// | |
Status = CoreCreateEvent ( | |
EVT_NOTIFY_SIGNAL, | |
TPL_CALLBACK, | |
GenericProtocolNotify, | |
Entry, | |
&Entry->Event | |
); | |
ASSERT_EFI_ERROR (Status); | |
// | |
// Register for protocol notifactions on this event | |
// | |
Status = CoreRegisterProtocolNotify ( | |
Entry->ProtocolGuid, | |
Entry->Event, | |
&Entry->Registration | |
); | |
ASSERT_EFI_ERROR (Status); | |
} | |
} | |
/** | |
Creates an events for the Architectural Protocols and the optional protocols | |
that are fired everytime a Protocol of a specific type is installed. | |
**/ | |
VOID | |
CoreNotifyOnProtocolInstallation ( | |
VOID | |
) | |
{ | |
CoreNotifyOnProtocolEntryTable (mArchProtocols); | |
CoreNotifyOnProtocolEntryTable (mOptionalProtocols); | |
} | |
/** | |
Displays Architectural protocols that were not loaded and are required for DXE | |
core to function. Only used in Debug Builds. | |
**/ | |
VOID | |
CoreDisplayMissingArchProtocols ( | |
VOID | |
) | |
{ | |
EFI_CORE_PROTOCOL_NOTIFY_ENTRY *Entry; | |
CONST GUID_TO_STRING_PROTOCOL_ENTRY *MissingEntry; | |
for (Entry = mArchProtocols; Entry->ProtocolGuid != NULL; Entry++) { | |
if (!Entry->Present) { | |
for (MissingEntry = mMissingProtocols; MissingEntry->ProtocolGuid != NULL; MissingEntry++) { | |
if (CompareGuid (Entry->ProtocolGuid, MissingEntry->ProtocolGuid)) { | |
DEBUG ((DEBUG_ERROR, "\n%a Arch Protocol not present!!\n", MissingEntry->GuidString)); | |
break; | |
} | |
} | |
} | |
} | |
} |