ia64/xen-unstable

changeset 9777:5765497cf75e

Sync PIT device model with latest qemu and move it to hypervisor.
Signed-off-by: Edwin Zhai <edwin.zhai@intel.com>
author kaf24@firebug.cl.cam.ac.uk
date Wed Apr 19 18:38:14 2006 +0100 (2006-04-19)
parents 72f9c751d3ea
children 123ff1c70728
files tools/ioemu/hw/pc.c tools/ioemu/target-i386-dm/Makefile xen/arch/x86/hvm/Makefile xen/arch/x86/hvm/hvm.c xen/arch/x86/hvm/i8254.c xen/arch/x86/hvm/intercept.c xen/arch/x86/hvm/io.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/vpit.h
line diff
     1.1 --- a/tools/ioemu/hw/pc.c	Wed Apr 19 18:32:20 2006 +0100
     1.2 +++ b/tools/ioemu/hw/pc.c	Wed Apr 19 18:38:14 2006 +0100
     1.3 @@ -40,7 +40,6 @@ int speaker_data_on;
     1.4  int dummy_refresh_clock;
     1.5  static fdctrl_t *floppy_controller;
     1.6  static RTCState *rtc_state;
     1.7 -static PITState *pit;
     1.8  
     1.9  static void ioport80_write(void *opaque, uint32_t addr, uint32_t data)
    1.10  {
    1.11 @@ -243,17 +242,13 @@ static void cmos_init(uint64_t ram_size,
    1.12  
    1.13  static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val)
    1.14  {
    1.15 -    speaker_data_on = (val >> 1) & 1;
    1.16 -    pit_set_gate(pit, 2, val & 1);
    1.17 +    fprintf(stderr, "speaker port should not be handled in DM!\n");
    1.18  }
    1.19  
    1.20  static uint32_t speaker_ioport_read(void *opaque, uint32_t addr)
    1.21  {
    1.22 -    int out;
    1.23 -    out = pit_get_out(pit, 2, qemu_get_clock(vm_clock));
    1.24 -    dummy_refresh_clock ^= 1;
    1.25 -    return (speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) |
    1.26 -      (dummy_refresh_clock << 4);
    1.27 +    fprintf(stderr, "speaker port should not be handled in DM!\n");
    1.28 +    return 0;
    1.29  }
    1.30  
    1.31  static void ioport92_write(void *opaque, uint32_t addr, uint32_t val)
    1.32 @@ -529,7 +524,6 @@ void pc_init(uint64_t ram_size, int vga_
    1.33      register_ioport_write(0x92, 1, 1, ioport92_write, NULL);
    1.34  
    1.35      pic_init();
    1.36 -    pit = pit_init(0x40, 0);
    1.37  
    1.38      for(i = 0; i < MAX_SERIAL_PORTS; i++) {
    1.39          if (serial_hds[i]) {
     2.1 --- a/tools/ioemu/target-i386-dm/Makefile	Wed Apr 19 18:32:20 2006 +0100
     2.2 +++ b/tools/ioemu/target-i386-dm/Makefile	Wed Apr 19 18:38:14 2006 +0100
     2.3 @@ -277,7 +277,7 @@ endif
     2.4  
     2.5  # Hardware support
     2.6  VL_OBJS+= ide.o ne2000.o pckbd.o vga.o dma.o
     2.7 -VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259_stub.o i8254.o pc.o port-e9.o
     2.8 +VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259_stub.o pc.o port-e9.o
     2.9  VL_OBJS+= cirrus_vga.o pcnet.o
    2.10  VL_OBJS+= $(SOUND_HW) $(AUDIODRV) mixeng.o
    2.11  
     3.1 --- a/xen/arch/x86/hvm/Makefile	Wed Apr 19 18:32:20 2006 +0100
     3.2 +++ b/xen/arch/x86/hvm/Makefile	Wed Apr 19 18:38:14 2006 +0100
     3.3 @@ -2,6 +2,7 @@ subdir-y += svm
     3.4  subdir-y += vmx
     3.5  
     3.6  obj-y += hvm.o
     3.7 +obj-y += i8254.o
     3.8  obj-y += i8259.o
     3.9  obj-y += intercept.o
    3.10  obj-y += io.o
     4.1 --- a/xen/arch/x86/hvm/hvm.c	Wed Apr 19 18:32:20 2006 +0100
     4.2 +++ b/xen/arch/x86/hvm/hvm.c	Wed Apr 19 18:38:14 2006 +0100
     4.3 @@ -203,6 +203,8 @@ void hvm_setup_platform(struct domain* d
     4.4          spin_lock_init(&d->arch.hvm_domain.round_robin_lock);
     4.5          hvm_vioapic_init(d);
     4.6      }
     4.7 +
     4.8 +    pit_init(&platform->vpit, current);
     4.9  }
    4.10  
    4.11  void pic_irq_request(void *data, int level)
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/xen/arch/x86/hvm/i8254.c	Wed Apr 19 18:38:14 2006 +0100
     5.3 @@ -0,0 +1,594 @@
     5.4 +/*
     5.5 + * QEMU 8253/8254 interval timer emulation
     5.6 + * 
     5.7 + * Copyright (c) 2003-2004 Fabrice Bellard
     5.8 + * Copyright (c) 2006 Intel Corperation
     5.9 + * 
    5.10 + * Permission is hereby granted, free of charge, to any person obtaining a copy
    5.11 + * of this software and associated documentation files (the "Software"), to deal
    5.12 + * in the Software without restriction, including without limitation the rights
    5.13 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    5.14 + * copies of the Software, and to permit persons to whom the Software is
    5.15 + * furnished to do so, subject to the following conditions:
    5.16 + *
    5.17 + * The above copyright notice and this permission notice shall be included in
    5.18 + * all copies or substantial portions of the Software.
    5.19 + *
    5.20 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    5.21 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    5.22 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    5.23 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    5.24 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    5.25 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    5.26 + * THE SOFTWARE.
    5.27 + */
    5.28 +/* Edwin Zhai <edwin.zhai@intel.com>
    5.29 + * Ported to xen:
    5.30 + * use actimer for intr generation;
    5.31 + * move speaker io access to hypervisor;
    5.32 + * use new method for counter/intrs calculation
    5.33 + */
    5.34 +
    5.35 +#include <xen/config.h>
    5.36 +#include <xen/types.h>
    5.37 +#include <xen/mm.h>
    5.38 +#include <xen/xmalloc.h>
    5.39 +#include <xen/lib.h>
    5.40 +#include <xen/errno.h>
    5.41 +#include <xen/sched.h>
    5.42 +#include <asm/hvm/hvm.h>
    5.43 +#include <asm/hvm/io.h>
    5.44 +#include <asm/hvm/support.h>
    5.45 +#include <asm/hvm/vpit.h>
    5.46 +#include <asm/current.h>
    5.47 +
    5.48 +/*#define DEBUG_PIT*/
    5.49 +
    5.50 +#define RW_STATE_LSB 1
    5.51 +#define RW_STATE_MSB 2
    5.52 +#define RW_STATE_WORD0 3
    5.53 +#define RW_STATE_WORD1 4
    5.54 +
    5.55 +#ifndef NSEC_PER_SEC
    5.56 +#define NSEC_PER_SEC (1000000000ULL)
    5.57 +#endif
    5.58 +
    5.59 +#ifndef TIMER_SLOP 
    5.60 +#define TIMER_SLOP (50*1000) /* ns */
    5.61 +#endif
    5.62 +
    5.63 +static void pit_irq_timer_update(PITChannelState *s, s64 current_time);
    5.64 +
    5.65 +s_time_t hvm_get_clock(void)
    5.66 +{
    5.67 +    /* TODO: add pause/unpause support */
    5.68 +    return NOW();
    5.69 +}
    5.70 +
    5.71 +static int pit_get_count(PITChannelState *s)
    5.72 +{
    5.73 +    u64 d;
    5.74 +    u64 counter;
    5.75 +
    5.76 +    d = hvm_get_clock() - s->count_load_time;
    5.77 +    switch(s->mode) {
    5.78 +    case 0:
    5.79 +    case 1:
    5.80 +    case 4:
    5.81 +    case 5:
    5.82 +        counter = (s->period - d) & 0xffff;
    5.83 +        break;
    5.84 +    case 3:
    5.85 +        /* XXX: may be incorrect for odd counts */
    5.86 +        counter = s->period - ((2 * d) % s->period);
    5.87 +        break;
    5.88 +    default:
    5.89 +        /* mod 2 counter handle */
    5.90 +        d = hvm_get_clock() - s->hvm_time->count_point;
    5.91 +        d += s->hvm_time->count_advance;
    5.92 +        counter = s->period - (d % s->period);
    5.93 +        break;
    5.94 +    }
    5.95 +    /* change from ns to pit counter */
    5.96 +    counter = DIV_ROUND( (counter * PIT_FREQ), NSEC_PER_SEC);
    5.97 +    return counter;
    5.98 +}
    5.99 +
   5.100 +/* get pit output bit */
   5.101 +static int pit_get_out1(PITChannelState *s, s64 current_time)
   5.102 +{
   5.103 +    u64 d;
   5.104 +    int out;
   5.105 +
   5.106 +    d = current_time - s->count_load_time;
   5.107 +    switch(s->mode) {
   5.108 +    default:
   5.109 +    case 0:
   5.110 +        out = (d >= s->period);
   5.111 +        break;
   5.112 +    case 1:
   5.113 +        out = (d < s->period);
   5.114 +        break;
   5.115 +    case 2:
   5.116 +        /* mod2 out is no meaning, since intr are generated in background */
   5.117 +        if ((d % s->period) == 0 && d != 0)
   5.118 +            out = 1;
   5.119 +        else
   5.120 +            out = 0;
   5.121 +        break;
   5.122 +    case 3:
   5.123 +        out = (d % s->period) < ((s->period + 1) >> 1);
   5.124 +        break;
   5.125 +    case 4:
   5.126 +    case 5:
   5.127 +        out = (d == s->period);
   5.128 +        break;
   5.129 +    }
   5.130 +    return out;
   5.131 +}
   5.132 +
   5.133 +int pit_get_out(hvm_virpit *pit, int channel, s64 current_time)
   5.134 +{
   5.135 +    PITChannelState *s = &pit->channels[channel];
   5.136 +    return pit_get_out1(s, current_time);
   5.137 +}
   5.138 +
   5.139 +static __inline__ s64 missed_ticks(PITChannelState *s, s64 current_time)
   5.140 +{
   5.141 +    struct hvm_time_info *hvm_time = s->hvm_time;
   5.142 +    /* ticks from current time(expected time) to NOW */ 
   5.143 +    int missed_ticks;
   5.144 +    /* current_time is expected time for next intr, check if it's true
   5.145 +     * (actimer has a TIMER_SLOP in advance)
   5.146 +     */
   5.147 +    s64 missed_time = hvm_get_clock() + TIMER_SLOP - current_time;
   5.148 +
   5.149 +    if (missed_time >= 0) {
   5.150 +        missed_ticks = missed_time/(s_time_t)s->period + 1;
   5.151 +        hvm_time->pending_intr_nr += missed_ticks;
   5.152 +        s->next_transition_time = current_time + (missed_ticks ) * s->period;
   5.153 +    } else
   5.154 +        printk("HVM_PIT:missed ticks < 0 \n");
   5.155 +
   5.156 +    return s->next_transition_time;
   5.157 +}
   5.158 +
   5.159 +/* only rearm the actimer when return value > 0
   5.160 + *  -2: init state
   5.161 + *  -1: the mode has expired
   5.162 + *   0: current VCPU is not running
   5.163 + *  >0: the next fired time
   5.164 + */
   5.165 +s64 pit_get_next_transition_time(PITChannelState *s, 
   5.166 +                                            s64 current_time)
   5.167 +{
   5.168 +    s64 d, next_time, base;
   5.169 +    int period2;
   5.170 +    struct hvm_time_info *hvm_time = s->hvm_time;
   5.171 +
   5.172 +    d = current_time - s->count_load_time;
   5.173 +    switch(s->mode) {
   5.174 +    default:
   5.175 +    case 0:
   5.176 +    case 1:
   5.177 +        if (d < s->period)
   5.178 +            next_time = s->period;
   5.179 +        else
   5.180 +            return -1;
   5.181 +        break;
   5.182 +    case 2:
   5.183 +        if (test_bit(_VCPUF_running, &(hvm_time->vcpu->vcpu_flags)) )
   5.184 +            next_time = missed_ticks(s, current_time);
   5.185 +        else
   5.186 +            return 0;
   5.187 +        break;
   5.188 +    case 3:
   5.189 +        base = (d / s->period) * s->period;
   5.190 +        period2 = ((s->period + 1) >> 1);
   5.191 +        if ((d - base) < period2) 
   5.192 +            next_time = base + period2;
   5.193 +        else
   5.194 +            next_time = base + s->period;
   5.195 +        break;
   5.196 +    case 4:
   5.197 +    case 5:
   5.198 +        if (d < s->period)
   5.199 +            next_time = s->period;
   5.200 +        else if (d == s->period)
   5.201 +            next_time = s->period + 1;
   5.202 +        else
   5.203 +            return -1;
   5.204 +        break;
   5.205 +    case 0xff:
   5.206 +        return -2;      /* for init state */ 
   5.207 +        break;
   5.208 +    }
   5.209 +    /* XXX: better solution: use a clock at PIT_FREQ Hz */
   5.210 +    if (next_time <= current_time){
   5.211 +#ifdef DEBUG_PIT
   5.212 +        printk("HVM_PIT:next_time <= current_time. next=0x%llx, current=0x%llx!\n",next_time, current_time);
   5.213 +#endif
   5.214 +        next_time = current_time + 1;
   5.215 +    }
   5.216 +    return next_time;
   5.217 +}
   5.218 +
   5.219 +/* val must be 0 or 1 */
   5.220 +void pit_set_gate(hvm_virpit *pit, int channel, int val)
   5.221 +{
   5.222 +    PITChannelState *s = &pit->channels[channel];
   5.223 +
   5.224 +    switch(s->mode) {
   5.225 +    default:
   5.226 +    case 0:
   5.227 +    case 4:
   5.228 +        /* XXX: just disable/enable counting */
   5.229 +        break;
   5.230 +    case 1:
   5.231 +    case 5:
   5.232 +        if (s->gate < val) {
   5.233 +            /* restart counting on rising edge */
   5.234 +            s->count_load_time = hvm_get_clock();
   5.235 +            pit_irq_timer_update(s, s->count_load_time);
   5.236 +        }
   5.237 +        break;
   5.238 +    case 2:
   5.239 +    case 3:
   5.240 +        if (s->gate < val) {
   5.241 +            /* restart counting on rising edge */
   5.242 +            s->count_load_time = hvm_get_clock();
   5.243 +            pit_irq_timer_update(s, s->count_load_time);
   5.244 +        }
   5.245 +        /* XXX: disable/enable counting */
   5.246 +        break;
   5.247 +    }
   5.248 +    s->gate = val;
   5.249 +}
   5.250 +
   5.251 +int pit_get_gate(hvm_virpit *pit, int channel)
   5.252 +{
   5.253 +    PITChannelState *s = &pit->channels[channel];
   5.254 +    return s->gate;
   5.255 +}
   5.256 +
   5.257 +static inline void pit_load_count(PITChannelState *s, int val)
   5.258 +{
   5.259 +    if (val == 0)
   5.260 +        val = 0x10000;
   5.261 +
   5.262 +    s->count_load_time = hvm_get_clock();
   5.263 +    s->count = val;
   5.264 +    s->period = DIV_ROUND(((s->count) * NSEC_PER_SEC), PIT_FREQ);
   5.265 +
   5.266 +#ifdef DEBUG_PIT
   5.267 +    printk("HVM_PIT: pit-load-counter, count=0x%x,period=0x%u us,mode=%d, load_time=%lld\n",
   5.268 +            val,
   5.269 +            s->period / 1000,
   5.270 +            s->mode,
   5.271 +            s->count_load_time);
   5.272 +#endif
   5.273 +
   5.274 +    if (s->mode == HVM_PIT_ACCEL_MODE) {
   5.275 +        if (!s->hvm_time) {
   5.276 +            printk("HVM_PIT:guest should only set mod 2 on channel 0!\n");
   5.277 +            return;
   5.278 +        }
   5.279 +        s->hvm_time->period_cycles = (u64)s->period * cpu_khz / 1000000L;
   5.280 +        s->hvm_time->first_injected = 0;
   5.281 +
   5.282 +        if (s->period < 900000) { /* < 0.9 ms */
   5.283 +            printk("HVM_PIT: guest programmed too small an count: %x\n",
   5.284 +                    s->count);
   5.285 +            s->period = 1000000;
   5.286 +        }
   5.287 +    }
   5.288 +        
   5.289 +    pit_irq_timer_update(s, s->count_load_time);
   5.290 +}
   5.291 +
   5.292 +/* if already latched, do not latch again */
   5.293 +static void pit_latch_count(PITChannelState *s)
   5.294 +{
   5.295 +    if (!s->count_latched) {
   5.296 +        s->latched_count = pit_get_count(s);
   5.297 +        s->count_latched = s->rw_mode;
   5.298 +    }
   5.299 +}
   5.300 +
   5.301 +static void pit_ioport_write(void *opaque, u32 addr, u32 val)
   5.302 +{
   5.303 +    hvm_virpit *pit = opaque;
   5.304 +    int channel, access;
   5.305 +    PITChannelState *s;
   5.306 +    val &= 0xff;
   5.307 +
   5.308 +    addr &= 3;
   5.309 +    if (addr == 3) {
   5.310 +        channel = val >> 6;
   5.311 +        if (channel == 3) {
   5.312 +            /* read back command */
   5.313 +            for(channel = 0; channel < 3; channel++) {
   5.314 +                s = &pit->channels[channel];
   5.315 +                if (val & (2 << channel)) {
   5.316 +                    if (!(val & 0x20)) {
   5.317 +                        pit_latch_count(s);
   5.318 +                    }
   5.319 +                    if (!(val & 0x10) && !s->status_latched) {
   5.320 +                        /* status latch */
   5.321 +                        /* XXX: add BCD and null count */
   5.322 +                        s->status =  (pit_get_out1(s, hvm_get_clock()) << 7) |
   5.323 +                            (s->rw_mode << 4) |
   5.324 +                            (s->mode << 1) |
   5.325 +                            s->bcd;
   5.326 +                        s->status_latched = 1;
   5.327 +                    }
   5.328 +                }
   5.329 +            }
   5.330 +        } else {
   5.331 +            s = &pit->channels[channel];
   5.332 +            access = (val >> 4) & 3;
   5.333 +            if (access == 0) {
   5.334 +                pit_latch_count(s);
   5.335 +            } else {
   5.336 +                s->rw_mode = access;
   5.337 +                s->read_state = access;
   5.338 +                s->write_state = access;
   5.339 +
   5.340 +                s->mode = (val >> 1) & 7;
   5.341 +                s->bcd = val & 1;
   5.342 +                /* XXX: update irq timer ? */
   5.343 +            }
   5.344 +        }
   5.345 +    } else {
   5.346 +        s = &pit->channels[addr];
   5.347 +        switch(s->write_state) {
   5.348 +        default:
   5.349 +        case RW_STATE_LSB:
   5.350 +            pit_load_count(s, val);
   5.351 +            break;
   5.352 +        case RW_STATE_MSB:
   5.353 +            pit_load_count(s, val << 8);
   5.354 +            break;
   5.355 +        case RW_STATE_WORD0:
   5.356 +            s->write_latch = val;
   5.357 +            s->write_state = RW_STATE_WORD1;
   5.358 +            break;
   5.359 +        case RW_STATE_WORD1:
   5.360 +            pit_load_count(s, s->write_latch | (val << 8));
   5.361 +            s->write_state = RW_STATE_WORD0;
   5.362 +            break;
   5.363 +        }
   5.364 +    }
   5.365 +}
   5.366 +
   5.367 +static u32 pit_ioport_read(void *opaque, u32 addr)
   5.368 +{
   5.369 +    hvm_virpit *pit = opaque;
   5.370 +    int ret, count;
   5.371 +    PITChannelState *s;
   5.372 +    
   5.373 +    addr &= 3;
   5.374 +    s = &pit->channels[addr];
   5.375 +    if (s->status_latched) {
   5.376 +        s->status_latched = 0;
   5.377 +        ret = s->status;
   5.378 +    } else if (s->count_latched) {
   5.379 +        switch(s->count_latched) {
   5.380 +        default:
   5.381 +        case RW_STATE_LSB:
   5.382 +            ret = s->latched_count & 0xff;
   5.383 +            s->count_latched = 0;
   5.384 +            break;
   5.385 +        case RW_STATE_MSB:
   5.386 +            ret = s->latched_count >> 8;
   5.387 +            s->count_latched = 0;
   5.388 +            break;
   5.389 +        case RW_STATE_WORD0:
   5.390 +            ret = s->latched_count & 0xff;
   5.391 +            s->count_latched = RW_STATE_MSB;
   5.392 +            break;
   5.393 +        }
   5.394 +    } else {
   5.395 +        switch(s->read_state) {
   5.396 +        default:
   5.397 +        case RW_STATE_LSB:
   5.398 +            count = pit_get_count(s);
   5.399 +            ret = count & 0xff;
   5.400 +            break;
   5.401 +        case RW_STATE_MSB:
   5.402 +            count = pit_get_count(s);
   5.403 +            ret = (count >> 8) & 0xff;
   5.404 +            break;
   5.405 +        case RW_STATE_WORD0:
   5.406 +            count = pit_get_count(s);
   5.407 +            ret = count & 0xff;
   5.408 +            s->read_state = RW_STATE_WORD1;
   5.409 +            break;
   5.410 +        case RW_STATE_WORD1:
   5.411 +            count = pit_get_count(s);
   5.412 +            ret = (count >> 8) & 0xff;
   5.413 +            s->read_state = RW_STATE_WORD0;
   5.414 +            break;
   5.415 +        }
   5.416 +    }
   5.417 +    return ret;
   5.418 +}
   5.419 +
   5.420 +static void pit_irq_timer_update(PITChannelState *s, s64 current_time)
   5.421 +{
   5.422 +    s64 expire_time;
   5.423 +    int irq_level;
   5.424 +    struct vcpu *v = current;
   5.425 +    struct hvm_virpic *pic= &v->domain->arch.hvm_domain.vpic;
   5.426 +
   5.427 +    if (!s->hvm_time || s->mode == 0xff)
   5.428 +        return;
   5.429 +
   5.430 +    expire_time = pit_get_next_transition_time(s, current_time);
   5.431 +    /* not generate intr by direct pic_set_irq in mod 2
   5.432 +     * XXX:mod 3 should be same as mod 2
   5.433 +     */
   5.434 +    if (s->mode != HVM_PIT_ACCEL_MODE) {
   5.435 +        irq_level = pit_get_out1(s, current_time);
   5.436 +        pic_set_irq(pic, s->irq, irq_level);
   5.437 +        s->next_transition_time = expire_time;
   5.438 +#ifdef DEBUG_PIT
   5.439 +        printk("HVM_PIT:irq_level=%d next_delay=%l ns\n",
   5.440 +                irq_level, 
   5.441 +                (expire_time - current_time));
   5.442 +#endif
   5.443 +    }
   5.444 +
   5.445 +    if (expire_time > 0)
   5.446 +        set_timer(&(s->hvm_time->pit_timer), s->next_transition_time);
   5.447 +
   5.448 +}
   5.449 +
   5.450 +static void pit_irq_timer(void *data)
   5.451 +{
   5.452 +    PITChannelState *s = data;
   5.453 +
   5.454 +    pit_irq_timer_update(s, s->next_transition_time);
   5.455 +}
   5.456 +
   5.457 +static void pit_reset(void *opaque)
   5.458 +{
   5.459 +    hvm_virpit *pit = opaque;
   5.460 +    PITChannelState *s;
   5.461 +    int i;
   5.462 +
   5.463 +    for(i = 0;i < 3; i++) {
   5.464 +        s = &pit->channels[i];
   5.465 +        s->mode = 0xff; /* the init mode */
   5.466 +        s->gate = (i != 2);
   5.467 +        pit_load_count(s, 0);
   5.468 +    }
   5.469 +}
   5.470 +
   5.471 +/* hvm_io_assist light-weight version, specific to PIT DM */ 
   5.472 +static void resume_pit_io(ioreq_t *p)
   5.473 +{
   5.474 +    struct cpu_user_regs *regs = guest_cpu_user_regs();
   5.475 +    unsigned long old_eax = regs->eax;
   5.476 +    p->state = STATE_INVALID;
   5.477 +
   5.478 +    switch(p->size) {
   5.479 +    case 1:
   5.480 +        regs->eax = (old_eax & 0xffffff00) | (p->u.data & 0xff);
   5.481 +        break;
   5.482 +    case 2:
   5.483 +        regs->eax = (old_eax & 0xffff0000) | (p->u.data & 0xffff);
   5.484 +        break;
   5.485 +    case 4:
   5.486 +        regs->eax = (p->u.data & 0xffffffff);
   5.487 +        break;
   5.488 +    default:
   5.489 +        BUG();
   5.490 +    }
   5.491 +}
   5.492 +
   5.493 +/* the intercept action for PIT DM retval:0--not handled; 1--handled */  
   5.494 +int handle_pit_io(ioreq_t *p)
   5.495 +{
   5.496 +    struct vcpu *v = current;
   5.497 +    struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
   5.498 +
   5.499 +    if (p->size != 1 ||
   5.500 +        p->pdata_valid ||
   5.501 +        p->type != IOREQ_TYPE_PIO){
   5.502 +        printk("HVM_PIT:wrong PIT IO!\n");
   5.503 +        return 1;
   5.504 +    }
   5.505 +    
   5.506 +    if (p->dir == 0) {/* write */
   5.507 +        pit_ioport_write(vpit, p->addr, p->u.data);
   5.508 +    } else if (p->dir == 1) { /* read */
   5.509 +        p->u.data = pit_ioport_read(vpit, p->addr);
   5.510 +        resume_pit_io(p);
   5.511 +    }
   5.512 +
   5.513 +    /* always return 1, since PIT sit in HV now */
   5.514 +    return 1;
   5.515 +}
   5.516 +
   5.517 +static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val)
   5.518 +{
   5.519 +    hvm_virpit *pit = opaque;
   5.520 +    val &= 0xff;
   5.521 +    pit->speaker_data_on = (val >> 1) & 1;
   5.522 +    pit_set_gate(pit, 2, val & 1);
   5.523 +}
   5.524 +
   5.525 +static uint32_t speaker_ioport_read(void *opaque, uint32_t addr)
   5.526 +{
   5.527 +    int out;
   5.528 +    hvm_virpit *pit = opaque;
   5.529 +    out = pit_get_out(pit, 2, hvm_get_clock());
   5.530 +    pit->dummy_refresh_clock ^= 1;
   5.531 +
   5.532 +    return (pit->speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) |
   5.533 +      (pit->dummy_refresh_clock << 4);
   5.534 +}
   5.535 +
   5.536 +int handle_speaker_io(ioreq_t *p)
   5.537 +{
   5.538 +    struct vcpu *v = current;
   5.539 +    struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
   5.540 +
   5.541 +    if (p->size != 1 ||
   5.542 +        p->pdata_valid ||
   5.543 +        p->type != IOREQ_TYPE_PIO){
   5.544 +        printk("HVM_SPEAKER:wrong SPEAKER IO!\n");
   5.545 +        return 1;
   5.546 +    }
   5.547 +    
   5.548 +    if (p->dir == 0) {/* write */
   5.549 +        speaker_ioport_write(vpit, p->addr, p->u.data);
   5.550 +    } else if (p->dir == 1) {/* read */
   5.551 +        p->u.data = speaker_ioport_read(vpit, p->addr);
   5.552 +        resume_pit_io(p);
   5.553 +    }
   5.554 +
   5.555 +    return 1;
   5.556 +}
   5.557 +
   5.558 +/* pick up missed timer ticks at deactive time */
   5.559 +void pickup_deactive_ticks(struct hvm_virpit *vpit)
   5.560 +{
   5.561 +    s64 next_time;
   5.562 +    PITChannelState *s = &(vpit->channels[0]);
   5.563 +    if ( !active_timer(&(vpit->time_info.pit_timer)) ) {
   5.564 +        next_time = pit_get_next_transition_time(s, s->next_transition_time); 
   5.565 +        if (next_time > 0)
   5.566 +            set_timer(&(s->hvm_time->pit_timer), s->next_transition_time);
   5.567 +        else {
   5.568 +            printk("HVM_PIT:not set_timer before resume next_time=%lld!\n", next_time);
   5.569 +            next_time = s->next_transition_time;
   5.570 +        }
   5.571 +    }
   5.572 +}
   5.573 +
   5.574 +void pit_init(struct hvm_virpit *pit, struct vcpu *v)
   5.575 +{
   5.576 +    PITChannelState *s;
   5.577 +    struct hvm_time_info *hvm_time;
   5.578 +
   5.579 +    s = &pit->channels[0];
   5.580 +    /* the timer 0 is connected to an IRQ */
   5.581 +    s->irq = 0;
   5.582 +    /* channel 0 need access the related time info for intr injection */
   5.583 +    hvm_time = s->hvm_time = &pit->time_info;
   5.584 +    hvm_time->vcpu = v;
   5.585 +
   5.586 +    init_timer(&(hvm_time->pit_timer), pit_irq_timer, s, v->processor);
   5.587 +
   5.588 +    register_portio_handler(PIT_BASE, 4, handle_pit_io);
   5.589 +
   5.590 +    /* register the speaker port */
   5.591 +    register_portio_handler(0x61, 1, handle_speaker_io);
   5.592 +
   5.593 +    pit_reset(pit);
   5.594 +
   5.595 +    return;
   5.596 +
   5.597 +}
     6.1 --- a/xen/arch/x86/hvm/intercept.c	Wed Apr 19 18:32:20 2006 +0100
     6.2 +++ b/xen/arch/x86/hvm/intercept.c	Wed Apr 19 18:38:14 2006 +0100
     6.3 @@ -206,139 +206,6 @@ int register_io_handler(unsigned long ad
     6.4      return 1;
     6.5  }
     6.6  
     6.7 -static void pit_cal_count(struct hvm_virpit *vpit)
     6.8 -{
     6.9 -    u64 nsec_delta = (unsigned int)((NOW() - vpit->count_point));
    6.10 -
    6.11 -    nsec_delta += vpit->count_advance;
    6.12 -    if (nsec_delta > vpit->period)
    6.13 -        HVM_DBG_LOG(DBG_LEVEL_1,
    6.14 -	            "HVM_PIT: long time has passed from last injection!");
    6.15 -
    6.16 -    if(vpit->init_val == 0)
    6.17 -    {
    6.18 -        printk("PIT init value == 0!\n");
    6.19 -        domain_crash_synchronous();
    6.20 -    }
    6.21 -
    6.22 -    vpit->count = vpit->init_val
    6.23 -                  - ((nsec_delta * PIT_FREQ / 1000000000ULL) % vpit->init_val);
    6.24 -}
    6.25 -
    6.26 -static void pit_latch_io(struct hvm_virpit *vpit)
    6.27 -{
    6.28 -    pit_cal_count(vpit);
    6.29 -
    6.30 -    switch(vpit->read_state) {
    6.31 -    case MSByte:
    6.32 -        vpit->count_MSB_latched=1;
    6.33 -        break;
    6.34 -    case LSByte:
    6.35 -        vpit->count_LSB_latched=1;
    6.36 -        break;
    6.37 -    case LSByte_multiple:
    6.38 -        vpit->count_LSB_latched=1;
    6.39 -        vpit->count_MSB_latched=1;
    6.40 -        break;
    6.41 -    case MSByte_multiple:
    6.42 -        HVM_DBG_LOG(DBG_LEVEL_1,
    6.43 -	            "HVM_PIT: latch PIT counter before MSB_multiple!");
    6.44 -        vpit->read_state=LSByte_multiple;
    6.45 -        vpit->count_LSB_latched=1;
    6.46 -        vpit->count_MSB_latched=1;
    6.47 -        break;
    6.48 -    default:
    6.49 -        domain_crash_synchronous();
    6.50 -    }
    6.51 -}
    6.52 -
    6.53 -static int pit_read_io(struct hvm_virpit *vpit)
    6.54 -{
    6.55 -    if(vpit->count_LSB_latched) {
    6.56 -        /* Read Least Significant Byte */
    6.57 -        if(vpit->read_state==LSByte_multiple) {
    6.58 -            vpit->read_state=MSByte_multiple;
    6.59 -        }
    6.60 -        vpit->count_LSB_latched=0;
    6.61 -        return (vpit->count & 0xFF);
    6.62 -    } else if(vpit->count_MSB_latched) {
    6.63 -        /* Read Most Significant Byte */
    6.64 -        if(vpit->read_state==MSByte_multiple) {
    6.65 -            vpit->read_state=LSByte_multiple;
    6.66 -        }
    6.67 -        vpit->count_MSB_latched=0;
    6.68 -        return ((vpit->count>>8) & 0xFF);
    6.69 -    } else {
    6.70 -        /* Unlatched Count Read */
    6.71 -        HVM_DBG_LOG(DBG_LEVEL_1, "HVM_PIT: unlatched read");
    6.72 -        pit_cal_count(vpit);
    6.73 -        if(!(vpit->read_state & 0x1)) {
    6.74 -            /* Read Least Significant Byte */
    6.75 -            if(vpit->read_state==LSByte_multiple) {
    6.76 -                vpit->read_state=MSByte_multiple;
    6.77 -            }
    6.78 -            return (vpit->count & 0xFF);
    6.79 -        } else {
    6.80 -            /* Read Most Significant Byte */
    6.81 -            if(vpit->read_state==MSByte_multiple) {
    6.82 -                vpit->read_state=LSByte_multiple;
    6.83 -            }
    6.84 -            return ((vpit->count>>8) & 0xFF);
    6.85 -        }
    6.86 -    }
    6.87 -}
    6.88 -
    6.89 -/* hvm_io_assist light-weight version, specific to PIT DM */ 
    6.90 -static void resume_pit_io(ioreq_t *p)
    6.91 -{
    6.92 -    struct cpu_user_regs *regs = guest_cpu_user_regs();
    6.93 -    unsigned long old_eax = regs->eax;
    6.94 -    p->state = STATE_INVALID;
    6.95 -
    6.96 -    switch(p->size) {
    6.97 -    case 1:
    6.98 -        regs->eax = (old_eax & 0xffffff00) | (p->u.data & 0xff);
    6.99 -        break;
   6.100 -    case 2:
   6.101 -        regs->eax = (old_eax & 0xffff0000) | (p->u.data & 0xffff);
   6.102 -        break;
   6.103 -    case 4:
   6.104 -        regs->eax = (p->u.data & 0xffffffff);
   6.105 -        break;
   6.106 -    default:
   6.107 -        BUG();
   6.108 -    }
   6.109 -}
   6.110 -
   6.111 -/* the intercept action for PIT DM retval:0--not handled; 1--handled */
   6.112 -int intercept_pit_io(ioreq_t *p)
   6.113 -{
   6.114 -    struct vcpu *v = current;
   6.115 -    struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
   6.116 -
   6.117 -    if (p->size != 1 ||
   6.118 -        p->pdata_valid ||
   6.119 -        p->type != IOREQ_TYPE_PIO)
   6.120 -        return 0;
   6.121 -    
   6.122 -    if (p->addr == PIT_MODE &&
   6.123 -        p->dir == 0 &&    /* write */
   6.124 -        ((p->u.data >> 4) & 0x3) == 0 && /* latch command */
   6.125 -        ((p->u.data >> 6) & 0x3) == (vpit->channel)) {/* right channel */
   6.126 -        pit_latch_io(vpit);
   6.127 -        return 1;
   6.128 -    }
   6.129 -
   6.130 -    if (p->addr == (PIT_CH0 + vpit->channel) &&
   6.131 -        p->dir == 1) { /* read */
   6.132 -        p->u.data = pit_read_io(vpit);
   6.133 -        resume_pit_io(p);
   6.134 -        return 1;
   6.135 -    }
   6.136 -
   6.137 -    return 0;
   6.138 -}
   6.139 -
   6.140  /* hooks function for the HLT instruction emulation wakeup */
   6.141  void hlt_timer_fn(void *data)
   6.142  {
   6.143 @@ -347,109 +214,6 @@ void hlt_timer_fn(void *data)
   6.144      evtchn_set_pending(v, iopacket_port(v));
   6.145  }
   6.146  
   6.147 -static __inline__ void missed_ticks(struct hvm_virpit*vpit)
   6.148 -{
   6.149 -    int missed_ticks;
   6.150 -
   6.151 -    missed_ticks = (NOW() - vpit->scheduled)/(s_time_t) vpit->period;
   6.152 -    if ( missed_ticks++ >= 0 ) {
   6.153 -        vpit->pending_intr_nr += missed_ticks;
   6.154 -        vpit->scheduled += missed_ticks * vpit->period;
   6.155 -    }
   6.156 -}
   6.157 -
   6.158 -/* hooks function for the PIT when the guest is active */
   6.159 -static void pit_timer_fn(void *data)
   6.160 -{
   6.161 -    struct vcpu *v = data;
   6.162 -    struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
   6.163 -
   6.164 -    /* pick up missed timer tick */
   6.165 -    missed_ticks(vpit);
   6.166 -    if ( test_bit(_VCPUF_running, &v->vcpu_flags) ) {
   6.167 -        set_timer(&vpit->pit_timer, vpit->scheduled);
   6.168 -    }
   6.169 -}
   6.170 -
   6.171 -/* pick up missed timer ticks at deactive time */
   6.172 -void pickup_deactive_ticks(struct hvm_virpit *vpit)
   6.173 -{
   6.174 -    if ( !active_timer(&(vpit->pit_timer)) ) {
   6.175 -        missed_ticks(vpit);
   6.176 -        set_timer(&vpit->pit_timer, vpit->scheduled);
   6.177 -    }
   6.178 -}
   6.179 -
   6.180 -/* Only some PIT operations such as load init counter need a hypervisor hook.
   6.181 - * leave all other operations in user space DM
   6.182 - */
   6.183 -void hvm_hooks_assist(struct vcpu *v)
   6.184 -{
   6.185 -    vcpu_iodata_t *vio = get_vio(v->domain, v->vcpu_id);
   6.186 -    ioreq_t *p = &vio->vp_ioreq;
   6.187 -    struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
   6.188 -    int rw_mode, reinit = 0;
   6.189 -
   6.190 -    /* load init count*/
   6.191 -    if (p->state == STATE_IORESP_HOOK) {
   6.192 -        /* set up actimer, handle re-init */
   6.193 -        if ( active_timer(&(vpit->pit_timer)) ) {
   6.194 -            HVM_DBG_LOG(DBG_LEVEL_1, "HVM_PIT: guest reset PIT with channel %lx!\n", (unsigned long) ((p->u.data >> 24) & 0x3) );
   6.195 -            stop_timer(&(vpit->pit_timer));
   6.196 -            reinit = 1;
   6.197 - 
   6.198 -        }
   6.199 -        else {
   6.200 -            init_timer(&vpit->pit_timer, pit_timer_fn, v, v->processor);
   6.201 -        }
   6.202 -
   6.203 -        /* init count for this channel */
   6.204 -        vpit->init_val = (p->u.data & 0xFFFF) ;
   6.205 -        /* frequency(ns) of pit */
   6.206 -        vpit->period = DIV_ROUND(((vpit->init_val) * 1000000000ULL), PIT_FREQ);
   6.207 -        HVM_DBG_LOG(DBG_LEVEL_1,"HVM_PIT: guest set init pit freq:%u ns, initval:0x%x\n", vpit->period, vpit->init_val);
   6.208 -        if (vpit->period < 900000) { /* < 0.9 ms */
   6.209 -            printk("HVM_PIT: guest programmed too small an init_val: %x\n",
   6.210 -                   vpit->init_val);
   6.211 -            vpit->period = 1000000;
   6.212 -        }
   6.213 -         vpit->period_cycles = (u64)vpit->period * cpu_khz / 1000000L;
   6.214 -         printk("HVM_PIT: guest freq in cycles=%lld\n",(long long)vpit->period_cycles);
   6.215 -
   6.216 -        vpit->channel = ((p->u.data >> 24) & 0x3);
   6.217 -        vpit->first_injected = 0;
   6.218 -
   6.219 -        vpit->count_LSB_latched = 0;
   6.220 -        vpit->count_MSB_latched = 0;
   6.221 -
   6.222 -        rw_mode = ((p->u.data >> 26) & 0x3);
   6.223 -        switch(rw_mode) {
   6.224 -        case 0x1:
   6.225 -            vpit->read_state=LSByte;
   6.226 -            break;
   6.227 -        case 0x2:
   6.228 -            vpit->read_state=MSByte;
   6.229 -            break;
   6.230 -        case 0x3:
   6.231 -            vpit->read_state=LSByte_multiple;
   6.232 -            break;
   6.233 -        default:
   6.234 -            printk("HVM_PIT:wrong PIT rw_mode!\n");
   6.235 -            break;
   6.236 -        }
   6.237 -
   6.238 -        vpit->scheduled = NOW() + vpit->period;
   6.239 -        set_timer(&vpit->pit_timer, vpit->scheduled);
   6.240 -
   6.241 -        /*restore the state*/
   6.242 -        p->state = STATE_IORESP_READY;
   6.243 -
   6.244 -        /* register handler to intercept the PIT io when vm_exit */
   6.245 -        if (!reinit) {
   6.246 -            register_portio_handler(0x40, 4, intercept_pit_io); 
   6.247 -        }
   6.248 -    }
   6.249 -}
   6.250  
   6.251  /*
   6.252   * Local variables:
     7.1 --- a/xen/arch/x86/hvm/io.c	Wed Apr 19 18:32:20 2006 +0100
     7.2 +++ b/xen/arch/x86/hvm/io.c	Wed Apr 19 18:38:14 2006 +0100
     7.3 @@ -674,8 +674,6 @@ void hvm_io_assist(struct vcpu *v)
     7.4      }
     7.5  
     7.6      p = &vio->vp_ioreq;
     7.7 -    if (p->state == STATE_IORESP_HOOK)
     7.8 -        hvm_hooks_assist(v);
     7.9  
    7.10      /* clear IO wait HVM flag */
    7.11      if (test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags)) {
     8.1 --- a/xen/arch/x86/hvm/svm/intr.c	Wed Apr 19 18:32:20 2006 +0100
     8.2 +++ b/xen/arch/x86/hvm/svm/intr.c	Wed Apr 19 18:38:14 2006 +0100
     8.3 @@ -46,44 +46,43 @@
     8.4  
     8.5  u64 svm_get_guest_time(struct vcpu *v)
     8.6  {
     8.7 -    struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
     8.8 +    struct hvm_time_info *time_info = &(v->domain->arch.hvm_domain.vpit.time_info);
     8.9      u64    host_tsc;
    8.10      
    8.11      rdtscll(host_tsc);
    8.12 -    return host_tsc + vpit->cache_tsc_offset;
    8.13 +    return host_tsc + time_info->cache_tsc_offset;
    8.14  }
    8.15  
    8.16  void svm_set_guest_time(struct vcpu *v, u64 gtime)
    8.17  {
    8.18 -    struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
    8.19 +    struct hvm_time_info *time_info = &(v->domain->arch.hvm_domain.vpit.time_info);
    8.20      u64    host_tsc;
    8.21     
    8.22      rdtscll(host_tsc);
    8.23      
    8.24 -    vpit->cache_tsc_offset = gtime - host_tsc;
    8.25 -    v->arch.hvm_svm.vmcb->tsc_offset = vpit->cache_tsc_offset;
    8.26 +    time_info->cache_tsc_offset = gtime - host_tsc;
    8.27 +    v->arch.hvm_svm.vmcb->tsc_offset = time_info->cache_tsc_offset;
    8.28  }
    8.29  
    8.30  static inline void
    8.31  interrupt_post_injection(struct vcpu * v, int vector, int type)
    8.32  {
    8.33      struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
    8.34 +    struct hvm_time_info *time_info = &vpit->time_info;
    8.35  
    8.36      if ( is_pit_irq(v, vector, type) ) {
    8.37 -        if ( !vpit->first_injected ) {
    8.38 -            vpit->pending_intr_nr = 0;
    8.39 -            vpit->last_pit_gtime = svm_get_guest_time(v);
    8.40 -            vpit->scheduled = NOW() + vpit->period;
    8.41 -            set_timer(&vpit->pit_timer, vpit->scheduled);
    8.42 -            vpit->first_injected = 1;
    8.43 +        if ( !time_info->first_injected ) {
    8.44 +            time_info->pending_intr_nr = 0;
    8.45 +            time_info->last_pit_gtime = svm_get_guest_time(v);
    8.46 +            time_info->first_injected = 1;
    8.47          } else {
    8.48 -            vpit->pending_intr_nr--;
    8.49 +            time_info->pending_intr_nr--;
    8.50          }
    8.51 -        vpit->count_advance = 0;
    8.52 -        vpit->count_point = NOW();
    8.53 +        time_info->count_advance = 0;
    8.54 +        time_info->count_point = NOW();
    8.55  
    8.56 -        vpit->last_pit_gtime += vpit->period_cycles;
    8.57 -        svm_set_guest_time(v, vpit->last_pit_gtime);
    8.58 +        time_info->last_pit_gtime += time_info->period_cycles;
    8.59 +        svm_set_guest_time(v, time_info->last_pit_gtime);
    8.60      }
    8.61  
    8.62      switch(type)
    8.63 @@ -123,6 +122,7 @@ asmlinkage void svm_intr_assist(void)
    8.64      struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
    8.65      struct hvm_domain *plat=&v->domain->arch.hvm_domain; 
    8.66      struct hvm_virpit *vpit = &plat->vpit;
    8.67 +    struct hvm_time_info *time_info = &vpit->time_info;
    8.68      struct hvm_virpic *pic= &plat->vpic;
    8.69      int intr_type = VLAPIC_DELIV_MODE_EXT;
    8.70      int intr_vector = -1;
    8.71 @@ -185,7 +185,7 @@ asmlinkage void svm_intr_assist(void)
    8.72        if ( cpu_has_pending_irq(v) ) {
    8.73             intr_vector = cpu_get_interrupt(v, &intr_type);
    8.74        }
    8.75 -      else  if ( (v->vcpu_id == 0) && vpit->pending_intr_nr ) {
    8.76 +      else  if ( (v->vcpu_id == 0) && time_info->pending_intr_nr ) {
    8.77            pic_set_irq(pic, 0, 0);
    8.78            pic_set_irq(pic, 0, 1);
    8.79            intr_vector = cpu_get_interrupt(v, &intr_type);
    8.80 @@ -201,7 +201,7 @@ asmlinkage void svm_intr_assist(void)
    8.81              /* Re-injecting a PIT interruptt? */
    8.82              if (re_injecting && 
    8.83                  is_pit_irq(v, intr_vector, intr_type)) {
    8.84 -                    ++vpit->pending_intr_nr;
    8.85 +                    ++time_info->pending_intr_nr;
    8.86              }
    8.87              /* let's inject this interrupt */
    8.88              TRACE_3D(TRC_VMX_INT, v->domain->domain_id, intr_vector, 0);
     9.1 --- a/xen/arch/x86/hvm/svm/svm.c	Wed Apr 19 18:32:20 2006 +0100
     9.2 +++ b/xen/arch/x86/hvm/svm/svm.c	Wed Apr 19 18:38:14 2006 +0100
     9.3 @@ -675,12 +675,12 @@ static void arch_svm_do_launch(struct vc
     9.4  
     9.5  static void svm_freeze_time(struct vcpu *v)
     9.6  {
     9.7 -    struct hvm_virpit *vpit = &v->domain->arch.hvm_domain.vpit;
     9.8 +    struct hvm_time_info *time_info = &v->domain->arch.hvm_domain.vpit.time_info;
     9.9      
    9.10 -    if ( vpit->first_injected && !v->domain->arch.hvm_domain.guest_time ) {
    9.11 +    if ( time_info->first_injected && !v->domain->arch.hvm_domain.guest_time ) {
    9.12          v->domain->arch.hvm_domain.guest_time = svm_get_guest_time(v);
    9.13 -        vpit->count_advance += (NOW() - vpit->count_point);
    9.14 -        stop_timer(&(vpit->pit_timer));
    9.15 +        time_info->count_advance += (NOW() - time_info->count_point);
    9.16 +        stop_timer(&(time_info->pit_timer));
    9.17      }
    9.18  }
    9.19  
    9.20 @@ -750,7 +750,7 @@ static void svm_relinquish_guest_resourc
    9.21          }
    9.22      }
    9.23  
    9.24 -    kill_timer(&d->arch.hvm_domain.vpit.pit_timer);
    9.25 +    kill_timer(&d->arch.hvm_domain.vpit.time_info.pit_timer);
    9.26  
    9.27      if ( d->arch.hvm_domain.shared_page_va )
    9.28          unmap_domain_page_global(
    9.29 @@ -780,10 +780,10 @@ void arch_svm_do_resume(struct vcpu *v)
    9.30  
    9.31  void svm_migrate_timers(struct vcpu *v)
    9.32  {
    9.33 -    struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
    9.34 -
    9.35 -    migrate_timer( &vpit->pit_timer, v->processor );
    9.36 -    migrate_timer( &v->arch.hvm_svm.hlt_timer, v->processor );
    9.37 +    struct hvm_time_info *time_info = &v->domain->arch.hvm_domain.vpit.time_info;
    9.38 +
    9.39 +    migrate_timer(&time_info->pit_timer, v->processor);
    9.40 +    migrate_timer(&v->arch.hvm_svm.hlt_timer, v->processor);
    9.41      if ( hvm_apic_support(v->domain) && VLAPIC( v ))
    9.42          migrate_timer( &(VLAPIC(v)->vlapic_timer ), v->processor );
    9.43  }
    9.44 @@ -1843,11 +1843,11 @@ static inline void svm_do_msr_access(str
    9.45          switch (regs->ecx) {
    9.46          case MSR_IA32_TIME_STAMP_COUNTER:
    9.47          {
    9.48 -            struct hvm_virpit *vpit;
    9.49 +            struct hvm_time_info *time_info;
    9.50  
    9.51              rdtscll(msr_content);
    9.52 -            vpit = &(v->domain->arch.hvm_domain.vpit);
    9.53 -            msr_content += vpit->cache_tsc_offset;
    9.54 +            time_info = &v->domain->arch.hvm_domain.vpit.time_info;
    9.55 +            msr_content += time_info->cache_tsc_offset;
    9.56              break;
    9.57          }
    9.58          case MSR_IA32_SYSENTER_CS:
    10.1 --- a/xen/arch/x86/hvm/svm/vmcb.c	Wed Apr 19 18:32:20 2006 +0100
    10.2 +++ b/xen/arch/x86/hvm/svm/vmcb.c	Wed Apr 19 18:38:14 2006 +0100
    10.3 @@ -478,14 +478,15 @@ void svm_do_resume(struct vcpu *v)
    10.4  {
    10.5      struct domain *d = v->domain;
    10.6      struct hvm_virpit *vpit = &d->arch.hvm_domain.vpit;
    10.7 +    struct hvm_time_info *time_info = &vpit->time_info;
    10.8  
    10.9      svm_stts(v);
   10.10      
   10.11      /* pick up the elapsed PIT ticks and re-enable pit_timer */
   10.12 -    if ( vpit->first_injected ) {
   10.13 +    if ( time_info->first_injected ) {
   10.14          if ( v->domain->arch.hvm_domain.guest_time ) {
   10.15              svm_set_guest_time(v, v->domain->arch.hvm_domain.guest_time);
   10.16 -            vpit->count_point = NOW();
   10.17 +            time_info->count_point = NOW();
   10.18              v->domain->arch.hvm_domain.guest_time = 0;
   10.19          }
   10.20          pickup_deactive_ticks(vpit);
    11.1 --- a/xen/arch/x86/hvm/vmx/io.c	Wed Apr 19 18:32:20 2006 +0100
    11.2 +++ b/xen/arch/x86/hvm/vmx/io.c	Wed Apr 19 18:38:14 2006 +0100
    11.3 @@ -51,44 +51,43 @@ void __set_tsc_offset(u64  offset)
    11.4  
    11.5  u64 get_guest_time(struct vcpu *v)
    11.6  {
    11.7 -    struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
    11.8 +    struct hvm_time_info *time_info = &(v->domain->arch.hvm_domain.vpit.time_info);
    11.9      u64    host_tsc;
   11.10      
   11.11      rdtscll(host_tsc);
   11.12 -    return host_tsc + vpit->cache_tsc_offset;
   11.13 +    return host_tsc + time_info->cache_tsc_offset;
   11.14  }
   11.15  
   11.16  void set_guest_time(struct vcpu *v, u64 gtime)
   11.17  {
   11.18 -    struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
   11.19 +    struct hvm_time_info *time_info = &(v->domain->arch.hvm_domain.vpit.time_info);
   11.20      u64    host_tsc;
   11.21     
   11.22      rdtscll(host_tsc);
   11.23      
   11.24 -    vpit->cache_tsc_offset = gtime - host_tsc;
   11.25 -    __set_tsc_offset(vpit->cache_tsc_offset);
   11.26 +    time_info->cache_tsc_offset = gtime - host_tsc;
   11.27 +    __set_tsc_offset(time_info->cache_tsc_offset);
   11.28  }
   11.29  
   11.30  static inline void
   11.31  interrupt_post_injection(struct vcpu * v, int vector, int type)
   11.32  {
   11.33      struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
   11.34 +    struct hvm_time_info *time_info = &vpit->time_info;
   11.35  
   11.36      if ( is_pit_irq(v, vector, type) ) {
   11.37 -        if ( !vpit->first_injected ) {
   11.38 -            vpit->pending_intr_nr = 0;
   11.39 -            vpit->last_pit_gtime = get_guest_time(v);
   11.40 -            vpit->scheduled = NOW() + vpit->period;
   11.41 -            set_timer(&vpit->pit_timer, vpit->scheduled);
   11.42 -            vpit->first_injected = 1;
   11.43 +        if ( !time_info->first_injected ) {
   11.44 +            time_info->pending_intr_nr = 0;
   11.45 +            time_info->last_pit_gtime = get_guest_time(v);
   11.46 +            time_info->first_injected = 1;
   11.47          } else {
   11.48 -            vpit->pending_intr_nr--;
   11.49 +            time_info->pending_intr_nr--;
   11.50          }
   11.51 -        vpit->count_advance = 0;
   11.52 -        vpit->count_point = NOW();
   11.53 +        time_info->count_advance = 0;
   11.54 +        time_info->count_point = NOW();
   11.55  
   11.56 -        vpit->last_pit_gtime += vpit->period_cycles;
   11.57 -        set_guest_time(v, vpit->last_pit_gtime);
   11.58 +        time_info->last_pit_gtime += time_info->period_cycles;
   11.59 +        set_guest_time(v, time_info->last_pit_gtime);
   11.60      }
   11.61  
   11.62      switch(type)
   11.63 @@ -152,13 +151,13 @@ asmlinkage void vmx_intr_assist(void)
   11.64      unsigned long eflags;
   11.65      struct vcpu *v = current;
   11.66      struct hvm_domain *plat=&v->domain->arch.hvm_domain;
   11.67 -    struct hvm_virpit *vpit = &plat->vpit;
   11.68 +    struct hvm_time_info *time_info = &plat->vpit.time_info;
   11.69      struct hvm_virpic *pic= &plat->vpic;
   11.70  
   11.71      if ( v->vcpu_id == 0 )
   11.72          hvm_pic_assist(v);
   11.73  
   11.74 -    if ( (v->vcpu_id == 0) && vpit->pending_intr_nr ) {
   11.75 +    if ( (v->vcpu_id == 0) && time_info->pending_intr_nr ) {
   11.76          pic_set_irq(pic, 0, 0);
   11.77          pic_set_irq(pic, 0, 1);
   11.78      }
   11.79 @@ -203,13 +202,14 @@ void vmx_do_resume(struct vcpu *v)
   11.80  {
   11.81      struct domain *d = v->domain;
   11.82      struct hvm_virpit *vpit = &v->domain->arch.hvm_domain.vpit;
   11.83 +    struct hvm_time_info *time_info = &vpit->time_info;
   11.84  
   11.85      vmx_stts();
   11.86  
   11.87      /* pick up the elapsed PIT ticks and re-enable pit_timer */
   11.88 -    if ( vpit->first_injected ) {
   11.89 +    if ( time_info->first_injected ) {
   11.90          if ( v->domain->arch.hvm_domain.guest_time ) {
   11.91 -            vpit->count_point = NOW();
   11.92 +            time_info->count_point = NOW();
   11.93              set_guest_time(v, v->domain->arch.hvm_domain.guest_time);
   11.94              v->domain->arch.hvm_domain.guest_time = 0;
   11.95          }
    12.1 --- a/xen/arch/x86/hvm/vmx/vmx.c	Wed Apr 19 18:32:20 2006 +0100
    12.2 +++ b/xen/arch/x86/hvm/vmx/vmx.c	Wed Apr 19 18:38:14 2006 +0100
    12.3 @@ -102,7 +102,7 @@ static void vmx_relinquish_guest_resourc
    12.4          }
    12.5      }
    12.6  
    12.7 -    kill_timer(&d->arch.hvm_domain.vpit.pit_timer);
    12.8 +    kill_timer(&d->arch.hvm_domain.vpit.time_info.pit_timer);
    12.9  
   12.10      if ( d->arch.hvm_domain.shared_page_va )
   12.11          unmap_domain_page_global(
   12.12 @@ -358,12 +358,12 @@ static inline int long_mode_do_msr_write
   12.13  
   12.14  static void vmx_freeze_time(struct vcpu *v)
   12.15  {
   12.16 -    struct hvm_virpit *vpit = &v->domain->arch.hvm_domain.vpit;
   12.17 +    struct hvm_time_info *time_info = &(v->domain->arch.hvm_domain.vpit.time_info);
   12.18      
   12.19 -    if ( vpit->first_injected && !v->domain->arch.hvm_domain.guest_time ) {
   12.20 +    if ( time_info->first_injected && !v->domain->arch.hvm_domain.guest_time ) {
   12.21          v->domain->arch.hvm_domain.guest_time = get_guest_time(v);
   12.22 -        vpit->count_advance += (NOW() - vpit->count_point);
   12.23 -        stop_timer(&(vpit->pit_timer));
   12.24 +        time_info->count_advance += (NOW() - time_info->count_point);
   12.25 +        stop_timer(&(time_info->pit_timer));
   12.26      }
   12.27  }
   12.28  
   12.29 @@ -393,9 +393,9 @@ int vmx_initialize_guest_resources(struc
   12.30  
   12.31  void vmx_migrate_timers(struct vcpu *v)
   12.32  {
   12.33 -    struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
   12.34 +    struct hvm_time_info *time_info = &v->domain->arch.hvm_domain.vpit.time_info;
   12.35  
   12.36 -    migrate_timer(&vpit->pit_timer, v->processor);
   12.37 +    migrate_timer(&time_info->pit_timer, v->processor);
   12.38      migrate_timer(&v->arch.hvm_vmx.hlt_timer, v->processor);
   12.39      if ( hvm_apic_support(v->domain) && VLAPIC(v))
   12.40          migrate_timer(&(VLAPIC(v)->vlapic_timer), v->processor);
   12.41 @@ -1836,11 +1836,11 @@ static inline void vmx_do_msr_read(struc
   12.42      switch (regs->ecx) {
   12.43      case MSR_IA32_TIME_STAMP_COUNTER:
   12.44      {
   12.45 -        struct hvm_virpit *vpit;
   12.46 +        struct hvm_time_info *time_info;
   12.47  
   12.48          rdtscll(msr_content);
   12.49 -        vpit = &(v->domain->arch.hvm_domain.vpit);
   12.50 -        msr_content += vpit->cache_tsc_offset;
   12.51 +        time_info = &(v->domain->arch.hvm_domain.vpit.time_info);
   12.52 +        msr_content += time_info->cache_tsc_offset;
   12.53          break;
   12.54      }
   12.55      case MSR_IA32_SYSENTER_CS:
    13.1 --- a/xen/include/asm-x86/hvm/vpit.h	Wed Apr 19 18:32:20 2006 +0100
    13.2 +++ b/xen/include/asm-x86/hvm/vpit.h	Wed Apr 19 18:38:14 2006 +0100
    13.3 @@ -30,47 +30,65 @@
    13.4  
    13.5  #define PIT_FREQ 1193181
    13.6  
    13.7 -#define LSByte          0
    13.8 -#define MSByte          1
    13.9 -#define LSByte_multiple 2
   13.10 -#define MSByte_multiple 3
   13.11 +#define PIT_BASE 0x40
   13.12 +#define HVM_PIT_ACCEL_MODE 2
   13.13  
   13.14 -struct hvm_virpit {
   13.15 -    /* for simulation of counter 0 in mode 2 */
   13.16 +typedef struct PITChannelState {
   13.17 +    int count; /* can be 65536 */
   13.18 +    u16 latched_count;
   13.19 +    u8 count_latched;
   13.20 +    u8 status_latched;
   13.21 +    u8 status;
   13.22 +    u8 read_state;
   13.23 +    u8 write_state;
   13.24 +    u8 write_latch;
   13.25 +    u8 rw_mode;
   13.26 +    u8 mode;
   13.27 +    u8 bcd; /* not supported */
   13.28 +    u8 gate; /* timer start */
   13.29 +    s64 count_load_time;
   13.30 +    /* irq handling */
   13.31 +    s64 next_transition_time;
   13.32 +    int irq;
   13.33 +    struct hvm_time_info *hvm_time;
   13.34 +    u32 period; /* period(ns) based on count */
   13.35 +} PITChannelState;
   13.36 +
   13.37 +struct hvm_time_info {
   13.38 +    /* extra info for the mode 2 channel */
   13.39 +    struct timer pit_timer;
   13.40 +    struct vcpu *vcpu;          /* which vcpu the ac_timer bound to */
   13.41      u64 period_cycles;          /* pit frequency in cpu cycles */
   13.42      s_time_t count_advance;     /* accumulated count advance since last fire */
   13.43      s_time_t count_point;        /* last point accumulating count advance */
   13.44 -    s_time_t scheduled;         /* scheduled timer interrupt */
   13.45 -    struct timer pit_timer;     /* periodic timer for mode 2*/
   13.46 -    unsigned int channel;       /* the pit channel, counter 0~2 */
   13.47      unsigned int pending_intr_nr; /* the couner for pending timer interrupts */
   13.48 -    u32 period;                 /* pit frequency in ns */
   13.49      int first_injected;         /* flag to prevent shadow window */
   13.50      s64 cache_tsc_offset;       /* cache of VMCS TSC_OFFSET offset */
   13.51      u64 last_pit_gtime;         /* guest time when last pit is injected */
   13.52 +};
   13.53  
   13.54 -    /* virtual PIT state for handle related I/O */
   13.55 -    int read_state;
   13.56 -    int count_LSB_latched;
   13.57 -    int count_MSB_latched;
   13.58 +typedef struct hvm_virpit {
   13.59 +    PITChannelState channels[3];
   13.60 +    struct hvm_time_info time_info;
   13.61 +    int speaker_data_on;
   13.62 +    int dummy_refresh_clock;
   13.63 +}hvm_virpit;
   13.64  
   13.65 -    unsigned int count;  /* the 16 bit channel count */
   13.66 -    unsigned int init_val; /* the init value for the counter */
   13.67 -};
   13.68  
   13.69  static __inline__ s_time_t get_pit_scheduled(
   13.70      struct vcpu *v,
   13.71      struct hvm_virpit *vpit)
   13.72  {
   13.73 +    struct PITChannelState *s = &(vpit->channels[0]);
   13.74      if ( is_irq_enabled(v, 0) ) {
   13.75 -        return vpit->scheduled;
   13.76 +        return s->next_transition_time;
   13.77      }
   13.78      else
   13.79          return -1;
   13.80  }
   13.81  
   13.82  /* to hook the ioreq packet to get the PIT initialization info */
   13.83 -extern void hvm_hooks_assist(struct vcpu *v);
   13.84 -void pickup_deactive_ticks(struct hvm_virpit *vpit);
   13.85 +extern void pit_init(struct hvm_virpit *pit, struct vcpu *v);
   13.86 +extern void pickup_deactive_ticks(struct hvm_virpit *vpit);
   13.87  
   13.88  #endif /* __ASM_X86_HVM_VPIT_H__ */