赞
踩
在前面有关PCIe基础知识的介绍中中已经结合Spec详细的介绍了PCIe的空间情况、如何读取PCIe的配置空间以及读取出来的PCIe配置空间的含义。以上的介绍已经大致回答了之前提出的第二个问题:
即 利用CFC&CF8两个端口读取回来的信息具体含义是什么?
接下来我们开始第一个问题的分析整理:
PCIe设备的Bus Device Function号是如何分配的?
BDF的分配是UEFI在扫描 PCIe设备、分配资源、构建PCIe层级结构、最终生成完整的PCIe子系统这一系列操作中的一个小步骤。PCIe设备的扫描以及层级的构建是UEFI中一个非常重要的模块,因此单独孤立的看BDF的分配对于理解这个过程的帮助有限,因此接下来我会将PCIe子构建的整个流程按照代码顺序做一个简单的梳理。
在结合代码进行深入的了解之前,首先需要了解的是一些PCIe相关的基础概念,这些概念是能够看懂代码的基础,也是实际常常能够用到的东西。
A defined System Element that includes at least one Host Bridge, Root Port, or Root Complex Integrated Endpoint. 1
一个被定义的系统元素,至少包括一个HostBridge,RootPort 或者 Root Complex Integrated Endpoint
Pcie Spec中的说明并不是很精确,查阅了很多的资料之后个人对此的理解总结如下:
前面介绍RC的过程中就提到了root port的概念。要明确这一个概念首先先了解Port的意思 1
port
- 逻辑上,指组件和PCIe link之间的接口
- 物理上,指位于同一个芯片上的一组发射/接收器,这组发射接收器定义了一个link
更加详细的解释2:
Port是PCIe 组成和链路之间的接口, 由发射器和接收器组成。
Upstream port 指的是指向RC的port,Downstream port是指向背离RC的port。
Endpoint 是 Upstream port ,RC port 是 Downstream port
Ingress Port是接收packet的port, Egress Port是发送packet的port
下面再来看root port的概念
Root Port是位于RC上的port,这些port通过相关联的虚拟PCI-PCI bridge 映射层级结构中的部分
这样看起来比较抽象,可以综合上面的解释,在对root (complex) port进行一个说明
Root port就是位于RC上的连接RC与link的interface, 从物理结构上看是一对发射接收器,逻辑上是一个downstream port
RC中还提到了HostBridge,下面是PCIe Spec对HostBridge 的定义1
Host Bridge 是RC的一部分,用以连接CPU和PCIe层级结构
在PI Spec 3中对于Host Bridge 有更详细的描述
PCI host bridge
能够产生一个或者多个PCI Root Bridge的软件抽象。由一个host bus controller产生的所有的PCI bus都属于同一个coherency domain。 PCI Host Bridge 是一个抽象的概念,可能会由很多的硬件设备组成。大多数的系统都可以抽象成只有一个PCI Host Bridge的模型。当处理PCI 资源分配的时候这种软件层面的抽象是必须的,因为对一个PCI root bridge 的资源分配要依赖于另外的root bridge,并且在资源分配期间必须考虑所有相关的PCI Host Bridge
每一个PCI Host Bridge 都是由一个或者多个PCI root bridge组成,并且存在与PCI root bridge相关的硬件寄存器。这些寄存器控制 由PCI root bridge生成的root bus和所有这个root bus生成的子bus 申请的bus memory IO资源
综合以上的描述,可以对host bridge 进行总结
PI Spec中的介绍
Root Bridge
Root Bridge会产生root PCI bus。Root Bridge连接了root PCI bus和非PCI bus. 一个PCI host bridge 可能会有一个或者多个root bridge。对于同一个host bridge 下的 一个root bridge 的配置要依赖于其下其余的root bridge的情况
UEFI Spec中的介绍
PCI root bridge 能够产生物理PCI bus的芯片组组件。它也是一组PCI 设备的父设备,这些PCI设备共享PCI IO ,Memory, prefetchable memory区域。一个PCI host bus controller 由一个或者多个PCI root bridge组成
综合以上可以得到对PCI root bridge 的总结
前面说了Host Bridge Root Bridge,关于Bridge的具体含义也需要看一下
Bridge
定义的系统基本元素之一。
将PCI/PCI-X Segment (or PCIe Port) 与内部组件或者另外的PCI/PCI-X Segment (or PCIe Port)进行互联.
在RC或者Switch中虚拟的bridge必须使用使用规范中的配置接口进行描述
简单来说,PCI bridge 提供了以其他总线或者与PCIe总线的连接。实际上,我看到的比较常见的桥的功能就是扩展出一个PCI bus
Switch
定义的系统基本元素之一。它连接了两个或者多个port,允许 packet从一个port路由到另一个。
对于软件来说,switch可以看做虚拟的P2Pbridge的集合
从上述我们可以总结
前面分散的说了很多概念,在实际的代码和应用中,除了了解这些概念更重要的是掌握这些概念之间的关系以及使用的情况。以EDKII代码为例,说一下我自己对这些概念的理解
HostBridge : RC的组成部分用来实现地址转化的结构,Host Bridge 和 RootBridge 由HostBus连接.这个Bus 是在 Chipset Component内部进行连接的,其在系统中的抽象就是Pci Host Bus Controller
RootBeidge : RC的组成部分,由HostBridge产生,其延伸出的就是 Pci Local Bus
RootPort : 位于RC上的连接 RC与下级PCI结构的 Port
还有需要补充的一点,在一个系统中,理论上可以存在多个HostBridge,实际上很多代码中,也是视为存在多个HostBridge进行处理的。但是目前为止起码我接触到的平台实际上还都是一个HostBridge的
前面说HostBridge能够产生RootBrodge,产生的RootBridge的数量是不确定的,可以是一个也可以是多个。一般来说,简单的桌面系统是一个RootBridge的,但是一般大型的服务器,都是存在多个RootBridge的
根据前面对于PCIe一些相关的概念的描述,可以得到一个包含了RC ,host bridge, root bridge switch的PCIe结构关系的示意图(个人理解)
在UEFI中,针对PCIe子系统的构建主要可以分成两个部分:
前面已经说过HostBridge的具体实现情况是与平台相关的,不同平台的实现方法是不同的。但是在代码中,都是需要对HostBridge进行初始化并且构建相应的结构体描述。现在不讨论对于HostBridge的初始化,仅仅对后面构建相应的结构进行介绍,这一部分在 PciHostBridge.c
文件中。
!!!再次说明,不同平台对于HostBridge的实现情况是不同的,所以初始化、结构构建情况也是不同的,当前只是以EDKII中的代码作为示例
在详细了解初始化函数之前先看一下 inf 文件
可以看到这是一个DXE_DRIVER
类型的driver,这种类型的driver在DXE的初始阶段执行,通常用来做硬件的初始化并且产生后续需要使用的protocol。入口函数为 InitializePciHostBridge
大致分析一下 InitializePciHostBridge
函数
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; }
函数一开始就对当前HostBridge下的RootBridges进行了枚举,获取到了当前这个HostBridge下的所有的RootBridges的基础信息和RootBridges的数量。RootBridges为 PCI_ROOT_BRIDGE
类型的结构体,其定义如下
typedef struct { UINT32 Segment; ///< Segment number. UINT64 Supports; ///< Supported attributes. ///< Refer to EFI_PCI_ATTRIBUTE_xxx used by GetAttributes() ///< and SetAttributes() in EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. UINT64 Attributes; ///< Initial attributes. ///< Refer to EFI_PCI_ATTRIBUTE_xxx used by GetAttributes() ///< and SetAttributes() in EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. BOOLEAN DmaAbove4G; ///< DMA above 4GB memory. ///< Set to TRUE when root bridge supports DMA above 4GB memory. BOOLEAN NoExtendedConfigSpace; ///< When FALSE, the root bridge supports ///< Extended (4096-byte) Configuration Space. ///< When TRUE, the root bridge supports ///< 256-byte Configuration Space only. BOOLEAN ResourceAssigned; ///< Resource assignment status of the root bridge. ///< Set to TRUE if Bus/IO/MMIO resources for root bridge have been assigned. UINT64 AllocationAttributes; ///< Allocation attributes. ///< Refer to EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM and ///< EFI_PCI_HOST_BRIDGE_MEM64_DECODE used by GetAllocAttributes() ///< in EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL. PCI_ROOT_BRIDGE_APERTURE Bus; ///< Bus aperture which can be used by the root bridge. PCI_ROOT_BRIDGE_APERTURE Io; ///< IO aperture which can be used by the root bridge. PCI_ROOT_BRIDGE_APERTURE Mem; ///< MMIO aperture below 4GB which can be used by the root bridge. PCI_ROOT_BRIDGE_APERTURE MemAbove4G; ///< MMIO aperture above 4GB which can be used by the root bridge. PCI_ROOT_BRIDGE_APERTURE PMem; ///< Prefetchable MMIO aperture below 4GB which can be used by the root bridge. PCI_ROOT_BRIDGE_APERTURE PMemAbove4G; ///< Prefetchable MMIO aperture above 4GB which can be used by the root bridge. EFI_DEVICE_PATH_PROTOCOL *DevicePath; ///< Device path. } PCI_ROOT_BRIDGE;
这个地方需要说明两个问题
PciHostBridgeGetRootBridges
在不同平台的实现完全不同。在EDKII中有Ovmf &Uefipayload的实现情况,感兴趣的可以自己详细研究一下,这两种实现是两个思路:Ovmf是扫描设备信息进行信息的获取(因为是虚拟机),而Uefipayload是根据PEI阶段传递的HOB进行信息的获取与构建PciHostBridgeGetRootBridges
代码进行简单的介绍,所有PciHostBridgeGetRootBridges
的最终目的都是为了获取RootBridge的基本信息(这个函数和平台是高度相关的 所以不同平台上是不同的)PCI_ROOT_BRIDGE * EFIAPI PciHostBridgeGetRootBridges ( UINTN *Count ) { PCI_ROOT_BRIDGE *RootBridges; *Count = 1; RootBridges = AllocateZeroPool(sizeof (PCI_ROOT_BRIDGE)); if(RootBridges == NULL) { DEBUG ((EFI_D_ERROR, "RootBridges AllocateZeroPool error!\n")); return NULL; } RootBridges->Attributes = ( EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO | EFI_PCI_ATTRIBUTE_ISA_IO | EFI_PCI_ATTRIBUTE_VGA_MEMORY | EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_ATTRIBUTE EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO | EFI_PCI_ATTRIBUTE_ISA_IO_16 | EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16 | EFI_PCI_ATTRIBUTE_VGA_IO_16); RootBridges->Supports = ( EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO | EFI_PCI_ATTRIBUTE_ISA_IO | EFI_PCI_ATTRIBUTE_VGA_MEMORY | EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_ATTRIBUTE EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO | EFI_PCI_ATTRIBUTE_ISA_IO_16 | EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16 | EFI_PCI_ATTRIBUTE_VGA_IO_16); RootBridges->DmaAbove4G = 1; RootBridges->Bus.Base = 0; RootBridges->Bus.Limit = 255; RootBridges->Io.Base = 0x20000; //0xffffffffb8000000 DEBUG ((EFI_D_ERROR, "Io.Base 0x%llx\n",RootBridges->Io.Base)); RootBridges->Io.Limit = RootBridges->Io.Base + 0x2000000 ; DEBUG ((EFI_D_ERROR, "Io.Limit 0x%llx\n",RootBridges->Io.Limit)); RootBridges->Mem.Base = 0x40000000; //0xffffffff40000000 DEBUG ((EFI_D_ERROR, "Mem.Base 0x%llx\n",RootBridges->Mem.Base)); RootBridges->Mem.Limit = RootBridges->Mem.Base + 0x40000000; DEBUG ((EFI_D_ERROR, "Mem.Limit 0x%llx\n",RootBridges->Mem.Limit)); return RootBridges; }
上述代码中初始化了 PCI_ROOT_BRIDGE *RootBridges;
结构体的部分成员,其中最重要的成员就是Bus ,IO ,Mem的 Base &limit。
Io.Base表示了这个root bridge的IO空间可分配的基地址,这个基地址就是我们前面说过的要写入Bar空间的基地址 只不过后面扫描出的设备多了,写入的地址需要累加变大就是了。Io.Limit表示了长度。Mem.Base和Mem.Limit同理
接下来是根据已知的HostBridge信息创建结构体 PCI_HOST_BRIDGE_INSTANCE *HostBridge;
//
// 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;
此处仅对部分成员初始化了,未初始化的成员后面会进行相应的操作
PCI_HOST_BRIDGE_INSTANCE
的详细信息如下
typedef struct {
UINTN Signature;
EFI_HANDLE Handle;
LIST_ENTRY RootBridges;
BOOLEAN CanRestarted;
EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL ResAlloc;
} PCI_HOST_BRIDGE_INSTANCE;
此结构体中三个关键的成员分别进行简单的说明
EFI_HANDLE Handle
: 此时没有对这个Handle进行初始化,后面会进行。此处的Handle和之前我们介绍的Handle一样,在软件层面表示了当前的HostBridge Controller,这个Handle同样会插入 handle database
链表进行相应的维护LIST_ENTRY RootBridges
前面反复的说过,LIST_ENTRY
是一个很明显的信号,表示这个位置能够扩展出一个双向链表。后面就会发现,此处在这个PCI_HOST_BRIDGE_INSTANCE 下,连接的是PCI_ROOT_BRIDGE_INSTANCE链表EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL ResAlloc
定义了EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
的函数,这些函数在后面扫描设备、申请空间的时候需要用到接下来对当前HostBridge下的所有的RootBridge进行了遍历
for (Index = 0; Index < RootBridgeCount; Index++)
对每一个获得的RootBridge创建相应的Instance结构体
//
// Create Root Bridge Handle Instance
//
RootBridge = CreateRootBridge (&RootBridges[Index]);
ASSERT (RootBridge != NULL);
if (RootBridge == NULL) {
continue;
}
PCI_ROOT_BRIDGE_INSTANCE结构体如下
typedef struct { UINT32 Signature; LIST_ENTRY Link; EFI_HANDLE Handle; UINT64 AllocationAttributes; UINT64 Attributes; UINT64 Supports; PCI_RES_NODE ResAllocNode[TypeMax]; PCI_ROOT_BRIDGE_APERTURE Bus; PCI_ROOT_BRIDGE_APERTURE Io; PCI_ROOT_BRIDGE_APERTURE Mem; PCI_ROOT_BRIDGE_APERTURE PMem; PCI_ROOT_BRIDGE_APERTURE MemAbove4G; PCI_ROOT_BRIDGE_APERTURE PMemAbove4G; BOOLEAN DmaAbove4G; BOOLEAN NoExtendedConfigSpace; VOID *ConfigBuffer; EFI_DEVICE_PATH_PROTOCOL *DevicePath; CHAR16 *DevicePathStr; EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL RootBridgeIo; BOOLEAN ResourceSubmitted; LIST_ENTRY Maps; } PCI_ROOT_BRIDGE_INSTANCE;
部分CreateRootBridge函数
PCI_ROOT_BRIDGE_INSTANCE * CreateRootBridge ( IN PCI_ROOT_BRIDGE *Bridge ) { PCI_ROOT_BRIDGE_INSTANCE *RootBridge; PCI_RESOURCE_TYPE Index; CHAR16 *DevicePathStr; PCI_ROOT_BRIDGE_APERTURE *Aperture; // ... RootBridge->Signature = PCI_ROOT_BRIDGE_SIGNATURE; RootBridge->Supports = Bridge->Supports; RootBridge->Attributes = Bridge->Attributes; RootBridge->DmaAbove4G = Bridge->DmaAbove4G; RootBridge->NoExtendedConfigSpace = Bridge->NoExtendedConfigSpace; RootBridge->AllocationAttributes = Bridge->AllocationAttributes; RootBridge->DevicePath = DuplicateDevicePath (Bridge->DevicePath); RootBridge->DevicePathStr = DevicePathStr; RootBridge->ConfigBuffer = AllocatePool ( TypeMax * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR) ); ASSERT (RootBridge->ConfigBuffer != NULL); InitializeListHead (&RootBridge->Maps); CopyMem (&RootBridge->Bus, &Bridge->Bus, sizeof (PCI_ROOT_BRIDGE_APERTURE)); CopyMem (&RootBridge->Io, &Bridge->Io, sizeof (PCI_ROOT_BRIDGE_APERTURE)); CopyMem (&RootBridge->Mem, &Bridge->Mem, sizeof (PCI_ROOT_BRIDGE_APERTURE)); CopyMem (&RootBridge->MemAbove4G, &Bridge->MemAbove4G, sizeof (PCI_ROOT_BRIDGE_APERTURE)); CopyMem (&RootBridge->PMem, &Bridge->PMem, sizeof (PCI_ROOT_BRIDGE_APERTURE)); CopyMem (&RootBridge->PMemAbove4G, &Bridge->PMemAbove4G, sizeof (PCI_ROOT_BRIDGE_APERTURE)); for (Index = TypeIo; Index < TypeMax; Index++) { switch (Index) { case TypeBus: Aperture = &RootBridge->Bus; break; case TypeIo: Aperture = &RootBridge->Io; break; case TypeMem32: Aperture = &RootBridge->Mem; break; case TypeMem64: Aperture = &RootBridge->MemAbove4G; break; case TypePMem32: Aperture = &RootBridge->PMem; break; case TypePMem64: Aperture = &RootBridge->PMemAbove4G; break; default: ASSERT (FALSE); Aperture = NULL; break; } RootBridge->ResAllocNode[Index].Type = Index; if (Bridge->ResourceAssigned && (Aperture->Limit >= Aperture->Base)) { // // Base in ResAllocNode is a host address, while Base in Aperture is a // device address. // RootBridge->ResAllocNode[Index].Base = TO_HOST_ADDRESS ( Aperture->Base, Aperture->Translation ); RootBridge->ResAllocNode[Index].Length = Aperture->Limit - Aperture->Base + 1; RootBridge->ResAllocNode[Index].Status = ResAllocated; } else { RootBridge->ResAllocNode[Index].Base = 0; RootBridge->ResAllocNode[Index].Length = 0; RootBridge->ResAllocNode[Index].Status = ResNone; } } RootBridge->RootBridgeIo.SegmentNumber = Bridge->Segment; RootBridge->RootBridgeIo.PollMem = RootBridgeIoPollMem; RootBridge->RootBridgeIo.PollIo = RootBridgeIoPollIo; RootBridge->RootBridgeIo.Mem.Read = RootBridgeIoMemRead; RootBridge->RootBridgeIo.Mem.Write = RootBridgeIoMemWrite; RootBridge->RootBridgeIo.Io.Read = RootBridgeIoIoRead; RootBridge->RootBridgeIo.Io.Write = RootBridgeIoIoWrite; RootBridge->RootBridgeIo.CopyMem = RootBridgeIoCopyMem; RootBridge->RootBridgeIo.Pci.Read = RootBridgeIoPciRead; RootBridge->RootBridgeIo.Pci.Write = RootBridgeIoPciWrite; RootBridge->RootBridgeIo.Map = RootBridgeIoMap; RootBridge->RootBridgeIo.Unmap = RootBridgeIoUnmap; RootBridge->RootBridgeIo.AllocateBuffer = RootBridgeIoAllocateBuffer; RootBridge->RootBridgeIo.FreeBuffer = RootBridgeIoFreeBuffer; RootBridge->RootBridgeIo.Flush = RootBridgeIoFlush; RootBridge->RootBridgeIo.GetAttributes = RootBridgeIoGetAttributes; RootBridge->RootBridgeIo.SetAttributes = RootBridgeIoSetAttributes; RootBridge->RootBridgeIo.Configuration = RootBridgeIoConfiguration; return RootBridge;
在CreateRootBridge函数中可以看到PCI_ROOT_BRIDGE_INSTANCE结构体的绝大部分成员都是直接从PCI_ROOT_BRIDGE RootBridges
获得的,但是有一个位置的参数是经过了转换的
RootBridge->ResAllocNode[Index].Type = Index; if (Bridge->ResourceAssigned && (Aperture->Limit >= Aperture->Base)) { // // Base in ResAllocNode is a host address, while Base in Aperture is a // device address. // RootBridge->ResAllocNode[Index].Base = TO_HOST_ADDRESS ( Aperture->Base, Aperture->Translation ); RootBridge->ResAllocNode[Index].Length = Aperture->Limit - Aperture->Base + 1; RootBridge->ResAllocNode[Index].Status = ResAllocated; } else { RootBridge->ResAllocNode[Index].Base = 0; RootBridge->ResAllocNode[Index].Length = 0; RootBridge->ResAllocNode[Index].Status = ResNone; } }
这个位置实现的就是我们前面一直在说的PCI CPU域地址的转换。当前在 ResAllocNode结构体数组中保存的Base地址是Host域的地址,而Aperture 中的Base 表示的就是当前device 域中的地址
后面就是将RootBridge->RootBridgeIo 对应的函数都进行了初始化
接下来对所有的ResourceAssigned进行了统一 保证所有结构体中的ResourceAssigned是相同的值
//
// Make sure all root bridges share the same ResourceAssigned value.
//
if (Index == 0) {
ResourceAssigned = RootBridges[Index].ResourceAssigned;
} else {
ASSERT (ResourceAssigned == RootBridges[Index].ResourceAssigned);
}
下面的部分是针对现在有的信息将对应的结果添加到GCD中,这个部分没有详细的研究 先跳过这个部分
接下来 将初始化完成的RootBridge添加到HostBridge->RootBridges链表中。
//
// Insert Root Bridge Handle Instance
//
InsertTailList (&HostBridge->RootBridges, &RootBridge->Link);
然后安装 HostBridgeResourceAllocationProtocol到HostBridge Handle
// // 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); }
这一段代码中在此遍历了创建好的RootBridge Instance结构体,并且在每个对应的Handle上都安装了DevicePathProtocol
和 RootBridgeIoProtocol
。
最后free掉了最开始Get到的 PCI_ROOT_BRIDGE RootBridges
数组
PciHostBridgeFreeRootBridges (RootBridges, RootBridgeCount);
最后这个部分创建了一个与IOMMU相关的Event 当IoMmuProtocol被注册的时候这个函数就会被调用
if (!EFI_ERROR (Status)) {
mIoMmuEvent = EfiCreateProtocolNotifyEvent (
&gEdkiiIoMmuProtocolGuid,
TPL_CALLBACK,
IoMmuProtocolCallback,
NULL,
&mIoMmuRegistration
);
}
当前不关心这个部分 跳过
HostBridge初始化函数 InitializePciHostBridge
主要完成的工作有以下几点
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。