/** @file | |
MM Driver Dispatcher. | |
Step #1 - When a FV protocol is added to the system every driver in the FV | |
is added to the mDiscoveredList. The Before, and After Depex are | |
pre-processed as drivers are added to the mDiscoveredList. If an Apriori | |
file exists in the FV those drivers are added to the | |
mScheduledQueue. The mFwVolList is used to make sure a | |
FV is only processed once. | |
Step #2 - Dispatch. Remove driver from the mScheduledQueue and load and | |
start it. After mScheduledQueue is drained check the | |
mDiscoveredList to see if any item has a Depex that is ready to | |
be placed on the mScheduledQueue. | |
Step #3 - Adding to the mScheduledQueue requires that you process Before | |
and After dependencies. This is done recursively as the call to add | |
to the mScheduledQueue checks for Before Depexes and recursively | |
adds all Before Depexes. It then adds the item that was passed in | |
and then processess the After dependencies by recursively calling | |
the routine. | |
Dispatcher Rules: | |
The rules for the dispatcher are similar to the DXE dispatcher. | |
The rules for DXE dispatcher are in chapter 10 of the DXE CIS. Figure 10-3 | |
is the state diagram for the DXE dispatcher | |
Depex - Dependency Expresion. | |
Copyright (c) 2014, Hewlett-Packard Development Company, L.P. | |
Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR> | |
Copyright (c) 2016 - 2021, Arm Limited. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "StandaloneMmCore.h" | |
// | |
// MM Dispatcher Data structures | |
// | |
#define KNOWN_FWVOL_SIGNATURE SIGNATURE_32('k','n','o','w') | |
typedef struct { | |
UINTN Signature; | |
LIST_ENTRY Link; // mFwVolList | |
EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; | |
} KNOWN_FWVOL; | |
// | |
// Function Prototypes | |
// | |
/** | |
Insert InsertedDriverEntry onto the mScheduledQueue. To do this you | |
must add any driver with a before dependency on InsertedDriverEntry first. | |
You do this by recursively calling this routine. After all the Before Depexes | |
are processed you can add InsertedDriverEntry to the mScheduledQueue. | |
Then you can add any driver with an After dependency on InsertedDriverEntry | |
by recursively calling this routine. | |
@param InsertedDriverEntry The driver to insert on the ScheduledLink Queue | |
**/ | |
VOID | |
MmInsertOnScheduledQueueWhileProcessingBeforeAndAfter ( | |
IN EFI_MM_DRIVER_ENTRY *InsertedDriverEntry | |
); | |
// | |
// The Driver List contains one copy of every driver that has been discovered. | |
// Items are never removed from the driver list. List of EFI_MM_DRIVER_ENTRY | |
// | |
LIST_ENTRY mDiscoveredList = INITIALIZE_LIST_HEAD_VARIABLE (mDiscoveredList); | |
// | |
// Queue of drivers that are ready to dispatch. This queue is a subset of the | |
// mDiscoveredList.list of EFI_MM_DRIVER_ENTRY. | |
// | |
LIST_ENTRY mScheduledQueue = INITIALIZE_LIST_HEAD_VARIABLE (mScheduledQueue); | |
// | |
// List of firmware volume headers whose containing firmware volumes have been | |
// parsed and added to the mFwDriverList. | |
// | |
LIST_ENTRY mFwVolList = INITIALIZE_LIST_HEAD_VARIABLE (mFwVolList); | |
// | |
// Flag for the MM Dispacher. TRUE if dispatcher is executing. | |
// | |
BOOLEAN gDispatcherRunning = FALSE; | |
// | |
// Flag for the MM Dispacher. TRUE if there is one or more MM drivers ready to be dispatched | |
// | |
BOOLEAN gRequestDispatch = FALSE; | |
/** | |
Loads an EFI image into SMRAM. | |
@param DriverEntry EFI_MM_DRIVER_ENTRY instance | |
@return EFI_STATUS | |
**/ | |
EFI_STATUS | |
EFIAPI | |
MmLoadImage ( | |
IN OUT EFI_MM_DRIVER_ENTRY *DriverEntry | |
) | |
{ | |
UINTN PageCount; | |
EFI_STATUS Status; | |
EFI_PHYSICAL_ADDRESS DstBuffer; | |
PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; | |
DEBUG ((DEBUG_INFO, "MmLoadImage - %g\n", &DriverEntry->FileName)); | |
Status = EFI_SUCCESS; | |
// | |
// Initialize ImageContext | |
// | |
ImageContext.Handle = DriverEntry->Pe32Data; | |
ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; | |
// | |
// Get information about the image being loaded | |
// | |
Status = PeCoffLoaderGetImageInfo (&ImageContext); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); | |
DstBuffer = (UINTN)(-1); | |
Status = MmAllocatePages ( | |
AllocateMaxAddress, | |
EfiRuntimeServicesCode, | |
PageCount, | |
&DstBuffer | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer; | |
// | |
// Align buffer on section boundary | |
// | |
ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; | |
ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)(ImageContext.SectionAlignment - 1)); | |
// | |
// Load the image to our new buffer | |
// | |
Status = PeCoffLoaderLoadImage (&ImageContext); | |
if (EFI_ERROR (Status)) { | |
MmFreePages (DstBuffer, PageCount); | |
return Status; | |
} | |
// | |
// Relocate the image in our new buffer | |
// | |
Status = PeCoffLoaderRelocateImage (&ImageContext); | |
if (EFI_ERROR (Status)) { | |
MmFreePages (DstBuffer, PageCount); | |
return Status; | |
} | |
// | |
// Flush the instruction cache so the image data are written before we execute it | |
// | |
InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); | |
// | |
// Save Image EntryPoint in DriverEntry | |
// | |
DriverEntry->ImageEntryPoint = ImageContext.EntryPoint; | |
DriverEntry->ImageBuffer = DstBuffer; | |
DriverEntry->NumberOfPage = PageCount; | |
if (mEfiSystemTable != NULL) { | |
Status = mEfiSystemTable->BootServices->AllocatePool ( | |
EfiBootServicesData, | |
sizeof (EFI_LOADED_IMAGE_PROTOCOL), | |
(VOID **)&DriverEntry->LoadedImage | |
); | |
if (EFI_ERROR (Status)) { | |
MmFreePages (DstBuffer, PageCount); | |
return Status; | |
} | |
ZeroMem (DriverEntry->LoadedImage, sizeof (EFI_LOADED_IMAGE_PROTOCOL)); | |
// | |
// Fill in the remaining fields of the Loaded Image Protocol instance. | |
// Note: ImageBase is an SMRAM address that can not be accessed outside of SMRAM if SMRAM window is closed. | |
// | |
DriverEntry->LoadedImage->Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION; | |
DriverEntry->LoadedImage->ParentHandle = NULL; | |
DriverEntry->LoadedImage->SystemTable = mEfiSystemTable; | |
DriverEntry->LoadedImage->DeviceHandle = NULL; | |
DriverEntry->LoadedImage->FilePath = NULL; | |
DriverEntry->LoadedImage->ImageBase = (VOID *)(UINTN)DriverEntry->ImageBuffer; | |
DriverEntry->LoadedImage->ImageSize = ImageContext.ImageSize; | |
DriverEntry->LoadedImage->ImageCodeType = EfiRuntimeServicesCode; | |
DriverEntry->LoadedImage->ImageDataType = EfiRuntimeServicesData; | |
// | |
// Create a new image handle in the UEFI handle database for the MM Driver | |
// | |
DriverEntry->ImageHandle = NULL; | |
Status = mEfiSystemTable->BootServices->InstallMultipleProtocolInterfaces ( | |
&DriverEntry->ImageHandle, | |
&gEfiLoadedImageProtocolGuid, | |
DriverEntry->LoadedImage, | |
NULL | |
); | |
} | |
// | |
// Print the load address and the PDB file name if it is available | |
// | |
DEBUG_CODE_BEGIN (); | |
UINTN Index; | |
UINTN StartIndex; | |
CHAR8 EfiFileName[256]; | |
DEBUG (( | |
DEBUG_INFO | DEBUG_LOAD, | |
"Loading MM driver at 0x%11p EntryPoint=0x%11p ", | |
(VOID *)(UINTN)ImageContext.ImageAddress, | |
FUNCTION_ENTRY_POINT (ImageContext.EntryPoint) | |
)); | |
// | |
// Print Module Name by Pdb file path. | |
// Windows and Unix style file path are all trimmed correctly. | |
// | |
if (ImageContext.PdbPointer != NULL) { | |
StartIndex = 0; | |
for (Index = 0; ImageContext.PdbPointer[Index] != 0; Index++) { | |
if ((ImageContext.PdbPointer[Index] == '\\') || (ImageContext.PdbPointer[Index] == '/')) { | |
StartIndex = Index + 1; | |
} | |
} | |
// | |
// Copy the PDB file name to our temporary string, and replace .pdb with .efi | |
// The PDB file name is limited in the range of 0~255. | |
// If the length is bigger than 255, trim the redundant characters to avoid overflow in array boundary. | |
// | |
for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) { | |
EfiFileName[Index] = ImageContext.PdbPointer[Index + StartIndex]; | |
if (EfiFileName[Index] == 0) { | |
EfiFileName[Index] = '.'; | |
} | |
if (EfiFileName[Index] == '.') { | |
EfiFileName[Index + 1] = 'e'; | |
EfiFileName[Index + 2] = 'f'; | |
EfiFileName[Index + 3] = 'i'; | |
EfiFileName[Index + 4] = 0; | |
break; | |
} | |
} | |
if (Index == sizeof (EfiFileName) - 4) { | |
EfiFileName[Index] = 0; | |
} | |
DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); | |
} | |
DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n")); | |
DEBUG_CODE_END (); | |
return Status; | |
} | |
/** | |
Preprocess dependency expression and update DriverEntry to reflect the | |
state of Before and After dependencies. If DriverEntry->Before | |
or DriverEntry->After is set it will never be cleared. | |
@param DriverEntry DriverEntry element to update . | |
@retval EFI_SUCCESS It always works. | |
**/ | |
EFI_STATUS | |
MmPreProcessDepex ( | |
IN EFI_MM_DRIVER_ENTRY *DriverEntry | |
) | |
{ | |
UINT8 *Iterator; | |
Iterator = DriverEntry->Depex; | |
DriverEntry->Dependent = TRUE; | |
if (*Iterator == EFI_DEP_BEFORE) { | |
DriverEntry->Before = TRUE; | |
} else if (*Iterator == EFI_DEP_AFTER) { | |
DriverEntry->After = TRUE; | |
} | |
if (DriverEntry->Before || DriverEntry->After) { | |
CopyMem (&DriverEntry->BeforeAfterGuid, Iterator + 1, sizeof (EFI_GUID)); | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Read Depex and pre-process the Depex for Before and After. If Section Extraction | |
protocol returns an error via ReadSection defer the reading of the Depex. | |
@param DriverEntry Driver to work on. | |
@retval EFI_SUCCESS Depex read and preprossesed | |
@retval EFI_PROTOCOL_ERROR The section extraction protocol returned an error | |
and Depex reading needs to be retried. | |
@retval Error DEPEX not found. | |
**/ | |
EFI_STATUS | |
MmGetDepexSectionAndPreProccess ( | |
IN EFI_MM_DRIVER_ENTRY *DriverEntry | |
) | |
{ | |
EFI_STATUS Status; | |
// | |
// Data already read | |
// | |
if (DriverEntry->Depex == NULL) { | |
Status = EFI_NOT_FOUND; | |
} else { | |
Status = EFI_SUCCESS; | |
} | |
if (EFI_ERROR (Status)) { | |
if (Status == EFI_PROTOCOL_ERROR) { | |
// | |
// The section extraction protocol failed so set protocol error flag | |
// | |
DriverEntry->DepexProtocolError = TRUE; | |
} else { | |
// | |
// If no Depex assume depend on all architectural protocols | |
// | |
DriverEntry->Depex = NULL; | |
DriverEntry->Dependent = TRUE; | |
DriverEntry->DepexProtocolError = FALSE; | |
} | |
} else { | |
// | |
// Set Before and After state information based on Depex | |
// Driver will be put in Dependent state | |
// | |
MmPreProcessDepex (DriverEntry); | |
DriverEntry->DepexProtocolError = FALSE; | |
} | |
return Status; | |
} | |
/** | |
This is the main Dispatcher for MM and it exits when there are no more | |
drivers to run. Drain the mScheduledQueue and load and start a PE | |
image for each driver. Search the mDiscoveredList to see if any driver can | |
be placed on the mScheduledQueue. If no drivers are placed on the | |
mScheduledQueue exit the function. | |
@retval EFI_SUCCESS All of the MM Drivers that could be dispatched | |
have been run and the MM Entry Point has been | |
registered. | |
@retval EFI_NOT_READY The MM Driver that registered the MM Entry Point | |
was just dispatched. | |
@retval EFI_NOT_FOUND There are no MM Drivers available to be dispatched. | |
@retval EFI_ALREADY_STARTED The MM Dispatcher is already running | |
**/ | |
EFI_STATUS | |
MmDispatcher ( | |
VOID | |
) | |
{ | |
EFI_STATUS Status; | |
LIST_ENTRY *Link; | |
EFI_MM_DRIVER_ENTRY *DriverEntry; | |
BOOLEAN ReadyToRun; | |
DEBUG ((DEBUG_INFO, "MmDispatcher\n")); | |
if (!gRequestDispatch) { | |
DEBUG ((DEBUG_INFO, " !gRequestDispatch\n")); | |
return EFI_NOT_FOUND; | |
} | |
if (gDispatcherRunning) { | |
DEBUG ((DEBUG_INFO, " gDispatcherRunning\n")); | |
// | |
// If the dispatcher is running don't let it be restarted. | |
// | |
return EFI_ALREADY_STARTED; | |
} | |
gDispatcherRunning = TRUE; | |
do { | |
// | |
// Drain the Scheduled Queue | |
// | |
DEBUG ((DEBUG_INFO, " Drain the Scheduled Queue\n")); | |
while (!IsListEmpty (&mScheduledQueue)) { | |
DriverEntry = CR ( | |
mScheduledQueue.ForwardLink, | |
EFI_MM_DRIVER_ENTRY, | |
ScheduledLink, | |
EFI_MM_DRIVER_ENTRY_SIGNATURE | |
); | |
DEBUG ((DEBUG_INFO, " DriverEntry (Scheduled) - %g\n", &DriverEntry->FileName)); | |
// | |
// Load the MM Driver image into memory. If the Driver was transitioned from | |
// Untrusted to Scheduled it would have already been loaded so we may need to | |
// skip the LoadImage | |
// | |
if (DriverEntry->ImageHandle == NULL) { | |
Status = MmLoadImage (DriverEntry); | |
// | |
// Update the driver state to reflect that it's been loaded | |
// | |
if (EFI_ERROR (Status)) { | |
// | |
// The MM Driver could not be loaded, and do not attempt to load or start it again. | |
// Take driver from Scheduled to Initialized. | |
// | |
DriverEntry->Initialized = TRUE; | |
DriverEntry->Scheduled = FALSE; | |
RemoveEntryList (&DriverEntry->ScheduledLink); | |
// | |
// If it's an error don't try the StartImage | |
// | |
continue; | |
} | |
} | |
DriverEntry->Scheduled = FALSE; | |
DriverEntry->Initialized = TRUE; | |
RemoveEntryList (&DriverEntry->ScheduledLink); | |
// | |
// For each MM driver, pass NULL as ImageHandle | |
// | |
if (mEfiSystemTable == NULL) { | |
DEBUG ((DEBUG_INFO, "StartImage - 0x%x (Standalone Mode)\n", DriverEntry->ImageEntryPoint)); | |
Status = ((MM_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint)(DriverEntry->ImageHandle, &gMmCoreMmst); | |
} else { | |
DEBUG ((DEBUG_INFO, "StartImage - 0x%x (Tradition Mode)\n", DriverEntry->ImageEntryPoint)); | |
Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint)( | |
DriverEntry->ImageHandle, | |
mEfiSystemTable | |
); | |
} | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_INFO, "StartImage Status - %r\n", Status)); | |
MmFreePages (DriverEntry->ImageBuffer, DriverEntry->NumberOfPage); | |
} | |
} | |
// | |
// Search DriverList for items to place on Scheduled Queue | |
// | |
DEBUG ((DEBUG_INFO, " Search DriverList for items to place on Scheduled Queue\n")); | |
ReadyToRun = FALSE; | |
for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { | |
DriverEntry = CR (Link, EFI_MM_DRIVER_ENTRY, Link, EFI_MM_DRIVER_ENTRY_SIGNATURE); | |
DEBUG ((DEBUG_INFO, " DriverEntry (Discovered) - %g\n", &DriverEntry->FileName)); | |
if (DriverEntry->DepexProtocolError) { | |
// | |
// If Section Extraction Protocol did not let the Depex be read before retry the read | |
// | |
Status = MmGetDepexSectionAndPreProccess (DriverEntry); | |
} | |
if (DriverEntry->Dependent) { | |
if (MmIsSchedulable (DriverEntry)) { | |
MmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry); | |
ReadyToRun = TRUE; | |
} | |
} | |
} | |
} while (ReadyToRun); | |
// | |
// If there is no more MM driver to dispatch, stop the dispatch request | |
// | |
DEBUG ((DEBUG_INFO, " no more MM driver to dispatch, stop the dispatch request\n")); | |
gRequestDispatch = FALSE; | |
for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { | |
DriverEntry = CR (Link, EFI_MM_DRIVER_ENTRY, Link, EFI_MM_DRIVER_ENTRY_SIGNATURE); | |
DEBUG ((DEBUG_INFO, " DriverEntry (Discovered) - %g\n", &DriverEntry->FileName)); | |
if (!DriverEntry->Initialized) { | |
// | |
// We have MM driver pending to dispatch | |
// | |
gRequestDispatch = TRUE; | |
break; | |
} | |
} | |
gDispatcherRunning = FALSE; | |
return EFI_SUCCESS; | |
} | |
/** | |
Insert InsertedDriverEntry onto the mScheduledQueue. To do this you | |
must add any driver with a before dependency on InsertedDriverEntry first. | |
You do this by recursively calling this routine. After all the Before Depexes | |
are processed you can add InsertedDriverEntry to the mScheduledQueue. | |
Then you can add any driver with an After dependency on InsertedDriverEntry | |
by recursively calling this routine. | |
@param InsertedDriverEntry The driver to insert on the ScheduledLink Queue | |
**/ | |
VOID | |
MmInsertOnScheduledQueueWhileProcessingBeforeAndAfter ( | |
IN EFI_MM_DRIVER_ENTRY *InsertedDriverEntry | |
) | |
{ | |
LIST_ENTRY *Link; | |
EFI_MM_DRIVER_ENTRY *DriverEntry; | |
// | |
// Process Before Dependency | |
// | |
for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { | |
DriverEntry = CR (Link, EFI_MM_DRIVER_ENTRY, Link, EFI_MM_DRIVER_ENTRY_SIGNATURE); | |
if (DriverEntry->Before && DriverEntry->Dependent && (DriverEntry != InsertedDriverEntry)) { | |
DEBUG ((DEBUG_DISPATCH, "Evaluate MM DEPEX for FFS(%g)\n", &DriverEntry->FileName)); | |
DEBUG ((DEBUG_DISPATCH, " BEFORE FFS(%g) = ", &DriverEntry->BeforeAfterGuid)); | |
if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) { | |
// | |
// Recursively process BEFORE | |
// | |
DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n")); | |
MmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry); | |
} else { | |
DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n")); | |
} | |
} | |
} | |
// | |
// Convert driver from Dependent to Scheduled state | |
// | |
InsertedDriverEntry->Dependent = FALSE; | |
InsertedDriverEntry->Scheduled = TRUE; | |
InsertTailList (&mScheduledQueue, &InsertedDriverEntry->ScheduledLink); | |
// | |
// Process After Dependency | |
// | |
for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { | |
DriverEntry = CR (Link, EFI_MM_DRIVER_ENTRY, Link, EFI_MM_DRIVER_ENTRY_SIGNATURE); | |
if (DriverEntry->After && DriverEntry->Dependent && (DriverEntry != InsertedDriverEntry)) { | |
DEBUG ((DEBUG_DISPATCH, "Evaluate MM DEPEX for FFS(%g)\n", &DriverEntry->FileName)); | |
DEBUG ((DEBUG_DISPATCH, " AFTER FFS(%g) = ", &DriverEntry->BeforeAfterGuid)); | |
if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) { | |
// | |
// Recursively process AFTER | |
// | |
DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n")); | |
MmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry); | |
} else { | |
DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n")); | |
} | |
} | |
} | |
} | |
/** | |
Return TRUE if the firmware volume has been processed, FALSE if not. | |
@param FwVolHeader The header of the firmware volume that's being | |
tested. | |
@retval TRUE The firmware volume denoted by FwVolHeader has | |
been processed | |
@retval FALSE The firmware volume denoted by FwVolHeader has | |
not yet been processed | |
**/ | |
BOOLEAN | |
FvHasBeenProcessed ( | |
IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader | |
) | |
{ | |
LIST_ENTRY *Link; | |
KNOWN_FWVOL *KnownFwVol; | |
for (Link = mFwVolList.ForwardLink; | |
Link != &mFwVolList; | |
Link = Link->ForwardLink) | |
{ | |
KnownFwVol = CR (Link, KNOWN_FWVOL, Link, KNOWN_FWVOL_SIGNATURE); | |
if (KnownFwVol->FwVolHeader == FwVolHeader) { | |
return TRUE; | |
} | |
} | |
return FALSE; | |
} | |
/** | |
Remember that the firmware volume denoted by FwVolHeader has had its drivers | |
placed on mDiscoveredList. This function adds entries to mFwVolList. Items | |
are never removed/freed from mFwVolList. | |
@param FwVolHeader The header of the firmware volume that's being | |
processed. | |
**/ | |
VOID | |
FvIsBeingProcessed ( | |
IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader | |
) | |
{ | |
KNOWN_FWVOL *KnownFwVol; | |
DEBUG ((DEBUG_INFO, "FvIsBeingProcessed - 0x%08x\n", FwVolHeader)); | |
KnownFwVol = AllocatePool (sizeof (KNOWN_FWVOL)); | |
ASSERT (KnownFwVol != NULL); | |
KnownFwVol->Signature = KNOWN_FWVOL_SIGNATURE; | |
KnownFwVol->FwVolHeader = FwVolHeader; | |
InsertTailList (&mFwVolList, &KnownFwVol->Link); | |
} | |
/** | |
Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry, | |
and initialise any state variables. Read the Depex from the FV and store it | |
in DriverEntry. Pre-process the Depex to set the Before and After state. | |
The Discovered list is never freed and contains booleans that represent the | |
other possible MM driver states. | |
@param [in] FwVolHeader Pointer to the formware volume header. | |
@param [in] Pe32Data Pointer to the PE data. | |
@param [in] Pe32DataSize Size of the PE data. | |
@param [in] Depex Pointer to the Depex info. | |
@param [in] DepexSize Size of the Depex info. | |
@param [in] DriverName Name of driver to add to mDiscoveredList. | |
@retval EFI_SUCCESS If driver was added to the mDiscoveredList. | |
**/ | |
EFI_STATUS | |
MmAddToDriverList ( | |
IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader, | |
IN VOID *Pe32Data, | |
IN UINTN Pe32DataSize, | |
IN VOID *Depex, | |
IN UINTN DepexSize, | |
IN EFI_GUID *DriverName | |
) | |
{ | |
EFI_MM_DRIVER_ENTRY *DriverEntry; | |
DEBUG ((DEBUG_INFO, "MmAddToDriverList - %g (0x%08x)\n", DriverName, Pe32Data)); | |
// | |
// Create the Driver Entry for the list. ZeroPool initializes lots of variables to | |
// NULL or FALSE. | |
// | |
DriverEntry = AllocateZeroPool (sizeof (EFI_MM_DRIVER_ENTRY)); | |
ASSERT (DriverEntry != NULL); | |
DriverEntry->Signature = EFI_MM_DRIVER_ENTRY_SIGNATURE; | |
CopyGuid (&DriverEntry->FileName, DriverName); | |
DriverEntry->FwVolHeader = FwVolHeader; | |
DriverEntry->Pe32Data = Pe32Data; | |
DriverEntry->Pe32DataSize = Pe32DataSize; | |
DriverEntry->Depex = Depex; | |
DriverEntry->DepexSize = DepexSize; | |
MmGetDepexSectionAndPreProccess (DriverEntry); | |
InsertTailList (&mDiscoveredList, &DriverEntry->Link); | |
gRequestDispatch = TRUE; | |
return EFI_SUCCESS; | |
} | |
/** | |
Traverse the discovered list for any drivers that were discovered but not loaded | |
because the dependency expressions evaluated to false. | |
**/ | |
VOID | |
MmDisplayDiscoveredNotDispatched ( | |
VOID | |
) | |
{ | |
LIST_ENTRY *Link; | |
EFI_MM_DRIVER_ENTRY *DriverEntry; | |
for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { | |
DriverEntry = CR (Link, EFI_MM_DRIVER_ENTRY, Link, EFI_MM_DRIVER_ENTRY_SIGNATURE); | |
if (DriverEntry->Dependent) { | |
DEBUG ((DEBUG_LOAD, "MM Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName)); | |
} | |
} | |
} |