ia64/xen-unstable

changeset 18702:71c15dfaa12b

Port HPET device model to vpt timer subsystem

The current hpet implementation runs a one-shot xen timer for each
hpet timer whenever the main counter is enabled regardless of whether
or not the individual hpet timers are enabled. When the timer fires,
if it is enabled the interrupt is routed to the guest. If the hpet
timer is periodic, a new one-shot timer is set, for NOW()+period.
There are a number of problems with this the most significant is guest
time drift. Windows does not read the hardware clock to verify time,
it depends on timer interrupts firing at the expected interval. The
existing implementation queues a new one-shot timer each time it fires
and does not allow for a difference between NOW() and the time the
timer was expected to fire, causing drift. Also there is
no allowance for lost ticks. This modification changes HPET to use the
Virtual Platform Timer (VPT) and, for periodic timers, to use periodic
timers. The VPT ensures an interrupt is delivered to the guest for
each period that elapses, plus, its use of xen periodic timers ensures
no drift.

Signed-off-by: Peter Johnston <peter.johnston@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Oct 22 12:04:32 2008 +0100 (2008-10-22)
parents 007a5df1d45b
children 6f74549ac4c5
files xen/arch/x86/hvm/hpet.c xen/arch/x86/hvm/hvm.c xen/arch/x86/hvm/i8254.c xen/arch/x86/hvm/rtc.c xen/arch/x86/hvm/vlapic.c xen/arch/x86/hvm/vpt.c xen/include/asm-x86/hvm/vpt.h
line diff
     1.1 --- a/xen/arch/x86/hvm/hpet.c	Wed Oct 22 11:59:19 2008 +0100
     1.2 +++ b/xen/arch/x86/hvm/hpet.c	Wed Oct 22 12:04:32 2008 +0100
     1.3 @@ -76,6 +76,7 @@
     1.4          ~0ULL : (tick) * (h)->hpet_to_ns_scale) >> 10))
     1.5  
     1.6  #define timer_config(h, n)       (h->hpet.timers[n].config)
     1.7 +#define timer_enabled(h, n)      (timer_config(h, n) & HPET_TN_ENABLE)
     1.8  #define timer_is_periodic(h, n)  (timer_config(h, n) & HPET_TN_PERIODIC)
     1.9  #define timer_is_32bit(h, n)     (timer_config(h, n) & HPET_TN_32BIT)
    1.10  #define hpet_enabled(h)          (h->hpet.config & HPET_CFG_ENABLE)
    1.11 @@ -88,9 +89,40 @@
    1.12      ((timer_config(h, n) & HPET_TN_INT_ROUTE_CAP_MASK) \
    1.13          >> HPET_TN_INT_ROUTE_CAP_SHIFT)
    1.14  
    1.15 -#define hpet_time_after(a, b)   ((int32_t)(b) - (int32_t)(a) < 0)
    1.16 -#define hpet_time_after64(a, b) ((int64_t)(b) - (int64_t)(a) < 0)
    1.17 +static inline uint64_t hpet_read_maincounter(HPETState *h)
    1.18 +{
    1.19 +    ASSERT(spin_is_locked(&h->lock));
    1.20  
    1.21 +    if ( hpet_enabled(h) )
    1.22 +        return guest_time_hpet(h->vcpu) + h->mc_offset;
    1.23 +    else 
    1.24 +        return h->hpet.mc64;
    1.25 +}
    1.26 +
    1.27 +static uint64_t hpet_get_comparator(HPETState *h, unsigned int tn)
    1.28 +{
    1.29 +    uint64_t comparator;
    1.30 +    uint64_t elapsed;
    1.31 +
    1.32 +    comparator = h->hpet.comparator64[tn];
    1.33 +    if ( timer_is_periodic(h, tn) )
    1.34 +    {
    1.35 +        /* update comparator by number of periods elapsed since last update */
    1.36 +        uint64_t period = h->hpet.period[tn];
    1.37 +        if (period)
    1.38 +        {
    1.39 +            elapsed = hpet_read_maincounter(h) + period - 1 - comparator;
    1.40 +            comparator += (elapsed / period) * period;
    1.41 +            h->hpet.comparator64[tn] = comparator;
    1.42 +        }
    1.43 +    }
    1.44 +    
    1.45 +    /* truncate if timer is in 32 bit mode */
    1.46 +    if ( timer_is_32bit(h, tn) )
    1.47 +        comparator = (uint32_t)comparator;
    1.48 +    h->hpet.timers[tn].cmp = comparator;
    1.49 +    return comparator;
    1.50 +}
    1.51  static inline uint64_t hpet_read64(HPETState *h, unsigned long addr)
    1.52  {
    1.53      addr &= ~7;
    1.54 @@ -104,7 +136,7 @@ static inline uint64_t hpet_read64(HPETS
    1.55      case HPET_STATUS:
    1.56          return h->hpet.isr;
    1.57      case HPET_COUNTER:
    1.58 -        return h->hpet.mc64;
    1.59 +        return hpet_read_maincounter(h);
    1.60      case HPET_T0_CFG:
    1.61      case HPET_T1_CFG:
    1.62      case HPET_T2_CFG:
    1.63 @@ -112,7 +144,7 @@ static inline uint64_t hpet_read64(HPETS
    1.64      case HPET_T0_CMP:
    1.65      case HPET_T1_CMP:
    1.66      case HPET_T2_CMP:
    1.67 -        return h->hpet.timers[(addr - HPET_T0_CMP) >> 5].cmp;
    1.68 +        return hpet_get_comparator(h, (addr - HPET_T0_CMP) >> 5);
    1.69      case HPET_T0_ROUTE:
    1.70      case HPET_T1_ROUTE:
    1.71      case HPET_T2_ROUTE:
    1.72 @@ -140,16 +172,6 @@ static inline int hpet_check_access_leng
    1.73      return 0;
    1.74  }
    1.75  
    1.76 -static inline uint64_t hpet_read_maincounter(HPETState *h)
    1.77 -{
    1.78 -    ASSERT(spin_is_locked(&h->lock));
    1.79 -
    1.80 -    if ( hpet_enabled(h) )
    1.81 -        return guest_time_hpet(h->vcpu) + h->mc_offset;
    1.82 -    else 
    1.83 -        return h->hpet.mc64;
    1.84 -}
    1.85 -
    1.86  static int hpet_read(
    1.87      struct vcpu *v, unsigned long addr, unsigned long length,
    1.88      unsigned long *pval)
    1.89 @@ -169,8 +191,6 @@ static int hpet_read(
    1.90      spin_lock(&h->lock);
    1.91  
    1.92      val = hpet_read64(h, addr);
    1.93 -    if ( (addr & ~7) == HPET_COUNTER )
    1.94 -        val = hpet_read_maincounter(h);
    1.95  
    1.96      result = val;
    1.97      if ( length != 8 )
    1.98 @@ -187,7 +207,10 @@ static void hpet_stop_timer(HPETState *h
    1.99  {
   1.100      ASSERT(tn < HPET_TIMER_NUM);
   1.101      ASSERT(spin_is_locked(&h->lock));
   1.102 -    stop_timer(&h->timers[tn]);
   1.103 +    destroy_periodic_time(&h->pt[tn]);
   1.104 +    /* read the comparator to get it updated so a read while stopped will
   1.105 +     * return the expected value. */
   1.106 +    hpet_get_comparator(h, tn);
   1.107  }
   1.108  
   1.109  /* the number of HPET tick that stands for
   1.110 @@ -197,6 +220,8 @@ static void hpet_stop_timer(HPETState *h
   1.111  static void hpet_set_timer(HPETState *h, unsigned int tn)
   1.112  {
   1.113      uint64_t tn_cmp, cur_tick, diff;
   1.114 +    unsigned int irq;
   1.115 +    unsigned int oneshot;
   1.116  
   1.117      ASSERT(tn < HPET_TIMER_NUM);
   1.118      ASSERT(spin_is_locked(&h->lock));
   1.119 @@ -209,7 +234,10 @@ static void hpet_set_timer(HPETState *h,
   1.120          pit_stop_channel0_irq(pit);
   1.121      }
   1.122  
   1.123 -    tn_cmp   = h->hpet.timers[tn].cmp;
   1.124 +    if ( !timer_enabled(h, tn) )
   1.125 +        return;
   1.126 +
   1.127 +    tn_cmp   = hpet_get_comparator(h, tn);
   1.128      cur_tick = hpet_read_maincounter(h);
   1.129      if ( timer_is_32bit(h, tn) )
   1.130      {
   1.131 @@ -229,7 +257,25 @@ static void hpet_set_timer(HPETState *h,
   1.132          diff = (timer_is_32bit(h, tn) && (-diff > HPET_TINY_TIME_SPAN))
   1.133              ? (uint32_t)diff : 0;
   1.134  
   1.135 -    set_timer(&h->timers[tn], NOW() + hpet_tick_to_ns(h, diff));
   1.136 +    if ( (tn <= 1) && (h->hpet.config & HPET_CFG_LEGACY) )
   1.137 +        /* if LegacyReplacementRoute bit is set, HPET specification requires
   1.138 +           timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC,
   1.139 +           timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC. */
   1.140 +        irq = (tn == 0) ? 0 : 8;
   1.141 +    else
   1.142 +        irq = timer_int_route(h, tn);
   1.143 +
   1.144 +    /*
   1.145 +     * diff is the time from now when the timer should fire, for a periodic 
   1.146 +     * timer we also need the period which may be different because time may
   1.147 +     * have elapsed between the time the comparator was written and the timer
   1.148 +     * being enabled (now).
   1.149 +     */
   1.150 +    oneshot = !timer_is_periodic(h, tn);
   1.151 +    create_periodic_time(h->vcpu, &h->pt[tn],
   1.152 +                         hpet_tick_to_ns(h, diff),
   1.153 +                         oneshot ? 0 : hpet_tick_to_ns(h, h->hpet.period[tn]),
   1.154 +                         irq, NULL, NULL);
   1.155  }
   1.156  
   1.157  static inline uint64_t hpet_fixup_reg(
   1.158 @@ -248,6 +294,13 @@ static int hpet_write(
   1.159      uint64_t old_val, new_val;
   1.160      int tn, i;
   1.161  
   1.162 +    /* Acculumate a bit mask of timers whos state is changed by this write. */
   1.163 +    unsigned long start_timers = 0;
   1.164 +    unsigned long stop_timers  = 0;
   1.165 +#define set_stop_timer(n)    (__set_bit((n), &stop_timers))
   1.166 +#define set_start_timer(n)   (__set_bit((n), &start_timers))
   1.167 +#define set_restart_timer(n) (set_stop_timer(n),set_start_timer(n))
   1.168 +
   1.169      addr &= HPET_MMAP_SIZE-1;
   1.170  
   1.171      if ( hpet_check_access_length(addr, length) != 0 )
   1.172 @@ -256,9 +309,6 @@ static int hpet_write(
   1.173      spin_lock(&h->lock);
   1.174  
   1.175      old_val = hpet_read64(h, addr);
   1.176 -    if ( (addr & ~7) == HPET_COUNTER )
   1.177 -        old_val = hpet_read_maincounter(h);
   1.178 -
   1.179      new_val = val;
   1.180      if ( length != 8 )
   1.181          new_val = hpet_fixup_reg(
   1.182 @@ -275,22 +325,35 @@ static int hpet_write(
   1.183              /* Enable main counter and interrupt generation. */
   1.184              h->mc_offset = h->hpet.mc64 - guest_time_hpet(h->vcpu);
   1.185              for ( i = 0; i < HPET_TIMER_NUM; i++ )
   1.186 -                hpet_set_timer(h, i); 
   1.187 +            {
   1.188 +                h->hpet.comparator64[i] =
   1.189 +                            h->hpet.timers[i].config & HPET_TN_32BIT ?
   1.190 +                                          (uint32_t)h->hpet.timers[i].cmp :
   1.191 +                                                    h->hpet.timers[i].cmp;
   1.192 +                if ( timer_enabled(h, i) )
   1.193 +                    set_start_timer(i);
   1.194 +            }
   1.195          }
   1.196          else if ( (old_val & HPET_CFG_ENABLE) && !(new_val & HPET_CFG_ENABLE) )
   1.197          {
   1.198              /* Halt main counter and disable interrupt generation. */
   1.199              h->hpet.mc64 = h->mc_offset + guest_time_hpet(h->vcpu);
   1.200              for ( i = 0; i < HPET_TIMER_NUM; i++ )
   1.201 -                hpet_stop_timer(h, i);
   1.202 +                if ( timer_enabled(h, i) )
   1.203 +                    set_stop_timer(i);
   1.204          }
   1.205          break;
   1.206  
   1.207      case HPET_COUNTER:
   1.208 +        h->hpet.mc64 = new_val;
   1.209          if ( hpet_enabled(h) )
   1.210 +        {
   1.211              gdprintk(XENLOG_WARNING, 
   1.212                       "HPET: writing main counter but it's not halted!\n");
   1.213 -        h->hpet.mc64 = new_val;
   1.214 +            for ( i = 0; i < HPET_TIMER_NUM; i++ )
   1.215 +                if ( timer_enabled(h, i) )
   1.216 +                    set_restart_timer(i);
   1.217 +        }
   1.218          break;
   1.219  
   1.220      case HPET_T0_CFG:
   1.221 @@ -313,7 +376,28 @@ static int hpet_write(
   1.222              h->hpet.timers[tn].cmp = (uint32_t)h->hpet.timers[tn].cmp;
   1.223              h->hpet.period[tn] = (uint32_t)h->hpet.period[tn];
   1.224          }
   1.225 -
   1.226 +        if ( hpet_enabled(h) )
   1.227 +        {
   1.228 +            if ( new_val & HPET_TN_ENABLE )
   1.229 +            {
   1.230 +                if ( (new_val ^ old_val) & HPET_TN_PERIODIC )
   1.231 +                    /* timer is enabled but switching mode to/from periodic/
   1.232 +                     * one-shot, stop and restart the vpt timer to get it in
   1.233 +                     * the right mode. */
   1.234 +                    set_restart_timer(tn);
   1.235 +                else if ( (new_val & HPET_TN_32BIT) &&
   1.236 +                         !(old_val & HPET_TN_32BIT) )
   1.237 +                    /* switching from 64 bit to 32 bit mode could cause timer
   1.238 +                     * next fire time, or period, to change. */
   1.239 +                    set_restart_timer(tn);
   1.240 +                else if ( !(old_val & HPET_TN_ENABLE) )
   1.241 +                    /* transition from timer disabled to timer enabled. */
   1.242 +                    set_start_timer(tn);
   1.243 +            }
   1.244 +            else if ( old_val & HPET_TN_ENABLE )
   1.245 +                /* transition from timer enabled to timer disabled. */
   1.246 +                set_stop_timer(tn);
   1.247 +        }
   1.248          break;
   1.249  
   1.250      case HPET_T0_CMP:
   1.251 @@ -322,10 +406,18 @@ static int hpet_write(
   1.252          tn = (addr - HPET_T0_CMP) >> 5;
   1.253          if ( timer_is_32bit(h, tn) )
   1.254              new_val = (uint32_t)new_val;
   1.255 -        if ( !timer_is_periodic(h, tn) ||
   1.256 -             (h->hpet.timers[tn].config & HPET_TN_SETVAL) )
   1.257 -            h->hpet.timers[tn].cmp = new_val;
   1.258 -        else
   1.259 +        h->hpet.timers[tn].cmp = new_val;
   1.260 +        if ( h->hpet.timers[tn].config & HPET_TN_SETVAL )
   1.261 +            /*
   1.262 +             * When SETVAL is one, software is able to "directly set a periodic
   1.263 +             * timer's accumulator."  That is, set the comparator without
   1.264 +             * adjusting the period.  Much the same as just setting the
   1.265 +             * comparator on an enabled one-shot timer.
   1.266 +             * 
   1.267 +             * This configuration bit clears when the comparator is written.
   1.268 +             */
   1.269 +            h->hpet.timers[tn].config &= ~HPET_TN_SETVAL;
   1.270 +        else if ( timer_is_periodic(h, tn) )
   1.271          {
   1.272              /*
   1.273               * Clamp period to reasonable min/max values:
   1.274 @@ -337,9 +429,9 @@ static int hpet_write(
   1.275              new_val &= (timer_is_32bit(h, tn) ? ~0u : ~0ull) >> 1;
   1.276              h->hpet.period[tn] = new_val;
   1.277          }
   1.278 -        h->hpet.timers[tn].config &= ~HPET_TN_SETVAL;
   1.279 -        if ( hpet_enabled(h) )
   1.280 -            hpet_set_timer(h, tn);
   1.281 +        h->hpet.comparator64[tn] = new_val;
   1.282 +        if ( hpet_enabled(h) && timer_enabled(h, tn) )
   1.283 +            set_restart_timer(tn);
   1.284          break;
   1.285  
   1.286      case HPET_T0_ROUTE:
   1.287 @@ -354,6 +446,25 @@ static int hpet_write(
   1.288          break;
   1.289      }
   1.290  
   1.291 +    /* stop/start timers whos state was changed by this write. */
   1.292 +    while (stop_timers)
   1.293 +    {
   1.294 +        i = find_first_set_bit(stop_timers);
   1.295 +        __clear_bit(i, &stop_timers);
   1.296 +        hpet_stop_timer(h, i);
   1.297 +    }
   1.298 +
   1.299 +    while (start_timers)
   1.300 +    {
   1.301 +        i = find_first_set_bit(start_timers);
   1.302 +        __clear_bit(i, &start_timers);
   1.303 +        hpet_set_timer(h, i);
   1.304 +    }
   1.305 +
   1.306 +#undef set_stop_timer
   1.307 +#undef set_start_timer
   1.308 +#undef set_restart_timer
   1.309 +
   1.310      spin_unlock(&h->lock);
   1.311  
   1.312   out:
   1.313 @@ -373,86 +484,6 @@ struct hvm_mmio_handler hpet_mmio_handle
   1.314      .write_handler = hpet_write
   1.315  };
   1.316  
   1.317 -static void hpet_route_interrupt(HPETState *h, unsigned int tn)
   1.318 -{
   1.319 -    unsigned int tn_int_route = timer_int_route(h, tn);
   1.320 -    struct domain *d = h->vcpu->domain;
   1.321 -
   1.322 -    ASSERT(spin_is_locked(&h->lock));
   1.323 -
   1.324 -    if ( (tn <= 1) && (h->hpet.config & HPET_CFG_LEGACY) )
   1.325 -    {
   1.326 -        /* if LegacyReplacementRoute bit is set, HPET specification requires
   1.327 -           timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC,
   1.328 -           timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC. */
   1.329 -        int isa_irq = (tn == 0) ? 0 : 8;
   1.330 -        hvm_isa_irq_deassert(d, isa_irq);
   1.331 -        hvm_isa_irq_assert(d, isa_irq);
   1.332 -        return;
   1.333 -    }
   1.334 -
   1.335 -    if ( !(timer_int_route_cap(h, tn) & (1U << tn_int_route)) )
   1.336 -    {
   1.337 -        gdprintk(XENLOG_ERR,
   1.338 -                 "HPET: timer%u: invalid interrupt route config\n", tn);
   1.339 -        domain_crash(d);
   1.340 -        return;
   1.341 -    }
   1.342 -
   1.343 -    /* We support only edge-triggered interrupt. */
   1.344 -    spin_lock(&d->arch.hvm_domain.irq_lock);
   1.345 -    vioapic_irq_positive_edge(d, tn_int_route);
   1.346 -    spin_unlock(&d->arch.hvm_domain.irq_lock);
   1.347 -}
   1.348 -
   1.349 -static void hpet_timer_fn(void *opaque)
   1.350 -{
   1.351 -    struct HPET_timer_fn_info *htfi = opaque;
   1.352 -    HPETState *h = htfi->hs;
   1.353 -    unsigned int tn = htfi->tn;
   1.354 -
   1.355 -    spin_lock(&h->lock);
   1.356 -
   1.357 -    if ( !hpet_enabled(h) )
   1.358 -    {
   1.359 -        spin_unlock(&h->lock);
   1.360 -        return;
   1.361 -    }
   1.362 -
   1.363 -    if ( timer_config(h, tn) & HPET_TN_ENABLE )
   1.364 -        hpet_route_interrupt(h, tn);
   1.365 -
   1.366 -    if ( timer_is_periodic(h, tn) && (h->hpet.period[tn] != 0) )
   1.367 -    {
   1.368 -        uint64_t mc = hpet_read_maincounter(h), period = h->hpet.period[tn];
   1.369 -        if ( timer_is_32bit(h, tn) )
   1.370 -        {
   1.371 -            while ( hpet_time_after(mc, h->hpet.timers[tn].cmp) )
   1.372 -                h->hpet.timers[tn].cmp = (uint32_t)(
   1.373 -                    h->hpet.timers[tn].cmp + period);
   1.374 -        }
   1.375 -        else
   1.376 -        {
   1.377 -            while ( hpet_time_after64(mc, h->hpet.timers[tn].cmp) )
   1.378 -                h->hpet.timers[tn].cmp += period;
   1.379 -        }
   1.380 -        set_timer(&h->timers[tn], NOW() + hpet_tick_to_ns(h, period));
   1.381 -    }
   1.382 -
   1.383 -    spin_unlock(&h->lock);
   1.384 -}
   1.385 -
   1.386 -void hpet_migrate_timers(struct vcpu *v)
   1.387 -{
   1.388 -    struct HPETState *h = &v->domain->arch.hvm_domain.pl_time.vhpet;
   1.389 -    int i;
   1.390 -
   1.391 -    if ( v != h->vcpu )
   1.392 -        return;
   1.393 -
   1.394 -    for ( i = 0; i < HPET_TIMER_NUM; i++ )
   1.395 -        migrate_timer(&h->timers[i], v->processor);
   1.396 -}
   1.397  
   1.398  static int hpet_save(struct domain *d, hvm_domain_context_t *h)
   1.399  {
   1.400 @@ -477,18 +508,20 @@ static int hpet_save(struct domain *d, h
   1.401          C(isr);
   1.402          C(mc64);
   1.403          C(timers[0].config);
   1.404 -        C(timers[0].cmp);
   1.405          C(timers[0].fsb);
   1.406          C(timers[1].config);
   1.407 -        C(timers[1].cmp);
   1.408          C(timers[1].fsb);
   1.409          C(timers[2].config);
   1.410 -        C(timers[2].cmp);
   1.411          C(timers[2].fsb);
   1.412          C(period[0]);
   1.413          C(period[1]);
   1.414          C(period[2]);
   1.415  #undef C
   1.416 +        /* save the 64 bit comparator in the 64 bit timer[n].cmp field
   1.417 +         * regardless of whether or not the timer is in 32 bit mode. */
   1.418 +        rec->timers[0].cmp = hp->hpet.comparator64[0];
   1.419 +        rec->timers[1].cmp = hp->hpet.comparator64[1];
   1.420 +        rec->timers[2].cmp = hp->hpet.comparator64[2];
   1.421      }
   1.422  
   1.423      spin_unlock(&hp->lock);
   1.424 @@ -500,6 +533,7 @@ static int hpet_load(struct domain *d, h
   1.425  {
   1.426      HPETState *hp = &d->arch.hvm_domain.pl_time.vhpet;
   1.427      struct hvm_hw_hpet *rec;
   1.428 +    uint64_t cmp;
   1.429      int i;
   1.430  
   1.431      spin_lock(&hp->lock);
   1.432 @@ -515,32 +549,38 @@ static int hpet_load(struct domain *d, h
   1.433      h->cur += HVM_SAVE_LENGTH(HPET);
   1.434  
   1.435  #define C(x) hp->hpet.x = rec->x
   1.436 -        C(capability);
   1.437 -        C(config);
   1.438 -        C(isr);
   1.439 -        C(mc64);
   1.440 -        C(timers[0].config);
   1.441 -        C(timers[0].cmp);
   1.442 -        C(timers[0].fsb);
   1.443 -        C(timers[1].config);
   1.444 -        C(timers[1].cmp);
   1.445 -        C(timers[1].fsb);
   1.446 -        C(timers[2].config);
   1.447 -        C(timers[2].cmp);
   1.448 -        C(timers[2].fsb);
   1.449 -        C(period[0]);
   1.450 -        C(period[1]);
   1.451 -        C(period[2]);
   1.452 +    C(capability);
   1.453 +    C(config);
   1.454 +    C(isr);
   1.455 +    C(mc64);
   1.456 +    /* The following define will generate a compiler error if HPET_TIMER_NUM
   1.457 +     * changes. This indicates an incompatability with previous saved state. */
   1.458 +#define HPET_TIMER_NUM 3
   1.459 +    for ( i = 0; i < HPET_TIMER_NUM; i++ )
   1.460 +    {
   1.461 +        C(timers[i].config);
   1.462 +        C(timers[i].fsb);
   1.463 +        C(period[i]);
   1.464 +        /* restore the hidden 64 bit comparator and truncate the timer's
   1.465 +         * visible comparator field if in 32 bit mode. */
   1.466 +        cmp = rec->timers[i].cmp;
   1.467 +        hp->hpet.comparator64[i] = cmp;
   1.468 +        if ( timer_is_32bit(hp, i) )
   1.469 +            cmp = (uint32_t)cmp;
   1.470 +        hp->hpet.timers[i].cmp = cmp;
   1.471 +    }
   1.472  #undef C
   1.473      
   1.474      /* Recalculate the offset between the main counter and guest time */
   1.475      hp->mc_offset = hp->hpet.mc64 - guest_time_hpet(hp->vcpu);
   1.476 -                
   1.477 -    /* Restart the timers */
   1.478 -    for ( i = 0; i < HPET_TIMER_NUM; i++ )
   1.479 -        if ( hpet_enabled(hp) )
   1.480 -            hpet_set_timer(hp, i);
   1.481  
   1.482 +    /* restart all timers */
   1.483 +
   1.484 +    if ( hpet_enabled(hp) )
   1.485 +        for ( i = 0; i < HPET_TIMER_NUM; i++ )
   1.486 +            if ( timer_enabled(hp, i) )
   1.487 +                hpet_set_timer(hp, i);
   1.488 + 
   1.489      spin_unlock(&hp->lock);
   1.490  
   1.491      return 0;
   1.492 @@ -575,10 +615,7 @@ void hpet_init(struct vcpu *v)
   1.493          h->hpet.timers[i].config = 
   1.494              HPET_TN_INT_ROUTE_CAP | HPET_TN_SIZE_CAP | HPET_TN_PERIODIC_CAP;
   1.495          h->hpet.timers[i].cmp = ~0ULL;
   1.496 -        h->timer_fn_info[i].hs = h;
   1.497 -        h->timer_fn_info[i].tn = i;
   1.498 -        init_timer(&h->timers[i], hpet_timer_fn, &h->timer_fn_info[i],
   1.499 -                   v->processor);
   1.500 +        h->pt[i].source = PTSRC_isa;
   1.501      }
   1.502  }
   1.503  
   1.504 @@ -587,8 +624,14 @@ void hpet_deinit(struct domain *d)
   1.505      int i;
   1.506      HPETState *h = &d->arch.hvm_domain.pl_time.vhpet;
   1.507  
   1.508 -    for ( i = 0; i < HPET_TIMER_NUM; i++ )
   1.509 -        kill_timer(&h->timers[i]);
   1.510 +    spin_lock(&h->lock);
   1.511 +
   1.512 +    if ( hpet_enabled(h) )
   1.513 +        for ( i = 0; i < HPET_TIMER_NUM; i++ )
   1.514 +            if ( timer_enabled(h, i) )
   1.515 +                hpet_stop_timer(h, i);
   1.516 +
   1.517 +    spin_unlock(&h->lock);
   1.518  }
   1.519  
   1.520  void hpet_reset(struct domain *d)
     2.1 --- a/xen/arch/x86/hvm/hvm.c	Wed Oct 22 11:59:19 2008 +0100
     2.2 +++ b/xen/arch/x86/hvm/hvm.c	Wed Oct 22 12:04:32 2008 +0100
     2.3 @@ -163,7 +163,6 @@ u64 hvm_get_guest_tsc(struct vcpu *v)
     2.4  void hvm_migrate_timers(struct vcpu *v)
     2.5  {
     2.6      rtc_migrate_timers(v);
     2.7 -    hpet_migrate_timers(v);
     2.8      pt_migrate(v);
     2.9  }
    2.10  
     3.1 --- a/xen/arch/x86/hvm/i8254.c	Wed Oct 22 11:59:19 2008 +0100
     3.2 +++ b/xen/arch/x86/hvm/i8254.c	Wed Oct 22 12:04:32 2008 +0100
     3.3 @@ -213,13 +213,13 @@ static void pit_load_count(PITState *pit
     3.4      case 2:
     3.5      case 3:
     3.6          /* Periodic timer. */
     3.7 -        create_periodic_time(v, &pit->pt0, period, 0, 0, pit_time_fired, 
     3.8 +        create_periodic_time(v, &pit->pt0, period, period, 0, pit_time_fired, 
     3.9                               &pit->count_load_time[channel]);
    3.10          break;
    3.11      case 1:
    3.12      case 4:
    3.13          /* One-shot timer. */
    3.14 -        create_periodic_time(v, &pit->pt0, period, 0, 1, pit_time_fired,
    3.15 +        create_periodic_time(v, &pit->pt0, period, 0, 0, pit_time_fired,
    3.16                               &pit->count_load_time[channel]);
    3.17          break;
    3.18      default:
     4.1 --- a/xen/arch/x86/hvm/rtc.c	Wed Oct 22 11:59:19 2008 +0100
     4.2 +++ b/xen/arch/x86/hvm/rtc.c	Wed Oct 22 12:04:32 2008 +0100
     4.3 @@ -59,8 +59,8 @@ static void rtc_timer_update(RTCState *s
     4.4  
     4.5          period = 1 << (period_code - 1); /* period in 32 Khz cycles */
     4.6          period = DIV_ROUND((period * 1000000000ULL), 32768); /* period in ns */
     4.7 -        create_periodic_time(v, &s->pt, period, RTC_IRQ,
     4.8 -                             0, rtc_periodic_cb, s);
     4.9 +        create_periodic_time(v, &s->pt, period, period, RTC_IRQ,
    4.10 +                             rtc_periodic_cb, s);
    4.11      }
    4.12      else
    4.13      {
     5.1 --- a/xen/arch/x86/hvm/vlapic.c	Wed Oct 22 11:59:19 2008 +0100
     5.2 +++ b/xen/arch/x86/hvm/vlapic.c	Wed Oct 22 12:04:32 2008 +0100
     5.3 @@ -701,8 +701,9 @@ static int vlapic_write(struct vcpu *v, 
     5.4                              (uint32_t)val * vlapic->hw.timer_divisor;
     5.5  
     5.6          vlapic_set_reg(vlapic, APIC_TMICT, val);
     5.7 -        create_periodic_time(current, &vlapic->pt, period, vlapic->pt.irq,
     5.8 -                             !vlapic_lvtt_period(vlapic), vlapic_pt_cb,
     5.9 +        create_periodic_time(current, &vlapic->pt, period, 
    5.10 +                             vlapic_lvtt_period(vlapic) ? period : 0,
    5.11 +                             vlapic->pt.irq, vlapic_pt_cb,
    5.12                               &vlapic->timer_last_update);
    5.13          vlapic->timer_last_update = vlapic->pt.last_plt_gtime;
    5.14  
    5.15 @@ -861,8 +862,9 @@ static void lapic_rearm(struct vlapic *s
    5.16      period = ((uint64_t)APIC_BUS_CYCLE_NS *
    5.17                (uint32_t)tmict * s->hw.timer_divisor);
    5.18      s->pt.irq = vlapic_get_reg(s, APIC_LVTT) & APIC_VECTOR_MASK;
    5.19 -    create_periodic_time(vlapic_vcpu(s), &s->pt, period, s->pt.irq,
    5.20 -                         !vlapic_lvtt_period(s), vlapic_pt_cb,
    5.21 +    create_periodic_time(vlapic_vcpu(s), &s->pt, period,
    5.22 +                         vlapic_lvtt_period(s) ? period : 0,
    5.23 +                         s->pt.irq, vlapic_pt_cb,
    5.24                           &s->timer_last_update);
    5.25      s->timer_last_update = s->pt.last_plt_gtime;
    5.26  }
     6.1 --- a/xen/arch/x86/hvm/vpt.c	Wed Oct 22 11:59:19 2008 +0100
     6.2 +++ b/xen/arch/x86/hvm/vpt.c	Wed Oct 22 12:04:32 2008 +0100
     6.3 @@ -355,8 +355,8 @@ void pt_migrate(struct vcpu *v)
     6.4  }
     6.5  
     6.6  void create_periodic_time(
     6.7 -    struct vcpu *v, struct periodic_time *pt, uint64_t period,
     6.8 -    uint8_t irq, char one_shot, time_cb *cb, void *data)
     6.9 +    struct vcpu *v, struct periodic_time *pt, uint64_t delta,
    6.10 +    uint64_t period, uint8_t irq, time_cb *cb, void *data)
    6.11  {
    6.12      ASSERT(pt->source != 0);
    6.13  
    6.14 @@ -369,7 +369,7 @@ void create_periodic_time(
    6.15      pt->irq_issued = 0;
    6.16  
    6.17      /* Periodic timer must be at least 0.9ms. */
    6.18 -    if ( (period < 900000) && !one_shot )
    6.19 +    if ( (period < 900000) && period )
    6.20      {
    6.21          if ( !test_and_set_bool(pt->warned_timeout_too_short) )
    6.22              gdprintk(XENLOG_WARNING, "HVM_PlatformTime: program too "
    6.23 @@ -382,15 +382,15 @@ void create_periodic_time(
    6.24      pt->last_plt_gtime = hvm_get_guest_time(pt->vcpu);
    6.25      pt->irq = irq;
    6.26      pt->period_cycles = (u64)period;
    6.27 -    pt->one_shot = one_shot;
    6.28 -    pt->scheduled = NOW() + period;
    6.29 +    pt->one_shot = !period;
    6.30 +    pt->scheduled = NOW() + delta;
    6.31      /*
    6.32       * Offset LAPIC ticks from other timer ticks. Otherwise guests which use
    6.33       * LAPIC ticks for process accounting can see long sequences of process
    6.34       * ticks incorrectly accounted to interrupt processing.
    6.35       */
    6.36      if ( pt->source == PTSRC_lapic )
    6.37 -        pt->scheduled += period >> 1;
    6.38 +        pt->scheduled += delta >> 1;
    6.39      pt->cb = cb;
    6.40      pt->priv = data;
    6.41  
     7.1 --- a/xen/include/asm-x86/hvm/vpt.h	Wed Oct 22 11:59:19 2008 +0100
     7.2 +++ b/xen/include/asm-x86/hvm/vpt.h	Wed Oct 22 12:04:32 2008 +0100
     7.3 @@ -32,41 +32,6 @@
     7.4  #include <asm/hvm/irq.h>
     7.5  #include <public/hvm/save.h>
     7.6  
     7.7 -struct HPETState;
     7.8 -struct HPET_timer_fn_info {
     7.9 -    struct HPETState *hs;
    7.10 -    unsigned int tn;
    7.11 -};
    7.12 -
    7.13 -struct hpet_registers {
    7.14 -    /* Memory-mapped, software visible registers */
    7.15 -    uint64_t capability;        /* capabilities */
    7.16 -    uint64_t config;            /* configuration */
    7.17 -    uint64_t isr;               /* interrupt status reg */
    7.18 -    uint64_t mc64;              /* main counter */
    7.19 -    struct {                    /* timers */
    7.20 -        uint64_t config;        /* configuration/cap */
    7.21 -        uint64_t cmp;           /* comparator */
    7.22 -        uint64_t fsb;           /* FSB route, not supported now */
    7.23 -    } timers[HPET_TIMER_NUM];
    7.24 -
    7.25 -    /* Hidden register state */
    7.26 -    uint64_t period[HPET_TIMER_NUM]; /* Last value written to comparator */
    7.27 -};
    7.28 -
    7.29 -typedef struct HPETState {
    7.30 -    struct hpet_registers hpet;
    7.31 -    struct vcpu *vcpu;
    7.32 -    uint64_t stime_freq;
    7.33 -    uint64_t hpet_to_ns_scale; /* hpet ticks to ns (multiplied by 2^10) */
    7.34 -    uint64_t hpet_to_ns_limit; /* max hpet ticks convertable to ns      */
    7.35 -    uint64_t mc_offset;
    7.36 -    struct timer timers[HPET_TIMER_NUM];
    7.37 -    struct HPET_timer_fn_info timer_fn_info[HPET_TIMER_NUM]; 
    7.38 -    spinlock_t lock;
    7.39 -} HPETState;
    7.40 -
    7.41 -
    7.42  /*
    7.43   * Abstract layer of periodic time, one short time.
    7.44   */
    7.45 @@ -108,6 +73,34 @@ typedef struct PITState {
    7.46      spinlock_t lock;
    7.47  } PITState;
    7.48  
    7.49 +struct hpet_registers {
    7.50 +    /* Memory-mapped, software visible registers */
    7.51 +    uint64_t capability;        /* capabilities */
    7.52 +    uint64_t config;            /* configuration */
    7.53 +    uint64_t isr;               /* interrupt status reg */
    7.54 +    uint64_t mc64;              /* main counter */
    7.55 +    struct {                    /* timers */
    7.56 +        uint64_t config;        /* configuration/cap */
    7.57 +        uint64_t cmp;           /* comparator */
    7.58 +        uint64_t fsb;           /* FSB route, not supported now */
    7.59 +    } timers[HPET_TIMER_NUM];
    7.60 +
    7.61 +    /* Hidden register state */
    7.62 +    uint64_t period[HPET_TIMER_NUM]; /* Last value written to comparator */
    7.63 +    uint64_t comparator64[HPET_TIMER_NUM]; /* 64 bit running comparator */
    7.64 +};
    7.65 +
    7.66 +typedef struct HPETState {
    7.67 +    struct hpet_registers hpet;
    7.68 +    struct vcpu *vcpu;
    7.69 +    uint64_t stime_freq;
    7.70 +    uint64_t hpet_to_ns_scale; /* hpet ticks to ns (multiplied by 2^10) */
    7.71 +    uint64_t hpet_to_ns_limit; /* max hpet ticks convertable to ns      */
    7.72 +    uint64_t mc_offset;
    7.73 +    struct periodic_time pt[HPET_TIMER_NUM];
    7.74 +    spinlock_t lock;
    7.75 +} HPETState;
    7.76 +
    7.77  typedef struct RTCState {
    7.78      /* Hardware state */
    7.79      struct hvm_hw_rtc hw;
    7.80 @@ -160,13 +153,13 @@ void pt_migrate(struct vcpu *v);
    7.81   * The given periodic timer structure must be initialised with zero bytes,
    7.82   * except for the 'source' field which must be initialised with the
    7.83   * correct PTSRC_ value. The initialised timer structure can then be passed
    7.84 - * to {create,destroy}_periodic_time() and number of times and in any order.
    7.85 + * to {create,destroy}_periodic_time() any number of times and in any order.
    7.86   * Note that, for a given periodic timer, invocations of these functions MUST
    7.87   * be serialised.
    7.88   */
    7.89  void create_periodic_time(
    7.90 -    struct vcpu *v, struct periodic_time *pt, uint64_t period,
    7.91 -    uint8_t irq, char one_shot, time_cb *cb, void *data);
    7.92 +    struct vcpu *v, struct periodic_time *pt, uint64_t delta,
    7.93 +    uint64_t period, uint8_t irq, time_cb *cb, void *data);
    7.94  void destroy_periodic_time(struct periodic_time *pt);
    7.95  
    7.96  int pv_pit_handler(int port, int data, int write);
    7.97 @@ -185,7 +178,6 @@ void pmtimer_init(struct vcpu *v);
    7.98  void pmtimer_deinit(struct domain *d);
    7.99  void pmtimer_reset(struct domain *d);
   7.100  
   7.101 -void hpet_migrate_timers(struct vcpu *v);
   7.102  void hpet_init(struct vcpu *v);
   7.103  void hpet_deinit(struct domain *d);
   7.104  void hpet_reset(struct domain *d);