我正在编写VMM,我正在尝试支持在VMX非root模式下运行的来宾操作系统对x2APIC寄存器的虚拟访问。
我想首先做一些简单的事情,比如从客户操作系统中读取本地APIC ID。我已尝试在我的VMM中添加对此的支持,但我读到的值似乎不正确。
不幸的是,我似乎无法在网上找到有关虚拟APIC页面的大量信息。我已经阅读了英特尔手册(APIC虚拟化和虚拟中断)的第29章,这就是我正在做的事情:
在基于二级处理器的VM执行控件中,我将以下位设置为1 :(我在下面设置了第9位,因为我最终想支持发布的IPI)
SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE
(第4位)SECONDARY_EXEC_APIC_REGISTER_VIRT
(第8位)SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY
(第9位)在MSR位图中,我禁用0x802
的截取,这是本地APIC ID寄存器。
在我的来宾操作系统中,我使用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
偏移量对我有意义:当与0x802
和0x2
进行AND运算时,MSR地址0xFF
将为0x2
0x20
当左移4位时{1}}。如果您通过其内存映射寄存器访问xAPIC,则0x20
是物理APIC页面内的偏移量。然后读取8个字节(即64位),因此低32位是x2APIC的本地APIC ID。
答案 0 :(得分:1)
我能够在@prl的帮助下解决这个问题。我必须自己为每个核心分配一个虚拟APIC页面,然后使用其相关核心的本地APIC ID单独初始化每个页面。
然后我将页面的物理地址添加到VMCS(在Linux内核中定义了一个名为VIRTUAL_APIC_PAGE_ADDR
的常量,其中包含VMCS中的偏移量)。我没有意识到我必须初始化页面,因为它没有自动完成。
编辑:我在Linux上实现了一个有效的虚拟化系统,支持x2APIC虚拟化和发布中断处理,并在this document中写了这两个主题。该文档应该相当简单,并且包含指向我的实现的链接。