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

Re: [Xen-devel] [PATCH 4/4] SVM: clean up svm_vmcb_isvalid()



On 31/05/17 08:23, Jan Beulich wrote:
> - correct CR3 and CR4 checks
> - add vcpu parameter (to include in log messages) and constify vmcb one
> - use bool/true/false
> - use accessors
> - adjust formatting
>
> Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
>
> --- a/xen/arch/x86/hvm/svm/nestedsvm.c
> +++ b/xen/arch/x86/hvm/svm/nestedsvm.c
> @@ -658,13 +658,13 @@ static int nsvm_vmcb_prepare4vmrun(struc
>      /* Cleanbits */
>      n2vmcb->cleanbits.bytes = 0;
>  
> -    rc = svm_vmcb_isvalid(__func__, ns_vmcb, 1);
> +    rc = svm_vmcb_isvalid(__func__, ns_vmcb, v, true);
>      if (rc) {
>          gdprintk(XENLOG_ERR, "virtual vmcb invalid\n");
>          return NSVM_ERROR_VVMCB;
>      }
>  
> -    rc = svm_vmcb_isvalid(__func__, n2vmcb, 1);
> +    rc = svm_vmcb_isvalid(__func__, n2vmcb, v, true);

As these are the only two callsites, I don't think the __func__ or
verbose parameters are useful.  I'd just drop them.

>      if (rc) {
>          gdprintk(XENLOG_ERR, "n2vmcb invalid\n");
>          return NSVM_ERROR_VMENTRY;
> --- a/xen/arch/x86/hvm/svm/svmdebug.c
> +++ b/xen/arch/x86/hvm/svm/svmdebug.c
> @@ -16,6 +16,7 @@
>   *
>   */
>  
> +#include <xen/sched.h>
>  #include <asm/processor.h>
>  #include <asm/msr-index.h>
>  #include <asm/hvm/svm/svmdebug.h>
> @@ -87,93 +88,76 @@ void svm_vmcb_dump(const char *from, con
>      svm_dump_sel("  TR", &vmcb->tr);
>  }
>  
> -bool_t
> -svm_vmcb_isvalid(const char *from, struct vmcb_struct *vmcb,
> -                 bool_t verbose)
> +bool svm_vmcb_isvalid(const char *from, const struct vmcb_struct *vmcb,
> +                      const struct vcpu *v, bool verbose)
>  {
> -    bool_t ret = 0; /* ok */
> +    bool ret = false; /* ok */
>  
> -#define PRINTF(...) \
> -    if (verbose) { ret = 1; printk("%s: ", from); printk(__VA_ARGS__); \
> -    } else return 1;
> +#define PRINTF(fmt, args...) do { \
> +    if ( !verbose ) return true; \
> +    ret = true; \
> +    printk(XENLOG_GUEST "%pv[%s]: " fmt, v, from, ## args); \
> +} while (0)
>  
> -    if ((vmcb->_efer & EFER_SVME) == 0) {
> -        PRINTF("EFER: SVME bit not set (%#"PRIx64")\n", vmcb->_efer);
> -    }
> +    if ( !(vmcb_get_efer(vmcb) & EFER_SVME) )
> +        PRINTF("EFER: SVME bit not set (%#"PRIx64")\n", vmcb_get_efer(vmcb));
>  
> -    if ((vmcb->_cr0 & X86_CR0_CD) == 0 && (vmcb->_cr0 & X86_CR0_NW) != 0) {
> +    if ( !(vmcb_get_cr0(vmcb) & X86_CR0_CD) && (vmcb_get_cr0(vmcb) & 
> X86_CR0_NW) )
>          PRINTF("CR0: CD bit is zero and NW bit set (%#"PRIx64")\n",
> -                vmcb->_cr0);
> -    }
> +                vmcb_get_cr0(vmcb));
>  
> -    if ((vmcb->_cr0 >> 32U) != 0) {
> +    if ( vmcb_get_cr0(vmcb) >> 32 )
>          PRINTF("CR0: bits [63:32] are not zero (%#"PRIx64")\n",
> -                vmcb->_cr0);
> -    }
> +                vmcb_get_cr0(vmcb));
>  
> -    if ((vmcb->_cr3 & 0x7) != 0) {
> -        PRINTF("CR3: MBZ bits are set (%#"PRIx64")\n", vmcb->_cr3);
> -    }
> -    if ((vmcb->_efer & EFER_LMA) && (vmcb->_cr3 & 0xfe) != 0) {
> -        PRINTF("CR3: MBZ bits are set (%#"PRIx64")\n", vmcb->_cr3);
> -    }
> +    if ( (vmcb_get_cr3(vmcb) & 0x7) ||
> +         ((!(vmcb_get_cr4(vmcb) & X86_CR4_PAE) ||
> +           (vmcb_get_efer(vmcb) & EFER_LMA)) &&
> +          (vmcb_get_cr3(vmcb) & 0xfe0)) ||
> +         ((vmcb_get_efer(vmcb) & EFER_LMA) &&
> +          (vmcb_get_cr3(vmcb) >> v->domain->arch.cpuid->extd.maxphysaddr)) )
> +        PRINTF("CR3: MBZ bits are set (%#"PRIx64")\n", vmcb_get_cr3(vmcb));

Is any of this correct if CR0.PG is clear?  It was my understanding that
outside of paged mode, all bits are software available.

This is certainly the behaviour of hvm_set_cr3() (which itself has
further knock-on bugs resulting in vmentry failures, due to insufficient
CR3 checks when enabling CR0.PG)

>  
> -    if ((vmcb->_cr4 >> 19U) != 0) {
> -        PRINTF("CR4: bits [63:19] are not zero (%#"PRIx64")\n",
> -                vmcb->_cr4);
> -    }
> -
> -    if (((vmcb->_cr4 >> 11U) & 0x7fU) != 0) {
> -        PRINTF("CR4: bits [17:11] are not zero (%#"PRIx64")\n",
> -                vmcb->_cr4);
> -    }
> +    if ( vmcb_get_cr4(vmcb) & ~hvm_cr4_guest_valid_bits(v, false) )
> +        PRINTF("CR4: MBZ bits are set (%#"PRIx64")\n", vmcb_get_cr4(vmcb));

This isn't quite MBZ bits.  It also includes bits disallowed by the
chosen CPUID policy.  I'd suggest "CR4: Invalid bits are set
(%#"PRIx64", valid: %#"PRIx64")\n" and print both values.

>  
> -    if ((vmcb->_dr6 >> 32U) != 0) {
> +    if ( vmcb_get_dr6(vmcb) >> 32 )
>          PRINTF("DR6: bits [63:32] are not zero (%#"PRIx64")\n",
> -                vmcb->_dr6);
> -    }
> +                vmcb_get_dr6(vmcb));
>  
> -    if ((vmcb->_dr7 >> 32U) != 0) {
> +    if ( vmcb_get_dr7(vmcb) >> 32 )
>          PRINTF("DR7: bits [63:32] are not zero (%#"PRIx64")\n",
> -                vmcb->_dr7);
> -    }
> +                vmcb_get_dr7(vmcb));
>  
> -    if ((vmcb->_efer >> 15U) != 0) {
> +    if ( vmcb_get_efer(vmcb) >> 15U )
>          PRINTF("EFER: bits [63:15] are not zero (%#"PRIx64")\n",
> -                vmcb->_efer);
> -    }

