ia64/xen-unstable

changeset 15734:25e5c1b9faad

hvm: Unify %cr0 handling.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Wed Aug 08 16:09:17 2007 +0100 (2007-08-08)
parents 359707941ae8
children 9ef1c3e6c48e
files xen/arch/x86/hvm/hvm.c xen/arch/x86/hvm/svm/svm.c xen/arch/x86/hvm/svm/vmcb.c xen/arch/x86/hvm/vmx/vmx.c xen/include/asm-x86/hvm/hvm.h xen/include/asm-x86/hvm/support.h xen/include/asm-x86/hvm/vcpu.h
line diff
     1.1 --- a/xen/arch/x86/hvm/hvm.c	Wed Aug 08 15:03:40 2007 +0100
     1.2 +++ b/xen/arch/x86/hvm/hvm.c	Wed Aug 08 16:09:17 2007 +0100
     1.3 @@ -76,13 +76,6 @@ void hvm_enable(struct hvm_function_tabl
     1.4      hvm_enabled = 1;
     1.5  }
     1.6  
     1.7 -void hvm_stts(struct vcpu *v)
     1.8 -{
     1.9 -    /* FPU state already dirty? Then no need to setup_fpu() lazily. */
    1.10 -    if ( !v->fpu_dirtied )
    1.11 -        hvm_funcs.stts(v);
    1.12 -}
    1.13 -
    1.14  void hvm_set_guest_time(struct vcpu *v, u64 gtime)
    1.15  {
    1.16      u64 host_tsc;
    1.17 @@ -112,7 +105,8 @@ void hvm_do_resume(struct vcpu *v)
    1.18  {
    1.19      ioreq_t *p;
    1.20  
    1.21 -    hvm_stts(v);
    1.22 +    if ( !v->fpu_dirtied )
    1.23 +        hvm_funcs.stts(v);
    1.24  
    1.25      pt_thaw_time(v);
    1.26  
    1.27 @@ -520,6 +514,99 @@ void hvm_triple_fault(void)
    1.28      domain_shutdown(v->domain, SHUTDOWN_reboot);
    1.29  }
    1.30  
    1.31 +int hvm_set_cr0(unsigned long value)
    1.32 +{
    1.33 +    struct vcpu *v = current;
    1.34 +    unsigned long mfn, old_base_mfn, old_value = v->arch.hvm_vcpu.guest_cr[0];
    1.35 +  
    1.36 +    HVM_DBG_LOG(DBG_LEVEL_VMMU, "Update CR0 value = %lx", value);
    1.37 +
    1.38 +    if ( (u32)value != value )
    1.39 +    {
    1.40 +        HVM_DBG_LOG(DBG_LEVEL_1,
    1.41 +                    "Guest attempts to set upper 32 bits in CR0: %lx",
    1.42 +                    value);
    1.43 +        hvm_inject_exception(TRAP_gp_fault, 0, 0);
    1.44 +        return 0;
    1.45 +    }
    1.46 +
    1.47 +    value &= ~HVM_CR0_GUEST_RESERVED_BITS;
    1.48 +
    1.49 +    /* ET is reserved and should be always be 1. */
    1.50 +    value |= X86_CR0_ET;
    1.51 +
    1.52 +    if ( (value & (X86_CR0_PE|X86_CR0_PG)) == X86_CR0_PG )
    1.53 +    {
    1.54 +        hvm_inject_exception(TRAP_gp_fault, 0, 0);
    1.55 +        return 0;
    1.56 +    }
    1.57 +
    1.58 +    if ( (value & X86_CR0_PG) && !(old_value & X86_CR0_PG) )
    1.59 +    {
    1.60 +        if ( v->arch.hvm_vcpu.guest_efer & EFER_LME )
    1.61 +        {
    1.62 +            if ( !(v->arch.hvm_vcpu.guest_cr[4] & X86_CR4_PAE) )
    1.63 +            {
    1.64 +                HVM_DBG_LOG(DBG_LEVEL_1, "Enable paging before PAE enable");
    1.65 +                hvm_inject_exception(TRAP_gp_fault, 0, 0);
    1.66 +                return 0;
    1.67 +            }
    1.68 +            HVM_DBG_LOG(DBG_LEVEL_1, "Enabling long mode");
    1.69 +            v->arch.hvm_vcpu.guest_efer |= EFER_LMA;
    1.70 +            hvm_update_guest_efer(v);
    1.71 +        }
    1.72 +
    1.73 +        if ( !paging_mode_hap(v->domain) )
    1.74 +        {
    1.75 +            /* The guest CR3 must be pointing to the guest physical. */
    1.76 +            mfn = get_mfn_from_gpfn(v->arch.hvm_vcpu.guest_cr[3]>>PAGE_SHIFT);
    1.77 +            if ( !mfn_valid(mfn) || !get_page(mfn_to_page(mfn), v->domain))
    1.78 +            {
    1.79 +                gdprintk(XENLOG_ERR, "Invalid CR3 value = %lx (mfn=%lx)\n", 
    1.80 +                         v->arch.hvm_vcpu.guest_cr[3], mfn);
    1.81 +                domain_crash(v->domain);
    1.82 +                return 0;
    1.83 +            }
    1.84 +
    1.85 +            /* Now arch.guest_table points to machine physical. */
    1.86 +            old_base_mfn = pagetable_get_pfn(v->arch.guest_table);
    1.87 +            v->arch.guest_table = pagetable_from_pfn(mfn);
    1.88 +            if ( old_base_mfn )
    1.89 +                put_page(mfn_to_page(old_base_mfn));
    1.90 +
    1.91 +            HVM_DBG_LOG(DBG_LEVEL_VMMU, "Update CR3 value = %lx, mfn = %lx",
    1.92 +                        v->arch.hvm_vcpu.guest_cr[3], mfn);
    1.93 +        }
    1.94 +    }
    1.95 +    else if ( !(value & X86_CR0_PG) && (old_value & X86_CR0_PG) )
    1.96 +    {
    1.97 +        /* When CR0.PG is cleared, LMA is cleared immediately. */
    1.98 +        if ( hvm_long_mode_enabled(v) )
    1.99 +        {
   1.100 +            v->arch.hvm_vcpu.guest_efer &= ~EFER_LMA;
   1.101 +            hvm_update_guest_efer(v);
   1.102 +        }
   1.103 +
   1.104 +        if ( !paging_mode_hap(v->domain) && v->arch.hvm_vcpu.guest_cr[3] )
   1.105 +        {
   1.106 +            put_page(mfn_to_page(get_mfn_from_gpfn(
   1.107 +                v->arch.hvm_vcpu.guest_cr[3] >> PAGE_SHIFT)));
   1.108 +            v->arch.guest_table = pagetable_null();
   1.109 +        }
   1.110 +    }
   1.111 +
   1.112 +    v->arch.hvm_vcpu.guest_cr[0] = value;
   1.113 +    v->arch.hvm_vcpu.hw_cr[0] = value;
   1.114 +    if ( !paging_mode_hap(v->domain) )
   1.115 +        v->arch.hvm_vcpu.hw_cr[0] |= X86_CR0_PG | X86_CR0_WP;
   1.116 +    hvm_update_guest_cr(v, 0);
   1.117 +
   1.118 +    if ( (value ^ old_value) & X86_CR0_PG )
   1.119 +        paging_update_paging_modes(v);
   1.120 +
   1.121 +    return 1;
   1.122 +}
   1.123 +
   1.124  int hvm_set_cr3(unsigned long value)
   1.125  {
   1.126      unsigned long old_base_mfn, mfn;
     2.1 --- a/xen/arch/x86/hvm/svm/svm.c	Wed Aug 08 15:03:40 2007 +0100
     2.2 +++ b/xen/arch/x86/hvm/svm/svm.c	Wed Aug 08 16:09:17 2007 +0100
     2.3 @@ -344,7 +344,8 @@ int svm_vmcb_restore(struct vcpu *v, str
     2.4      vmcb->rflags = c->rflags;
     2.5  
     2.6      v->arch.hvm_vcpu.guest_cr[0] = c->cr0;
     2.7 -    vmcb->cr0 = c->cr0 | X86_CR0_WP | X86_CR0_ET | X86_CR0_PG;
     2.8 +    vmcb->cr0 = v->arch.hvm_vcpu.hw_cr[0] = 
     2.9 +        c->cr0 | X86_CR0_WP | X86_CR0_ET | X86_CR0_PG;
    2.10  
    2.11      v->arch.hvm_vcpu.guest_cr[2] = c->cr2;
    2.12  
    2.13 @@ -392,7 +393,7 @@ int svm_vmcb_restore(struct vcpu *v, str
    2.14      }
    2.15  
    2.16   skip_cr3:
    2.17 -    vmcb->cr4 = c->cr4 | HVM_CR4_HOST_MASK;
    2.18 +    vmcb->cr4 = v->arch.hvm_vcpu.hw_cr[4] = c->cr4 | HVM_CR4_HOST_MASK;
    2.19      v->arch.hvm_vcpu.guest_cr[4] = c->cr4;
    2.20      
    2.21      vmcb->idtr.limit = c->idtr_limit;
    2.22 @@ -448,10 +449,10 @@ int svm_vmcb_restore(struct vcpu *v, str
    2.23  
    2.24      if ( paging_mode_hap(v->domain) )
    2.25      {
    2.26 -        vmcb->cr0 = v->arch.hvm_vcpu.guest_cr[0];
    2.27 -        vmcb->cr4 = (v->arch.hvm_vcpu.guest_cr[4] |
    2.28 -                     (HVM_CR4_HOST_MASK & ~X86_CR4_PAE));
    2.29 -        vmcb->cr3 = c->cr3;
    2.30 +        vmcb->cr0 = v->arch.hvm_vcpu.hw_cr[0] = v->arch.hvm_vcpu.guest_cr[0];
    2.31 +        vmcb->cr4 = v->arch.hvm_vcpu.hw_cr[4] =
    2.32 +            v->arch.hvm_vcpu.guest_cr[4] | (HVM_CR4_HOST_MASK & ~X86_CR4_PAE);
    2.33 +        vmcb->cr3 = v->arch.hvm_vcpu.hw_cr[3] = c->cr3;
    2.34          vmcb->np_enable = 1;
    2.35          vmcb->g_pat = 0x0007040600070406ULL; /* guest PAT */
    2.36          vmcb->h_cr3 = pagetable_get_paddr(v->domain->arch.phys_table);
    2.37 @@ -580,20 +581,40 @@ static void svm_update_host_cr3(struct v
    2.38  
    2.39  static void svm_update_guest_cr(struct vcpu *v, unsigned int cr)
    2.40  {
    2.41 +    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
    2.42 +
    2.43      switch ( cr )
    2.44      {
    2.45 +    case 0:
    2.46 +        vmcb->cr0 = v->arch.hvm_vcpu.hw_cr[0];
    2.47 +        break;
    2.48 +    case 2:
    2.49 +        vmcb->cr2 = v->arch.hvm_vcpu.hw_cr[2];
    2.50 +        break;
    2.51      case 3:
    2.52 -        v->arch.hvm_svm.vmcb->cr3 = v->arch.hvm_vcpu.hw_cr[3];
    2.53 +        vmcb->cr3 = v->arch.hvm_vcpu.hw_cr[3];
    2.54          svm_asid_inv_asid(v);
    2.55          break;
    2.56      case 4:
    2.57 -        v->arch.hvm_svm.vmcb->cr4 = v->arch.hvm_vcpu.hw_cr[4];
    2.58 +        vmcb->cr4 = v->arch.hvm_vcpu.hw_cr[4];
    2.59          break;
    2.60      default:
    2.61          BUG();
    2.62      }
    2.63  }
    2.64  
    2.65 +static void svm_update_guest_efer(struct vcpu *v)
    2.66 +{
    2.67 +#ifdef __x86_64__
    2.68 +    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
    2.69 +
    2.70 +    if ( v->arch.hvm_vcpu.guest_efer & EFER_LMA )
    2.71 +        vmcb->efer |= EFER_LME | EFER_LMA;
    2.72 +    else
    2.73 +        vmcb->efer &= ~(EFER_LME | EFER_LMA);
    2.74 +#endif
    2.75 +}
    2.76 +
    2.77  static void svm_flush_guest_tlbs(void)
    2.78  {
    2.79      /* Roll over the CPU's ASID generation, so it gets a clean TLB when we
    2.80 @@ -703,7 +724,7 @@ static void svm_stts(struct vcpu *v)
    2.81      if ( !(v->arch.hvm_vcpu.guest_cr[0] & X86_CR0_TS) )
    2.82      {
    2.83          v->arch.hvm_svm.vmcb->exception_intercepts |= 1U << TRAP_no_device;
    2.84 -        vmcb->cr0 |= X86_CR0_TS;
    2.85 +        vmcb->cr0 = v->arch.hvm_vcpu.hw_cr[0] |= X86_CR0_TS;
    2.86      }
    2.87  }
    2.88  
    2.89 @@ -928,6 +949,7 @@ static struct hvm_function_table svm_fun
    2.90      .get_segment_register = svm_get_segment_register,
    2.91      .update_host_cr3      = svm_update_host_cr3,
    2.92      .update_guest_cr      = svm_update_guest_cr,
    2.93 +    .update_guest_efer    = svm_update_guest_efer,
    2.94      .flush_guest_tlbs     = svm_flush_guest_tlbs,
    2.95      .update_vtpr          = svm_update_vtpr,
    2.96      .stts                 = svm_stts,
    2.97 @@ -1023,7 +1045,7 @@ static void svm_do_no_device_fault(struc
    2.98      vmcb->exception_intercepts &= ~(1U << TRAP_no_device);
    2.99  
   2.100      if ( !(v->arch.hvm_vcpu.guest_cr[0] & X86_CR0_TS) )
   2.101 -        vmcb->cr0 &= ~X86_CR0_TS;
   2.102 +        vmcb->cr0 = v->arch.hvm_vcpu.hw_cr[0] &= ~X86_CR0_TS;
   2.103  }
   2.104  
   2.105  /* Reserved bits ECX: [31:14], [12:4], [2:1]*/
   2.106 @@ -1597,31 +1619,11 @@ static void svm_io_instruction(struct vc
   2.107  static int svm_set_cr0(unsigned long value)
   2.108  {
   2.109      struct vcpu *v = current;
   2.110 -    unsigned long mfn, old_value = v->arch.hvm_vcpu.guest_cr[0];
   2.111      struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
   2.112 -    unsigned long old_base_mfn;
   2.113 -  
   2.114 -    HVM_DBG_LOG(DBG_LEVEL_VMMU, "Update CR0 value = %lx", value);
   2.115 +    int rc = hvm_set_cr0(value);
   2.116  
   2.117 -    if ( (u32)value != value )
   2.118 -    {
   2.119 -        HVM_DBG_LOG(DBG_LEVEL_1,
   2.120 -                    "Guest attempts to set upper 32 bits in CR0: %lx",
   2.121 -                    value);
   2.122 -        svm_inject_exception(v, TRAP_gp_fault, 1, 0);
   2.123 +    if ( rc == 0 )
   2.124          return 0;
   2.125 -    }
   2.126 -
   2.127 -    value &= ~HVM_CR0_GUEST_RESERVED_BITS;
   2.128 -
   2.129 -    /* ET is reserved and should be always be 1. */
   2.130 -    value |= X86_CR0_ET;
   2.131 -
   2.132 -    if ( (value & (X86_CR0_PE|X86_CR0_PG)) == X86_CR0_PG )
   2.133 -    {
   2.134 -        svm_inject_exception(v, TRAP_gp_fault, 1, 0);
   2.135 -        return 0;
   2.136 -    }
   2.137  
   2.138      /* TS cleared? Then initialise FPU now. */
   2.139      if ( !(value & X86_CR0_TS) )
   2.140 @@ -1630,67 +1632,6 @@ static int svm_set_cr0(unsigned long val
   2.141          vmcb->exception_intercepts &= ~(1U << TRAP_no_device);
   2.142      }
   2.143  
   2.144 -    if ( (value & X86_CR0_PG) && !(old_value & X86_CR0_PG) )
   2.145 -    {
   2.146 -        if ( svm_lme_is_set(v) )
   2.147 -        {
   2.148 -            if ( !(v->arch.hvm_vcpu.guest_cr[4] & X86_CR4_PAE) )
   2.149 -            {
   2.150 -                HVM_DBG_LOG(DBG_LEVEL_1, "Enable paging before PAE enable");
   2.151 -                svm_inject_exception(v, TRAP_gp_fault, 1, 0);
   2.152 -                return 0;
   2.153 -            }
   2.154 -            HVM_DBG_LOG(DBG_LEVEL_1, "Enable the Long mode");
   2.155 -            v->arch.hvm_vcpu.guest_efer |= EFER_LMA;
   2.156 -            vmcb->efer |= EFER_LMA | EFER_LME;
   2.157 -        }
   2.158 -
   2.159 -        if ( !paging_mode_hap(v->domain) )
   2.160 -        {
   2.161 -            /* The guest CR3 must be pointing to the guest physical. */
   2.162 -            mfn = get_mfn_from_gpfn(v->arch.hvm_vcpu.guest_cr[3] >> PAGE_SHIFT);
   2.163 -            if ( !mfn_valid(mfn) || !get_page(mfn_to_page(mfn), v->domain))
   2.164 -            {
   2.165 -                gdprintk(XENLOG_ERR, "Invalid CR3 value = %lx (mfn=%lx)\n", 
   2.166 -                         v->arch.hvm_vcpu.guest_cr[3], mfn);
   2.167 -                domain_crash(v->domain);
   2.168 -                return 0;
   2.169 -            }
   2.170 -
   2.171 -            /* Now arch.guest_table points to machine physical. */
   2.172 -            old_base_mfn = pagetable_get_pfn(v->arch.guest_table);
   2.173 -            v->arch.guest_table = pagetable_from_pfn(mfn);
   2.174 -            if ( old_base_mfn )
   2.175 -                put_page(mfn_to_page(old_base_mfn));
   2.176 -
   2.177 -            HVM_DBG_LOG(DBG_LEVEL_VMMU, "Update CR3 value = %lx, mfn = %lx",
   2.178 -                        v->arch.hvm_vcpu.guest_cr[3], mfn);
   2.179 -        }
   2.180 -    }
   2.181 -    else if ( !(value & X86_CR0_PG) && (old_value & X86_CR0_PG) )
   2.182 -    {
   2.183 -        /* When CR0.PG is cleared, LMA is cleared immediately. */
   2.184 -        if ( hvm_long_mode_enabled(v) )
   2.185 -        {
   2.186 -            vmcb->efer &= ~(EFER_LME | EFER_LMA);
   2.187 -            v->arch.hvm_vcpu.guest_efer &= ~EFER_LMA;
   2.188 -        }
   2.189 -
   2.190 -        if ( !paging_mode_hap(v->domain) && v->arch.hvm_vcpu.guest_cr[3] )
   2.191 -        {
   2.192 -            put_page(mfn_to_page(get_mfn_from_gpfn(
   2.193 -                v->arch.hvm_vcpu.guest_cr[3] >> PAGE_SHIFT)));
   2.194 -            v->arch.guest_table = pagetable_null();
   2.195 -        }
   2.196 -    }
   2.197 -
   2.198 -    vmcb->cr0 = v->arch.hvm_vcpu.guest_cr[0] = value;
   2.199 -    if ( !paging_mode_hap(v->domain) )
   2.200 -        vmcb->cr0 |= X86_CR0_PG | X86_CR0_WP;
   2.201 -
   2.202 -    if ( (value ^ old_value) & X86_CR0_PG )
   2.203 -        paging_update_paging_modes(v);
   2.204 -
   2.205      return 1;
   2.206  }
   2.207  
   2.208 @@ -1833,7 +1774,7 @@ static void svm_cr_access(
   2.209          /* TS being cleared means that it's time to restore fpu state. */
   2.210          setup_fpu(current);
   2.211          vmcb->exception_intercepts &= ~(1U << TRAP_no_device);
   2.212 -        vmcb->cr0 &= ~X86_CR0_TS; /* clear TS */
   2.213 +        vmcb->cr0 = v->arch.hvm_vcpu.hw_cr[0] &= ~X86_CR0_TS; /* clear TS */
   2.214          v->arch.hvm_vcpu.guest_cr[0] &= ~X86_CR0_TS; /* clear TS */
   2.215          break;
   2.216  
   2.217 @@ -2144,20 +2085,21 @@ static int svm_reset_to_realmode(struct 
   2.218  
   2.219      memset(regs, 0, sizeof(struct cpu_user_regs));
   2.220  
   2.221 -    vmcb->cr0 = X86_CR0_ET | X86_CR0_PG | X86_CR0_WP;
   2.222 +    vmcb->cr0 = v->arch.hvm_vcpu.hw_cr[0] =
   2.223 +        X86_CR0_ET | X86_CR0_PG | X86_CR0_WP;
   2.224      v->arch.hvm_vcpu.guest_cr[0] = X86_CR0_ET;
   2.225  
   2.226      vmcb->cr2 = 0;
   2.227      vmcb->efer = EFER_SVME;
   2.228  
   2.229 -    vmcb->cr4 = HVM_CR4_HOST_MASK;
   2.230 +    vmcb->cr4 = v->arch.hvm_vcpu.hw_cr[4] = HVM_CR4_HOST_MASK;
   2.231      v->arch.hvm_vcpu.guest_cr[4] = 0;
   2.232  
   2.233      if ( paging_mode_hap(v->domain) )
   2.234      {
   2.235 -        vmcb->cr0 = v->arch.hvm_vcpu.guest_cr[0];
   2.236 -        vmcb->cr4 = (v->arch.hvm_vcpu.guest_cr[4] |
   2.237 -                     (HVM_CR4_HOST_MASK & ~X86_CR4_PAE));
   2.238 +        vmcb->cr0 = v->arch.hvm_vcpu.hw_cr[0] = v->arch.hvm_vcpu.guest_cr[0];
   2.239 +        vmcb->cr4 = v->arch.hvm_vcpu.hw_cr[4] =
   2.240 +            v->arch.hvm_vcpu.guest_cr[4] | (HVM_CR4_HOST_MASK & ~X86_CR4_PAE);
   2.241      }
   2.242  
   2.243      /* This will jump to ROMBIOS */
     3.1 --- a/xen/arch/x86/hvm/svm/vmcb.c	Wed Aug 08 15:03:40 2007 +0100
     3.2 +++ b/xen/arch/x86/hvm/svm/vmcb.c	Wed Aug 08 16:09:17 2007 +0100
     3.3 @@ -217,24 +217,26 @@ static int construct_vmcb(struct vcpu *v
     3.4      vmcb->tr.limit = 0xff;
     3.5  
     3.6      /* Guest CR0. */
     3.7 -    vmcb->cr0 = read_cr0();
     3.8 -    v->arch.hvm_vcpu.guest_cr[0] = vmcb->cr0 & ~(X86_CR0_PG | X86_CR0_TS);
     3.9 +    vmcb->cr0 = v->arch.hvm_vcpu.hw_cr[0] = read_cr0();
    3.10 +    v->arch.hvm_vcpu.guest_cr[0] =
    3.11 +        v->arch.hvm_vcpu.hw_cr[0] & ~(X86_CR0_PG | X86_CR0_TS);
    3.12  
    3.13      /* Guest CR4. */
    3.14      v->arch.hvm_vcpu.guest_cr[4] =
    3.15          read_cr4() & ~(X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE);
    3.16 -    vmcb->cr4 = v->arch.hvm_vcpu.guest_cr[4] | HVM_CR4_HOST_MASK;
    3.17 +    vmcb->cr4 = v->arch.hvm_vcpu.hw_cr[4] =
    3.18 +        v->arch.hvm_vcpu.guest_cr[4] | HVM_CR4_HOST_MASK;
    3.19  
    3.20      paging_update_paging_modes(v);
    3.21      vmcb->cr3 = v->arch.hvm_vcpu.hw_cr[3]; 
    3.22  
    3.23      if ( paging_mode_hap(v->domain) )
    3.24      {
    3.25 -        vmcb->cr0 = v->arch.hvm_vcpu.guest_cr[0];
    3.26 +        vmcb->cr0 = v->arch.hvm_vcpu.hw_cr[0] = v->arch.hvm_vcpu.guest_cr[0];
    3.27          vmcb->np_enable = 1; /* enable nested paging */
    3.28          vmcb->g_pat = 0x0007040600070406ULL; /* guest PAT */
    3.29          vmcb->h_cr3 = pagetable_get_paddr(v->domain->arch.phys_table);
    3.30 -        vmcb->cr4 = v->arch.hvm_vcpu.guest_cr[4] =
    3.31 +        vmcb->cr4 = v->arch.hvm_vcpu.hw_cr[4] = v->arch.hvm_vcpu.guest_cr[4] =
    3.32              HVM_CR4_HOST_MASK & ~X86_CR4_PAE;
    3.33          vmcb->exception_intercepts = HVM_TRAP_MASK;
    3.34  
     4.1 --- a/xen/arch/x86/hvm/vmx/vmx.c	Wed Aug 08 15:03:40 2007 +0100
     4.2 +++ b/xen/arch/x86/hvm/vmx/vmx.c	Wed Aug 08 16:09:17 2007 +0100
     4.3 @@ -61,6 +61,7 @@ static void vmx_ctxt_switch_to(struct vc
     4.4  static int  vmx_alloc_vlapic_mapping(struct domain *d);
     4.5  static void vmx_free_vlapic_mapping(struct domain *d);
     4.6  static void vmx_install_vlapic_mapping(struct vcpu *v);
     4.7 +static void vmx_update_guest_efer(struct vcpu *v);
     4.8  
     4.9  static int vmx_domain_initialise(struct domain *d)
    4.10  {
    4.11 @@ -102,33 +103,6 @@ static void vmx_vcpu_destroy(struct vcpu
    4.12  
    4.13  #ifdef __x86_64__
    4.14  
    4.15 -static int vmx_lme_is_set(struct vcpu *v)
    4.16 -{
    4.17 -    return v->arch.hvm_vcpu.guest_efer & EFER_LME;
    4.18 -}
    4.19 -
    4.20 -static void vmx_enable_long_mode(struct vcpu *v)
    4.21 -{
    4.22 -    unsigned long vm_entry_value;
    4.23 -
    4.24 -    vm_entry_value = __vmread(VM_ENTRY_CONTROLS);
    4.25 -    vm_entry_value |= VM_ENTRY_IA32E_MODE;
    4.26 -    __vmwrite(VM_ENTRY_CONTROLS, vm_entry_value);
    4.27 -
    4.28 -    v->arch.hvm_vcpu.guest_efer |= EFER_LMA;
    4.29 -}
    4.30 -
    4.31 -static void vmx_disable_long_mode(struct vcpu *v)
    4.32 -{
    4.33 -    unsigned long vm_entry_value;
    4.34 -
    4.35 -    vm_entry_value = __vmread(VM_ENTRY_CONTROLS);
    4.36 -    vm_entry_value &= ~VM_ENTRY_IA32E_MODE;
    4.37 -    __vmwrite(VM_ENTRY_CONTROLS, vm_entry_value);
    4.38 -
    4.39 -    v->arch.hvm_vcpu.guest_efer &= ~EFER_LMA;
    4.40 -}
    4.41 -
    4.42  static DEFINE_PER_CPU(struct vmx_msr_state, host_msr_state);
    4.43  
    4.44  static u32 msr_index[VMX_MSR_COUNT] =
    4.45 @@ -378,13 +352,6 @@ static void vmx_restore_guest_msrs(struc
    4.46  
    4.47  #else  /* __i386__ */
    4.48  
    4.49 -static int vmx_lme_is_set(struct vcpu *v)
    4.50 -{ return 0; }
    4.51 -static void vmx_enable_long_mode(struct vcpu *v)
    4.52 -{ BUG(); }
    4.53 -static void vmx_disable_long_mode(struct vcpu *v)
    4.54 -{ BUG(); }
    4.55 -
    4.56  #define vmx_save_host_msrs()        ((void)0)
    4.57  
    4.58  static void vmx_restore_host_msrs(void)
    4.59 @@ -644,8 +611,7 @@ int vmx_vmcs_restore(struct vcpu *v, str
    4.60   skip_cr3:
    4.61      v->arch.hvm_vcpu.guest_cr[3] = c->cr3;
    4.62  
    4.63 -    if ( hvm_long_mode_enabled(v) )
    4.64 -        vmx_enable_long_mode(v);
    4.65 +    vmx_update_guest_efer(v);
    4.66  
    4.67      __vmwrite(GUEST_CR4, (c->cr4 | HVM_CR4_HOST_MASK));
    4.68      v->arch.hvm_vcpu.guest_cr[4] = c->cr4;
    4.69 @@ -1095,6 +1061,14 @@ static void vmx_update_guest_cr(struct v
    4.70  
    4.71      switch ( cr )
    4.72      {
    4.73 +    case 0:
    4.74 +        v->arch.hvm_vcpu.hw_cr[0] |= X86_CR0_PE | X86_CR0_NE;
    4.75 +        __vmwrite(GUEST_CR0, v->arch.hvm_vcpu.hw_cr[0]);
    4.76 +        __vmwrite(CR0_READ_SHADOW, v->arch.hvm_vcpu.guest_cr[0]);
    4.77 +        break;
    4.78 +    case 2:
    4.79 +        /* CR2 is updated in exit stub. */
    4.80 +        break;
    4.81      case 3:
    4.82          __vmwrite(GUEST_CR3, v->arch.hvm_vcpu.hw_cr[3]);
    4.83          break;
    4.84 @@ -1109,6 +1083,26 @@ static void vmx_update_guest_cr(struct v
    4.85      vmx_vmcs_exit(v);
    4.86  }
    4.87  
    4.88 +static void vmx_update_guest_efer(struct vcpu *v)
    4.89 +{
    4.90 +#ifdef __x86_64__
    4.91 +    unsigned long vm_entry_value;
    4.92 +
    4.93 +    ASSERT((v == current) || !vcpu_runnable(v));
    4.94 +
    4.95 +    vmx_vmcs_enter(v);
    4.96 +
    4.97 +    vm_entry_value = __vmread(VM_ENTRY_CONTROLS);
    4.98 +    if ( v->arch.hvm_vcpu.guest_efer & EFER_LMA )
    4.99 +        vm_entry_value |= VM_ENTRY_IA32E_MODE;
   4.100 +    else
   4.101 +        vm_entry_value &= ~VM_ENTRY_IA32E_MODE;
   4.102 +    __vmwrite(VM_ENTRY_CONTROLS, vm_entry_value);
   4.103 +
   4.104 +    vmx_vmcs_exit(v);
   4.105 +#endif
   4.106 +}
   4.107 +
   4.108  static void vmx_flush_guest_tlbs(void)
   4.109  {
   4.110      /* No tagged TLB support on VMX yet.  The fact that we're in Xen
   4.111 @@ -1172,6 +1166,7 @@ static struct hvm_function_table vmx_fun
   4.112      .get_segment_register = vmx_get_segment_register,
   4.113      .update_host_cr3      = vmx_update_host_cr3,
   4.114      .update_guest_cr      = vmx_update_guest_cr,
   4.115 +    .update_guest_efer    = vmx_update_guest_efer,
   4.116      .flush_guest_tlbs     = vmx_flush_guest_tlbs,
   4.117      .update_vtpr          = vmx_update_vtpr,
   4.118      .stts                 = vmx_stts,
   4.119 @@ -2110,33 +2105,11 @@ static int vmx_assist(struct vcpu *v, in
   4.120  static int vmx_set_cr0(unsigned long value)
   4.121  {
   4.122      struct vcpu *v = current;
   4.123 -    unsigned long mfn;
   4.124      unsigned long eip;
   4.125 -    int paging_enabled;
   4.126 -    unsigned long old_cr0;
   4.127 -    unsigned long old_base_mfn;
   4.128 -
   4.129 -    HVM_DBG_LOG(DBG_LEVEL_VMMU, "Update CR0 value = %lx", value);
   4.130 -
   4.131 -    if ( (u32)value != value )
   4.132 -    {
   4.133 -        HVM_DBG_LOG(DBG_LEVEL_1,
   4.134 -                    "Guest attempts to set upper 32 bits in CR0: %lx",
   4.135 -                    value);
   4.136 -        vmx_inject_hw_exception(v, TRAP_gp_fault, 0);
   4.137 +    int rc = hvm_set_cr0(value);
   4.138 +
   4.139 +    if ( rc == 0 )
   4.140          return 0;
   4.141 -    }
   4.142 -
   4.143 -    value &= ~HVM_CR0_GUEST_RESERVED_BITS;
   4.144 -
   4.145 -    /* ET is reserved and should be always be 1. */
   4.146 -    value |= X86_CR0_ET;
   4.147 -
   4.148 -    if ( (value & (X86_CR0_PE | X86_CR0_PG)) == X86_CR0_PG )
   4.149 -    {
   4.150 -        vmx_inject_hw_exception(v, TRAP_gp_fault, 0);
   4.151 -        return 0;
   4.152 -    }
   4.153  
   4.154      /* TS cleared? Then initialise FPU now. */
   4.155      if ( !(value & X86_CR0_TS) )
   4.156 @@ -2145,88 +2118,13 @@ static int vmx_set_cr0(unsigned long val
   4.157          __vm_clear_bit(EXCEPTION_BITMAP, TRAP_no_device);
   4.158      }
   4.159  
   4.160 -    old_cr0 = v->arch.hvm_vcpu.guest_cr[0];
   4.161 -    paging_enabled = old_cr0 & X86_CR0_PG;
   4.162 -
   4.163 -    v->arch.hvm_vcpu.hw_cr[0] = (value | X86_CR0_PE | X86_CR0_PG |
   4.164 -                                 X86_CR0_NE | X86_CR0_WP);
   4.165 -    __vmwrite(GUEST_CR0, v->arch.hvm_vcpu.hw_cr[0]);
   4.166 -
   4.167 -    v->arch.hvm_vcpu.guest_cr[0] = value;
   4.168 -    __vmwrite(CR0_READ_SHADOW, v->arch.hvm_vcpu.guest_cr[0]);
   4.169 -
   4.170 -    /* Trying to enable paging. */
   4.171 -    if ( (value & X86_CR0_PE) && (value & X86_CR0_PG) && !paging_enabled )
   4.172 -    {
   4.173 -        if ( vmx_lme_is_set(v) && !hvm_long_mode_enabled(v) )
   4.174 -        {
   4.175 -            if ( !(v->arch.hvm_vcpu.guest_cr[4] & X86_CR4_PAE) )
   4.176 -            {
   4.177 -                HVM_DBG_LOG(DBG_LEVEL_1, "Guest enabled paging "
   4.178 -                            "with EFER.LME set but not CR4.PAE");
   4.179 -                vmx_inject_hw_exception(v, TRAP_gp_fault, 0);
   4.180 -                return 0;
   4.181 -            }
   4.182 -
   4.183 -            HVM_DBG_LOG(DBG_LEVEL_1, "Enabling long mode");
   4.184 -            vmx_enable_long_mode(v);
   4.185 -        }
   4.186 -
   4.187 -        /*
   4.188 -         * The guest CR3 must be pointing to the guest physical.
   4.189 -         */
   4.190 -        mfn = get_mfn_from_gpfn(v->arch.hvm_vcpu.guest_cr[3] >> PAGE_SHIFT);
   4.191 -        if ( !mfn_valid(mfn) || !get_page(mfn_to_page(mfn), v->domain) )
   4.192 -        {
   4.193 -            gdprintk(XENLOG_ERR, "Invalid CR3 value = %lx (mfn=%lx)\n",
   4.194 -                     v->arch.hvm_vcpu.guest_cr[3], mfn);
   4.195 -            domain_crash(v->domain);
   4.196 -            return 0;
   4.197 -        }
   4.198 -
   4.199 -        /*
   4.200 -         * Now arch.guest_table points to machine physical.
   4.201 -         */
   4.202 -        old_base_mfn = pagetable_get_pfn(v->arch.guest_table);
   4.203 -        v->arch.guest_table = pagetable_from_pfn(mfn);
   4.204 -        if ( old_base_mfn )
   4.205 -            put_page(mfn_to_page(old_base_mfn));
   4.206 -
   4.207 -        HVM_DBG_LOG(DBG_LEVEL_VMMU, "Update CR3 value = %lx, mfn = %lx",
   4.208 -                    v->arch.hvm_vcpu.guest_cr[3], mfn);
   4.209 -
   4.210 -        paging_update_paging_modes(v);
   4.211 -    }
   4.212 -
   4.213 -    /* Trying to disable paging. */
   4.214 -    if ( ((value & (X86_CR0_PE | X86_CR0_PG)) != (X86_CR0_PE | X86_CR0_PG)) &&
   4.215 -         paging_enabled )
   4.216 -    {
   4.217 -        /* When CR0.PG is cleared, LMA is cleared immediately. */
   4.218 -        if ( hvm_long_mode_enabled(v) )
   4.219 -            vmx_disable_long_mode(v);
   4.220 -
   4.221 -        if ( v->arch.hvm_vcpu.guest_cr[3] )
   4.222 -        {
   4.223 -            put_page(mfn_to_page(get_mfn_from_gpfn(
   4.224 -                      v->arch.hvm_vcpu.guest_cr[3] >> PAGE_SHIFT)));
   4.225 -            v->arch.guest_table = pagetable_null();
   4.226 -        }
   4.227 -    }
   4.228 -
   4.229      /*
   4.230       * VMX does not implement real-mode virtualization. We emulate
   4.231       * real-mode by performing a world switch to VMXAssist whenever
   4.232       * a partition disables the CR0.PE bit.
   4.233       */
   4.234 -    if ( (value & X86_CR0_PE) == 0 )
   4.235 +    if ( !(value & X86_CR0_PE) )
   4.236      {
   4.237 -        if ( value & X86_CR0_PG )
   4.238 -        {
   4.239 -            vmx_inject_hw_exception(v, TRAP_gp_fault, 0);
   4.240 -            return 0;
   4.241 -        }
   4.242 -
   4.243          if ( vmx_assist(v, VMX_ASSIST_INVOKE) )
   4.244          {
   4.245              eip = __vmread(GUEST_RIP);
   4.246 @@ -2247,8 +2145,6 @@ static int vmx_set_cr0(unsigned long val
   4.247              return 0; /* do not update eip! */
   4.248          }
   4.249      }
   4.250 -    else if ( (value & (X86_CR0_PE | X86_CR0_PG)) == X86_CR0_PE )
   4.251 -        paging_update_paging_modes(v);
   4.252  
   4.253      return 1;
   4.254  }
     5.1 --- a/xen/include/asm-x86/hvm/hvm.h	Wed Aug 08 15:03:40 2007 +0100
     5.2 +++ b/xen/include/asm-x86/hvm/hvm.h	Wed Aug 08 16:09:17 2007 +0100
     5.3 @@ -112,9 +112,10 @@ struct hvm_function_table {
     5.4      void (*update_host_cr3)(struct vcpu *v);
     5.5  
     5.6      /*
     5.7 -     * Called to inform HVM layer that a guest control register has changed.
     5.8 +     * Called to inform HVM layer that a guest CRn or EFER has changed.
     5.9       */
    5.10      void (*update_guest_cr)(struct vcpu *v, unsigned int cr);
    5.11 +    void (*update_guest_efer)(struct vcpu *v);
    5.12  
    5.13      /*
    5.14       * Called to ensure than all guest-specific mappings in a tagged TLB
    5.15 @@ -225,6 +226,11 @@ static inline void hvm_update_guest_cr(s
    5.16      hvm_funcs.update_guest_cr(v, cr);
    5.17  }
    5.18  
    5.19 +static inline void hvm_update_guest_efer(struct vcpu *v)
    5.20 +{
    5.21 +    hvm_funcs.update_guest_efer(v);
    5.22 +}
    5.23 +
    5.24  static inline void 
    5.25  hvm_flush_guest_tlbs(void)
    5.26  {
    5.27 @@ -250,7 +256,6 @@ hvm_get_segment_register(struct vcpu *v,
    5.28  
    5.29  void hvm_cpuid(unsigned int input, unsigned int *eax, unsigned int *ebx,
    5.30                                     unsigned int *ecx, unsigned int *edx);
    5.31 -void hvm_stts(struct vcpu *v);
    5.32  void hvm_migrate_timers(struct vcpu *v);
    5.33  void hvm_do_resume(struct vcpu *v);
    5.34  
     6.1 --- a/xen/include/asm-x86/hvm/support.h	Wed Aug 08 15:03:40 2007 +0100
     6.2 +++ b/xen/include/asm-x86/hvm/support.h	Wed Aug 08 16:09:17 2007 +0100
     6.3 @@ -234,6 +234,7 @@ int hvm_do_hypercall(struct cpu_user_reg
     6.4  void hvm_hlt(unsigned long rflags);
     6.5  void hvm_triple_fault(void);
     6.6  
     6.7 +int hvm_set_cr0(unsigned long value);
     6.8  int hvm_set_cr3(unsigned long value);
     6.9  int hvm_set_cr4(unsigned long value);
    6.10  
     7.1 --- a/xen/include/asm-x86/hvm/vcpu.h	Wed Aug 08 15:03:40 2007 +0100
     7.2 +++ b/xen/include/asm-x86/hvm/vcpu.h	Wed Aug 08 16:09:17 2007 +0100
     7.3 @@ -33,11 +33,7 @@ struct hvm_vcpu {
     7.4      unsigned long       guest_cr[5];
     7.5      unsigned long       guest_efer;
     7.6  
     7.7 -    /*
     7.8 -     * Processor-visible CR0-4 while guest executes.
     7.9 -     * Only CR3 is guaranteed to be valid: all other array entries are private
    7.10 -     * to the specific HVM implementation (e.g., VMX, SVM).
    7.11 -     */
    7.12 +    /* Processor-visible control-register values, while guest executes. */
    7.13      unsigned long       hw_cr[5];
    7.14  
    7.15      struct hvm_io_op    io_op;