3

我正在编写一个 VMM,并且我正在尝试支持在 VMX 非 root 模式下运行的来宾操作系统对 x2APIC 寄存器的虚拟访问。

我想从做一些简单的事情开始,例如从客户操作系统中读取本地 APIC ID。我尝试在我的 VMM 中添加对此的支持,但我读取的值似乎不正确。

不幸的是,我似乎无法在网上找到很多关于虚拟 APIC 页面的信息。我已经阅读了英特尔手册的第 29 章(APIC 虚拟化和虚拟中断),这就是我正在做的事情:

  1. 在基于辅助处理器的 VM 执行控件中,我将以下位设置为 1:(我在下面设置位 9,因为我最终想要支持发布的 IPI)

    1. SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE(第 4 位)
    2. SECONDARY_EXEC_APIC_REGISTER_VIRT(第 8 位)
    3. SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY(位 9)
  2. 在 MSR 位图中,我禁用了对 的拦截0x802,这是本地 APIC ID 寄存器。

  3. 在我的来宾操作系统中,我rdmsr用来阅读0x802.

我在固定到不同内核的两个线程上执行第 3 步。他们都2621447225从寄存器中读取值。这似乎是不正确的,因为线程被固定到不同的内核,因此应该读取不同的本地 APIC ID(而且数量2621447225非常大)。我做错了什么?

以下是一些附加信息供您参考:

在英特尔手册的第 29.5 节(虚拟化基于 MSR 的 APIC 访问)中,它说:

If “APIC-register virtualization” is 1 and ECX contains a value in the range 800H–8FFH, the instruction reads the 8 bytes from offset X on the virtual-APIC page into EDX:EAX, where X = (ECX & FFH) « 4. This occurs even if the local APIC is not in x2APIC mode (no general-protection fault occurs because the local APIC is not in x2APIC mode).

偏移量对X我来说很有意义:MSR 地址0x8020x2在与 进行与运算时变为0xFF,并且在左移 4 位时变为。如果您通过其内存映射寄存器访问 xAPIC,则它是物理 APIC 页面内的偏移量。然后读取 8 个字节(即 64 位),因此低 32 位是 x2APIC 的本地 APIC ID。0x20x200x20

4

1 回答 1

1

在@prl 的帮助下,我能够解决这个问题。我必须自己为每个内核分配一个虚拟 APIC 页面,然后使用相关内核的本地 APIC ID 分别初始化每个页面。

然后我将页面的物理地址添加到 VMCS(在 Linux 内核中定义了一个常量,称为VIRTUAL_APIC_PAGE_ADDR包含 VMCS 内的偏移量)。我没有意识到我必须初始化页面,因为它不是自动完成的。

编辑:我在 Linux 上实现了一个工作虚拟化系统,支持 x2APIC 虚拟化并发布了中断处理,并在本文档中写了这两个主题。该文档应该相当简单,并且包含指向我的实现的链接。

于 2017-12-24T07:41:27.567 回答