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
/**
  Scan for all root bridges in platform.

  @param[out] NumberOfRootBridges  Number of root bridges detected

  @retval     Pointer to the allocated PCI_ROOT_BRIDGE structure array.
**/
PCI_ROOT_BRIDGE *
ScanForRootBridges (
  OUT UINTN      *NumberOfRootBridges
)
{
  UINTN      PrimaryBus;
  UINTN      SubBus;
  UINT8      Device;
  UINT8      Function;
  UINTN      NumberOfDevices;
  UINTN      Address;
  PCI_TYPE01 Pci;
  UINT64     Attributes;
  UINT64     Base;
  UINT64     Limit;
  UINT64     Value;
  PCI_ROOT_BRIDGE_APERTURE Io, Mem, MemAbove4G, PMem, PMemAbove4G, *MemAperture;
  PCI_ROOT_BRIDGE *RootBridges;
  UINTN      BarOffsetEnd;


  *NumberOfRootBridges = 0;
  RootBridges = NULL;

  //
  // 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.
  //
  for (PrimaryBus = 0; PrimaryBus <= PCI_MAX_BUS; PrimaryBus = SubBus + 1) {
    SubBus = PrimaryBus;
    Attributes = 0;
    Io.Base = Mem.Base = MemAbove4G.Base = PMem.Base = PMemAbove4G.Base = MAX_UINT64;
    Io.Limit = Mem.Limit = MemAbove4G.Limit = PMem.Limit = PMemAbove4G.Limit = 0;
    //
    // Scan all the PCI devices on the primary bus of the PCI root bridge
    //
    for (Device = 0, NumberOfDevices = 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 = PCI_LIB_ADDRESS (PrimaryBus, Device, Function, 0);

        //
        // Read the Vendor ID from the PCI Configuration Header
        //
        if (PciRead16 (Address) == MAX_UINT16) {
          if (Function == 0) {
            //
            // If the PCI Configuration Read fails, or a PCI device does not
            // exist, then skip this entire PCI device
            //
            break;
          } else {
            //
            // If PCI function != 0, VendorId == 0xFFFF, we continue to search
            // PCI function.
            //
            continue;
          }
        }

        //
        // Read the entire PCI Configuration Header
        //
        PciReadBuffer (Address, sizeof (Pci), &Pci);

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

        //
        // Look for devices with the VGA Palette Snoop enabled in the COMMAND
        // register of the PCI Config Header
        //
        if ((Pci.Hdr.Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) {
          Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
          Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16;
        }

        BarOffsetEnd = 0;

        //
        // PCI-PCI Bridge
        //
        if (IS_PCI_BRIDGE (&Pci)) {
          //
          // Get the Bus range that the PPB is decoding
          //
          if (Pci.Bridge.SubordinateBus > SubBus) {
            //
            // 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
            //
            SubBus = Pci.Bridge.SubordinateBus;
          }

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

          //
          // Get the Memory range that the PPB is decoding
          //
          Base = ((UINT32) Pci.Bridge.MemoryBase & 0xfff0) << 16;
          Limit = (((UINT32) Pci.Bridge.MemoryLimit & 0xfff0) << 16) | 0xfffff;
          if ((Base > 0) && (Base < Limit)) {
            if (Mem.Base > Base) {
              Mem.Base = Base;
            }
            if (Mem.Limit < Limit) {
              Mem.Limit = Limit;
            }
          }

          //
          // Get the Prefetchable Memory range that the PPB is decoding
          //
          Value = Pci.Bridge.PrefetchableMemoryBase & 0x0f;
          Base = ((UINT32) Pci.Bridge.PrefetchableMemoryBase & 0xfff0) << 16;
          Limit = (((UINT32) Pci.Bridge.PrefetchableMemoryLimit & 0xfff0)
                   << 16) | 0xfffff;
          MemAperture = &PMem;
          if (Value == BIT0) {
            Base |= LShiftU64 (Pci.Bridge.PrefetchableBaseUpper32, 32);
            Limit |= LShiftU64 (Pci.Bridge.PrefetchableLimitUpper32, 32);
            MemAperture = &PMemAbove4G;
          }
          if ((Base > 0) && (Base < Limit)) {
            if (MemAperture->Base > Base) {
              MemAperture->Base = Base;
            }
            if (MemAperture->Limit < Limit) {
              MemAperture->Limit = Limit;
            }
          }

          //
          // Look at the PPB Configuration for legacy decoding attributes
          //
          if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA)
              == EFI_PCI_BRIDGE_CONTROL_ISA) {
            Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO;
            Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO_16;
            Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO;
          }
          if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA)
              == EFI_PCI_BRIDGE_CONTROL_VGA) {
            Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
            Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY;
            Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO;
            if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16)
                != 0) {
              Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16;
              Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO_16;
            }
          }

          BarOffsetEnd = OFFSET_OF (PCI_TYPE01, Bridge.Bar[2]);
        } else {
          //
          // Parse the BARs of the PCI device to get what I/O Ranges, Memory
          // Ranges, and Prefetchable Memory Ranges the device is decoding
          //
          if ((Pci.Hdr.HeaderType & HEADER_LAYOUT_CODE) == HEADER_TYPE_DEVICE) {
            BarOffsetEnd = OFFSET_OF (PCI_TYPE00, Device.Bar[6]);
          }
        }

        PcatPciRootBridgeParseBars (
          Pci.Hdr.Command,
          PrimaryBus,
          Device,
          Function,
          OFFSET_OF (PCI_TYPE00, Device.Bar),
          BarOffsetEnd,
          &Io,
          &Mem, &MemAbove4G,
          &PMem, &PMemAbove4G
        );

        //
        // See if the PCI device is an IDE controller
        //
        if (IS_CLASS2 (&Pci, PCI_CLASS_MASS_STORAGE,
                       PCI_CLASS_MASS_STORAGE_IDE)) {
          if (Pci.Hdr.ClassCode[0] & 0x80) {
            Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO;
            Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO;
          }
          if (Pci.Hdr.ClassCode[0] & 0x01) {
            Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO;
          }
          if (Pci.Hdr.ClassCode[0] & 0x04) {
            Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO;
          }
        }

        //
        // See if the PCI device is a legacy VGA controller or
        // a standard VGA controller
        //
        if (IS_CLASS2 (&Pci, PCI_CLASS_OLD, PCI_CLASS_OLD_VGA) ||
            IS_CLASS2 (&Pci, PCI_CLASS_DISPLAY, PCI_CLASS_DISPLAY_VGA)
           ) {
          Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
          Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16;
          Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY;
          Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO;
          Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO_16;
        }

        //
        // See if the PCI Device is a PCI - ISA or PCI - EISA
        // or ISA_POSITIVIE_DECODE Bridge device
        //
        if (Pci.Hdr.ClassCode[2] == PCI_CLASS_BRIDGE) {
          if (Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA ||
              Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_EISA ||
              Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA_PDECODE) {
            Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO;
            Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO_16;
            Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO;
          }
        }

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

    //
    // If at least one PCI device was found on the primary bus of this PCI
    // root bridge, then the PCI root bridge exists.
    //
    if (NumberOfDevices > 0) {
      RootBridges = ReallocatePool (
                      (*NumberOfRootBridges) * sizeof (PCI_ROOT_BRIDGE),
                      (*NumberOfRootBridges + 1) * sizeof (PCI_ROOT_BRIDGE),
                      RootBridges
                    );
      ASSERT (RootBridges != NULL);

      AdjustRootBridgeResource (&Io, &Mem, &MemAbove4G, &PMem, &PMemAbove4G);

      InitRootBridge (
        Attributes, Attributes, 0,
        (UINT8) PrimaryBus, (UINT8) SubBus,
        &Io, &Mem, &MemAbove4G, &PMem, &PMemAbove4G,
        &RootBridges[*NumberOfRootBridges]
      );
      RootBridges[*NumberOfRootBridges].ResourceAssigned = TRUE;
      //
      // Increment the index for the next PCI Root Bridge
      //
      (*NumberOfRootBridges)++;
    }
  }

  return RootBridges;
}