MSI-X 如何触发中断处理程序?是否需要轮询选择的内存地址?

How does MSI-X triggers interrupt handlers? Is there a need to poll the chosen memory address?

我有一个用 UEFI 引导的小内核。我正在使用 QEMU 进行虚拟化。我想编写一个 xHCI 驱动程序以在我的内核中支持 USB 键盘。我很难找到简洁明了的信息。我在内核中“找到”了 xHCI。我有一个指向其 PCI 配置的指针 space。它支持 MSI-X。我想使用 MSI-X,但我很难理解它如何与 xHCI 和 USB 一起工作。

我的问题是,通常 osdev.org 的信息量很大,并且具有实现某些功能所需的基础。在 MSI-X 的情况下,情况似乎并非如此。我很难在 osdev.org 上的所有信息与 MSI-X 功能之间做出 link。

所以基本上,我找到了 MSI-X table,然后我在那里设置了一些地址,告诉 xHCI PCI 设备写入该地址以触发中断。但是是否在某个时候调用了中断处理程序?我是否需要轮询此地址以确定是否发生中断?我本以为 MSI-X table 中的向量控制字段让我设置一个中断向量,但所有位都被保留。

编辑

我发现以下 Whosebug 问答部分回答了我的问题:

所以基本上,数据寄存器的低字节包含要触发的向量,消息地址寄存器包含要触发的 LAPIC id。我还有一些问题。

  1. 为什么“Message Address register contains fixed top of 0xFEE”。

  2. 消息地址寄存器中的 RH、DM 和 XX 位是什么?

  3. LAPIC 如何工作?基本上,它是如何触发 LAPIC 中的中断的。它是 PCI 设备的一项特殊功能,允许它们在 LAPIC 中触发中断。或者仅仅是 PCI 设备使用触发中断的特定数据写入 LAPIC 的内存映射寄存器。因为通常 LAPIC 是从内核内部访问的,地址对每个 LAPIC 都是相同的。它是来自 CPU 之外的某种处理器间中断吗?

  1. Why does the "Message Address register contains fixed top of 0xFEE".

CPUs 就像网络 - 带有 headers 的数据包描述了它们的内容,这些数据包根据“地址”(类似于 IP 地址)围绕一组链接进行路由TCP/IP 包)。

MSI 本质上是一个数据包,上面写着“将此数据写入该地址”,其中该地址对应于另一个设备(CPU 中的本地 APIC)并且是必需的,因为这就是 protocol/s 总线需要 packet/message 类型,因为这告诉本地 APIC 它必须接受数据包并进行干预。如果地址部分是错误的,那么它看起来就像任何其他写入任何其他东西(并且不会被本地 APIC 接受并且不会作为 IRQ 传递给 CPU 的核心) .

注意:理论上,对于大多数(Intel)CPU来说,本地APIC的物理地址是可以改变的。实际上,没有任何理智的理由想要这样做,如果本地 APIC 的物理地址发生变化,我认为 standard/original“0xFEE.....”地址范围仍然是 hard-wired接受 MSI 的本地 APIC。

  1. What are the RH, DM and XX bits in the Message Address register?

软件(内核)在一个 CPU 上使用本地 APIC(以及其他用途)将 IRQ/s 发送到其他 CPU;称为“inter-processor 中断”(IPI)。当 MSI 被发明时,它们只是 re-used IPI 已经存在的相同标志。换句话说,DM(目标模式)和大多数其他位在 Intel 手册中描述本地 APIC 的部分中定义。要正确理解这些位,您需要了解本地 APIC 和 IPI;特别是关于IPI交付的部分。

后来(在引入硬件虚拟化时)Intel 添加了一个“重定向提示”(以允许将来自设备的 IRQ 重定向到特定的虚拟机)。这在名为“面向定向 I/O 架构规范的英特尔® 虚拟化技术”的规范中有所描述(可在此处获取:https://software.intel.com/content/www/us/en/develop/download/intel-virtualization-technology-for-directed-io-architecture-specification.html)。

甚至后来,英特尔希望支持超过 255 CPU 的系统,但“APIC ID”是一个 8 位 ID(将系统限制为最多 255 CPU s 和一个 IO APIC)。为了解决这个问题,他们创建了 x2APIC(它改变了很多东西——32 位 APIC ID,MSR 访问的本地 APIC 而不是物理地址,...)。然而,所有的旧设备(包括 IO APIC 和 MSI)都是为 8 位 APIC ID 设计的,所以为了解决这个问题,他们只是回收了他们已经拥有的相同的“IRQ 重新映射”(来自虚拟化),以便 8 位 IRQ APIC ID 可以重新映射到具有 32 位 APIC ID 的 IRQ。结果相对可怕且过于混乱(例如,想要支持大量 CPUs 的内核需要使用 IOMMU 来处理与虚拟化无关的事情),但它没有向后兼容性问题。

  1. How does this work with the lAPIC? Basically, how does it trigger interrupts in the lAPIC.

我希望(对于 P6 及更高版本 - 80486 和 Pentium 使用不同的“3 线 APIC 总线”)它们都使用相同的“数据包格式”(消息) - 例如IO APIC 发送 IPI 和 MSI 使用的相同的“将此数据写入此地址”packet/message(到本地 APIC)。

Is it some kind of inter-processor interrupt from outside the CPU?

是的! :-)