x86: vmx: Verify L2 modification to L1 LAPIC TPR works when L0 use TPR threshold
diff mbox series

Message ID 20191111123726.93391-1-liran.alon@oracle.com
State New
Headers show
Series
  • x86: vmx: Verify L2 modification to L1 LAPIC TPR works when L0 use TPR threshold
Related show

Commit Message

Liran Alon Nov. 11, 2019, 12:37 p.m. UTC
Test aims to verify that the issue fixed by commit ("KVM: nVMX: Update
vmcs01 TPR_THRESHOLD if L2 changed L1 TPR") is indeed fixed.

Test performs the following steps:
1) Disable interrupts.
2) Raise TPR to high value and queue a pending interrupt in LAPIC by
issueing a self-IPI with lower priority.
3) Launch guest such that it is provided with passthrough access to
LAPIC.
4) Inside guest, disable interrupts and lower TPR to 0 and then exit guest.
5) Back on host, verify that indeed TPR was set to 0 and that enabling
interrupts indeed deliever pending interrupt in LAPIC.

Without above mentioned commit in L0, step (2) will cause L0 to raise
TPR-threshold to self-IPI vector priority and step (4) will *not* change
vmcs01 TPR-threshold to 0. This will result in infinite loop of VMExits
on TPR_BELOW_THRESHOLD every time L0 attempts to enter L1. Which will
cause test to hang and eventually fail on timeout.

Reviewed-by: Joao Martins <joao.m.martins@oracle.com>
Signed-off-by: Liran Alon <liran.alon@oracle.com>
---
 x86/unittests.cfg |  9 ++++++++-
 x86/vmx_tests.c   | 43 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 51 insertions(+), 1 deletion(-)

Comments

Paolo Bonzini Nov. 15, 2019, 10:20 a.m. UTC | #1
On 11/11/19 13:37, Liran Alon wrote:
> Test aims to verify that the issue fixed by commit ("KVM: nVMX: Update
> vmcs01 TPR_THRESHOLD if L2 changed L1 TPR") is indeed fixed.
> 
> Test performs the following steps:
> 1) Disable interrupts.
> 2) Raise TPR to high value and queue a pending interrupt in LAPIC by
> issueing a self-IPI with lower priority.
> 3) Launch guest such that it is provided with passthrough access to
> LAPIC.
> 4) Inside guest, disable interrupts and lower TPR to 0 and then exit guest.
> 5) Back on host, verify that indeed TPR was set to 0 and that enabling
> interrupts indeed deliever pending interrupt in LAPIC.
> 
> Without above mentioned commit in L0, step (2) will cause L0 to raise
> TPR-threshold to self-IPI vector priority and step (4) will *not* change
> vmcs01 TPR-threshold to 0. This will result in infinite loop of VMExits
> on TPR_BELOW_THRESHOLD every time L0 attempts to enter L1. Which will
> cause test to hang and eventually fail on timeout.
> 
> Reviewed-by: Joao Martins <joao.m.martins@oracle.com>
> Signed-off-by: Liran Alon <liran.alon@oracle.com>
> ---
>  x86/unittests.cfg |  9 ++++++++-
>  x86/vmx_tests.c   | 43 +++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 51 insertions(+), 1 deletion(-)
> 
> diff --git a/x86/unittests.cfg b/x86/unittests.cfg
> index 5ecb9bba535b..fd3197455aa6 100644
> --- a/x86/unittests.cfg
> +++ b/x86/unittests.cfg
> @@ -232,7 +232,7 @@ extra_params = -cpu qemu64,+umip
>  
>  [vmx]
>  file = vmx.flat
> -extra_params = -cpu host,+vmx -append "-exit_monitor_from_l2_test -ept_access* -vmx_smp* -vmx_vmcs_shadow_test -atomic_switch_overflow_msrs_test -vmx_init_signal_test"
> +extra_params = -cpu host,+vmx -append "-exit_monitor_from_l2_test -ept_access* -vmx_smp* -vmx_vmcs_shadow_test -atomic_switch_overflow_msrs_test -vmx_init_signal_test -vmx_apic_passthrough_tpr_threshold_test"
>  arch = x86_64
>  groups = vmx
>  
> @@ -278,6 +278,13 @@ arch = x86_64
>  groups = vmx
>  timeout = 10
>  
> +[vmx_apic_passthrough_tpr_threshold_test]
> +file = vmx.flat
> +extra_params = -cpu host,+vmx -m 2048 -append vmx_apic_passthrough_tpr_threshold_test
> +arch = x86_64
> +groups = vmx
> +timeout = 10
> +
>  [vmx_vmcs_shadow_test]
>  file = vmx.flat
>  extra_params = -cpu host,+vmx -append vmx_vmcs_shadow_test
> diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
> index 4aebc3fe1ff9..b137fc5456b8 100644
> --- a/x86/vmx_tests.c
> +++ b/x86/vmx_tests.c
> @@ -8343,6 +8343,48 @@ static void vmx_apic_passthrough_thread_test(void)
>  	vmx_apic_passthrough(true);
>  }
>  
> +static void vmx_apic_passthrough_tpr_threshold_guest(void)
> +{
> +	cli();
> +	apic_set_tpr(0);
> +}
> +
> +static bool vmx_apic_passthrough_tpr_threshold_ipi_isr_fired;
> +static void vmx_apic_passthrough_tpr_threshold_ipi_isr(isr_regs_t *regs)
> +{
> +	vmx_apic_passthrough_tpr_threshold_ipi_isr_fired = true;
> +	eoi();
> +}
> +
> +static void vmx_apic_passthrough_tpr_threshold_test(void)
> +{
> +	int ipi_vector = 0xe1;
> +
> +	disable_intercept_for_x2apic_msrs();
> +	vmcs_clear_bits(PIN_CONTROLS, PIN_EXTINT);
> +
> +	/* Raise L0 TPR-threshold by queueing vector in LAPIC IRR */
> +	cli();
> +	apic_set_tpr((ipi_vector >> 4) + 1);
> +	apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL |
> +			APIC_DM_FIXED | ipi_vector,
> +			0);
> +
> +	test_set_guest(vmx_apic_passthrough_tpr_threshold_guest);
> +	enter_guest();
> +
> +	report("TPR was zero by guest", apic_get_tpr() == 0);
> +
> +	/* Clean pending self-IPI */
> +	vmx_apic_passthrough_tpr_threshold_ipi_isr_fired = false;
> +	handle_irq(ipi_vector, vmx_apic_passthrough_tpr_threshold_ipi_isr);
> +	sti();
> +	asm volatile ("nop");
> +	report("self-IPI fired", vmx_apic_passthrough_tpr_threshold_ipi_isr_fired);
> +
> +	report(__func__, 1);
> +}
> +
>  static u64 init_signal_test_exit_reason;
>  static bool init_signal_test_thread_continued;
>  
> @@ -9022,6 +9064,7 @@ struct vmx_test vmx_tests[] = {
>  	/* APIC pass-through tests */
>  	TEST(vmx_apic_passthrough_test),
>  	TEST(vmx_apic_passthrough_thread_test),
> +	TEST(vmx_apic_passthrough_tpr_threshold_test),
>  	TEST(vmx_init_signal_test),
>  	/* VMCS Shadowing tests */
>  	TEST(vmx_vmcs_shadow_test),
> 

Queued, thanks.

Patch
diff mbox series

diff --git a/x86/unittests.cfg b/x86/unittests.cfg
index 5ecb9bba535b..fd3197455aa6 100644
--- a/x86/unittests.cfg
+++ b/x86/unittests.cfg
@@ -232,7 +232,7 @@  extra_params = -cpu qemu64,+umip
 
 [vmx]
 file = vmx.flat
-extra_params = -cpu host,+vmx -append "-exit_monitor_from_l2_test -ept_access* -vmx_smp* -vmx_vmcs_shadow_test -atomic_switch_overflow_msrs_test -vmx_init_signal_test"
+extra_params = -cpu host,+vmx -append "-exit_monitor_from_l2_test -ept_access* -vmx_smp* -vmx_vmcs_shadow_test -atomic_switch_overflow_msrs_test -vmx_init_signal_test -vmx_apic_passthrough_tpr_threshold_test"
 arch = x86_64
 groups = vmx
 
@@ -278,6 +278,13 @@  arch = x86_64
 groups = vmx
 timeout = 10
 
+[vmx_apic_passthrough_tpr_threshold_test]
+file = vmx.flat
+extra_params = -cpu host,+vmx -m 2048 -append vmx_apic_passthrough_tpr_threshold_test
+arch = x86_64
+groups = vmx
+timeout = 10
+
 [vmx_vmcs_shadow_test]
 file = vmx.flat
 extra_params = -cpu host,+vmx -append vmx_vmcs_shadow_test
diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
index 4aebc3fe1ff9..b137fc5456b8 100644
--- a/x86/vmx_tests.c
+++ b/x86/vmx_tests.c
@@ -8343,6 +8343,48 @@  static void vmx_apic_passthrough_thread_test(void)
 	vmx_apic_passthrough(true);
 }
 
