写在前面的话:
真的可能是英语学得不好,计算基础也学得不好,在学习过程中一些基础的概念都弄不清楚,比如PCIe Capability和PCIe Extended Configuration Space我看名字还以为两者有什么关系,现在弄清楚之后发现两者根本就不是一个水平的概念,现在回想刚接触Spec第7章的我……有点蠢。
主要参考:
NCB-PCI_Express_Base_5.0r1.0-2019-05-22.pdf(也就是PCIe base spec 5.0)
《PCI Express 体系结构导读》
CSDN以及其他各路大神的博客链接,我会在文中或者最后贴上,只限和spec chapter7相关的(学习spec的时候有很多大神博客真幸福,比学习sas幸福多了)
上图是经典的configuration space图,来自spce5.0 r1.0,参考一下《PCI Express 体系结构导读》中的话,
• PCI 设备使用的基本配置空间。这个基本配置空间共由 64 个字节组成,其地址范围为 0x00~0x3F ,这 64 个字节是所有 PCI 设备必须支持的。事实上,许多 PCI 设备也仅支持这 64 个配置寄存器。• 此外 PCI/PCI-X 和 PCIe 设备还扩展了 0x40~0xFF 这段配置空间, 在这段空间主要存放一些与 MSI 或者 MSI-X 中断机制和电源管理相关的 Capability 结构 。其中所有能够提交中断请求的 PCIe 设备,必须支持 MSI 或者 MSI-X Capability 结构。• PCIe 设备还支持 0x100~0xFFF 这段扩展配置空间。 PCIe 设备使用的扩展配置空间最大为 4KB ,在 PCIe 总线的扩展配置空间中,存放 PCIe 设备所独有的一些 Capability 结构,而 PCI 设备不能使用这段空间。
读完上面的话,我恍悟了capabilities的概念,之前就是很疑惑,也不知道其实在PCIe里面有两个capabilities链表。
换成我自己的理解,就是最开始只有PCI设备,它的配置空间就只有0x00~0x3F这么大,这里存放configuration space Header,后来更新换代,新的PCI/PCI-X扩展了0x40~0xFF这段配置空间,在这段空间里存放第一个capabilities链表,这些capabilities主要和中断以及电源管理相关,这里放上一个lecroy协议分析仪分析的configuration space图。
框起来的就是存放在这段空间内的capabilities,注意这里有一个PCI Express Capability,初学时我一直在想这个和PCIe extended configuration space有什么关系,幻想是不是在PCI Configuration Space里面使能了这个Capability,PCIe extended configuration space才能使用。学习禁止幻想,好好读书,两者没有关系。PCIe Capability就是一个叫做PCIe这个名字的Capability,和中断用的Capability,电源管理用的Capability一样,放在0x40~0xFF这段配置空间,“存放一些和PCIe总线相关的信息,包括PCIe链路和插槽的信息”。0x40~0xFF空间不是全部塞满capabilities的,《PCI Express 体系结构导读》中说“事实上,许多PCI设备也仅支持这64个配置寄存器。”就是可能扩展的空间没有实际利用掉,就没有capabilities……
然后设备再更新换代,就有了PCIe,要扩展更多空间,所以有了“PCIe设备还支持0x100~0xFFF这段扩展配置空间”这句话,0x100~0xFFF这段空间存放第二个capabilities链表。
再总结一下,Configuration Space可以分为两段(对着第一个图看可能更清晰),第一段是PCI configuration Space(spec上也称之为PCI-Compatible Configuration),这一段可以分为两部分,第一部分是0x00~0x3F存放Configuration space Header,第二部分是0x40~0xFF存放中断、电源管理相关的一些capabilities,这些capabilities组成一个链表,有头有尾;第二段是PCI EXpress Extended Configuration space,这一部分存放PCIe独有的一些capabilities,这是另外一个链表,也有自己的首尾。
(总结的话有点废话……但是对于初学的我来说,终于理清楚了,感谢龙哥,感谢协议分析仪,终于看到第二个链表起始位置就在100h,理解了再去看之前大神的博客里面的话,觉得自己好傻哈哈哈)
这里按照第一节的总结的话来分述,但是我觉得spec把逻辑复杂了,小节标题整体按照spec的思路,但是有些部分不是完全按照的。
header里面每一个register的含义概念,在spec上都可以查找到,每个bit的含义也都有明确定义,如果看不懂可以参考《PCI Express 体系结构导读》,但是没有实际应用的时候,看了也就是看个表皮,我现在就是只知道有这个概念,每个bit什么时候使能都不太懂,遇到具体问题可以具体查看每个bit。根据前一段的学习,我觉得比较大的概念是Base Address Register(BAR),Expansion Rom Base Address和Capabilities Pointer(status和command似乎也很重要,但是还没深入学到,严谨来讲,每一个bit都很重要),所以只简单说一些我对着三个register的学习及理解。
1.1.1Base Address Register(BAR)
• X86 采用独立编址的方式,将 memory 操作与外设 IO 操作分开了,才有了 memory 空间和 IO 空间的区分。 X86 平台 CPU 内部对内存和外设寄存器访问的指令也是不同的。• IO 空间 :访问外部设备寄存器的地址区域,( PCI 支持 4GB 的 IO 空间,但是 x86 平台为 64KB )。• memory 空间 :访问内存的地址空间, 32 位平台为 4G 。 此 memory 空间和 main memory (平时常说的内存或者主存)是两个概念, 32bit 平台下 CPU memory 地址总线只能寻址到 4G ,这 4G 空间包括 main memory 、外设 IO 空间映射( MMIO )等,不能全给 main memory ,因此 32bit 的 CPU 是无法配置 4G 内存的。• X86 的 CPU 可以直接访问 memory 空间和 IO 空间,但是不能直接访问 PCIe 配置空间(原因很简单, X86 的 CPU 只有 memory 指令和 IO 指令,没有配置指令)。因此,需要把 PCIe 配置空间映射到 memory 空间或者 IO 空间(一般不推荐映射到 IO 空间)。原文链接: https://blog.csdn.net/linjiasen/article/details/87944672
上述引用的内容搞明白了,总之configuration space要映射到memory/io space中,才方便cpu访问,io方式是老设备常用的,目前大多数保留了io映射以及访问方式,但基本都采用memory映射及访问。
BAR(base address registers)就是为了把设备的内部各种资源映射到IO空间(IO BAR)或者memory 空间(memory BAR)。(这里还有一个小小问题,还没学到,等学到再补上,这个内部资源是什么呢,是设备的一些data?)
Type0的BAR从 010h到024h,一共6个BAR,一个32bit是一个BAR,bit0是0就是memory映射,是1就是io映射,这里不讲io映射,只讲memory映射。
对于memory映射,bits 2:1表示映射方式是32位还是64位,如果是32位就只使用一个BAR完成一次映射,比如BAR0,如果是64位,就用两个BAR映射,比如BAR0-1。一旦BAR的值确定了(Have been programmed),其指定范围内的当前设备中的内部寄存器(或内部存储空间)就可以被访问了。
BAR配置过程:PCIe扫盲——基地址寄存器(BAR)详解-Felix-电子技术应用-AET-中国科技核心期刊-最丰富的电子设计资源平台 (chinaaet.com)http://blog.chinaaet.com/justlxy/p/5100053320
上述博客写得很详细了,参考这篇博客再结合实际抓的包,再梳理一下下BAR配置过程。
初始化BAR0-BAR1,所谓初始化,就是系统(软件)向整个BAR都写1,来确定BAR的可操作的最低位是哪一位。(CfgWr0)
读取初始化后的BAR0-BAR1,确定当前可操作的最低位为25,因此当前BAR可申请的(最小)地址空间大小为32MB(2^25). (CfgRd0)
软件向BAR的高比特写入地址空间的起始地址(Start Address)。(CfgWr0)
起始地址: 0000 019D 0E00 0000h
上图框起来的(5),写入的全是0应该是没有实用的第一次写入,第二个图写入的才是真正的起始的地址。抓的包,BAR2-5全是0,默认是不使用的意思。
1.1.2 Expansion Rom Base Address
•Expansion rom是pci/pcie设备可选的一个外接的EPROM芯片,其中用来存储相应pci设备的初始化代码或者系统启动代码(比如pxe或者pci boot)。BIOS在POST(Power-on Self Test)阶段,会扫描pci设备是否有expansion rom,有的话将其拷贝到ram中执行。在PCI规范中称为expansion rom,在BIOS术语里面称为option rom。
1.2 PCI&PCIE ExpansionOption ROM_pwl999的博客-CSDN博客https://blog.csdn.net/pwl999/article/details/78208065/本小节大多摘自这篇博客……
1.1.2.1 从configuration space角度去看expansion rom:
bit11-bit31定义expansion rom的映射到memory空间的高位地址bit11-bit31(下位为11位的扩展ROM基址寄存器被软件屏蔽(设为零),形成一个32位地址)。bit0表示是否使能expansion rom,1使能为使能,需要注意的是expansion rom和pci其他的bar空间是共享地址解码的,所以一旦使能expansion rom就不能对其他的bar空间进行操作。
1.1.2.2 从System角度(BIOS 初始化过程)来看expansion rom(option Rom):
• Expansion rom 的组织结构有相应的规范。 一个可能包含多个 rom image , 可以支持多个不同类型的 pci 设备 ,每种设备也可以支持不同架构 cpu 的可执行代码。多个 image 在一个 expansion rom 芯片中的组织如下图所示,其中每份 image 的开始地址都是以 512bytes 对齐的 .• 一份标准的 image 由两部分组成: PCI Expansion ROM Header Format 和 PCI Data Structure Format 。 具体的格式定义如下图:
BIOS的POST阶段,扫描并执行pci设备的expansion rom的过程大概分以下几步:
a、首先判断pci设备是否实现“Expansion rom base address”寄存器,有则进行下一步判断;
#define PCI_DEVICE_ROMBAR 0x30
#define PCI_BRIDGE_ROMBAR 0x38
b、如果有实现了expansion的基址寄存器,则配置和使能expansion rom(),然后查找expansion rom是否有”AA55”的标示字符,如果有则说明设备有真实的expansion rom芯片存在;
#define PCI_EXPANSION_ROM_HEADER_SIGNATURE 0xaa55
b-1 配置和使能expansion rom
Expansion Rom初始化过程与BAR一样,空间计算方法也一样,软件把“Expansion rom base address”寄存器的基地址配置成相应的memory空间地址并使能expansion rom以后,就可以对设备的expansion rom进行读访问了。
上图中,申请了32bit的1MB的Mmory Address Space;起始位置为:D8A0 0000h
b-2 查找expansion rom是否有”AA55”的标示字符
一份标准的image由两部分组成:PCI Expansion ROM Header Format和PCI Data Structure Format。下面是真实的抓包中读取的一份image,有助于加深对image的理解,对照着 1.1.2.2 第二幅图看理解。
Image0->PCI Expansion ROM Header
Image0-> PCI Data Structure
c、如果expansion rom已经存在,则扫描是否有适合本设备和本CPU架构的image代码存在;
d、如果有适合本环境的image代码存在,则把相应的代码拷贝到ram的合适位置,并跳入header format中指定的初始化入口执行;
e、最后关闭expansion rom的使能。
( “还有, option rom 从来就不是在flash 上运行的,它必须先行copy 到RAM 上面,才能执行。”option rom这一部分还是只学会了概念性的东西,对于如何copy,如何映射,只知道表面概念,驱动的代码还没有深入理解。这一部分学得不是很好,可能要好好学习一下bios或者UEFI才可以吧)
1.1.3 Capabilities Pointer
在configuration space总述中,按照理解,如果存在capabilities链表,可以分为两个,一个在PCI configuration space中,在0x40~0xFF这段配置空间;一个在PCIe extended configuration space中,在0x100~0xFFF这段配置空间.
每个链表的结构如下图:
上图是0x40~0xFF这段配置空间capabilities链表的一个例子。链表的开始在Header中0x34处1byte的值。(0x100~0xFFF这段配置空间链表的结构类似,只是链表的开始在0x100处)
在PCI 总线的基本配置空间中,包含一个Capabilities Pointer 寄存器,该寄存器存放Capabilities 结构链表的头指针。
其中每一个Capability 结构都有唯一的ID 号,每一个Capability 寄存器都有一个指针,这个指针指向下一个Capability 结构,从而组成一个单向链表结构,这个链表的最后一个Capability 结构的指针为0。
看实际的包,加深一下理解:
(后续学习,对每个register都有深入一些的理解后,再补充进来一些。)
该部分也只简单说一些我对着某些register的学习(及理解)。和Type0中名称一致的register用途一样,不再累述。
1.2.1 Primary Bus Number Register、Secondary Bus Number Register、Subordinate Bus Number Register
Subordinate Bus Number Register 存放当前 PCI 树中,编号最大的 PCI 总线号; Secondary Bus Number Register 存放当前 PCI 桥的 Secondary Bus 使用的总线号,是该 PCI 桥管理的编号最小的 PCI 总线号。因此一个 PCI 桥能管理的 PCI 总线号在 Secondary Bus Number ~ Subordinate Bus Number 之间,两个寄存器的值在软件系统遍历 PCI 总树时设置。 Primary Bus Number Register 存放该 PCI 桥上游的总线号。该寄存器可读写。
1.2.2 Base/ Limit Registers
Base 和 Limit 寄存器分别确定了其所有分支下设备( The device that live beneath this bridge )的地址的起始和结束地址。根据请求类型的不同,分别对应不同的 Limit&Base 组合:① Prefetchable Memory Space ( P-MMIO )② Non- Prefetchable Memory Space ( NP-MMIO )③ IO Space ( IO )一旦该桥分支下面的任意设备的BAR发生改变,该桥的Base&Limit寄存器也需要做出对应的改变。
PCIe扫盲——Base & Limit寄存器详解-Felix-电子技术应用-AET-中国科技核心期刊-最丰富的电子设计资源平台 (chinaaet.com)http://blog.chinaaet.com/justlxy/p/5100053321
上面提到这里面存放一些和中断以及电源管理相关的capabilities,在spec中主要讲了PCI Power Management Capability和PCI EXpress capability。(累了不想写了,先把图放上去,其实这里需要看哪个bit概念含义对着spec看就行了,register太多了。等后期有经验,哪个bit需要着重关注,再补充)
•该寄存器主要用来记录当前PCIe设备的物理属性
•系统软件需要从该寄存器获得当前PCIe设备的信息后,才能对PMCSR进行修改
• 系统软件可以通过操作 PMCSR 寄存器,完成 PCIe 设备电源管理状态的迁移
2.2 PCI EXpress capability
3. PCI Express Extended configuration space——0x100~0xFFF
这段配置空间存放PCIe独有的capabilities,链表的开始在0x100,其余规则与PCI configuration space 中的capabilities链表方式一致。
只学习了整体概念,具体到每一个capabilities、register的学习还需要进一步的展开,离大神还有很远很远很远很远……很远的很远的距离~以上纯属个人学习理解,应该会有很多小错误。
option rom 学习过程参考链接:
https://maxwell.blog.csdn.net/article/details/51785335
https://blog.csdn.net/Lq19880521/article/details/106078561
https://blog.csdn.net/luobing4365/article/details/102577039?spm=1001.2014.3001.5501
BIOS/UEFI 学习过程参考链接:
https://www.zhihu.com/question/28815746
https://zhuanlan.zhihu.com/p/45352657
https://blog.csdn.net/cqwei1987/article/details/107365329
https://zhuanlan.zhihu.com/p/336441128