According to section "Checks on VMX Controls" in Intel SDM vol 3C, the following check needs to be enforced on vmentry of L2 guests: If the “process posted interrupts” VM-execution control is 1, the following must be true: - The “virtual-interrupt delivery” VM-execution control is 1. - The “acknowledge interrupt on exit” VM-exit control is 1. - The posted-interrupt notification vector has a value in the - range 0–255 (bits 15:8 are all 0). - Bits 5:0 of the posted-interrupt descriptor address are all 0. - The posted-interrupt descriptor address does not set any bits beyond the processor's physical-address width. Signed-off-by: Krish Sadhukhan <krish.sadhukhan@xxxxxxxxxx> Reviewed-by: Darren Kenny <darren.kenny@xxxxxxxxxx> Reviewed-by: Karl Heubaum <karl.heubaum@xxxxxxxxxx> --- x86/vmx.h | 1 + x86/vmx_tests.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) diff --git a/x86/vmx.h b/x86/vmx.h index 54646f5..22b2892 100644 --- a/x86/vmx.h +++ b/x86/vmx.h @@ -144,6 +144,7 @@ enum Encoding { TSC_OFFSET_HI = 0x2011ul, APIC_VIRT_ADDR = 0x2012ul, APIC_ACCS_ADDR = 0x2014ul, + POSTED_INTR_DESC_ADDR = 0x2016ul, EPTP = 0x201aul, EPTP_HI = 0x201bul, VMREAD_BITMAP = 0x2026ul, diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c index caa1834..8b2efd8 100644 --- a/x86/vmx_tests.c +++ b/x86/vmx_tests.c @@ -3912,12 +3912,140 @@ static void test_virtual_intr_ctls(void) vmcs_write(PIN_CONTROLS, pin_saved); } +static void test_pi_desc_addr(u64 addr, bool ctrl) +{ + vmcs_write(POSTED_INTR_DESC_ADDR, addr); + report_prefix_pushf("Process-posted-interrupts enabled; posted-interrupt-descriptor-address 0x%lx", addr); + test_vmx_controls(ctrl, false); + report_prefix_pop(); +} + +/* + * If the “process posted interrupts” VM-execution control is 1, the + * following must be true: + * + * - The “virtual-interrupt delivery” VM-execution control is 1. + * - The “acknowledge interrupt on exit” VM-exit control is 1. + * - The posted-interrupt notification vector has a value in the + * - range 0–255 (bits 15:8 are all 0). + * - Bits 5:0 of the posted-interrupt descriptor address are all 0. + * - The posted-interrupt descriptor address does not set any bits + * beyond the processor's physical-address width. + * [Intel SDM] + */ +static void test_posted_intr(void) +{ + u32 saved_primary = vmcs_read(CPU_EXEC_CTRL0); + u32 saved_secondary = vmcs_read(CPU_EXEC_CTRL1); + u32 saved_pin = vmcs_read(PIN_CONTROLS); + u32 exit_ctl_saved = vmcs_read(EXI_CONTROLS); + u32 primary = saved_primary; + u32 secondary = saved_secondary; + u32 pin = saved_pin; + u32 exit_ctl = exit_ctl_saved; + u16 vec; + int i; + + if (!((ctrl_pin_rev.clr & PIN_POST_INTR) && + (ctrl_cpu_rev[1].clr & CPU_VINTD) && + (ctrl_exit_rev.clr & EXI_INTA))) + return; + + vmcs_write(CPU_EXEC_CTRL0, primary | CPU_SECONDARY | CPU_TPR_SHADOW); + + /* + * Test virtual-interrupt-delivery and acknowledge-interrupt-on-exit + */ + pin |= PIN_POST_INTR; + vmcs_write(PIN_CONTROLS, pin); + secondary &= ~CPU_VINTD; + vmcs_write(CPU_EXEC_CTRL1, secondary); + report_prefix_pushf("Process-posted-interrupts enabled; virtual-interrupt-delivery disabled"); + test_vmx_controls(false, false); + report_prefix_pop(); + + secondary |= CPU_VINTD; + vmcs_write(CPU_EXEC_CTRL1, secondary); + report_prefix_pushf("Process-posted-interrupts enabled; virtual-interrupt-delivery enabled"); + test_vmx_controls(false, false); + report_prefix_pop(); + + exit_ctl &= ~EXI_INTA; + vmcs_write(EXI_CONTROLS, exit_ctl); + report_prefix_pushf("Process-posted-interrupts enabled; virtual-interrupt-delivery enabled; acknowledge-interrupt-on-exit disabled"); + test_vmx_controls(false, false); + report_prefix_pop(); + + exit_ctl |= EXI_INTA; + vmcs_write(EXI_CONTROLS, exit_ctl); + report_prefix_pushf("Process-posted-interrupts enabled; virtual-interrupt-delivery enabled; acknowledge-interrupt-on-exit enabled"); + test_vmx_controls(true, false); + report_prefix_pop(); + + secondary &= ~CPU_VINTD; + vmcs_write(CPU_EXEC_CTRL1, secondary); + report_prefix_pushf("Process-posted-interrupts enabled; virtual-interrupt-delivery disabled; acknowledge-interrupt-on-exit enabled"); + test_vmx_controls(false, false); + report_prefix_pop(); + + secondary |= CPU_VINTD; + vmcs_write(CPU_EXEC_CTRL1, secondary); + report_prefix_pushf("Process-posted-interrupts enabled; virtual-interrupt-delivery enabled; acknowledge-interrupt-on-exit enabled"); + test_vmx_controls(true, false); + report_prefix_pop(); + + /* + * Test posted-interrupt notification vector + */ + for (i = 0; i < 8; i++) { + vec = (1ul << i); + vmcs_write(PINV, vec); + report_prefix_pushf("Process-posted-interrupts enabled; posted-interrupt-notification-vector %u", vec); + test_vmx_controls(true, false); + report_prefix_pop(); + } + for (i = 8; i < 16; i++) { + vec = (1ul << i); + vmcs_write(PINV, vec); + report_prefix_pushf("Process-posted-interrupts enabled; posted-interrupt-notification-vector %u", vec); + test_vmx_controls(false, false); + report_prefix_pop(); + } + + vec &= ~(0xff << 8); + vmcs_write(PINV, vec); + report_prefix_pushf("Process-posted-interrupts enabled; posted-interrupt-notification-vector %u", vec); + test_vmx_controls(true, false); + report_prefix_pop(); + + /* + * Test posted-interrupt descriptor addresss + */ + for (i = 0; i < 6; i++) { + test_pi_desc_addr(1ul << i, false); + } + + test_pi_desc_addr(0xf0, false); + test_pi_desc_addr(0xff, false); + test_pi_desc_addr(0x0f, false); + test_pi_desc_addr(0x8000, true); + test_pi_desc_addr(0x00, true); + test_pi_desc_addr(0xc000, true); + + test_vmcs_page_values("process-posted interrupts", POSTED_INTR_DESC_ADDR, false, false); + + vmcs_write(CPU_EXEC_CTRL0, saved_primary); + vmcs_write(CPU_EXEC_CTRL1, saved_secondary); + vmcs_write(PIN_CONTROLS, saved_pin); +} + static void test_apic_ctls(void) { test_apic_virt_addr(); test_apic_access_addr(); test_apic_virtual_ctls(); test_virtual_intr_ctls(); + test_posted_intr(); } static void set_vtpr(unsigned vtpr) -- 2.9.5