MMIO&PMIO

文章目录

    • CPU的访问范围
      • IO接口和port
    • 地址空间
      • 物理地址空间
    • 编址
      • 独立编址(PIO port IO)
      • 统一编址(MMIO)
      • CPU通过MMIO访问外设
        • bar
    • 参考资料

CPU的访问范围

CPU能够访问哪些位置?CPU是如何实现访问这些位置的?
CPU能够访问的资源包括了两种:物理内存 (physical memory)和寄存器(register)。

物理内存 (physical memory ):这里需要注意的第一个定义 不仅仅指日常最经常说的主存(main memory),还包括了其他各种各样的ROM,比如BIOS的ROM PCIE设备上的ROM等。

寄存器register:也分为两种:内部寄存器和外设寄存器。一般来说内部寄存器指的就是CPU内部的寄存器,如EX DX寄存器等。
而外设寄存器就比较特殊了,外设寄存器一般指的是主板上除了CPU外其他位置上分部的能够让CPU直接操作以方便CPU对外部设备进行访问的寄存器,我们常说的端口Port 本质上就是指这些外设寄存器。

IO接口和port

IO接口:解决外设和主机之间的连接问题,IO interface从物理上最直观的例子就是主板上的对外接口,这些接口中的接口芯片就起到了沟通CPU和外设的功能。比如最最常见的USB 接口 PCIe接口。种隐藏的接口芯片也不在少数,很多都是我们不能直观看到的。

在IO 接口的两端连接的分别是CPU和外设的[设备控制器](这个控制器对外设起到了一个管理的作用 可以根据CPU传递过来的数据选择对应的设备并且命令设备进行相应的操作)

IO接口为了能够实现上述的功能,其内部就需要许多的寄存器。这些寄存器根据功能大致分为三类:

  1. 控制寄存器 : CPU通过总线读写控制寄存器告知设备自己想要进行的操作
  2. 状态寄存器:设备通过状态寄存器告知CPU自己是否准备好进行操作
  3. 数据寄存器:CPU通过读写状态寄存器来决定是否将准备传送的数据放到数据寄存器中
    一次数据的传输过程中,可以发现控制寄存器只在第一步告知操作的时候用到,所以往往将控制寄存器和状态寄存区进行合并节约空间,这样就只剩下数据寄存器和控制寄存器两个了

本质上CPU对外部设备的控制就是对外设(控制器)对应的寄存器的控制。

我们平时所说的外设的端口(Port),指的就是IO接口中的能够被CPU直接访问的寄存器。我们所说的统一编址和独立编址就是给这些Port进行编址。
IO接口包含port并且有些是直观看到的接口形态,而port指io接口中的寄存器

地址空间

前面已经详尽的讨论了CPU能够访问的位置有哪些,接下来的问题就是CPU如何访问这些位置。
一个思路就是对这些存储单元、寄存器进行“编号”。在计算机中,也确实是这样做的,只不过这种给地址单元、寄存器赋予特定“号码”的动作在计算机中被称为编址操作,而这些号码也被称为地址

对physical memory依次进行“编号”,得到的“号码”就是物理地址physical address.
物理地址最大能够达到的范围,就被称为物理地址空间physical address space

物理地址空间

首先建立基础的正确认知,32位 、64位CPU中,32 64指的是CPU寄存器的位宽而并非地址线位数,而且CPU地址线位数与CPU寄存器的位宽没有任何关系!!!
CPU寄存器的位宽限制的是CPU处理数据的能力,CPU地址线才是关键的能够决定physical address space的。

限制physical address space大小的因素都有什么?
首先地址总线的位数极大程度的影响物理地址空间,毕竟物理地址需要在地址总线上传递,2根地址线不可能找到5个地址。其次,CPU的位数也是限制物理地址空间的原因之一,毕竟需要CPU去处理数据,如果CPU的寄存器只有2位,是没有办法找到地址5的。

在早期的CPU中,CPU的位宽为32,而地址线能够达到36根(是的没错,并不是大多数人以为的32位地址线),此时限制physical address space的主要因素就是CPU的位宽了。
经过发展到了后期CPU的位宽达到了64,但是目前地址总线最大能够达到的只有52根,此时限制physical address space的主要因素就是地址总线的位数了.

编址

已经将物理地址空间的概念说清楚了 ,接下来需要考虑的就是如何将主板上所有CPU能够访问的地址空间进行编址了.
不同架构的CPU对于这一问题有着不同的处理方式,主要就是两种统一编址和独立编址。
统一编址就是对physical memory 和 Register 统一处理,相对应的,独立编址就是将physical memory 和 Register分别进行编址。
MMIO&PMIO_第1张图片

PIO 是 x86 架构独有的映射方式,是指将 I/O 端口映射到专门的 I/O 地址空间,x86 架构一共有 65536 个 8 位的 I/O 端口,编号从 0 到 0xffff,组成了一个独立于物理地址空间的 64KB 的 I/O 地址空间,访问 I/O 地址空间也需要专用的 IN/OUT/INTS/OUTS 指令

相较于 PIO,MMIO 的应用更加广泛,支持几乎所有的 CPU 架构,如 x86、ARM、RISC-V 等,ARM 和 RISC-V 使用的 RISC 精简指令集,只支持 MMIO

独立编址(PIO port IO)

总的来说PMIO的情况下,CPU使用特殊的指令去对外设寄存器直接进行操作,具体到以X86为架构的处理器上就是 IN/OUT指令。这种情况下IO的地址空间和物理内存地址空间是分开的、彼此隔离孤立的。

