svm: add test for VMRUN with interrupt shadow enabled

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
diff --git a/x86/svm_tests.c b/x86/svm_tests.c
index c81b746..33b2559 100644
--- a/x86/svm_tests.c
+++ b/x86/svm_tests.c
@@ -1554,10 +1554,12 @@
 }
 
 static volatile bool virq_fired;
+static volatile unsigned long virq_rip;
 
 static void virq_isr(isr_regs_t *regs)
 {
 	virq_fired = true;
+	virq_rip = regs->rip;
 }
 
 static void virq_inject_prepare(struct svm_test *test)
@@ -1568,6 +1570,7 @@
 		(0x0f << V_INTR_PRIO_SHIFT); // Set to the highest priority
 	vmcb->control.int_vector = 0xf1;
 	virq_fired = false;
+	virq_rip = -1;
 	set_test_stage(test, 0);
 }
 
@@ -1678,6 +1681,45 @@
 	return get_test_stage(test) == 5;
 }
 
+static void virq_inject_within_shadow_prepare(struct svm_test *test)
+{
+	virq_inject_prepare(test);
+	vmcb->control.int_state = SVM_INTERRUPT_SHADOW_MASK;
+	vmcb->save.rflags |= X86_EFLAGS_IF;
+}
+
+extern void virq_inject_within_shadow_test(struct svm_test *test);
+asm("virq_inject_within_shadow_test: nop; nop; vmmcall");
+
+static void virq_inject_within_shadow_prepare_gif_clear(struct svm_test *test)
+{
+	vmcb->save.rip = (unsigned long) test->guest_func;
+}
+
+static bool virq_inject_within_shadow_finished(struct svm_test *test)
+{
+	if (vmcb->control.exit_code != SVM_EXIT_VMMCALL)
+		report_fail("VMEXIT not due to vmmcall. Exit reason 0x%x",
+			    vmcb->control.exit_code);
+	if (!virq_fired)
+		report_fail("V_IRQ did not fire");
+	else if (virq_rip != (unsigned long) virq_inject_within_shadow_test + 1)
+		report_fail("Unexpected RIP for interrupt handler");
+	else if (vmcb->control.int_ctl & V_IRQ_MASK)
+		report_fail("V_IRQ not cleared on VMEXIT after firing");
+	else if (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK)
+		report_fail("Interrupt shadow not cleared");
+	else
+		inc_test_stage(test);
+
+	return true;
+}
+
+static bool virq_inject_within_shadow_check(struct svm_test *test)
+{
+	return get_test_stage(test) == 1;
+}
+
 /*
  * Detect nested guest RIP corruption as explained in kernel commit
  * b6162e82aef19fee9c32cb3fe9ac30d9116a8c73
@@ -3352,6 +3394,9 @@
 	{ "virq_inject", default_supported, virq_inject_prepare,
 	  default_prepare_gif_clear, virq_inject_test,
 	  virq_inject_finished, virq_inject_check },
+	{ "virq_inject_within_shadow", default_supported, virq_inject_within_shadow_prepare,
+	  virq_inject_within_shadow_prepare_gif_clear, virq_inject_within_shadow_test,
+	  virq_inject_within_shadow_finished, virq_inject_within_shadow_check },
 	{ "reg_corruption", default_supported, reg_corruption_prepare,
 	  default_prepare_gif_clear, reg_corruption_test,
 	  reg_corruption_finished, reg_corruption_check },