summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c
diff options
context:
space:
mode:
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.c1056
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;
+}
+