linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH kvm-unit-tests v2 0/3] svm: INIT test and test_run on selected vcpu
@ 2020-07-17 11:34 Cathy Avery
  2020-07-17 11:34 ` [PATCH kvm-unit-tests v2 1/3] svm: Add ability to execute test via test_run on a vcpu other than vcpu 0 Cathy Avery
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Cathy Avery @ 2020-07-17 11:34 UTC (permalink / raw)
  To: linux-kernel, kvm, pbonzini

INIT intercept test and the ability to execute test_run
on a selected vcpu

Changes from v1:

1) Incorporated feedback:
	- DR6/DR7/CR2/DEBUGCTL should not be need.
	- HSAVE should be set to a different page for each vCPU
	- The on_cpu to set EFER should be in setup_svm
	- The on_cpu to set cr0/cr3/cr4 should be in setup_vm.

2) Execute tests on selected vcpu using on_cpu_async so the tests
may use the on_cpu functions without causing an ipi_lock deadlock.

3) Added additional test svm_init_startup_test which inits the vcpu and
restarts with sipi.

Cathy Avery (3):
  svm: Add ability to execute test via test_run on a vcpu other than
    vcpu 0
  svm: INIT and STARTUP ipi test
  svm: INIT intercept test

 lib/x86/vm.c    | 18 +++++++++
 lib/x86/vm.h    |  7 ++++
 x86/cstart64.S  |  1 +
 x86/svm.c       | 24 +++++++++++-
 x86/svm.h       |  2 +
 x86/svm_tests.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 148 insertions(+), 1 deletion(-)

-- 
2.20.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH kvm-unit-tests v2 1/3] svm: Add ability to execute test via test_run on a vcpu other than vcpu 0
  2020-07-17 11:34 [PATCH kvm-unit-tests v2 0/3] svm: INIT test and test_run on selected vcpu Cathy Avery
@ 2020-07-17 11:34 ` Cathy Avery
  2020-11-05 17:20   ` Paolo Bonzini
  2020-07-17 11:34 ` [PATCH kvm-unit-tests v2 2/3] svm: INIT and STARTUP ipi test Cathy Avery
  2020-07-17 11:34 ` [PATCH kvm-unit-tests v2 3/3] svm: INIT intercept test Cathy Avery
  2 siblings, 1 reply; 5+ messages in thread
From: Cathy Avery @ 2020-07-17 11:34 UTC (permalink / raw)
  To: linux-kernel, kvm, pbonzini

When running tests that can result in a vcpu being left in an
indeterminate state it is useful to be able to run the test on
a vcpu other than 0. This patch allows test_run to be executed
on any vcpu indicated by the on_vcpu member of the svm_test struct.
The initialized state of the vcpu0 registers used to populate the
vmcb is carried forward to the other vcpus.

Signed-off-by: Cathy Avery <cavery@redhat.com>
---
 lib/x86/vm.c | 18 ++++++++++++++++++
 lib/x86/vm.h |  7 +++++++
 x86/svm.c    | 24 +++++++++++++++++++++++-
 x86/svm.h    |  2 ++
 4 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/lib/x86/vm.c b/lib/x86/vm.c
index 41d6d96..e223bb4 100644
--- a/lib/x86/vm.c
+++ b/lib/x86/vm.c
@@ -2,6 +2,7 @@
 #include "libcflat.h"
 #include "vmalloc.h"
 #include "alloc_page.h"
+#include "smp.h"
 
 pteval_t *install_pte(pgd_t *cr3,
 		      int pte_level,
@@ -139,9 +140,18 @@ static void setup_mmu_range(pgd_t *cr3, phys_addr_t start, size_t len)
 	install_pages(cr3, phys, max - phys, (void *)(ulong)phys);
 }
 
+static void set_additional_vcpu_vmregs(struct vm_vcpu_info *info)
+{
+	write_cr3(info->cr3);
+	write_cr4(info->cr4);
+	write_cr0(info->cr0);
+}
+
 void *setup_mmu(phys_addr_t end_of_memory)
 {
     pgd_t *cr3 = alloc_page();
+    struct vm_vcpu_info info;
+    int i;
 
     memset(cr3, 0, PAGE_SIZE);
 
@@ -166,6 +176,14 @@ void *setup_mmu(phys_addr_t end_of_memory)
     printf("cr0 = %lx\n", read_cr0());
     printf("cr3 = %lx\n", read_cr3());
     printf("cr4 = %lx\n", read_cr4());
+
+    info.cr3 = read_cr3();
+    info.cr4 = read_cr4();
+    info.cr0 = read_cr0();
+
+    for (i = 1; i < cpu_count(); i++)
+        on_cpu(i, (void *)set_additional_vcpu_vmregs, &info);
+
     return cr3;
 }
 
diff --git a/lib/x86/vm.h b/lib/x86/vm.h
index 8750a1e..3a1432f 100644
--- a/lib/x86/vm.h
+++ b/lib/x86/vm.h
@@ -45,4 +45,11 @@ static inline void *current_page_table(void)
 
 void split_large_page(unsigned long *ptep, int level);
 void force_4k_page(void *addr);
+
+struct vm_vcpu_info {
+        u64 cr3;
+        u64 cr4;
+        u64 cr0;
+};
+
 #endif
diff --git a/x86/svm.c b/x86/svm.c
index d8c8272..975c477 100644
--- a/x86/svm.c
+++ b/x86/svm.c
@@ -275,6 +275,17 @@ static void test_run(struct svm_test *test)
 	irq_enable();
 
 	report(test->succeeded(test), "%s", test->name);
+
+        if (test->on_vcpu)
+	    test->on_vcpu_done = true;
+}
+
+static void set_additional_vpcu_msr(void *msr_efer)
+{
+	void *hsave = alloc_page();
+
+	wrmsr(MSR_VM_HSAVE_PA, virt_to_phys(hsave));
+	wrmsr(MSR_EFER, (ulong)msr_efer | EFER_SVME | EFER_NX);
 }
 
 static void setup_svm(void)
@@ -294,6 +305,9 @@ static void setup_svm(void)
 	if (!npt_supported())
 		return;
 
+	for (i = 1; i < cpu_count(); i++)
+		on_cpu(i, (void *)set_additional_vpcu_msr, (void *)rdmsr(MSR_EFER));
+
 	printf("NPT detected - running all tests with NPT enabled\n");
 
 	/*
@@ -396,7 +410,15 @@ int main(int ac, char **av)
 		if (svm_tests[i].supported && !svm_tests[i].supported())
 			continue;
 		if (svm_tests[i].v2 == NULL) {
-			test_run(&svm_tests[i]);
+			if (svm_tests[i].on_vcpu) {
+				if (cpu_count() <= svm_tests[i].on_vcpu)
+					continue;
+				on_cpu_async(svm_tests[i].on_vcpu, (void *)test_run, &svm_tests[i]);
+				while (!svm_tests[i].on_vcpu_done)
+					cpu_relax();
+			}
+			else
+				test_run(&svm_tests[i]);
 		} else {
 			vmcb_ident(vmcb);
 			v2_test = &(svm_tests[i]);
diff --git a/x86/svm.h b/x86/svm.h
index f8e7429..1e60d52 100644
--- a/x86/svm.h
+++ b/x86/svm.h
@@ -348,6 +348,8 @@ struct svm_test {
 	ulong scratch;
 	/* Alternative test interface. */
 	void (*v2)(void);
+	int on_vcpu;
+	bool on_vcpu_done;
 };
 
 struct regs {
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH kvm-unit-tests v2 2/3] svm: INIT and STARTUP ipi test
  2020-07-17 11:34 [PATCH kvm-unit-tests v2 0/3] svm: INIT test and test_run on selected vcpu Cathy Avery
  2020-07-17 11:34 ` [PATCH kvm-unit-tests v2 1/3] svm: Add ability to execute test via test_run on a vcpu other than vcpu 0 Cathy Avery
