diff options
author | Bandan Das <bsd@redhat.com> | 2017-05-05 15:29:23 -0400 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2017-05-11 13:14:00 +0200 |
commit | 195177318f161fb28d1d303a32a2fb65d31829ab (patch) | |
tree | 9f9ef52a8fe367751e234c35e26fa6dc3128a76b | |
parent | 73055fa926ce314f110414c41163ba255a738ffe (diff) | |
download | kvm-unit-tests-next-fixed.tar.gz |
vmx_tests: Add Page Modification Logging testsnext-fixed
Verify that a gpa is logged in the pml buffer when
it's written to. Also verify that when the PML buffer
overflows, a PML FULL event occurs.
Signed-off-by: Bandan Das <bsd@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r-- | x86/unittests.cfg | 6 | ||||
-rw-r--r-- | x86/vmx.h | 5 | ||||
-rw-r--r-- | x86/vmx_tests.c | 93 |
3 files changed, 104 insertions, 0 deletions
diff --git a/x86/unittests.cfg b/x86/unittests.cfg index 09b2252..5ab4667 100644 --- a/x86/unittests.cfg +++ b/x86/unittests.cfg @@ -308,6 +308,12 @@ extra_params = -cpu host,+vmx -append EPT_A/D_disabled arch = x86_64 groups = vmx +[vmx_PML] +file = vmx.flat +extra_params = -cpu host,+vmx -append PML +arch = x86_64 +groups = vmx + [vmx_VPID] file = vmx.flat extra_params = -cpu host,+vmx -append VPID @@ -110,6 +110,7 @@ enum Encoding { GUEST_SEL_LDTR = 0x080cul, GUEST_SEL_TR = 0x080eul, GUEST_INT_STATUS = 0x0810ul, + GUEST_PML_INDEX = 0x0812ul, /* 16-Bit Host State Fields */ HOST_SEL_ES = 0x0c00ul, @@ -134,6 +135,9 @@ enum Encoding { APIC_ACCS_ADDR = 0x2014ul, EPTP = 0x201aul, EPTP_HI = 0x201bul, + PMLADDR = 0x200eul, + PMLADDR_HI = 0x200ful, + /* 64-Bit Readonly Data Field */ INFO_PHYS_ADDR = 0x2400ul, @@ -385,6 +389,7 @@ enum Ctrl1 { CPU_URG = 1ul << 7, CPU_WBINVD = 1ul << 6, CPU_RDRAND = 1ul << 11, + CPU_PML = 1ul << 17, }; enum Intr_type { diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c index 197d57b..03e4ad4 100644 --- a/x86/vmx_tests.c +++ b/x86/vmx_tests.c @@ -22,6 +22,9 @@ unsigned long *pml4; u64 eptp; void *data_page1, *data_page2; +void *pml_log; +#define PML_INDEX 512 + static inline void vmcall() { asm volatile("vmcall"); @@ -1110,6 +1113,52 @@ bool invept_test(int type, u64 eptp) return true; } +static int pml_exit_handler(void) +{ + u16 index, count; + ulong reason = vmcs_read(EXI_REASON) & 0xff; + u64 *pmlbuf = pml_log; + u64 guest_rip = vmcs_read(GUEST_RIP);; + u64 guest_cr3 = vmcs_read(GUEST_CR3); + u32 insn_len = vmcs_read(EXI_INST_LEN); + + switch (reason) { + case VMX_VMCALL: + switch (vmx_get_test_stage()) { + case 0: + index = vmcs_read(GUEST_PML_INDEX); + for (count = index + 1; count < PML_INDEX; count++) { + if (pmlbuf[count] == (u64)data_page2) { + vmx_inc_test_stage(); + clear_ept_ad(pml4, guest_cr3, (unsigned long)data_page2); + break; + } + } + break; + case 1: + index = vmcs_read(GUEST_PML_INDEX); + /* Keep clearing the dirty bit till a overflow */ + clear_ept_ad(pml4, guest_cr3, (unsigned long)data_page2); + break; + default: + printf("ERROR - unexpected stage, %d.\n", + vmx_get_test_stage()); + print_vmexit_info(); + return VMX_TEST_VMEXIT; + } + vmcs_write(GUEST_RIP, guest_rip + insn_len); + return VMX_TEST_RESUME; + case VMX_PML_FULL: + vmx_inc_test_stage(); + vmcs_write(GUEST_PML_INDEX, PML_INDEX - 1); + return VMX_TEST_RESUME; + default: + printf("Unknown exit reason, %ld\n", reason); + print_vmexit_info(); + } + return VMX_TEST_VMEXIT; +} + static int ept_exit_handler_common(bool have_ad) { u64 guest_rip; @@ -1269,6 +1318,49 @@ static int eptad_init() return r; } +static int pml_init() +{ + u32 ctrl_cpu; + int r = eptad_init(); + + if (r == VMX_TEST_EXIT) + return r; + + if (!(ctrl_cpu_rev[0].clr & CPU_SECONDARY) || + !(ctrl_cpu_rev[1].clr & CPU_PML)) { + printf("\tPML is not supported"); + return VMX_TEST_EXIT; + } + + pml_log = alloc_page(); + memset(pml_log, 0x0, PAGE_SIZE); + vmcs_write(PMLADDR, (u64)pml_log); + vmcs_write(GUEST_PML_INDEX, PML_INDEX - 1); + + ctrl_cpu = vmcs_read(CPU_EXEC_CTRL1) | CPU_PML; + vmcs_write(CPU_EXEC_CTRL1, ctrl_cpu); + + return VMX_TEST_START; +} + +static void pml_main() +{ + int count = 0; + + vmx_set_test_stage(0); + *((u32 *)data_page2) = 0x1; + vmcall(); + report("PML - Dirty GPA Logging", vmx_get_test_stage() == 1); + + while (vmx_get_test_stage() == 1) { + *((u32 *)data_page2) = 0x1; + if (count++ > PML_INDEX) + break; + vmcall(); + } + report("PML Full Event", vmx_get_test_stage() == 2); +} + static void eptad_main() { ept_common(); @@ -2844,6 +2936,7 @@ struct vmx_test vmx_tests[] = { insn_intercept_exit_handler, NULL, {0} }, { "EPT A/D disabled", ept_init, ept_main, ept_exit_handler, NULL, {0} }, { "EPT A/D enabled", eptad_init, eptad_main, eptad_exit_handler, NULL, {0} }, + { "PML", pml_init, pml_main, pml_exit_handler, NULL, {0} }, { "VPID", vpid_init, vpid_main, vpid_exit_handler, NULL, {0} }, { "interrupt", interrupt_init, interrupt_main, interrupt_exit_handler, NULL, {0} }, |