kvm-unit-test: nSVM: Add alternative (v2) test format for nested guests

  ..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>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
diff --git a/x86/svm.c b/x86/svm.c
index a014adb..41685bf 100644
--- a/x86/svm.c
+++ b/x86/svm.c
@@ -112,9 +112,16 @@
 	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();
 }
 
@@ -193,13 +200,48 @@
 
 #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->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;
@@ -211,19 +253,7 @@
 			"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:
@@ -357,9 +387,17 @@
 	vmcb = alloc_page();
 
 	for (; svm_tests[i].name != NULL; i++) {
-		if (!test_wanted(svm_tests[i].name, av, ac) || !svm_tests[i].supported())
+		if (!test_wanted(svm_tests[i].name, av, ac))
 			continue;
-		test_run(&svm_tests[i], vmcb);
+		if (svm_tests[i].supported && !svm_tests[i].supported())
+			continue;
+		if (svm_tests[i].v2 == NULL) {
+			test_run(&svm_tests[i]);
+		} else {
+			vmcb_ident(vmcb);
+			v2_test = &(svm_tests[i]);
+			svm_tests[i].v2();
+		}
 	}
 
 	if (!matched)
diff --git a/x86/svm.h b/x86/svm.h
index 599050e..645deb7 100644
--- a/x86/svm.h
+++ b/x86/svm.h
@@ -336,6 +336,8 @@
 	bool (*succeeded)(struct svm_test *test);
 	int exits;
 	ulong scratch;
+	/* Alternative test interface. */
+	void (*v2)(void);
 };
 
 struct regs {
@@ -358,6 +360,8 @@
 	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);
@@ -373,6 +377,8 @@
 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);
 
 extern struct vmcb *vmcb;
 extern struct svm_test svm_tests[];
diff --git a/x86/svm_tests.c b/x86/svm_tests.c
index 3eef913..f1945ee 100644
--- a/x86/svm_tests.c
+++ b/x86/svm_tests.c
@@ -1340,6 +1340,8 @@
     return get_test_stage(test) == 5;
 }
 
+#define TEST(name) { #name, .v2 = name }
+
 struct svm_test svm_tests[] = {
     { "null", default_supported, default_prepare,
       default_prepare_gif_clear, null_test,