ia64/xen-unstable

changeset 8852:7d89f672aa49

More fixes to HVM FPU management. Mostly for SVM, but also
fix VMX mov_to_cr0: must setup_fpu() if the new cr0 value
has TS clear, regardless of previous cr0.TS value.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Wed Feb 15 00:15:11 2006 +0100 (2006-02-15)
parents ee6f025fb264
children 166322cd55df
files xen/arch/x86/hvm/svm/svm.c xen/arch/x86/hvm/svm/vmcb.c xen/arch/x86/hvm/svm/x86_32/exits.S xen/arch/x86/hvm/vmx/vmx.c xen/arch/x86/traps.c xen/include/asm-x86/i387.h
line diff
     1.1 --- a/xen/arch/x86/hvm/svm/svm.c	Tue Feb 14 23:30:59 2006 +0100
     1.2 +++ b/xen/arch/x86/hvm/svm/svm.c	Wed Feb 15 00:15:11 2006 +0100
     1.3 @@ -701,12 +701,21 @@ void svm_stts(struct vcpu *v)
     1.4  {
     1.5      struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
     1.6  
     1.7 -    ASSERT(vmcb);    
     1.8 -
     1.9 -    vmcb->cr0 |= X86_CR0_TS;
    1.10 -
    1.11 -    if (!(v->arch.hvm_svm.cpu_shadow_cr0 & X86_CR0_TS))
    1.12 +    /* FPU state already dirty? Then no need to setup_fpu() lazily. */
    1.13 +    if ( test_bit(_VCPUF_fpu_dirtied, &v->vcpu_flags) )
    1.14 +        return;
    1.15 +
    1.16 +    /*
    1.17 +     * If the guest does not have TS enabled then we must cause and handle an 
    1.18 +     * exception on first use of the FPU. If the guest *does* have TS enabled 
    1.19 +     * then this is not necessary: no FPU activity can occur until the guest 
    1.20 +     * clears CR0.TS, and we will initialise the FPU when that happens.
    1.21 +     */
    1.22 +    if ( !(v->arch.hvm_svm.cpu_shadow_cr0 & X86_CR0_TS) )
    1.23 +    {
    1.24          v->arch.hvm_svm.vmcb->exception_intercepts |= EXCEPTION_BITMAP_NM;
    1.25 +        vmcb->cr0 |= X86_CR0_TS;
    1.26 +    }
    1.27  }
    1.28  
    1.29  static void arch_svm_do_launch(struct vcpu *v) 
    1.30 @@ -884,14 +893,11 @@ static void svm_do_no_device_fault(struc
    1.31  {
    1.32      struct vcpu *v = current;
    1.33  
    1.34 -    clts();
    1.35 -
    1.36      setup_fpu(v);    
    1.37 -
    1.38 -    if (!(v->arch.hvm_svm.cpu_shadow_cr0 & X86_CR0_TS))
    1.39 +    vmcb->exception_intercepts &= ~EXCEPTION_BITMAP_NM;
    1.40 +
    1.41 +    if ( !(v->arch.hvm_svm.cpu_shadow_cr0 & X86_CR0_TS) )
    1.42          vmcb->cr0 &= ~X86_CR0_TS;
    1.43 -    
    1.44 -    vmcb->exception_intercepts &= ~EXCEPTION_BITMAP_NM;
    1.45  }
    1.46  
    1.47  
    1.48 @@ -1350,10 +1356,11 @@ static int svm_set_cr0(unsigned long val
    1.49      vmcb->cr0 = value | X86_CR0_PG;
    1.50      v->arch.hvm_svm.cpu_shadow_cr0 = value;
    1.51  
    1.52 -    /* Check if FP Unit Trap need to be on */
    1.53 -    if (value & X86_CR0_TS)
    1.54 -    { 
    1.55 -       vmcb->exception_intercepts |= EXCEPTION_BITMAP_NM;
    1.56 +    /* TS cleared? Then initialise FPU now. */
    1.57 +    if ( !(value & X86_CR0_TS) )
    1.58 +    {
    1.59 +        setup_fpu(v);
    1.60 +        vmcb->exception_intercepts &= ~EXCEPTION_BITMAP_NM;
    1.61      }
    1.62  
    1.63      HVM_DBG_LOG(DBG_LEVEL_VMMU, "Update CR0 value = %lx\n", value);
    1.64 @@ -1669,11 +1676,11 @@ static int svm_cr_access(struct vcpu *v,
    1.65          break;
    1.66  
    1.67      case INSTR_CLTS:
    1.68 -        clts();
    1.69 +        /* TS being cleared means that it's time to restore fpu state. */
    1.70          setup_fpu(current);
    1.71 +        vmcb->exception_intercepts &= ~EXCEPTION_BITMAP_NM;
    1.72          vmcb->cr0 &= ~X86_CR0_TS; /* clear TS */
    1.73          v->arch.hvm_svm.cpu_shadow_cr0 &= ~X86_CR0_TS; /* clear TS */
    1.74 -        vmcb->exception_intercepts &= ~EXCEPTION_BITMAP_NM;
    1.75          break;
    1.76  
    1.77      case INSTR_LMSW:
    1.78 @@ -1803,11 +1810,8 @@ static inline void svm_vmexit_do_hlt(str
    1.79      struct vcpu *v = current;
    1.80      struct hvm_virpit *vpit = &v->domain->arch.hvm_domain.vpit;
    1.81      s_time_t  next_pit = -1, next_wakeup;
    1.82 -    unsigned int inst_len;
    1.83 -
    1.84 -    svm_stts(v);
    1.85 -    inst_len = __get_instruction_length(vmcb, INSTR_HLT, NULL);
    1.86 -    __update_guest_eip(vmcb, inst_len);
    1.87 +
    1.88 +    __update_guest_eip(vmcb, 1);
    1.89  
    1.90      if ( !v->vcpu_id )
    1.91          next_pit = get_pit_scheduled(v, vpit);
    1.92 @@ -1822,7 +1826,6 @@ static inline void svm_vmexit_do_hlt(str
    1.93  
    1.94  static inline void svm_vmexit_do_mwait(void)
    1.95  {
    1.96 -    return;
    1.97  }
    1.98  
    1.99  
   1.100 @@ -2494,7 +2497,6 @@ asmlinkage void svm_vmexit_handler(struc
   1.101          break;
   1.102  
   1.103      case VMEXIT_INTR:
   1.104 -        svm_stts(v);
   1.105          raise_softirq(SCHEDULE_SOFTIRQ);
   1.106          break;
   1.107  
     2.1 --- a/xen/arch/x86/hvm/svm/vmcb.c	Tue Feb 14 23:30:59 2006 +0100
     2.2 +++ b/xen/arch/x86/hvm/svm/vmcb.c	Wed Feb 15 00:15:11 2006 +0100
     2.3 @@ -489,7 +489,9 @@ void svm_do_resume(struct vcpu *v)
     2.4  {
     2.5      struct domain *d = v->domain;
     2.6      struct hvm_virpit *vpit = &d->arch.hvm_domain.vpit;
     2.7 -    
     2.8 +
     2.9 +    svm_stts(v);
    2.10 +
    2.11      if ( test_bit(iopacket_port(d), &d->shared_info->evtchn_pending[0]) ||
    2.12           test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags) )
    2.13          hvm_wait_io();
    2.14 @@ -498,7 +500,7 @@ void svm_do_resume(struct vcpu *v)
    2.15      if ( vpit->first_injected )
    2.16          pickup_deactive_ticks(vpit);
    2.17      svm_set_tsc_shift(v, vpit);
    2.18 -    
    2.19 +
    2.20      /* We can't resume the guest if we're waiting on I/O */
    2.21      ASSERT(!test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags));
    2.22  }
     3.1 --- a/xen/arch/x86/hvm/svm/x86_32/exits.S	Tue Feb 14 23:30:59 2006 +0100
     3.2 +++ b/xen/arch/x86/hvm/svm/x86_32/exits.S	Wed Feb 15 00:15:11 2006 +0100
     3.3 @@ -89,7 +89,7 @@
     3.4  #define CLGI   .byte 0x0F,0x01,0xDD
     3.5  
     3.6  #define DO_TSC_OFFSET 0
     3.7 -#define DO_FPUSAVE    1
     3.8 +#define DO_FPUSAVE    0
     3.9          
    3.10  ENTRY(svm_asm_do_launch)
    3.11          sti
     4.1 --- a/xen/arch/x86/hvm/vmx/vmx.c	Tue Feb 14 23:30:59 2006 +0100
     4.2 +++ b/xen/arch/x86/hvm/vmx/vmx.c	Wed Feb 15 00:15:11 2006 +0100
     4.3 @@ -615,8 +615,8 @@ static void vmx_do_no_device_fault(void)
     4.4      unsigned long cr0;
     4.5      struct vcpu *v = current;
     4.6  
     4.7 -    clts();
     4.8      setup_fpu(current);
     4.9 +    __vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_NM);
    4.10  
    4.11      /* Disable TS in guest CR0 unless the guest wants the exception too. */
    4.12      __vmread_vcpu(v, CR0_READ_SHADOW, &cr0);
    4.13 @@ -626,9 +626,6 @@ static void vmx_do_no_device_fault(void)
    4.14          cr0 &= ~X86_CR0_TS;
    4.15          __vmwrite(GUEST_CR0, cr0);
    4.16      }
    4.17 -
    4.18 -    /* Xen itself doesn't need another exception. */
    4.19 -    __vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_NM);
    4.20  }
    4.21  
    4.22  /* Reserved bits: [31:15], [12:11], [9], [6], [2:1] */
    4.23 @@ -1158,14 +1155,11 @@ static int vmx_set_cr0(unsigned long val
    4.24      __vmread_vcpu(v, CR0_READ_SHADOW, &old_cr0);
    4.25      paging_enabled = (old_cr0 & X86_CR0_PE) && (old_cr0 & X86_CR0_PG);
    4.26  
    4.27 -    /*
    4.28 -     * Disable TS? Then we do so at the same time, and initialise FPU.
    4.29 -     * This avoids needing another vmexit.
    4.30 -     */
    4.31 -    if ( (old_cr0 & ~value & X86_CR0_TS) != 0 )
    4.32 +    /* TS cleared? Then initialise FPU now. */
    4.33 +    if ( !(value & X86_CR0_TS) )
    4.34      {
    4.35 -        clts();
    4.36          setup_fpu(v);
    4.37 +        __vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_NM);
    4.38      }
    4.39  
    4.40      __vmwrite(GUEST_CR0, value | X86_CR0_PE | X86_CR0_PG | X86_CR0_NE);
    4.41 @@ -1520,8 +1514,8 @@ static int vmx_cr_access(unsigned long e
    4.42          TRACE_VMEXIT(1,TYPE_CLTS);
    4.43  
    4.44          /* We initialise the FPU now, to avoid needing another vmexit. */
    4.45 -        clts();
    4.46 -        setup_fpu(current);
    4.47 +        setup_fpu(v);
    4.48 +        __vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_NM);
    4.49  
    4.50          __vmread_vcpu(v, GUEST_CR0, &value);
    4.51          value &= ~X86_CR0_TS; /* clear TS */
     5.1 --- a/xen/arch/x86/traps.c	Tue Feb 14 23:30:59 2006 +0100
     5.2 +++ b/xen/arch/x86/traps.c	Wed Feb 15 00:15:11 2006 +0100
     5.3 @@ -1261,9 +1261,6 @@ asmlinkage int math_state_restore(struct
     5.4      struct trap_bounce *tb;
     5.5      struct trap_info *ti;
     5.6  
     5.7 -    /* Prevent recursion. */
     5.8 -    clts();
     5.9 -
    5.10      setup_fpu(current);
    5.11  
    5.12      if ( current->arch.guest_context.ctrlreg[0] & X86_CR0_TS )
     6.1 --- a/xen/include/asm-x86/i387.h	Tue Feb 14 23:30:59 2006 +0100
     6.2 +++ b/xen/include/asm-x86/i387.h	Wed Feb 15 00:15:11 2006 +0100
     6.3 @@ -33,6 +33,7 @@ static inline void setup_fpu(struct vcpu
     6.4  {
     6.5      if ( !test_and_set_bit(_VCPUF_fpu_dirtied, &v->vcpu_flags) )
     6.6      {
     6.7 +        clts();
     6.8          if ( test_bit(_VCPUF_fpu_initialised, &v->vcpu_flags) )
     6.9              restore_fpu(v);
    6.10          else