没有负责将设备映射到内存的指令1。
一个完整的答案过于宽泛,但我们可以举一两个例子。
首先,说服您自己可以通过简单地告诉设备要收听的地址来配置设备。在硬件层面,这只不过是一种比较。
某些设备具有固定地址。
这些是旧设备,在系统首次发布时出现,并被其他竞争对手克隆,以及后续版本以实现向后兼容性。
可配置设备。
这些设备有跳线/开关来选择要收听的地址范围。用户的任务是避免冲突并适当地配置软件。
Plug and play 设备。
最著名的 PnP 总线是 PCI,但 ISA 和 MCA 也是 PnP 的地方(ISA 是“某种”PnP)。
这些设备与上述设备类似,但可在软件中进行配置,它们所需的资源(IRQ、DMA、MMIO)也是可枚举的,以让固件和操作系统分配它们而不会发生冲突。
现在您想知道如何实现选项 3。答案很简单:使用元地址空间。
以 PCI 为例,地址 0cf8h 和 0cfch2 用于选择设备,设备上的寄存器configuration space,并读取或写入该寄存器。
配置空间中的寄存器可用于变基设备。
假设寄存器10h保存设备监听的地址,那么这段伪代码将设备映射到88888888h
uint32_t* select = MAKE_POINTER(0xCF8);
uint32_t* data = MAKE_POINTER(0xCFC);
*select = MAKE_SELECT(0, 1, 31, 0x10); //Bus 0, Device 1, Function 31, Register 0x10
*data = 0x88888888; //Set reg 0x10 to 0x88888888
如您所见,取消指针会生成对内存位置 0cf8h 和 0cfch 的写入,但这些位置不会被硬件路由到主内存,而是转到 Host-to-PCI 桥控制器将它们转换为感兴趣的设备将获取的 PCI 配置空间访问。
稍后,当访问 88888888h 时,这又不是路由到主内存3,而是路由到配置设备所在的 PCI 总线(通常是 subtractive decoding 的结果)正在听。
1 从某种意义上说,没有特制的 CPU 指令。一切都是执行某些指令的结果,因此从某种意义上说,某些“必须对被映射的设备负责”。对于这个答案的其余部分,我假设您想知道MMIO 的工作原理。
2 仅适用于 IO 地址空间中的 x86,但不要让我们分心。
3 硬件知道内存在哪里结束,如果软件将设备映射到实际存在内存的位置,则后者优先且不会访问该设备。