由谁决定I / O映射和内存映射的I / O(x86)

时间:2019-06-29 16:40:19

标签: assembly x86 cpu-architecture

在x86体系结构中,我们将IN和OUT之类的I / O指令用于I / O映射的I / O。据我所知,我们在内存映射的I / O中使用诸如MOV之类的内存指令。一切都很好,但是谁决定使用哪种I / O方法呢?如果要构建自己的设备(外围设备),是否可以自由选择使用I / O映射还是内存映射的I / O与PC进行通信?还是所有设备都必须同时支持两者?

不明白是谁决定用于与设备通信的I / O方法。

2 个答案:

答案 0 :(得分:4)

Michael Petch said in his comment是制造商,但它并不总是拥有完全的自由。
标准和规范可以要求使用地址空间,某些标准是通用的(例如OHCI,USB 1.0,指的是“无法分配的地址空间”,在x86上可以是IO或MMIO),其他则不是(例如,PC Client TPM规范根据使用的MMIO区域按位置映射TPM寄存器。


据我所知,就我们对这个答案的关注而言,MMIO的采用随着PCI 1 的出现而成为主流。 PCI BAR(基址寄存器)具有一种特殊的格式,该格式允许软件知道卡所使用的地址空间(以及需要多少地址空间):

PCI BAR format

位0是只读的(由制造商设置),并告知卡正在使用哪个地址空间。

与MMIO相比,IO空间具有不需要任何设置的优势,MMIO需要虚拟到物理的映射以及正确的缓存类型。
但是IO空间只有64KiB + 3B,非常小。
实际上,PCI 2.2将单个BAR使用的最大IO空间限制为256个字节。

256 IO bytes per BAR

很抱歉,该图片从PDF规范中复制后显得很乱

此外,指针在IO空间中不起作用,并且某些设备可以使用指针(例如USB控制器,GBe等)。

IO肯定会用于旧式设备(在MMIO尚未出现之前)。
我曾经认为IO用于具有少量寄存器的设备,但这并不总是正确的,例如PCH(芯片组)的Power Manager Control寄存器是IO映射的,并占用128B。

有时,设备同时支持IO和MMIO。这需要两个BAR,例如PCH的SMBus控制器:

SMBus controller's BARs

它有两个BAR(请注意默认值,一个用于IO,另一个用于MMIO),用于控制相同寄存器集。
该文档指定两者都可以使用。

我不能给出何时使用IO vs MMIO的确切规则。
我认为性能没有区别,区别仅在于PCIe链路层发送的TLP数据包中。
但是,我从未对此事进行调查,IO指令正在串行化,因此在软件级别会降低性能。

我的经验法则是,如果满足以下任一条件,则可以/可以使用IO:

  • 该设备是旧设备(实际上,这里没有选择的自由)。
  • 您的设备未使用指针(因为IO没有指针)并且寄存器集很小。
  • 寄存器主要用于控制和报告设备或整个系统的状态(因为IO指令正在串行化)。

这些只是经验法则,根据我的阅读和记忆,有很多例外和反例。
今天的趋势是使用MMIO,这可能需要更多的 解码逻辑(需要解码的更多地址线),但PCI规范通过允许设备将其解码数舍入到4KiB来简化了此操作。
一个示例是PCIe配置空间,在PCI中它是IO访问的(使用类似于VGA控制器中使用的寄存器堆叠技术),但现在已映射到内存。

由于PCIe是现代PC上的主要总线,因此无需考虑其他总线,其他所有事物都通过PCIe设备(例如USB使用xHCI PCI设备)。
唯一的例外是脱核设备(例如LAPIC,TXT寄存器),它们可以通过内存映射的IO进行访问,因为我认为它的性能更高,这种访问不会到达系统代理(这些设备是接近它们的内核,并且始终在CPU封装内部),因此使用(序列化)IO指令将对其产生重大影响。
另外,在4GiB的顶部还有一个不错的地方,英特尔可以在不对其他设备施加太大压力的情况下回收内存。
有趣的事实:由于FPU是协处理器(x87)的时间而保留了端口0xf8-0xff,并且CPU使用该端口与其进行通信。


1 在此之前,其他两个PnP总线(例如PnP ISA和MCA)都已经可用,但是解码存储器访问主要是为了提供对ROM和板载访问的权限内存。我猜还不是将寄存器映射到内存的事情。

答案 1 :(得分:3)

  

如果我想构建自己的设备(外围设备),我可以自由选择使用I / O映射还是内存映射的I / O与PC进行通信?

哪种设备?

如果它是旧设备(例如,古老的“ PS / 2控制器”或串行端口或并行端口或..)或标准化设备(例如,实现AHCI或NVMe或xHCI),则它必须符合现有的标准(正式或事实上的)规范。

否则(无需使用现有的规范进行编译);如果是USB设备,则不能使用IO端口或MMIO(它正在响应串行总线上的请求);如果它是PCI设备且需要高性能,则应使用MMIO(因为IO端口是性能问题);如果它是不需要高性能的PCI设备,那么就根本不应该是PCI设备(应该是USB)。