Re: [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]

 



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




[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