diff options
author | Sean Christopherson <sean.j.christopherson@intel.com> | 2020-03-09 20:54:32 -0700 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2020-03-31 11:15:31 -0400 |
commit | 3c7dfedb65484f05156eb452ce5eb2afc14f1b68 (patch) | |
tree | aab84d8be23cfdc518311a85951d86a98353d055 | |
parent | 41692a119aa03780fab3c376080f602a7e4ad16b (diff) | |
download | kvm-unit-tests-3c7dfedb65484f05156eb452ce5eb2afc14f1b68.tar.gz |
x86: access: Shadow CR0, CR4 and EFER to avoid unnecessary VM-Exits
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@intel.com>
Message-Id: <20200310035432.3447-1-sean.j.christopherson@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r-- | x86/access.c | 45 |
1 files 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(); } |