一、地址空间回顾
在最开始,我们先来回顾一下PCIe的一些基本概念,首先,PCIe是PCI的延伸,全名叫 Peripheral Component Interface Express。从名字就能看出,这是一种外设总线协议。在整个系统中,外设只是其中的一部分,系统中最重要的部分当属处理器(Processer)。一个系统要运行,CPU就是那个大脑,外设就类似于我们的手和脚,外设能起很多特定作用,但还是要依靠大脑(CPU)指挥。
那么CPU如何高效地指挥外设就显得很重要了,最简单的方式,CPU直接把所有的控制信息线输出给外设,这种方式最直接也最愚蠢,当外设数量很多,这显然不是一种好的方式,设计复杂,灵活性差。而且对于CPU来讲,不可能每次增加一个外设,就去增加对应的控制线,所以这注定不是一个好的方案。
人们就开始寻找更简单的方案,直接手递手传递信息不太合适,能不能找到一个中介,我们在CPU和外设之间开设一块区域,双方把需要交换的信息都存放到这个区域里,这样就简化了CPU的操作难度。这就是端口映射I/O操作(Port-Mapped I/O, PMIO),也就是我们在PCI总线地址空间分配中提到的I/O地址空间(I/O Map),在x86处理器中,处理器就支持直接访问I/O空间。
但是这样做还是有不足的地方,那就是这个空间的大小很难让人满意,对于CPU设计来讲,不是所有的系统都需要配备大量外设,那这个区域设计过大就会导致浪费,设计过小又满足不了一些产品的需求。而且,增加一种额外的操作(操作I/O Map)也是CPU不愿意看到的。这个时候,聪明的人们发现,CPU本身就有一块需要频繁进行数据交互的区域:内存(memory),我们直接把对外设的操作映射成对内存的操作,这样不是更方便了吗,让MMU到时候把对外设的操作转外设不就行了,从CPU的视角,所有的操作就都是对于内存的操作了(别管他是物理的还是虚拟的)。这就有了内存地址空间(Memory Map)。在x86处理器中,处理器可以直接访问内存和I/O空间。PCI设备可以映射到处理器的内存地址空间,支持32位或64位内存寻址。
随着时代的发展,I/O地址空间(I/O Map)的应用场景越来越少了,大家都更喜欢使用 内存地址空间(Memory Map)。但是PCIe需要兼容PCI设备啊,人们就开始想办法,我们把I/O地址空间(I/O Map)也映射到内存吧,这样从CPU的角度,操作I/O地址空间也变成操作内存地址空间(Memory Map)了。这就有了MMIO(Memory Map I/O),这是后话,我们稍后再聊。
二、PCIe配置
我们知道,对于PCI协议,它引入了第三种地址空间,称为配置空间,该空间只能通过间接方式访问。每个功能包含内部寄存器,用于配置空间的管理。这些寄存器为软件提供了标准化的地址和资源控制,使得PC真正实现了“即插即用”环境。软件通过配置空间就可以用一种标准化的方法来对设备的状态进行控制和检查。
这是什么意思呢,我们简单解读一下,要想让PC进入“即插即用”环境需要做些什么。对于一个外设,插上去就能做到适配使用,CPU对外设的控制就需要统一。也就是要统一所有的控制接口,这个接口就是我们的“配置空间”。这个配置空间首先在物理上就应该在PCIe接口设备上,而不是在CPU那侧,这样不同的PCIe设备可以方便通过自己的方式去获取配置信息。但是系统怎么去操作PCIe设备的配置空间就成了一个问题。而这就是我们本系列需要讨论的关键。