Message ID | 20180824000304.19070-3-krish.sadhukhan@oracle.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [1/2] nVMX x86: check posted-interrupt descriptor addresss on vmentry of L2 | expand |
Ping... On 08/23/2018 05:03 PM, Krish Sadhukhan wrote: > 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@oracle.com> > Reviewed-by: Darren Kenny <darren.kenny@oracle.com> > Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com> > --- > 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)
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)