On 07/07/2017 01:14, Bandan Das wrote: > > Besides for the obvious vmfunc call in L2 for eptp switching, > other tests are to check for valid error paths when L2 calls > vmfunc when L1 hasn't enabled it in the secondary controls, > L2 calls vmfunc with an invalid function number or calls it > with an invalid field from the eptp list > > Signed-off-by: Bandan Das <bsd@xxxxxxxxxx> > --- > lib/x86/msr.h | 1 + > x86/vmx.h | 8 +++- > x86/vmx_tests.c | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 154 insertions(+), 1 deletion(-) > > diff --git a/lib/x86/msr.h b/lib/x86/msr.h > index 2c0598c..41f75d9 100644 > --- a/lib/x86/msr.h > +++ b/lib/x86/msr.h > @@ -400,6 +400,7 @@ > #define MSR_IA32_VMX_TRUE_PROC 0x0000048e > #define MSR_IA32_VMX_TRUE_EXIT 0x0000048f > #define MSR_IA32_VMX_TRUE_ENTRY 0x00000490 > +#define MSR_IA32_VMX_VMFUNC 0x00000491 > > #define MSR_IA32_TSCDEADLINE 0x000006e0 > > diff --git a/x86/vmx.h b/x86/vmx.h > index d12b9de..b424674 100644 > --- a/x86/vmx.h > +++ b/x86/vmx.h > @@ -138,11 +138,14 @@ enum Encoding { > TSC_OFFSET_HI = 0x2011ul, > APIC_VIRT_ADDR = 0x2012ul, > APIC_ACCS_ADDR = 0x2014ul, > + VMFUNC_CTRL = 0x2018ul, > + VMFUNC_CTRL_HI = 0x2019ul, > EPTP = 0x201aul, > EPTP_HI = 0x201bul, > PMLADDR = 0x200eul, > PMLADDR_HI = 0x200ful, > - > + EPTP_LIST_ADDR = 0x2024ul, > + EPTP_LIST_ADDR_HI = 0x2025ul, > > /* 64-Bit Readonly Data Field */ > INFO_PHYS_ADDR = 0x2400ul, > @@ -394,6 +397,7 @@ enum Ctrl1 { > CPU_URG = 1ul << 7, > CPU_WBINVD = 1ul << 6, > CPU_RDRAND = 1ul << 11, > + CPU_VMFUNC = 1ul << 13, > CPU_PML = 1ul << 17, > }; > > @@ -405,6 +409,8 @@ enum Intr_type { > VMX_INTR_TYPE_SOFT_EXCEPTION = 6, > }; > > +#define EPTP_SWITCHING 0x1 > + > /* > * Interruption-information format > */ > diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c > index 2522d3a..01c58cc 100644 > --- a/x86/vmx_tests.c > +++ b/x86/vmx_tests.c > @@ -29,6 +29,9 @@ void *data_page1, *data_page2; > void *pml_log; > #define PML_INDEX 512 > > +void *vpage, *hpage1, *hpage2; > +void *eptp_list; > + > static inline unsigned ffs(unsigned x) > { > int pos = -1; > @@ -1332,6 +1335,148 @@ static int eptad_init() > return r; > } > > +static int vmfunc_init() > +{ > + eptp_list = alloc_page(); > + u64 *buf = eptp_list; > + > + vpage = alloc_page(); > + hpage1 = alloc_page(); > + hpage2 = alloc_page(); > + > + *((u32 *)vpage) = 0x1; > + *((u32 *)hpage1) = 0x2; > + *((u32 *)hpage2) = 0x3; > + > + ept_init_common(false); > + buf[0] = (u64)pml4; > + install_ept(pml4, (unsigned long)hpage1, (unsigned long)vpage, > + EPT_RA | EPT_WA | EPT_EA); > + > + ept_init_common(false); > + buf[1] = (u64)pml4; > + install_ept(pml4, (unsigned long)hpage2, (unsigned long)vpage, > + EPT_RA | EPT_WA | EPT_EA); > + > + if (!(ctrl_cpu_rev[1].clr & CPU_VMFUNC)) { > + printf("\tVMFUNC is not supported"); > + return VMX_TEST_EXIT; > + } > + > + return VMX_TEST_START; > +} > + > +static void vmfunc_ud_handler(struct ex_regs *regs) > +{ > + switch(vmx_get_test_stage()) { > + case 0: > + case 3: > + regs->rip += 3; > + vmx_inc_test_stage(); > + vmx_inc_test_stage(); > + break; > + default: > + printf("Unexpected #UD hit!\n"); > + print_vmexit_info(); > + exit(0); > + } > +} > + > +static void vmfunc_main() > +{ > + int nr = 0, ept = 0; > + > + handle_exception(UD_VECTOR, vmfunc_ud_handler); > + vmx_set_test_stage(0); > + > + /* Call vmfunc when L1 hasn't enabled it' */ > + asm volatile("vmfunc" > + : > + : "a"(nr), "c"(ept) > + : "memory"); > + > + report("VMFUNC - Disabled VMFUNC in sec controls causes #UD", > + vmx_get_test_stage() == 2); > + > + vmcall(); > + /* function > 64 causes #UD */ > + nr = 64; > + asm volatile("vmfunc" > + : > + : "a"(nr), "c"(ept) > + : "memory"); > + report("VMFUNC - guest call with EAX > 63 causes #UD", > + vmx_get_test_stage() == 5); > + > + /* invalid vm function causes vmexit */ > + nr = 1; > + asm volatile("vmfunc" > + : > + : "a"(nr), "c"(ept) > + : "memory"); > + report("VMFUNC - guest call with non-existant function", > + vmx_get_test_stage() == 6); > + > + /* invalid entry from the eptp list causes vmexit */ > + nr = 0; > + ept = 512; > + asm volatile("vmfunc" > + : > + : "a"(nr), "c"(ept) > + : "memory"); > + report("VMFUNC - guest call with invalid entry in eptp list", > + vmx_get_test_stage() == 7); > + > + /* > + * vpage points to hpage2 with value 0x3 > + * vmfunc with ecx = 0 should make vpage > + * point to 0x2 > + */ > + if (*((u32 *)vpage) != 0x3) { > + printf("Guest address points to unexpected page\n"); > + exit(0); > + } > + ept = 0; > + asm volatile("vmfunc" > + : > + : "a"(nr), "c"(ept) > + : "memory"); > + report("VMFUNC - call to switch ept pointer without an exit", > + (vmx_get_test_stage() == 7) && (*((u32 *)vpage) == 0x2)); > +} > + > +static int vmfunc_exit_handler(void) > +{ > + ulong reason = vmcs_read(EXI_REASON) & 0xff; > + u64 guest_rip = vmcs_read(GUEST_RIP); > + u32 insn_len = vmcs_read(EXI_INST_LEN); > + u32 ctrl_cpu; > + u64 controls; > + > + switch (reason) { > + case VMX_VMCALL: > + ctrl_cpu = vmcs_read(CPU_EXEC_CTRL1) | CPU_VMFUNC; > + vmcs_write(CPU_EXEC_CTRL1, ctrl_cpu); > + > + controls = rdmsr(MSR_IA32_VMX_VMFUNC) & 1; > + if (!(controls & EPTP_SWITCHING)) { > + printf("\tEPTP switching is not supported"); > + return VMX_TEST_EXIT; > + } > + > + vmcs_write(EPTP_LIST_ADDR, (u64)eptp_list); > + vmcs_write(VMFUNC_CTRL, controls); > + case VMX_VMFUNC: > + vmx_inc_test_stage(); > + vmcs_write(GUEST_RIP, guest_rip + insn_len); > + return VMX_TEST_RESUME; > + default: > + report("Unknown exit reason, %ld", false, reason); > + print_vmexit_info(); > + } > + return VMX_TEST_VMEXIT; > +} > + > static int pml_init() > { > u32 ctrl_cpu; > @@ -3173,6 +3318,7 @@ struct vmx_test vmx_tests[] = { > disable_rdtscp_exit_handler, NULL, {0} }, > { "int3", int3_init, int3_guest_main, int3_exit_handler, NULL, {0} }, > { "into", into_init, into_guest_main, into_exit_handler, NULL, {0} }, > + { "vmfunc", vmfunc_init, vmfunc_main, vmfunc_exit_handler, NULL, {0} }, > { "exit_monitor_from_l2_test", NULL, exit_monitor_from_l2_main, > exit_monitor_from_l2_handler, NULL, {0} }, > /* Basic V2 tests. */ > Reviewed-by: Paolo Bonzini <pbonzini@xxxxxxxxxx>