diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
commit | f215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch) | |
tree | 6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c | |
parent | Initial commit. (diff) | |
download | virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip |
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c')
-rw-r--r-- | src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c | 1056 |
1 files changed, 1056 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c new file mode 100644 index 00000000..7effbd50 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c @@ -0,0 +1,1056 @@ +/** @file + Supporting functions implementation for PCI devices management. + +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR> +(C) Copyright 2018 Hewlett Packard Enterprise Development LP<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "PciBus.h" + +// +// This device structure is serviced as a header. +// Its next field points to the first root bridge device node. +// +LIST_ENTRY mPciDevicePool; + +/** + Initialize the PCI devices pool. + +**/ +VOID +InitializePciDevicePool ( + VOID + ) +{ + InitializeListHead (&mPciDevicePool); +} + +/** + Insert a root bridge into PCI device pool. + + @param RootBridge A pointer to the PCI_IO_DEVICE. + +**/ +VOID +InsertRootBridge ( + IN PCI_IO_DEVICE *RootBridge + ) +{ + InsertTailList (&mPciDevicePool, &(RootBridge->Link)); +} + +/** + This function is used to insert a PCI device node under + a bridge. + + @param Bridge The PCI bridge. + @param PciDeviceNode The PCI device needs inserting. + +**/ +VOID +InsertPciDevice ( + IN PCI_IO_DEVICE *Bridge, + IN PCI_IO_DEVICE *PciDeviceNode + ) +{ + InsertTailList (&Bridge->ChildList, &(PciDeviceNode->Link)); + PciDeviceNode->Parent = Bridge; +} + +/** + Destroy root bridge and remove it from device tree. + + @param RootBridge The bridge want to be removed. + +**/ +VOID +DestroyRootBridge ( + IN PCI_IO_DEVICE *RootBridge + ) +{ + DestroyPciDeviceTree (RootBridge); + + FreePciDevice (RootBridge); +} + +/** + Destroy a pci device node. + + All direct or indirect allocated resource for this node will be freed. + + @param PciIoDevice A pointer to the PCI_IO_DEVICE to be destroyed. + +**/ +VOID +FreePciDevice ( + IN PCI_IO_DEVICE *PciIoDevice + ) +{ + ASSERT (PciIoDevice != NULL); + // + // Assume all children have been removed underneath this device + // + if (PciIoDevice->ResourcePaddingDescriptors != NULL) { + FreePool (PciIoDevice->ResourcePaddingDescriptors); + } + + if (PciIoDevice->DevicePath != NULL) { + FreePool (PciIoDevice->DevicePath); + } + + if (PciIoDevice->BusNumberRanges != NULL) { + FreePool (PciIoDevice->BusNumberRanges); + } + + FreePool (PciIoDevice); +} + +/** + Destroy all the pci device node under the bridge. + Bridge itself is not included. + + @param Bridge A pointer to the PCI_IO_DEVICE. + +**/ +VOID +DestroyPciDeviceTree ( + IN PCI_IO_DEVICE *Bridge + ) +{ + LIST_ENTRY *CurrentLink; + PCI_IO_DEVICE *Temp; + + while (!IsListEmpty (&Bridge->ChildList)) { + + CurrentLink = Bridge->ChildList.ForwardLink; + + // + // Remove this node from the linked list + // + RemoveEntryList (CurrentLink); + + Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + + if (!IsListEmpty (&Temp->ChildList)) { + DestroyPciDeviceTree (Temp); + } + + FreePciDevice (Temp); + } +} + +/** + Destroy all device nodes under the root bridge + specified by Controller. + + The root bridge itself is also included. + + @param Controller Root bridge handle. + + @retval EFI_SUCCESS Destroy all device nodes successfully. + @retval EFI_NOT_FOUND Cannot find any PCI device under specified + root bridge. + +**/ +EFI_STATUS +DestroyRootBridgeByHandle ( + IN EFI_HANDLE Controller + ) +{ + + LIST_ENTRY *CurrentLink; + PCI_IO_DEVICE *Temp; + + CurrentLink = mPciDevicePool.ForwardLink; + + while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) { + Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + + if (Temp->Handle == Controller) { + + RemoveEntryList (CurrentLink); + + DestroyPciDeviceTree (Temp); + + FreePciDevice (Temp); + + return EFI_SUCCESS; + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return EFI_NOT_FOUND; +} + +/** + This function registers the PCI IO device. + + It creates a handle for this PCI IO device (if the handle does not exist), attaches + appropriate protocols onto the handle, does necessary initialization, and sets up + parent/child relationship with its bus controller. + + @param Controller An EFI handle for the PCI bus controller. + @param PciIoDevice A PCI_IO_DEVICE pointer to the PCI IO device to be registered. + @param Handle A pointer to hold the returned EFI handle for the PCI IO device. + + @retval EFI_SUCCESS The PCI device is successfully registered. + @retval other An error occurred when registering the PCI device. + +**/ +EFI_STATUS +RegisterPciDevice ( + IN EFI_HANDLE Controller, + IN PCI_IO_DEVICE *PciIoDevice, + OUT EFI_HANDLE *Handle OPTIONAL + ) +{ + EFI_STATUS Status; + VOID *PlatformOpRomBuffer; + UINTN PlatformOpRomSize; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT8 Data8; + BOOLEAN HasEfiImage; + + // + // Install the pciio protocol, device path protocol + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &PciIoDevice->Handle, + &gEfiDevicePathProtocolGuid, + PciIoDevice->DevicePath, + &gEfiPciIoProtocolGuid, + &PciIoDevice->PciIo, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Force Interrupt line to "Unknown" or "No Connection" + // + PciIo = &(PciIoDevice->PciIo); + Data8 = PCI_INT_LINE_UNKNOWN; + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &Data8); + + // + // Process OpRom + // + if (!PciIoDevice->AllOpRomProcessed) { + + // + // Get the OpRom provided by platform + // + if (gPciPlatformProtocol != NULL) { + Status = gPciPlatformProtocol->GetPciRom ( + gPciPlatformProtocol, + PciIoDevice->Handle, + &PlatformOpRomBuffer, + &PlatformOpRomSize + ); + if (!EFI_ERROR (Status)) { + PciIoDevice->EmbeddedRom = FALSE; + PciIoDevice->RomSize = (UINT32) PlatformOpRomSize; + PciIoDevice->PciIo.RomSize = PlatformOpRomSize; + PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer; + // + // For OpROM read from gPciPlatformProtocol: + // Add the Rom Image to internal database for later PCI light enumeration + // + PciRomAddImageMapping ( + NULL, + PciIoDevice->PciRootBridgeIo->SegmentNumber, + PciIoDevice->BusNumber, + PciIoDevice->DeviceNumber, + PciIoDevice->FunctionNumber, + PciIoDevice->PciIo.RomImage, + PciIoDevice->PciIo.RomSize + ); + } + } else if (gPciOverrideProtocol != NULL) { + Status = gPciOverrideProtocol->GetPciRom ( + gPciOverrideProtocol, + PciIoDevice->Handle, + &PlatformOpRomBuffer, + &PlatformOpRomSize + ); + if (!EFI_ERROR (Status)) { + PciIoDevice->EmbeddedRom = FALSE; + PciIoDevice->RomSize = (UINT32) PlatformOpRomSize; + PciIoDevice->PciIo.RomSize = PlatformOpRomSize; + PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer; + // + // For OpROM read from gPciOverrideProtocol: + // Add the Rom Image to internal database for later PCI light enumeration + // + PciRomAddImageMapping ( + NULL, + PciIoDevice->PciRootBridgeIo->SegmentNumber, + PciIoDevice->BusNumber, + PciIoDevice->DeviceNumber, + PciIoDevice->FunctionNumber, + PciIoDevice->PciIo.RomImage, + PciIoDevice->PciIo.RomSize + ); + } + } + } + + // + // Determine if there are EFI images in the option rom + // + HasEfiImage = ContainEfiImage (PciIoDevice->PciIo.RomImage, PciIoDevice->PciIo.RomSize); + + if (HasEfiImage) { + Status = gBS->InstallMultipleProtocolInterfaces ( + &PciIoDevice->Handle, + &gEfiLoadFile2ProtocolGuid, + &PciIoDevice->LoadFile2, + NULL + ); + if (EFI_ERROR (Status)) { + gBS->UninstallMultipleProtocolInterfaces ( + PciIoDevice->Handle, + &gEfiDevicePathProtocolGuid, + PciIoDevice->DevicePath, + &gEfiPciIoProtocolGuid, + &PciIoDevice->PciIo, + NULL + ); + return Status; + } + } + + + if (!PciIoDevice->AllOpRomProcessed) { + + PciIoDevice->AllOpRomProcessed = TRUE; + + // + // Dispatch the EFI OpRom for the PCI device. + // The OpRom is got from platform in the above code + // or loaded from device in the previous round of bus enumeration + // + if (HasEfiImage) { + ProcessOpRomImage (PciIoDevice); + } + } + + if (PciIoDevice->BusOverride) { + // + // Install Bus Specific Driver Override Protocol + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &PciIoDevice->Handle, + &gEfiBusSpecificDriverOverrideProtocolGuid, + &PciIoDevice->PciDriverOverride, + NULL + ); + if (EFI_ERROR (Status)) { + gBS->UninstallMultipleProtocolInterfaces ( + PciIoDevice->Handle, + &gEfiDevicePathProtocolGuid, + PciIoDevice->DevicePath, + &gEfiPciIoProtocolGuid, + &PciIoDevice->PciIo, + NULL + ); + if (HasEfiImage) { + gBS->UninstallMultipleProtocolInterfaces ( + PciIoDevice->Handle, + &gEfiLoadFile2ProtocolGuid, + &PciIoDevice->LoadFile2, + NULL + ); + } + + return Status; + } + } + + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciRootBridgeIoProtocolGuid, + (VOID **) &(PciIoDevice->PciRootBridgeIo), + gPciBusDriverBinding.DriverBindingHandle, + PciIoDevice->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Handle != NULL) { + *Handle = PciIoDevice->Handle; + } + + // + // Indicate the pci device is registered + // + PciIoDevice->Registered = TRUE; + + return EFI_SUCCESS; +} + +/** + This function is used to remove the whole PCI devices on the specified bridge from + the root bridge. + + @param RootBridgeHandle The root bridge device handle. + @param Bridge The bridge device to be removed. + +**/ +VOID +RemoveAllPciDeviceOnBridge ( + EFI_HANDLE RootBridgeHandle, + PCI_IO_DEVICE *Bridge + ) +{ + LIST_ENTRY *CurrentLink; + PCI_IO_DEVICE *Temp; + + while (!IsListEmpty (&Bridge->ChildList)) { + + CurrentLink = Bridge->ChildList.ForwardLink; + Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + + // + // Check if the current node has been deregistered before + // If it is not, then deregister it + // + if (Temp->Registered) { + DeRegisterPciDevice (RootBridgeHandle, Temp->Handle); + } + + // + // Remove this node from the linked list + // + RemoveEntryList (CurrentLink); + + if (!IsListEmpty (&Temp->ChildList)) { + RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp); + } + + FreePciDevice (Temp); + } +} + +/** + This function is used to de-register the PCI IO device. + + That includes un-installing PciIo protocol from the specified PCI + device handle. + + @param Controller An EFI handle for the PCI bus controller. + @param Handle PCI device handle. + + @retval EFI_SUCCESS The PCI device is successfully de-registered. + @retval other An error occurred when de-registering the PCI device. + +**/ +EFI_STATUS +DeRegisterPciDevice ( + IN EFI_HANDLE Controller, + IN EFI_HANDLE Handle + ) + +{ + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + PCI_IO_DEVICE *Node; + LIST_ENTRY *CurrentLink; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + + Status = gBS->OpenProtocol ( + Handle, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + gPciBusDriverBinding.DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo); + + // + // If it is already de-registered + // + if (!PciIoDevice->Registered) { + return EFI_SUCCESS; + } + + // + // If it is PPB, first de-register its children + // + + if (!IsListEmpty (&PciIoDevice->ChildList)) { + + CurrentLink = PciIoDevice->ChildList.ForwardLink; + + while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) { + Node = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + Status = DeRegisterPciDevice (Controller, Node->Handle); + + if (EFI_ERROR (Status)) { + return Status; + } + + CurrentLink = CurrentLink->ForwardLink; + } + } + + // + // Close the child handle + // + Status = gBS->CloseProtocol ( + Controller, + &gEfiPciRootBridgeIoProtocolGuid, + gPciBusDriverBinding.DriverBindingHandle, + Handle + ); + + // + // Un-install the Device Path protocol and PCI I/O protocol + // and Bus Specific Driver Override protocol if needed. + // + if (PciIoDevice->BusOverride) { + Status = gBS->UninstallMultipleProtocolInterfaces ( + Handle, + &gEfiDevicePathProtocolGuid, + PciIoDevice->DevicePath, + &gEfiPciIoProtocolGuid, + &PciIoDevice->PciIo, + &gEfiBusSpecificDriverOverrideProtocolGuid, + &PciIoDevice->PciDriverOverride, + NULL + ); + } else { + Status = gBS->UninstallMultipleProtocolInterfaces ( + Handle, + &gEfiDevicePathProtocolGuid, + PciIoDevice->DevicePath, + &gEfiPciIoProtocolGuid, + &PciIoDevice->PciIo, + NULL + ); + } + + if (!EFI_ERROR (Status)) { + // + // Try to uninstall LoadFile2 protocol if exists + // + Status = gBS->OpenProtocol ( + Handle, + &gEfiLoadFile2ProtocolGuid, + NULL, + gPciBusDriverBinding.DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + Status = gBS->UninstallMultipleProtocolInterfaces ( + Handle, + &gEfiLoadFile2ProtocolGuid, + &PciIoDevice->LoadFile2, + NULL + ); + } + // + // Restore Status + // + Status = EFI_SUCCESS; + } + + + if (EFI_ERROR (Status)) { + gBS->OpenProtocol ( + Controller, + &gEfiPciRootBridgeIoProtocolGuid, + (VOID **) &PciRootBridgeIo, + gPciBusDriverBinding.DriverBindingHandle, + Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + return Status; + } + + // + // The Device Driver should disable this device after disconnect + // so the Pci Bus driver will not touch this device any more. + // Restore the register field to the original value + // + PciIoDevice->Registered = FALSE; + PciIoDevice->Handle = NULL; + } else { + + // + // Handle may be closed before + // + return EFI_SUCCESS; + } + + return EFI_SUCCESS; +} + +/** + Start to manage the PCI device on the specified root bridge or PCI-PCI Bridge. + + @param Controller The root bridge handle. + @param RootBridge A pointer to the PCI_IO_DEVICE. + @param RemainingDevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL. + @param NumberOfChildren Children number. + @param ChildHandleBuffer A pointer to the child handle buffer. + + @retval EFI_NOT_READY Device is not allocated. + @retval EFI_UNSUPPORTED Device only support PCI-PCI bridge. + @retval EFI_NOT_FOUND Can not find the specific device. + @retval EFI_SUCCESS Success to start Pci devices on bridge. + +**/ +EFI_STATUS +StartPciDevicesOnBridge ( + IN EFI_HANDLE Controller, + IN PCI_IO_DEVICE *RootBridge, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath, + IN OUT UINT8 *NumberOfChildren, + IN OUT EFI_HANDLE *ChildHandleBuffer + ) + +{ + PCI_IO_DEVICE *PciIoDevice; + EFI_DEV_PATH_PTR Node; + EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath; + EFI_STATUS Status; + LIST_ENTRY *CurrentLink; + UINT64 Supports; + + PciIoDevice = NULL; + CurrentLink = RootBridge->ChildList.ForwardLink; + + while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) { + + PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + if (RemainingDevicePath != NULL) { + + Node.DevPath = RemainingDevicePath; + + if (Node.Pci->Device != PciIoDevice->DeviceNumber || + Node.Pci->Function != PciIoDevice->FunctionNumber) { + CurrentLink = CurrentLink->ForwardLink; + continue; + } + + // + // Check if the device has been assigned with required resource + // + if (!PciIoDevice->Allocated) { + return EFI_NOT_READY; + } + + // + // Check if the current node has been registered before + // If it is not, register it + // + if (!PciIoDevice->Registered) { + Status = RegisterPciDevice ( + Controller, + PciIoDevice, + NULL + ); + + } + + if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) { + ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle; + (*NumberOfChildren)++; + } + + // + // Get the next device path + // + CurrentDevicePath = NextDevicePathNode (RemainingDevicePath); + if (IsDevicePathEnd (CurrentDevicePath)) { + return EFI_SUCCESS; + } + + // + // If it is a PPB + // + if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) { + Status = StartPciDevicesOnBridge ( + Controller, + PciIoDevice, + CurrentDevicePath, + NumberOfChildren, + ChildHandleBuffer + ); + + PciIoDevice->PciIo.Attributes ( + &(PciIoDevice->PciIo), + EfiPciIoAttributeOperationSupported, + 0, + &Supports + ); + Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE; + PciIoDevice->PciIo.Attributes ( + &(PciIoDevice->PciIo), + EfiPciIoAttributeOperationEnable, + Supports, + NULL + ); + + return Status; + } else { + + // + // Currently, the PCI bus driver only support PCI-PCI bridge + // + return EFI_UNSUPPORTED; + } + + } else { + + // + // If remaining device path is NULL, + // try to enable all the pci devices under this bridge + // + if (!PciIoDevice->Registered && PciIoDevice->Allocated) { + Status = RegisterPciDevice ( + Controller, + PciIoDevice, + NULL + ); + + } + + if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) { + ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle; + (*NumberOfChildren)++; + } + + if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) { + Status = StartPciDevicesOnBridge ( + Controller, + PciIoDevice, + RemainingDevicePath, + NumberOfChildren, + ChildHandleBuffer + ); + + PciIoDevice->PciIo.Attributes ( + &(PciIoDevice->PciIo), + EfiPciIoAttributeOperationSupported, + 0, + &Supports + ); + Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE; + PciIoDevice->PciIo.Attributes ( + &(PciIoDevice->PciIo), + EfiPciIoAttributeOperationEnable, + Supports, + NULL + ); + + } + + CurrentLink = CurrentLink->ForwardLink; + } + } + + if (PciIoDevice == NULL) { + return EFI_NOT_FOUND; + } else { + return EFI_SUCCESS; + } +} + +/** + Start to manage all the PCI devices it found previously under + the entire host bridge. + + @param Controller The root bridge handle. + + @retval EFI_NOT_READY Device is not allocated. + @retval EFI_SUCCESS Success to start Pci device on host bridge. + +**/ +EFI_STATUS +StartPciDevices ( + IN EFI_HANDLE Controller + ) +{ + PCI_IO_DEVICE *RootBridge; + EFI_HANDLE ThisHostBridge; + LIST_ENTRY *CurrentLink; + + RootBridge = GetRootBridgeByHandle (Controller); + ASSERT (RootBridge != NULL); + ThisHostBridge = RootBridge->PciRootBridgeIo->ParentHandle; + + CurrentLink = mPciDevicePool.ForwardLink; + + while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) { + + RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + // + // Locate the right root bridge to start + // + if (RootBridge->PciRootBridgeIo->ParentHandle == ThisHostBridge) { + StartPciDevicesOnBridge ( + RootBridge->Handle, + RootBridge, + NULL, + NULL, + NULL + ); + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return EFI_SUCCESS; +} + +/** + Create root bridge device. + + @param RootBridgeHandle Specified root bridge handle. + + @return The crated root bridge device instance, NULL means no + root bridge device instance created. + +**/ +PCI_IO_DEVICE * +CreateRootBridge ( + IN EFI_HANDLE RootBridgeHandle + ) +{ + EFI_STATUS Status; + PCI_IO_DEVICE *Dev; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + + Dev = AllocateZeroPool (sizeof (PCI_IO_DEVICE)); + if (Dev == NULL) { + return NULL; + } + + Dev->Signature = PCI_IO_DEVICE_SIGNATURE; + Dev->Handle = RootBridgeHandle; + InitializeListHead (&Dev->ChildList); + + Status = gBS->OpenProtocol ( + RootBridgeHandle, + &gEfiDevicePathProtocolGuid, + (VOID **) &ParentDevicePath, + gPciBusDriverBinding.DriverBindingHandle, + RootBridgeHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + FreePool (Dev); + return NULL; + } + + // + // Record the root bridge parent device path + // + Dev->DevicePath = DuplicateDevicePath (ParentDevicePath); + + // + // Get the pci root bridge io protocol + // + Status = gBS->OpenProtocol ( + RootBridgeHandle, + &gEfiPciRootBridgeIoProtocolGuid, + (VOID **) &PciRootBridgeIo, + gPciBusDriverBinding.DriverBindingHandle, + RootBridgeHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + FreePciDevice (Dev); + return NULL; + } + + Dev->PciRootBridgeIo = PciRootBridgeIo; + + // + // Initialize the PCI I/O instance structure + // + InitializePciIoInstance (Dev); + InitializePciDriverOverrideInstance (Dev); + InitializePciLoadFile2 (Dev); + + // + // Initialize reserved resource list and + // option rom driver list + // + InitializeListHead (&Dev->ReservedResourceList); + InitializeListHead (&Dev->OptionRomDriverList); + + return Dev; +} + +/** + Get root bridge device instance by specific root bridge handle. + + @param RootBridgeHandle Given root bridge handle. + + @return The root bridge device instance, NULL means no root bridge + device instance found. + +**/ +PCI_IO_DEVICE * +GetRootBridgeByHandle ( + EFI_HANDLE RootBridgeHandle + ) +{ + PCI_IO_DEVICE *RootBridgeDev; + LIST_ENTRY *CurrentLink; + + CurrentLink = mPciDevicePool.ForwardLink; + + while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) { + + RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + if (RootBridgeDev->Handle == RootBridgeHandle) { + return RootBridgeDev; + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return NULL; +} + +/** + Judge whether Pci device existed. + + @param Bridge Parent bridge instance. + @param PciIoDevice Device instance. + + @retval TRUE Pci device existed. + @retval FALSE Pci device did not exist. + +**/ +BOOLEAN +PciDeviceExisted ( + IN PCI_IO_DEVICE *Bridge, + IN PCI_IO_DEVICE *PciIoDevice + ) +{ + + PCI_IO_DEVICE *Temp; + LIST_ENTRY *CurrentLink; + + CurrentLink = Bridge->ChildList.ForwardLink; + + while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) { + + Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + + if (Temp == PciIoDevice) { + return TRUE; + } + + if (!IsListEmpty (&Temp->ChildList)) { + if (PciDeviceExisted (Temp, PciIoDevice)) { + return TRUE; + } + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return FALSE; +} + +/** + Get the active VGA device on the specified Host Bridge. + + @param HostBridgeHandle Host Bridge handle. + + @return The active VGA device on the specified Host Bridge. + +**/ +PCI_IO_DEVICE * +LocateVgaDeviceOnHostBridge ( + IN EFI_HANDLE HostBridgeHandle + ) +{ + LIST_ENTRY *CurrentLink; + PCI_IO_DEVICE *PciIoDevice; + + CurrentLink = mPciDevicePool.ForwardLink; + + while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) { + + PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + + if (PciIoDevice->PciRootBridgeIo->ParentHandle== HostBridgeHandle) { + + PciIoDevice = LocateVgaDevice (PciIoDevice); + + if (PciIoDevice != NULL) { + return PciIoDevice; + } + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return NULL; +} + +/** + Locate the active VGA device under the bridge. + + @param Bridge PCI IO instance for the bridge. + + @return The active VGA device. + +**/ +PCI_IO_DEVICE * +LocateVgaDevice ( + IN PCI_IO_DEVICE *Bridge + ) +{ + LIST_ENTRY *CurrentLink; + PCI_IO_DEVICE *PciIoDevice; + + CurrentLink = Bridge->ChildList.ForwardLink; + + while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) { + + PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + + if (IS_PCI_VGA(&PciIoDevice->Pci) && + (PciIoDevice->Attributes & + (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | + EFI_PCI_IO_ATTRIBUTE_VGA_IO | + EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) { + return PciIoDevice; + } + + if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) { + + PciIoDevice = LocateVgaDevice (PciIoDevice); + + if (PciIoDevice != NULL) { + return PciIoDevice; + } + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return NULL; +} + |