> +static void svm_l2_nm_test(struct svm_test *svm) > +{ > + write_cr0(read_cr0() | X86_CR0_TS); > + asm volatile("fnop"); > +} > + > +static void svm_l2_of_test(struct svm_test *svm) > +{ > + struct far_pointer32 fp = { > + .offset = (uintptr_t)&&into, > + .selector = KERNEL_CS32, > + }; > + uintptr_t rsp; > + > + asm volatile ("mov %%rsp, %0" : "=r"(rsp)); > + > + if (fp.offset != (uintptr_t)&&into) { > + printf("Codee address too high.\n"); Nit: Code > + return; > + } > + > + if ((u32)rsp != rsp) { > + printf("Stack address too high.\n"); > + } > + > + asm goto("lcall *%0" : : "m" (fp) : "rax" : into); > + return; > +into: > + asm volatile (".code32;" > + "movl $0x7fffffff, %eax;" > + "addl %eax, %eax;" > + "into;" > + "lret;" > + ".code64"); > + __builtin_unreachable(); > +} > + > +static void svm_l2_ac_test(struct svm_test *test) > +{ > + bool hit_ac = false; > + > + write_cr0(read_cr0() | X86_CR0_AM); > + write_rflags(read_rflags() | X86_EFLAGS_AC); > + > + run_in_user(usermode_callback, AC_VECTOR, 0, 0, 0, 0, &hit_ac); > + > + report(hit_ac, "Usermode #AC handled in L2"); > + vmmcall(); > +} > + > +static void svm_ac_init(void) > +{ > + set_user_mask_all(phys_to_virt(read_cr3()), PAGE_LEVEL); > +} > + > +static void svm_ac_uninit(void) > +{ > + clear_user_mask_all(phys_to_virt(read_cr3()), PAGE_LEVEL); > +} > + > +struct svm_exception_test { > + u8 vector; > + void (*guest_code)(struct svm_test*); > + void (*init_test)(void); > + void (*uninit_test)(void); > +}; > + > +struct svm_exception_test svm_exception_tests[] = { > + { GP_VECTOR, svm_l2_gp_test }, > + { UD_VECTOR, svm_l2_ud_test }, > + { DE_VECTOR, svm_l2_de_test }, > + { BP_VECTOR, svm_l2_bp_test }, > + { NM_VECTOR, svm_l2_nm_test }, > + { OF_VECTOR, svm_l2_of_test }, > + { DB_VECTOR, svm_l2_db_test }, > + { AC_VECTOR, svm_l2_ac_test, svm_ac_init, svm_ac_uninit }, > +}; If you set and clear PT_USER_MASK in svm_l2_ac_test() before calling into userspace you can remove init_test and uninit_test from the framework all together. That will simplify the code. Further, it would be nice to then hoist this framework and the one in vmx into a common x86 file, but looking at this that may be something to think about in the future. There would have to be wrappers when interacting with the vmc{s,b} and macros at the very least. > + > +static u8 svm_exception_test_vector; > + > +static void svm_exception_handler(struct ex_regs *regs) > +{ > + report(regs->vector == svm_exception_test_vector, > + "Handling %s in L2's exception handler", > + exception_mnemonic(svm_exception_test_vector)); > + vmmcall(); > +} > +