MMIO&PMIO_第2张图片
IO space的范围其实是由最初的8086CPU的架构延续下来的,8086中IO address space 的范围由AD线数目决定,即16根。
关于独立编址的IO Port,目前需要记住的就是对于PCI设备访问的时候,需要用到的 I/O Port的address 为CF8 CONFIG_ADDRESS 和 CFC CONFIG_DATA

统一编址(MMIO)

独立编址是很容易理解的一种编址方式,两个空间相互不干扰,想要访问的位置分别使用对应的指令对地址进行操作就行了。虽然这样对于外设的访问方便,但是也是有问题的: IO独立编址需要单独的控制引脚用来区分IO address space和 physical-memory address space 这样会增加芯片面积,不利于芯片设计。因此将端口和物理内存进行统一编址访问就成为另一个编址方向。Memory-Mapped I/O.

MMIO(Memory mapping I/O)即内存映射I/O,它是PCI规范的一部分,I/O设备被放置在内存空间而不是I/O空间
从处理器的角度看,内存映射I/O后系统设备访问起来和内存一样。这样访问pcie显卡上,PCI设备就可以使用读写内存一样的汇编指令完成,简化了程序设计的难度和接口的复杂性。

MMIO&PMIO_第3张图片
DRAM Controller View就是内存控制器能够控制的内存地址的范围,那顾名思义,内存控制器的这个控制范围主要肯定就是内存的大小范围,在内存还没有增长到今天这个范围的以前,内存控制器能够识别的大小可能只有2G,而今天它能够识别的范围远远超过之前。

System View是指从CPU的角度来看,当前系统的地址范围到底是多大。需要注意的是,我们之前就说过,MMIO是将IO设备也同时映射到内存地址空间进行统一的编址,这样的话CPU能发现的地址范围肯定是要大于内存控制器所能发现的地址范围的,所以在上图中也能够看到System View是远大于DRAM Controller View的。

0-1M:被分配成DOS Legacy Address Range

1M-TOLUD (Top of Low Usable Dram ):被分配成Low Main Memory Address Range,这一部分主要是Main Memory,也就是对应DRAM,但是在这段memory中间还有一些小小的地址被占用作他用,比如ISA Hole TSEG等,这些被占用的地址是极少部分,绝大部分都是被分配用在了memory上,所以这些地址大部分是可以直接被DRAM Controller访问找到对应的DRAM的

TOLUD-4G:被分配成为PCI Memory Address Range (MMIO Low),其中主要分了三个部分 Flash APCI等,DMI Interface 和 PCIe Configuration Space 。这部分地址就是被MMIO所占用的,所以这部分地址就不能让DRAM Controller在DRAM上找到对应的位置了,因为这地址表示的就不是DRAM

4G -TOUUD (Top of Upper Usable DRAM) :Upper Main Memory Address Range, 这部分就比较容易理解,就是DRAM中超过4G的部分,所对应的地址

TOUUD-TOUUD+X : Reclaim Address 对4G以下MMIO占用部分内存的重新映射,利用这部分地址就能够重新利用之前浪费掉的地址空间。

TOUUD+X- MAX range : MMIO High 这部分都可以用来作为PCIE MMIO 的地址了 并且利用这部分地址也不会再占用内存地址造成内存空间的浪费了

CPU通过MMIO访问外设

CPU如果想访问PCIE上的某个设备的空间,由于它不能访问PCIe设备配置空间,会让RC通过TLP把数据从PCIe外设读到内存,然后CPU从Host内存读数据;
如果CPU要往外设写数据,则先把数据在内存中准备好,然后RC通过TLP写入到PCIe设备。

下图例子中,最左边虚线的表示CPU要读Endpoint A的数据,RC则通过TLP(经历Switch)数据交互获得数据,并把它写入到系统内存中,然后CPU从内存中读取数据(紫色箭头所示),从而CPU间接完成对PCIe设备数据的读取。
MMIO&PMIO_第4张图片
具体实现就是上电的时候,系统把PCIe设备开放的空间(系统可见)映射到内存空间,CPU要访问该PCIe设备空间,只需访问对应的内存空间。RC检查该内存地址,如果发现该内存空间地址是某个PCIe设备空间的映射,就会触发其产生TLP,去访问对应的PCIe设备,读取或者写入PCIe设备

bar

一个PCIe设备,可能有若干个内部空间(属性可能不一样,比如有些可预读,有些不可预读)需要映射到内存空间,设备出厂时,这些空间的大小和属性都写在Configuration BAR寄存器里面,然后上电后,系统软件读取这些BAR,分别为其分配对应的系统内存空间,并把相应的内存基地址写回到BAR。

PCIe设备,系统软件是如何为其分配映射空间的 (32 Bit memory address)
上电时,系统软件首先会读取PCIe设备的BAR0,得到数据:(1)
然后系统软件往该BAR0写入全1,得到:(2)
BAR寄存器有些bit是只读的,是PCIe设备在出厂前就固定好的bit,写全1进去,如果值保持不变,就说明这些bit是厂家固化好的,这些固化好的bit提供了这块内部空间的一些信息
解读:低12没变,表明该设备空间大小是4KB(2的12次方),然后低4位表明了该存储空间的一些属性,这些都是PCIe设备在出厂前都设置好的,提供给系统软件的信息。
然后系统软件根据这些信息,在系统内存空间找到这样一块地方来映射这4KB的空间,把分配的基地址写入到BAR0:(3)
从而最终完成了该PCIe空间的映射。一个PCIe设备可能有若干个内部空间需要开放出来,系统软件依次读取BAR1,BAR2。。。,直到BAR5,完成所有内部空间的映射。

MMIO&PMIO_第5张图片

参考资料

https://blog.csdn.net/weixin_43921686/article/details/129106423
https://blog.csdn.net/weixin_43405280/article/details/131663456

你可能感兴趣的:(#,操作系统学习笔记,操作系统)