[kvm-unit-tests PATCH] x86: access: Shadow CR0, CR4 and EFER to avoid unnecessary VM-Exits

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

 



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();
     }
 
-- 
2.24.1




[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