EFI_STATUS
EFIAPI
InitializePcatPciRootBridge (
  IN EFI_HANDLE       ImageHandle,
  IN EFI_SYSTEM_TABLE *SystemTable
  )
/*++

Routine Description:
  Initializes the PCI Root Bridge Controller

Arguments:
  ImageHandle -
  SystemTable -
    
Returns:
    None

--*/
{
  EFI_STATUS                     Status;
  PCAT_PCI_ROOT_BRIDGE_INSTANCE  *PrivateData;
  UINTN                          PciSegmentIndex;
  UINTN                          PciRootBridgeIndex;
  UINTN                          PrimaryBusIndex;
  UINTN                          NumberOfPciRootBridges;
  UINTN                          NumberOfPciDevices;
  UINTN                          Device;
  UINTN                          Function;
  UINT16                         VendorId;
  PCI_TYPE02                     PciConfigurationHeader;
  UINT64                         Address;
  UINT64                         Value;
  UINT64                         Base;
  UINT64                         Limit;

  //
  // Initialize gCpuIo now since the chipset init code requires it.
  //
  Status = gBS->LocateProtocol (&gEfiCpuIo2ProtocolGuid, NULL, (VOID **)&gCpuIo);
  ASSERT_EFI_ERROR (Status);

  //
  // Initialize variables required to search all PCI segments for PCI devices
  //
  PciSegmentIndex        = 0;
  PciRootBridgeIndex     = 0;
  NumberOfPciRootBridges = 0;
  PrimaryBusIndex        = 0;

  while (PciSegmentIndex <= PCI_MAX_SEGMENT) {

    PrivateData = NULL;
    Status = gBS->AllocatePool(
                    EfiBootServicesData,
                    sizeof (PCAT_PCI_ROOT_BRIDGE_INSTANCE),
                    (VOID **)&PrivateData
                    );
    if (EFI_ERROR (Status)) {
      goto Done;
    }

    ZeroMem (PrivateData, sizeof (PCAT_PCI_ROOT_BRIDGE_INSTANCE));

    //
    // Initialize the signature of the private data structure
    //
    PrivateData->Signature  = PCAT_PCI_ROOT_BRIDGE_SIGNATURE;
    PrivateData->Handle     = NULL;
    PrivateData->DevicePath = NULL;
    InitializeListHead (&PrivateData->MapInfo);

    //
    // Initialize the PCI root bridge number and the bus range for that root bridge
    //
    PrivateData->RootBridgeNumber = (UINT32)PciRootBridgeIndex;
    PrivateData->PrimaryBus       = (UINT32)PrimaryBusIndex;
    PrivateData->SubordinateBus   = (UINT32)PrimaryBusIndex;

    PrivateData->IoBase      = 0xffffffff;
    PrivateData->MemBase     = 0xffffffff;
    PrivateData->Mem32Base   = 0xffffffffffffffffULL;
    PrivateData->Pmem32Base  = 0xffffffffffffffffULL;
    PrivateData->Mem64Base   = 0xffffffffffffffffULL;
    PrivateData->Pmem64Base  = 0xffffffffffffffffULL;

    //
    // The default mechanism for performing PCI Configuration cycles is to 
    // use the I/O ports at 0xCF8 and 0xCFC.  This is only used for IA-32.
    // IPF uses SAL calls to perform PCI COnfiguration cycles
    //
    PrivateData->PciAddress  = 0xCF8;
    PrivateData->PciData     = 0xCFC;

    //
    // Get the physical I/O base for performing PCI I/O cycles
    // For IA-32, this is always 0, because IA-32 has IN and OUT instructions
    // For IPF, a SAL call is made to retrieve the base address for PCI I/O cycles
    //
    Status = PcatRootBridgeIoGetIoPortMapping (
               &PrivateData->PhysicalIoBase, 
               &PrivateData->PhysicalMemoryBase
               );
    if (EFI_ERROR (Status)) {
      goto Done;
    }

    //
    // Get PCI Express Base Address
    //
    PrivateData->PciExpressBaseAddress = GetPciExpressBaseAddressForRootBridge (PciSegmentIndex, PciRootBridgeIndex);
 /*   if (PrivateData->PciExpressBaseAddress != 0) {
      DEBUG ((EFI_D_ERROR, "PCIE Base - 0x%lx\n", PrivateData->PciExpressBaseAddress));
    }
*/
    //
    // Create a lock for performing PCI Configuration cycles
    //
    EfiInitializeLock (&PrivateData->PciLock, TPL_HIGH_LEVEL);

    //
    // Initialize the attributes for this PCI root bridge
    //
    PrivateData->Attributes  = 0;

    //
    // Build the EFI Device Path Protocol instance for this PCI Root Bridge
    //
    Status = PcatRootBridgeDevicePathConstructor (&PrivateData->DevicePath, PciRootBridgeIndex, (BOOLEAN)((PrivateData->PciExpressBaseAddress != 0) ? TRUE : FALSE));
    if (EFI_ERROR (Status)) {
      goto Done;
    }

    //
    // Build the PCI Root Bridge I/O Protocol instance for this PCI Root Bridge
    //
    Status = PcatRootBridgeIoConstructor (&PrivateData->Io, PciSegmentIndex);
    if (EFI_ERROR (Status)) {
      goto Done;
    }
    
    //
    // Scan all the PCI devices on the primary bus of the PCI root bridge
    //
    for (Device = 0, NumberOfPciDevices = 0; Device <= PCI_MAX_DEVICE; Device++) {
    
      for (Function = 0; Function <= PCI_MAX_FUNC; Function++) {

        //
        // Compute the PCI configuration address of the PCI device to probe
        //
        Address = EFI_PCI_ADDRESS (PrimaryBusIndex, Device, Function, 0);

        //
        // Read the Vendor ID from the PCI Configuration Header
        //
        Status = PrivateData->Io.Pci.Read (
                                       &PrivateData->Io, 
                                       EfiPciWidthUint16, 
                                       Address, 
                                       sizeof (VendorId) / sizeof (UINT16), 
                                       &VendorId
                                       );
        if ((EFI_ERROR (Status)) || ((VendorId == 0xffff) && (Function == 0))) {
          //
          // If the PCI Configuration Read fails, or a PCI device does not exist, then 
          // skip this entire PCI device
          //
          break;
        }
        if (VendorId == 0xffff) {
          //
          // If PCI function != 0, VendorId == 0xFFFF, we continue to search PCI function.
          //
          continue;
        }

        //
        // Read the entire PCI Configuration Header
        //
        Status = PrivateData->Io.Pci.Read (
                                       &PrivateData->Io, 
                                       EfiPciWidthUint16, 
                                       Address, 
                                       sizeof (PciConfigurationHeader) / sizeof (UINT16), 
                                       &PciConfigurationHeader
                                       );
        if (EFI_ERROR (Status)) {
          //
          // If the entire PCI Configuration Header can not be read, then skip this entire PCI device
          //
          break;
        }


        //
        // Increment the number of PCI device found on the primary bus of the PCI root bridge
        //
        NumberOfPciDevices++;

        //
        // Look for devices with the VGA Palette Snoop enabled in the COMMAND register of the PCI Config Header
        //
        if (PciConfigurationHeader.Hdr.Command & 0x20) {
          PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
        }

        //
        // If the device is a PCI-PCI Bridge, then look at the Subordinate Bus Number
        //
        if (IS_PCI_BRIDGE(&PciConfigurationHeader)) {
          //
          // Get the Bus range that the PPB is decoding
          //
          if (PciConfigurationHeader.Bridge.P2PBridge.SubordinateBus > PrivateData->SubordinateBus) {
            //
            // If the suborinate bus number of the PCI-PCI bridge is greater than the PCI root bridge's
            // current subordinate bus number, then update the PCI root bridge's subordinate bus number 
            //
            PrivateData->SubordinateBus = PciConfigurationHeader.Bridge.P2PBridge.SubordinateBus;
          }

          //
          // Get the I/O range that the PPB is decoding
          //
          Value = PciConfigurationHeader.Bridge.P2PBridge.IoBase & 0x0f;
          Base  = ((UINT32)PciConfigurationHeader.Bridge.P2PBridge.IoBase & 0xf0) << 8;
          Limit = (((UINT32)PciConfigurationHeader.Bridge.P2PBridge.IoLimit & 0xf0) << 8) | 0x0fff;
          if (Value == 0x01) {
            Base  |= ((UINT32)PciConfigurationHeader.Bridge.P2PBridge.IoBaseUpper16 << 16);
            Limit |= ((UINT32)PciConfigurationHeader.Bridge.P2PBridge.IoLimitUpper16 << 16);
          }
          if (Base < Limit) {
            if (PrivateData->IoBase > Base) {
              PrivateData->IoBase = Base;
            }
            if (PrivateData->IoLimit < Limit) {
              PrivateData->IoLimit = Limit;
            }
          }

          //
          // Get the Memory range that the PPB is decoding
          //
          Base  = ((UINT32)PciConfigurationHeader.Bridge.P2PBridge.MemoryBase & 0xfff0) << 16;
          Limit = (((UINT32)PciConfigurationHeader.Bridge.P2PBridge.MemoryLimit & 0xfff0) << 16) | 0xfffff;
          if (Base < Limit) {
            if (PrivateData->MemBase > Base) {
              PrivateData->MemBase = Base;
            }
            if (PrivateData->MemLimit < Limit) {
              PrivateData->MemLimit = Limit;
            }
            if (PrivateData->Mem32Base > Base) {
              PrivateData->Mem32Base = Base;
            }
            if (PrivateData->Mem32Limit < Limit) {
              PrivateData->Mem32Limit = Limit;
            }
          }

          //
          // Get the Prefetchable Memory range that the PPB is decoding
          //
          Value = PciConfigurationHeader.Bridge.P2PBridge.PrefetchableMemoryBase & 0x0f;
          Base  = ((UINT32)PciConfigurationHeader.Bridge.P2PBridge.PrefetchableMemoryBase & 0xfff0) << 16;
          Limit = (((UINT32)PciConfigurationHeader.Bridge.P2PBridge.PrefetchableMemoryLimit & 0xfff0) << 16) | 0xffffff;
          if (Value == 0x01) {
            Base  |= LShiftU64((UINT64)PciConfigurationHeader.Bridge.P2PBridge.PrefetchableBaseUpper32,32);
            Limit |= LShiftU64((UINT64)PciConfigurationHeader.Bridge.P2PBridge.PrefetchableLimitUpper32,32);
          }
          if (Base < Limit) {
            if (PrivateData->MemBase > Base) {
              PrivateData->MemBase = Base;
            }
            if (PrivateData->MemLimit < Limit) {
              PrivateData->MemLimit = Limit;
            }
            if (Value == 0x00) {
              if (PrivateData->Pmem32Base > Base) {
                PrivateData->Pmem32Base = Base;
              }
              if (PrivateData->Pmem32Limit < Limit) {
                PrivateData->Pmem32Limit = Limit;
              }
            }
            if (Value == 0x01) {
              if (PrivateData->Pmem64Base > Base) {
                PrivateData->Pmem64Base = Base;
              }
              if (PrivateData->Pmem64Limit < Limit) {
                PrivateData->Pmem64Limit = Limit;
              }
            }
          }

          //
          // Look at the PPB Configuration for legacy decoding attributes
          //
          if (PciConfigurationHeader.Bridge.P2PBridge.BridgeControl & 0x04) {
            PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO;
            PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO;
          }
          if (PciConfigurationHeader.Bridge.P2PBridge.BridgeControl & 0x08) {
           // PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
            PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY;
            PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO;
          }

        } else if (IS_CARDBUS_BRIDGE(&PciConfigurationHeader)) {
          //
          // Get the Bus range that the PPB is decoding
          //
          if (PciConfigurationHeader.Bridge.CardBridge.SubordinateBusNumber > PrivateData->SubordinateBus) {
            //
            // If the suborinate bus number of the PCI-PCI bridge is greater than the PCI root bridge's
            // current subordinate bus number, then update the PCI root bridge's subordinate bus number 
            //
            PrivateData->SubordinateBus = PciConfigurationHeader.Bridge.CardBridge.SubordinateBusNumber;
          }
          
          //
          // Get the I/O range that the PPB is decoding
          //
          Base  = PciConfigurationHeader.Bridge.CardBridge.IoBase0;
          Limit = PciConfigurationHeader.Bridge.CardBridge.IoLimit0;
          if (Base < Limit) {
            if (PrivateData->IoBase > Base) {
              PrivateData->IoBase = Base;
            }
            if (PrivateData->IoLimit < Limit) {
              PrivateData->IoLimit = Limit;
            }
          }
          
          //
          // Get the Memory range that the PPB is decoding
          //
          Base  = PciConfigurationHeader.Bridge.CardBridge.MemoryBase0;
          Limit = PciConfigurationHeader.Bridge.CardBridge.MemoryLimit0;
          if (Base < Limit) {
            if (PrivateData->MemBase > Base) {
              PrivateData->MemBase = Base;
            }
            if (PrivateData->MemLimit < Limit) {
              PrivateData->MemLimit = Limit;
            }
            if (PrivateData->Mem32Base > Base) {
              PrivateData->Mem32Base = Base;
            }
            if (PrivateData->Mem32Limit < Limit) {
              PrivateData->Mem32Limit = Limit;
            }
          }
          
        } else 
          {
          //
          // Parse the BARs of the PCI device to determine what I/O Ranges,
          // Memory Ranges, and Prefetchable Memory Ranges the device is decoding
          //
          if ((PciConfigurationHeader.Hdr.HeaderType & HEADER_LAYOUT_CODE) == HEADER_TYPE_DEVICE) {
            Status = PcatPciRootBridgeParseBars (
                       PrivateData, 
                       PciConfigurationHeader.Hdr.Command,
                       PrimaryBusIndex, 
                       Device, 
                       Function
                       );
          }

          //
          // See if the PCI device is an IDE controller
          //
          if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x01 &&
              PciConfigurationHeader.Hdr.ClassCode[1] == 0x01    ) {
            if (PciConfigurationHeader.Hdr.ClassCode[0] & 0x80) {
              PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO;
              PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO;
            }
            if (PciConfigurationHeader.Hdr.ClassCode[0] & 0x01) {
              PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO;
            }
            if (PciConfigurationHeader.Hdr.ClassCode[0] & 0x04) {
              PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO;
            }
          }

          //
          // See if the PCI device is a legacy VGA controller
          //
          if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x00 &&
              PciConfigurationHeader.Hdr.ClassCode[1] == 0x01    ) {
            PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
            PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY;
            PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO;
          }

          //
          // See if the PCI device is a standard VGA controller
          //
          if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x03 &&
              PciConfigurationHeader.Hdr.ClassCode[1] == 0x00    ) {
            PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
            PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY;
            PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO;
          }

          //
          // See if the PCI Device is a PCI - ISA or PCI - EISA 
          // or ISA_POSITIVIE_DECODE Bridge device
          //
          if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x06) {
            if (PciConfigurationHeader.Hdr.ClassCode[1] == 0x01 ||
                PciConfigurationHeader.Hdr.ClassCode[1] == 0x02 || 
                PciConfigurationHeader.Hdr.ClassCode[1] == 0x80 ) {
              PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO;
              PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO;

              if (PrivateData->MemBase > 0xa0000) {
                PrivateData->MemBase = 0xa0000;
              }
              if (PrivateData->MemLimit < 0xbffff) {
               PrivateData->MemLimit = 0xbffff;
             }
            }
          }
        }

        //
        // If this device is not a multi function device, then skip the rest of this PCI device
        //
        if (Function == 0 && !(PciConfigurationHeader.Hdr.HeaderType & HEADER_TYPE_MULTI_FUNCTION)) {
          break;
        }
      }
    }

    //
    // After scanning all the PCI devices on the PCI root bridge's primary bus, update the 
    // Primary Bus Number for the next PCI root bridge to be this PCI root bridge's subordinate
    // bus number + 1.
    //
    PrimaryBusIndex = PrivateData->SubordinateBus + 1;

    //
    // If at least one PCI device was found on the primary bus of this PCI root bridge, then the PCI root bridge
    // exists.
    //
    if (NumberOfPciDevices > 0) {

      //
      // Adjust the I/O range used for bounds checking for the legacy decoding attributed
      //
      if (PrivateData->Attributes & 0x7f) {
        PrivateData->IoBase = 0;
        if (PrivateData->IoLimit < 0xffff) {
          PrivateData->IoLimit = 0xffff;
        }
      }

      //
      // Adjust the Memory range used for bounds checking for the legacy decoding attributed
      //
      if (PrivateData->Attributes & EFI_PCI_ATTRIBUTE_VGA_MEMORY) {
        if (PrivateData->MemBase > 0xa0000) {
          PrivateData->MemBase = 0xa0000;
        }
        if (PrivateData->MemLimit < 0xbffff) {
          PrivateData->MemLimit = 0xbffff;
        }
      }

      //
      // Build ACPI descriptors for the resources on the PCI Root Bridge
      //
      Status = ConstructConfiguration(PrivateData);
      ASSERT_EFI_ERROR (Status);

      //
      // Create the handle for this PCI Root Bridge 
      //
      Status = gBS->InstallMultipleProtocolInterfaces (
                     &PrivateData->Handle,              
                     &gEfiDevicePathProtocolGuid,
                     PrivateData->DevicePath,
                     &gEfiPciRootBridgeIoProtocolGuid,
                     &PrivateData->Io,
                     NULL
                     );
      ASSERT_EFI_ERROR (Status);

      //
      // Contruct DeviceIoProtocol
      //
      Status = DeviceIoConstructor (
                 PrivateData->Handle,
                 &PrivateData->Io,
                 PrivateData->DevicePath,
                 (UINT16)PrivateData->PrimaryBus,
                 (UINT16)PrivateData->SubordinateBus
                 );
      ASSERT_EFI_ERROR (Status);
#if 0 //patch by nms42
      //
      // Scan this PCI Root Bridge for PCI Option ROMs and add them to the PCI Option ROM Table
      //
      Status = ScanPciRootBridgeForRoms(&PrivateData->Io);
#endif
      //
      // Increment the index for the next PCI Root Bridge
      //
      PciRootBridgeIndex++;

    } else {

      //
      // If no PCI Root Bridges were found on the current PCI segment, then exit
      //
      if (NumberOfPciRootBridges == 0) {
        Status = EFI_SUCCESS;
        goto Done;
      }

    }

    //
    // If the PrimaryBusIndex is greater than the maximum allowable PCI bus number, then
    // the PCI Segment Number is incremented, and the next segment is searched starting at Bus #0
    // Otherwise, the search is continued on the next PCI Root Bridge
    //
    if (PrimaryBusIndex > PCI_MAX_BUS) {
      PciSegmentIndex++;
      NumberOfPciRootBridges = 0;
      PrimaryBusIndex = 0;
    } else {
      NumberOfPciRootBridges++;
    }

  }

  return EFI_SUCCESS;

