svm: INIT test and test_run on selected vcpu
v2 cover svm: INIT test and test_run on selected vcpu
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(-)
Signature · 1 line
2.20.1
PATCH v2 1/3 svm: Add ability to execute test via test_run on a vcpu other than vcpu 0
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.
--- 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(-)
lib/x86/vm.c +18 -0
@@ -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; }
lib/x86/vm.h +7 -0
@@ -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
x86/svm.c +23 -1
@@ -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]);
x86/svm.h +2 -0
@@ -348,6 +348,8 @@ struct svm_test {ulong scratch;/* Alternative test interface. */ void (*v2)(void ); +int on_vcpu; +bool on_vcpu_done; };struct regs {
Signature · 1 line
2.20.1
Re: [PATCH kvm-unit-tests v2 1/3] svm: Add ability to execute test via test_run on a vcpu other than vcpu 0
Quoted 132 lines · Cathy Avery
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_runto be executed on any vcpu indicated by theon_vcpumember of thesvm_teststruct. The initialized state of the vcpu0 registers used to populate the vmcb is carried forward to the other vcpus.Signed-off-by Cathy Avery <[email protected]>--- 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(-)lib/x86/vm.c +18
-0@@ -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; }lib/x86/vm.h +7
-0@@ -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 x86/svm.c +23
-1@@ -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]);x86/svm.h +0
-0
x86/svm.h struct svm_test { · line 355
Quoted 8 lines
x86/svm.h +2
-0@@ -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
PATCH v2 2/3 svm: INIT and STARTUP ipi test
In reply to Cathy AveryInit the vcpu and issue the STARTUP ipi to indicate the vcpu should execute its startup routine.
--- x86/cstart64.S | 1 + x86/svm_tests.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+)
x86/cstart64.S +1 -0
@@ -7,6 +7,7 @@ .globl tss_descr .globl gdt64_desc .globl online_cpus +.globl cpu_online_count ipi_vector = 0x20
x86/svm_tests.c +57 -0
75 lines not on this page · raw message
Signature · 1 line
2.20.1
PATCH v2 3/3 svm: INIT intercept test
In reply to Cathy AveryINIT vcpu 2 and intercept the INIT. This test
will leave the vcpu in an unusable state.
--- x86/svm_tests.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+)
x86/svm_tests.c +40 -0
@@ -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 } };
Signature · 1 line
2.20.1