ia64/xen-unstable

changeset 17720:6c4cab061af4

hvm: Build guest timers on monotonic system time.

Move hvm platform timers from underlying physical CPU TSC to Xen
system time and ensure domain-wide monotonicity. TSC on many systems
may skew between processors leading to 'time going backwards' messages
from some guests.

Signed-off-by: Dan Magenheimer <dan.magenheimer@oracle.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Sat May 24 09:27:03 2008 +0100 (2008-05-24)
parents 30bf34f5a414
children c4506386b299
files xen/arch/x86/hvm/hpet.c xen/arch/x86/hvm/hvm.c xen/arch/x86/hvm/i8254.c xen/arch/x86/hvm/pmtimer.c xen/arch/x86/hvm/svm/svm.c xen/arch/x86/hvm/vlapic.c xen/arch/x86/hvm/vmx/vmx.c xen/arch/x86/hvm/vpt.c xen/include/asm-x86/hvm/hvm.h xen/include/asm-x86/hvm/vcpu.h xen/include/asm-x86/hvm/vmx/vmx.h xen/include/asm-x86/hvm/vpt.h xen/include/xen/time.h
line diff
     1.1 --- a/xen/arch/x86/hvm/hpet.c	Sat May 24 08:54:59 2008 +0100
     1.2 +++ b/xen/arch/x86/hvm/hpet.c	Sat May 24 09:27:03 2008 +0100
     1.3 @@ -29,9 +29,9 @@
     1.4  #define S_TO_NS  1000000000ULL           /* 1s  = 10^9  ns */
     1.5  #define S_TO_FS  1000000000000000ULL     /* 1s  = 10^15 fs */
     1.6  
     1.7 -/* Frequency_of_TSC / frequency_of_HPET = 32 */
     1.8 -#define TSC_PER_HPET_TICK 32
     1.9 -#define guest_time_hpet(v) (hvm_get_guest_time(v) / TSC_PER_HPET_TICK)
    1.10 +/* Frequency_of_Xen_systeme_time / frequency_of_HPET = 16 */
    1.11 +#define STIME_PER_HPET_TICK 16
    1.12 +#define guest_time_hpet(v) (hvm_get_guest_time(v) / STIME_PER_HPET_TICK)
    1.13  
    1.14  #define HPET_ID         0x000
    1.15  #define HPET_PERIOD     0x004
    1.16 @@ -192,7 +192,7 @@ static void hpet_stop_timer(HPETState *h
    1.17  
    1.18  /* the number of HPET tick that stands for
    1.19   * 1/(2^10) second, namely, 0.9765625 milliseconds */
    1.20 -#define  HPET_TINY_TIME_SPAN  ((h->tsc_freq >> 10) / TSC_PER_HPET_TICK)
    1.21 +#define  HPET_TINY_TIME_SPAN  ((h->stime_freq >> 10) / STIME_PER_HPET_TICK)
    1.22  
    1.23  static void hpet_set_timer(HPETState *h, unsigned int tn)
    1.24  {
    1.25 @@ -558,17 +558,17 @@ void hpet_init(struct vcpu *v)
    1.26      spin_lock_init(&h->lock);
    1.27  
    1.28      h->vcpu = v;
    1.29 -    h->tsc_freq = ticks_per_sec(v);
    1.30 +    h->stime_freq = S_TO_NS;
    1.31  
    1.32 -    h->hpet_to_ns_scale = ((S_TO_NS * TSC_PER_HPET_TICK) << 10) / h->tsc_freq;
    1.33 +    h->hpet_to_ns_scale = ((S_TO_NS * STIME_PER_HPET_TICK) << 10) / h->stime_freq;
    1.34      h->hpet_to_ns_limit = ~0ULL / h->hpet_to_ns_scale;
    1.35  
    1.36      /* 64-bit main counter; 3 timers supported; LegacyReplacementRoute. */
    1.37      h->hpet.capability = 0x8086A201ULL;
    1.38  
    1.39      /* This is the number of femptoseconds per HPET tick. */
    1.40 -    /* Here we define HPET's frequency to be 1/32 of the TSC's */
    1.41 -    h->hpet.capability |= ((S_TO_FS*TSC_PER_HPET_TICK/h->tsc_freq) << 32);
    1.42 +    /* Here we define HPET's frequency to be 1/16 of Xen system time */
    1.43 +    h->hpet.capability |= ((S_TO_FS*STIME_PER_HPET_TICK/h->stime_freq) << 32);
    1.44  
    1.45      for ( i = 0; i < HPET_TIMER_NUM; i++ )
    1.46      {
     2.1 --- a/xen/arch/x86/hvm/hvm.c	Sat May 24 08:54:59 2008 +0100
     2.2 +++ b/xen/arch/x86/hvm/hvm.c	Sat May 24 09:27:03 2008 +0100
     2.3 @@ -296,6 +296,8 @@ int hvm_domain_initialise(struct domain 
     2.4      spin_lock_init(&d->arch.hvm_domain.irq_lock);
     2.5      spin_lock_init(&d->arch.hvm_domain.uc_lock);
     2.6  
     2.7 +    hvm_init_guest_time(d);
     2.8 +
     2.9      d->arch.hvm_domain.params[HVM_PARAM_HPET_ENABLED] = 1;
    2.10  
    2.11      hvm_init_cacheattr_region_list(d);
    2.12 @@ -661,7 +663,7 @@ int hvm_vcpu_initialise(struct vcpu *v)
    2.13          hpet_init(v);
    2.14   
    2.15          /* Init guest TSC to start from zero. */
    2.16 -        hvm_set_guest_time(v, 0);
    2.17 +        hvm_set_guest_tsc(v, 0);
    2.18  
    2.19          /* Can start up without SIPI-SIPI or setvcpucontext domctl. */
    2.20          v->is_initialised = 1;
    2.21 @@ -1632,7 +1634,7 @@ int hvm_msr_read_intercept(struct cpu_us
    2.22      switch ( ecx )
    2.23      {
    2.24      case MSR_IA32_TSC:
    2.25 -        msr_content = hvm_get_guest_time(v);
    2.26 +        msr_content = hvm_get_guest_tsc(v);
    2.27          break;
    2.28  
    2.29      case MSR_IA32_APICBASE:
    2.30 @@ -1725,7 +1727,7 @@ int hvm_msr_write_intercept(struct cpu_u
    2.31      switch ( ecx )
    2.32      {
    2.33       case MSR_IA32_TSC:
    2.34 -        hvm_set_guest_time(v, msr_content);
    2.35 +        hvm_set_guest_tsc(v, msr_content);
    2.36          pt_reset(v);
    2.37          break;
    2.38  
     3.1 --- a/xen/arch/x86/hvm/i8254.c	Sat May 24 08:54:59 2008 +0100
     3.2 +++ b/xen/arch/x86/hvm/i8254.c	Sat May 24 09:27:03 2008 +0100
     3.3 @@ -31,6 +31,7 @@
     3.4  #include <xen/lib.h>
     3.5  #include <xen/errno.h>
     3.6  #include <xen/sched.h>
     3.7 +#include <asm/time.h>
     3.8  #include <asm/hvm/hvm.h>
     3.9  #include <asm/hvm/io.h>
    3.10  #include <asm/hvm/support.h>
    3.11 @@ -87,7 +88,7 @@ static int pit_get_count(PITState *pit, 
    3.12      ASSERT(spin_is_locked(&pit->lock));
    3.13  
    3.14      d = muldiv64(hvm_get_guest_time(v) - pit->count_load_time[channel],
    3.15 -                 PIT_FREQ, ticks_per_sec(v));
    3.16 +                 PIT_FREQ, SYSTEM_TIME_HZ);
    3.17  
    3.18      switch ( c->mode )
    3.19      {
    3.20 @@ -118,7 +119,7 @@ static int pit_get_out(PITState *pit, in
    3.21      ASSERT(spin_is_locked(&pit->lock));
    3.22  
    3.23      d = muldiv64(hvm_get_guest_time(v) - pit->count_load_time[channel], 
    3.24 -                 PIT_FREQ, ticks_per_sec(v));
    3.25 +                 PIT_FREQ, SYSTEM_TIME_HZ);
    3.26  
    3.27      switch ( s->mode )
    3.28      {
    3.29 @@ -195,11 +196,11 @@ static void pit_load_count(PITState *pit
    3.30          val = 0x10000;
    3.31  
    3.32      if ( v == NULL )
    3.33 -        rdtscll(pit->count_load_time[channel]);
    3.34 +        pit->count_load_time[channel] = 0;
    3.35      else
    3.36          pit->count_load_time[channel] = hvm_get_guest_time(v);
    3.37      s->count = val;
    3.38 -    period = DIV_ROUND((val * 1000000000ULL), PIT_FREQ);
    3.39 +    period = DIV_ROUND(val * SYSTEM_TIME_HZ, PIT_FREQ);
    3.40  
    3.41      if ( (v == NULL) || !is_hvm_vcpu(v) || (channel != 0) )
    3.42          return;
     4.1 --- a/xen/arch/x86/hvm/pmtimer.c	Sat May 24 08:54:59 2008 +0100
     4.2 +++ b/xen/arch/x86/hvm/pmtimer.c	Sat May 24 09:27:03 2008 +0100
     4.3 @@ -257,7 +257,7 @@ void pmtimer_init(struct vcpu *v)
     4.4  
     4.5      spin_lock_init(&s->lock);
     4.6  
     4.7 -    s->scale = ((uint64_t)FREQUENCE_PMTIMER << 32) / ticks_per_sec(v);
     4.8 +    s->scale = ((uint64_t)FREQUENCE_PMTIMER << 32) / SYSTEM_TIME_HZ;
     4.9      s->vcpu = v;
    4.10  
    4.11      /* Intercept port I/O (need two handlers because PM1a_CNT is between
     5.1 --- a/xen/arch/x86/hvm/svm/svm.c	Sat May 24 08:54:59 2008 +0100
     5.2 +++ b/xen/arch/x86/hvm/svm/svm.c	Sat May 24 09:27:03 2008 +0100
     5.3 @@ -299,7 +299,7 @@ static void svm_save_cpu_state(struct vc
     5.4      data->msr_efer         = v->arch.hvm_vcpu.guest_efer;
     5.5      data->msr_flags        = -1ULL;
     5.6  
     5.7 -    data->tsc = hvm_get_guest_time(v);
     5.8 +    data->tsc = hvm_get_guest_tsc(v);
     5.9  }
    5.10  
    5.11  
    5.12 @@ -315,7 +315,7 @@ static void svm_load_cpu_state(struct vc
    5.13      v->arch.hvm_vcpu.guest_efer = data->msr_efer;
    5.14      svm_update_guest_efer(v);
    5.15  
    5.16 -    hvm_set_guest_time(v, data->tsc);
    5.17 +    hvm_set_guest_tsc(v, data->tsc);
    5.18  }
    5.19  
    5.20  static void svm_save_vmcb_ctxt(struct vcpu *v, struct hvm_hw_cpu *ctxt)
     6.1 --- a/xen/arch/x86/hvm/vlapic.c	Sat May 24 08:54:59 2008 +0100
     6.2 +++ b/xen/arch/x86/hvm/vlapic.c	Sat May 24 09:27:03 2008 +0100
     6.3 @@ -473,7 +473,6 @@ static uint32_t vlapic_get_tmcct(struct 
     6.4      uint64_t counter_passed;
     6.5  
     6.6      counter_passed = ((hvm_get_guest_time(v) - vlapic->timer_last_update)
     6.7 -                      * 1000000000ULL / ticks_per_sec(v)
     6.8                        / APIC_BUS_CYCLE_NS / vlapic->hw.timer_divisor);
     6.9      tmcct = tmict - counter_passed;
    6.10  
     7.1 --- a/xen/arch/x86/hvm/vmx/vmx.c	Sat May 24 08:54:59 2008 +0100
     7.2 +++ b/xen/arch/x86/hvm/vmx/vmx.c	Sat May 24 09:27:03 2008 +0100
     7.3 @@ -607,7 +607,7 @@ static void vmx_save_cpu_state(struct vc
     7.4      data->msr_syscall_mask = guest_state->msrs[VMX_INDEX_MSR_SYSCALL_MASK];
     7.5  #endif
     7.6  
     7.7 -    data->tsc = hvm_get_guest_time(v);
     7.8 +    data->tsc = hvm_get_guest_tsc(v);
     7.9  }
    7.10  
    7.11  static void vmx_load_cpu_state(struct vcpu *v, struct hvm_hw_cpu *data)
    7.12 @@ -625,7 +625,7 @@ static void vmx_load_cpu_state(struct vc
    7.13      v->arch.hvm_vmx.shadow_gs = data->shadow_gs;
    7.14  #endif
    7.15  
    7.16 -    hvm_set_guest_time(v, data->tsc);
    7.17 +    hvm_set_guest_tsc(v, data->tsc);
    7.18  }
    7.19  
    7.20  
     8.1 --- a/xen/arch/x86/hvm/vpt.c	Sat May 24 08:54:59 2008 +0100
     8.2 +++ b/xen/arch/x86/hvm/vpt.c	Sat May 24 09:27:03 2008 +0100
     8.3 @@ -25,6 +25,36 @@
     8.4  #define mode_is(d, name) \
     8.5      ((d)->arch.hvm_domain.params[HVM_PARAM_TIMER_MODE] == HVMPTM_##name)
     8.6  
     8.7 +void hvm_init_guest_time(struct domain *d)
     8.8 +{
     8.9 +    struct pl_time *pl = &d->arch.hvm_domain.pl_time;
    8.10 +
    8.11 +    spin_lock_init(&pl->pl_time_lock);
    8.12 +    pl->stime_offset = -(u64)get_s_time();
    8.13 +    pl->last_guest_time = 0;
    8.14 +}
    8.15 +
    8.16 +u64 hvm_get_guest_time(struct vcpu *v)
    8.17 +{
    8.18 +    struct pl_time *pl = &v->domain->arch.hvm_domain.pl_time;
    8.19 +    u64 now;
    8.20 +
    8.21 +    spin_lock(&pl->pl_time_lock);
    8.22 +    now = get_s_time() + pl->stime_offset;
    8.23 +    if ( (int64_t)(now - pl->last_guest_time) >= 0 )
    8.24 +        pl->last_guest_time = now;
    8.25 +    else
    8.26 +        now = pl->last_guest_time;
    8.27 +    spin_unlock(&pl->pl_time_lock);
    8.28 +
    8.29 +    return now + v->arch.hvm_vcpu.stime_offset;
    8.30 +}
    8.31 +
    8.32 +void hvm_set_guest_time(struct vcpu *v, u64 guest_time)
    8.33 +{
    8.34 +    v->arch.hvm_vcpu.stime_offset += guest_time - hvm_get_guest_time(v);
    8.35 +}
    8.36 +
    8.37  static int pt_irq_vector(struct periodic_time *pt, enum hvm_intsrc src)
    8.38  {
    8.39      struct vcpu *v = pt->vcpu;
    8.40 @@ -348,7 +378,7 @@ void create_periodic_time(
    8.41      pt->vcpu = v;
    8.42      pt->last_plt_gtime = hvm_get_guest_time(pt->vcpu);
    8.43      pt->irq = irq;
    8.44 -    pt->period_cycles = (u64)period * cpu_khz / 1000000L;
    8.45 +    pt->period_cycles = (u64)period;
    8.46      pt->one_shot = one_shot;
    8.47      pt->scheduled = NOW() + period;
    8.48      /*
     9.1 --- a/xen/include/asm-x86/hvm/hvm.h	Sat May 24 08:54:59 2008 +0100
     9.2 +++ b/xen/include/asm-x86/hvm/hvm.h	Sat May 24 09:27:03 2008 +0100
     9.3 @@ -147,8 +147,10 @@ void hvm_send_assist_req(struct vcpu *v)
     9.4  
     9.5  void hvm_set_guest_tsc(struct vcpu *v, u64 guest_tsc);
     9.6  u64 hvm_get_guest_tsc(struct vcpu *v);
     9.7 -#define hvm_set_guest_time(vcpu, gtime) hvm_set_guest_tsc(vcpu, gtime)
     9.8 -#define hvm_get_guest_time(vcpu)        hvm_get_guest_tsc(vcpu)
     9.9 +
    9.10 +void hvm_init_guest_time(struct domain *d);
    9.11 +void hvm_set_guest_time(struct vcpu *v, u64 guest_time);
    9.12 +u64 hvm_get_guest_time(struct vcpu *v);
    9.13  
    9.14  #define hvm_paging_enabled(v) \
    9.15      (!!((v)->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PG))
    10.1 --- a/xen/include/asm-x86/hvm/vcpu.h	Sat May 24 08:54:59 2008 +0100
    10.2 +++ b/xen/include/asm-x86/hvm/vcpu.h	Sat May 24 09:27:03 2008 +0100
    10.3 @@ -68,6 +68,9 @@ struct hvm_vcpu {
    10.4      struct mtrr_state   mtrr;
    10.5      u64                 pat_cr;
    10.6  
    10.7 +    /* In mode delay_for_missed_ticks, VCPUs have differing guest times. */
    10.8 +    int64_t             stime_offset;
    10.9 +
   10.10      /* Which cache mode is this VCPU in (CR0:CD/NW)? */
   10.11      u8                  cache_mode;
   10.12  
    11.1 --- a/xen/include/asm-x86/hvm/vmx/vmx.h	Sat May 24 08:54:59 2008 +0100
    11.2 +++ b/xen/include/asm-x86/hvm/vmx/vmx.h	Sat May 24 09:27:03 2008 +0100
    11.3 @@ -49,7 +49,6 @@ void vmx_asm_vmexit_handler(struct cpu_u
    11.4  void vmx_asm_do_vmentry(void);
    11.5  void vmx_intr_assist(void);
    11.6  void vmx_do_resume(struct vcpu *);
    11.7 -void set_guest_time(struct vcpu *v, u64 gtime);
    11.8  void vmx_vlapic_msr_changed(struct vcpu *v);
    11.9  void vmx_realmode(struct cpu_user_regs *regs);
   11.10  
    12.1 --- a/xen/include/asm-x86/hvm/vpt.h	Sat May 24 08:54:59 2008 +0100
    12.2 +++ b/xen/include/asm-x86/hvm/vpt.h	Sat May 24 09:27:03 2008 +0100
    12.3 @@ -57,7 +57,7 @@ struct hpet_registers {
    12.4  typedef struct HPETState {
    12.5      struct hpet_registers hpet;
    12.6      struct vcpu *vcpu;
    12.7 -    uint64_t tsc_freq;
    12.8 +    uint64_t stime_freq;
    12.9      uint64_t hpet_to_ns_scale; /* hpet ticks to ns (multiplied by 2^10) */
   12.10      uint64_t hpet_to_ns_limit; /* max hpet ticks convertable to ns      */
   12.11      uint64_t mc_offset;
   12.12 @@ -137,6 +137,11 @@ struct pl_time {    /* platform time */
   12.13      struct RTCState  vrtc;
   12.14      struct HPETState vhpet;
   12.15      struct PMTState  vpmt;
   12.16 +    /* guest_time = Xen sys time + stime_offset */
   12.17 +    int64_t stime_offset;
   12.18 +    /* Ensures monotonicity in appropriate timer modes. */
   12.19 +    uint64_t last_guest_time;
   12.20 +    spinlock_t pl_time_lock;
   12.21  };
   12.22  
   12.23  #define ticks_per_sec(v) (v->domain->arch.hvm_domain.tsc_frequency)
    13.1 --- a/xen/include/xen/time.h	Sat May 24 08:54:59 2008 +0100
    13.2 +++ b/xen/include/xen/time.h	Sat May 24 09:27:03 2008 +0100
    13.3 @@ -47,6 +47,7 @@ struct tm {
    13.4  };
    13.5  struct tm gmtime(unsigned long t);
    13.6  
    13.7 +#define SYSTEM_TIME_HZ  1000000000ULL
    13.8  #define NOW()           ((s_time_t)get_s_time())
    13.9  #define SECONDS(_s)     ((s_time_t)((_s)  * 1000000000ULL))
   13.10  #define MILLISECS(_ms)  ((s_time_t)((_ms) * 1000000ULL))