direct-io.hg

changeset 15513:1d1ccf6b8614

hvm: Clean ups and fix MSR access functions.
Signed-off-by: Xin Li <xin.b.li@intel.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Mon Jul 09 18:04:23 2007 +0100 (2007-07-09)
parents aa640601575f
children 7486ab2b6ae6
files xen/arch/x86/hvm/svm/svm.c xen/arch/x86/hvm/vmx/vmx.c
line diff
     1.1 --- a/xen/arch/x86/hvm/svm/svm.c	Mon Jul 09 14:51:44 2007 +0100
     1.2 +++ b/xen/arch/x86/hvm/svm/svm.c	Mon Jul 09 18:04:23 2007 +0100
     1.3 @@ -53,6 +53,8 @@
     1.4  #define set_segment_register(name, value)  \
     1.5      asm volatile ( "movw %%ax ,%%" STR(name) "" : : "a" (value) )
     1.6  
     1.7 +enum handler_return { HNDL_done, HNDL_unhandled, HNDL_exception_raised };
     1.8 +
     1.9  int inst_copy_from_guest(unsigned char *buf, unsigned long guest_eip,
    1.10                           int inst_len);
    1.11  asmlinkage void do_IRQ(struct cpu_user_regs *);
    1.12 @@ -173,7 +175,7 @@ static void svm_store_cpu_guest_regs(
    1.13      }
    1.14  }
    1.15  
    1.16 -static int long_mode_do_msr_write(struct cpu_user_regs *regs)
    1.17 +static enum handler_return long_mode_do_msr_write(struct cpu_user_regs *regs)
    1.18  {
    1.19      u64 msr_content = (u32)regs->eax | ((u64)regs->edx << 32);
    1.20      u32 ecx = regs->ecx;
    1.21 @@ -237,14 +239,14 @@ static int long_mode_do_msr_write(struct
    1.22          break;
    1.23  
    1.24      default:
    1.25 -        return 0;
    1.26 +        return HNDL_unhandled;
    1.27      }
    1.28  
    1.29 -    return 1;
    1.30 +    return HNDL_done;
    1.31  
    1.32   gp_fault:
    1.33      svm_inject_exception(v, TRAP_gp_fault, 1, 0);
    1.34 -    return 0;
    1.35 +    return HNDL_exception_raised;
    1.36  }
    1.37  
    1.38  
    1.39 @@ -1716,8 +1718,8 @@ static int svm_set_cr0(unsigned long val
    1.40              if ( old_base_mfn )
    1.41                  put_page(mfn_to_page(old_base_mfn));
    1.42  
    1.43 -            HVM_DBG_LOG(DBG_LEVEL_VMMU, "New arch.guest_table = %lx", 
    1.44 -                        (unsigned long) (mfn << PAGE_SHIFT));
    1.45 +            HVM_DBG_LOG(DBG_LEVEL_VMMU, "Update CR3 value = %lx, mfn = %lx",
    1.46 +                        v->arch.hvm_vmx.cpu_cr3, mfn);
    1.47          }
    1.48      }
    1.49      else if ( !(value & X86_CR0_PG) && (old_value & X86_CR0_PG) )
    1.50 @@ -1744,8 +1746,7 @@ static int svm_set_cr0(unsigned long val
    1.51      if ( (value ^ old_value) & X86_CR0_PG )
    1.52      {
    1.53          paging_update_paging_modes(v);
    1.54 -        /* signal paging update to ASID handler */
    1.55 -        svm_asid_g_update_paging (v);
    1.56 +        svm_asid_g_update_paging(v);
    1.57      }
    1.58  
    1.59      return 1;
    1.60 @@ -1894,8 +1895,8 @@ static int mov_to_cr(int gpreg, int cr, 
    1.61          {
    1.62              if ( svm_pgbit_test(v) )
    1.63              {
    1.64 +#if CONFIG_PAGING_LEVELS >= 3
    1.65                  /* The guest is a 32-bit PAE guest. */
    1.66 -#if CONFIG_PAGING_LEVELS >= 3
    1.67                  unsigned long mfn, old_base_mfn;
    1.68                  mfn = get_mfn_from_gpfn(v->arch.hvm_svm.cpu_cr3 >> PAGE_SHIFT);
    1.69                  if ( !mfn_valid(mfn) || 
    1.70 @@ -1905,7 +1906,6 @@ static int mov_to_cr(int gpreg, int cr, 
    1.71                  /*
    1.72                   * Now arch.guest_table points to machine physical.
    1.73                   */
    1.74 -
    1.75                  old_base_mfn = pagetable_get_pfn(v->arch.guest_table);
    1.76                  v->arch.guest_table = pagetable_from_pfn(mfn);
    1.77                  if ( old_base_mfn )
    1.78 @@ -1914,9 +1914,6 @@ static int mov_to_cr(int gpreg, int cr, 
    1.79                  /* signal paging update to ASID handler */
    1.80                  svm_asid_g_update_paging (v);
    1.81  
    1.82 -                HVM_DBG_LOG(DBG_LEVEL_VMMU, "New arch.guest_table = %lx",
    1.83 -                            (unsigned long) (mfn << PAGE_SHIFT));
    1.84 -
    1.85                  HVM_DBG_LOG(DBG_LEVEL_VMMU, 
    1.86                              "Update CR3 value = %lx, mfn = %lx",
    1.87                              v->arch.hvm_svm.cpu_cr3, mfn);
    1.88 @@ -2201,8 +2198,16 @@ static void svm_do_msr_access(
    1.89              break;
    1.90  
    1.91          default:
    1.92 -            if ( !long_mode_do_msr_write(regs) )
    1.93 +            switch ( long_mode_do_msr_write(regs) )
    1.94 +            {
    1.95 +            case HNDL_unhandled:
    1.96                  wrmsr_hypervisor_regs(ecx, regs->eax, regs->edx);
    1.97 +                break;
    1.98 +            case HNDL_exception_raised:
    1.99 +                return;
   1.100 +            case HNDL_done:
   1.101 +                break;
   1.102 +            }
   1.103              break;
   1.104          }
   1.105  
     2.1 --- a/xen/arch/x86/hvm/vmx/vmx.c	Mon Jul 09 14:51:44 2007 +0100
     2.2 +++ b/xen/arch/x86/hvm/vmx/vmx.c	Mon Jul 09 18:04:23 2007 +0100
     2.3 @@ -51,6 +51,8 @@
     2.4  #include <public/hvm/save.h>
     2.5  #include <asm/hvm/trace.h>
     2.6  
     2.7 +enum handler_return { HNDL_done, HNDL_unhandled, HNDL_exception_raised };
     2.8 +
     2.9  char *vmx_msr_bitmap;
    2.10  
    2.11  static void vmx_ctxt_switch_from(struct vcpu *v);
    2.12 @@ -178,14 +180,15 @@ static void vmx_save_host_msrs(void)
    2.13          set_bit(VMX_INDEX_MSR_ ## address, &host_msr_state->flags);     \
    2.14          break
    2.15  
    2.16 -static int long_mode_do_msr_read(struct cpu_user_regs *regs)
    2.17 +static enum handler_return long_mode_do_msr_read(struct cpu_user_regs *regs)
    2.18  {
    2.19      u64 msr_content = 0;
    2.20      u32 ecx = regs->ecx;
    2.21      struct vcpu *v = current;
    2.22      struct vmx_msr_state *guest_msr_state = &v->arch.hvm_vmx.msr_state;
    2.23  
    2.24 -    switch ( ecx ) {
    2.25 +    switch ( ecx )
    2.26 +    {
    2.27      case MSR_EFER:
    2.28          msr_content = v->arch.hvm_vmx.efer;
    2.29          break;
    2.30 @@ -204,7 +207,7 @@ static int long_mode_do_msr_read(struct 
    2.31          if ( !(vmx_long_mode_enabled(v)) )
    2.32          {
    2.33              vmx_inject_hw_exception(v, TRAP_gp_fault, 0);
    2.34 -            return 0;
    2.35 +            return HNDL_exception_raised;
    2.36          }
    2.37          break;
    2.38  
    2.39 @@ -225,7 +228,7 @@ static int long_mode_do_msr_read(struct 
    2.40          break;
    2.41  
    2.42      default:
    2.43 -        return 0;
    2.44 +        return HNDL_unhandled;
    2.45      }
    2.46  
    2.47      HVM_DBG_LOG(DBG_LEVEL_0, "msr 0x%x content 0x%"PRIx64, ecx, msr_content);
    2.48 @@ -233,10 +236,10 @@ static int long_mode_do_msr_read(struct 
    2.49      regs->eax = (u32)(msr_content >>  0);
    2.50      regs->edx = (u32)(msr_content >> 32);
    2.51  
    2.52 -    return 1;
    2.53 +    return HNDL_done;
    2.54  }
    2.55  
    2.56 -static int long_mode_do_msr_write(struct cpu_user_regs *regs)
    2.57 +static enum handler_return long_mode_do_msr_write(struct cpu_user_regs *regs)
    2.58  {
    2.59      u64 msr_content = (u32)regs->eax | ((u64)regs->edx << 32);
    2.60      u32 ecx = regs->ecx;
    2.61 @@ -326,16 +329,16 @@ static int long_mode_do_msr_write(struct
    2.62          WRITE_MSR(SYSCALL_MASK);
    2.63  
    2.64      default:
    2.65 -        return 0;
    2.66 +        return HNDL_unhandled;
    2.67      }
    2.68  
    2.69 -    return 1;
    2.70 +    return HNDL_done;
    2.71  
    2.72   uncanonical_address:
    2.73      HVM_DBG_LOG(DBG_LEVEL_0, "Not cano address of msr write %x", ecx);
    2.74   gp_fault:
    2.75      vmx_inject_hw_exception(v, TRAP_gp_fault, 0);
    2.76 -    return 0;
    2.77 +    return HNDL_exception_raised;
    2.78  }
    2.79  
    2.80  /*
    2.81 @@ -434,7 +437,7 @@ static void vmx_restore_guest_msrs(struc
    2.82      }
    2.83  }
    2.84  
    2.85 -static int long_mode_do_msr_read(struct cpu_user_regs *regs)
    2.86 +static enum handler_return long_mode_do_msr_read(struct cpu_user_regs *regs)
    2.87  {
    2.88      u64 msr_content = 0;
    2.89      struct vcpu *v = current;
    2.90 @@ -445,16 +448,16 @@ static int long_mode_do_msr_read(struct 
    2.91          break;
    2.92  
    2.93      default:
    2.94 -        return 0;
    2.95 +        return HNDL_unhandled;
    2.96      }
    2.97  
    2.98      regs->eax = msr_content >>  0;
    2.99      regs->edx = msr_content >> 32;
   2.100  
   2.101 -    return 1;
   2.102 +    return HNDL_done;
   2.103  }
   2.104  
   2.105 -static int long_mode_do_msr_write(struct cpu_user_regs *regs)
   2.106 +static enum handler_return long_mode_do_msr_write(struct cpu_user_regs *regs)
   2.107  {
   2.108      u64 msr_content = regs->eax | ((u64)regs->edx << 32);
   2.109      struct vcpu *v = current;
   2.110 @@ -469,7 +472,7 @@ static int long_mode_do_msr_write(struct
   2.111              gdprintk(XENLOG_WARNING, "Trying to set reserved bit in "
   2.112                       "EFER: %"PRIx64"\n", msr_content);
   2.113              vmx_inject_hw_exception(v, TRAP_gp_fault, 0);
   2.114 -            return 0;
   2.115 +            return HNDL_exception_raised;
   2.116          }
   2.117  
   2.118          if ( (msr_content ^ v->arch.hvm_vmx.efer) & EFER_NX )
   2.119 @@ -479,10 +482,10 @@ static int long_mode_do_msr_write(struct
   2.120          break;
   2.121  
   2.122      default:
   2.123 -        return 0;
   2.124 +        return HNDL_unhandled;
   2.125      }
   2.126  
   2.127 -    return 1;
   2.128 +    return HNDL_done;
   2.129  }
   2.130  
   2.131  #endif /* __i386__ */
   2.132 @@ -683,9 +686,9 @@ int vmx_vmcs_restore(struct vcpu *v, str
   2.133      if ( old_base_mfn )
   2.134          put_page(mfn_to_page(old_base_mfn));
   2.135  
   2.136 + skip_cr3:
   2.137      v->arch.hvm_vmx.cpu_cr3 = c->cr3;
   2.138  
   2.139 - skip_cr3:
   2.140      if ( vmx_long_mode_enabled(v) )
   2.141          vmx_enable_long_mode(v);
   2.142  
   2.143 @@ -1663,10 +1666,10 @@ static int vmx_str_pio_check_descriptor(
   2.144  }
   2.145  
   2.146  
   2.147 -static void vmx_str_pio_check_limit(u32 limit, unsigned int size,
   2.148 -                                    u32 ar_bytes, unsigned long addr,
   2.149 -                                    unsigned long base, int df,
   2.150 -                                    unsigned long *count)
   2.151 +static int vmx_str_pio_check_limit(u32 limit, unsigned int size,
   2.152 +                                   u32 ar_bytes, unsigned long addr,
   2.153 +                                   unsigned long base, int df,
   2.154 +                                   unsigned long *count)
   2.155  {
   2.156      unsigned long ea = addr - base;
   2.157  
   2.158 @@ -1675,10 +1678,7 @@ static void vmx_str_pio_check_limit(u32 
   2.159      if ( (u32)(ea + size - 1) < (u32)ea ||
   2.160           (ar_bytes & 0xc) != 0x4 ? ea + size - 1 > limit
   2.161                                   : ea <= limit )
   2.162 -    {
   2.163 -        vmx_inject_hw_exception(current, TRAP_gp_fault, 0);
   2.164 -        return;
   2.165 -    }
   2.166 +        return 0;
   2.167  
   2.168      /* Check the limit for repeated instructions, as above we checked
   2.169         only the first instance. Truncate the count if a limit violation
   2.170 @@ -1719,22 +1719,23 @@ static void vmx_str_pio_check_limit(u32 
   2.171          }
   2.172          ASSERT(*count);
   2.173      }
   2.174 +
   2.175 +    return 1;
   2.176  }
   2.177  
   2.178  #ifdef __x86_64__
   2.179 -static void vmx_str_pio_lm_check_limit(struct cpu_user_regs *regs,
   2.180 -                                       unsigned int size,
   2.181 -                                       unsigned long addr,
   2.182 -                                       unsigned long *count)
   2.183 +static int vmx_str_pio_lm_check_limit(struct cpu_user_regs *regs,
   2.184 +                                      unsigned int size,
   2.185 +                                      unsigned long addr,
   2.186 +                                      unsigned long *count)
   2.187  {
   2.188      if ( !is_canonical_address(addr) ||
   2.189           !is_canonical_address(addr + size - 1) )
   2.190 -    {
   2.191 -        vmx_inject_hw_exception(current, TRAP_gp_fault, 0);
   2.192 -        return;
   2.193 -    }
   2.194 +        return 0;
   2.195 +
   2.196      if ( *count > (1UL << 48) / size )
   2.197          *count = (1UL << 48) / size;
   2.198 +
   2.199      if ( !(regs->eflags & EF_DF) )
   2.200      {
   2.201          if ( addr + *count * size - 1 < addr ||
   2.202 @@ -1747,7 +1748,10 @@ static void vmx_str_pio_lm_check_limit(s
   2.203               !is_canonical_address(addr + (*count - 1) * size) )
   2.204              *count = (addr & ~((1UL << 48) - 1)) / size + 1;
   2.205      }
   2.206 +
   2.207      ASSERT(*count);
   2.208 +
   2.209 +    return 1;
   2.210  }
   2.211  #endif
   2.212  
   2.213 @@ -1875,18 +1879,21 @@ static void vmx_do_str_pio(unsigned long
   2.214      if ( !long_mode )
   2.215      {
   2.216          /* Segment must be readable for outs and writeable for ins. */
   2.217 -        if ( dir == IOREQ_WRITE ? (ar_bytes & 0xa) == 0x8
   2.218 -                                : (ar_bytes & 0xa) != 0x2 ) {
   2.219 +        if ( ((dir == IOREQ_WRITE)
   2.220 +              ? ((ar_bytes & 0xa) == 0x8)
   2.221 +              : ((ar_bytes & 0xa) != 0x2)) ||
   2.222 +             !vmx_str_pio_check_limit(limit, size, ar_bytes,
   2.223 +                                      addr, base, df, &count) )
   2.224 +        {
   2.225              vmx_inject_hw_exception(current, TRAP_gp_fault, 0);
   2.226              return;
   2.227          }
   2.228 -
   2.229 -        vmx_str_pio_check_limit(limit, size, ar_bytes, addr, base, df, &count);
   2.230      }
   2.231  #ifdef __x86_64__
   2.232 -    else
   2.233 +    else if ( !vmx_str_pio_lm_check_limit(regs, size, addr, &count) )
   2.234      {
   2.235 -        vmx_str_pio_lm_check_limit(regs, size, addr, &count);
   2.236 +        vmx_inject_hw_exception(current, TRAP_gp_fault, 0);
   2.237 +        return;
   2.238      }
   2.239  #endif
   2.240  
   2.241 @@ -2133,12 +2140,20 @@ static int vmx_assist(struct vcpu *v, in
   2.242      struct hvm_hw_vpic *vpic = v->domain->arch.hvm_domain.vpic;
   2.243      u32 magic, cp;
   2.244  
   2.245 -    /* make sure vmxassist exists (this is not an error) */
   2.246      if ( hvm_copy_from_guest_phys(&magic, VMXASSIST_MAGIC_OFFSET,
   2.247                                    sizeof(magic)) )
   2.248 +    {
   2.249 +        gdprintk(XENLOG_ERR, "No vmxassist: can't execute real mode code\n");
   2.250 +        domain_crash(v->domain);
   2.251          return 0;
   2.252 +    }
   2.253 +
   2.254      if ( magic != VMXASSIST_MAGIC )
   2.255 +    {
   2.256 +        gdprintk(XENLOG_ERR, "vmxassist magic number not match\n");
   2.257 +        domain_crash(v->domain);
   2.258          return 0;
   2.259 +    }
   2.260  
   2.261      switch ( mode ) {
   2.262          /*
   2.263 @@ -2280,28 +2295,26 @@ static int vmx_set_cr0(unsigned long val
   2.264          if ( old_base_mfn )
   2.265              put_page(mfn_to_page(old_base_mfn));
   2.266  
   2.267 -        paging_update_paging_modes(v);
   2.268 -
   2.269 -        HVM_DBG_LOG(DBG_LEVEL_VMMU, "New arch.guest_table = %lx",
   2.270 -                    (unsigned long) (mfn << PAGE_SHIFT));
   2.271 -
   2.272          HVM_DBG_LOG(DBG_LEVEL_VMMU, "Update CR3 value = %lx, mfn = %lx",
   2.273                      v->arch.hvm_vmx.cpu_cr3, mfn);
   2.274 +
   2.275 +        paging_update_paging_modes(v);
   2.276      }
   2.277  
   2.278      /* Trying to disable paging. */
   2.279      if ( ((value & (X86_CR0_PE | X86_CR0_PG)) != (X86_CR0_PE | X86_CR0_PG)) &&
   2.280           paging_enabled )
   2.281      {
   2.282 +        /* When CR0.PG is cleared, LMA is cleared immediately. */
   2.283 +        if ( vmx_long_mode_enabled(v) )
   2.284 +            vmx_disable_long_mode(v);
   2.285 +
   2.286          if ( v->arch.hvm_vmx.cpu_cr3 )
   2.287          {
   2.288              put_page(mfn_to_page(get_mfn_from_gpfn(
   2.289                        v->arch.hvm_vmx.cpu_cr3 >> PAGE_SHIFT)));
   2.290              v->arch.guest_table = pagetable_null();
   2.291          }
   2.292 -
   2.293 -        if ( vmx_long_mode_enabled(v) )
   2.294 -            vmx_disable_long_mode(v);
   2.295      }
   2.296  
   2.297      /*
   2.298 @@ -2461,8 +2474,8 @@ static int mov_to_cr(int gp, int cr, str
   2.299          {
   2.300              if ( vmx_pgbit_test(v) )
   2.301              {
   2.302 +#if CONFIG_PAGING_LEVELS >= 3
   2.303                  /* The guest is a 32-bit PAE guest. */
   2.304 -#if CONFIG_PAGING_LEVELS >= 3
   2.305                  unsigned long mfn, old_base_mfn;
   2.306                  mfn = get_mfn_from_gpfn(v->arch.hvm_vmx.cpu_cr3 >> PAGE_SHIFT);
   2.307                  if ( !mfn_valid(mfn) ||
   2.308 @@ -2477,9 +2490,6 @@ static int mov_to_cr(int gp, int cr, str
   2.309                  if ( old_base_mfn )
   2.310                      put_page(mfn_to_page(old_base_mfn));
   2.311  
   2.312 -                HVM_DBG_LOG(DBG_LEVEL_VMMU, "New arch.guest_table = %lx",
   2.313 -                            (unsigned long) (mfn << PAGE_SHIFT));
   2.314 -
   2.315                  HVM_DBG_LOG(DBG_LEVEL_VMMU,
   2.316                              "Update CR3 value = %lx, mfn = %lx",
   2.317                              v->arch.hvm_vmx.cpu_cr3, mfn);
   2.318 @@ -2645,8 +2655,15 @@ static int vmx_do_msr_read(struct cpu_us
   2.319      case MSR_IA32_VMX_BASIC...MSR_IA32_VMX_PROCBASED_CTLS2:
   2.320          goto gp_fault;
   2.321      default:
   2.322 -        if ( long_mode_do_msr_read(regs) )
   2.323 -            goto done;
   2.324 +        switch ( long_mode_do_msr_read(regs) )
   2.325 +        {
   2.326 +            case HNDL_unhandled:
   2.327 +                break;
   2.328 +            case HNDL_exception_raised:
   2.329 +                return 0;
   2.330 +            case HNDL_done:
   2.331 +                goto done;
   2.332 +        }
   2.333  
   2.334          if ( rdmsr_hypervisor_regs(ecx, &eax, &edx) ||
   2.335               rdmsr_safe(ecx, eax, edx) == 0 )
   2.336 @@ -2771,8 +2788,16 @@ static int vmx_do_msr_write(struct cpu_u
   2.337      case MSR_IA32_VMX_BASIC...MSR_IA32_VMX_PROCBASED_CTLS2:
   2.338          goto gp_fault;
   2.339      default:
   2.340 -        if ( !long_mode_do_msr_write(regs) )
   2.341 -            wrmsr_hypervisor_regs(ecx, regs->eax, regs->edx);
   2.342 +        switch ( long_mode_do_msr_write(regs) )
   2.343 +        {
   2.344 +            case HNDL_unhandled:
   2.345 +                wrmsr_hypervisor_regs(ecx, regs->eax, regs->edx);
   2.346 +                break;
   2.347 +            case HNDL_exception_raised:
   2.348 +                return 0;
   2.349 +            case HNDL_done:
   2.350 +                break;
   2.351 +        }
   2.352          break;
   2.353      }
   2.354  
   2.355 @@ -2812,7 +2837,8 @@ static void vmx_do_extint(struct cpu_use
   2.356      vector &= INTR_INFO_VECTOR_MASK;
   2.357      HVMTRACE_1D(INTR, current, vector);
   2.358  
   2.359 -    switch(vector) {
   2.360 +    switch ( vector )
   2.361 +    {
   2.362      case LOCAL_TIMER_VECTOR:
   2.363          smp_apic_timer_interrupt(regs);
   2.364          break;