Re: [kvm-unit-tests PATCH] x86: nSVM: Add tests for instruction interrupts

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Aug 20, 2025 at 12:29 PM Kevin Cheng <chengkev@xxxxxxxxxx> wrote:
>
> The nVMX tests already have coverage for instruction intercepts.
> Add a similar test for nSVM to improve test parity between nSVM and
> nVMX.
>
> Signed-off-by: Kevin Cheng <chengkev@xxxxxxxxxx>
> ---
>  x86/svm_tests.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 120 insertions(+)
>
> diff --git a/x86/svm_tests.c b/x86/svm_tests.c
> index 80d5aeb1..50201683 100644
> --- a/x86/svm_tests.c
> +++ b/x86/svm_tests.c
> @@ -12,6 +12,7 @@
>  #include "util.h"
>  #include "x86/usermode.h"
>  #include "vmalloc.h"
> +#include "pmu.h"
>
>  #define SVM_EXIT_MAX_DR_INTERCEPT 0x3f
>
> @@ -2487,6 +2488,124 @@ static void test_dr(void)
>         vmcb->save.dr7 = dr_saved;
>  }
>
> +asm(
> +       "insn_sidt: sidt idt_descr;ret\n\t"
> +       "insn_sgdt: sgdt gdt_descr;ret\n\t"
> +       "insn_sldt: sldt %ax;ret\n\t"
> +       "insn_str: str %ax;ret\n\t"
> +       "insn_lidt: lidt idt_descr;ret\n\t"
> +       "insn_lgdt: lgdt gdt_descr;ret\n\t"
> +       "insn_lldt: xor %eax, %eax; lldt %ax;ret\n\t"
> +       "insn_rdpmc: xor %ecx, %ecx; rdpmc;ret\n\t"
> +       "insn_cpuid: mov $10, %eax; cpuid;ret\n\t"
> +       "insn_invd: invd;ret\n\t"
> +       "insn_pause: pause;ret\n\t"
> +       "insn_hlt: hlt;ret\n\t"
> +       "insn_invlpg: invlpg 0x12345678;ret\n\t"
> +       "insn_monitor: xor %eax, %eax; xor %ecx, %ecx; xor %edx, %edx; monitor;ret\n\t"
> +       "insn_mwait: xor %eax, %eax; xor %ecx, %ecx; mwait;ret\n\t"
> +);
> +
> +extern void insn_sidt(struct svm_test *test);
> +extern void insn_sgdt(struct svm_test *test);
> +extern void insn_sldt(struct svm_test *test);
> +extern void insn_str(struct svm_test *test);
> +extern void insn_lidt(struct svm_test *test);
> +extern void insn_lgdt(struct svm_test *test);
> +extern void insn_lldt(struct svm_test *test);
> +extern void insn_rdpmc(struct svm_test *test);
> +extern void insn_cpuid(struct svm_test *test);
> +extern void insn_invd(struct svm_test *test);
> +extern void insn_pause(struct svm_test *test);
> +extern void insn_hlt(struct svm_test *test);
> +extern void insn_invlpg(struct svm_test *test);
> +extern void insn_monitor(struct svm_test *test);
> +extern void insn_mwait(struct svm_test *test);
> +
> +u32 cur_insn;
> +
> +typedef bool (*supported_fn)(void);
> +
> +static bool this_cpu_has_mwait(void)
> +{
> +       return this_cpu_has(X86_FEATURE_MWAIT);
> +}
> +
> +struct insn_table {
> +       const char *name;
> +       u32 flag;
> +       void (*insn_func)(struct svm_test *test);
> +       u32 reason;
> +       u64 exit_info_1;
> +       u64 exit_info_2;
> +       bool always_traps;
> +       const supported_fn supported_fn;
> +};
> +
> +static struct insn_table insn_table[] = {
> +       {"STORE IDTR", INTERCEPT_STORE_IDTR, insn_sidt, SVM_EXIT_IDTR_READ, 0, 0},
> +       {"STORE GDTR", INTERCEPT_STORE_GDTR, insn_sgdt, SVM_EXIT_GDTR_READ, 0, 0},
> +       {"STORE LDTR", INTERCEPT_STORE_LDTR, insn_sldt, SVM_EXIT_LDTR_READ, 0, 0},
> +       {"STORE TR", INTERCEPT_STORE_TR, insn_str, SVM_EXIT_TR_READ, 0, 0},
> +       {"LOAD IDTR", INTERCEPT_LOAD_IDTR, insn_lidt, SVM_EXIT_IDTR_WRITE, 0, 0},
> +       {"LOAD GDTR", INTERCEPT_LOAD_GDTR, insn_lgdt, SVM_EXIT_GDTR_WRITE, 0, 0},
> +       {"LOAD LDTR", INTERCEPT_LOAD_LDTR, insn_lldt, SVM_EXIT_LDTR_WRITE, 0, 0},
> +       {"RDPMC", INTERCEPT_RDPMC, insn_rdpmc, SVM_EXIT_RDPMC, 0, 0, false, this_cpu_has_pmu},
> +       {"CPUID", INTERCEPT_CPUID, insn_cpuid, SVM_EXIT_CPUID, 0, 0, true},
> +       {"INVD", INTERCEPT_INVD, insn_invd, SVM_EXIT_INVD, 0, 0, true},
> +       {"PAUSE", INTERCEPT_PAUSE, insn_pause, SVM_EXIT_PAUSE, 0, 0},
> +       {"HLT", INTERCEPT_HLT, insn_hlt, SVM_EXIT_HLT, 0, 0},
> +       {"INVLPG", INTERCEPT_INVLPG, insn_invlpg, SVM_EXIT_INVLPG, 0, 0},
> +       {"MONITOR", INTERCEPT_MONITOR, insn_monitor, SVM_EXIT_MONITOR, 0, 0, false, this_cpu_has_mwait},
> +       {"MWAIT", INTERCEPT_MWAIT, insn_mwait, SVM_EXIT_MWAIT, 0, 0, false, this_cpu_has_mwait},
> +       {NULL},
> +};
> +
> +static void insn_intercept_test(void)
> +{
> +       u32 exit_code;
> +       u64 exit_info_1;
> +       u64 exit_info_2;
> +
> +       for (cur_insn = 0; insn_table[cur_insn].name != NULL; ++cur_insn) {
> +               struct insn_table insn = insn_table[cur_insn];
> +
> +               if (insn.supported_fn && !insn.supported_fn()) {
> +                       printf("\tFeature required for %s is not supported.\n",
> +                              insn_table[cur_insn].name);
> +                       continue;
> +               }
> +
> +               test_set_guest(insn.insn_func);
> +
> +               if (insn.insn_func != insn_hlt && !insn.always_traps)
> +                       report(svm_vmrun() == SVM_EXIT_VMMCALL, "execute %s", insn.name);
> +
> +               vmcb->control.intercept |= 1 << insn.flag;
> +
> +               svm_vmrun();
> +
> +               exit_code = vmcb->control.exit_code;
> +               exit_info_1 = vmcb->control.exit_info_1;
> +               exit_info_2 = vmcb->control.exit_info_2;
> +
> +               report(exit_code == insn.reason,
> +                       "Expected exit code: 0x%x, received exit code: 0x%x",
> +                       exit_code, insn.reason);
> +
> +               if (!exit_info_1)
> +                       report(exit_info_1 == insn.exit_info_1,
> +                       "Expected exit_info_1: 0x%lx, received exit_info_1: 0x%lx",
> +                       exit_info_1, insn.exit_info_1);
> +               if (!exit_info_2)
> +                       report(exit_info_2 == insn.exit_info_2,
> +                       "Expected exit_info_2: 0x%lx, received exit_info_2: 0x%lx",
> +                       exit_info_2, insn.exit_info_2);
> +
> +               vmcb->control.intercept &= ~(1 << insn.flag);
> +       }
> +}
> +
>  /* 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) {                                         \
> @@ -3564,6 +3683,7 @@ struct svm_test svm_tests[] = {
>         TEST(svm_tsc_scale_test),
>         TEST(pause_filter_test),
>         TEST(svm_shutdown_intercept_test),
> +       TEST(insn_intercept_test),
>         { NULL, NULL, NULL, NULL, NULL, NULL, NULL }
>  };
>
> --
> 2.51.0.261.g7ce5a0a67e-goog
>

Just checking in as it's been a couple weeks :) If there is anyone
else who would be better suited to take a look at these please let me
know and I can cc them as well!





[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux