✨MMIO
在计算机体系结构中,MMIO (Memory-Mapped I/O) 和 port I/O(也称为端口映射I/O或I/O端口访问)是两种不同的硬件资源访问机制。它们都用于CPU与硬件设备的通信,但在具体的实现和使用方式上有所不同。I/O作为CPU和外设交流的一个渠道,主要分为两种,一种是Port I/O,一种是MMIO(Memory mapping I/O)。
✨MMIO (Memory-Mapped I/O)
MMIO是一种使用内存寻址方式访问硬件设备的技术。在这种机制中,硬件设备的控制寄存器被映射到CPU的地址空间中的特定内存区域。这意味着CPU访问这些设备的方式与访问RAM相同,都是通过读写内存地址来完成。
🌟优点:
使用内存寻址方式可以让程序员方便地使用指针和其他内存访问操作来交互设备。
MMIO允许32位或64位数据宽度的存取,便于传输大量数据。
适用于更复杂的硬件设备控制,可以方便地实现内存映射文件或DMA(直接内存访问)。
🌟 缺点:
占用CPU的地址空间,限制了内存的可用大小。
使用方式:
在Linux系统中,可以通过mmap()系统调用来将硬件设备的MMIO区域映射到程序的地址空间,然后通过指针直接访问这些地址来读写设备寄存器。
✨Port I/O
端口I/O是一种使用专门的CPU指令来访问硬件设备的方法。在这种机制中,每个设备分配有一组特定的I/O端口号,CPU使用这些端口号和指令(如x86架构的IN和OUT)来与设备进行通信。
🌟优点:
不需要使用宝贵的CPU寻址空间,因为它通过端口号实现访问控制。
适合于简单的设备或较少的数据交云。
🌟缺点:
访问数据的宽度受限,通常是8位或16位。
对于需要频繁交互的设备,效率可能不如MMIO。
🌟使用方式:
在Linux系统中通常不直接操作端口I/O,因为这需要特权级别的操作。但你可以使用如inb、inw、inl、outb、outw、outl等内核提供的函数(针对8、16、32位操作)来执行端口I/O。这些函数包装了必要的汇编指令来实现硬件访问。
✨IO地址空间&内存地址空间
🌟 IO地址空间
访问外部设备寄存器的地址区域,(PCI支持4GB的IO空间,但是x86平台为 64KB),因为X86平台只支持64KB的IO空间,Endpoint为了能在X86上使用,只 能把自己的消耗的IO资源限制在64KB以内。由于Endpoint纷纷把IO资源的消耗 限制在64KB,因此,大部分其他架构的CPU也把IO空间限制到64KB以内了。
🌟内存地址空间
访问memory的地址空间,32位平台为4G。 此memory空间和main memory(平 时常说的内存或者主存)是两个概念,32bit平台下CPU memory地址总线只能 寻址到4G,这4G空间包括main memory、外设IO 、空间映射(MMIO)等,不 能全给main memory,因此32bit的CPU是无法配置4G内存的。
✨MMIO分类
在PCI Express (PCIe) 总线规范中,内存映射IO(MMIO)可以被分成两大类:可预取的内存映射IO(Prefetchable MMIO,简称 P-MMIO)和不可预取的内存映射IO(Non-Prefetchable MMIO,简称 NP-MMIO)。这两种类型的MMIO主要区别在于它们的数据访问和优化机制。
🌟P-MMIO (Prefetchable MMIO)
P-MMIO区域通常包含的是可以被CPU或者其他总线主体所预取(prefetch)的数据。当数据被标记为可预取时,意味着系统可以在实际的读取操作之前就将这些数据加载到缓存中。这可以提高访问效率,因为在请求数据时它们已经可用在缓存之中。
🌟可预取的区域主要用于:
静态数据访问:暂存那些不会频繁变化的数据,例如静态配置表或者只读数据结构。
性能优化:当一个程序频繁访问一块数据区域时,预取可以显著提高数据访问速度。
在PCI设备的配置空间的Base Address Registers (BARs)中,可预取的MMIO BAR会被特殊的位标记,以指示该内存范围可以安全预取。
🌟NP-MMIO (Non-Prefetchable MMIO)
NP-MMIO区域包含的是不应该被预取的数据。这通常用于存储易变数据,如硬件状态寄存器、控制寄存器或者实时的数据缓冲区。对于这一类数据,预取并不合适,因为数据可能在任何时候被硬件更改,预取到缓存中的数据可能很快就会过时。
🌟不可预取的区域用于:
动态数据访问:存储会动态变化的数据,为了保证数据的实时准确性,每次访问都需要直接从硬件读写。
避免数据不一致:对于数据的实时性有严格要求的操作必须避免数据在传输到CPU前被无效地存储在缓存中。
与可预取的MMIO一样,在PCI设备的配置空间中,不可预取的MMIO BAR会表明相应的内存区间不能被预取。
✨MMIO (Memory-Mapped I/O) cfg空间和PCIe 的BAR (Base Address Registers) 空间
MMIO (Memory-Mapped I/O) cfg空间和PCIe 的BAR (Base Address Registers) 空间是计算机系统中用于硬件设备访问的两种不同的内存映射区域。尽管它们都利用了内存映射的概念来实现对设备的访问控制,但它们的用途和工作方式有所不同。
🌟MMIO cfg空间
定义:MMIO cfg空间指的是通过内存映射的方式访问的PCI/PCIe设备的配置空间。这是一段特定的内存区域,用于存放和读取PCI/PCIe设备的配置信息,例如设备ID、供应商ID、中断信息和BARs等。
功能: 它主要用于配置和管理PCI/PCIe设备。系统在启动时或者当新设备被热插拔时,操作系统通过读写CFG空间的方式来识别和配置设备。
大小: 大小固定,对于大多数设备而言,配置空间为256字节,对于支持扩展功能的设备而言,可以更大。
🌟PCIe 的BAR空间
定义:BAR空间指的是分配给每个PCI/PCIe设备的一段或多段内存地址空间。每个PCI/PCIe设备可以有多达六个BAR,用于定义设备需要的I/O和内存资源的大小和位置。
功能: BAR被用于实际的数据传输和设备控制。设备的驱动程序通过读写这些内存地址来与硬件设备通信,执行数据的输入/输出操作。
大小: BAR的大小是可变的,根据连接到PCIe总线上的设备的不同而不同。设备初始化时会通过PCIe枚举过程请求必要的地址空间大小,系统基于这些请求分配资源。
🌟核心区别
用途: MMIO cfg空间用于设备的识别和配置,而BAR空间用于实际的设备数据传输和控制。
访问方式: cfg空间通常在设备初始化和配置阶段访问,用于配置设备使用的基本参数和功能;BAR空间在设备正常运行时不断访问,用于设备的日常操作和数据交换。
容量和数量: 设备配置空间的大小是标准化的,而BAR空间的大小和数量则根据设备的具体需求分配,具有较大的灵活性。
简而言之,MMIO cfg空间与PCIe的BAR空间共同工作,以确保PCI/PCIe设备可以被正确识别、配置和使用。cfg空间主要用于初始的设备配置,BAR空间则用于设备的常规操作。
✨总结:
MMIO和端口I/O都是处理器与I/O设备之间通信的方法。选择哪一种方法取决于硬件设计和特定的应用场景。在现代系统中,MMIO因为其灵活性和易于编程等优势越来越常用,特别是在需要大块数据传输的情况下。端口I/O则主要在传统的或简单的硬件接口(如早期的PC架构)中使用。
在具体的编程实践中,高级语言通常通过操作系统提供的抽象(如设备驱动程序接口)来间接访问这些硬件资源,因而开发者通常不必担心底层访问的细节。