ia64/xen-unstable

changeset 9334:56a775219c88

This patch fix HVM/VMX time resolution issue that cause IA32E complain
"loss tick" occationally and APIC time calibration issue.

Signed-off-by: Xiaowei Yang <xiaowei.yang@intel.com>
Signed-off-by: Eddie Dong <eddie.dong@intel.com>
author kaf24@firebug.cl.cam.ac.uk
date Sun Mar 19 18:52:20 2006 +0100 (2006-03-19)
parents 760f9149dbaa
children 1ecb7f1ddc79
files xen/arch/x86/hvm/intercept.c xen/arch/x86/hvm/vmx/io.c xen/arch/x86/hvm/vmx/vmcs.c xen/arch/x86/hvm/vmx/vmx.c xen/include/asm-x86/hvm/domain.h xen/include/asm-x86/hvm/vmx/vmcs.h xen/include/asm-x86/hvm/vmx/vmx.h xen/include/asm-x86/hvm/vpit.h
line diff
     1.1 --- a/xen/arch/x86/hvm/intercept.c	Sun Mar 19 17:10:20 2006 +0100
     1.2 +++ b/xen/arch/x86/hvm/intercept.c	Sun Mar 19 18:52:20 2006 +0100
     1.3 @@ -338,10 +338,10 @@ void hlt_timer_fn(void *data)
     1.4  
     1.5  static __inline__ void missed_ticks(struct hvm_virpit*vpit)
     1.6  {
     1.7 -    int        missed_ticks;
     1.8 +    int missed_ticks;
     1.9  
    1.10      missed_ticks = (NOW() - vpit->scheduled)/(s_time_t) vpit->period;
    1.11 -    if ( missed_ticks > 0 ) {
    1.12 +    if ( missed_ticks++ >= 0 ) {
    1.13          vpit->pending_intr_nr += missed_ticks;
    1.14          vpit->scheduled += missed_ticks * vpit->period;
    1.15      }
    1.16 @@ -355,22 +355,16 @@ static void pit_timer_fn(void *data)
    1.17  
    1.18      /* pick up missed timer tick */
    1.19      missed_ticks(vpit);
    1.20 -
    1.21 -    vpit->pending_intr_nr++;
    1.22      if ( test_bit(_VCPUF_running, &v->vcpu_flags) ) {
    1.23 -        vpit->scheduled += vpit->period;
    1.24          set_timer(&vpit->pit_timer, vpit->scheduled);
    1.25      }
    1.26  }
    1.27  
    1.28 +/* pick up missed timer ticks at deactive time */
    1.29  void pickup_deactive_ticks(struct hvm_virpit *vpit)
    1.30  {
    1.31 -
    1.32      if ( !active_timer(&(vpit->pit_timer)) ) {
    1.33 -        /* pick up missed timer tick */
    1.34          missed_ticks(vpit);
    1.35 -    
    1.36 -        vpit->scheduled += vpit->period;
    1.37          set_timer(&vpit->pit_timer, vpit->scheduled);
    1.38      }
    1.39  }
     2.1 --- a/xen/arch/x86/hvm/vmx/io.c	Sun Mar 19 17:10:20 2006 +0100
     2.2 +++ b/xen/arch/x86/hvm/vmx/io.c	Sun Mar 19 18:52:20 2006 +0100
     2.3 @@ -40,20 +40,33 @@
     2.4  
     2.5  #define BSP_CPU(v)    (!(v->vcpu_id))
     2.6  
     2.7 -void vmx_set_tsc_shift(struct vcpu *v, struct hvm_virpit *vpit)
     2.8 +static inline 
     2.9 +void __set_tsc_offset(u64  offset)
    2.10  {
    2.11 -    u64   drift;
    2.12 +    __vmwrite(TSC_OFFSET, offset);
    2.13 +#if defined (__i386__)
    2.14 +    __vmwrite(TSC_OFFSET_HIGH, offset >> 32);
    2.15 +#endif
    2.16 +}
    2.17  
    2.18 -    if ( vpit->first_injected )
    2.19 -        drift = vpit->period_cycles * vpit->pending_intr_nr;
    2.20 -    else 
    2.21 -        drift = 0;
    2.22 -    vpit->shift = v->arch.hvm_vmx.tsc_offset - drift;
    2.23 -    __vmwrite(TSC_OFFSET, vpit->shift);
    2.24 +u64 get_guest_time(struct vcpu *v)
    2.25 +{
    2.26 +    struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
    2.27 +    u64    host_tsc;
    2.28 +    
    2.29 +    rdtscll(host_tsc);
    2.30 +    return host_tsc + vpit->cache_tsc_offset;
    2.31 +}
    2.32  
    2.33 -#if defined (__i386__)
    2.34 -    __vmwrite(TSC_OFFSET_HIGH, ((vpit->shift)>> 32));
    2.35 -#endif
    2.36 +void set_guest_time(struct vcpu *v, u64 gtime)
    2.37 +{
    2.38 +    struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
    2.39 +    u64    host_tsc;
    2.40 +   
    2.41 +    rdtscll(host_tsc);
    2.42 +    
    2.43 +    vpit->cache_tsc_offset = gtime - host_tsc;
    2.44 +    __set_tsc_offset(vpit->cache_tsc_offset);
    2.45  }
    2.46  
    2.47  static inline void
    2.48 @@ -64,6 +77,7 @@ interrupt_post_injection(struct vcpu * v
    2.49      if ( is_pit_irq(v, vector, type) ) {
    2.50          if ( !vpit->first_injected ) {
    2.51              vpit->pending_intr_nr = 0;
    2.52 +            vpit->last_pit_gtime = get_guest_time(v);
    2.53              vpit->scheduled = NOW() + vpit->period;
    2.54              set_timer(&vpit->pit_timer, vpit->scheduled);
    2.55              vpit->first_injected = 1;
    2.56 @@ -71,7 +85,9 @@ interrupt_post_injection(struct vcpu * v
    2.57              vpit->pending_intr_nr--;
    2.58          }
    2.59          vpit->inject_point = NOW();
    2.60 -        vmx_set_tsc_shift (v, vpit);
    2.61 +
    2.62 +        vpit->last_pit_gtime += vpit->period;
    2.63 +        set_guest_time(v, vpit->last_pit_gtime);
    2.64      }
    2.65  
    2.66      switch(type)
    2.67 @@ -189,15 +205,16 @@ void vmx_do_resume(struct vcpu *v)
    2.68  
    2.69      vmx_stts();
    2.70  
    2.71 +    /* pick up the elapsed PIT ticks and re-enable pit_timer */
    2.72 +    if ( vpit->first_injected) {
    2.73 +        set_guest_time(v, v->domain->arch.hvm_domain.guest_time);
    2.74 +        pickup_deactive_ticks(vpit);
    2.75 +    }
    2.76 +
    2.77      if ( test_bit(iopacket_port(v), &d->shared_info->evtchn_pending[0]) ||
    2.78           test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags) )
    2.79          hvm_wait_io();
    2.80  
    2.81 -    /* pick up the elapsed PIT ticks and re-enable pit_timer */
    2.82 -    if ( vpit->first_injected )
    2.83 -        pickup_deactive_ticks(vpit);
    2.84 -    vmx_set_tsc_shift(v, vpit);
    2.85 -
    2.86      /* We can't resume the guest if we're waiting on I/O */
    2.87      ASSERT(!test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags));
    2.88  }
     3.1 --- a/xen/arch/x86/hvm/vmx/vmcs.c	Sun Mar 19 17:10:20 2006 +0100
     3.2 +++ b/xen/arch/x86/hvm/vmx/vmcs.c	Sun Mar 19 18:52:20 2006 +0100
     3.3 @@ -195,7 +195,6 @@ static void vmx_do_launch(struct vcpu *v
     3.4  /* Update CR3, GDT, LDT, TR */
     3.5      unsigned int  error = 0;
     3.6      unsigned long cr0, cr4;
     3.7 -    u64     host_tsc;
     3.8  
     3.9      if (v->vcpu_id == 0)
    3.10          hvm_setup_platform(v->domain);
    3.11 @@ -250,9 +249,7 @@ static void vmx_do_launch(struct vcpu *v
    3.12      v->arch.hvm_vmx.launch_cpu = smp_processor_id();
    3.13  
    3.14      /* init guest tsc to start from 0 */
    3.15 -    rdtscll(host_tsc);
    3.16 -    v->arch.hvm_vmx.tsc_offset = 0 - host_tsc;
    3.17 -    vmx_set_tsc_shift(v, &v->domain->arch.hvm_domain.vpit);
    3.18 +    set_guest_time(v, 0);
    3.19  }
    3.20  
    3.21  /*
     4.1 --- a/xen/arch/x86/hvm/vmx/vmx.c	Sun Mar 19 17:10:20 2006 +0100
     4.2 +++ b/xen/arch/x86/hvm/vmx/vmx.c	Sun Mar 19 18:52:20 2006 +0100
     4.3 @@ -354,8 +354,18 @@ static inline int long_mode_do_msr_write
     4.4  
     4.5  #endif /* __i386__ */
     4.6  
     4.7 +static void vmx_freeze_time(struct vcpu *v)
     4.8 +{
     4.9 +    struct hvm_virpit *vpit = &v->domain->arch.hvm_domain.vpit;
    4.10 +    
    4.11 +    v->domain->arch.hvm_domain.guest_time = get_guest_time(v);
    4.12 +    if ( vpit->first_injected )
    4.13 +        stop_timer(&(vpit->pit_timer));
    4.14 +}
    4.15 +
    4.16  static void vmx_ctxt_switch_from(struct vcpu *v)
    4.17  {
    4.18 +    vmx_freeze_time(v);
    4.19      vmx_save_segments(v);
    4.20      vmx_load_msrs();
    4.21  }
    4.22 @@ -1707,7 +1717,7 @@ static inline void vmx_do_msr_read(struc
    4.23  
    4.24          rdtscll(msr_content);
    4.25          vpit = &(v->domain->arch.hvm_domain.vpit);
    4.26 -        msr_content += vpit->shift;
    4.27 +        msr_content += vpit->cache_tsc_offset;
    4.28          break;
    4.29      }
    4.30      case MSR_IA32_SYSENTER_CS:
    4.31 @@ -1751,22 +1761,8 @@ static inline void vmx_do_msr_write(stru
    4.32  
    4.33      switch (regs->ecx) {
    4.34      case MSR_IA32_TIME_STAMP_COUNTER:
    4.35 -    {
    4.36 -        struct hvm_virpit *vpit;
    4.37 -        u64 host_tsc, drift;
    4.38 -
    4.39 -        rdtscll(host_tsc);
    4.40 -        vpit = &(v->domain->arch.hvm_domain.vpit);
    4.41 -        drift = v->arch.hvm_vmx.tsc_offset - vpit->shift;
    4.42 -        vpit->shift = msr_content - host_tsc;
    4.43 -	v->arch.hvm_vmx.tsc_offset = vpit->shift + drift;
    4.44 -        __vmwrite(TSC_OFFSET, vpit->shift);
    4.45 -
    4.46 -#if defined (__i386__)
    4.47 -        __vmwrite(TSC_OFFSET_HIGH, ((vpit->shift)>>32));
    4.48 -#endif
    4.49 +        set_guest_time(v, msr_content);
    4.50          break;
    4.51 -    }
    4.52      case MSR_IA32_SYSENTER_CS:
    4.53          __vmwrite(GUEST_SYSENTER_CS, msr_content);
    4.54          break;
     5.1 --- a/xen/include/asm-x86/hvm/domain.h	Sun Mar 19 17:10:20 2006 +0100
     5.2 +++ b/xen/include/asm-x86/hvm/domain.h	Sun Mar 19 18:52:20 2006 +0100
     5.3 @@ -37,6 +37,7 @@ struct hvm_domain {
     5.4      unsigned int           pae_enabled;
     5.5  
     5.6      struct hvm_virpit      vpit;
     5.7 +    u64                    guest_time;
     5.8      struct hvm_virpic      vpic;
     5.9      struct hvm_vioapic     vioapic;
    5.10      struct hvm_io_handler  io_handler;
     6.1 --- a/xen/include/asm-x86/hvm/vmx/vmcs.h	Sun Mar 19 17:10:20 2006 +0100
     6.2 +++ b/xen/include/asm-x86/hvm/vmx/vmcs.h	Sun Mar 19 18:52:20 2006 +0100
     6.3 @@ -77,7 +77,6 @@ struct arch_vmx_struct {
     6.4      unsigned long           cpu_based_exec_control;
     6.5      struct vmx_msr_state    msr_content;
     6.6      void                    *io_bitmap_a, *io_bitmap_b;
     6.7 -    u64                     tsc_offset;
     6.8      struct timer            hlt_timer;  /* hlt ins emulation wakeup timer */
     6.9  };
    6.10  
     7.1 --- a/xen/include/asm-x86/hvm/vmx/vmx.h	Sun Mar 19 17:10:20 2006 +0100
     7.2 +++ b/xen/include/asm-x86/hvm/vmx/vmx.h	Sun Mar 19 18:52:20 2006 +0100
     7.3 @@ -30,10 +30,11 @@ extern void vmx_asm_vmexit_handler(struc
     7.4  extern void vmx_asm_do_resume(void);
     7.5  extern void vmx_asm_do_launch(void);
     7.6  extern void vmx_intr_assist(void);
     7.7 -extern void vmx_set_tsc_shift(struct vcpu *, struct hvm_virpit *);
     7.8  extern void vmx_migrate_timers(struct vcpu *v);
     7.9  extern void arch_vmx_do_launch(struct vcpu *);
    7.10  extern void arch_vmx_do_resume(struct vcpu *);
    7.11 +extern void set_guest_time(struct vcpu *v, u64 gtime);
    7.12 +extern u64  get_guest_time(struct vcpu *v);
    7.13  
    7.14  extern unsigned int cpu_rev;
    7.15  
     8.1 --- a/xen/include/asm-x86/hvm/vpit.h	Sun Mar 19 17:10:20 2006 +0100
     8.2 +++ b/xen/include/asm-x86/hvm/vpit.h	Sun Mar 19 18:52:20 2006 +0100
     8.3 @@ -38,7 +38,6 @@
     8.4  struct hvm_virpit {
     8.5      /* for simulation of counter 0 in mode 2 */
     8.6      u64 period_cycles;          /* pit frequency in cpu cycles */
     8.7 -    u64 shift;                  /* save the value of offset - drift */
     8.8      s_time_t inject_point;      /* the time inject virt intr */
     8.9      s_time_t scheduled;         /* scheduled timer interrupt */
    8.10      struct timer pit_timer;     /* periodic timer for mode 2*/
    8.11 @@ -46,6 +45,8 @@ struct hvm_virpit {
    8.12      unsigned int pending_intr_nr; /* the couner for pending timer interrupts */
    8.13      u32 period;                 /* pit frequency in ns */
    8.14      int first_injected;         /* flag to prevent shadow window */
    8.15 +    s64 cache_tsc_offset;       /* cache of VMCS TSC_OFFSET offset */
    8.16 +    u64 last_pit_gtime;         /* guest time when last pit is injected */
    8.17  
    8.18      /* virtual PIT state for handle related I/O */
    8.19      int read_state;