ia64/xen-unstable

changeset 10182:da7fe04d8e80

[HVM] Support multiple HVM time device models coming soon.
1: Adopt an abstract layer for periodic time on top of different
HV time device models like PIT, RTC and ACPI time.
2: Extract VMM knowledge from PIT DM code and keep close with
qemu for easy maintain in future.
3: Use guest time (TSC) to drive PIT CLK that helps us to remove
a lot of extra logic previously introduced to convert from host time to
guest time.
4: Some cleanup for SMP code like move cache_tsc_offset to per VP.

Signed-off-by: Eddie Dong <eddie.dong@intel.com>
author kaf24@firebug.cl.cam.ac.uk
date Thu May 25 16:00:36 2006 +0100 (2006-05-25)
parents f4f4dd936103
children 218daa547e8a
files xen/arch/x86/hvm/hvm.c xen/arch/x86/hvm/i8254.c xen/arch/x86/hvm/intercept.c xen/arch/x86/hvm/svm/intr.c xen/arch/x86/hvm/svm/svm.c xen/arch/x86/hvm/svm/vmcb.c xen/arch/x86/hvm/vmx/io.c xen/arch/x86/hvm/vmx/vmx.c xen/include/asm-x86/hvm/domain.h xen/include/asm-x86/hvm/svm/intr.h xen/include/asm-x86/hvm/svm/svm.h xen/include/asm-x86/hvm/vcpu.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/hvm.c	Thu May 25 16:00:09 2006 +0100
     1.2 +++ b/xen/arch/x86/hvm/hvm.c	Thu May 25 16:00:36 2006 +0100
     1.3 @@ -185,8 +185,9 @@ static void hvm_get_info(struct domain *
     1.4  void hvm_setup_platform(struct domain* d)
     1.5  {
     1.6      struct hvm_domain *platform;
     1.7 +    struct vcpu *v=current;
     1.8  
     1.9 -    if ( !hvm_guest(current) || (current->vcpu_id != 0) )
    1.10 +    if ( !hvm_guest(v) || (v->vcpu_id != 0) )
    1.11          return;
    1.12  
    1.13      if ( shadow_direct_map_init(d) == 0 )
    1.14 @@ -208,7 +209,8 @@ void hvm_setup_platform(struct domain* d
    1.15          hvm_vioapic_init(d);
    1.16      }
    1.17  
    1.18 -    pit_init(&platform->vpit, current);
    1.19 +    init_timer(&platform->pl_time.periodic_tm.timer, pt_timer_fn, v, v->processor);
    1.20 +    pit_init(v, cpu_khz);
    1.21  }
    1.22  
    1.23  void pic_irq_request(void *data, int level)
    1.24 @@ -240,6 +242,14 @@ void hvm_pic_assist(struct vcpu *v)
    1.25      }
    1.26  }
    1.27  
    1.28 +u64 hvm_get_guest_time(struct vcpu *v)
    1.29 +{
    1.30 +    u64    host_tsc;
    1.31 +    
    1.32 +    rdtscll(host_tsc);
    1.33 +    return host_tsc + v->arch.hvm_vcpu.cache_tsc_offset;
    1.34 +}
    1.35 +
    1.36  int cpu_get_interrupt(struct vcpu *v, int *type)
    1.37  {
    1.38      int intno;
     2.1 --- a/xen/arch/x86/hvm/i8254.c	Thu May 25 16:00:09 2006 +0100
     2.2 +++ b/xen/arch/x86/hvm/i8254.c	Thu May 25 16:00:36 2006 +0100
     2.3 @@ -22,11 +22,10 @@
     2.4   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     2.5   * THE SOFTWARE.
     2.6   */
     2.7 -/* Edwin Zhai <edwin.zhai@intel.com>
     2.8 +/* Edwin Zhai <edwin.zhai@intel.com>, Eddie Dong <eddie.dong@intel.com>
     2.9   * Ported to xen:
    2.10 - * use actimer for intr generation;
    2.11 + * Add a new layer of periodic time on top of PIT;
    2.12   * move speaker io access to hypervisor;
    2.13 - * use new method for counter/intrs calculation
    2.14   */
    2.15  
    2.16  #include <xen/config.h>
    2.17 @@ -42,184 +41,117 @@
    2.18  #include <asm/hvm/vpit.h>
    2.19  #include <asm/current.h>
    2.20  
    2.21 -/*#define DEBUG_PIT*/
    2.22 +/* Enable DEBUG_PIT may cause guest calibration inaccuracy */
    2.23 +/* #define DEBUG_PIT */
    2.24  
    2.25  #define RW_STATE_LSB 1
    2.26  #define RW_STATE_MSB 2
    2.27  #define RW_STATE_WORD0 3
    2.28  #define RW_STATE_WORD1 4
    2.29  
    2.30 -#ifndef NSEC_PER_SEC
    2.31 -#define NSEC_PER_SEC (1000000000ULL)
    2.32 -#endif
    2.33 +#define ticks_per_sec(v)      (v->domain->arch.hvm_domain.tsc_frequency)
    2.34 +static int handle_pit_io(ioreq_t *p);
    2.35 +static int handle_speaker_io(ioreq_t *p);
    2.36 +
    2.37 +/* compute with 96 bit intermediate result: (a*b)/c */
    2.38 +uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
    2.39 +{
    2.40 +    union {
    2.41 +        uint64_t ll;
    2.42 +        struct {
    2.43 +#ifdef WORDS_BIGENDIAN
    2.44 +            uint32_t high, low;
    2.45 +#else
    2.46 +            uint32_t low, high;
    2.47 +#endif            
    2.48 +        } l;
    2.49 +    } u, res;
    2.50 +    uint64_t rl, rh;
    2.51  
    2.52 -#ifndef TIMER_SLOP 
    2.53 -#define TIMER_SLOP (50*1000) /* ns */
    2.54 -#endif
    2.55 +    u.ll = a;
    2.56 +    rl = (uint64_t)u.l.low * (uint64_t)b;
    2.57 +    rh = (uint64_t)u.l.high * (uint64_t)b;
    2.58 +    rh += (rl >> 32);
    2.59 +    res.l.high = rh / c;
    2.60 +    res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;
    2.61 +    return res.ll;
    2.62 +}
    2.63  
    2.64 -static void pit_irq_timer_update(PITChannelState *s, s64 current_time);
    2.65 -
    2.66 -s_time_t hvm_get_clock(void)
    2.67 +/*
    2.68 + * get processor time.
    2.69 + * unit: TSC
    2.70 + */
    2.71 +int64_t hvm_get_clock(struct vcpu *v)
    2.72  {
    2.73 -    /* TODO: add pause/unpause support */
    2.74 -    return NOW();
    2.75 +    uint64_t  gtsc;
    2.76 +    gtsc = hvm_get_guest_time(v);
    2.77 +    return gtsc;
    2.78  }
    2.79  
    2.80  static int pit_get_count(PITChannelState *s)
    2.81  {
    2.82 -    u64 d;
    2.83 -    u64 counter;
    2.84 +    uint64_t d;
    2.85 +    int  counter;
    2.86  
    2.87 -    d = hvm_get_clock() - s->count_load_time;
    2.88 +    d = muldiv64(hvm_get_clock(s->vcpu) - s->count_load_time, PIT_FREQ, ticks_per_sec(s->vcpu));
    2.89      switch(s->mode) {
    2.90      case 0:
    2.91      case 1:
    2.92      case 4:
    2.93      case 5:
    2.94 -        counter = (s->period - d) & 0xffff;
    2.95 +        counter = (s->count - d) & 0xffff;
    2.96          break;
    2.97      case 3:
    2.98          /* XXX: may be incorrect for odd counts */
    2.99 -        counter = s->period - ((2 * d) % s->period);
   2.100 +        counter = s->count - ((2 * d) % s->count);
   2.101          break;
   2.102      default:
   2.103 -        /* mod 2 counter handle */
   2.104 -        d = hvm_get_clock() - s->hvm_time->count_point;
   2.105 -        d += s->hvm_time->count_advance;
   2.106 -        counter = s->period - (d % s->period);
   2.107 +        counter = s->count - (d % s->count);
   2.108          break;
   2.109      }
   2.110 -    /* change from ns to pit counter */
   2.111 -    counter = DIV_ROUND( (counter * PIT_FREQ), NSEC_PER_SEC);
   2.112      return counter;
   2.113  }
   2.114  
   2.115  /* get pit output bit */
   2.116 -static int pit_get_out1(PITChannelState *s, s64 current_time)
   2.117 +static int pit_get_out1(PITChannelState *s, int64_t current_time)
   2.118  {
   2.119 -    u64 d;
   2.120 +    uint64_t d;
   2.121      int out;
   2.122  
   2.123 -    d = current_time - s->count_load_time;
   2.124 +    d = muldiv64(current_time - s->count_load_time, PIT_FREQ, ticks_per_sec(s->vcpu));
   2.125      switch(s->mode) {
   2.126      default:
   2.127      case 0:
   2.128 -        out = (d >= s->period);
   2.129 +        out = (d >= s->count);
   2.130          break;
   2.131      case 1:
   2.132 -        out = (d < s->period);
   2.133 +        out = (d < s->count);
   2.134          break;
   2.135      case 2:
   2.136 -        /* mod2 out is no meaning, since intr are generated in background */
   2.137 -        if ((d % s->period) == 0 && d != 0)
   2.138 +        if ((d % s->count) == 0 && d != 0)
   2.139              out = 1;
   2.140          else
   2.141              out = 0;
   2.142          break;
   2.143      case 3:
   2.144 -        out = (d % s->period) < ((s->period + 1) >> 1);
   2.145 +        out = (d % s->count) < ((s->count + 1) >> 1);
   2.146          break;
   2.147      case 4:
   2.148      case 5:
   2.149 -        out = (d == s->period);
   2.150 +        out = (d == s->count);
   2.151          break;
   2.152      }
   2.153      return out;
   2.154  }
   2.155  
   2.156 -int pit_get_out(hvm_virpit *pit, int channel, s64 current_time)
   2.157 +int pit_get_out(PITState *pit, int channel, int64_t current_time)
   2.158  {
   2.159      PITChannelState *s = &pit->channels[channel];
   2.160      return pit_get_out1(s, current_time);
   2.161  }
   2.162  
   2.163 -static __inline__ s64 missed_ticks(PITChannelState *s, s64 current_time)
   2.164 -{
   2.165 -    struct hvm_time_info *hvm_time = s->hvm_time;
   2.166 -    struct domain *d = (void *) s - 
   2.167 -        offsetof(struct domain, arch.hvm_domain.vpit.channels[0]);
   2.168 -
   2.169 -    /* ticks from current time(expected time) to NOW */ 
   2.170 -    int missed_ticks;
   2.171 -    /* current_time is expected time for next intr, check if it's true
   2.172 -     * (actimer has a TIMER_SLOP in advance)
   2.173 -     */
   2.174 -    s64 missed_time = hvm_get_clock() + TIMER_SLOP - current_time;
   2.175 -
   2.176 -    if (missed_time >= 0) {
   2.177 -        missed_ticks = missed_time/(s_time_t)s->period + 1;
   2.178 -        if (test_bit(_DOMF_debugging, &d->domain_flags)) {
   2.179 -            hvm_time->pending_intr_nr++;
   2.180 -        } else {
   2.181 -            hvm_time->pending_intr_nr += missed_ticks;
   2.182 -        }
   2.183 -        s->next_transition_time = current_time + (missed_ticks ) * s->period;
   2.184 -    }
   2.185 -
   2.186 -    return s->next_transition_time;
   2.187 -}
   2.188 -
   2.189 -/* only rearm the actimer when return value > 0
   2.190 - *  -2: init state
   2.191 - *  -1: the mode has expired
   2.192 - *   0: current VCPU is not running
   2.193 - *  >0: the next fired time
   2.194 - */
   2.195 -s64 pit_get_next_transition_time(PITChannelState *s, 
   2.196 -                                            s64 current_time)
   2.197 -{
   2.198 -    s64 d, next_time, base;
   2.199 -    int period2;
   2.200 -    struct hvm_time_info *hvm_time = s->hvm_time;
   2.201 -
   2.202 -    d = current_time - s->count_load_time;
   2.203 -    switch(s->mode) {
   2.204 -    default:
   2.205 -    case 0:
   2.206 -    case 1:
   2.207 -        if (d < s->period)
   2.208 -            next_time = s->period;
   2.209 -        else
   2.210 -            return -1;
   2.211 -        break;
   2.212 -    case 2:
   2.213 -        next_time = missed_ticks(s, current_time);
   2.214 -        if ( !test_bit(_VCPUF_running, &(hvm_time->vcpu->vcpu_flags)) )
   2.215 -            return 0;
   2.216 -        break;
   2.217 -    case 3:
   2.218 -        base = (d / s->period) * s->period;
   2.219 -        period2 = ((s->period + 1) >> 1);
   2.220 -        if ((d - base) < period2) 
   2.221 -            next_time = base + period2;
   2.222 -        else
   2.223 -            next_time = base + s->period;
   2.224 -        break;
   2.225 -    case 4:
   2.226 -    case 5:
   2.227 -        if (d < s->period)
   2.228 -            next_time = s->period;
   2.229 -        else if (d == s->period)
   2.230 -            next_time = s->period + 1;
   2.231 -        else
   2.232 -            return -1;
   2.233 -        break;
   2.234 -    case 0xff:
   2.235 -        return -2;      /* for init state */ 
   2.236 -        break;
   2.237 -    }
   2.238 -    /* XXX: better solution: use a clock at PIT_FREQ Hz */
   2.239 -    if (next_time <= current_time){
   2.240 -#ifdef DEBUG_PIT
   2.241 -        printk("HVM_PIT:next_time <= current_time. next=0x%llx, current=0x%llx!\n",next_time, current_time);
   2.242 -#endif
   2.243 -        next_time = current_time + 1;
   2.244 -    }
   2.245 -    return next_time;
   2.246 -}
   2.247 -
   2.248  /* val must be 0 or 1 */
   2.249 -void pit_set_gate(hvm_virpit *pit, int channel, int val)
   2.250 +void pit_set_gate(PITState *pit, int channel, int val)
   2.251  {
   2.252      PITChannelState *s = &pit->channels[channel];
   2.253  
   2.254 @@ -233,16 +165,16 @@ void pit_set_gate(hvm_virpit *pit, int c
   2.255      case 5:
   2.256          if (s->gate < val) {
   2.257              /* restart counting on rising edge */
   2.258 -            s->count_load_time = hvm_get_clock();
   2.259 -            pit_irq_timer_update(s, s->count_load_time);
   2.260 +            s->count_load_time = hvm_get_clock(s->vcpu);
   2.261 +//            pit_irq_timer_update(s, s->count_load_time);
   2.262          }
   2.263          break;
   2.264      case 2:
   2.265      case 3:
   2.266          if (s->gate < val) {
   2.267              /* restart counting on rising edge */
   2.268 -            s->count_load_time = hvm_get_clock();
   2.269 -            pit_irq_timer_update(s, s->count_load_time);
   2.270 +            s->count_load_time = hvm_get_clock(s->vcpu);
   2.271 +//            pit_irq_timer_update(s, s->count_load_time);
   2.272          }
   2.273          /* XXX: disable/enable counting */
   2.274          break;
   2.275 @@ -250,7 +182,7 @@ void pit_set_gate(hvm_virpit *pit, int c
   2.276      s->gate = val;
   2.277  }
   2.278  
   2.279 -int pit_get_gate(hvm_virpit *pit, int channel)
   2.280 +int pit_get_gate(PITState *pit, int channel)
   2.281  {
   2.282      PITChannelState *s = &pit->channels[channel];
   2.283      return s->gate;
   2.284 @@ -258,37 +190,37 @@ int pit_get_gate(hvm_virpit *pit, int ch
   2.285  
   2.286  static inline void pit_load_count(PITChannelState *s, int val)
   2.287  {
   2.288 +    u32   period;
   2.289      if (val == 0)
   2.290          val = 0x10000;
   2.291 -
   2.292 -    s->count_load_time = hvm_get_clock();
   2.293 +    s->count_load_time = hvm_get_clock(s->vcpu);
   2.294      s->count = val;
   2.295 -    s->period = DIV_ROUND(((s->count) * NSEC_PER_SEC), PIT_FREQ);
   2.296 +    period = DIV_ROUND((val * 1000000000ULL), PIT_FREQ);
   2.297  
   2.298  #ifdef DEBUG_PIT
   2.299 -    printk("HVM_PIT: pit-load-counter, count=0x%x,period=0x%u us,mode=%d, load_time=%lld\n",
   2.300 +    printk("HVM_PIT: pit-load-counter(%p), count=0x%x, period=%uns mode=%d, load_time=%lld\n",
   2.301 +            s,
   2.302              val,
   2.303 -            s->period / 1000,
   2.304 +            period,
   2.305              s->mode,
   2.306 -            s->count_load_time);
   2.307 +            (long long)s->count_load_time);
   2.308  #endif
   2.309  
   2.310 -    if (s->mode == HVM_PIT_ACCEL_MODE) {
   2.311 -        if (!s->hvm_time) {
   2.312 -            printk("HVM_PIT:guest should only set mod 2 on channel 0!\n");
   2.313 -            return;
   2.314 -        }
   2.315 -        s->hvm_time->period_cycles = (u64)s->period * cpu_khz / 1000000L;
   2.316 -        s->hvm_time->first_injected = 0;
   2.317 -
   2.318 -        if (s->period < 900000) { /* < 0.9 ms */
   2.319 -            printk("HVM_PIT: guest programmed too small an count: %x\n",
   2.320 -                    s->count);
   2.321 -            s->period = 1000000;
   2.322 -        }
   2.323 +    switch (s->mode) {
   2.324 +        case 2:
   2.325 +            /* create periodic time */
   2.326 +            s->pt = create_periodic_time (s->vcpu, period, 0, 0);
   2.327 +            break;
   2.328 +        case 1:
   2.329 +            /* create one shot time */
   2.330 +            s->pt = create_periodic_time (s->vcpu, period, 0, 1);
   2.331 +#ifdef DEBUG_PIT
   2.332 +            printk("HVM_PIT: create one shot time.\n");
   2.333 +#endif
   2.334 +            break;
   2.335 +        default:
   2.336 +            break;
   2.337      }
   2.338 -        
   2.339 -    pit_irq_timer_update(s, s->count_load_time);
   2.340  }
   2.341  
   2.342  /* if already latched, do not latch again */
   2.343 @@ -300,9 +232,9 @@ static void pit_latch_count(PITChannelSt
   2.344      }
   2.345  }
   2.346  
   2.347 -static void pit_ioport_write(void *opaque, u32 addr, u32 val)
   2.348 +static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
   2.349  {
   2.350 -    hvm_virpit *pit = opaque;
   2.351 +    PITState *pit = opaque;
   2.352      int channel, access;
   2.353      PITChannelState *s;
   2.354      val &= 0xff;
   2.355 @@ -321,7 +253,7 @@ static void pit_ioport_write(void *opaqu
   2.356                      if (!(val & 0x10) && !s->status_latched) {
   2.357                          /* status latch */
   2.358                          /* XXX: add BCD and null count */
   2.359 -                        s->status =  (pit_get_out1(s, hvm_get_clock()) << 7) |
   2.360 +                        s->status =  (pit_get_out1(s, hvm_get_clock(s->vcpu)) << 7) |
   2.361                              (s->rw_mode << 4) |
   2.362                              (s->mode << 1) |
   2.363                              s->bcd;
   2.364 @@ -366,9 +298,9 @@ static void pit_ioport_write(void *opaqu
   2.365      }
   2.366  }
   2.367  
   2.368 -static u32 pit_ioport_read(void *opaque, u32 addr)
   2.369 +static uint32_t pit_ioport_read(void *opaque, uint32_t addr)
   2.370  {
   2.371 -    hvm_virpit *pit = opaque;
   2.372 +    PITState *pit = opaque;
   2.373      int ret, count;
   2.374      PITChannelState *s;
   2.375      
   2.376 @@ -419,84 +351,51 @@ static u32 pit_ioport_read(void *opaque,
   2.377      return ret;
   2.378  }
   2.379  
   2.380 -static void pit_irq_timer_update(PITChannelState *s, s64 current_time)
   2.381 -{
   2.382 -    s64 expire_time;
   2.383 -    int irq_level;
   2.384 -    struct vcpu *v = current;
   2.385 -    struct hvm_virpic *pic= &v->domain->arch.hvm_domain.vpic;
   2.386 -
   2.387 -    if (!s->hvm_time || s->mode == 0xff)
   2.388 -        return;
   2.389 -
   2.390 -    expire_time = pit_get_next_transition_time(s, current_time);
   2.391 -    /* not generate intr by direct pic_set_irq in mod 2
   2.392 -     * XXX:mod 3 should be same as mod 2
   2.393 -     */
   2.394 -    if (s->mode != HVM_PIT_ACCEL_MODE) {
   2.395 -        irq_level = pit_get_out1(s, current_time);
   2.396 -        pic_set_irq(pic, s->irq, irq_level);
   2.397 -        s->next_transition_time = expire_time;
   2.398 -#ifdef DEBUG_PIT
   2.399 -        printk("HVM_PIT:irq_level=%d next_delay=%l ns\n",
   2.400 -                irq_level, 
   2.401 -                (expire_time - current_time));
   2.402 -#endif
   2.403 -    }
   2.404 -
   2.405 -    if (expire_time > 0)
   2.406 -        set_timer(&(s->hvm_time->pit_timer), s->next_transition_time);
   2.407 -
   2.408 -}
   2.409 -
   2.410 -static void pit_irq_timer(void *data)
   2.411 -{
   2.412 -    PITChannelState *s = data;
   2.413 -
   2.414 -    pit_irq_timer_update(s, s->next_transition_time);
   2.415 -}
   2.416 -
   2.417  static void pit_reset(void *opaque)
   2.418  {
   2.419 -    hvm_virpit *pit = opaque;
   2.420 +    PITState *pit = opaque;
   2.421      PITChannelState *s;
   2.422      int i;
   2.423  
   2.424      for(i = 0;i < 3; i++) {
   2.425          s = &pit->channels[i];
   2.426 +        if ( s -> pt ) {
   2.427 +            destroy_periodic_time (s->pt);
   2.428 +            s->pt = NULL;
   2.429 +        }
   2.430          s->mode = 0xff; /* the init mode */
   2.431          s->gate = (i != 2);
   2.432          pit_load_count(s, 0);
   2.433      }
   2.434  }
   2.435  
   2.436 -/* hvm_io_assist light-weight version, specific to PIT DM */ 
   2.437 -static void resume_pit_io(ioreq_t *p)
   2.438 +void pit_init(struct vcpu *v, unsigned long cpu_khz)
   2.439  {
   2.440 -    struct cpu_user_regs *regs = guest_cpu_user_regs();
   2.441 -    unsigned long old_eax = regs->eax;
   2.442 -    p->state = STATE_INVALID;
   2.443 +    PITState *pit = &v->domain->arch.hvm_domain.pl_time.vpit;
   2.444 +    PITChannelState *s;
   2.445  
   2.446 -    switch(p->size) {
   2.447 -    case 1:
   2.448 -        regs->eax = (old_eax & 0xffffff00) | (p->u.data & 0xff);
   2.449 -        break;
   2.450 -    case 2:
   2.451 -        regs->eax = (old_eax & 0xffff0000) | (p->u.data & 0xffff);
   2.452 -        break;
   2.453 -    case 4:
   2.454 -        regs->eax = (p->u.data & 0xffffffff);
   2.455 -        break;
   2.456 -    default:
   2.457 -        BUG();
   2.458 -    }
   2.459 +    s = &pit->channels[0];
   2.460 +    /* the timer 0 is connected to an IRQ */
   2.461 +    s->vcpu = v;
   2.462 +    s++; s->vcpu = v;
   2.463 +    s++; s->vcpu = v;
   2.464 +
   2.465 +    register_portio_handler(PIT_BASE, 4, handle_pit_io);
   2.466 +    /* register the speaker port */
   2.467 +    register_portio_handler(0x61, 1, handle_speaker_io);
   2.468 +    ticks_per_sec(v) = cpu_khz * (int64_t)1000; 
   2.469 +#ifdef DEBUG_PIT
   2.470 +    printk("HVM_PIT: guest frequency =%lld\n", (long long)ticks_per_sec(v));
   2.471 +#endif
   2.472 +    pit_reset(pit);
   2.473 +    return;
   2.474  }
   2.475  
   2.476  /* the intercept action for PIT DM retval:0--not handled; 1--handled */  
   2.477 -int handle_pit_io(ioreq_t *p)
   2.478 +static int handle_pit_io(ioreq_t *p)
   2.479  {
   2.480      struct vcpu *v = current;
   2.481 -    struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
   2.482 +    struct PITState *vpit = &(v->domain->arch.hvm_domain.pl_time.vpit);
   2.483  
   2.484      if (p->size != 1 ||
   2.485          p->pdata_valid ||
   2.486 @@ -508,18 +407,18 @@ int handle_pit_io(ioreq_t *p)
   2.487      if (p->dir == 0) {/* write */
   2.488          pit_ioport_write(vpit, p->addr, p->u.data);
   2.489      } else if (p->dir == 1) { /* read */
   2.490 -        p->u.data = pit_ioport_read(vpit, p->addr);
   2.491 -        resume_pit_io(p);
   2.492 +        if ( (p->addr & 3) != 3 ) {
   2.493 +            p->u.data = pit_ioport_read(vpit, p->addr);
   2.494 +        } else {
   2.495 +            printk("HVM_PIT: read A1:A0=3!\n");
   2.496 +        }
   2.497      }
   2.498 -
   2.499 -    /* always return 1, since PIT sit in HV now */
   2.500      return 1;
   2.501  }
   2.502  
   2.503  static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val)
   2.504  {
   2.505 -    hvm_virpit *pit = opaque;
   2.506 -    val &= 0xff;
   2.507 +    PITState *pit = opaque;
   2.508      pit->speaker_data_on = (val >> 1) & 1;
   2.509      pit_set_gate(pit, 2, val & 1);
   2.510  }
   2.511 @@ -527,18 +426,18 @@ static void speaker_ioport_write(void *o
   2.512  static uint32_t speaker_ioport_read(void *opaque, uint32_t addr)
   2.513  {
   2.514      int out;
   2.515 -    hvm_virpit *pit = opaque;
   2.516 -    out = pit_get_out(pit, 2, hvm_get_clock());
   2.517 +    PITState *pit = opaque;
   2.518 +    out = pit_get_out(pit, 2, hvm_get_clock(pit->channels[2].vcpu));
   2.519      pit->dummy_refresh_clock ^= 1;
   2.520  
   2.521      return (pit->speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) |
   2.522        (pit->dummy_refresh_clock << 4);
   2.523  }
   2.524  
   2.525 -int handle_speaker_io(ioreq_t *p)
   2.526 +static int handle_speaker_io(ioreq_t *p)
   2.527  {
   2.528      struct vcpu *v = current;
   2.529 -    struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
   2.530 +    struct PITState *vpit = &(v->domain->arch.hvm_domain.pl_time.vpit);
   2.531  
   2.532      if (p->size != 1 ||
   2.533          p->pdata_valid ||
   2.534 @@ -551,45 +450,7 @@ int handle_speaker_io(ioreq_t *p)
   2.535          speaker_ioport_write(vpit, p->addr, p->u.data);
   2.536      } else if (p->dir == 1) {/* read */
   2.537          p->u.data = speaker_ioport_read(vpit, p->addr);
   2.538 -        resume_pit_io(p);
   2.539      }
   2.540  
   2.541      return 1;
   2.542  }
   2.543 -
   2.544 -/* pick up missed timer ticks at deactive time */
   2.545 -void pickup_deactive_ticks(struct hvm_virpit *vpit)
   2.546 -{
   2.547 -    s64 next_time;
   2.548 -    PITChannelState *s = &(vpit->channels[0]);
   2.549 -    if ( !active_timer(&(vpit->time_info.pit_timer)) ) {
   2.550 -        next_time = pit_get_next_transition_time(s, s->next_transition_time); 
   2.551 -        if (next_time >= 0)
   2.552 -            set_timer(&(s->hvm_time->pit_timer), s->next_transition_time);
   2.553 -    }
   2.554 -}
   2.555 -
   2.556 -void pit_init(struct hvm_virpit *pit, struct vcpu *v)
   2.557 -{
   2.558 -    PITChannelState *s;
   2.559 -    struct hvm_time_info *hvm_time;
   2.560 -
   2.561 -    s = &pit->channels[0];
   2.562 -    /* the timer 0 is connected to an IRQ */
   2.563 -    s->irq = 0;
   2.564 -    /* channel 0 need access the related time info for intr injection */
   2.565 -    hvm_time = s->hvm_time = &pit->time_info;
   2.566 -    hvm_time->vcpu = v;
   2.567 -
   2.568 -    init_timer(&(hvm_time->pit_timer), pit_irq_timer, s, v->processor);
   2.569 -
   2.570 -    register_portio_handler(PIT_BASE, 4, handle_pit_io);
   2.571 -
   2.572 -    /* register the speaker port */
   2.573 -    register_portio_handler(0x61, 1, handle_speaker_io);
   2.574 -
   2.575 -    pit_reset(pit);
   2.576 -
   2.577 -    return;
   2.578 -
   2.579 -}
     3.1 --- a/xen/arch/x86/hvm/intercept.c	Thu May 25 16:00:09 2006 +0100
     3.2 +++ b/xen/arch/x86/hvm/intercept.c	Thu May 25 16:00:36 2006 +0100
     3.3 @@ -214,6 +214,88 @@ void hlt_timer_fn(void *data)
     3.4      evtchn_set_pending(v, iopacket_port(v));
     3.5  }
     3.6  
     3.7 +static __inline__ void missed_ticks(struct periodic_time *pt)
     3.8 +{
     3.9 +    int missed_ticks;
    3.10 +
    3.11 +    missed_ticks = (NOW() - pt->scheduled)/(s_time_t) pt->period;
    3.12 +    if ( missed_ticks++ >= 0 ) {
    3.13 +        if ( missed_ticks > 1000 ) {
    3.14 +            /* TODO: Adjust guest time togther */
    3.15 +            pt->pending_intr_nr ++;
    3.16 +        }
    3.17 +        else {
    3.18 +            pt->pending_intr_nr += missed_ticks;
    3.19 +        }
    3.20 +        pt->scheduled += missed_ticks * pt->period;
    3.21 +    }
    3.22 +}
    3.23 +
    3.24 +/* hook function for the platform periodic time */
    3.25 +void pt_timer_fn(void *data)
    3.26 +{
    3.27 +    struct vcpu *v = data;
    3.28 +    struct periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
    3.29 +
    3.30 +    /* pick up missed timer tick */
    3.31 +    missed_ticks(pt);
    3.32 +    if ( test_bit(_VCPUF_running, &v->vcpu_flags) ) {
    3.33 +        set_timer(&pt->timer, pt->scheduled);
    3.34 +    }
    3.35 +}
    3.36 +
    3.37 +/* pick up missed timer ticks at deactive time */
    3.38 +void pickup_deactive_ticks(struct periodic_time *pt)
    3.39 +{
    3.40 +    if ( !active_timer(&(pt->timer)) ) {
    3.41 +        missed_ticks(pt);
    3.42 +        set_timer(&pt->timer, pt->scheduled);
    3.43 +    }
    3.44 +}
    3.45 +
    3.46 +/*
    3.47 + * period: fire frequency in ns.
    3.48 + */
    3.49 +struct periodic_time * create_periodic_time(
    3.50 +        struct vcpu *v, 
    3.51 +        u32 period, 
    3.52 +        char irq,
    3.53 +        char one_shot)
    3.54 +{
    3.55 +    struct periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
    3.56 +    if ( pt->enabled ) {
    3.57 +        if ( v->vcpu_id != 0 ) {
    3.58 +            printk("HVM_PIT: start 2nd periodic time on non BSP!\n");
    3.59 +        }
    3.60 +        stop_timer (&pt->timer);
    3.61 +        pt->enabled = 0;
    3.62 +    }
    3.63 +    pt->pending_intr_nr = 0;
    3.64 +    pt->first_injected = 0;
    3.65 +    if (period < 900000) { /* < 0.9 ms */
    3.66 +        printk("HVM_PlatformTime: program too small period %u\n",period);
    3.67 +        period = 900000;   /* force to 0.9ms */
    3.68 +    }
    3.69 +    pt->period = period;
    3.70 +    pt->irq = irq;
    3.71 +    pt->period_cycles = (u64)period * cpu_khz / 1000000L;
    3.72 +    pt->one_shot = one_shot;
    3.73 +    if ( one_shot ) {
    3.74 +        printk("HVM_PL: No support for one shot platform time yet\n");
    3.75 +    }
    3.76 +    pt->scheduled = NOW() + period;
    3.77 +    set_timer (&pt->timer,pt->scheduled);
    3.78 +    pt->enabled = 1;
    3.79 +    return pt;
    3.80 +}
    3.81 +
    3.82 +void destroy_periodic_time(struct periodic_time *pt)
    3.83 +{
    3.84 +    if ( pt->enabled ) {
    3.85 +        stop_timer(&pt->timer);
    3.86 +        pt->enabled = 0;
    3.87 +    }
    3.88 +}
    3.89  
    3.90  /*
    3.91   * Local variables:
     4.1 --- a/xen/arch/x86/hvm/svm/intr.c	Thu May 25 16:00:09 2006 +0100
     4.2 +++ b/xen/arch/x86/hvm/svm/intr.c	Thu May 25 16:00:36 2006 +0100
     4.3 @@ -44,45 +44,33 @@
     4.4   */
     4.5  #define BSP_CPU(v)    (!(v->vcpu_id))
     4.6  
     4.7 -u64 svm_get_guest_time(struct vcpu *v)
     4.8 -{
     4.9 -    struct hvm_time_info *time_info = &(v->domain->arch.hvm_domain.vpit.time_info);
    4.10 -    u64    host_tsc;
    4.11 -    
    4.12 -    rdtscll(host_tsc);
    4.13 -    return host_tsc + time_info->cache_tsc_offset;
    4.14 -}
    4.15 -
    4.16  void svm_set_guest_time(struct vcpu *v, u64 gtime)
    4.17  {
    4.18 -    struct hvm_time_info *time_info = &(v->domain->arch.hvm_domain.vpit.time_info);
    4.19      u64    host_tsc;
    4.20     
    4.21      rdtscll(host_tsc);
    4.22      
    4.23 -    time_info->cache_tsc_offset = gtime - host_tsc;
    4.24 -    v->arch.hvm_svm.vmcb->tsc_offset = time_info->cache_tsc_offset;
    4.25 +    v->arch.hvm_vcpu.cache_tsc_offset = gtime - host_tsc;
    4.26 +    v->arch.hvm_svm.vmcb->tsc_offset = v->arch.hvm_vcpu.cache_tsc_offset;
    4.27  }
    4.28  
    4.29  static inline void
    4.30  interrupt_post_injection(struct vcpu * v, int vector, int type)
    4.31  {
    4.32 -    struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
    4.33 -    struct hvm_time_info *time_info = &vpit->time_info;
    4.34 +    struct  periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
    4.35  
    4.36      if ( is_pit_irq(v, vector, type) ) {
    4.37 -        if ( !time_info->first_injected ) {
    4.38 -            time_info->pending_intr_nr = 0;
    4.39 -            time_info->last_pit_gtime = svm_get_guest_time(v);
    4.40 -            time_info->first_injected = 1;
    4.41 +        if ( !pt->first_injected ) {
    4.42 +            pt->pending_intr_nr = 0;
    4.43 +            pt->last_plt_gtime = hvm_get_guest_time(v);
    4.44 +            pt->scheduled = NOW() + pt->period;
    4.45 +            set_timer(&pt->timer, pt->scheduled);
    4.46 +            pt->first_injected = 1;
    4.47          } else {
    4.48 -            time_info->pending_intr_nr--;
    4.49 +            pt->pending_intr_nr--;
    4.50 +            pt->last_plt_gtime += pt->period_cycles;
    4.51 +            svm_set_guest_time(v, pt->last_plt_gtime);
    4.52          }
    4.53 -        time_info->count_advance = 0;
    4.54 -        time_info->count_point = NOW();
    4.55 -
    4.56 -        time_info->last_pit_gtime += time_info->period_cycles;
    4.57 -        svm_set_guest_time(v, time_info->last_pit_gtime);
    4.58      }
    4.59  
    4.60      switch(type)
    4.61 @@ -121,8 +109,7 @@ asmlinkage void svm_intr_assist(void)
    4.62      struct vcpu *v = current;
    4.63      struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
    4.64      struct hvm_domain *plat=&v->domain->arch.hvm_domain; 
    4.65 -    struct hvm_virpit *vpit = &plat->vpit;
    4.66 -    struct hvm_time_info *time_info = &vpit->time_info;
    4.67 +    struct periodic_time *pt = &plat->pl_time.periodic_tm;
    4.68      struct hvm_virpic *pic= &plat->vpic;
    4.69      int intr_type = VLAPIC_DELIV_MODE_EXT;
    4.70      int intr_vector = -1;
    4.71 @@ -174,9 +161,9 @@ asmlinkage void svm_intr_assist(void)
    4.72        if ( cpu_has_pending_irq(v) ) {
    4.73             intr_vector = cpu_get_interrupt(v, &intr_type);
    4.74        }
    4.75 -      else  if ( (v->vcpu_id == 0) && time_info->pending_intr_nr ) {
    4.76 -          pic_set_irq(pic, 0, 0);
    4.77 -          pic_set_irq(pic, 0, 1);
    4.78 +      else  if ( (v->vcpu_id == 0) && pt->enabled && pt->pending_intr_nr ) {
    4.79 +          pic_set_irq(pic, pt->irq, 0);
    4.80 +          pic_set_irq(pic, pt->irq, 1);
    4.81            intr_vector = cpu_get_interrupt(v, &intr_type);
    4.82        }
    4.83      }
    4.84 @@ -190,7 +177,7 @@ asmlinkage void svm_intr_assist(void)
    4.85              /* Re-injecting a PIT interruptt? */
    4.86              if (re_injecting && 
    4.87                  is_pit_irq(v, intr_vector, intr_type)) {
    4.88 -                    ++time_info->pending_intr_nr;
    4.89 +                    ++pt->pending_intr_nr;
    4.90              }
    4.91              /* let's inject this interrupt */
    4.92              TRACE_3D(TRC_VMX_INT, v->domain->domain_id, intr_vector, 0);
     5.1 --- a/xen/arch/x86/hvm/svm/svm.c	Thu May 25 16:00:09 2006 +0100
     5.2 +++ b/xen/arch/x86/hvm/svm/svm.c	Thu May 25 16:00:36 2006 +0100
     5.3 @@ -672,12 +672,11 @@ static void arch_svm_do_launch(struct vc
     5.4  
     5.5  static void svm_freeze_time(struct vcpu *v)
     5.6  {
     5.7 -    struct hvm_time_info *time_info = &v->domain->arch.hvm_domain.vpit.time_info;
     5.8 +    struct periodic_time *pt=&v->domain->arch.hvm_domain.pl_time.periodic_tm;
     5.9      
    5.10 -    if ( time_info->first_injected && !v->domain->arch.hvm_domain.guest_time ) {
    5.11 -        v->domain->arch.hvm_domain.guest_time = svm_get_guest_time(v);
    5.12 -        time_info->count_advance += (NOW() - time_info->count_point);
    5.13 -        stop_timer(&(time_info->pit_timer));
    5.14 +    if ( pt->enabled && pt->first_injected && !v->arch.hvm_vcpu.guest_time ) {
    5.15 +        v->arch.hvm_vcpu.guest_time = hvm_get_guest_time(v);
    5.16 +        stop_timer(&(pt->timer));
    5.17      }
    5.18  }
    5.19  
    5.20 @@ -754,7 +753,7 @@ static void svm_relinquish_guest_resourc
    5.21          }
    5.22      }
    5.23  
    5.24 -    kill_timer(&d->arch.hvm_domain.vpit.time_info.pit_timer);
    5.25 +    kill_timer(&d->arch.hvm_domain.pl_time.periodic_tm.timer);
    5.26  
    5.27      if ( d->arch.hvm_domain.shared_page_va )
    5.28          unmap_domain_page_global(
    5.29 @@ -784,10 +783,12 @@ void arch_svm_do_resume(struct vcpu *v)
    5.30  
    5.31  void svm_migrate_timers(struct vcpu *v)
    5.32  {
    5.33 -    struct hvm_time_info *time_info = &v->domain->arch.hvm_domain.vpit.time_info;
    5.34 -
    5.35 -    migrate_timer(&time_info->pit_timer, v->processor);
    5.36 -    migrate_timer(&v->arch.hvm_svm.hlt_timer, v->processor);
    5.37 +    struct periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
    5.38 +
    5.39 +    if ( pt->enabled ) {
    5.40 +        migrate_timer( &pt->timer, v->processor );
    5.41 +        migrate_timer( &v->arch.hvm_svm.hlt_timer, v->processor );
    5.42 +    }
    5.43      if ( hvm_apic_support(v->domain) && VLAPIC( v ))
    5.44          migrate_timer( &(VLAPIC(v)->vlapic_timer ), v->processor );
    5.45  }
    5.46 @@ -1901,14 +1902,8 @@ static inline void svm_do_msr_access(str
    5.47          regs->edx = 0;
    5.48          switch (regs->ecx) {
    5.49          case MSR_IA32_TIME_STAMP_COUNTER:
    5.50 -        {
    5.51 -            struct hvm_time_info *time_info;
    5.52 -
    5.53 -            rdtscll(msr_content);
    5.54 -            time_info = &v->domain->arch.hvm_domain.vpit.time_info;
    5.55 -            msr_content += time_info->cache_tsc_offset;
    5.56 +            msr_content = hvm_get_guest_time(v);
    5.57              break;
    5.58 -        }
    5.59          case MSR_IA32_SYSENTER_CS:
    5.60              msr_content = vmcb->sysenter_cs;
    5.61              break;
    5.62 @@ -1975,7 +1970,7 @@ done:
    5.63  static inline void svm_vmexit_do_hlt(struct vmcb_struct *vmcb)
    5.64  {
    5.65      struct vcpu *v = current;
    5.66 -    struct hvm_virpit *vpit = &v->domain->arch.hvm_domain.vpit;
    5.67 +    struct periodic_time *pt=&v->domain->arch.hvm_domain.pl_time.periodic_tm;
    5.68      s_time_t  next_pit = -1, next_wakeup;
    5.69  
    5.70      __update_guest_eip(vmcb, 1);
    5.71 @@ -1985,7 +1980,7 @@ static inline void svm_vmexit_do_hlt(str
    5.72         return; 
    5.73  
    5.74      if ( !v->vcpu_id )
    5.75 -        next_pit = get_pit_scheduled(v, vpit);
    5.76 +        next_pit = get_scheduled(v, pt->irq, pt);
    5.77      next_wakeup = get_apictime_scheduled(v);
    5.78      if ( (next_pit != -1 && next_pit < next_wakeup) || next_wakeup == -1 )
    5.79          next_wakeup = next_pit;
     6.1 --- a/xen/arch/x86/hvm/svm/vmcb.c	Thu May 25 16:00:09 2006 +0100
     6.2 +++ b/xen/arch/x86/hvm/svm/vmcb.c	Thu May 25 16:00:36 2006 +0100
     6.3 @@ -442,19 +442,17 @@ void set_hsa_to_guest( struct arch_svm_s
     6.4  void svm_do_resume(struct vcpu *v) 
     6.5  {
     6.6      struct domain *d = v->domain;
     6.7 -    struct hvm_virpit *vpit = &d->arch.hvm_domain.vpit;
     6.8 -    struct hvm_time_info *time_info = &vpit->time_info;
     6.9 +    struct periodic_time *pt = &d->arch.hvm_domain.pl_time.periodic_tm;
    6.10  
    6.11      svm_stts(v);
    6.12  
    6.13      /* pick up the elapsed PIT ticks and re-enable pit_timer */
    6.14 -    if ( time_info->first_injected ) {
    6.15 -        if ( v->domain->arch.hvm_domain.guest_time ) {
    6.16 -            svm_set_guest_time(v, v->domain->arch.hvm_domain.guest_time);
    6.17 -            time_info->count_point = NOW();
    6.18 -            v->domain->arch.hvm_domain.guest_time = 0;
    6.19 +    if ( pt->enabled && pt->first_injected ) {
    6.20 +        if ( v->arch.hvm_vcpu.guest_time ) {
    6.21 +            svm_set_guest_time(v, v->arch.hvm_vcpu.guest_time);
    6.22 +            v->arch.hvm_vcpu.guest_time = 0;
    6.23          }
    6.24 -        pickup_deactive_ticks(vpit);
    6.25 +        pickup_deactive_ticks(pt);
    6.26      }
    6.27  
    6.28      if ( test_bit(iopacket_port(v), &d->shared_info->evtchn_pending[0]) ||
     7.1 --- a/xen/arch/x86/hvm/vmx/io.c	Thu May 25 16:00:09 2006 +0100
     7.2 +++ b/xen/arch/x86/hvm/vmx/io.c	Thu May 25 16:00:36 2006 +0100
     7.3 @@ -49,45 +49,33 @@ void __set_tsc_offset(u64  offset)
     7.4  #endif
     7.5  }
     7.6  
     7.7 -u64 get_guest_time(struct vcpu *v)
     7.8 -{
     7.9 -    struct hvm_time_info *time_info = &(v->domain->arch.hvm_domain.vpit.time_info);
    7.10 -    u64    host_tsc;
    7.11 -    
    7.12 -    rdtscll(host_tsc);
    7.13 -    return host_tsc + time_info->cache_tsc_offset;
    7.14 -}
    7.15 -
    7.16  void set_guest_time(struct vcpu *v, u64 gtime)
    7.17  {
    7.18 -    struct hvm_time_info *time_info = &(v->domain->arch.hvm_domain.vpit.time_info);
    7.19      u64    host_tsc;
    7.20     
    7.21      rdtscll(host_tsc);
    7.22      
    7.23 -    time_info->cache_tsc_offset = gtime - host_tsc;
    7.24 -    __set_tsc_offset(time_info->cache_tsc_offset);
    7.25 +    v->arch.hvm_vcpu.cache_tsc_offset = gtime - host_tsc;
    7.26 +    __set_tsc_offset(v->arch.hvm_vcpu.cache_tsc_offset);
    7.27  }
    7.28  
    7.29  static inline void
    7.30  interrupt_post_injection(struct vcpu * v, int vector, int type)
    7.31  {
    7.32 -    struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
    7.33 -    struct hvm_time_info *time_info = &vpit->time_info;
    7.34 +    struct periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
    7.35  
    7.36      if ( is_pit_irq(v, vector, type) ) {
    7.37 -        if ( !time_info->first_injected ) {
    7.38 -            time_info->pending_intr_nr = 0;
    7.39 -            time_info->last_pit_gtime = get_guest_time(v);
    7.40 -            time_info->first_injected = 1;
    7.41 +        if ( !pt->first_injected ) {
    7.42 +            pt->pending_intr_nr = 0;
    7.43 +            pt->last_plt_gtime = hvm_get_guest_time(v);
    7.44 +            pt->scheduled = NOW() + pt->period;
    7.45 +            set_timer(&pt->timer, pt->scheduled);
    7.46 +            pt->first_injected = 1;
    7.47          } else {
    7.48 -            time_info->pending_intr_nr--;
    7.49 +            pt->pending_intr_nr--;
    7.50 +            pt->last_plt_gtime += pt->period_cycles;
    7.51 +            set_guest_time(v, pt->last_plt_gtime);
    7.52          }
    7.53 -        time_info->count_advance = 0;
    7.54 -        time_info->count_point = NOW();
    7.55 -
    7.56 -        time_info->last_pit_gtime += time_info->period_cycles;
    7.57 -        set_guest_time(v, time_info->last_pit_gtime);
    7.58      }
    7.59  
    7.60      switch(type)
    7.61 @@ -151,7 +139,7 @@ asmlinkage void vmx_intr_assist(void)
    7.62      unsigned long eflags;
    7.63      struct vcpu *v = current;
    7.64      struct hvm_domain *plat=&v->domain->arch.hvm_domain;
    7.65 -    struct hvm_time_info *time_info = &plat->vpit.time_info;
    7.66 +    struct periodic_time *pt = &plat->pl_time.periodic_tm;
    7.67      struct hvm_virpic *pic= &plat->vpic;
    7.68      unsigned int idtv_info_field;
    7.69      unsigned long inst_len;
    7.70 @@ -160,9 +148,9 @@ asmlinkage void vmx_intr_assist(void)
    7.71      if ( v->vcpu_id == 0 )
    7.72          hvm_pic_assist(v);
    7.73  
    7.74 -    if ( (v->vcpu_id == 0) && time_info->pending_intr_nr ) {
    7.75 -        pic_set_irq(pic, 0, 0);
    7.76 -        pic_set_irq(pic, 0, 1);
    7.77 +    if ( (v->vcpu_id == 0) && pt->enabled && pt->pending_intr_nr ) {
    7.78 +        pic_set_irq(pic, pt->irq, 0);
    7.79 +        pic_set_irq(pic, pt->irq, 1);
    7.80      }
    7.81  
    7.82      has_ext_irq = cpu_has_pending_irq(v);
    7.83 @@ -232,19 +220,17 @@ asmlinkage void vmx_intr_assist(void)
    7.84  void vmx_do_resume(struct vcpu *v)
    7.85  {
    7.86      struct domain *d = v->domain;
    7.87 -    struct hvm_virpit *vpit = &v->domain->arch.hvm_domain.vpit;
    7.88 -    struct hvm_time_info *time_info = &vpit->time_info;
    7.89 +    struct periodic_time *pt = &v->domain->arch.hvm_domain.pl_time.periodic_tm;
    7.90  
    7.91      vmx_stts();
    7.92  
    7.93      /* pick up the elapsed PIT ticks and re-enable pit_timer */
    7.94 -    if ( time_info->first_injected ) {
    7.95 -        if ( v->domain->arch.hvm_domain.guest_time ) {
    7.96 -            time_info->count_point = NOW();
    7.97 -            set_guest_time(v, v->domain->arch.hvm_domain.guest_time);
    7.98 -            v->domain->arch.hvm_domain.guest_time = 0;
    7.99 +    if ( pt->enabled && pt->first_injected ) {
   7.100 +        if ( v->arch.hvm_vcpu.guest_time ) {
   7.101 +            set_guest_time(v, v->arch.hvm_vcpu.guest_time);
   7.102 +            v->arch.hvm_vcpu.guest_time = 0;
   7.103          }
   7.104 -        pickup_deactive_ticks(vpit);
   7.105 +        pickup_deactive_ticks(pt);
   7.106      }
   7.107  
   7.108      if ( test_bit(iopacket_port(v), &d->shared_info->evtchn_pending[0]) ||
     8.1 --- a/xen/arch/x86/hvm/vmx/vmx.c	Thu May 25 16:00:09 2006 +0100
     8.2 +++ b/xen/arch/x86/hvm/vmx/vmx.c	Thu May 25 16:00:36 2006 +0100
     8.3 @@ -102,7 +102,7 @@ static void vmx_relinquish_guest_resourc
     8.4          }
     8.5      }
     8.6  
     8.7 -    kill_timer(&d->arch.hvm_domain.vpit.time_info.pit_timer);
     8.8 +    kill_timer(&d->arch.hvm_domain.pl_time.periodic_tm.timer);
     8.9  
    8.10      if ( d->arch.hvm_domain.shared_page_va )
    8.11          unmap_domain_page_global(
    8.12 @@ -358,12 +358,11 @@ static inline int long_mode_do_msr_write
    8.13  
    8.14  static void vmx_freeze_time(struct vcpu *v)
    8.15  {
    8.16 -    struct hvm_time_info *time_info = &(v->domain->arch.hvm_domain.vpit.time_info);
    8.17 +    struct periodic_time *pt=&v->domain->arch.hvm_domain.pl_time.periodic_tm;
    8.18      
    8.19 -    if ( time_info->first_injected && !v->domain->arch.hvm_domain.guest_time ) {
    8.20 -        v->domain->arch.hvm_domain.guest_time = get_guest_time(v);
    8.21 -        time_info->count_advance += (NOW() - time_info->count_point);
    8.22 -        stop_timer(&(time_info->pit_timer));
    8.23 +    if ( pt->enabled && pt->first_injected && !v->arch.hvm_vcpu.guest_time ) {
    8.24 +        v->arch.hvm_vcpu.guest_time = hvm_get_guest_time(v);
    8.25 +        stop_timer(&(pt->timer));
    8.26      }
    8.27  }
    8.28  
    8.29 @@ -393,10 +392,12 @@ int vmx_initialize_guest_resources(struc
    8.30  
    8.31  void vmx_migrate_timers(struct vcpu *v)
    8.32  {
    8.33 -    struct hvm_time_info *time_info = &v->domain->arch.hvm_domain.vpit.time_info;
    8.34 +    struct periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
    8.35  
    8.36 -    migrate_timer(&time_info->pit_timer, v->processor);
    8.37 -    migrate_timer(&v->arch.hvm_vmx.hlt_timer, v->processor);
    8.38 +    if ( pt->enabled ) {
    8.39 +        migrate_timer(&pt->timer, v->processor);
    8.40 +        migrate_timer(&v->arch.hvm_vmx.hlt_timer, v->processor);
    8.41 +    }
    8.42      if ( hvm_apic_support(v->domain) && VLAPIC(v))
    8.43          migrate_timer(&(VLAPIC(v)->vlapic_timer), v->processor);
    8.44  }
    8.45 @@ -1861,14 +1862,8 @@ static inline void vmx_do_msr_read(struc
    8.46                  (unsigned long)regs->edx);
    8.47      switch (regs->ecx) {
    8.48      case MSR_IA32_TIME_STAMP_COUNTER:
    8.49 -    {
    8.50 -        struct hvm_time_info *time_info;
    8.51 -
    8.52 -        rdtscll(msr_content);
    8.53 -        time_info = &(v->domain->arch.hvm_domain.vpit.time_info);
    8.54 -        msr_content += time_info->cache_tsc_offset;
    8.55 +        msr_content = hvm_get_guest_time(v);
    8.56          break;
    8.57 -    }
    8.58      case MSR_IA32_SYSENTER_CS:
    8.59          __vmread(GUEST_SYSENTER_CS, (u32 *)&msr_content);
    8.60          break;
    8.61 @@ -1941,11 +1936,11 @@ static inline void vmx_do_msr_write(stru
    8.62  void vmx_vmexit_do_hlt(void)
    8.63  {
    8.64      struct vcpu *v=current;
    8.65 -    struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
    8.66 +    struct periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
    8.67      s_time_t   next_pit=-1,next_wakeup;
    8.68  
    8.69      if ( !v->vcpu_id )
    8.70 -        next_pit = get_pit_scheduled(v,vpit);
    8.71 +        next_pit = get_scheduled(v, pt->irq, pt);
    8.72      next_wakeup = get_apictime_scheduled(v);
    8.73      if ( (next_pit != -1 && next_pit < next_wakeup) || next_wakeup == -1 )
    8.74          next_wakeup = next_pit;
     9.1 --- a/xen/include/asm-x86/hvm/domain.h	Thu May 25 16:00:09 2006 +0100
     9.2 +++ b/xen/include/asm-x86/hvm/domain.h	Thu May 25 16:00:36 2006 +0100
     9.3 @@ -35,9 +35,9 @@ struct hvm_domain {
     9.4      unsigned int           nr_vcpus;
     9.5      unsigned int           apic_enabled;
     9.6      unsigned int           pae_enabled;
     9.7 -
     9.8 -    struct hvm_virpit      vpit;
     9.9 -    u64                    guest_time;
    9.10 +    s64                    tsc_frequency;
    9.11 +    struct pl_time         pl_time;
    9.12 +    
    9.13      struct hvm_virpic      vpic;
    9.14      struct hvm_vioapic     vioapic;
    9.15      struct hvm_io_handler  io_handler;
    10.1 --- a/xen/include/asm-x86/hvm/svm/intr.h	Thu May 25 16:00:09 2006 +0100
    10.2 +++ b/xen/include/asm-x86/hvm/svm/intr.h	Thu May 25 16:00:36 2006 +0100
    10.3 @@ -21,7 +21,6 @@
    10.4  #ifndef __ASM_X86_HVM_SVM_INTR_H__
    10.5  #define __ASM_X86_HVM_SVM_INTR_H__
    10.6  
    10.7 -extern void svm_set_tsc_shift(struct vcpu *v, struct hvm_virpit *vpit);
    10.8  extern void svm_intr_assist(void);
    10.9  extern void svm_intr_assist_update(struct vcpu *v, int highest_vector);
   10.10  extern void svm_intr_assist_test_valid(struct vcpu *v, 
    11.1 --- a/xen/include/asm-x86/hvm/svm/svm.h	Thu May 25 16:00:09 2006 +0100
    11.2 +++ b/xen/include/asm-x86/hvm/svm/svm.h	Thu May 25 16:00:36 2006 +0100
    11.3 @@ -48,7 +48,6 @@ extern void svm_stts(struct vcpu *v);
    11.4  extern void svm_do_launch(struct vcpu *v);
    11.5  extern void svm_do_resume(struct vcpu *v);
    11.6  extern void svm_set_guest_time(struct vcpu *v, u64 gtime);
    11.7 -extern u64 svm_get_guest_time(struct vcpu *v);
    11.8  extern void arch_svm_do_resume(struct vcpu *v);
    11.9  extern int load_vmcb(struct arch_svm_struct *arch_svm, u64 phys_hsa);
   11.10  /* For debugging. Remove when no longer needed. */
    12.1 --- a/xen/include/asm-x86/hvm/vcpu.h	Thu May 25 16:00:09 2006 +0100
    12.2 +++ b/xen/include/asm-x86/hvm/vcpu.h	Thu May 25 16:00:36 2006 +0100
    12.3 @@ -32,6 +32,9 @@ struct hvm_vcpu {
    12.4      unsigned long   ioflags;
    12.5      struct mmio_op  mmio_op;
    12.6      struct vlapic   *vlapic;
    12.7 +    s64             cache_tsc_offset;
    12.8 +    u64             guest_time;
    12.9 +
   12.10      /* For AP startup */
   12.11      unsigned long   init_sipi_sipi_state;
   12.12  
    13.1 --- a/xen/include/asm-x86/hvm/vmx/vmx.h	Thu May 25 16:00:09 2006 +0100
    13.2 +++ b/xen/include/asm-x86/hvm/vmx/vmx.h	Thu May 25 16:00:36 2006 +0100
    13.3 @@ -34,7 +34,6 @@ extern void vmx_migrate_timers(struct vc
    13.4  extern void arch_vmx_do_launch(struct vcpu *);
    13.5  extern void arch_vmx_do_resume(struct vcpu *);
    13.6  extern void set_guest_time(struct vcpu *v, u64 gtime);
    13.7 -extern u64  get_guest_time(struct vcpu *v);
    13.8  
    13.9  extern unsigned int cpu_rev;
   13.10  
    14.1 --- a/xen/include/asm-x86/hvm/vpit.h	Thu May 25 16:00:09 2006 +0100
    14.2 +++ b/xen/include/asm-x86/hvm/vpit.h	Thu May 25 16:00:36 2006 +0100
    14.3 @@ -29,9 +29,7 @@
    14.4  #include <asm/hvm/vpic.h>
    14.5  
    14.6  #define PIT_FREQ 1193181
    14.7 -
    14.8 -#define PIT_BASE 0x40
    14.9 -#define HVM_PIT_ACCEL_MODE 2
   14.10 +#define PIT_BASE        0x40
   14.11  
   14.12  typedef struct PITChannelState {
   14.13      int count; /* can be 65536 */
   14.14 @@ -48,47 +46,56 @@ typedef struct PITChannelState {
   14.15      u8 gate; /* timer start */
   14.16      s64 count_load_time;
   14.17      /* irq handling */
   14.18 -    s64 next_transition_time;
   14.19 -    int irq;
   14.20 -    struct hvm_time_info *hvm_time;
   14.21 -    u32 period; /* period(ns) based on count */
   14.22 +    struct vcpu      *vcpu;
   14.23 +    struct periodic_time *pt;
   14.24  } PITChannelState;
   14.25 -
   14.26 -struct hvm_time_info {
   14.27 -    /* extra info for the mode 2 channel */
   14.28 -    struct timer pit_timer;
   14.29 -    struct vcpu *vcpu;          /* which vcpu the ac_timer bound to */
   14.30 -    u64 period_cycles;          /* pit frequency in cpu cycles */
   14.31 -    s_time_t count_advance;     /* accumulated count advance since last fire */
   14.32 -    s_time_t count_point;        /* last point accumulating count advance */
   14.33 -    unsigned int pending_intr_nr; /* the couner for pending timer interrupts */
   14.34 -    int first_injected;         /* flag to prevent shadow window */
   14.35 -    s64 cache_tsc_offset;       /* cache of VMCS TSC_OFFSET offset */
   14.36 -    u64 last_pit_gtime;         /* guest time when last pit is injected */
   14.37 +   
   14.38 +/*
   14.39 + * Abstract layer of periodic time, one short time.
   14.40 + */
   14.41 +struct periodic_time {
   14.42 +    char enabled;               /* enabled */
   14.43 +    char one_shot;              /* one shot time */
   14.44 +    char irq;
   14.45 +    char first_injected;        /* flag to prevent shadow window */
   14.46 +    u32 pending_intr_nr;        /* the couner for pending timer interrupts */
   14.47 +    u32 period;                 /* frequency in ns */
   14.48 +    u64 period_cycles;          /* frequency in cpu cycles */
   14.49 +    s_time_t scheduled;         /* scheduled timer interrupt */
   14.50 +    u64 last_plt_gtime;         /* platform time when last IRQ is injected */
   14.51 +    struct timer timer;         /* ac_timer */
   14.52  };
   14.53  
   14.54 -typedef struct hvm_virpit {
   14.55 +typedef struct PITState {
   14.56      PITChannelState channels[3];
   14.57 -    struct hvm_time_info time_info;
   14.58      int speaker_data_on;
   14.59      int dummy_refresh_clock;
   14.60 -}hvm_virpit;
   14.61 -
   14.62 +} PITState;
   14.63  
   14.64 -static __inline__ s_time_t get_pit_scheduled(
   14.65 -    struct vcpu *v,
   14.66 -    struct hvm_virpit *vpit)
   14.67 +struct pl_time {    /* platform time */
   14.68 +    struct periodic_time periodic_tm;
   14.69 +    struct PITState      vpit;
   14.70 +    /* TODO: RTC/ACPI time */
   14.71 +};
   14.72 +
   14.73 +static __inline__ s_time_t get_scheduled(
   14.74 +    struct vcpu *v, int irq,
   14.75 +    struct periodic_time *pt)
   14.76  {
   14.77 -    struct PITChannelState *s = &(vpit->channels[0]);
   14.78 -    if ( is_irq_enabled(v, 0) ) {
   14.79 -        return s->next_transition_time;
   14.80 +    if ( is_irq_enabled(v, irq) ) {
   14.81 +        return pt->scheduled;
   14.82      }
   14.83      else
   14.84          return -1;
   14.85  }
   14.86  
   14.87  /* to hook the ioreq packet to get the PIT initialization info */
   14.88 -extern void pit_init(struct hvm_virpit *pit, struct vcpu *v);
   14.89 -extern void pickup_deactive_ticks(struct hvm_virpit *vpit);
   14.90 +extern void hvm_hooks_assist(struct vcpu *v);
   14.91 +extern void pickup_deactive_ticks(struct periodic_time *vpit);
   14.92 +extern u64 hvm_get_guest_time(struct vcpu *v);
   14.93 +extern struct periodic_time *create_periodic_time(struct vcpu *v, u32 period, char irq, char one_shot);
   14.94 +extern void destroy_periodic_time(struct periodic_time *pt);
   14.95 +void pit_init(struct vcpu *v, unsigned long cpu_khz);
   14.96 +void pt_timer_fn(void *data);
   14.97  
   14.98  #endif /* __ASM_X86_HVM_VPIT_H__ */