aboutsummaryrefslogtreecommitdiffstats
path: root/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideLib.c
diff options
context:
space:
mode:
Diffstat (limited to 'roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideLib.c')
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideLib.c1941
1 files changed, 1941 insertions, 0 deletions
diff --git a/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideLib.c b/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideLib.c
new file mode 100644
index 000000000..f91f038b7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideLib.c
@@ -0,0 +1,1941 @@
+/** @file
+ Implementation of the shared functions to do the platform driver vverride mapping.
+
+ Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalPlatDriOverrideDxe.h"
+
+#define PLATFORM_OVERRIDE_ITEM_SIGNATURE SIGNATURE_32('p','d','o','i')
+ typedef struct _PLATFORM_OVERRIDE_ITEM {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ UINT32 DriverInfoNum;
+ EFI_DEVICE_PATH_PROTOCOL *ControllerDevicePath;
+ ///
+ /// List of DRIVER_IMAGE_INFO
+ ///
+ LIST_ENTRY DriverInfoList;
+ EFI_HANDLE LastReturnedImageHandle;
+} PLATFORM_OVERRIDE_ITEM;
+
+#define DRIVER_IMAGE_INFO_SIGNATURE SIGNATURE_32('p','d','i','i')
+typedef struct _DRIVER_IMAGE_INFO {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ EFI_HANDLE ImageHandle;
+ EFI_DEVICE_PATH_PROTOCOL *DriverImagePath;
+ BOOLEAN UnLoadable;
+ BOOLEAN UnStartable;
+} DRIVER_IMAGE_INFO;
+
+#define DEVICE_PATH_STACK_ITEM_SIGNATURE SIGNATURE_32('d','p','s','i')
+typedef struct _DEVICE_PATH_STACK_ITEM{
+ UINTN Signature;
+ LIST_ENTRY Link;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+} DEVICE_PATH_STACK_ITEM;
+
+
+LIST_ENTRY mDevicePathStack = INITIALIZE_LIST_HEAD_VARIABLE (mDevicePathStack);
+
+/**
+ Push a controller device path into a globle device path list.
+
+ @param DevicePath The controller device path to push into stack
+
+ @retval EFI_SUCCESS Device path successfully pushed into the stack.
+
+**/
+EFI_STATUS
+EFIAPI
+PushDevPathStack (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ DEVICE_PATH_STACK_ITEM *DevicePathStackItem;
+
+ DevicePathStackItem = AllocateZeroPool (sizeof (DEVICE_PATH_STACK_ITEM));
+ ASSERT (DevicePathStackItem != NULL);
+ DevicePathStackItem->Signature = DEVICE_PATH_STACK_ITEM_SIGNATURE;
+ DevicePathStackItem->DevicePath = DuplicateDevicePath (DevicePath);
+ InsertTailList (&mDevicePathStack, &DevicePathStackItem->Link);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Pop a controller device path from a globle device path list
+
+ @param DevicePath The controller device path popped from stack
+
+ @retval EFI_SUCCESS Controller device path successfully popped.
+ @retval EFI_NOT_FOUND Stack is empty.
+
+**/
+EFI_STATUS
+EFIAPI
+PopDevPathStack (
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ DEVICE_PATH_STACK_ITEM *DevicePathStackItem;
+ LIST_ENTRY *ItemListIndex;
+
+ ItemListIndex = mDevicePathStack.BackLink;
+ //
+ // Check if the stack is empty
+ //
+ if (ItemListIndex != &mDevicePathStack){
+ DevicePathStackItem = CR(ItemListIndex, DEVICE_PATH_STACK_ITEM, Link, DEVICE_PATH_STACK_ITEM_SIGNATURE);
+ if (DevicePath != NULL) {
+ *DevicePath = DuplicateDevicePath (DevicePathStackItem->DevicePath);
+ }
+ FreePool (DevicePathStackItem->DevicePath);
+ RemoveEntryList (&DevicePathStackItem->Link);
+ FreePool (DevicePathStackItem);
+ return EFI_SUCCESS;
+ }
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Check whether a controller device path is in a globle device path list
+
+ @param DevicePath The controller device path to check
+
+ @retval TRUE DevicePath exists in the stack.
+ @retval FALSE DevicePath does not exist in the stack.
+
+**/
+BOOLEAN
+EFIAPI
+CheckExistInStack (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ DEVICE_PATH_STACK_ITEM *DevicePathStackItem;
+ LIST_ENTRY *ItemListIndex;
+ UINTN DevicePathSize;
+
+ ItemListIndex = mDevicePathStack.BackLink;
+ while (ItemListIndex != &mDevicePathStack){
+ DevicePathStackItem = CR(ItemListIndex, DEVICE_PATH_STACK_ITEM, Link, DEVICE_PATH_STACK_ITEM_SIGNATURE);
+ DevicePathSize = GetDevicePathSize (DevicePath);
+ if (DevicePathSize == GetDevicePathSize (DevicePathStackItem->DevicePath)) {
+ if (CompareMem (DevicePath, DevicePathStackItem->DevicePath, DevicePathSize) == 0) {
+ return TRUE;
+ }
+ }
+ ItemListIndex = ItemListIndex->BackLink;
+ }
+
+ return FALSE;
+}
+
+/**
+ Update the FV file device path if it is not valid.
+
+ According to a file GUID, check a Fv file device path is valid. If it is invalid,
+ try to return the valid device path.
+ FV address maybe changes for memory layout adjust from time to time, use this function
+ could promise the Fv file device path is right.
+
+ @param DevicePath On input, the FV file device path to check
+ On output, the updated valid FV file device path
+ @param FileGuid The FV file GUID
+ @param CallerImageHandle Image handle of the caller
+
+ @retval EFI_INVALID_PARAMETER the input DevicePath or FileGuid is invalid
+ parameter
+ @retval EFI_UNSUPPORTED the input DevicePath does not contain FV file
+ GUID at all
+ @retval EFI_ALREADY_STARTED the input DevicePath has pointed to FV file, it
+ is valid
+ @retval EFI_SUCCESS Successfully updated the invalid DevicePath,
+ and return the updated device path in DevicePath
+
+**/
+EFI_STATUS
+EFIAPI
+UpdateFvFileDevicePath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
+ IN EFI_GUID *FileGuid,
+ IN EFI_HANDLE CallerImageHandle
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
+ EFI_STATUS Status;
+ EFI_GUID *GuidPoint;
+ UINTN Index;
+ UINTN FvHandleCount;
+ EFI_HANDLE *FvHandleBuffer;
+ EFI_FV_FILETYPE Type;
+ UINTN Size;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINT32 AuthenticationStatus;
+ BOOLEAN FindFvFile;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode;
+ EFI_HANDLE FoundFvHandle;
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
+ BOOLEAN HasFvNode;
+
+ if (DevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*DevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether the device path points to the default the input FV file
+ //
+ TempDevicePath = *DevicePath;
+ LastDeviceNode = TempDevicePath;
+ while (!IsDevicePathEnd (TempDevicePath)) {
+ LastDeviceNode = TempDevicePath;
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ }
+ GuidPoint = EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode);
+ if (GuidPoint == NULL) {
+ //
+ // If this option does not point to a FV file, just return EFI_UNSUPPORTED.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ if (FileGuid != NULL) {
+ if (!CompareGuid (GuidPoint, FileGuid)) {
+ //
+ // If the FV file is not the input file GUID, just return EFI_UNSUPPORTED
+ //
+ return EFI_UNSUPPORTED;
+ }
+ } else {
+ FileGuid = GuidPoint;
+ }
+
+ //
+ // Check to see if the device path contains memory map node
+ //
+ TempDevicePath = *DevicePath;
+ HasFvNode = FALSE;
+ while (!IsDevicePathEnd (TempDevicePath)) {
+ //
+ // Use old Device Path
+ //
+ if (DevicePathType (TempDevicePath) == HARDWARE_DEVICE_PATH &&
+ DevicePathSubType (TempDevicePath) == HW_MEMMAP_DP) {
+ HasFvNode = TRUE;
+ break;
+ }
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ }
+
+ if (!HasFvNode) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check whether the input Fv file device path is valid
+ //
+ TempDevicePath = *DevicePath;
+ FoundFvHandle = NULL;
+ Status = gBS->LocateDevicePath (
+ &gEfiFirmwareVolume2ProtocolGuid,
+ &TempDevicePath,
+ &FoundFvHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (
+ FoundFvHandle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **) &Fv
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Set FV ReadFile Buffer as NULL, only need to check whether input Fv file exist there
+ //
+ Status = Fv->ReadFile (
+ Fv,
+ FileGuid,
+ NULL,
+ &Size,
+ &Type,
+ &Attributes,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ return EFI_ALREADY_STARTED;
+ }
+ }
+ }
+
+ //
+ // Look for the input wanted FV file in current FV
+ // First, try to look for in Caller own FV. Caller and input wanted FV file usually are in the same FV
+ //
+ FindFvFile = FALSE;
+ FoundFvHandle = NULL;
+ Status = gBS->HandleProtocol (
+ CallerImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &LoadedImage
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (
+ LoadedImage->DeviceHandle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **) &Fv
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = Fv->ReadFile (
+ Fv,
+ FileGuid,
+ NULL,
+ &Size,
+ &Type,
+ &Attributes,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ FindFvFile = TRUE;
+ FoundFvHandle = LoadedImage->DeviceHandle;
+ }
+ }
+ }
+ //
+ // Second, if fail to find, try to enumerate all FV
+ //
+ if (!FindFvFile) {
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &FvHandleCount,
+ &FvHandleBuffer
+ );
+ for (Index = 0; Index < FvHandleCount; Index++) {
+ gBS->HandleProtocol (
+ FvHandleBuffer[Index],
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **) &Fv
+ );
+
+ Status = Fv->ReadFile (
+ Fv,
+ FileGuid,
+ NULL,
+ &Size,
+ &Type,
+ &Attributes,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Skip if input Fv file not in the FV
+ //
+ continue;
+ }
+ FindFvFile = TRUE;
+ FoundFvHandle = FvHandleBuffer[Index];
+ break;
+ }
+ }
+
+ if (FindFvFile) {
+ //
+ // Build the shell device path
+ //
+ NewDevicePath = DevicePathFromHandle (FoundFvHandle);
+ EfiInitializeFwVolDevicepathNode (&FvFileNode, FileGuid);
+ NewDevicePath = AppendDevicePathNode (NewDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &FvFileNode);
+ *DevicePath = NewDevicePath;
+ return EFI_SUCCESS;
+ }
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Gets the data and size of a variable.
+
+ Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
+ buffer, and the size of the buffer. If failure return NULL.
+
+ @param Name String part of EFI variable name
+ @param VendorGuid GUID part of EFI variable name
+ @param VariableSize Returns the size of the EFI variable that was
+ read
+
+ @return Dynamically allocated memory that contains a copy of the EFI variable.
+ Caller is responsible freeing the buffer.
+ @retval NULL Variable was not read
+
+**/
+VOID *
+EFIAPI
+GetVariableAndSize (
+ IN CHAR16 *Name,
+ IN EFI_GUID *VendorGuid,
+ OUT UINTN *VariableSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ VOID *Buffer;
+
+ Buffer = NULL;
+
+ //
+ // Pass in a zero size buffer to find the required buffer size.
+ //
+ BufferSize = 0;
+ Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ //
+ // Allocate the buffer to return
+ //
+ Buffer = AllocateZeroPool (BufferSize);
+ if (Buffer == NULL) {
+ return NULL;
+ }
+ //
+ // Read variable into the allocated buffer.
+ //
+ Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ BufferSize = 0;
+ }
+ }
+
+ *VariableSize = BufferSize;
+ return Buffer;
+}
+
+/**
+ Connect to the handle to a device on the device path.
+
+ This function will create all handles associate with every device
+ path node. If the handle associate with one device path node can not
+ be created success, then still give one chance to do the dispatch,
+ which load the missing drivers if possible.
+
+ @param DevicePathToConnect The device path which will be connected, it can
+ be a multi-instance device path
+
+ @retval EFI_SUCCESS All handles associate with every device path
+ node have been created
+ @retval EFI_OUT_OF_RESOURCES There is no resource to create new handles
+ @retval EFI_NOT_FOUND Create the handle associate with one device
+ path node failed
+
+**/
+EFI_STATUS
+EFIAPI
+ConnectDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePathToConnect
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *CopyOfDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *Next;
+ EFI_HANDLE Handle;
+ EFI_HANDLE PreviousHandle;
+ UINTN Size;
+
+ if (DevicePathToConnect == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ DevicePath = DuplicateDevicePath (DevicePathToConnect);
+ CopyOfDevicePath = DevicePath;
+ if (DevicePath == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ do {
+ //
+ // The outer loop handles multi instance device paths.
+ // Only console variables contain multiple instance device paths.
+ //
+ // After this call DevicePath points to the next Instance
+ //
+ Instance = GetNextDevicePathInstance (&DevicePath, &Size);
+ ASSERT (Instance != NULL);
+
+ Next = Instance;
+ while (!IsDevicePathEndType (Next)) {
+ Next = NextDevicePathNode (Next);
+ }
+
+ SetDevicePathEndNode (Next);
+
+ //
+ // Start the real work of connect with RemainingDevicePath
+ //
+ PreviousHandle = NULL;
+ do {
+ //
+ // Find the handle that best matches the Device Path. If it is only a
+ // partial match the remaining part of the device path is returned in
+ // RemainingDevicePath.
+ //
+ RemainingDevicePath = Instance;
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &Handle);
+
+ if (!EFI_ERROR (Status)) {
+ if (Handle == PreviousHandle) {
+ //
+ // If no forward progress is made try invoking the Dispatcher.
+ // A new FV may have been added to the system an new drivers
+ // may now be found.
+ // Status == EFI_SUCCESS means a driver was dispatched
+ // Status == EFI_NOT_FOUND means no new drivers were dispatched
+ //
+ Status = gDS->Dispatch ();
+ }
+
+ if (!EFI_ERROR (Status)) {
+ PreviousHandle = Handle;
+ //
+ // Connect all drivers that apply to Handle and RemainingDevicePath,
+ // the Recursive flag is FALSE so only one level will be expanded.
+ //
+ // Do not check the connect status here, if the connect controller fail,
+ // then still give the chance to do dispatch, because partial
+ // RemainingDevicepath may be in the new FV
+ //
+ // 1. If the connect fails, RemainingDevicepath and handle will not
+ // change, so next time will do the dispatch, then dispatch's status
+ // will take effect
+ // 2. If the connect succeeds, the RemainingDevicepath and handle will
+ // change, then avoid the dispatch, we have chance to continue the
+ // next connection
+ //
+ gBS->ConnectController (Handle, NULL, RemainingDevicePath, FALSE);
+ }
+ }
+ //
+ // Loop until RemainingDevicePath is an empty device path
+ //
+ } while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath));
+
+ } while (DevicePath != NULL);
+
+ if (CopyOfDevicePath != NULL) {
+ FreePool (CopyOfDevicePath);
+ }
+ //
+ // All handle with DevicePath exists in the handle database
+ //
+ return Status;
+}
+
+/**
+ Free all the mapping database memory resource and initialize the mapping list entry.
+
+ @param MappingDataBase Mapping database list entry pointer
+
+ @retval EFI_SUCCESS Mapping database successfully freed
+ @retval EFI_INVALID_PARAMETER MappingDataBase is NULL
+
+**/
+EFI_STATUS
+EFIAPI
+FreeMappingDatabase (
+ IN OUT LIST_ENTRY *MappingDataBase
+ )
+{
+ LIST_ENTRY *OverrideItemListIndex;
+ LIST_ENTRY *ImageInfoListIndex;
+ PLATFORM_OVERRIDE_ITEM *OverrideItem;
+ DRIVER_IMAGE_INFO *DriverImageInfo;
+
+ if (MappingDataBase == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OverrideItemListIndex = GetFirstNode (MappingDataBase);
+ while (!IsNull (MappingDataBase, OverrideItemListIndex)) {
+ OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);
+ //
+ // Free PLATFORM_OVERRIDE_ITEM.ControllerDevicePath[]
+ //
+ if (OverrideItem->ControllerDevicePath != NULL){
+ FreePool (OverrideItem->ControllerDevicePath);
+ }
+
+ ImageInfoListIndex = GetFirstNode (&OverrideItem->DriverInfoList);
+ while (!IsNull (&OverrideItem->DriverInfoList, ImageInfoListIndex)) {
+ //
+ // Free DRIVER_IMAGE_INFO.DriverImagePath[]
+ //
+ DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);
+ if (DriverImageInfo->DriverImagePath != NULL) {
+ FreePool(DriverImageInfo->DriverImagePath);
+ }
+ //
+ // Free DRIVER_IMAGE_INFO itself
+ //
+ ImageInfoListIndex = GetNextNode (&OverrideItem->DriverInfoList, ImageInfoListIndex);
+ RemoveEntryList (&DriverImageInfo->Link);
+ FreePool (DriverImageInfo);
+ }
+ //
+ // Free PLATFORM_OVERRIDE_ITEM itself
+ //
+ OverrideItemListIndex = GetNextNode (MappingDataBase, OverrideItemListIndex);
+ RemoveEntryList (&OverrideItem->Link);
+ FreePool (OverrideItem);
+ }
+
+ InitializeListHead (MappingDataBase);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Create the mapping database according to variable.
+
+ Read the environment variable(s) that contain the override mappings from Controller Device Path to
+ a set of Driver Device Paths, and create the mapping database in memory with those variable info.
+ VariableLayout{
+ //
+ // NotEnd indicate whether the variable is the last one, and has no subsequent variable need to load.
+ // Each variable has MaximumVariableSize limitation, so we maybe need multiple variables to store
+ // large mapping infos.
+ // The variable(s) name rule is PlatDriOver, PlatDriOver1, PlatDriOver2, ....
+ //
+ UINT32 NotEnd; //Zero is the last one.
+ //
+ // The entry which contains the mapping that Controller Device Path to a set of Driver Device Paths
+ // There are often multi mapping entries in a variable.
+ //
+ UINT32 SIGNATURE; //SIGNATURE_32('p','d','o','i')
+ UINT32 DriverNum;
+ EFI_DEVICE_PATH_PROTOCOL ControllerDevicePath[];
+ EFI_DEVICE_PATH_PROTOCOL DriverDevicePath[];
+ EFI_DEVICE_PATH_PROTOCOL DriverDevicePath[];
+ EFI_DEVICE_PATH_PROTOCOL DriverDevicePath[];
+ ......
+ UINT32 NotEnd; //Zero is the last one.
+ UINT32 SIGNATURE;
+ UINT32 DriverNum;
+ EFI_DEVICE_PATH_PROTOCOL ControllerDevicePath[];
+ EFI_DEVICE_PATH_PROTOCOL DriverDevicePath[];
+ EFI_DEVICE_PATH_PROTOCOL DriverDevicePath[];
+ EFI_DEVICE_PATH_PROTOCOL DriverDevicePath[];
+ ......
+ }
+
+ @param MappingDataBase Mapping database list entry pointer
+
+ @retval EFI_SUCCESS Create the mapping database in memory successfully
+ @retval EFI_INVALID_PARAMETER MappingDataBase pointer is null
+ @retval EFI_NOT_FOUND Cannot find the 'PlatDriOver' NV variable
+ @retval EFI_VOLUME_CORRUPTED The found NV variable is corrupted
+
+**/
+EFI_STATUS
+EFIAPI
+InitOverridesMapping (
+ OUT LIST_ENTRY *MappingDataBase
+ )
+{
+ UINTN BufferSize;
+ VOID *VariableBuffer;
+ UINT8 *VariableIndex;
+ UINTN VariableNum;
+ CHAR16 OverrideVariableName[40];
+ UINT32 NotEnd;
+ UINT32 DriverNumber;
+ PLATFORM_OVERRIDE_ITEM *OverrideItem;
+ DRIVER_IMAGE_INFO *DriverImageInfo;
+ BOOLEAN Corrupted;
+ UINT32 Signature;
+ EFI_DEVICE_PATH_PROTOCOL *ControllerDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DriverDevicePath;
+ UINTN Index;
+
+ if (MappingDataBase == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check the environment variable(s) that contain the override mappings .
+ //
+ VariableBuffer = GetVariableAndSize (L"PlatDriOver", &gEfiCallerIdGuid, &BufferSize);
+ ASSERT ((UINTN) VariableBuffer % sizeof(UINTN) == 0);
+ if (VariableBuffer == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Traverse all variables.
+ //
+ VariableNum = 1;
+ Corrupted = FALSE;
+ NotEnd = 0;
+ do {
+ VariableIndex = VariableBuffer;
+ if (VariableIndex + sizeof (UINT32) > (UINT8 *) VariableBuffer + BufferSize) {
+ Corrupted = TRUE;
+ } else {
+ //
+ // End flag
+ //
+ NotEnd = *(UINT32*) VariableIndex;
+ }
+ //
+ // Traverse the entries containing the mapping that Controller Device Path
+ // to a set of Driver Device Paths within this variable.
+ //
+ VariableIndex = VariableIndex + sizeof (UINT32);
+ while (VariableIndex < ((UINT8 *)VariableBuffer + BufferSize)) {
+ //
+ // Check signature of this entry
+ //
+ if (VariableIndex + sizeof (UINT32) > (UINT8 *) VariableBuffer + BufferSize) {
+ Corrupted = TRUE;
+ break;
+ }
+ Signature = *(UINT32 *) VariableIndex;
+ if (Signature != PLATFORM_OVERRIDE_ITEM_SIGNATURE) {
+ Corrupted = TRUE;
+ break;
+ }
+ //
+ // Create PLATFORM_OVERRIDE_ITEM for this mapping
+ //
+ OverrideItem = AllocateZeroPool (sizeof (PLATFORM_OVERRIDE_ITEM));
+ ASSERT (OverrideItem != NULL);
+ OverrideItem->Signature = PLATFORM_OVERRIDE_ITEM_SIGNATURE;
+ InitializeListHead (&OverrideItem->DriverInfoList);
+ VariableIndex = VariableIndex + sizeof (UINT32);
+ //
+ // Get DriverNum
+ //
+ if (VariableIndex + sizeof (UINT32) >= (UINT8 *) VariableBuffer + BufferSize) {
+ Corrupted = TRUE;
+ break;
+ }
+ DriverNumber = *(UINT32*) VariableIndex;
+ OverrideItem->DriverInfoNum = DriverNumber;
+ VariableIndex = VariableIndex + sizeof (UINT32);
+ //
+ // Get ControllerDevicePath[]
+ //
+ ControllerDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) VariableIndex;
+ OverrideItem->ControllerDevicePath = DuplicateDevicePath (ControllerDevicePath);
+ VariableIndex = VariableIndex + GetDevicePathSize (ControllerDevicePath);
+ //
+ // Align the VariableIndex since the controller device path may not be aligned, refer to the SaveOverridesMapping()
+ //
+ VariableIndex += ((sizeof(UINT32) - ((UINTN) (VariableIndex))) & (sizeof(UINT32) - 1));
+ //
+ // Check buffer overflow.
+ //
+ if ((OverrideItem->ControllerDevicePath == NULL) || (VariableIndex < (UINT8 *) ControllerDevicePath) ||
+ (VariableIndex > (UINT8 *) VariableBuffer + BufferSize)) {
+ Corrupted = TRUE;
+ break;
+ }
+
+ //
+ // Get all DriverImageDevicePath[]
+ //
+ for (Index = 0; Index < DriverNumber; Index++) {
+ //
+ // Create DRIVER_IMAGE_INFO for this DriverDevicePath[]
+ //
+ DriverImageInfo = AllocateZeroPool (sizeof (DRIVER_IMAGE_INFO));
+ ASSERT (DriverImageInfo != NULL);
+ DriverImageInfo->Signature = DRIVER_IMAGE_INFO_SIGNATURE;
+
+ DriverDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) VariableIndex;
+ DriverImageInfo->DriverImagePath = DuplicateDevicePath (DriverDevicePath);
+ VariableIndex = VariableIndex + GetDevicePathSize (DriverDevicePath);
+ //
+ // Align the VariableIndex since the driver image device path may not be aligned, refer to the SaveOverridesMapping()
+ //
+ VariableIndex += ((sizeof(UINT32) - ((UINTN) (VariableIndex))) & (sizeof(UINT32) - 1));
+
+ InsertTailList (&OverrideItem->DriverInfoList, &DriverImageInfo->Link);
+
+ //
+ // Check buffer overflow
+ //
+ if ((DriverImageInfo->DriverImagePath == NULL) || (VariableIndex < (UINT8 *) DriverDevicePath) ||
+ (VariableIndex < (UINT8 *) VariableBuffer + BufferSize)) {
+ Corrupted = TRUE;
+ break;
+ }
+ }
+ InsertTailList (MappingDataBase, &OverrideItem->Link);
+ if (Corrupted) {
+ break;
+ }
+ }
+
+ FreePool (VariableBuffer);
+ if (Corrupted) {
+ FreeMappingDatabase (MappingDataBase);
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ //
+ // If there are additional variables (PlatDriOver1, PlatDriOver2, PlatDriOver3.....), get them.
+ // NotEnd indicates whether current variable is the end variable.
+ //
+ if (NotEnd != 0) {
+ UnicodeSPrint (OverrideVariableName, sizeof (OverrideVariableName), L"PlatDriOver%d", VariableNum++);
+ VariableBuffer = GetVariableAndSize (OverrideVariableName, &gEfiCallerIdGuid, &BufferSize);
+ ASSERT ((UINTN) VariableBuffer % sizeof(UINTN) == 0);
+ if (VariableBuffer == NULL) {
+ FreeMappingDatabase (MappingDataBase);
+ return EFI_VOLUME_CORRUPTED;
+ }
+ }
+
+ } while (NotEnd != 0);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Calculate the needed size in NV variable for recording a specific PLATFORM_OVERRIDE_ITEM info.
+
+ @param OverrideItemListIndex Pointer to the list of a specific PLATFORM_OVERRIDE_ITEM
+
+ @return The needed size number
+
+**/
+UINTN
+EFIAPI
+GetOneItemNeededSize (
+ IN LIST_ENTRY *OverrideItemListIndex
+ )
+{
+ UINTN NeededSize;
+ PLATFORM_OVERRIDE_ITEM *OverrideItem;
+ LIST_ENTRY *ImageInfoListIndex;
+ DRIVER_IMAGE_INFO *DriverImageInfo;
+ UINTN DevicePathSize;
+
+ NeededSize = 0;
+ OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);
+ NeededSize += sizeof (UINT32); //UINT32 SIGNATURE;
+ NeededSize += sizeof (UINT32); //UINT32 DriverNum;
+ DevicePathSize = GetDevicePathSize (OverrideItem->ControllerDevicePath);
+ NeededSize += DevicePathSize; // ControllerDevicePath
+ //
+ // Align the controller device path
+ //
+ NeededSize += ((sizeof(UINT32) - DevicePathSize) & (sizeof(UINT32) - 1));
+ //
+ // Traverse the Driver Info List of this Override Item
+ //
+ ImageInfoListIndex = GetFirstNode (&OverrideItem->DriverInfoList);
+ while (!IsNull (&OverrideItem->DriverInfoList, ImageInfoListIndex)) {
+ DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);
+ DevicePathSize = GetDevicePathSize (DriverImageInfo->DriverImagePath);
+ NeededSize += DevicePathSize; //DriverDevicePath
+ //
+ // Align the driver image device path
+ //
+ NeededSize += ((sizeof(UINT32) - DevicePathSize) & (sizeof(UINT32) - 1));
+ ImageInfoListIndex = GetNextNode (&OverrideItem->DriverInfoList, ImageInfoListIndex);
+ }
+
+ return NeededSize;
+}
+
+/**
+ Deletes all environment variable(s) that contain the override mappings from Controller Device Path to
+ a set of Driver Device Paths.
+
+ @retval EFI_SUCCESS Delete all variable(s) successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+DeleteOverridesVariables (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VOID *VariableBuffer;
+ UINTN VariableNum;
+ UINTN BufferSize;
+ UINTN Index;
+ CHAR16 OverrideVariableName[40];
+
+ //
+ // Get environment variable(s) number
+ //
+ VariableNum = 0;
+ VariableBuffer = GetVariableAndSize (L"PlatDriOver", &gEfiCallerIdGuid, &BufferSize);
+ VariableNum++;
+ if (VariableBuffer == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Check NotEnd to get all PlatDriOverX variable(s)
+ //
+ while ((VariableBuffer != NULL) && ((*(UINT32*)VariableBuffer) != 0)) {
+ FreePool (VariableBuffer);
+ UnicodeSPrint (OverrideVariableName, sizeof (OverrideVariableName), L"PlatDriOver%d", VariableNum);
+ VariableBuffer = GetVariableAndSize (OverrideVariableName, &gEfiCallerIdGuid, &BufferSize);
+ VariableNum++;
+ }
+
+ //
+ // Delete PlatDriOver and all additional variables, if exist.
+ //
+ Status = gRT->SetVariable (
+ L"PlatDriOver",
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ 0,
+ NULL
+ );
+ ASSERT (!EFI_ERROR (Status));
+ for (Index = 1; Index < VariableNum; Index++) {
+ UnicodeSPrint (OverrideVariableName, sizeof (OverrideVariableName), L"PlatDriOver%d", Index);
+ Status = gRT->SetVariable (
+ OverrideVariableName,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ 0,
+ NULL
+ );
+ ASSERT (!EFI_ERROR (Status));
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Save the memory mapping database into NV environment variable(s).
+
+ @param MappingDataBase Mapping database list entry pointer
+
+ @retval EFI_SUCCESS Save memory mapping database successfully
+ @retval EFI_INVALID_PARAMETER MappingDataBase pointer is null
+
+**/
+EFI_STATUS
+EFIAPI
+SaveOverridesMapping (
+ IN LIST_ENTRY *MappingDataBase
+ )
+{
+ EFI_STATUS Status;
+ VOID *VariableBuffer;
+ UINT8 *VariableIndex;
+ UINTN NumIndex;
+ CHAR16 OverrideVariableName[40];
+ UINT32 NotEnd;
+ PLATFORM_OVERRIDE_ITEM *OverrideItem;
+ DRIVER_IMAGE_INFO *DriverImageInfo;
+ LIST_ENTRY *OverrideItemListIndex;
+ LIST_ENTRY *ItemIndex;
+ LIST_ENTRY *ImageInfoListIndex;
+ UINTN VariableNeededSize;
+ UINT64 MaximumVariableStorageSize;
+ UINT64 RemainingVariableStorageSize;
+ UINT64 MaximumVariableSize;
+ UINTN OneItemNeededSize;
+
+ if (MappingDataBase == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IsListEmpty (MappingDataBase)) {
+ Status = DeleteOverridesVariables ();
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get the the maximum size of an individual EFI variable in current system
+ //
+ gRT->QueryVariableInfo (
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ &MaximumVariableStorageSize,
+ &RemainingVariableStorageSize,
+ &MaximumVariableSize
+ );
+
+ NumIndex = 0;
+ OverrideItemListIndex = GetFirstNode (MappingDataBase);
+ while (!IsNull (MappingDataBase, OverrideItemListIndex)) {
+ //
+ // Try to find the most proper variable size which <= MaximumVariableSize,
+ // but can contain mapping info as much as possible
+ //
+ VariableNeededSize = sizeof (UINT32); // NotEnd;
+ ItemIndex = OverrideItemListIndex;
+ NotEnd = FALSE;
+ //
+ // Traverse all PLATFORM_OVERRIDE_ITEMs and get the total size.
+ //
+ while (!IsNull (MappingDataBase, ItemIndex)) {
+ OneItemNeededSize = GetOneItemNeededSize (ItemIndex);
+ //
+ // If the total size exceeds the MaximumVariableSize, then we must use
+ // multiple variables.
+ //
+ if ((VariableNeededSize +
+ OneItemNeededSize +
+ StrSize (L"PlatDriOver ")
+ ) >= MaximumVariableSize
+ ) {
+ NotEnd = TRUE;
+ break;
+ }
+
+ VariableNeededSize += OneItemNeededSize;
+ ItemIndex = GetNextNode (MappingDataBase, ItemIndex);
+ }
+
+ if (NotEnd != 0) {
+ if (VariableNeededSize == sizeof (UINT32)) {
+ //
+ // If an individual EFI variable cannot contain a single Item, return error
+ //
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ //
+ // VariableNeededSize is the most proper variable size, allocate variable buffer
+ // ItemIndex now points to the next PLATFORM_OVERRIDE_ITEM which is not covered by VariableNeededSize
+ //
+ VariableBuffer = AllocateZeroPool (VariableNeededSize);
+ ASSERT (VariableBuffer != NULL);
+ ASSERT ((UINTN) VariableBuffer % sizeof(UINTN) == 0);
+
+ //
+ // Fill the variable buffer according to MappingDataBase
+ //
+ VariableIndex = VariableBuffer;
+ *(UINT32 *) VariableIndex = NotEnd;
+ VariableIndex += sizeof (UINT32); // pass NotEnd
+ //
+ // ItemIndex points to the next PLATFORM_OVERRIDE_ITEM which is not covered by VariableNeededSize
+ //
+ while (OverrideItemListIndex != ItemIndex){
+ *(UINT32 *) VariableIndex = PLATFORM_OVERRIDE_ITEM_SIGNATURE;
+ VariableIndex += sizeof (UINT32); // pass SIGNATURE
+
+ OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);
+ *(UINT32 *) VariableIndex = OverrideItem->DriverInfoNum;
+ VariableIndex += sizeof (UINT32); // pass DriverNum
+
+ CopyMem (VariableIndex, OverrideItem->ControllerDevicePath, GetDevicePathSize (OverrideItem->ControllerDevicePath));
+ VariableIndex += GetDevicePathSize (OverrideItem->ControllerDevicePath); // pass ControllerDevicePath
+
+ //
+ // Align the VariableIndex since the controller device path may not be aligned
+ //
+ VariableIndex += ((sizeof(UINT32) - ((UINTN) (VariableIndex))) & (sizeof(UINT32) - 1));
+ //
+ // Save the Driver Info List of this PLATFORM_OVERRIDE_ITEM
+ //
+ ImageInfoListIndex = GetFirstNode (&OverrideItem->DriverInfoList);
+ while (!IsNull (&OverrideItem->DriverInfoList, ImageInfoListIndex)) {
+ DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);
+ CopyMem (VariableIndex, DriverImageInfo->DriverImagePath, GetDevicePathSize (DriverImageInfo->DriverImagePath));
+ VariableIndex += GetDevicePathSize (DriverImageInfo->DriverImagePath); // pass DriverImageDevicePath
+ //
+ // Align the VariableIndex since the driver image device path may not be aligned
+ //
+ VariableIndex += ((sizeof(UINT32) - ((UINTN) (VariableIndex))) & (sizeof(UINT32) - 1));
+ ImageInfoListIndex = GetNextNode (&OverrideItem->DriverInfoList, ImageInfoListIndex);
+ }
+
+ OverrideItemListIndex = GetNextNode (MappingDataBase, OverrideItemListIndex);
+ }
+
+ ASSERT (((UINTN)VariableIndex - (UINTN)VariableBuffer) == VariableNeededSize);
+
+ if (NumIndex == 0) {
+ UnicodeSPrint (OverrideVariableName, sizeof (OverrideVariableName), L"PlatDriOver");
+ } else {
+ UnicodeSPrint (OverrideVariableName, sizeof (OverrideVariableName), L"PlatDriOver%d", NumIndex );
+ }
+
+ Status = gRT->SetVariable (
+ OverrideVariableName,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ VariableNeededSize,
+ VariableBuffer
+ );
+ FreePool (VariableBuffer);
+
+ if (EFI_ERROR (Status)) {
+ if (NumIndex > 0) {
+ //
+ // Delete all PlatDriOver variables when full mapping can't be set.
+ //
+ DeleteOverridesVariables ();
+ }
+ return Status;
+ }
+
+ NumIndex ++;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the first Binding protocol which has the specific image handle.
+
+ @param ImageHandle The Image handle
+ @param BindingHandle The BindingHandle of the found Driver Binding protocol.
+ If Binding protocol is not found, it is set to NULL.
+
+ @return Pointer into the Binding Protocol interface
+ @retval NULL The parameter is not valid or the binding protocol is not found.
+
+**/
+EFI_DRIVER_BINDING_PROTOCOL *
+EFIAPI
+GetBindingProtocolFromImageHandle (
+ IN EFI_HANDLE ImageHandle,
+ OUT EFI_HANDLE *BindingHandle
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN DriverBindingHandleCount;
+ EFI_HANDLE *DriverBindingHandleBuffer;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBindingInterface;
+
+ if (BindingHandle == NULL || ImageHandle == NULL) {
+ return NULL;
+ }
+ //
+ // Get all drivers which support driver binding protocol
+ //
+ DriverBindingHandleCount = 0;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiDriverBindingProtocolGuid,
+ NULL,
+ &DriverBindingHandleCount,
+ &DriverBindingHandleBuffer
+ );
+ if (EFI_ERROR (Status) || (DriverBindingHandleCount == 0)) {
+ return NULL;
+ }
+
+ for (Index = 0; Index < DriverBindingHandleCount; Index++) {
+ DriverBindingInterface = NULL;
+ Status = gBS->OpenProtocol (
+ DriverBindingHandleBuffer[Index],
+ &gEfiDriverBindingProtocolGuid,
+ (VOID **) &DriverBindingInterface,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if (DriverBindingInterface->ImageHandle == ImageHandle) {
+ *BindingHandle = DriverBindingHandleBuffer[Index];
+ FreePool (DriverBindingHandleBuffer);
+ return DriverBindingInterface;
+ }
+ }
+
+ //
+ // If no Driver Binding Protocol instance is found
+ //
+ FreePool (DriverBindingHandleBuffer);
+ *BindingHandle = NULL;
+ return NULL;
+}
+
+/**
+ Return the current TPL.
+
+ @return Current TPL
+
+**/
+EFI_TPL
+GetCurrentTpl (
+ VOID
+ )
+{
+ EFI_TPL Tpl;
+
+ Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+ gBS->RestoreTPL (Tpl);
+
+ return Tpl;
+}
+
+
+/**
+ Retrieves the image handle of the platform override driver for a controller in
+ the system from the memory mapping database.
+
+ @param ControllerHandle The device handle of the controller to check if
+ a driver override exists.
+ @param DriverImageHandle On input, the previously returnd driver image handle.
+ On output, a pointer to the next driver handle.
+ Passing in a pointer to NULL, will return the
+ first driver handle for ControllerHandle.
+ @param MappingDataBase Mapping database list entry pointer
+ @param CallerImageHandle The caller driver's image handle, for
+ UpdateFvFileDevicePath use.
+
+ @retval EFI_INVALID_PARAMETER The handle specified by ControllerHandle is not
+ a valid handle. Or DriverImagePath is not a
+ device path that was returned on a previous call
+ to GetDriverPath().
+ @retval EFI_NOT_FOUND A driver override for ControllerHandle was not
+ found.
+ @retval EFI_UNSUPPORTED The operation is not supported.
+ @retval EFI_SUCCESS The driver override for ControllerHandle was
+ returned in DriverImagePath.
+
+**/
+EFI_STATUS
+EFIAPI
+GetDriverFromMapping (
+ IN EFI_HANDLE ControllerHandle,
+ IN OUT EFI_HANDLE *DriverImageHandle,
+ IN LIST_ENTRY *MappingDataBase,
+ IN EFI_HANDLE CallerImageHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *ControllerDevicePath;
+ BOOLEAN ControllerFound;
+ BOOLEAN ImageFound;
+ EFI_HANDLE *ImageHandleBuffer;
+ UINTN ImageHandleCount;
+ UINTN Index;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
+ EFI_HANDLE DriverBindingHandle;
+ BOOLEAN FoundLastReturned;
+ PLATFORM_OVERRIDE_ITEM *OverrideItem;
+ DRIVER_IMAGE_INFO *DriverImageInfo;
+ LIST_ENTRY *OverrideItemListIndex;
+ LIST_ENTRY *ImageInfoListIndex;
+ EFI_DEVICE_PATH_PROTOCOL *TempDriverImagePath;
+ EFI_HANDLE ImageHandle;
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath;
+ EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *BusSpecificDriverOverride;
+ UINTN DevicePathSize;
+
+ //
+ // Check that ControllerHandle is a valid handle
+ //
+ if (ControllerHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Get the device path of ControllerHandle
+ //
+ Status = gBS->HandleProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ControllerDevicePath
+ );
+ if (EFI_ERROR (Status) || ControllerDevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Search ControllerDevicePath in MappingDataBase
+ //
+ OverrideItem = NULL;
+ ControllerFound = FALSE;
+ DevicePathSize = GetDevicePathSize (ControllerDevicePath);
+
+ OverrideItemListIndex = GetFirstNode (MappingDataBase);
+ while (!IsNull (MappingDataBase, OverrideItemListIndex)) {
+ OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);
+ if (DevicePathSize == GetDevicePathSize (OverrideItem->ControllerDevicePath)) {
+ if (CompareMem (
+ ControllerDevicePath,
+ OverrideItem->ControllerDevicePath,
+ DevicePathSize
+ ) == 0
+ ) {
+ ControllerFound = TRUE;
+ break;
+ }
+ }
+ OverrideItemListIndex = GetNextNode (MappingDataBase, OverrideItemListIndex);
+ }
+
+ if (!ControllerFound) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Passing in a pointer to NULL, will return the first driver device path for ControllerHandle.
+ // Check whether the driverImagePath is not a device path that was returned on a previous call to GetDriverPath().
+ //
+ if (*DriverImageHandle != NULL) {
+ if (*DriverImageHandle != OverrideItem->LastReturnedImageHandle) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // The GetDriverPath() may be called recursively, because it use ConnectDevicePath() internally,
+ // so should check whether there is a dead loop.
+ // Here use a controller device path stack to record all processed controller device path during a GetDriverPath() call,
+ // and check the controller device path whether appear again during the GetDriverPath() call.
+ //
+ if (CheckExistInStack (OverrideItem->ControllerDevicePath)) {
+ //
+ // There is a dependency dead loop if the ControllerDevicePath appear in stack twice
+ //
+ return EFI_UNSUPPORTED;
+ }
+ PushDevPathStack (OverrideItem->ControllerDevicePath);
+
+ //
+ // Check every override driver, try to load and start them
+ //
+ ImageInfoListIndex = GetFirstNode (&OverrideItem->DriverInfoList);
+ while (!IsNull (&OverrideItem->DriverInfoList, ImageInfoListIndex)) {
+ DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);
+ if (DriverImageInfo->ImageHandle == NULL) {
+ //
+ // Skip if the image is unloadable or unstartable
+ //
+ if ((!DriverImageInfo->UnLoadable) && ((!DriverImageInfo->UnStartable))) {
+ TempDriverImagePath = DriverImageInfo->DriverImagePath;
+ //
+ // If the image device path contains an FV node, check the FV file device path is valid.
+ // If it is invalid, try to return the valid device path.
+ // FV address maybe changes for memory layout adjust from time to time,
+ // use this function could promise the FV file device path is right.
+ //
+ Status = UpdateFvFileDevicePath (&TempDriverImagePath, NULL, CallerImageHandle);
+ if (!EFI_ERROR (Status)) {
+ FreePool (DriverImageInfo->DriverImagePath);
+ DriverImageInfo->DriverImagePath = TempDriverImagePath;
+ }
+ //
+ // Get all Loaded Image protocol to check whether the driver image has been loaded and started
+ //
+ ImageFound = FALSE;
+ ImageHandleCount = 0;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiLoadedImageProtocolGuid,
+ NULL,
+ &ImageHandleCount,
+ &ImageHandleBuffer
+ );
+ if (EFI_ERROR (Status) || (ImageHandleCount == 0)) {
+ return EFI_NOT_FOUND;
+ }
+
+ for(Index = 0; Index < ImageHandleCount; Index ++) {
+ //
+ // Get the EFI Loaded Image Device Path Protocol
+ //
+ LoadedImageDevicePath = NULL;
+ Status = gBS->HandleProtocol (
+ ImageHandleBuffer[Index],
+ &gEfiLoadedImageDevicePathProtocolGuid,
+ (VOID **) &LoadedImageDevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Maybe not all EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL existed.
+ //
+ continue;
+ }
+
+ DevicePathSize = GetDevicePathSize (DriverImageInfo->DriverImagePath);
+ if (DevicePathSize == GetDevicePathSize (LoadedImageDevicePath)) {
+ if (CompareMem (
+ DriverImageInfo->DriverImagePath,
+ LoadedImageDevicePath,
+ GetDevicePathSize (LoadedImageDevicePath)
+ ) == 0
+ ) {
+ ImageFound = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (ImageFound) {
+ //
+ // Find its related driver binding protocol
+ // Driver binding handle may be different with its driver's Image Handle.
+ //
+ DriverBindingHandle = NULL;
+ DriverBinding = GetBindingProtocolFromImageHandle (
+ ImageHandleBuffer[Index],
+ &DriverBindingHandle
+ );
+ ASSERT (DriverBinding != NULL);
+ DriverImageInfo->ImageHandle = ImageHandleBuffer[Index];
+ } else if (GetCurrentTpl() <= TPL_CALLBACK){
+ //
+ // The driver image has not been loaded and started. Try to load and start it now.
+ // Try to connect all device in the driver image path.
+ //
+ // Note: LoadImage() and StartImage() should be called under CALLBACK TPL in theory, but
+ // since many device need to be connected in CALLBACK level environment( e.g. Usb devices )
+ // and the Fat and Patition driver can endure executing in CALLBACK level in fact, so here permit
+ // to use LoadImage() and StartImage() in CALLBACK TPL.
+ //
+ Status = ConnectDevicePath (DriverImageInfo->DriverImagePath);
+ //
+ // check whether it points to a PCI Option Rom image,
+ // and try to use bus override protocol to get its first option rom image driver
+ //
+ TempDriverImagePath = DriverImageInfo->DriverImagePath;
+ gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &TempDriverImagePath, &Handle);
+ //
+ // Get the Bus Specific Driver Override Protocol instance on the Controller Handle
+ //
+ Status = gBS->HandleProtocol(
+ Handle,
+ &gEfiBusSpecificDriverOverrideProtocolGuid,
+ (VOID **) &BusSpecificDriverOverride
+ );
+ if (!EFI_ERROR (Status) && (BusSpecificDriverOverride != NULL)) {
+ ImageHandle = NULL;
+ Status = BusSpecificDriverOverride->GetDriver (
+ BusSpecificDriverOverride,
+ &ImageHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Find its related driver binding protocol
+ // Driver binding handle may be different with its driver's Image handle
+ //
+ DriverBindingHandle = NULL;
+ DriverBinding = GetBindingProtocolFromImageHandle (
+ ImageHandle,
+ &DriverBindingHandle
+ );
+ ASSERT (DriverBinding != NULL);
+ DriverImageInfo->ImageHandle = ImageHandle;
+ }
+ }
+ //
+ // Skip if any device cannot be connected now, future passes through GetDriver() may be able to load that driver.
+ // Only file path media or FwVol Device Path Node remain if all device is connected
+ //
+ TempDriverImagePath = DriverImageInfo->DriverImagePath;
+ gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &TempDriverImagePath, &Handle);
+ if (((DevicePathType (TempDriverImagePath) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (TempDriverImagePath) == MEDIA_FILEPATH_DP)) ||
+ (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) TempDriverImagePath) != NULL)
+ ) {
+ //
+ // Try to load the driver
+ //
+ TempDriverImagePath = DriverImageInfo->DriverImagePath;
+ Status = gBS->LoadImage (
+ FALSE,
+ CallerImageHandle,
+ TempDriverImagePath,
+ NULL,
+ 0,
+ &ImageHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Try to start the driver
+ //
+ Status = gBS->StartImage (ImageHandle, NULL, NULL);
+ if (EFI_ERROR (Status)){
+ DriverImageInfo->UnStartable = TRUE;
+ DriverImageInfo->ImageHandle = NULL;
+ } else {
+ //
+ // Find its related driver binding protocol
+ // Driver binding handle may be different with its driver's Image handle
+ //
+ DriverBindingHandle = NULL;
+ DriverBinding = GetBindingProtocolFromImageHandle (
+ ImageHandle,
+ &DriverBindingHandle
+ );
+ ASSERT (DriverBinding != NULL);
+ DriverImageInfo->ImageHandle = ImageHandle;
+ }
+ } else {
+ //
+ // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created
+ // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.
+ // If the caller doesn't have the option to defer the execution of an image, we should
+ // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak.
+ //
+ if (Status == EFI_SECURITY_VIOLATION) {
+ gBS->UnloadImage (ImageHandle);
+ }
+ DriverImageInfo->UnLoadable = TRUE;
+ DriverImageInfo->ImageHandle = NULL;
+ }
+ }
+ }
+ FreePool (ImageHandleBuffer);
+ }
+ }
+ ImageInfoListIndex = GetNextNode (&OverrideItem->DriverInfoList, ImageInfoListIndex);
+ }
+ //
+ // Finish try to load and start the override driver of a controller, popup the controller's device path
+ //
+ PopDevPathStack (NULL);
+
+ //
+ // return the DriverImageHandle for ControllerHandle
+ //
+ FoundLastReturned = FALSE;
+ ImageInfoListIndex = GetFirstNode (&OverrideItem->DriverInfoList);
+ while (!IsNull (&OverrideItem->DriverInfoList, ImageInfoListIndex)) {
+ DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);
+ if (DriverImageInfo->ImageHandle != NULL) {
+ if ((*DriverImageHandle == NULL) || FoundLastReturned) {
+ //
+ // If DriverImageHandle is NULL, then we just need to return the first driver.
+ // If FoundLastReturned, this means we have just encountered the previously returned driver.
+ // For both cases, we just return the image handle of this driver.
+ //
+ OverrideItem->LastReturnedImageHandle = DriverImageInfo->ImageHandle;
+ *DriverImageHandle = DriverImageInfo->ImageHandle;
+ return EFI_SUCCESS;
+ } else if (*DriverImageHandle == DriverImageInfo->ImageHandle){
+ //
+ // We have found the previously returned driver.
+ //
+ FoundLastReturned = TRUE;
+ }
+ }
+ ImageInfoListIndex = GetNextNode (&OverrideItem->DriverInfoList, ImageInfoListIndex);
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Check mapping database whether already has the mapping info which
+ records the input Controller to input DriverImage.
+
+ @param ControllerDevicePath The controller device path is to be check.
+ @param DriverImageDevicePath The driver image device path is to be check.
+ @param MappingDataBase Mapping database list entry pointer
+ @param DriverInfoNum the controller's total override driver number
+ @param DriverImageNO The driver order number for the input DriverImage.
+ If the DriverImageDevicePath is NULL, DriverImageNO is not set.
+
+ @retval EFI_INVALID_PARAMETER ControllerDevicePath or MappingDataBase is NULL.
+ @retval EFI_NOT_FOUND ControllerDevicePath is not found in MappingDataBase or
+ DriverImageDevicePath is not found in the found DriverImage Info list.
+ @retval EFI_SUCCESS The controller's total override driver number and
+ input DriverImage's order number is correctly return.
+**/
+EFI_STATUS
+EFIAPI
+CheckMapping (
+ IN EFI_DEVICE_PATH_PROTOCOL *ControllerDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *DriverImageDevicePath OPTIONAL,
+ IN LIST_ENTRY *MappingDataBase,
+ OUT UINT32 *DriverInfoNum OPTIONAL,
+ OUT UINT32 *DriverImageNO OPTIONAL
+ )
+{
+ LIST_ENTRY *OverrideItemListIndex;
+ PLATFORM_OVERRIDE_ITEM *OverrideItem;
+ LIST_ENTRY *ImageInfoListIndex;
+ DRIVER_IMAGE_INFO *DriverImageInfo;
+ BOOLEAN Found;
+ UINT32 ImageNO;
+ UINTN DevicePathSize;
+
+ if (ControllerDevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (MappingDataBase == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Search ControllerDevicePath in MappingDataBase
+ //
+ Found = FALSE;
+ OverrideItem = NULL;
+ OverrideItemListIndex = GetFirstNode (MappingDataBase);
+ while (!IsNull (MappingDataBase, OverrideItemListIndex)) {
+ OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);
+ DevicePathSize = GetDevicePathSize (ControllerDevicePath);
+ if (DevicePathSize == GetDevicePathSize (OverrideItem->ControllerDevicePath)) {
+ if (CompareMem (
+ ControllerDevicePath,
+ OverrideItem->ControllerDevicePath,
+ DevicePathSize
+ ) == 0
+ ) {
+ Found = TRUE;
+ break;
+ }
+ }
+ OverrideItemListIndex = GetNextNode (MappingDataBase, OverrideItemListIndex);
+ }
+
+ if (!Found) {
+ //
+ // ControllerDevicePath is not in MappingDataBase
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ ASSERT (OverrideItem->DriverInfoNum != 0);
+ if (DriverInfoNum != NULL) {
+ *DriverInfoNum = OverrideItem->DriverInfoNum;
+ }
+
+ //
+ // If DriverImageDevicePath is NULL, skip checking DriverImageDevicePath
+ // in the controller's Driver Image Info List
+ //
+ if (DriverImageDevicePath == NULL) {
+ return EFI_SUCCESS;
+ }
+ //
+ // return the DriverImageHandle for ControllerHandle
+ //
+ ImageNO = 0;
+ Found = FALSE;
+ ImageInfoListIndex = GetFirstNode (&OverrideItem->DriverInfoList);
+ while (!IsNull (&OverrideItem->DriverInfoList, ImageInfoListIndex)) {
+ DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);
+ ImageNO++;
+ DevicePathSize = GetDevicePathSize (DriverImageDevicePath);
+ if (DevicePathSize == GetDevicePathSize (DriverImageInfo->DriverImagePath)) {
+ if (CompareMem (
+ DriverImageDevicePath,
+ DriverImageInfo->DriverImagePath,
+ GetDevicePathSize (DriverImageInfo->DriverImagePath)
+ ) == 0
+ ) {
+ Found = TRUE;
+ break;
+ }
+ }
+ ImageInfoListIndex = GetNextNode (&OverrideItem->DriverInfoList, ImageInfoListIndex);
+ }
+
+ if (!Found) {
+ //
+ // DriverImageDevicePath is not found in the controller's Driver Image Info List
+ //
+ return EFI_NOT_FOUND;
+ } else {
+ if (DriverImageNO != NULL) {
+ *DriverImageNO = ImageNO;
+ }
+ return EFI_SUCCESS;
+ }
+}
+
+
+/**
+ Insert a driver image as a controller's override driver into the mapping database.
+ The driver image's order number is indicated by DriverImageNO.
+
+ @param ControllerDevicePath The controller device path need to add a
+ override driver image item
+ @param DriverImageDevicePath The driver image device path need to be insert
+ @param MappingDataBase Mapping database list entry pointer
+ @param DriverImageNO The inserted order number. If this number is taken,
+ the larger available number will be used.
+
+ @retval EFI_INVALID_PARAMETER ControllerDevicePath is NULL, or DriverImageDevicePath is NULL
+ or MappingDataBase is NULL
+ @retval EFI_ALREADY_STARTED The input Controller to input DriverImage has been
+ recorded into the mapping database.
+ @retval EFI_SUCCESS The Controller and DriverImage are inserted into
+ the mapping database successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+InsertDriverImage (
+ IN EFI_DEVICE_PATH_PROTOCOL *ControllerDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *DriverImageDevicePath,
+ IN LIST_ENTRY *MappingDataBase,
+ IN UINT32 DriverImageNO
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *OverrideItemListIndex;
+ PLATFORM_OVERRIDE_ITEM *OverrideItem;
+ LIST_ENTRY *ImageInfoListIndex;
+ DRIVER_IMAGE_INFO *DriverImageInfo;
+ BOOLEAN Found;
+ UINT32 ImageNO;
+ UINTN DevicePathSize;
+
+ if (ControllerDevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (DriverImageDevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (MappingDataBase == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If the driver is already in the controller's Driver Image Info List,
+ // just return EFI_ALREADY_STARTED.
+ //
+ Status = CheckMapping (
+ ControllerDevicePath,
+ DriverImageDevicePath,
+ MappingDataBase,
+ NULL,
+ NULL
+ );
+ if (Status == EFI_SUCCESS) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ //
+ // Search the input ControllerDevicePath in MappingDataBase
+ //
+ Found = FALSE;
+ OverrideItem = NULL;
+ OverrideItemListIndex = GetFirstNode (MappingDataBase);
+ while (!IsNull (MappingDataBase, OverrideItemListIndex)) {
+ OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);
+ DevicePathSize = GetDevicePathSize (ControllerDevicePath);
+ if (DevicePathSize == GetDevicePathSize (OverrideItem->ControllerDevicePath)) {
+ if (CompareMem (
+ ControllerDevicePath,
+ OverrideItem->ControllerDevicePath,
+ DevicePathSize
+ ) == 0
+ ) {
+ Found = TRUE;
+ break;
+ }
+ }
+ OverrideItemListIndex = GetNextNode (MappingDataBase, OverrideItemListIndex);
+ }
+ //
+ // If cannot find, this is a new controller item
+ // Add the Controller related PLATFORM_OVERRIDE_ITEM structrue in mapping data base
+ //
+ if (!Found) {
+ OverrideItem = AllocateZeroPool (sizeof (PLATFORM_OVERRIDE_ITEM));
+ ASSERT (OverrideItem != NULL);
+ OverrideItem->Signature = PLATFORM_OVERRIDE_ITEM_SIGNATURE;
+ OverrideItem->ControllerDevicePath = DuplicateDevicePath (ControllerDevicePath);
+ InitializeListHead (&OverrideItem->DriverInfoList);
+ InsertTailList (MappingDataBase, &OverrideItem->Link);
+ }
+
+ //
+ // Prepare the driver image related DRIVER_IMAGE_INFO structure.
+ //
+ DriverImageInfo = AllocateZeroPool (sizeof (DRIVER_IMAGE_INFO));
+ ASSERT (DriverImageInfo != NULL);
+ DriverImageInfo->Signature = DRIVER_IMAGE_INFO_SIGNATURE;
+ DriverImageInfo->DriverImagePath = DuplicateDevicePath (DriverImageDevicePath);
+ //
+ // Find the driver image wanted order location
+ //
+ ImageNO = 0;
+ Found = FALSE;
+ ImageInfoListIndex = GetFirstNode (&OverrideItem->DriverInfoList);
+ while (!IsNull (&OverrideItem->DriverInfoList, ImageInfoListIndex)) {
+ if (ImageNO == (DriverImageNO - 1)) {
+ //
+ // find the wanted order location, insert it
+ //
+ InsertTailList (ImageInfoListIndex, &DriverImageInfo->Link);
+ OverrideItem->DriverInfoNum ++;
+ Found = TRUE;
+ break;
+ }
+ ImageNO++;
+ ImageInfoListIndex = GetNextNode (&OverrideItem->DriverInfoList, ImageInfoListIndex);
+ }
+
+ if (!Found) {
+ //
+ // if not find the wanted order location, add it as last item of the controller mapping item
+ //
+ InsertTailList (&OverrideItem->DriverInfoList, &DriverImageInfo->Link);
+ OverrideItem->DriverInfoNum ++;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Delete a controller's override driver from the mapping database.
+
+ @param ControllerDevicePath The controller device path will be deleted
+ when all drivers images on it are removed.
+ @param DriverImageDevicePath The driver image device path will be delete.
+ If NULL, all driver image will be delete.
+ @param MappingDataBase Mapping database list entry pointer
+
+ @retval EFI_INVALID_PARAMETER ControllerDevicePath is NULL, or MappingDataBase is NULL
+ @retval EFI_NOT_FOUND ControllerDevicePath is not found in MappingDataBase or
+ DriverImageDevicePath is not found in the found DriverImage Info list.
+ @retval EFI_SUCCESS Delete the specified driver successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+DeleteDriverImage (
+ IN EFI_DEVICE_PATH_PROTOCOL *ControllerDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *DriverImageDevicePath,
+ IN LIST_ENTRY *MappingDataBase
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *OverrideItemListIndex;
+ PLATFORM_OVERRIDE_ITEM *OverrideItem;
+ LIST_ENTRY *ImageInfoListIndex;
+ DRIVER_IMAGE_INFO *DriverImageInfo;
+ BOOLEAN Found;
+ UINTN DevicePathSize;
+
+ if (ControllerDevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MappingDataBase == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If ControllerDevicePath is not found in mapping database, return EFI_NOT_FOUND.
+ //
+ Status = CheckMapping (
+ ControllerDevicePath,
+ DriverImageDevicePath,
+ MappingDataBase,
+ NULL,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Search ControllerDevicePath in MappingDataBase
+ //
+ Found = FALSE;
+ OverrideItem = NULL;
+ OverrideItemListIndex = GetFirstNode (MappingDataBase);
+ while (!IsNull (MappingDataBase, OverrideItemListIndex)) {
+ OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);
+ DevicePathSize = GetDevicePathSize (ControllerDevicePath);
+ if (DevicePathSize == GetDevicePathSize (OverrideItem->ControllerDevicePath)) {
+ if (CompareMem (
+ ControllerDevicePath,
+ OverrideItem->ControllerDevicePath,
+ DevicePathSize
+ ) == 0
+ ) {
+ Found = TRUE;
+ break;
+ }
+ }
+ OverrideItemListIndex = GetNextNode (MappingDataBase, OverrideItemListIndex);
+ }
+
+ ASSERT (Found);
+ ASSERT (OverrideItem->DriverInfoNum != 0);
+
+ Found = FALSE;
+ ImageInfoListIndex = GetFirstNode (&OverrideItem->DriverInfoList);
+ while (!IsNull (&OverrideItem->DriverInfoList, ImageInfoListIndex)) {
+ DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);
+ ImageInfoListIndex = GetNextNode (&OverrideItem->DriverInfoList, ImageInfoListIndex);
+ if (DriverImageDevicePath != NULL) {
+ //
+ // Search for the specified DriverImageDevicePath and remove it, then break.
+ //
+ DevicePathSize = GetDevicePathSize (DriverImageDevicePath);
+ if (DevicePathSize == GetDevicePathSize (DriverImageInfo->DriverImagePath)) {
+ if (CompareMem (
+ DriverImageDevicePath,
+ DriverImageInfo->DriverImagePath,
+ GetDevicePathSize (DriverImageInfo->DriverImagePath)
+ ) == 0
+ ) {
+ Found = TRUE;
+ FreePool(DriverImageInfo->DriverImagePath);
+ RemoveEntryList (&DriverImageInfo->Link);
+ OverrideItem->DriverInfoNum --;
+ break;
+ }
+ }
+ } else {
+ //
+ // Remove all existing driver image info entries, so no break here.
+ //
+ Found = TRUE;
+ FreePool(DriverImageInfo->DriverImagePath);
+ RemoveEntryList (&DriverImageInfo->Link);
+ OverrideItem->DriverInfoNum --;
+ }
+ }
+
+ //
+ // Confirm all driver image info entries have been removed,
+ // if DriverImageDevicePath is NULL.
+ //
+ if (DriverImageDevicePath == NULL) {
+ ASSERT (OverrideItem->DriverInfoNum == 0);
+ }
+ //
+ // If Override Item has no driver image info entry, then delete this item.
+ //
+ if (OverrideItem->DriverInfoNum == 0) {
+ FreePool(OverrideItem->ControllerDevicePath);
+ RemoveEntryList (&OverrideItem->Link);
+ FreePool (OverrideItem);
+ }
+
+ if (!Found) {
+ //
+ // DriverImageDevicePath is not NULL and cannot be found in the controller's
+ // driver image info list.
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}