Re: [kvm-unit-tests PATCH] x86: nSVM: Add test for EPT A/D bits

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Aug 20, 2025 at 12:29 PM Kevin Cheng <chengkev@xxxxxxxxxx> wrote:
>
> The nVMX tests already have coverage for TDP A/D bits. Add a
> similar test for nSVM to improve test parity between nSVM and nVMX.
>
> Signed-off-by: Kevin Cheng <chengkev@xxxxxxxxxx>
> ---
>  x86/svm.c     | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  x86/svm.h     |  5 +++
>  x86/svm_npt.c | 46 +++++++++++++++++++++++++
>  3 files changed, 144 insertions(+)
>
> diff --git a/x86/svm.c b/x86/svm.c
> index e715e270..53b78d16 100644
> --- a/x86/svm.c
> +++ b/x86/svm.c
> @@ -14,6 +14,8 @@
>  #include "isr.h"
>  #include "apic.h"
>
> +#include <asm/page.h>
> +
>  /* for the nested page table*/
>  u64 *pml4e;
>
> @@ -43,6 +45,97 @@ u64 *npt_get_pml4e(void)
>         return pml4e;
>  }
>
> +void clear_npt_ad(unsigned long *pml4e, u64 guest_cr3,
> +                 unsigned long guest_addr)
> +{
> +       int l;
> +       unsigned long *pt = (unsigned long *)guest_cr3, gpa;
> +       u64 *npt_pte, pte, offset_in_page;
> +       unsigned offset;
> +
> +       for (l = PAGE_LEVEL; ; --l) {
> +               offset = PGDIR_OFFSET(guest_addr, l);
> +               npt_pte = npt_get_pte((u64) &pt[offset]);
> +
> +               if(!npt_pte) {
> +                       printf("NPT - guest level %d page table is not mapped.\n", l);
> +                       return;
> +               }
> +
> +               *npt_pte &= ~(PT_AD_MASK);
> +
> +               pte = pt[offset];
> +               if (l == 1 || (l < 4 && (pte & PT_PAGE_SIZE_MASK)))
> +                       break;
> +               if (!(pte & PT_PRESENT_MASK))
> +                       return;
> +               pt = (unsigned long *)(pte & PT_ADDR_MASK);
> +       }
> +
> +       offset = PGDIR_OFFSET(guest_addr, l);
> +       offset_in_page = guest_addr &  ((1 << PGDIR_BITS(l)) - 1);
> +       gpa = (pt[offset] & PT_ADDR_MASK) | (guest_addr & offset_in_page);
> +       npt_pte = npt_get_pte(gpa);
> +       *npt_pte &= ~(PT_AD_MASK);
> +}
> +
> +void check_npt_ad(unsigned long *pml4e, u64 guest_cr3,
> +       unsigned long guest_addr, int expected_gpa_ad,
> +       int expected_pt_ad)
> +{
> +       int l;
> +       unsigned long *pt = (unsigned long *)guest_cr3, gpa;
> +       u64 *npt_pte, pte, offset_in_page;
> +       unsigned offset;
> +       bool bad_pt_ad = false;
> +
> +       for (l = PAGE_LEVEL; ; --l) {
> +               offset = PGDIR_OFFSET(guest_addr, l);
> +               npt_pte = npt_get_pte((u64) &pt[offset]);
> +
> +               if(!npt_pte) {
> +                       printf("NPT - guest level %d page table is not mapped.\n", l);
> +                       return;
> +               }
> +
> +               if (!bad_pt_ad) {
> +                       bad_pt_ad |= (*npt_pte & PT_AD_MASK) != expected_pt_ad;
> +                       if(bad_pt_ad)
> +                               report_fail("NPT - received guest level %d page table A=%d/D=%d",
> +                                           l,
> +                                           !!(expected_pt_ad & PT_ACCESSED_MASK),
> +                                           !!(expected_pt_ad & PT_DIRTY_MASK));
> +               }
> +
> +               pte = pt[offset];
> +               if (l == 1 || (l < 4 && (pte & PT_PAGE_SIZE_MASK)))
> +                       break;
> +               if (!(pte & PT_PRESENT_MASK))
> +                       return;
> +               pt = (unsigned long *)(pte & PT_ADDR_MASK);
> +       }
> +
> +       if (!bad_pt_ad)
> +               report_pass("NPT - guest page table structures A=%d/D=%d",
> +                           !!(expected_pt_ad & PT_ACCESSED_MASK),
> +                           !!(expected_pt_ad & PT_DIRTY_MASK));
> +
> +       offset = PGDIR_OFFSET(guest_addr, l);
> +       offset_in_page = guest_addr &  ((1 << PGDIR_BITS(l)) - 1);
> +       gpa = (pt[offset] & PT_ADDR_MASK) | (guest_addr & offset_in_page);
> +
> +       npt_pte = npt_get_pte(gpa);
> +
> +       if (!npt_pte) {
> +               report_fail("NPT - guest physical address is not mapped");
> +               return;
> +       }
> +       report((*npt_pte & PT_AD_MASK) == expected_gpa_ad,
> +              "NPT - guest physical address A=%d/D=%d",
> +              !!(expected_gpa_ad & PT_ACCESSED_MASK),
> +              !!(expected_gpa_ad & PT_DIRTY_MASK));
> +}
> +
>  bool smp_supported(void)
>  {
>         return cpu_count() > 1;
> diff --git a/x86/svm.h b/x86/svm.h
> index c1dd84af..1a83d778 100644
> --- a/x86/svm.h
> +++ b/x86/svm.h
> @@ -415,6 +415,11 @@ u64 *npt_get_pte(u64 address);
>  u64 *npt_get_pde(u64 address);
>  u64 *npt_get_pdpe(u64 address);
>  u64 *npt_get_pml4e(void);
> +void clear_npt_ad(unsigned long *pml4e, u64 guest_cr3,
> +                 unsigned long guest_addr);
> +void check_npt_ad(unsigned long *pml4e, u64 guest_cr3,
> +                 unsigned long guest_addr, int expected_gpa_ad,
> +                 int expected_pt_ad);
>  bool smp_supported(void);
>  bool default_supported(void);
>  bool vgif_supported(void);
> diff --git a/x86/svm_npt.c b/x86/svm_npt.c
> index bd5e8f35..abf44eb0 100644
> --- a/x86/svm_npt.c
> +++ b/x86/svm_npt.c
> @@ -380,6 +380,51 @@ skip_pte_test:
>         vmcb->save.cr4 = sg_cr4;
>  }
>
> +static void npt_ad_read_guest(struct svm_test *test)
> +{
> +       u64 *data = (void *)(0x80000);
> +       (void)*(volatile u64 *)data;
> +}
> +
> +static void npt_ad_write_guest(struct svm_test *test)
> +{
> +       u64 *data = (void *)(0x80000);
> +       *data = 0;
> +}
> +
> +static void npt_ad_test(void)
> +{
> +       u64 *data = (void *)(0x80000);
> +       u64 guest_cr3 = vmcb->save.cr3;
> +
> +       if (!npt_supported()) {
> +               report_skip("NPT not supported");
> +               return;
> +       }
> +
> +       clear_npt_ad(npt_get_pml4e(), guest_cr3, (unsigned long)data);
> +
> +       check_npt_ad(npt_get_pml4e(), guest_cr3, (unsigned long)data, 0, 0);
> +
> +       test_set_guest(npt_ad_read_guest);
> +       svm_vmrun();
> +
> +       check_npt_ad(npt_get_pml4e(), guest_cr3,
> +                    (unsigned long)data,
> +                    PT_ACCESSED_MASK,
> +                    PT_AD_MASK);
> +
> +       test_set_guest(npt_ad_write_guest);
> +       svm_vmrun();
> +
> +       check_npt_ad(npt_get_pml4e(), guest_cr3,
> +                    (unsigned long)data,
> +                    PT_AD_MASK,
> +                    PT_AD_MASK);
> +
> +       clear_npt_ad(npt_get_pml4e(), guest_cr3, (unsigned long)data);
> +}
> +
>  #define NPT_V1_TEST(name, prepare, guest_code, check)                          \
>         { #name, npt_supported, prepare, default_prepare_gif_clear, guest_code, \
>           default_finished, check }
> @@ -395,6 +440,7 @@ static struct svm_test npt_tests[] = {
>         NPT_V1_TEST(npt_l1mmio, npt_l1mmio_prepare, npt_l1mmio_test, npt_l1mmio_check),
>         NPT_V1_TEST(npt_rw_l1mmio, npt_rw_l1mmio_prepare, npt_rw_l1mmio_test, npt_rw_l1mmio_check),
>         NPT_V2_TEST(svm_npt_rsvd_bits_test),
> +       NPT_V2_TEST(npt_ad_test),
>         { NULL, NULL, NULL, NULL, NULL, NULL, NULL }
>  };
>
> --
> 2.51.0.261.g7ce5a0a67e-goog
>

Just checking in as it's been a couple weeks :) If there is anyone
else who would be better suited to take a look at these please let me
know and I can cc them as well!





[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux