svm: INIT test and test_run on selected vcpu
cover svm: INIT test and test_run on selected vcpu
INIT intercept test and the ability to execute test_run on a selected vcpu.
Cathy Avery (2):
svm: Add ability to execute test via test_run on a vcpu other than
vcpu 0
svm: INIT intercept test
x86/svm.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- x86/svm.h | 13 +++++++++++++ x86/svm_tests.c | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 1 deletion(-)
Signature · 1 line
2.20.1
PATCH 1/2 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.
--- x86/svm.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- x86/svm.h | 13 +++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-)
x86/svm.c +48 -1
@@ -367,6 +367,45 @@ test_wanted(const char *name, char *filters[], int filter_count) } } +static void set_additional_vpcu_regs (struct extra_vcpu_info *info) +{ +wrmsr (MSR_VM_HSAVE_PA , info->hsave); +wrmsr (MSR_EFER ,rdmsr (MSR_EFER ) |EFER_SVME ); +wrmsr (MSR_EFER ,rdmsr (MSR_EFER ) |EFER_NX ); +write_cr3 (info->cr3); +write_cr4 (info->cr4); +write_cr0 (info->cr0); +write_dr6 (info->dr6); +write_dr7 (info->dr7); +write_cr2 (info->cr2); +wrmsr (MSR_IA32_CR_PAT , info->g_pat); +wrmsr (MSR_IA32_DEBUGCTLMSR , info->dbgctl); +} + +static void get_additional_vcpu_regs (struct extra_vcpu_info *info) +{ + info->hsave =rdmsr (MSR_VM_HSAVE_PA ); + info->cr3 =read_cr3 (); + info->cr4 =read_cr4 (); + info->cr0 =read_cr0 (); + info->dr7 =read_dr7 (); + info->dr6 =read_dr6 (); + info->cr2 =read_cr2 (); + info->g_pat =rdmsr (MSR_IA32_CR_PAT ); + info->dbgctl =rdmsr (MSR_IA32_DEBUGCTLMSR ); +} + +static void init_additional_vcpu_regs (void ) +{ +int i; +struct extra_vcpu_info info; + +get_additional_vcpu_regs (&info); + +for (i =1 ; i <cpu_count (); i++) +on_cpu (i, (void *)set_additional_vpcu_regs, &info); +} +int main (int ac,char **av) {int i =0 ;
@@ -384,6 +423,8 @@ int main(int ac, char **av)setup_svm (); +init_additional_vcpu_regs (); + vmcb =alloc_page ();for (; svm_tests[i].name !=NULL ; i++) {
@@ -392,7 +433,13 @@ 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 (svm_tests[i].on_vcpu, (void *)test_run, &svm_tests[i]); + } +else +test_run (&svm_tests[i]); }else {vmcb_ident (vmcb); v2_test = &(svm_tests[i]);
x86/svm.h +13 -0
@@ -338,6 +338,7 @@ struct svm_test {ulong scratch;/* Alternative test interface. */ void (*v2)(void ); +int on_vcpu; };struct regs {
@@ -360,6 +361,18 @@ struct regs {u64 rflags; }; +struct extra_vcpu_info { +u64 hsave; +u64 cr3; +u64 cr4; +u64 cr0; +u64 dr7; +u64 dr6; +u64 cr2; +u64 g_pat; +u64 dbgctl; +}; +typedef void (*test_guest_func )(struct svm_test *);u64 *npt_get_pte (u64 address);
Signature · 1 line
2.20.1
Paolo Bonzini
maintainerRe: [PATCH kvm-unit-tests 1/2] svm: Add ability to execute test via test_run on a vcpu other than vcpu 0
Quoted 38 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]>--- x86/svm.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- x86/svm.h | 13 +++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-)x86/svm.c +17
-0@@ -367,6 +367,45 @@ test_wanted(const char *name, char *filters[], int filter_count) } } +static void set_additional_vpcu_regs (struct extra_vcpu_info *info) +{ +wrmsr (MSR_VM_HSAVE_PA , info->hsave); +wrmsr (MSR_EFER ,rdmsr (MSR_EFER ) |EFER_SVME ); +wrmsr (MSR_EFER ,rdmsr (MSR_EFER ) |EFER_NX ); +write_cr3 (info->cr3); +write_cr4 (info->cr4); +write_cr0 (info->cr0); +write_dr6 (info->dr6); +write_dr7 (info->dr7); +write_cr2 (info->cr2); +wrmsr (MSR_IA32_CR_PAT , info->g_pat); +wrmsr (MSR_IA32_DEBUGCTLMSR , info->dbgctl); +} + +static void get_additional_vcpu_regs (struct extra_vcpu_info *info) +{
x86/svm.c test_wanted(const char *name, char *filters[], int filter_count) · line 396
Quoted 10 lines
x86/svm.c +10
-0+ info->hsave =rdmsr (MSR_VM_HSAVE_PA ); + info->cr3 =read_cr3 (); + info->cr4 =read_cr4 (); + info->cr0 =read_cr0 (); + info->dr7 =read_dr7 (); + info->dr6 =read_dr6 (); + info->cr2 =read_cr2 (); + info->g_pat =rdmsr (MSR_IA32_CR_PAT ); + info->dbgctl =rdmsr (MSR_IA32_DEBUGCTLMSR ); +}
Some tweaks are needed here:
- DR6/DR7/CR2/DEBUGCTL should not be needed, are they? Same for PAT since it's not modified by the tests and defaults to the "right" value (0x0007040600070406ULL) rather than zero.
- HSAVE should be set to a different page for each vCPU
- The on_cpu to set EFER should be in setup_svm, rather than a separate function
- The on_cpu to set cr0/cr3/cr4 should be in setup_vm.
Paolo
PATCH 2/2 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
@@ -1789,6 +1789,43 @@ static bool virq_inject_check(struct svm_test *test)return get_test_stage (test) ==5 ; } +static volatile bool init_intercept; + +static void init_signal_intercept_prepare (struct svm_test *test) +{ + +vmcb_ident (vmcb); + vmcb->control.intercept |= (1ULL <<INTERCEPT_INIT ); + init_intercept = false; +} + +static void init_signal_test (struct svm_test *test) +{ +apic_icr_write (APIC_DEST_SELF |APIC_DEST_PHYSICAL |APIC_DM_INIT |APIC_INT_ASSERT ,0 ); +} + +static bool init_signal_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_signal_check (struct svm_test *test) +{ +return init_intercept; +} +#define TEST (name) { #name, .v2 = name }/*
@@ -1950,6 +1987,9 @@ struct svm_test svm_tests[] = { {"virq_inject" , default_supported, virq_inject_prepare, default_prepare_gif_clear, virq_inject_test, virq_inject_finished, virq_inject_check }, + { "svm_init_signal_intercept_test", default_supported, init_signal_intercept_prepare, + default_prepare_gif_clear, init_signal_test, + init_signal_finished, init_signal_check, .on_vcpu = 2 },TEST (svm_guest_state_test), { NULL, NULL, NULL, NULL, NULL, NULL, NULL } };
Signature · 1 line
2.20.1
Paolo Bonzini
maintainerRe: [PATCH kvm-unit-tests 2/2] svm: INIT intercept test
Quoted 4 lines · Cathy Avery
INIT vcpu 2 and intercept the INIT. This test
will leave the vcpu in an unusable state.Signed-off-by Cathy Avery <[email protected]>
It should be possible to reinitialize the vCPU using a SIPI interrupt, like
old = cpu_online_count--; apic_icr_write(APIC_DEST_PHYSICAL | APIC_DEST_SIPI, id_map[cpu]); while (cpu_online_count != old) cpu_relax();
You can test this by using vCPU 1 to run this test.
Paolo
Quoted 63 lines
--- x86/svm_tests.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+)x86/svm_tests.c +40
-0@@ -1789,6 +1789,43 @@ static bool virq_inject_check(struct svm_test *test)return get_test_stage (test) ==5 ; } +static volatile bool init_intercept; + +static void init_signal_intercept_prepare (struct svm_test *test) +{ + +vmcb_ident (vmcb); + vmcb->control.intercept |= (1ULL <<INTERCEPT_INIT ); + init_intercept = false; +} + +static void init_signal_test (struct svm_test *test) +{ +apic_icr_write (APIC_DEST_SELF |APIC_DEST_PHYSICAL |APIC_DM_INIT |APIC_INT_ASSERT ,0 ); +} + +static bool init_signal_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_signal_check (struct svm_test *test) +{ +return init_intercept; +} +#define TEST (name) { #name, .v2 = name }/* @@ -1950,6 +1987,9 @@ struct svm_test svm_tests[] = { {"virq_inject" , default_supported, virq_inject_prepare, default_prepare_gif_clear, virq_inject_test, virq_inject_finished, virq_inject_check }, + { "svm_init_signal_intercept_test", default_supported, init_signal_intercept_prepare, + default_prepare_gif_clear, init_signal_test, + init_signal_finished, init_signal_check, .on_vcpu = 2 },TEST (svm_guest_state_test), { NULL, NULL, NULL, NULL, NULL, NULL, NULL } };