Done:
  //
  // Clean up memory allocated for the PCI Root Bridge that was searched but not created.
  //
  if (PrivateData) {
    if (PrivateData->DevicePath) {
      gBS->FreePool(PrivateData->DevicePath);
    }
    gBS->FreePool (PrivateData);
  }

  //
  // If no PCI Root Bridges were discovered, then return the error condition from scanning the
  // first PCI Root Bridge
  //
  if (PciRootBridgeIndex == 0) {
    return Status;
  }

  return EFI_SUCCESS;
}
Пример #2
0
//
// Implementation
//
EFI_STATUS
InitializePciHostBridge (
  IN EFI_HANDLE       ImageHandle,
  IN EFI_SYSTEM_TABLE *SystemTable
  )
/*++

Routine Description:
  Entry point of this driver

Arguments:

    ImageHandle -

    SystemTable -
    
Returns:

--*/
// TODO:    EFI_DEVICE_ERROR - add return value to function comment
// TODO:    EFI_DEVICE_ERROR - add return value to function comment
// TODO:    EFI_SUCCESS - add return value to function comment
{
  EFI_STATUS                Status;
  UINTN                     Loop1;
  UINTN                     Loop2;
  PCI_HOST_BRIDGE_INSTANCE  *HostBridge;
  PCI_ROOT_BRIDGE_INSTANCE  *PrivateData;

  DxeInitializeDriverLib (ImageHandle, SystemTable);

  mDriverImageHandle = ImageHandle;

  //
  // Support one Host Bridge (one Root Bridge in this Host Bridge)
  //
  
  //
  // Create Host Bridge Device Handle
  //
  for (Loop1 = 0; Loop1 < HOST_BRIDGE_NUMBER; Loop1++) {
    Status = gBS->AllocatePool (
                    EfiBootServicesData,
                    sizeof (PCI_HOST_BRIDGE_INSTANCE),
                    &HostBridge
                    );
    ASSERT (!EFI_ERROR (Status));

    HostBridge->Signature                     = PCI_HOST_BRIDGE_SIGNATURE;
    HostBridge->RootBridgeNumber              = mRootBridgeNumber[Loop1];
    HostBridge->ResourceSubmited              = FALSE;
    HostBridge->CanRestarted                  = TRUE;

    HostBridge->ResAlloc.NotifyPhase          = NotifyPhase;
    HostBridge->ResAlloc.GetNextRootBridge    = GetNextRootBridge;
    HostBridge->ResAlloc.GetAllocAttributes   = GetAttributes;
    HostBridge->ResAlloc.StartBusEnumeration  = StartBusEnumeration;
    HostBridge->ResAlloc.SetBusNumbers        = SetBusNumbers;
    HostBridge->ResAlloc.SubmitResources      = SubmitResources;
    HostBridge->ResAlloc.GetProposedResources = GetProposedResources;
    HostBridge->ResAlloc.PreprocessController = PreprocessController;

    HostBridge->HostBridgeHandle              = NULL;
    Status = gBS->InstallProtocolInterface (
                    &HostBridge->HostBridgeHandle,
                    &gEfiPciHostBridgeResourceAllocationProtocolGuid,
                    EFI_NATIVE_INTERFACE,
                    &HostBridge->ResAlloc
                    );

    if (EFI_ERROR (Status)) {
      gBS->FreePool (HostBridge);
      return EFI_DEVICE_ERROR;
    }
  
    //
    // Create Root Bridge Device Handle in this Host Bridge
    //
    InitializeListHead (&HostBridge->Head);

    for (Loop2 = 0; Loop2 < HostBridge->RootBridgeNumber; Loop2++) {
      Status = gBS->AllocatePool (
                      EfiBootServicesData,
                      sizeof (PCI_ROOT_BRIDGE_INSTANCE),
                      &PrivateData
                      );
      ASSERT (!EFI_ERROR (Status));

      PrivateData->Signature  = PCI_ROOT_BRIDGE_SIGNATURE;

      PrivateData->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &mEfiPciRootBridgeDevicePath[Loop1][Loop2];
      RootBridgeConstructor (
        &PrivateData->Io,
        HostBridge->HostBridgeHandle,
        mRootBridgeAttribute[Loop1][Loop2],
        mResAppeture[Loop1][Loop2]
        );

      PrivateData->Handle = NULL;
      Status = gBS->InstallMultipleProtocolInterfaces (
                      &PrivateData->Handle,
                      &gEfiDevicePathProtocolGuid,
                      PrivateData->DevicePath,
                      &gEfiPciRootBridgeIoProtocolGuid,
                      &PrivateData->Io,
                      NULL
                      );
      if (EFI_ERROR (Status)) {
        gBS->FreePool (PrivateData);
        return EFI_DEVICE_ERROR;
      }

      //
      // Install DeviceIo
      //
      Status = DeviceIoConstructor (
                 PrivateData->Handle,
                 &PrivateData->Io,
                 PrivateData->DevicePath
                 );

      InsertTailList (&HostBridge->Head, &PrivateData->Link);
    }
    //
    // end for
    //
  }
  //
  // end for
  //
  Status = gDS->AddIoSpace (
                  EfiGcdIoTypeIo,
                  RES_IO_BASE,
                  RES_IO_LIMIT - RES_IO_BASE + 1
                  );

  Status = gDS->AddMemorySpace (
                  EfiGcdMemoryTypeMemoryMappedIo,
                  RES_MEM_BASE,
                  RES_MEM_LIMIT - RES_MEM_BASE + 1,
                  0
                  );

  return EFI_SUCCESS;
}