【问题标题】:Question About x86 I/O Port Addresses and IN/OUT Instructions关于x86 I/O端口地址和IN/OUT指令的问题
【发布时间】:2019-11-01 13:02:03
【问题描述】:

据我所知,这是 PC 总线系统的简化视图(不包括我所知道的桥)。

如图所示:

据我所知,现代 x86 CPU 的地址空间为 65536 字节 (0000-FFFF)。这些是 I/O 地址。在 x86 中,IN 和 OUT 指令用于通过 I/O 端口与设备通信。

考虑到 PC (x86 cpus),以下是我的问题:

  1. 我可以在不使用 PCI 或任何其他总线的情况下将设备添加到此 I/O 总线吗?我的意思是与 IN/OUT 的直接通信。如果是,如何分配 I/O 地址?他们不冲突吗?

  2. 如果我的 CPU 支持 PCI 和 I²C(是的,有些支持!),CPU 如何区分它们的 I/O 地址?它如何知道一个 I/O 地址属于 PCI 或 I²C。

(顺便说一句,我不知道 I²C 地址是否只是合乎逻辑的,而不是关于 I/O 端口,但这是另一个我也需要回答的问题)

【问题讨论】:

  • 是的,如果未配置即插即用,它们可能会发生冲突。 cpu 不区分,就像它不关心物理内存芯片或内存映射设备一样。我不知道 cpu 中的 I2C 实现,但如果它们像其他所有东西一样简单地隐藏在 PCI 设备中,我不会感到惊讶。

标签: assembly io x86 cpu-architecture


【解决方案1】:

1) 我可以在不使用 PCI 或任何其他总线的情况下将设备添加到此 I/O 总线吗?

理论上;是的。但是,对于现代系统,没有共享/公共总线(现在是“点对点链接”);内存控制器和 PCI 主机都内置在与 CPU 相同的芯片中,这意味着(除非您是英特尔等 CPU 供应商的员工)您必须处理高速串行链路(快速路径、 Hyper-transport、PCIe 或 DMI),它们既不便宜也不易于连接(换句话说,它不像 1980 年代那样你有一个好而缓慢的 ISA 总线可以连接)。

如果是,如何分配 I/O 地址?他们不冲突吗?

传统设备使用由历史/兼容性分配的固定 IO 端口。其他所有内容由一种“IO 端口范围分配器”(内置于固件和/或操作系统中)动态分配,该“IO 端口范围分配器”在 PCI 配置空间中配置 BAR(“基地址范围”寄存器)。有一些(现在已弃用/不存在)替代方案 - 由 ISA 卡上的物理跳线或 DIP 开关手动分配,ISA“即插即用”规范在许多设备支持之前大部分已被 PCI 取代,以及存在于其他类型的总线(MCA 和 EISA)用于动态资源分配。当然,大多数现代设备根本不使用 IO 端口(而是使用内存映射寄存器)。

2-) 如果我的 CPU 支持 PCI 和 I²C(有些支持!),cpu 如何区分它们的 I/O 地址?它如何知道一个 I/O 地址属于 PCI 或 I²C。

对于 I²C,可能在某处(在 IO 端口地址空间或物理地址空间中)有一对寄存器用于向/从 I²C 总线发送和接收字节。 I²C 总线上的所有内容都将通过这 2 个寄存器进行访问,I²C 总线上的任何内容都无法访问 I²C 总线上没有的任何内容(包括无法访问任何 IO 端口以及无法访问任何物理地址)。

大多数情况下(如以太网、视频、USB...),您有一个控制器(具有 CPU 可以直接访问的寄存器)来控制 CPU 无法直接访问的东西(LAN、显示器信号、USB插入 USB 总线的设备,...)。

(简化)示例

让我们假设(由于out dx,al 指令)CPU 在共享总线或显示“command = WRITE, space = IO port space, address = 0x1234, size = 1 byte, data = 0x56”的链接上发送消息。此消息可能会被 PCI 主机控制器截获,它查看详细信息(哪个地址在哪个地址空间中)并决定将消息转发到 PCI 总线上的“PCI 到 LPC 桥”设备。当“PCI 到 LPC 桥”收到消息时,它可能会查看详细信息(哪个地址在哪个地址空间中)并意识到它对应于 I²C 总线控制器并将其转发给 I²C 总线控制器。 I²C 总线控制器可能会解码消息并在 I²C 总线上发送字节 0x56(来自消息的“数据”部分)。然后,在 I²C 总线上侦听的设备可能会看到 0x56 字节并通过 I²C 总线将字节 0x78 发送回 I²C 总线控制器来响应,控制器将值 0x78 存储在内部缓冲寄存器中。

下一个; (因为in al,dx 指令)CPU 可能会发送另一条消息,上面写着“command = READ, space = IO port space, address = 0x1234, size = 1 byte”。此消息将遵循与前一个消息相同的路径(因为地址和地址空间相同)并最终到达 I²C 总线控制器。 I²C 总线控制器可能会解码消息并意识到消息要求从 I²C 总线控制器的内部缓冲寄存器(它保存之前的值 0x78)中读取;因此 I²C 总线控制器发回消息“command = READ_REPLY, space = IO port space, address = 0x1234, size = 1 byte, data = 0x78”。此回复消息将返回到 CPU(再次使用相同的路径,但方向相反 - 例如,到 PCI 到 LPC 桥,然后到 PCI 主机控制器,然后到 CPU)。当 CPU 收到回复时,它可以完成导致它的原始指令(例如,将 al 设置为“READ_reply”消息中的值以完成 in al,dx 指令)。

这里的重点是 CPU 不能直接向 I²C 总线上的设备发送任何内容(CPU 只能与 I²C 总线控制器通信);并且 I²C 总线上的任何设备也不能直接向 CPU 发送任何内容(它们也只能与 I²C 总线控制器通信)。 I²C 总线上的任何内容都不需要知道任何有关 IO 端口的信息; CPU 总线/链路上的任何内容都不需要了解 I²C 总线上的字节数。

还有; CPU 只是发送和接收消息。它不知道它们被发送后会发生什么,也不知道(例如)“command = READ”消息将如何转发到哪里,也不知道哪个设备将发送回一个“ command = READ_REPLY”消息。路由主要取决于消息所走路径中每个步骤的逻辑。例如,PCI 主机控制器可能被配置为将 0x0000 到 0x2000 范围内的 IO 端口访问的所有消息转发到 PCI 总线,而 PCI 到 LPC 桥接器可能被配置为转发 0x1234 范围内的 IO 端口访问的所有消息到 0x1235 到 I²C 总线控制器。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-25
    • 2023-03-22
    • 1970-01-01
    • 2015-10-01
    • 2012-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多