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@xxxxxxxxxx> --- x86/vmx.h | 8 ++++- x86/vmx_tests.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 1 deletion(-) diff --git a/x86/vmx.h b/x86/vmx.h index 290e6bd..087eb0c 100644 --- a/x86/vmx.h +++ b/x86/vmx.h @@ -108,6 +108,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, @@ -132,6 +133,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, @@ -317,7 +321,8 @@ enum Reason { VMX_PREEMPT = 52, VMX_INVVPID = 53, VMX_WBINVD = 54, - VMX_XSETBV = 55 + VMX_XSETBV = 55, + VMX_PMLFULL = 62, }; enum Ctrl_exi { @@ -375,6 +380,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 eca7fbd..8f4ad05 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"); @@ -1090,6 +1093,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_PMLFULL: + 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; @@ -1249,6 +1298,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(); @@ -1902,6 +1994,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} }, -- 2.9.3