Modify the test helper, ept_access_paddr(), to test the correctness of the L1's EPT AD bits when enabled. After a successful guest access, assert that the accessed bit (bit 8) has been set on all EPT entries which were used in the translation of the guest-physical address. Since ept_access_paddr() tests an EPT mapping that backs a guest paging structure, processor accesses are treated as writes and the dirty bit (bit 9) is set accordingly. Assert that the dirty bit is set on the leaf EPT entry. Signed-off-by: Oliver Upton <oupton@xxxxxxxxxx> --- x86/vmx_tests.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c index a456bd1..325dde7 100644 --- a/x86/vmx_tests.c +++ b/x86/vmx_tests.c @@ -1135,6 +1135,11 @@ static void ept_disable_ad_bits(void) vmcs_write(EPTP, eptp); } +static int ept_ad_enabled(void) +{ + return eptp & EPTP_AD_FLAG; +} + static void ept_enable_ad_bits_or_skip_test(void) { if (!ept_ad_bits_supported()) @@ -2500,6 +2505,8 @@ static void ept_access_paddr(unsigned long ept_access, unsigned long pte_ad, unsigned long *ptep; unsigned long gpa; unsigned long orig_epte; + unsigned long epte; + int i; /* Modify the guest PTE mapping data->gva according to @pte_ad. */ ptep = get_pte_level(current_page_table(), data->gva, /*level=*/1); @@ -2536,6 +2543,17 @@ static void ept_access_paddr(unsigned long ept_access, unsigned long pte_ad, do_ept_access_op(op); } else { do_ept_access_op(op); + if (ept_ad_enabled()) { + for (i = EPT_PAGE_LEVEL; i > 0; i--) { + TEST_ASSERT(get_ept_pte(pml4, gpa, i, &epte)); + TEST_ASSERT(epte & EPT_ACCESS_FLAG); + if (i == 1) + TEST_ASSERT(epte & EPT_DIRTY_FLAG); + else + TEST_ASSERT_EQ(epte & EPT_DIRTY_FLAG, 0); + } + } + ept_untwiddle(gpa, /*level=*/1, orig_epte); } -- 2.24.0.432.g9d3f5f5b63-goog