+static void vmx_apic_passthrough_tpr_threshold_guest(void)
+{
+	cli();
+	apic_set_tpr(0);
+}
+
+static bool vmx_apic_passthrough_tpr_threshold_ipi_isr_fired;
+static void vmx_apic_passthrough_tpr_threshold_ipi_isr(isr_regs_t *regs)
+{
+	vmx_apic_passthrough_tpr_threshold_ipi_isr_fired = true;
+	eoi();
+}
+
+static void vmx_apic_passthrough_tpr_threshold_test(void)
+{
+	int ipi_vector = 0xe1;
+
+	disable_intercept_for_x2apic_msrs();
+	vmcs_clear_bits(PIN_CONTROLS, PIN_EXTINT);
+
+	/* Raise L0 TPR-threshold by queueing vector in LAPIC IRR */
+	cli();
+	apic_set_tpr((ipi_vector >> 4) + 1);
+	apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL |
+			APIC_DM_FIXED | ipi_vector,
+			0);
+
+	test_set_guest(vmx_apic_passthrough_tpr_threshold_guest);
+	enter_guest();
+
+	report("TPR was zero by guest", apic_get_tpr() == 0);
+
+	/* Clean pending self-IPI */
+	vmx_apic_passthrough_tpr_threshold_ipi_isr_fired = false;
+	handle_irq(ipi_vector, vmx_apic_passthrough_tpr_threshold_ipi_isr);
+	sti();
+	asm volatile ("nop");
+	report("self-IPI fired", vmx_apic_passthrough_tpr_threshold_ipi_isr_fired);
+
+	report(__func__, 1);
+}
+
 static u64 init_signal_test_exit_reason;
 static bool init_signal_test_thread_continued;
 
@@ -9022,6 +9064,7 @@  struct vmx_test vmx_tests[] = {
 	/* APIC pass-through tests */
 	TEST(vmx_apic_passthrough_test),
 	TEST(vmx_apic_passthrough_thread_test),
+	TEST(vmx_apic_passthrough_tpr_threshold_test),
 	TEST(vmx_init_signal_test),
 	/* VMCS Shadowing tests */
 	TEST(vmx_vmcs_shadow_test),