目录
[config 空间:](#config 空间:)
[base address register(BAR):](#base address register(BAR):)
[memory 空间:](#memory 空间:)
参考:
https://www.cnblogs.com/linhaostudy/p/18793620https://www.cnblogs.com/linhaostudy/p/18793620
在PICE中定义了四种空间地址,分别为:config空间,mem空间,IO空间,message空间。
config 空间:
每个PCIE 的function 中都有4KB的配置空间,其中前256字节是和PCI兼容的配置空间,剩余的空间是PCIE的扩展配置空间。
配置空间不同于其他空间,PCIE的配置空间是由协议规定好的,什么地方要放什么内容都是有定义的。整个配置空间就是一些寄存器的组合,这些寄存器保存了设备的有关参数和信息。
软件可以通过配置空间对设备的状态进行控制和检查。PCI兼容的配置空间可以通过CAM或者ECAM机制进行访问,而PCIE扩展配置空间只能通过ECAM机制访问。
ECAM(enchanced configuration access mechanism)是访问PCIE配置空间的机制,这种机制是通过将PCIE的配置空间映射到MEM空间,使用MEM访问其配置空间的一种实现。
配置空间由两部分组成:64字节的header(配置头)+192字节的capability结构,capability结构是告诉主机它的一些特殊功能。
不过需要注意的是,PCIE配置空间对应的真实物理内存是在PCIE自己内部,不是在主机DDR里。这部分地址会映射到主机内存地址里。因此主机DDR用不了这个被映射的地址,说通俗点就是DDR用不了显存。
进入到PCIE时候后,192字节的capability结构不足以支持它的内容,为了保持兼容,整个空间由256字节扩展为4KB,前面的256bytes保持不变。
配置空间头(header):
header有两种类型,type0和type1,其中 type0是endpoint的配置只存在非bridge的设备中,type1是bridge的配置,存在于所有bridge(在PCIE中理解为switch)设备中。

base address register(BAR):
对于type0来说,里面有6个BAR,而type1中只有2个BAR。
由于CPU不能直接与外设交互,一般会通过RC作为中间媒介与PCIE外设交互。而PCIE系统中每个设备都需要分配一定的内存地址和IO空间来进行数据传输和控制等。
BAR的作用就是给该设备硬件资源分配地址。软件通过向BAR里写入特定的值,就能告知它在主机内存或者IO空间中被映射到的具体地址范围。
BAR支持不同类型的资源映射,包括了内存映射,IO映射。其中内存映射又可以分为可预取(prefetchable)和不可预取(non prefetchable)两种类型。
实现机制:
系统上电的时候,操作系统会将PCIE设备开放的空间映射到内存空间,CPU想要访问PCIE设备空间时,只需要访问被映射的内存空间就行。RC会检查这个被映射的内存空间,如果检测出该内存空间是某个PCIE设备空间的映射,就会产生TLP访问对应的PCIE设备。
同样的道理,一个PCIE设备中,内部也会有若干个内部空间,这些空间属性可能不同,不如有的可预读,有的不可预读。在PCIE设备出厂时,这写属性标记以及空间大小都会写入到BAR寄存器里面。
一旦上电后,操作系统会读取这些BAR,分别为这些BAR里的东西分配对应的内存空间,并把相应的内存基址写回到BAR里。
IO空间:
PCIE支持IO空间,以便于需要使用IO空间的传统设备(leagcy device)兼容。IO地址空间只有4GB,在PCIE说明文档里显示并不推荐使用IO空间,而是推荐使用内存空间映射(MMIO)。
memory 空间:
memory空间用于设备与主机之间进行数据交互。在交互过程中可以将数据存储到memory空间里。主机通过访问这个空间读取数据或者写入数据,写入命令等操作。
比如显卡中的显存就是这个功能。
通常来说memory空间可以被映射到主机的物理内存中,使得主机能够像访问内存地址一样。同时memory空间部分支持预取功能。
MMIO,即memory mapped IO ,就是把这些IO设备中内部的 存储和寄存器都映射到主机统一的存储地址空间中,系统通过内存地址空间访问这些IO设备。
一种通用的memory和IO映射如图所示:

在图中展示了EP使用的MMIO和IO,在switch和RC内部也存在着可以通过MMIO和IO地址 进行访问的设备特定寄存器。
在图中还显示了可预取MMIO和不可预取MMIO,可预取空间有两个属性:读操作无副作用,允许写合并。
值得注意的是不同架构的映射方式存有差别:
在RISC 和 ARM架构中,MMIO采用统一编址的方式,将外设也视作内存空间的一部分。
在X86架构中,采用独立编址的方式区分内存空间和IO空间。因此会出现memory空间和IO空间两个独立空间。

BAR空间实例:32bit内存地址空间请求
假设现在有一个请求,它要请求一个4KB大小的不可预取内存。在图中展示出了BAR在配置过程中的三个点。

在(1)中,我们可以看到BAR处于未初始化状态。该设备的设计者已经将低位bit(这里为低[11:0])固定为一个数值,以此指示需要的memory大小和类型;还可以看到高位比特(可读可写)仍然是X态的,这代表它们的值未知。
系统软件首先会将每个BAR都通过配置写操作来将可写入的比特全写为1(被固定的地位比特不受写操作影响)。
(2)中,展示的是BAR第二阶段的样子。看以看出除了被固定的地位比特之外,其余的所有比特都被写入了1。(通过BIOS或者OS)
全写入1是为了确定最低位可写入比特具体是哪一位? 这个比特的位置指示了需要被请求的地址空间大小。
在本例中,最低位的可写入比特为bit12,因此这个BAR需要请求的地址空间大小为(4KB)。如果最低位可写入比特是bit20 ,那么这个BAR请求的地址空间大小就是
(1MB)。
在软件将BARs中的所有可写比特都写为1之后,软件将会从BAR0开始,依次读取每个BAR的数值,以此来确定各个BAR需要的空间大小和类型。
下表总结了本例对BAR0进行配置读的结果。
(3)过程的最后一步是系统软件将起始地址写入BAR0来为BAR0分配一个地址范围,因为对于软件来说现在已经知道了BAR0请求的地址空间大小和类型。(3)展示了BAR处于第三阶段的样子,此时系统软件已经将一块地址区域的起始地址写入了BAR0中。在本例中这个起始地址为F900-0000h。
到这里为止,对BAR0的配置就完成了。一旦软件启动了命令寄存器(command register)中的内存地址译码(Memory Enable bit),那么这个设备就会接收所有地址在起始地址F900_0000h------F900_0FFFh(4KB)范围内的memory请求。
BAR空间示例:64bit内存地址空间请求
上个例子中,我们看到了通过BAR0来请求不可预取内存地址空间。这个例子中,BAR1和BAR2被用来请求一块64MB的可预期内存地址空间。
这里使用两个连续相连的BAR是因为当前这个设备支持的内存地址空间请求是使用64bit的地址,这意味着需要的话,软件可以给它分配的地址空间可以超过4GB地址边界。
由于地址是64bit位宽,因此必须将两个相连的BAR一起使用。换句话说,**当采用64bit映射时,需要使用两个BAR来定义基地址。**当PCIE设备使用64位地址时,它会张泳两个BAR地址空间,第一个BAR用来定义地址低32位,第二个BAR用来定义地址高32位。
与上述的例子一样,BAR的配置过程主要也为3个节点。

(1)BAR1 和 BAR2都处于未初始化状态,设计者将低位BAR(本例中为BAR1)中的低bit固定为一个数值,指示需要的memory大小和类型。高位BAR (BAR2) 中的bit则是可读可写的X态。
(2)软件为每个BAR都配置写操作,将所有可写入的 bit 全写为1。此例中除了BAR1中被固定的低位bit外,其余的所有bit全被写为1.
软件读取BAR0后,读取下一个BAR (BAR1) 来确定设备是否在请求更多的地址空间。在读取完BAR1后软件发现设备在请求更多的地址空间,并且还是可预取的MMIO空间,软件就会接着读取BAR2,但不会对BAR2做低bit评估,因为软件仅仅将BAR2看作BAR1发起64位地址请求中的高32bit。
(3)软件为这一对BAR分配地址范围。软件会通过两次配置写操作将64bit起始地址写入BAR1和BAR2中。在本例中,高位BAR的bit1(BAR pair 中的bit33)被置为1,低位BAR的bit30(BAR pair 中的bit30) 也被置为1,表示地址2_4000_0000h. 这两个BAR的所有其他可写 bit 都会被清零。
一旦软件使用了命令寄存器中的**内存地址译码,**那么这个设备就会接收所有地址在起始地址2_4000_0000h------2_43FF_FFFFh(64MB)范围内的memory请求。
message空间:
message空间用来报告带内的meaasge 和 event。例如错误消息,电源管理消息等。