aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Christopherson <sean.j.christopherson@intel.com>2020-03-09 20:54:32 -0700
committerPaolo Bonzini <pbonzini@redhat.com>2020-03-31 11:15:31 -0400
commit3c7dfedb65484f05156eb452ce5eb2afc14f1b68 (patch)
treeaab84d8be23cfdc518311a85951d86a98353d055
parent41692a119aa03780fab3c376080f602a7e4ad16b (diff)
downloadkvm-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.c45
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();
}