svm: Add SMI handler for svm_intr_intercept_mix_smi test L1 intercepts L2's SMI and the SMI is still pending at L0. When L1 re-enables GIF via stgi(), L0 delivers the SMI to L1. If SMBASE has not been relocated and no SMI handler has been installed, L1 enters SMM and executes garbage at the default entry point, causing an abort. Install a trivial SMI handler at the default SMBASE entry point so L1 can return from SMM. Signed-off-by: Ryosuke Yasuoka <ryasuoka@redhat.com> Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com> Message-ID: <20260820-add_smi_handler-v2-1-80d7316d5dde@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
diff --git a/x86/svm_tests.c b/x86/svm_tests.c index ccbab1d..4a11fb3 100644 --- a/x86/svm_tests.c +++ b/x86/svm_tests.c
@@ -3543,8 +3543,37 @@ report(0, "must not reach here"); } +#define SMBASE 0x30000 +#define SMBASE_ENTRY (SMBASE + 0x8000) +#define RSM_OPCODE 0xaa0f + +/* + * Install a trivial SMI handler at the default SMBASE entry point as a + * fallback for when SMBASE has not been relocated and no SMI handler has + * been installed. Without this, entering SMM executes garbage at the + * default entry point and aborts. + * + * If running with a firmware that supports SMM, it will relocate SMBASE + * and install its own handler, so the handler installed here will be + * safely ignored. + * + * The default SMBASE (0x30000) region is safe to write to as long as + * only one processor uses it at a given time; flat.lds places all + * sections starting at 4MB, and the page allocator starts after edata. + */ +static void install_smi_handler(void) +{ + WRITE_ONCE(*(u16 *)SMBASE_ENTRY, RSM_OPCODE); +} + static void svm_intr_intercept_mix_smi(void) { + /* + * L1 intercepts L2's SMI and the SMI is still pending at L0. + * When L1 re-enables GIF via stgi(), L0 delivers the SMI to L1. + */ + install_smi_handler(); + vmcb_set_intercept(INTERCEPT_SMI); vmcb->control.int_ctl &= ~V_INTR_MASKING_MASK; test_set_guest(svm_intr_intercept_mix_smi_guest);