When EFER.SVME is set to 0 VMRUN, VMSAVE, VMLOAD, CLGI, VMMCALL, and INVLPGA generate a #UD. STGI generates a #UD if SVME is not enabled and neither SVM Lock nor the device exclusion vector (DEV) are supported. Add a test to verify that disabling EFER.SVME makes the listed instructions generate a #UD when executed. Signed-off-by: Kevin Cheng --- x86/svm_tests.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++ x86/unittests.cfg | 10 ++++++++- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/x86/svm_tests.c b/x86/svm_tests.c index 5d27286129337..4c72443702578 100644 --- a/x86/svm_tests.c +++ b/x86/svm_tests.c @@ -2804,6 +2804,60 @@ static void svm_insn_intercept_test(void) } } +asm ( + "insn_invlpga: xor %rax, %rax; xor %ecx, %ecx; invlpga %rax, %ecx;ret\n\t" + "insn_vmrun: xor %rax, %rax; vmrun %rax;ret\n\t" + "insn_vmsave: xor %rax, %rax; vmsave %rax;ret\n\t" + "insn_vmload: xor %rax, %rax; vmload %rax;ret\n\t" +); + +extern void insn_invlpga(void); +extern void insn_vmrun(void); +extern void insn_vmsave(void); +extern void insn_vmload(void); + +static volatile bool ud_fired; + +static void svm_ud_test_handler(struct ex_regs *regs) +{ + ud_fired = true; + regs->rip += 3; +} + +static void svm_ud_test(void) +{ + u64 efer = rdmsr(MSR_EFER); + + handle_exception(UD_VECTOR, svm_ud_test_handler); + wrmsr(MSR_EFER, efer & ~EFER_SVME); + + insn_invlpga(); + report(ud_fired, "Instruction INVLPGA generated #UD when EFER.SVME=0"); + ud_fired = false; + + clgi(); + report(ud_fired, "Instruction CLGI generated #UD when EFER.SVME=0"); + ud_fired = false; + + stgi(); + report(ud_fired, "Instruction STGI generated #UD when EFER.SVME=0"); + ud_fired = false; + + insn_vmrun(); + report(ud_fired, "Instruction VMRUN generated #UD when EFER.SVME=0"); + ud_fired = false; + + insn_vmsave(); + report(ud_fired, "Instruction VMSAVE generated #UD when EFER.SVME=0"); + ud_fired = false; + + insn_vmload(); + report(ud_fired, "Instruction VMLOAD generated #UD when EFER.SVME=0"); + ud_fired = false; + + wrmsr(MSR_EFER, efer); +} + /* TODO: verify if high 32-bits are sign- or zero-extended on bare metal */ #define TEST_BITMAP_ADDR(save_intercept, type, addr, exit_code, \ msg) { \ @@ -4217,6 +4271,7 @@ struct svm_test svm_tests[] = { TEST(svm_shutdown_intercept_test), TEST(svm_insn_intercept_test), TEST(svm_event_injection), + TEST(svm_ud_test), { NULL, NULL, NULL, NULL, NULL, NULL, NULL } }; diff --git a/x86/unittests.cfg b/x86/unittests.cfg index 118e7cdd0286d..ad447e5f82f9f 100644 --- a/x86/unittests.cfg +++ b/x86/unittests.cfg @@ -253,11 +253,19 @@ arch = x86_64 [svm] file = svm.flat smp = 2 -test_args = "-pause_filter_test -svm_intr_intercept_mix_smi -svm_insn_intercept_test -svm_pf_exception_test -svm_pf_exception_forced_emulation_test -svm_pf_inv_asid_test -svm_pf_inv_tlb_ctl_test -svm_event_injection" +test_args = "-pause_filter_test -svm_intr_intercept_mix_smi -svm_insn_intercept_test -svm_pf_exception_test -svm_pf_exception_forced_emulation_test -svm_pf_inv_asid_test -svm_pf_inv_tlb_ctl_test -svm_event_injection -svm_ud_test" qemu_params = -cpu max,+svm -m 4g arch = x86_64 groups = svm +# Disable SKINIT and SVML to test STGI #UD when EFER.SVME=0 +[svm_ud_test] +file = svm.flat +test_args = svm_ud_test +qemu_params = -cpu max,-skinit,-svm-lock,+svm -m 4g +arch = x86_64 +groups = svm + [svm_event_injection] file = svm.flat test_args = svm_event_injection -- 2.52.0.457.g6b5491de43-goog