ia64/xen-unstable

changeset 16012:ff4ff3e3ebbe

hvm: Clean up EFER handling. Check CR0/CR4/EFER on HVM restore.
Signed-off-by: Keir Fraser <keir@xensource.com>
author Keir Fraser <keir@xensource.com>
date Fri Sep 28 16:00:44 2007 +0100 (2007-09-28)
parents 96f46954c7f1
children f34cc7d1f2f6
files xen/arch/x86/hvm/hvm.c xen/arch/x86/hvm/svm/svm.c xen/arch/x86/hvm/vmx/vmx.c xen/include/asm-x86/hvm/support.h
line diff
     1.1 --- a/xen/arch/x86/hvm/hvm.c	Fri Sep 28 15:05:11 2007 +0100
     1.2 +++ b/xen/arch/x86/hvm/hvm.c	Fri Sep 28 16:00:44 2007 +0100
     1.3 @@ -337,6 +337,34 @@ static int hvm_load_cpu_ctxt(struct doma
     1.4      if ( hvm_load_entry(CPU, h, &ctxt) != 0 ) 
     1.5          return -EINVAL;
     1.6  
     1.7 +    /* Sanity check some control registers. */
     1.8 +    if ( (ctxt.cr0 & HVM_CR0_GUEST_RESERVED_BITS) ||
     1.9 +         !(ctxt.cr0 & X86_CR0_ET) ||
    1.10 +         ((ctxt.cr0 & (X86_CR0_PE|X86_CR0_PG)) == X86_CR0_PG) )
    1.11 +    {
    1.12 +        gdprintk(XENLOG_ERR, "HVM restore: bad CR0 0x%"PRIx64"\n",
    1.13 +                 ctxt.msr_efer);
    1.14 +        return -EINVAL;
    1.15 +    }
    1.16 +
    1.17 +    if ( ctxt.cr4 & HVM_CR4_GUEST_RESERVED_BITS )
    1.18 +    {
    1.19 +        gdprintk(XENLOG_ERR, "HVM restore: bad CR4 0x%"PRIx64"\n",
    1.20 +                 ctxt.msr_efer);
    1.21 +        return -EINVAL;
    1.22 +    }
    1.23 +
    1.24 +    if ( (ctxt.msr_efer & ~(EFER_LME | EFER_NX | EFER_SCE)) ||
    1.25 +         ((sizeof(long) != 8) && (ctxt.msr_efer & EFER_LME)) ||
    1.26 +         (!cpu_has_nx && (ctxt.msr_efer & EFER_NX)) ||
    1.27 +         (!cpu_has_syscall && (ctxt.msr_efer & EFER_SCE)) ||
    1.28 +         ((ctxt.msr_efer & (EFER_LME|EFER_LMA)) == EFER_LMA) )
    1.29 +    {
    1.30 +        gdprintk(XENLOG_ERR, "HVM restore: bad EFER 0x%"PRIx64"\n",
    1.31 +                 ctxt.msr_efer);
    1.32 +        return -EINVAL;
    1.33 +    }
    1.34 +
    1.35      /* Architecture-specific vmcs/vmcb bits */
    1.36      if ( hvm_funcs.load_cpu_ctxt(v, &ctxt) < 0 )
    1.37          return -EINVAL;
    1.38 @@ -532,6 +560,39 @@ void hvm_triple_fault(void)
    1.39      domain_shutdown(v->domain, SHUTDOWN_reboot);
    1.40  }
    1.41  
    1.42 +int hvm_set_efer(uint64_t value)
    1.43 +{
    1.44 +    struct vcpu *v = current;
    1.45 +
    1.46 +    value &= ~EFER_LMA;
    1.47 +
    1.48 +    if ( (value & ~(EFER_LME | EFER_NX | EFER_SCE)) ||
    1.49 +         ((sizeof(long) != 8) && (value & EFER_LME)) ||
    1.50 +         (!cpu_has_nx && (value & EFER_NX)) ||
    1.51 +         (!cpu_has_syscall && (value & EFER_SCE)) )
    1.52 +    {
    1.53 +        gdprintk(XENLOG_WARNING, "Trying to set reserved bit in "
    1.54 +                 "EFER: %"PRIx64"\n", value);
    1.55 +        hvm_inject_exception(TRAP_gp_fault, 0, 0);
    1.56 +        return 0;
    1.57 +    }
    1.58 +
    1.59 +    if ( ((value ^ v->arch.hvm_vcpu.guest_efer) & EFER_LME) &&
    1.60 +         hvm_paging_enabled(v) )
    1.61 +    {
    1.62 +        gdprintk(XENLOG_WARNING,
    1.63 +                 "Trying to change EFER.LME with paging enabled\n");
    1.64 +        hvm_inject_exception(TRAP_gp_fault, 0, 0);
    1.65 +        return 0;
    1.66 +    }
    1.67 +
    1.68 +    value |= v->arch.hvm_vcpu.guest_efer & EFER_LMA;
    1.69 +    v->arch.hvm_vcpu.guest_efer = value;
    1.70 +    hvm_update_guest_efer(v);
    1.71 +
    1.72 +    return 1;
    1.73 +}
    1.74 +
    1.75  int hvm_set_cr0(unsigned long value)
    1.76  {
    1.77      struct vcpu *v = current;
     2.1 --- a/xen/arch/x86/hvm/svm/svm.c	Fri Sep 28 15:05:11 2007 +0100
     2.2 +++ b/xen/arch/x86/hvm/svm/svm.c	Fri Sep 28 16:00:44 2007 +0100
     2.3 @@ -69,6 +69,8 @@ static void *hsa[NR_CPUS] __read_mostly;
     2.4  /* vmcb used for extended host state */
     2.5  static void *root_vmcb[NR_CPUS] __read_mostly;
     2.6  
     2.7 +static void svm_update_guest_efer(struct vcpu *v);
     2.8 +
     2.9  static void inline __update_guest_eip(
    2.10      struct cpu_user_regs *regs, int inst_len) 
    2.11  {
    2.12 @@ -103,22 +105,10 @@ static void svm_cpu_down(void)
    2.13      write_efer(read_efer() & ~EFER_SVME);
    2.14  }
    2.15  
    2.16 -static int svm_lme_is_set(struct vcpu *v)
    2.17 -{
    2.18 -#ifdef __x86_64__
    2.19 -    u64 guest_efer = v->arch.hvm_vcpu.guest_efer;
    2.20 -    return guest_efer & EFER_LME;
    2.21 -#else
    2.22 -    return 0;
    2.23 -#endif
    2.24 -}
    2.25 -
    2.26  static enum handler_return long_mode_do_msr_write(struct cpu_user_regs *regs)
    2.27  {
    2.28      u64 msr_content = (u32)regs->eax | ((u64)regs->edx << 32);
    2.29      u32 ecx = regs->ecx;
    2.30 -    struct vcpu *v = current;
    2.31 -    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
    2.32  
    2.33      HVM_DBG_LOG(DBG_LEVEL_0, "msr %x msr_content %"PRIx64,
    2.34                  ecx, msr_content);
    2.35 @@ -126,47 +116,8 @@ static enum handler_return long_mode_do_
    2.36      switch ( ecx )
    2.37      {
    2.38      case MSR_EFER:
    2.39 -        /* Offending reserved bit will cause #GP. */
    2.40 -#ifdef __x86_64__
    2.41 -        if ( (msr_content & ~(EFER_LME | EFER_LMA | EFER_NX | EFER_SCE)) ||
    2.42 -#else
    2.43 -        if ( (msr_content & ~(EFER_NX | EFER_SCE)) ||
    2.44 -#endif
    2.45 -             (!cpu_has_nx && (msr_content & EFER_NX)) ||
    2.46 -             (!cpu_has_syscall && (msr_content & EFER_SCE)) )
    2.47 -        {
    2.48 -            gdprintk(XENLOG_WARNING, "Trying to set reserved bit in "
    2.49 -                     "EFER: %"PRIx64"\n", msr_content);
    2.50 -            goto gp_fault;
    2.51 -        }
    2.52 -
    2.53 -        if ( (msr_content & EFER_LME) && !svm_lme_is_set(v) )
    2.54 -        {
    2.55 -            /* EFER.LME transition from 0 to 1. */
    2.56 -            if ( hvm_paging_enabled(v) ||
    2.57 -                 !(v->arch.hvm_vcpu.guest_cr[4] & X86_CR4_PAE) )
    2.58 -            {
    2.59 -                gdprintk(XENLOG_WARNING, "Trying to set LME bit when "
    2.60 -                         "in paging mode or PAE bit is not set\n");
    2.61 -                goto gp_fault;
    2.62 -            }
    2.63 -        }
    2.64 -        else if ( !(msr_content & EFER_LME) && svm_lme_is_set(v) )
    2.65 -        {
    2.66 -            /* EFER.LME transistion from 1 to 0. */
    2.67 -            if ( hvm_paging_enabled(v) )
    2.68 -            {
    2.69 -                gdprintk(XENLOG_WARNING, 
    2.70 -                         "Trying to clear EFER.LME while paging enabled\n");
    2.71 -                goto gp_fault;
    2.72 -            }
    2.73 -        }
    2.74 -
    2.75 -        v->arch.hvm_vcpu.guest_efer = msr_content;
    2.76 -        vmcb->efer = msr_content | EFER_SVME;
    2.77 -        if ( !hvm_paging_enabled(v) )
    2.78 -            vmcb->efer &= ~(EFER_LME | EFER_LMA);
    2.79 -
    2.80 +        if ( !hvm_set_efer(msr_content) )
    2.81 +            return HNDL_exception_raised;
    2.82          break;
    2.83  
    2.84      case MSR_K8_MC4_MISC: /* Threshold register */
    2.85 @@ -182,10 +133,6 @@ static enum handler_return long_mode_do_
    2.86      }
    2.87  
    2.88      return HNDL_done;
    2.89 -
    2.90 - gp_fault:
    2.91 -    svm_inject_exception(v, TRAP_gp_fault, 1, 0);
    2.92 -    return HNDL_exception_raised;
    2.93  }
    2.94  
    2.95  
    2.96 @@ -449,11 +396,7 @@ static void svm_load_cpu_state(struct vc
    2.97      vmcb->cstar      = data->msr_cstar;
    2.98      vmcb->sfmask     = data->msr_syscall_mask;
    2.99      v->arch.hvm_vcpu.guest_efer = data->msr_efer;
   2.100 -    vmcb->efer       = data->msr_efer | EFER_SVME;
   2.101 -    /* VMCB's EFER.LME isn't set unless we're actually in long mode
   2.102 -     * (see long_mode_do_msr_write()) */
   2.103 -    if ( !(vmcb->efer & EFER_LMA) )
   2.104 -        vmcb->efer &= ~EFER_LME;
   2.105 +    svm_update_guest_efer(v);
   2.106  
   2.107      hvm_set_guest_time(v, data->tsc);
   2.108  }
   2.109 @@ -543,14 +486,11 @@ static void svm_update_guest_cr(struct v
   2.110  
   2.111  static void svm_update_guest_efer(struct vcpu *v)
   2.112  {
   2.113 -#ifdef __x86_64__
   2.114      struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
   2.115  
   2.116 -    if ( v->arch.hvm_vcpu.guest_efer & EFER_LMA )
   2.117 -        vmcb->efer |= EFER_LME | EFER_LMA;
   2.118 -    else
   2.119 -        vmcb->efer &= ~(EFER_LME | EFER_LMA);
   2.120 -#endif
   2.121 +    vmcb->efer = (v->arch.hvm_vcpu.guest_efer | EFER_SVME) & ~EFER_LME;
   2.122 +    if ( vmcb->efer & EFER_LMA )
   2.123 +        vmcb->efer |= EFER_LME;
   2.124  }
   2.125  
   2.126  static void svm_flush_guest_tlbs(void)
     3.1 --- a/xen/arch/x86/hvm/vmx/vmx.c	Fri Sep 28 15:05:11 2007 +0100
     3.2 +++ b/xen/arch/x86/hvm/vmx/vmx.c	Fri Sep 28 16:00:44 2007 +0100
     3.3 @@ -199,42 +199,8 @@ static enum handler_return long_mode_do_
     3.4      switch ( ecx )
     3.5      {
     3.6      case MSR_EFER:
     3.7 -        /* offending reserved bit will cause #GP */
     3.8 -        if ( (msr_content & ~(EFER_LME | EFER_LMA | EFER_NX | EFER_SCE)) ||
     3.9 -             (!cpu_has_nx && (msr_content & EFER_NX)) ||
    3.10 -             (!cpu_has_syscall && (msr_content & EFER_SCE)) )
    3.11 -        {
    3.12 -            gdprintk(XENLOG_WARNING, "Trying to set reserved bit in "
    3.13 -                     "EFER: %"PRIx64"\n", msr_content);
    3.14 -            goto gp_fault;
    3.15 -        }
    3.16 -
    3.17 -        if ( (msr_content & EFER_LME)
    3.18 -             &&  !(v->arch.hvm_vcpu.guest_efer & EFER_LME) )
    3.19 -        {
    3.20 -            if ( unlikely(hvm_paging_enabled(v)) )
    3.21 -            {
    3.22 -                gdprintk(XENLOG_WARNING,
    3.23 -                         "Trying to set EFER.LME with paging enabled\n");
    3.24 -                goto gp_fault;
    3.25 -            }
    3.26 -        }
    3.27 -        else if ( !(msr_content & EFER_LME)
    3.28 -                  && (v->arch.hvm_vcpu.guest_efer & EFER_LME) )
    3.29 -        {
    3.30 -            if ( unlikely(hvm_paging_enabled(v)) )
    3.31 -            {
    3.32 -                gdprintk(XENLOG_WARNING,
    3.33 -                         "Trying to clear EFER.LME with paging enabled\n");
    3.34 -                goto gp_fault;
    3.35 -            }
    3.36 -        }
    3.37 -
    3.38 -        if ( (msr_content ^ v->arch.hvm_vcpu.guest_efer) & (EFER_NX|EFER_SCE) )
    3.39 -            write_efer((read_efer() & ~(EFER_NX|EFER_SCE)) |
    3.40 -                       (msr_content & (EFER_NX|EFER_SCE)));
    3.41 -
    3.42 -        v->arch.hvm_vcpu.guest_efer = msr_content;
    3.43 +        if ( !hvm_set_efer(msr_content) )
    3.44 +            goto exception_raised;
    3.45          break;
    3.46  
    3.47      case MSR_FS_BASE:
    3.48 @@ -285,6 +251,7 @@ static enum handler_return long_mode_do_
    3.49      HVM_DBG_LOG(DBG_LEVEL_0, "Not cano address of msr write %x", ecx);
    3.50   gp_fault:
    3.51      vmx_inject_hw_exception(v, TRAP_gp_fault, 0);
    3.52 + exception_raised:
    3.53      return HNDL_exception_raised;
    3.54  }
    3.55  
    3.56 @@ -380,7 +347,8 @@ static enum handler_return long_mode_do_
    3.57      u64 msr_content = 0;
    3.58      struct vcpu *v = current;
    3.59  
    3.60 -    switch ( regs->ecx ) {
    3.61 +    switch ( regs->ecx )
    3.62 +    {
    3.63      case MSR_EFER:
    3.64          msr_content = v->arch.hvm_vcpu.guest_efer;
    3.65          break;
    3.66 @@ -398,25 +366,12 @@ static enum handler_return long_mode_do_
    3.67  static enum handler_return long_mode_do_msr_write(struct cpu_user_regs *regs)
    3.68  {
    3.69      u64 msr_content = regs->eax | ((u64)regs->edx << 32);
    3.70 -    struct vcpu *v = current;
    3.71  
    3.72      switch ( regs->ecx )
    3.73      {
    3.74      case MSR_EFER:
    3.75 -        /* offending reserved bit will cause #GP */
    3.76 -        if ( (msr_content & ~EFER_NX) ||
    3.77 -             (!cpu_has_nx && (msr_content & EFER_NX)) )
    3.78 -        {
    3.79 -            gdprintk(XENLOG_WARNING, "Trying to set reserved bit in "
    3.80 -                     "EFER: %"PRIx64"\n", msr_content);
    3.81 -            vmx_inject_hw_exception(v, TRAP_gp_fault, 0);
    3.82 +        if ( !hvm_set_efer(msr_content) )
    3.83              return HNDL_exception_raised;
    3.84 -        }
    3.85 -
    3.86 -        if ( (msr_content ^ v->arch.hvm_vcpu.guest_efer) & EFER_NX )
    3.87 -            write_efer((read_efer() & ~EFER_NX) | (msr_content & EFER_NX));
    3.88 -
    3.89 -        v->arch.hvm_vcpu.guest_efer = msr_content;
    3.90          break;
    3.91  
    3.92      default:
    3.93 @@ -1096,6 +1051,10 @@ static void vmx_update_guest_efer(struct
    3.94  
    3.95      vmx_vmcs_exit(v);
    3.96  #endif
    3.97 +
    3.98 +    if ( v == current )
    3.99 +        write_efer((read_efer() & ~(EFER_NX|EFER_SCE)) |
   3.100 +                   (v->arch.hvm_vcpu.guest_efer & (EFER_NX|EFER_SCE)));
   3.101  }
   3.102  
   3.103  static void vmx_flush_guest_tlbs(void)
     4.1 --- a/xen/include/asm-x86/hvm/support.h	Fri Sep 28 15:05:11 2007 +0100
     4.2 +++ b/xen/include/asm-x86/hvm/support.h	Fri Sep 28 16:00:44 2007 +0100
     4.3 @@ -234,6 +234,7 @@ int hvm_do_hypercall(struct cpu_user_reg
     4.4  void hvm_hlt(unsigned long rflags);
     4.5  void hvm_triple_fault(void);
     4.6  
     4.7 +int hvm_set_efer(uint64_t value);
     4.8  int hvm_set_cr0(unsigned long value);
     4.9  int hvm_set_cr3(unsigned long value);
    4.10  int hvm_set_cr4(unsigned long value);