On 10/03/20 04:54, Sean Christopherson wrote: > Track the last known CR0, CR4, and EFER values in the access test to > avoid taking a VM-Exit on every. single. test. The EFER VM-Exits in > particular absolutely tank performance when running the test in L1. > > Opportunistically tweak the 5-level test to print that it's starting > before configuring 5-level page tables, e.g. in case enabling 5-level > paging runs into issues. > > No functional change intended. > > Signed-off-by: Sean Christopherson <sean.j.christopherson@xxxxxxxxx> > --- > x86/access.c | 45 +++++++++++++++++++++++++++------------------ > 1 file changed, 27 insertions(+), 18 deletions(-) > > diff --git a/x86/access.c b/x86/access.c > index 7303fc3..86d8a72 100644 > --- a/x86/access.c > +++ b/x86/access.c > @@ -169,29 +169,33 @@ typedef struct { > > static void ac_test_show(ac_test_t *at); > > +static unsigned long shadow_cr0; > +static unsigned long shadow_cr4; > +static unsigned long long shadow_efer; > + > static void set_cr0_wp(int wp) > { > - unsigned long cr0 = read_cr0(); > - unsigned long old_cr0 = cr0; > + unsigned long cr0 = shadow_cr0; > > cr0 &= ~CR0_WP_MASK; > if (wp) > cr0 |= CR0_WP_MASK; > - if (old_cr0 != cr0) > + if (cr0 != shadow_cr0) { > write_cr0(cr0); > + shadow_cr0 = cr0; > + } > } > > static unsigned set_cr4_smep(int smep) > { > - unsigned long cr4 = read_cr4(); > - unsigned long old_cr4 = cr4; > + unsigned long cr4 = shadow_cr4; > extern u64 ptl2[]; > unsigned r; > > cr4 &= ~CR4_SMEP_MASK; > if (smep) > cr4 |= CR4_SMEP_MASK; > - if (old_cr4 == cr4) > + if (cr4 == shadow_cr4) > return 0; > > if (smep) > @@ -199,37 +203,39 @@ static unsigned set_cr4_smep(int smep) > r = write_cr4_checking(cr4); > if (r || !smep) > ptl2[2] |= PT_USER_MASK; > + if (!r) > + shadow_cr4 = cr4; > return r; > } > > static void set_cr4_pke(int pke) > { > - unsigned long cr4 = read_cr4(); > - unsigned long old_cr4 = cr4; > + unsigned long cr4 = shadow_cr4; > > cr4 &= ~X86_CR4_PKE; > if (pke) > cr4 |= X86_CR4_PKE; > - if (old_cr4 == cr4) > + if (cr4 == shadow_cr4) > return; > > /* Check that protection keys do not affect accesses when CR4.PKE=0. */ > - if ((read_cr4() & X86_CR4_PKE) && !pke) { > + if ((shadow_cr4 & X86_CR4_PKE) && !pke) > write_pkru(0xfffffffc); > - } > write_cr4(cr4); > + shadow_cr4 = cr4; > } > > static void set_efer_nx(int nx) > { > - unsigned long long efer = rdmsr(MSR_EFER); > - unsigned long long old_efer = efer; > + unsigned long long efer = shadow_efer; > > efer &= ~EFER_NX_MASK; > if (nx) > efer |= EFER_NX_MASK; > - if (old_efer != efer) > + if (efer != shadow_efer) { > wrmsr(MSR_EFER, efer); > + shadow_efer = efer; > + } > } > > static void ac_env_int(ac_pool_t *pool) > @@ -245,7 +251,7 @@ static void ac_env_int(ac_pool_t *pool) > > static void ac_test_init(ac_test_t *at, void *virt) > { > - wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NX_MASK); > + set_efer_nx(1); > set_cr0_wp(1); > at->flags = 0; > at->virt = virt; > @@ -935,14 +941,17 @@ static int ac_test_run(void) > printf("run\n"); > tests = successes = 0; > > + shadow_cr0 = read_cr0(); > + shadow_cr4 = read_cr4(); > + shadow_efer = rdmsr(MSR_EFER); > + > if (this_cpu_has(X86_FEATURE_PKU)) { > set_cr4_pke(1); > set_cr4_pke(0); > /* Now PKRU = 0xFFFFFFFF. */ > } else { > - unsigned long cr4 = read_cr4(); > tests++; > - if (write_cr4_checking(cr4 | X86_CR4_PKE) == GP_VECTOR) { > + if (write_cr4_checking(shadow_cr4 | X86_CR4_PKE) == GP_VECTOR) { > successes++; > invalid_mask |= AC_PKU_AD_MASK; > invalid_mask |= AC_PKU_WD_MASK; > @@ -996,8 +1005,8 @@ int main(void) > > if (this_cpu_has(X86_FEATURE_LA57)) { > page_table_levels = 5; > - setup_5level_page_table(); > printf("starting 5-level paging test.\n\n"); > + setup_5level_page_table(); > r = ac_test_run(); > } > > Applied all three patches, thanks. Paolo