audk/MdeModulePkg/Core/Dxe/DxeMain/DxeProtocolNotify.c

280 lines
9.3 KiB
C

/** @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;
}
}
}
}
}