Il 09/09/2013 06:57, Arthur Chunqi Li ha scritto: > Some test cases for nested EPT features, including: > 1. EPT basic framework tests: read, write and remap. > 2. EPT misconfigurations test cases: page permission mieconfiguration > and memory type misconfiguration > 3. EPT violations test cases: page permission violation and paging > structure violation > > Signed-off-by: Arthur Chunqi Li <yzt356@xxxxxxxxx> > --- > x86/vmx_tests.c | 266 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 266 insertions(+) > > diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c > index c1b39f4..a0b9824 100644 > --- a/x86/vmx_tests.c > +++ b/x86/vmx_tests.c > @@ -1,4 +1,36 @@ > #include "vmx.h" > +#include "processor.h" > +#include "vm.h" > +#include "msr.h" > +#include "fwcfg.h" > + > +volatile u32 stage; > +volatile bool init_fail; Why volatile? The patch looks good. > +unsigned long *pml4; > +u64 eptp; > +void *data_page1, *data_page2; > + > +static inline void set_stage(u32 s) > +{ > + barrier(); > + stage = s; > + barrier(); > +} > + > +static inline u32 get_stage() > +{ > + u32 s; > + > + barrier(); > + s = stage; > + barrier(); > + return s; > +} > + > +static inline void vmcall() > +{ > + asm volatile ("vmcall"); > +} > > void basic_init() > { > @@ -76,6 +108,238 @@ int vmenter_exit_handler() > return VMX_TEST_VMEXIT; > } > > +static int setup_ept() > +{ > + int support_2m; > + unsigned long end_of_memory; > + > + if (!(ept_vpid.val & EPT_CAP_UC) && > + !(ept_vpid.val & EPT_CAP_WB)) { > + printf("\tEPT paging-structure memory type " > + "UC&WB are not supported\n"); > + return 1; > + } > + if (ept_vpid.val & EPT_CAP_UC) > + eptp = EPT_MEM_TYPE_UC; > + else > + eptp = EPT_MEM_TYPE_WB; > + if (!(ept_vpid.val & EPT_CAP_PWL4)) { > + printf("\tPWL4 is not supported\n"); > + return 1; > + } > + eptp |= (3 << EPTP_PG_WALK_LEN_SHIFT); > + pml4 = alloc_page(); > + memset(pml4, 0, PAGE_SIZE); > + eptp |= virt_to_phys(pml4); > + vmcs_write(EPTP, eptp); > + support_2m = !!(ept_vpid.val & EPT_CAP_2M_PAGE); > + end_of_memory = fwcfg_get_u64(FW_CFG_RAM_SIZE); > + if (end_of_memory < (1ul << 32)) > + end_of_memory = (1ul << 32); > + if (setup_ept_range(pml4, 0, end_of_memory, > + 0, support_2m, EPT_WA | EPT_RA | EPT_EA)) { > + printf("\tSet ept tables failed.\n"); > + return 1; > + } > + return 0; > +} > + > +static void ept_init() > +{ > + u32 ctrl_cpu[2]; > + > + init_fail = false; > + ctrl_cpu[0] = vmcs_read(CPU_EXEC_CTRL0); > + ctrl_cpu[1] = vmcs_read(CPU_EXEC_CTRL1); > + ctrl_cpu[0] = (ctrl_cpu[0] | CPU_SECONDARY) > + & ctrl_cpu_rev[0].clr; > + ctrl_cpu[1] = (ctrl_cpu[1] | CPU_EPT) > + & ctrl_cpu_rev[1].clr; > + vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu[0]); > + vmcs_write(CPU_EXEC_CTRL1, ctrl_cpu[1] | CPU_EPT); > + if (setup_ept()) > + init_fail = true; > + data_page1 = alloc_page(); > + data_page2 = alloc_page(); > + memset(data_page1, 0x0, PAGE_SIZE); > + memset(data_page2, 0x0, PAGE_SIZE); > + *((u32 *)data_page1) = MAGIC_VAL_1; > + *((u32 *)data_page2) = MAGIC_VAL_2; > + install_ept(pml4, (unsigned long)data_page1, (unsigned long)data_page2, > + EPT_RA | EPT_WA | EPT_EA); > +} > + > +static void ept_main() > +{ > + if (init_fail) > + return; > + if (!(ctrl_cpu_rev[0].clr & CPU_SECONDARY) > + && !(ctrl_cpu_rev[1].clr & CPU_EPT)) { > + printf("\tEPT is not supported"); > + return; > + } > + set_stage(0); > + if (*((u32 *)data_page2) != MAGIC_VAL_1 && > + *((u32 *)data_page1) != MAGIC_VAL_1) > + report("EPT basic framework - read", 0); > + else { > + *((u32 *)data_page2) = MAGIC_VAL_3; > + vmcall(); > + if (get_stage() == 1) { > + if (*((u32 *)data_page1) == MAGIC_VAL_3 && > + *((u32 *)data_page2) == MAGIC_VAL_2) > + report("EPT basic framework", 1); > + else > + report("EPT basic framework - remap", 1); > + } > + } > + // Test EPT Misconfigurations > + set_stage(1); > + vmcall(); > + *((u32 *)data_page1) = MAGIC_VAL_1; > + if (get_stage() != 2) { > + report("EPT misconfigurations", 0); > + goto t1; > + } > + set_stage(2); > + vmcall(); > + *((u32 *)data_page1) = MAGIC_VAL_1; > + if (get_stage() != 3) { > + report("EPT misconfigurations", 0); > + goto t1; > + } > + report("EPT misconfigurations", 1); > +t1: > + // Test EPT violation > + set_stage(3); > + vmcall(); > + *((u32 *)data_page1) = MAGIC_VAL_1; > + if (get_stage() == 4) > + report("EPT violation - page permission", 1); > + else > + report("EPT violation - page permission", 0); > + // Violation caused by EPT paging structure > + set_stage(4); > + vmcall(); > + *((u32 *)data_page1) = MAGIC_VAL_2; > + if (get_stage() == 5) > + report("EPT violation - paging structure", 1); > + else > + report("EPT violation - paging structure", 0); > + return; > +} > + > +static int ept_exit_handler() > +{ > + u64 guest_rip; > + ulong reason; > + u32 insn_len; > + u32 exit_qual; > + static unsigned long data_page1_pte, data_page1_pte_pte; > + > + guest_rip = vmcs_read(GUEST_RIP); > + reason = vmcs_read(EXI_REASON) & 0xff; > + insn_len = vmcs_read(EXI_INST_LEN); > + exit_qual = vmcs_read(EXI_QUALIFICATION); > + switch (reason) { > + case VMX_VMCALL: > + switch (get_stage()) { > + case 0: > + if (*((u32 *)data_page1) == MAGIC_VAL_3 && > + *((u32 *)data_page2) == MAGIC_VAL_2) { > + set_stage(get_stage() + 1); > + install_ept(pml4, (unsigned long)data_page2, > + (unsigned long)data_page2, > + EPT_RA | EPT_WA | EPT_EA); > + } else > + report("EPT basic framework - write\n", 0); > + break; > + case 1: > + install_ept(pml4, (unsigned long)data_page1, > + (unsigned long)data_page1, EPT_WA); > + invept(INVEPT_SINGLE, eptp); > + break; > + case 2: > + install_ept(pml4, (unsigned long)data_page1, > + (unsigned long)data_page1, > + EPT_RA | EPT_WA | EPT_EA | > + (2 << EPT_MEM_TYPE_SHIFT)); > + invept(INVEPT_SINGLE, eptp); > + break; > + case 3: > + data_page1_pte = get_ept_pte(pml4, > + (unsigned long)data_page1, 1); > + set_ept_pte(pml4, (unsigned long)data_page1, > + 1, data_page1_pte & (~EPT_PRESENT)); > + invept(INVEPT_SINGLE, eptp); > + break; > + case 4: > + data_page1_pte = get_ept_pte(pml4, > + (unsigned long)data_page1, 2); > + data_page1_pte &= PAGE_MASK; > + data_page1_pte_pte = get_ept_pte(pml4, data_page1_pte, 2); > + set_ept_pte(pml4, data_page1_pte, 2, > + data_page1_pte_pte & (~EPT_PRESENT)); > + invept(INVEPT_SINGLE, eptp); > + break; > + // Should not reach here > + default: > + printf("ERROR - unknown stage, %d.\n", get_stage()); > + print_vmexit_info(); > + return VMX_TEST_VMEXIT; > + } > + vmcs_write(GUEST_RIP, guest_rip + insn_len); > + return VMX_TEST_RESUME; > + case VMX_EPT_MISCONFIG: > + switch (get_stage()) { > + case 1: > + case 2: > + set_stage(get_stage() + 1); > + install_ept(pml4, (unsigned long)data_page1, > + (unsigned long)data_page1, > + EPT_RA | EPT_WA | EPT_EA); > + invept(INVEPT_SINGLE, eptp); > + break; > + // Should not reach here > + default: > + printf("ERROR - unknown stage, %d.\n", get_stage()); > + print_vmexit_info(); > + return VMX_TEST_VMEXIT; > + } > + vmcs_write(GUEST_RIP, guest_rip + insn_len); > + return VMX_TEST_RESUME; > + case VMX_EPT_VIOLATION: > + switch(get_stage()) { > + case 3: > + if (exit_qual == (EPT_VLT_WR | EPT_VLT_LADDR_VLD | > + EPT_VLT_PADDR)) > + set_stage(get_stage() + 1); > + set_ept_pte(pml4, (unsigned long)data_page1, > + 1, data_page1_pte | (EPT_PRESENT)); > + invept(INVEPT_SINGLE, eptp); > + break; > + case 4: > + if (exit_qual == (EPT_VLT_RD | EPT_VLT_LADDR_VLD)) > + set_stage(get_stage() + 1); > + set_ept_pte(pml4, data_page1_pte, 2, > + data_page1_pte_pte | (EPT_PRESENT)); > + invept(INVEPT_SINGLE, eptp); > + break; > + default: > + // Should not reach here > + printf("ERROR : unknown stage, %d\n", get_stage()); > + print_vmexit_info(); > + return VMX_TEST_VMEXIT; > + } > + vmcs_write(GUEST_RIP, guest_rip + insn_len); > + return VMX_TEST_RESUME; > + default: > + printf("Unknown exit reason, %d\n", reason); > + print_vmexit_info(); > + } > + return VMX_TEST_VMEXIT; > +} > + > /* name/init/guest_main/exit_handler/syscall_handler/guest_regs > basic_* just implement some basic functions */ > struct vmx_test vmx_tests[] = { > @@ -83,5 +347,7 @@ struct vmx_test vmx_tests[] = { > basic_syscall_handler, {0} }, > { "vmenter", basic_init, vmenter_main, vmenter_exit_handler, > basic_syscall_handler, {0} }, > + { "EPT framework", ept_init, ept_main, ept_exit_handler, > + basic_syscall_handler, {0} }, > { NULL, NULL, NULL, NULL, NULL, {0} }, > }; > -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html