Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx> --- x86/svm_tests.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/x86/svm_tests.c b/x86/svm_tests.c index c81b7465..33b25599 100644 --- a/x86/svm_tests.c +++ b/x86/svm_tests.c @@ -1554,10 +1554,12 @@ static bool exc_inject_check(struct svm_test *test) } 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 @@ static void virq_inject_prepare(struct svm_test *test) (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 @@ static bool virq_inject_check(struct svm_test *test) 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 @@ 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 }, + { "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 }, -- 2.45.1