I don't see any justification for this particular check (even before
your modification).  The manual states "Any MBZ bit of EFER is set", so
I'd recommend using hvm_efer_valid() here, which also subsumes some of
the other checks.

> -
> -    if ((vmcb->_efer & EFER_LME) != 0 && ((vmcb->_cr0 & X86_CR0_PG) != 0)) {
> -        if ((vmcb->_cr4 & X86_CR4_PAE) == 0) {
> -            PRINTF("EFER_LME and CR0.PG are both set and CR4.PAE is 
> zero.\n");
> -        }
> -        if ((vmcb->_cr0 & X86_CR0_PE) == 0) {
> -            PRINTF("EFER_LME and CR0.PG are both set and CR0.PE is zero.\n");
> -        }
> -    }
> +                vmcb_get_efer(vmcb));
>  
> -    if ((vmcb->_efer & EFER_LME) != 0
> -        && (vmcb->_cr0 & X86_CR0_PG) != 0
> -        && (vmcb->_cr4 & X86_CR4_PAE) != 0
> -        && (vmcb->cs.attr.fields.l != 0)
> -        && (vmcb->cs.attr.fields.db != 0))
> +    if ( (vmcb_get_efer(vmcb) & EFER_LME) && (vmcb_get_cr0(vmcb) & 
> X86_CR0_PG) )
>      {
> -        PRINTF("EFER_LME, CR0.PG, CR4.PAE, CS.L and CS.D are all 
> non-zero.\n");
> +        if ( !(vmcb_get_cr4(vmcb) & X86_CR4_PAE) )
> +            PRINTF("EFER_LME and CR0.PG are both set and CR4.PAE is zero\n");
> +        if ( !(vmcb_get_cr0(vmcb) & X86_CR0_PE) )
> +            PRINTF("EFER_LME and CR0.PG are both set and CR0.PE is zero\n");
>      }
>  
> -    if ((vmcb->_general2_intercepts & GENERAL2_INTERCEPT_VMRUN) == 0) {
> +    if ( (vmcb_get_efer(vmcb) & EFER_LME) &&
> +         (vmcb_get_cr0(vmcb) & X86_CR0_PG) &&
> +         (vmcb_get_cr4(vmcb) & X86_CR4_PAE) &&
> +         vmcb->cs.attr.fields.l &&
> +         vmcb->cs.attr.fields.db )
> +        PRINTF("EFER_LME, CR0.PG, CR4.PAE, CS.L and CS.D are all 
> non-zero\n");
> +
> +    if ( !(vmcb_get_general2_intercepts(vmcb) & GENERAL2_INTERCEPT_VMRUN) )
>          PRINTF("GENERAL2_INTERCEPT: VMRUN intercept bit is clear 
> (%#"PRIx32")\n",
> -            vmcb->_general2_intercepts);
> -    }
> +            vmcb_get_general2_intercepts(vmcb));
>  
> -    if (vmcb->eventinj.fields.resvd1 != 0) {
> +    if ( vmcb->eventinj.fields.resvd1 )
>          PRINTF("eventinj: MBZ bits are set (%#"PRIx64")\n",
>                  vmcb->eventinj.bytes);
> -    }
>  
> -    if (vmcb->_np_enable && vmcb->_h_cr3 == 0) {
> +    if ( vmcb_get_np_enable(vmcb) && !vmcb_get_h_cr3(vmcb) )
>          PRINTF("nested paging enabled but host cr3 is 0\n");

I also can't see anything in the manual about this being invalid.

The only relevant restriction I can spot is nested paging is not
permitted if host paging is disabled.  A host cr3 value of 0 can
legitimately be used for paging suitable PTEs are written into mfn0.

~Andrew

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.