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