From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- .../PlatformDriOverrideDxe/PlatDriOverrideLib.c | 1941 ++++++++++++++++++++ 1 file changed, 1941 insertions(+) create mode 100644 roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideLib.c (limited to 'roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideLib.c') 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.
+ 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; +} -- cgit 1.2.3-korg