| /** @file | |
| Functions implementation for Bus Specific Driver Override protocol. | |
| Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR> | |
| 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; | |
| } |