@ 2020-07-17 11:34 ` Cathy Avery
  2020-07-17 11:34 ` [PATCH kvm-unit-tests v2 3/3] svm: INIT intercept test Cathy Avery
  2 siblings, 0 replies; 5+ messages in thread
From: Cathy Avery @ 2020-07-17 11:34 UTC (permalink / raw)
  To: linux-kernel, kvm, pbonzini

Init the vcpu and issue the STARTUP ipi to indicate the vcpu
should execute its startup routine.

Signed-off-by: Cathy Avery <cavery@redhat.com>
---
 x86/cstart64.S  |  1 +
 x86/svm_tests.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 58 insertions(+)

diff --git a/x86/cstart64.S b/x86/cstart64.S
index 3ae98d3..dfd7320 100644
--- a/x86/cstart64.S
+++ b/x86/cstart64.S
@@ -7,6 +7,7 @@
 .globl tss_descr
 .globl gdt64_desc
 .globl online_cpus
+.globl cpu_online_count
 
 ipi_vector = 0x20
 
diff --git a/x86/svm_tests.c b/x86/svm_tests.c
index 3b0d019..698eb20 100644
--- a/x86/svm_tests.c
+++ b/x86/svm_tests.c
@@ -17,6 +17,8 @@ static void *scratch_page;
 
 #define LATENCY_RUNS 1000000
 
