/** @file Functions implementation for Bus Specific Driver Override protocol. Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "PciBus.h" /** Initializes a PCI Driver Override Instance. @param PciIoDevice PCI Device instance. **/ VOID InitializePciDriverOverrideInstance ( IN OUT PCI_IO_DEVICE *PciIoDevice ) { PciIoDevice->PciDriverOverride.GetDriver = GetDriver; } /** Find the image handle whose path equals to ImagePath. @param ImagePath Image path. @return Image handle. **/ EFI_HANDLE LocateImageHandle ( IN EFI_DEVICE_PATH_PROTOCOL *ImagePath ) { EFI_STATUS Status; EFI_HANDLE *Handles; UINTN Index; UINTN HandleNum; EFI_DEVICE_PATH_PROTOCOL *DevicePath; UINTN ImagePathSize; EFI_HANDLE ImageHandle; Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiLoadedImageDevicePathProtocolGuid, NULL, &HandleNum, &Handles ); if (EFI_ERROR(Status)) { return NULL; } ImageHandle = NULL; ImagePathSize = GetDevicePathSize (ImagePath); for (Index = 0; Index < HandleNum; Index++) { Status = gBS->HandleProtocol (Handles[Index], &gEfiLoadedImageDevicePathProtocolGuid, (VOID **) &DevicePath); if (EFI_ERROR(Status)) { continue; } if ((ImagePathSize == GetDevicePathSize (DevicePath)) && (CompareMem (ImagePath, DevicePath, ImagePathSize) == 0) ) { ImageHandle = Handles[Index]; break; } } FreePool(Handles); return ImageHandle; } /** Uses a bus specific algorithm to retrieve a driver image handle for a controller. @param This A pointer to the EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL instance. @param DriverImageHandle On input, a pointer to the previous driver image handle returned by GetDriver(). On output, a pointer to the next driver image handle. Passing in a NULL, will return the first driver image handle. @retval EFI_SUCCESS A bus specific override driver is returned in DriverImageHandle. @retval EFI_NOT_FOUND The end of the list of override drivers was reached. A bus specific override driver is not returned in DriverImageHandle. @retval EFI_INVALID_PARAMETER DriverImageHandle is not a handle that was returned on a previous call to GetDriver(). **/ EFI_STATUS EFIAPI GetDriver ( IN EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *This, IN OUT EFI_HANDLE *DriverImageHandle ) { PCI_IO_DEVICE *PciIoDevice; LIST_ENTRY *Link; PCI_DRIVER_OVERRIDE_LIST *Override; BOOLEAN ReturnNext; Override = NULL; PciIoDevice = PCI_IO_DEVICE_FROM_PCI_DRIVER_OVERRIDE_THIS (This); ReturnNext = (BOOLEAN) (*DriverImageHandle == NULL); for ( Link = GetFirstNode (&PciIoDevice->OptionRomDriverList) ; !IsNull (&PciIoDevice->OptionRomDriverList, Link) ; Link = GetNextNode (&PciIoDevice->OptionRomDriverList, Link) ) { Override = DRIVER_OVERRIDE_FROM_LINK (Link); if (ReturnNext) { if (Override->DriverImageHandle == NULL) { Override->DriverImageHandle = LocateImageHandle (Override->DriverImagePath); } if (Override->DriverImageHandle == NULL) { // // The Option ROM identified by Override->DriverImagePath is not loaded. // continue; } else { *DriverImageHandle = Override->DriverImageHandle; return EFI_SUCCESS; } } if (*DriverImageHandle == Override->DriverImageHandle) { ReturnNext = TRUE; } } ASSERT (IsNull (&PciIoDevice->OptionRomDriverList, Link)); // // ReturnNext indicates a handle match happens. // If all nodes are checked without handle match happening, // the DriverImageHandle should be a invalid handle. // if (ReturnNext) { return EFI_NOT_FOUND; } else { return EFI_INVALID_PARAMETER; } } /** Add an overriding driver image. @param PciIoDevice Instance of PciIo device. @param DriverImageHandle Image handle of newly added driver image. @param DriverImagePath Device path of newly added driver image. @retval EFI_SUCCESS Successfully added driver. @retval EFI_OUT_OF_RESOURCES No memory resource for new driver instance. @retval other Some error occurred when locating gEfiLoadedImageProtocolGuid. **/ EFI_STATUS AddDriver ( IN PCI_IO_DEVICE *PciIoDevice, IN EFI_HANDLE DriverImageHandle, IN EFI_DEVICE_PATH_PROTOCOL *DriverImagePath ) { PCI_DRIVER_OVERRIDE_LIST *Node; // // Caller should pass in either Image Handle or Image Path, but not both. // ASSERT ((DriverImageHandle == NULL) || (DriverImagePath == NULL)); Node = AllocateZeroPool(sizeof (PCI_DRIVER_OVERRIDE_LIST)); if (Node == NULL) { return EFI_OUT_OF_RESOURCES; } Node->Signature = DRIVER_OVERRIDE_SIGNATURE; Node->DriverImageHandle = DriverImageHandle; Node->DriverImagePath = DuplicateDevicePath (DriverImagePath); InsertTailList (&PciIoDevice->OptionRomDriverList, &Node->Link); PciIoDevice->BusOverride = TRUE; return EFI_SUCCESS; }