/** @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; | |
} |