PciHostBridgeDxe

edk2中MdeModulePkg\Bus\Pci路径下PciHostBridgeDxe的源码阅读,记录一下学习过程。PciHostBridgeDxe是DXE_DRIVER,即只提供软件服务,并不绑定硬件。这个驱动为后续PciBusDxe的执行提供root bridge instances相关数据结构。入口函数是InitializePciHostBridge,驱动主体代码如下。

 

/**

  Entry point of this driver.

  @param ImageHandle  Image handle of this driver.
  @param SystemTable  Pointer to standard EFI system table.

  @retval EFI_SUCCESS       Succeed.
  @retval EFI_DEVICE_ERROR  Fail to install PCI_ROOT_BRIDGE_IO protocol.

**/
EFI_STATUS
EFIAPI
InitializePciHostBridge (
  IN EFI_HANDLE         ImageHandle,
  IN EFI_SYSTEM_TABLE   *SystemTable
  )
{
  EFI_STATUS                  Status;
  PCI_HOST_BRIDGE_INSTANCE    *HostBridge;
  PCI_ROOT_BRIDGE_INSTANCE    *RootBridge;
  PCI_ROOT_BRIDGE             *RootBridges;
  UINTN                       RootBridgeCount;
  UINTN                       Index;
  PCI_ROOT_BRIDGE_APERTURE    *MemApertures[4];
  UINTN                       MemApertureIndex;
  BOOLEAN                     ResourceAssigned;
  LIST_ENTRY                  *Link;
  UINT64                      HostAddress;

  RootBridges = PciHostBridgeGetRootBridges (&RootBridgeCount);
  if ((RootBridges == NULL) || (RootBridgeCount == 0)) {
    return EFI_UNSUPPORTED;
  }

  Status = gBS->LocateProtocol (&gEfiCpuIo2ProtocolGuid, NULL, (VOID **) &mCpuIo);
  ASSERT_EFI_ERROR (Status);

  //
  // Most systems in the world including complex servers have only one Host Bridge.
  //
  HostBridge = AllocateZeroPool (sizeof (PCI_HOST_BRIDGE_INSTANCE));
  ASSERT (HostBridge != NULL);

  HostBridge->Signature        = PCI_HOST_BRIDGE_SIGNATURE;
  HostBridge->CanRestarted     = TRUE;
  InitializeListHead (&HostBridge->RootBridges);
  ResourceAssigned             = FALSE;

  //
  // Create Root Bridge Device Handle in this Host Bridge
  //
  for (Index = 0; Index < RootBridgeCount; Index++) {
    //
    // Create Root Bridge Handle Instance
    //
    RootBridge = CreateRootBridge (&RootBridges[Index]);
    ASSERT (RootBridge != NULL);
    if (RootBridge == NULL) {
      continue;
    }

    //
    // Make sure all root bridges share the same ResourceAssigned value.
    //
    if (Index == 0) {
      ResourceAssigned = RootBridges[Index].ResourceAssigned;
    } else {
      ASSERT (ResourceAssigned == RootBridges[Index].ResourceAssigned);
    }

    if (RootBridges[Index].Io.Base <= RootBridges[Index].Io.Limit) {
      //
      // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.
      // For GCD resource manipulation, we need to use host address.
      //
      HostAddress = TO_HOST_ADDRESS (RootBridges[Index].Io.Base,
        RootBridges[Index].Io.Translation);

      Status = AddIoSpace (
                 HostAddress,
                 RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1
                 );
      ASSERT_EFI_ERROR (Status);
      if (ResourceAssigned) {
        Status = gDS->AllocateIoSpace (
                        EfiGcdAllocateAddress,
                        EfiGcdIoTypeIo,
                        0,
                        RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1,
                        &HostAddress,
                        gImageHandle,
                        NULL
                        );
        ASSERT_EFI_ERROR (Status);
      }
    }

    //
    // Add all the Mem/PMem aperture to GCD
    // Mem/PMem shouldn't overlap with each other
    // Root bridge which needs to combine MEM and PMEM should only report
    // the MEM aperture in Mem
    //
    MemApertures[0] = &RootBridges[Index].Mem;
    MemApertures[1] = &RootBridges[Index].MemAbove4G;
    MemApertures[2] = &RootBridges[Index].PMem;
    MemApertures[3] = &RootBridges[Index].PMemAbove4G;

    for (MemApertureIndex = 0; MemApertureIndex < ARRAY_SIZE (MemApertures); MemApertureIndex++) {
      if (MemApertures[MemApertureIndex]->Base <= MemApertures[MemApertureIndex]->Limit) {
        //
        // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.
        // For GCD resource manipulation, we need to use host address.
        //
        HostAddress = TO_HOST_ADDRESS (MemApertures[MemApertureIndex]->Base,
          MemApertures[MemApertureIndex]->Translation);
        Status = AddMemoryMappedIoSpace (
                   HostAddress,
                   MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,
                   EFI_MEMORY_UC
                   );
        ASSERT_EFI_ERROR (Status);
        Status = gDS->SetMemorySpaceAttributes (
                        HostAddress,
                        MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,
                        EFI_MEMORY_UC
                        );
        if (EFI_ERROR (Status)) {
          DEBUG ((DEBUG_WARN, "PciHostBridge driver failed to set EFI_MEMORY_UC to MMIO aperture - %r.\n", Status));
        }
        if (ResourceAssigned) {
          Status = gDS->AllocateMemorySpace (
                          EfiGcdAllocateAddress,
                          EfiGcdMemoryTypeMemoryMappedIo,
                          0,
                          MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,
                          &HostAddress,
                          gImageHandle,
                          NULL
                          );
          ASSERT_EFI_ERROR (Status);
        }
      }
    }
    //
    // Insert Root Bridge Handle Instance
    //
    InsertTailList (&HostBridge->RootBridges, &RootBridge->Link);
  }

  //
  // When resources were assigned, it's not needed to expose
  // PciHostBridgeResourceAllocation protocol.
  //
  if (!ResourceAssigned) {
    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;

    Status = gBS->InstallMultipleProtocolInterfaces (
                    &HostBridge->Handle,
                    &gEfiPciHostBridgeResourceAllocationProtocolGuid, &HostBridge->ResAlloc,
                    NULL
                    );
    ASSERT_EFI_ERROR (Status);
  }

  for (Link = GetFirstNode (&HostBridge->RootBridges)
       ; !IsNull (&HostBridge->RootBridges, Link)
       ; Link = GetNextNode (&HostBridge->RootBridges, Link)
       ) {
    RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
    RootBridge->RootBridgeIo.ParentHandle = HostBridge->Handle;

    Status = gBS->InstallMultipleProtocolInterfaces (
                    &RootBridge->Handle,
                    &gEfiDevicePathProtocolGuid, RootBridge->DevicePath,
                    &gEfiPciRootBridgeIoProtocolGuid, &RootBridge->RootBridgeIo,
                    NULL
                    );
    ASSERT_EFI_ERROR (Status);
  }
  PciHostBridgeFreeRootBridges (RootBridges, RootBridgeCount);

  if (!EFI_ERROR (Status)) {
    mIoMmuEvent = EfiCreateProtocolNotifyEvent (
                    &gEdkiiIoMmuProtocolGuid,
                    TPL_CALLBACK,
                    IoMmuProtocolCallback,
                    NULL,
                    &mIoMmuRegistration
                    );
  }

  return Status;
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1. 首先是PciHostBridgeGetRootBridges,这个函数在不同的平台上的实现细节不一样,下边是其中一种,但目的都是返回一个包含所有root bridge instances的数组。接口是统一的,实现细节有差异。

/**
  Return all the root bridge instances in an array.

  @param Count  Return the count of root bridge instances.

  @return All the root bridge instances in an array.
          The array should be passed into PciHostBridgeFreeRootBridges()
          when it's not used.
**/
PCI_ROOT_BRIDGE *
EFIAPI
PciHostBridgeGetRootBridges (
  UINTN *Count
)
{
  return ScanForRootBridges (Count);
}

按照PCI spec,一个PCI总线域的Bus取值范围为 0 ~ 255,Dev 0 ~ 31, Func 0 ~ 7.  ScanForRootBridges据此通过Bus/Dev/Func三层for循环轮询,挨个检查每个Func的configuration space的Vendor ID是否为FFFFh. 按照PCI spec定义FFFFh表示Func不存在。如果轮询发现一个Bus下至少存在一个Func, 则表示Root Bridge存在(有意义)。然后在RootBridges数组为这个Root Bridge分配并初始化一个PCI_ROOT_BRIDGE元素。说白了,其实就是用一个PCI_ROOT_BRIDGE structure数组来抽象所有的Root Bridges.

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

    ZeroMem (&Io, sizeof (Io));
    ZeroMem (&Mem, sizeof (Mem));
    ZeroMem (&MemAbove4G, sizeof (MemAbove4G));
    ZeroMem (&PMem, sizeof (PMem));
    ZeroMem (&PMemAbove4G, sizeof (PMemAbove4G));
    Io.Base = Mem.Base = MemAbove4G.Base = PMem.Base = PMemAbove4G.Base = MAX_UINT64;
    //
    // 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++;

        ...

      } // End Func
    } // End Dev


    //
    // 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)++;
    }
  }

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2. 因为一般大多数系统只含有一个Host Bridge, 驱动接下来初始化一个PCI_HOST_BRIDGE_INSTANCE结构变量,用以抽象Host Bridge. 

    然后,依照上边的PCI_ROOT_BRIDGE structure数组元素依次生成一个PCI_ROOT_BRIDGE_INSTANCE structure并初始化,将每个Root Bridge的IO/MEM资源记录到GCD.

    最后将PCI_ROOT_BRIDGE_INSTANCE  structure逐一添加到HostBridge->RootBridges链表。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

3. 如果没有分配资源,则给Host Bridge安装gEfiPciHostBridgeResourceAllocationProtocolGuid. 

    轮询HostBridge->RootBridges,给每个节点(Root Bridge)安装gEfiDevicePathProtocolGuid和gEfiPciRootBridgeIoProtocolGuid.

    释放PCI_ROOT_BRIDGE structure数组占用的资源。

    如果正常则创建gEdkiiIoMmuProtocolGuid的NotifyEvent.

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值