* [PATCH 1/3] kvm-unit-test: nSVM: Add alternative (v2) test format for nested guests
2020-03-17 20:05 [PATCH 0/3] kvm-unit-test: nSVM: Add alternative (v2) test framework and add test for SVME.EFER vmcb field Krish Sadhukhan
@ 2020-03-17 20:05 ` Krish Sadhukhan
2020-03-17 20:05 ` [PATCH 2/3] kvm-unit-test: nSVM: Add helper functions to write and read vmcb fields Krish Sadhukhan
2020-03-17 20:05 ` [PATCH 3/3] kvm-unit-test: nSVM: Test SVME.EFER on VMRUN of nested guests Krish Sadhukhan
2 siblings, 0 replies; 5+ messages in thread
From: Krish Sadhukhan @ 2020-03-17 20:05 UTC (permalink / raw)
To: kvm; +Cc: pbonzini
..so that we can add tests such as VMCB consistency tests, that require
the tests to only proceed up to the execution of the first guest (nested)
instruction and do not require us to define all the functions that the
current format dictates.
Signed-off-by: Krish Sadhukhan <krish.sadhukhan@oracle.com>
---
x86/svm.c | 75 ++++++++++++++++++++++++++++++++++++++++++---------------
x86/svm.h | 6 +++++
x86/svm_tests.c | 2 ++
3 files changed, 63 insertions(+), 20 deletions(-)
diff --git a/x86/svm.c b/x86/svm.c
index 07571e9..7ce33a6 100644
--- a/x86/svm.c
+++ b/x86/svm.c
@@ -110,9 +110,16 @@ inline void vmmcall(void)
asm volatile ("vmmcall" : : : "memory");
}
+static test_guest_func guest_main;
+
+void test_set_guest(test_guest_func func)
+{
+ guest_main = func;
+}
+
static void test_thunk(struct svm_test *test)
{
- test->guest_func(test);
+ guest_main(test);
vmmcall();
}
@@ -191,14 +198,49 @@ struct regs get_regs(void)
#define LOAD_GPR_C SAVE_GPR_C
-static void test_run(struct svm_test *test, struct vmcb *vmcb)
+struct svm_test *v2_test;
+struct vmcb *vmcb;
+
+#define ASM_VMRUN_CMD \
+ "vmload %%rax\n\t" \
+ "mov regs+0x80, %%r15\n\t" \
+ "mov %%r15, 0x170(%%rax)\n\t" \
+ "mov regs, %%r15\n\t" \
+ "mov %%r15, 0x1f8(%%rax)\n\t" \
+ LOAD_GPR_C \
+ "vmrun %%rax\n\t" \
+ SAVE_GPR_C \
+ "mov 0x170(%%rax), %%r15\n\t" \
+ "mov %%r15, regs+0x80\n\t" \
+ "mov 0x1f8(%%rax), %%r15\n\t" \
+ "mov %%r15, regs\n\t" \
+ "vmsave %%rax\n\t" \
+
+u64 guest_stack[10000];
+
+int svm_vmrun(void)
+{
+ vmcb->save.rip = (ulong)test_thunk;
+ vmcb->save.rsp = (ulong)(guest_stack + ARRAY_SIZE(guest_stack));
+ regs.rdi = (ulong)v2_test;
+
+ asm volatile (
+ ASM_VMRUN_CMD
+ :
+ : "a" (virt_to_phys(vmcb))
+ : "memory");
+
+ return (vmcb->control.exit_code);
+}
+
+static void test_run(struct svm_test *test)
{
u64 vmcb_phys = virt_to_phys(vmcb);
- u64 guest_stack[10000];
irq_disable();
test->vmcb = vmcb;
test->prepare(test);
+ guest_main = test->guest_func;
vmcb->save.rip = (ulong)test_thunk;
vmcb->save.rsp = (ulong)(guest_stack + ARRAY_SIZE(guest_stack));
regs.rdi = (ulong)test;
@@ -210,19 +252,7 @@ static void test_run(struct svm_test *test, struct vmcb *vmcb)
"sti \n\t"
"call *%c[PREPARE_GIF_CLEAR](%[test]) \n \t"
"mov %[vmcb_phys], %%rax \n\t"
- "vmload %%rax\n\t"
- "mov regs+0x80, %%r15\n\t" // rflags
- "mov %%r15, 0x170(%%rax)\n\t"
- "mov regs, %%r15\n\t" // rax
- "mov %%r15, 0x1f8(%%rax)\n\t"
- LOAD_GPR_C
- "vmrun %%rax\n\t"
- SAVE_GPR_C
- "mov 0x170(%%rax), %%r15\n\t" // rflags
- "mov %%r15, regs+0x80\n\t"
- "mov 0x1f8(%%rax), %%r15\n\t" // rax
- "mov %%r15, regs\n\t"
- "vmsave %%rax\n\t"
+ ASM_VMRUN_CMD
"cli \n\t"
"stgi"
: // inputs clobbered by the guest:
@@ -303,7 +333,6 @@ extern struct svm_test svm_tests[];
int main(int ac, char **av)
{
int i = 0;
- struct vmcb *vmcb;
setup_vm();
smp_init();
@@ -318,9 +347,15 @@ int main(int ac, char **av)
vmcb = alloc_page();
for (; svm_tests[i].name != NULL; i++) {
- if (!svm_tests[i].supported())
- continue;
- test_run(&svm_tests[i], vmcb);
+ if (svm_tests[i].v2 == NULL) {
+ if (!svm_tests[i].supported())
+ continue;
+ test_run(&svm_tests[i]);
+ } else {
+ vmcb_ident(vmcb);
+ v2_test = &(svm_tests[i]);
+ svm_tests[i].v2();
+ }
}
return report_summary();
diff --git a/x86/svm.h b/x86/svm.h
index ccc5172..25514de 100644
--- a/x86/svm.h
+++ b/x86/svm.h
@@ -337,6 +337,8 @@ struct svm_test {
struct vmcb *vmcb;
int exits;
ulong scratch;
+ /* Alternative test interface. */
+ void (*v2)(void);
};
struct regs {
@@ -359,6 +361,8 @@ struct regs {
u64 rflags;
};
+typedef void (*test_guest_func)(struct svm_test *);
+
u64 *npt_get_pte(u64 address);
u64 *npt_get_pde(u64 address);
u64 *npt_get_pdpe(void);
@@ -374,5 +378,7 @@ void inc_test_stage(struct svm_test *test);
void vmcb_ident(struct vmcb *vmcb);
struct regs get_regs(void);
void vmmcall(void);
+int svm_vmrun(void);
+void test_set_guest(test_guest_func func);
#endif
diff --git a/x86/svm_tests.c b/x86/svm_tests.c
index 264f8de..580bce6 100644
--- a/x86/svm_tests.c
+++ b/x86/svm_tests.c
@@ -1195,6 +1195,8 @@ static bool pending_event_check_vmask(struct svm_test *test)
return get_test_stage(test) == 2;
}
+#define TEST(name) { #name, .v2 = name }
+
struct svm_test svm_tests[] = {
{ "null", default_supported, default_prepare,
default_prepare_gif_clear, null_test,
--
1.8.3.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 3/3] kvm-unit-test: nSVM: Test SVME.EFER on VMRUN of nested guests
2020-03-17 20:05 [PATCH 0/3] kvm-unit-test: nSVM: Add alternative (v2) test framework and add test for SVME.EFER vmcb field Krish Sadhukhan
2020-03-17 20:05 ` [PATCH 1/3] kvm-unit-test: nSVM: Add alternative (v2) test format for nested guests Krish Sadhukhan
2020-03-17 20:05 ` [PATCH 2/3] kvm-unit-test: nSVM: Add helper functions to write and read vmcb fields Krish Sadhukhan
@ 2020-03-17 20:05 ` Krish Sadhukhan
2 siblings, 0 replies; 5+ messages in thread
From: Krish Sadhukhan @ 2020-03-17 20:05 UTC (permalink / raw)
To: kvm; +Cc: pbonzini
According to the section "Canonicalization and Consistency Checks" in 15.5.1
in APM vol 2, setting EFER.SVME to zero is an illegal guest state and will
cause the nested guest to VMEXIT to the guest with an exit code of
VMEXIT_INVALID.
Signed-off-by: Krish Sadhukhan <krish.sadhukhan@oracle.com>
---
x86/svm_tests.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/x86/svm_tests.c b/x86/svm_tests.c
index 580bce6..8de4b8e 100644
--- a/x86/svm_tests.c
+++ b/x86/svm_tests.c
@@ -1197,6 +1197,28 @@ static bool pending_event_check_vmask(struct svm_test *test)
#define TEST(name) { #name, .v2 = name }
+/*
+ * v2 tests
+ */
+
+static void basic_guest_main(struct svm_test *test)
+{
+}
+
+static void svm_guest_state_test(void)
+{
+ size_t offset = offsetof(struct vmcb_save_area, efer);
+ u64 efer_saved = vmcb_save_read64(offset);
+ u64 efer = efer_saved;
+
+ test_set_guest(basic_guest_main);
+ report (svm_vmrun() == SVM_EXIT_VMMCALL, "EFER.SVME: %lx", efer);
+ efer &= ~EFER_SVME;
+ vmcb_save_write64(offset, efer);
+ report (svm_vmrun() == SVM_EXIT_ERR, "EFER.SVME: %lx", efer);
+ vmcb_save_write64(offset, efer_saved);
+}
+
struct svm_test svm_tests[] = {
{ "null", default_supported, default_prepare,
default_prepare_gif_clear, null_test,
@@ -1277,5 +1299,6 @@ struct svm_test svm_tests[] = {
pending_event_prepare_gif_clear_vmask,
pending_event_test_vmask, pending_event_finished_vmask,
pending_event_check_vmask },
+ TEST(svm_guest_state_test),
{ NULL, NULL, NULL, NULL, NULL, NULL, NULL }
};
--
1.8.3.1
^ permalink raw reply related [flat|nested] 5+ messages in thread