+extern u16 cpu_online_count;
+
 u64 tsc_start;
 u64 tsc_end;
 
@@ -1885,6 +1887,58 @@ static bool reg_corruption_check(struct svm_test *test)
     return get_test_stage(test) == 1;
 }
 
+static void get_tss_entry(void *data)
+{
+    struct descriptor_table_ptr gdt;
+    struct segment_desc64 *gdt_table;
+    struct segment_desc64 *tss_entry;
+    u16 tr = 0;
+
+    sgdt(&gdt);
+    tr = str();
+    gdt_table = (struct segment_desc64 *) gdt.base;
+    tss_entry = &gdt_table[tr / sizeof(struct segment_desc64)];
+    *((struct segment_desc64 **)data) = tss_entry;
+}
+
+static int orig_cpu_count;
+
+static void init_startup_prepare(struct svm_test *test)
+{
+    struct segment_desc64 *tss_entry;
+    int i;
+
+    vmcb_ident(vmcb);
+
+    on_cpu(1, get_tss_entry, &tss_entry);
+
+    orig_cpu_count = cpu_online_count;
+
+    apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_INIT | APIC_INT_ASSERT,
+                   id_map[1]);
+
+    delay(100000000ULL);
+
+    --cpu_online_count;
+
+    *(uint64_t *)tss_entry &= ~DESC_BUSY;
+
+    apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_STARTUP, id_map[1]);
+
+    for (i = 0; i < 5 && cpu_online_count < orig_cpu_count; i++)
+       delay(100000000ULL);
+}
+
+static bool init_startup_finished(struct svm_test *test)
+{
+    return true;
+}
+
+static bool init_startup_check(struct svm_test *test)
+{
+    return cpu_online_count == orig_cpu_count;
+}
+
 #define TEST(name) { #name, .v2 = name }
 
 /*
@@ -2198,6 +2252,9 @@ struct svm_test svm_tests[] = {
     { "reg_corruption", default_supported, reg_corruption_prepare,
       default_prepare_gif_clear, reg_corruption_test,
       reg_corruption_finished, reg_corruption_check },
+    { "svm_init_startup_test", smp_supported, init_startup_prepare,
+      default_prepare_gif_clear, null_test,
+      init_startup_finished, init_startup_check },
     TEST(svm_guest_state_test),
     { NULL, NULL, NULL, NULL, NULL, NULL, NULL }
 };
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH kvm-unit-tests v2 3/3] svm: INIT intercept test
  2020-07-17 11:34 [PATCH kvm-unit-tests v2 0/3] svm: INIT test and test_run on selected vcpu Cathy Avery
  2020-07-17 11:34 ` [PATCH kvm-unit-tests v2 1/3] svm: Add ability to execute test via test_run on a vcpu other than vcpu 0 Cathy Avery
  2020-07-17 11:34 ` [PATCH kvm-unit-tests v2 2/3] svm: INIT and STARTUP ipi test Cathy Avery
@ 2020-07-17 11:34 ` Cathy Avery
  2 siblings, 0 replies; 5+ messages in thread
From: Cathy Avery @ 2020-07-17 11:34 UTC (permalink / raw)
  To: linux-kernel, kvm, pbonzini

INIT vcpu 2 and intercept the INIT. This test
will leave the vcpu in an unusable state.

Signed-off-by: Cathy Avery <cavery@redhat.com>
---
 x86/svm_tests.c | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/x86/svm_tests.c b/x86/svm_tests.c
index 698eb20..b43c19f 100644
--- a/x86/svm_tests.c
+++ b/x86/svm_tests.c
@@ -1939,6 +1939,43 @@ static bool init_startup_check(struct svm_test *test)
     return cpu_online_count == orig_cpu_count;
 }
 
+static volatile bool init_intercept;
+
+static void init_intercept_prepare(struct svm_test *test)
+{
+    init_intercept = false;
+    vmcb_ident(vmcb);
+    vmcb->control.intercept |= (1ULL << INTERCEPT_INIT);
+}
+
+static void init_intercept_test(struct svm_test *test)
+{
+    apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | APIC_DM_INIT | APIC_INT_ASSERT, 0);
+}
+
+static bool init_intercept_finished(struct svm_test *test)
+{
+    vmcb->save.rip += 3;
+
+    if (vmcb->control.exit_code != SVM_EXIT_INIT) {
+        report(false, "VMEXIT not due to init intercept. Exit reason 0x%x",
+               vmcb->control.exit_code);
+
+        return true;
+        }
+
+    init_intercept = true;
+
+    report(true, "INIT to vcpu intercepted");
+
+    return true;
+}
+
+static bool init_intercept_check(struct svm_test *test)
+{
+    return init_intercept;
+}
+
 #define TEST(name) { #name, .v2 = name }
 
 /*
@@ -2255,6 +2292,9 @@ struct svm_test svm_tests[] = {
     { "svm_init_startup_test", smp_supported, init_startup_prepare,
       default_prepare_gif_clear, null_test,
       init_startup_finished, init_startup_check },
+    { "svm_init_intercept_test", smp_supported, init_intercept_prepare,
+      default_prepare_gif_clear, init_intercept_test,
+      init_intercept_finished, init_intercept_check, .on_vcpu = 2 },
     TEST(svm_guest_state_test),
     { NULL, NULL, NULL, NULL, NULL, NULL, NULL }
 };
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH kvm-unit-tests v2 1/3] svm: Add ability to execute test via test_run on a vcpu other than vcpu 0
  2020-07-17 11:34 ` [PATCH kvm-unit-tests v2 1/3] svm: Add ability to execute test via test_run on a vcpu other than vcpu 0 Cathy Avery
@ 2020-11-05 17:20   ` Paolo Bonzini
  0 siblings, 0 replies; 5+ messages in thread
From: Paolo Bonzini @ 2020-11-05 17:20 UTC (permalink / raw)
  To: Cathy Avery, linux-kernel, kvm

On 17/07/20 13:34, Cathy Avery wrote:
> When running tests that can result in a vcpu being left in an
> indeterminate state it is useful to be able to run the test on
> a vcpu other than 0. This patch allows test_run to be executed
> on any vcpu indicated by the on_vcpu member of the svm_test struct.
> The initialized state of the vcpu0 registers used to populate the
> vmcb is carried forward to the other vcpus.
> 
> Signed-off-by: Cathy Avery <cavery@redhat.com>
> ---
>   lib/x86/vm.c | 18 ++++++++++++++++++
>   lib/x86/vm.h |  7 +++++++
>   x86/svm.c    | 24 +++++++++++++++++++++++-
>   x86/svm.h    |  2 ++
>   4 files changed, 50 insertions(+), 1 deletion(-)
> 
> diff --git a/lib/x86/vm.c b/lib/x86/vm.c
> index 41d6d96..e223bb4 100644
> --- a/lib/x86/vm.c
> +++ b/lib/x86/vm.c
> @@ -2,6 +2,7 @@
>   #include "libcflat.h"
>   #include "vmalloc.h"
>   #include "alloc_page.h"
> +#include "smp.h"
>   
>   pteval_t *install_pte(pgd_t *cr3,
>   		      int pte_level,
> @@ -139,9 +140,18 @@ static void setup_mmu_range(pgd_t *cr3, phys_addr_t start, size_t len)
>   	install_pages(cr3, phys, max - phys, (void *)(ulong)phys);
>   }
>   
> +static void set_additional_vcpu_vmregs(struct vm_vcpu_info *info)
> +{
> +	write_cr3(info->cr3);
> +	write_cr4(info->cr4);
> +	write_cr0(info->cr0);
> +}
> +
>   void *setup_mmu(phys_addr_t end_of_memory)
>   {
>       pgd_t *cr3 = alloc_page();
> +    struct vm_vcpu_info info;
> +    int i;
>   
>       memset(cr3, 0, PAGE_SIZE);
>   
> @@ -166,6 +176,14 @@ void *setup_mmu(phys_addr_t end_of_memory)
>       printf("cr0 = %lx\n", read_cr0());
>       printf("cr3 = %lx\n", read_cr3());
>       printf("cr4 = %lx\n", read_cr4());
> +
> +    info.cr3 = read_cr3();
> +    info.cr4 = read_cr4();
> +    info.cr0 = read_cr0();
> +
> +    for (i = 1; i < cpu_count(); i++)
> +        on_cpu(i, (void *)set_additional_vcpu_vmregs, &info);
> +
>       return cr3;
>   }
>   
> diff --git a/lib/x86/vm.h b/lib/x86/vm.h
> index 8750a1e..3a1432f 100644
> --- a/lib/x86/vm.h
> +++ b/lib/x86/vm.h
> @@ -45,4 +45,11 @@ static inline void *current_page_table(void)
>   
>   void split_large_page(unsigned long *ptep, int level);
>   void force_4k_page(void *addr);
> +
> +struct vm_vcpu_info {
> +        u64 cr3;
> +        u64 cr4;
> +        u64 cr0;
> +};
> +
>   #endif
> diff --git a/x86/svm.c b/x86/svm.c
> index d8c8272..975c477 100644
> --- a/x86/svm.c
> +++ b/x86/svm.c
> @@ -275,6 +275,17 @@ static void test_run(struct svm_test *test)
>   	irq_enable();
>   
>   	report(test->succeeded(test), "%s", test->name);
> +
> +        if (test->on_vcpu)
> +	    test->on_vcpu_done = true;
> +}
> +
> +static void set_additional_vpcu_msr(void *msr_efer)
> +{
> +	void *hsave = alloc_page();
> +
> +	wrmsr(MSR_VM_HSAVE_PA, virt_to_phys(hsave));
> +	wrmsr(MSR_EFER, (ulong)msr_efer | EFER_SVME | EFER_NX);
>   }
>   
>   static void setup_svm(void)
> @@ -294,6 +305,9 @@ static void setup_svm(void)
>   	if (!npt_supported())
>   		return;
>   
> +	for (i = 1; i < cpu_count(); i++)
> +		on_cpu(i, (void *)set_additional_vpcu_msr, (void *)rdmsr(MSR_EFER));
> +
>   	printf("NPT detected - running all tests with NPT enabled\n");
>   
>   	/*
> @@ -396,7 +410,15 @@ int main(int ac, char **av)
>   		if (svm_tests[i].supported && !svm_tests[i].supported())
>   			continue;
>   		if (svm_tests[i].v2 == NULL) {
> -			test_run(&svm_tests[i]);
> +			if (svm_tests[i].on_vcpu) {
> +				if (cpu_count() <= svm_tests[i].on_vcpu)
> +					continue;
> +				on_cpu_async(svm_tests[i].on_vcpu, (void *)test_run, &svm_tests[i]);
> +				while (!svm_tests[i].on_vcpu_done)
> +					cpu_relax();
> +			}
> +			else
> +				test_run(&svm_tests[i]);
>   		} else {
>   			vmcb_ident(vmcb);
>   			v2_test = &(svm_tests[i]);
> diff --git a/x86/svm.h b/x86/svm.h
> index f8e7429..1e60d52 100644
> --- a/x86/svm.h
> +++ b/x86/svm.h
> @@ -348,6 +348,8 @@ struct svm_test {
>   	ulong scratch;
>   	/* Alternative test interface. */
>   	void (*v2)(void);
> +	int on_vcpu;
> +	bool on_vcpu_done;
>   };
>   
>   struct regs {
> 

Queued, thanks.

Paolo


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2020-11-05 17:20 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-17 11:34 [PATCH kvm-unit-tests v2 0/3] svm: INIT test and test_run on selected vcpu Cathy Avery
2020-07-17 11:34 ` [PATCH kvm-unit-tests v2 1/3] svm: Add ability to execute test via test_run on a vcpu other than vcpu 0 Cathy Avery
2020-11-05 17:20   ` Paolo Bonzini
2020-07-17 11:34 ` [PATCH kvm-unit-tests v2 2/3] svm: INIT and STARTUP ipi test Cathy Avery
2020-07-17 11:34 ` [PATCH kvm-unit-tests v2 3/3] svm: INIT intercept test Cathy Avery

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).