[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [HVM] Support multiple HVM time device models coming soon.
# HG changeset patch # User kaf24@xxxxxxxxxxxxxxxxxxxx # Node ID da7fe04d8e80beeda874b89f8c6e6dc80bfec4c7 # Parent f4f4dd936103d5478f88346f917ba68d5cd32e4f [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@xxxxxxxxx> --- xen/arch/x86/hvm/hvm.c | 16 + xen/arch/x86/hvm/i8254.c | 405 ++++++++++++------------------------- xen/arch/x86/hvm/intercept.c | 82 +++++++ xen/arch/x86/hvm/svm/intr.c | 47 +--- xen/arch/x86/hvm/svm/svm.c | 33 +-- xen/arch/x86/hvm/svm/vmcb.c | 14 - xen/arch/x86/hvm/vmx/io.c | 62 ++--- xen/arch/x86/hvm/vmx/vmx.c | 35 +-- xen/include/asm-x86/hvm/domain.h | 6 xen/include/asm-x86/hvm/svm/intr.h | 1 xen/include/asm-x86/hvm/svm/svm.h | 1 xen/include/asm-x86/hvm/vcpu.h | 3 xen/include/asm-x86/hvm/vmx/vmx.h | 1 xen/include/asm-x86/hvm/vpit.h | 67 +++--- 14 files changed, 347 insertions(+), 426 deletions(-) diff -r f4f4dd936103 -r da7fe04d8e80 xen/arch/x86/hvm/hvm.c --- a/xen/arch/x86/hvm/hvm.c Thu May 25 16:00:09 2006 +0100 +++ b/xen/arch/x86/hvm/hvm.c Thu May 25 16:00:36 2006 +0100 @@ -185,8 +185,9 @@ void hvm_setup_platform(struct domain* d void hvm_setup_platform(struct domain* d) { struct hvm_domain *platform; - - if ( !hvm_guest(current) || (current->vcpu_id != 0) ) + struct vcpu *v=current; + + if ( !hvm_guest(v) || (v->vcpu_id != 0) ) return; if ( shadow_direct_map_init(d) == 0 ) @@ -208,7 +209,8 @@ void hvm_setup_platform(struct domain* d hvm_vioapic_init(d); } - pit_init(&platform->vpit, current); + init_timer(&platform->pl_time.periodic_tm.timer, pt_timer_fn, v, v->processor); + pit_init(v, cpu_khz); } void pic_irq_request(void *data, int level) @@ -238,6 +240,14 @@ void hvm_pic_assist(struct vcpu *v) } while ( (u16)cmpxchg(virq_line,irqs, 0) != irqs ); do_pic_irqs(pic, irqs); } +} + +u64 hvm_get_guest_time(struct vcpu *v) +{ + u64 host_tsc; + + rdtscll(host_tsc); + return host_tsc + v->arch.hvm_vcpu.cache_tsc_offset; } int cpu_get_interrupt(struct vcpu *v, int *type) diff -r f4f4dd936103 -r da7fe04d8e80 xen/arch/x86/hvm/i8254.c --- a/xen/arch/x86/hvm/i8254.c Thu May 25 16:00:09 2006 +0100 +++ b/xen/arch/x86/hvm/i8254.c Thu May 25 16:00:36 2006 +0100 @@ -22,11 +22,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -/* Edwin Zhai <edwin.zhai@xxxxxxxxx> +/* Edwin Zhai <edwin.zhai@xxxxxxxxx>, Eddie Dong <eddie.dong@xxxxxxxxx> * Ported to xen: - * use actimer for intr generation; + * Add a new layer of periodic time on top of PIT; * move speaker io access to hypervisor; - * use new method for counter/intrs calculation */ #include <xen/config.h> @@ -42,184 +41,117 @@ #include <asm/hvm/vpit.h> #include <asm/current.h> -/*#define DEBUG_PIT*/ +/* Enable DEBUG_PIT may cause guest calibration inaccuracy */ +/* #define DEBUG_PIT */ #define RW_STATE_LSB 1 #define RW_STATE_MSB 2 #define RW_STATE_WORD0 3 #define RW_STATE_WORD1 4 -#ifndef NSEC_PER_SEC -#define NSEC_PER_SEC (1000000000ULL) -#endif - -#ifndef TIMER_SLOP -#define TIMER_SLOP (50*1000) /* ns */ -#endif - -static void pit_irq_timer_update(PITChannelState *s, s64 current_time); - -s_time_t hvm_get_clock(void) -{ - /* TODO: add pause/unpause support */ - return NOW(); +#define ticks_per_sec(v) (v->domain->arch.hvm_domain.tsc_frequency) +static int handle_pit_io(ioreq_t *p); +static int handle_speaker_io(ioreq_t *p); + +/* compute with 96 bit intermediate result: (a*b)/c */ +uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) +{ + union { + uint64_t ll; + struct { +#ifdef WORDS_BIGENDIAN + uint32_t high, low; +#else + uint32_t low, high; +#endif + } l; + } u, res; + uint64_t rl, rh; + + u.ll = a; + rl = (uint64_t)u.l.low * (uint64_t)b; + rh = (uint64_t)u.l.high * (uint64_t)b; + rh += (rl >> 32); + res.l.high = rh / c; + res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c; + return res.ll; +} + +/* + * get processor time. + * unit: TSC + */ +int64_t hvm_get_clock(struct vcpu *v) +{ + uint64_t gtsc; + gtsc = hvm_get_guest_time(v); + return gtsc; } static int pit_get_count(PITChannelState *s) { - u64 d; - u64 counter; - - d = hvm_get_clock() - s->count_load_time; + uint64_t d; + int counter; + + d = muldiv64(hvm_get_clock(s->vcpu) - s->count_load_time, PIT_FREQ, ticks_per_sec(s->vcpu)); switch(s->mode) { case 0: case 1: case 4: case 5: - counter = (s->period - d) & 0xffff; + counter = (s->count - d) & 0xffff; break; case 3: /* XXX: may be incorrect for odd counts */ - counter = s->period - ((2 * d) % s->period); + counter = s->count - ((2 * d) % s->count); break; default: - /* mod 2 counter handle */ - d = hvm_get_clock() - s->hvm_time->count_point; - d += s->hvm_time->count_advance; - counter = s->period - (d % s->period); - break; - } - /* change from ns to pit counter */ - counter = DIV_ROUND( (counter * PIT_FREQ), NSEC_PER_SEC); + counter = s->count - (d % s->count); + break; + } return counter; } /* get pit output bit */ -static int pit_get_out1(PITChannelState *s, s64 current_time) -{ - u64 d; +static int pit_get_out1(PITChannelState *s, int64_t current_time) +{ + uint64_t d; int out; - d = current_time - s->count_load_time; + d = muldiv64(current_time - s->count_load_time, PIT_FREQ, ticks_per_sec(s->vcpu)); switch(s->mode) { default: case 0: - out = (d >= s->period); + out = (d >= s->count); break; case 1: - out = (d < s->period); + out = (d < s->count); break; case 2: - /* mod2 out is no meaning, since intr are generated in background */ - if ((d % s->period) == 0 && d != 0) + if ((d % s->count) == 0 && d != 0) out = 1; else out = 0; break; case 3: - out = (d % s->period) < ((s->period + 1) >> 1); + out = (d % s->count) < ((s->count + 1) >> 1); break; case 4: case 5: - out = (d == s->period); + out = (d == s->count); break; } return out; } -int pit_get_out(hvm_virpit *pit, int channel, s64 current_time) +int pit_get_out(PITState *pit, int channel, int64_t current_time) { PITChannelState *s = &pit->channels[channel]; return pit_get_out1(s, current_time); } -static __inline__ s64 missed_ticks(PITChannelState *s, s64 current_time) -{ - struct hvm_time_info *hvm_time = s->hvm_time; - struct domain *d = (void *) s - - offsetof(struct domain, arch.hvm_domain.vpit.channels[0]); - - /* ticks from current time(expected time) to NOW */ - int missed_ticks; - /* current_time is expected time for next intr, check if it's true - * (actimer has a TIMER_SLOP in advance) - */ - s64 missed_time = hvm_get_clock() + TIMER_SLOP - current_time; - - if (missed_time >= 0) { - missed_ticks = missed_time/(s_time_t)s->period + 1; - if (test_bit(_DOMF_debugging, &d->domain_flags)) { - hvm_time->pending_intr_nr++; - } else { - hvm_time->pending_intr_nr += missed_ticks; - } - s->next_transition_time = current_time + (missed_ticks ) * s->period; - } - - return s->next_transition_time; -} - -/* only rearm the actimer when return value > 0 - * -2: init state - * -1: the mode has expired - * 0: current VCPU is not running - * >0: the next fired time - */ -s64 pit_get_next_transition_time(PITChannelState *s, - s64 current_time) -{ - s64 d, next_time, base; - int period2; - struct hvm_time_info *hvm_time = s->hvm_time; - - d = current_time - s->count_load_time; - switch(s->mode) { - default: - case 0: - case 1: - if (d < s->period) - next_time = s->period; - else - return -1; - break; - case 2: - next_time = missed_ticks(s, current_time); - if ( !test_bit(_VCPUF_running, &(hvm_time->vcpu->vcpu_flags)) ) - return 0; - break; - case 3: - base = (d / s->period) * s->period; - period2 = ((s->period + 1) >> 1); - if ((d - base) < period2) - next_time = base + period2; - else - next_time = base + s->period; - break; - case 4: - case 5: - if (d < s->period) - next_time = s->period; - else if (d == s->period) - next_time = s->period + 1; - else - return -1; - break; - case 0xff: - return -2; /* for init state */ - break; - } - /* XXX: better solution: use a clock at PIT_FREQ Hz */ - if (next_time <= current_time){ -#ifdef DEBUG_PIT - printk("HVM_PIT:next_time <= current_time. next=0x%llx, current=0x%llx!\n",next_time, current_time); -#endif - next_time = current_time + 1; - } - return next_time; -} - /* val must be 0 or 1 */ -void pit_set_gate(hvm_virpit *pit, int channel, int val) +void pit_set_gate(PITState *pit, int channel, int val) { PITChannelState *s = &pit->channels[channel]; @@ -233,16 +165,16 @@ void pit_set_gate(hvm_virpit *pit, int c case 5: if (s->gate < val) { /* restart counting on rising edge */ - s->count_load_time = hvm_get_clock(); - pit_irq_timer_update(s, s->count_load_time); + s->count_load_time = hvm_get_clock(s->vcpu); +// pit_irq_timer_update(s, s->count_load_time); } break; case 2: case 3: if (s->gate < val) { /* restart counting on rising edge */ - s->count_load_time = hvm_get_clock(); - pit_irq_timer_update(s, s->count_load_time); + s->count_load_time = hvm_get_clock(s->vcpu); +// pit_irq_timer_update(s, s->count_load_time); } /* XXX: disable/enable counting */ break; @@ -250,7 +182,7 @@ void pit_set_gate(hvm_virpit *pit, int c s->gate = val; } -int pit_get_gate(hvm_virpit *pit, int channel) +int pit_get_gate(PITState *pit, int channel) { PITChannelState *s = &pit->channels[channel]; return s->gate; @@ -258,37 +190,37 @@ int pit_get_gate(hvm_virpit *pit, int ch static inline void pit_load_count(PITChannelState *s, int val) { + u32 period; if (val == 0) val = 0x10000; - - s->count_load_time = hvm_get_clock(); + s->count_load_time = hvm_get_clock(s->vcpu); s->count = val; - s->period = DIV_ROUND(((s->count) * NSEC_PER_SEC), PIT_FREQ); + period = DIV_ROUND((val * 1000000000ULL), PIT_FREQ); #ifdef DEBUG_PIT - printk("HVM_PIT: pit-load-counter, count=0x%x,period=0x%u us,mode=%d, load_time=%lld\n", + printk("HVM_PIT: pit-load-counter(%p), count=0x%x, period=%uns mode=%d, load_time=%lld\n", + s, val, - s->period / 1000, + period, s->mode, - s->count_load_time); + (long long)s->count_load_time); #endif - if (s->mode == HVM_PIT_ACCEL_MODE) { - if (!s->hvm_time) { - printk("HVM_PIT:guest should only set mod 2 on channel 0!\n"); - return; - } - s->hvm_time->period_cycles = (u64)s->period * cpu_khz / 1000000L; - s->hvm_time->first_injected = 0; - - if (s->period < 900000) { /* < 0.9 ms */ - printk("HVM_PIT: guest programmed too small an count: %x\n", - s->count); - s->period = 1000000; - } - } - - pit_irq_timer_update(s, s->count_load_time); + switch (s->mode) { + case 2: + /* create periodic time */ + s->pt = create_periodic_time (s->vcpu, period, 0, 0); + break; + case 1: + /* create one shot time */ + s->pt = create_periodic_time (s->vcpu, period, 0, 1); +#ifdef DEBUG_PIT + printk("HVM_PIT: create one shot time.\n"); +#endif + break; + default: + break; + } } /* if already latched, do not latch again */ @@ -300,9 +232,9 @@ static void pit_latch_count(PITChannelSt } } -static void pit_ioport_write(void *opaque, u32 addr, u32 val) -{ - hvm_virpit *pit = opaque; +static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val) +{ + PITState *pit = opaque; int channel, access; PITChannelState *s; val &= 0xff; @@ -321,7 +253,7 @@ static void pit_ioport_write(void *opaqu if (!(val & 0x10) && !s->status_latched) { /* status latch */ /* XXX: add BCD and null count */ - s->status = (pit_get_out1(s, hvm_get_clock()) << 7) | + s->status = (pit_get_out1(s, hvm_get_clock(s->vcpu)) << 7) | (s->rw_mode << 4) | (s->mode << 1) | s->bcd; @@ -366,9 +298,9 @@ static void pit_ioport_write(void *opaqu } } -static u32 pit_ioport_read(void *opaque, u32 addr) -{ - hvm_virpit *pit = opaque; +static uint32_t pit_ioport_read(void *opaque, uint32_t addr) +{ + PITState *pit = opaque; int ret, count; PITChannelState *s; @@ -419,84 +351,51 @@ static u32 pit_ioport_read(void *opaque, return ret; } -static void pit_irq_timer_update(PITChannelState *s, s64 current_time) -{ - s64 expire_time; - int irq_level; - struct vcpu *v = current; - struct hvm_virpic *pic= &v->domain->arch.hvm_domain.vpic; - - if (!s->hvm_time || s->mode == 0xff) - return; - - expire_time = pit_get_next_transition_time(s, current_time); - /* not generate intr by direct pic_set_irq in mod 2 - * XXX:mod 3 should be same as mod 2 - */ - if (s->mode != HVM_PIT_ACCEL_MODE) { - irq_level = pit_get_out1(s, current_time); - pic_set_irq(pic, s->irq, irq_level); - s->next_transition_time = expire_time; -#ifdef DEBUG_PIT - printk("HVM_PIT:irq_level=%d next_delay=%l ns\n", - irq_level, - (expire_time - current_time)); -#endif - } - - if (expire_time > 0) - set_timer(&(s->hvm_time->pit_timer), s->next_transition_time); - -} - -static void pit_irq_timer(void *data) -{ - PITChannelState *s = data; - - pit_irq_timer_update(s, s->next_transition_time); -} - static void pit_reset(void *opaque) { - hvm_virpit *pit = opaque; + PITState *pit = opaque; PITChannelState *s; int i; for(i = 0;i < 3; i++) { s = &pit->channels[i]; + if ( s -> pt ) { + destroy_periodic_time (s->pt); + s->pt = NULL; + } s->mode = 0xff; /* the init mode */ s->gate = (i != 2); pit_load_count(s, 0); } } -/* hvm_io_assist light-weight version, specific to PIT DM */ -static void resume_pit_io(ioreq_t *p) -{ - struct cpu_user_regs *regs = guest_cpu_user_regs(); - unsigned long old_eax = regs->eax; - p->state = STATE_INVALID; - - switch(p->size) { - case 1: - regs->eax = (old_eax & 0xffffff00) | (p->u.data & 0xff); - break; - case 2: - regs->eax = (old_eax & 0xffff0000) | (p->u.data & 0xffff); - break; - case 4: - regs->eax = (p->u.data & 0xffffffff); - break; - default: - BUG(); - } +void pit_init(struct vcpu *v, unsigned long cpu_khz) +{ + PITState *pit = &v->domain->arch.hvm_domain.pl_time.vpit; + PITChannelState *s; + + s = &pit->channels[0]; + /* the timer 0 is connected to an IRQ */ + s->vcpu = v; + s++; s->vcpu = v; + s++; s->vcpu = v; + + register_portio_handler(PIT_BASE, 4, handle_pit_io); + /* register the speaker port */ + register_portio_handler(0x61, 1, handle_speaker_io); + ticks_per_sec(v) = cpu_khz * (int64_t)1000; +#ifdef DEBUG_PIT + printk("HVM_PIT: guest frequency =%lld\n", (long long)ticks_per_sec(v)); +#endif + pit_reset(pit); + return; } /* the intercept action for PIT DM retval:0--not handled; 1--handled */ -int handle_pit_io(ioreq_t *p) +static int handle_pit_io(ioreq_t *p) { struct vcpu *v = current; - struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit); + struct PITState *vpit = &(v->domain->arch.hvm_domain.pl_time.vpit); if (p->size != 1 || p->pdata_valid || @@ -508,18 +407,18 @@ int handle_pit_io(ioreq_t *p) if (p->dir == 0) {/* write */ pit_ioport_write(vpit, p->addr, p->u.data); } else if (p->dir == 1) { /* read */ - p->u.data = pit_ioport_read(vpit, p->addr); - resume_pit_io(p); - } - - /* always return 1, since PIT sit in HV now */ + if ( (p->addr & 3) != 3 ) { + p->u.data = pit_ioport_read(vpit, p->addr); + } else { + printk("HVM_PIT: read A1:A0=3!\n"); + } + } return 1; } static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val) { - hvm_virpit *pit = opaque; - val &= 0xff; + PITState *pit = opaque; pit->speaker_data_on = (val >> 1) & 1; pit_set_gate(pit, 2, val & 1); } @@ -527,18 +426,18 @@ static uint32_t speaker_ioport_read(void static uint32_t speaker_ioport_read(void *opaque, uint32_t addr) { int out; - hvm_virpit *pit = opaque; - out = pit_get_out(pit, 2, hvm_get_clock()); + PITState *pit = opaque; + out = pit_get_out(pit, 2, hvm_get_clock(pit->channels[2].vcpu)); pit->dummy_refresh_clock ^= 1; return (pit->speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) | (pit->dummy_refresh_clock << 4); } -int handle_speaker_io(ioreq_t *p) +static int handle_speaker_io(ioreq_t *p) { struct vcpu *v = current; - struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit); + struct PITState *vpit = &(v->domain->arch.hvm_domain.pl_time.vpit); if (p->size != 1 || p->pdata_valid || @@ -551,45 +450,7 @@ int handle_speaker_io(ioreq_t *p) speaker_ioport_write(vpit, p->addr, p->u.data); } else if (p->dir == 1) {/* read */ p->u.data = speaker_ioport_read(vpit, p->addr); - resume_pit_io(p); } return 1; } - -/* pick up missed timer ticks at deactive time */ -void pickup_deactive_ticks(struct hvm_virpit *vpit) -{ - s64 next_time; - PITChannelState *s = &(vpit->channels[0]); - if ( !active_timer(&(vpit->time_info.pit_timer)) ) { - next_time = pit_get_next_transition_time(s, s->next_transition_time); - if (next_time >= 0) - set_timer(&(s->hvm_time->pit_timer), s->next_transition_time); - } -} - -void pit_init(struct hvm_virpit *pit, struct vcpu *v) -{ - PITChannelState *s; - struct hvm_time_info *hvm_time; - - s = &pit->channels[0]; - /* the timer 0 is connected to an IRQ */ - s->irq = 0; - /* channel 0 need access the related time info for intr injection */ - hvm_time = s->hvm_time = &pit->time_info; - hvm_time->vcpu = v; - - init_timer(&(hvm_time->pit_timer), pit_irq_timer, s, v->processor); - - register_portio_handler(PIT_BASE, 4, handle_pit_io); - - /* register the speaker port */ - register_portio_handler(0x61, 1, handle_speaker_io); - - pit_reset(pit); - - return; - -} diff -r f4f4dd936103 -r da7fe04d8e80 xen/arch/x86/hvm/intercept.c --- a/xen/arch/x86/hvm/intercept.c Thu May 25 16:00:09 2006 +0100 +++ b/xen/arch/x86/hvm/intercept.c Thu May 25 16:00:36 2006 +0100 @@ -214,6 +214,88 @@ void hlt_timer_fn(void *data) evtchn_set_pending(v, iopacket_port(v)); } +static __inline__ void missed_ticks(struct periodic_time *pt) +{ + int missed_ticks; + + missed_ticks = (NOW() - pt->scheduled)/(s_time_t) pt->period; + if ( missed_ticks++ >= 0 ) { + if ( missed_ticks > 1000 ) { + /* TODO: Adjust guest time togther */ + pt->pending_intr_nr ++; + } + else { + pt->pending_intr_nr += missed_ticks; + } + pt->scheduled += missed_ticks * pt->period; + } +} + +/* hook function for the platform periodic time */ +void pt_timer_fn(void *data) +{ + struct vcpu *v = data; + struct periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm); + + /* pick up missed timer tick */ + missed_ticks(pt); + if ( test_bit(_VCPUF_running, &v->vcpu_flags) ) { + set_timer(&pt->timer, pt->scheduled); + } +} + +/* pick up missed timer ticks at deactive time */ +void pickup_deactive_ticks(struct periodic_time *pt) +{ + if ( !active_timer(&(pt->timer)) ) { + missed_ticks(pt); + set_timer(&pt->timer, pt->scheduled); + } +} + +/* + * period: fire frequency in ns. + */ +struct periodic_time * create_periodic_time( + struct vcpu *v, + u32 period, + char irq, + char one_shot) +{ + struct periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm); + if ( pt->enabled ) { + if ( v->vcpu_id != 0 ) { + printk("HVM_PIT: start 2nd periodic time on non BSP!\n"); + } + stop_timer (&pt->timer); + pt->enabled = 0; + } + pt->pending_intr_nr = 0; + pt->first_injected = 0; + if (period < 900000) { /* < 0.9 ms */ + printk("HVM_PlatformTime: program too small period %u\n",period); + period = 900000; /* force to 0.9ms */ + } + pt->period = period; + pt->irq = irq; + pt->period_cycles = (u64)period * cpu_khz / 1000000L; + pt->one_shot = one_shot; + if ( one_shot ) { + printk("HVM_PL: No support for one shot platform time yet\n"); + } + pt->scheduled = NOW() + period; + set_timer (&pt->timer,pt->scheduled); + pt->enabled = 1; + return pt; +} + +void destroy_periodic_time(struct periodic_time *pt) +{ + if ( pt->enabled ) { + stop_timer(&pt->timer); + pt->enabled = 0; + } +} /* * Local variables: diff -r f4f4dd936103 -r da7fe04d8e80 xen/arch/x86/hvm/svm/intr.c --- a/xen/arch/x86/hvm/svm/intr.c Thu May 25 16:00:09 2006 +0100 +++ b/xen/arch/x86/hvm/svm/intr.c Thu May 25 16:00:36 2006 +0100 @@ -44,45 +44,33 @@ */ #define BSP_CPU(v) (!(v->vcpu_id)) -u64 svm_get_guest_time(struct vcpu *v) -{ - struct hvm_time_info *time_info = &(v->domain->arch.hvm_domain.vpit.time_info); - u64 host_tsc; - - rdtscll(host_tsc); - return host_tsc + time_info->cache_tsc_offset; -} - void svm_set_guest_time(struct vcpu *v, u64 gtime) { - struct hvm_time_info *time_info = &(v->domain->arch.hvm_domain.vpit.time_info); u64 host_tsc; rdtscll(host_tsc); - time_info->cache_tsc_offset = gtime - host_tsc; - v->arch.hvm_svm.vmcb->tsc_offset = time_info->cache_tsc_offset; + v->arch.hvm_vcpu.cache_tsc_offset = gtime - host_tsc; + v->arch.hvm_svm.vmcb->tsc_offset = v->arch.hvm_vcpu.cache_tsc_offset; } static inline void interrupt_post_injection(struct vcpu * v, int vector, int type) { - struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit); - struct hvm_time_info *time_info = &vpit->time_info; + struct periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm); if ( is_pit_irq(v, vector, type) ) { - if ( !time_info->first_injected ) { - time_info->pending_intr_nr = 0; - time_info->last_pit_gtime = svm_get_guest_time(v); - time_info->first_injected = 1; + if ( !pt->first_injected ) { + pt->pending_intr_nr = 0; + pt->last_plt_gtime = hvm_get_guest_time(v); + pt->scheduled = NOW() + pt->period; + set_timer(&pt->timer, pt->scheduled); + pt->first_injected = 1; } else { - time_info->pending_intr_nr--; + pt->pending_intr_nr--; + pt->last_plt_gtime += pt->period_cycles; + svm_set_guest_time(v, pt->last_plt_gtime); } - time_info->count_advance = 0; - time_info->count_point = NOW(); - - time_info->last_pit_gtime += time_info->period_cycles; - svm_set_guest_time(v, time_info->last_pit_gtime); } switch(type) @@ -121,8 +109,7 @@ asmlinkage void svm_intr_assist(void) struct vcpu *v = current; struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; struct hvm_domain *plat=&v->domain->arch.hvm_domain; - struct hvm_virpit *vpit = &plat->vpit; - struct hvm_time_info *time_info = &vpit->time_info; + struct periodic_time *pt = &plat->pl_time.periodic_tm; struct hvm_virpic *pic= &plat->vpic; int intr_type = VLAPIC_DELIV_MODE_EXT; int intr_vector = -1; @@ -174,9 +161,9 @@ asmlinkage void svm_intr_assist(void) if ( cpu_has_pending_irq(v) ) { intr_vector = cpu_get_interrupt(v, &intr_type); } - else if ( (v->vcpu_id == 0) && time_info->pending_intr_nr ) { - pic_set_irq(pic, 0, 0); - pic_set_irq(pic, 0, 1); + else if ( (v->vcpu_id == 0) && pt->enabled && pt->pending_intr_nr ) { + pic_set_irq(pic, pt->irq, 0); + pic_set_irq(pic, pt->irq, 1); intr_vector = cpu_get_interrupt(v, &intr_type); } } @@ -190,7 +177,7 @@ asmlinkage void svm_intr_assist(void) /* Re-injecting a PIT interruptt? */ if (re_injecting && is_pit_irq(v, intr_vector, intr_type)) { - ++time_info->pending_intr_nr; + ++pt->pending_intr_nr; } /* let's inject this interrupt */ TRACE_3D(TRC_VMX_INT, v->domain->domain_id, intr_vector, 0); diff -r f4f4dd936103 -r da7fe04d8e80 xen/arch/x86/hvm/svm/svm.c --- a/xen/arch/x86/hvm/svm/svm.c Thu May 25 16:00:09 2006 +0100 +++ b/xen/arch/x86/hvm/svm/svm.c Thu May 25 16:00:36 2006 +0100 @@ -672,12 +672,11 @@ static void arch_svm_do_launch(struct vc static void svm_freeze_time(struct vcpu *v) { - struct hvm_time_info *time_info = &v->domain->arch.hvm_domain.vpit.time_info; + struct periodic_time *pt=&v->domain->arch.hvm_domain.pl_time.periodic_tm; - if ( time_info->first_injected && !v->domain->arch.hvm_domain.guest_time ) { - v->domain->arch.hvm_domain.guest_time = svm_get_guest_time(v); - time_info->count_advance += (NOW() - time_info->count_point); - stop_timer(&(time_info->pit_timer)); + if ( pt->enabled && pt->first_injected && !v->arch.hvm_vcpu.guest_time ) { + v->arch.hvm_vcpu.guest_time = hvm_get_guest_time(v); + stop_timer(&(pt->timer)); } } @@ -754,7 +753,7 @@ static void svm_relinquish_guest_resourc } } - kill_timer(&d->arch.hvm_domain.vpit.time_info.pit_timer); + kill_timer(&d->arch.hvm_domain.pl_time.periodic_tm.timer); if ( d->arch.hvm_domain.shared_page_va ) unmap_domain_page_global( @@ -784,10 +783,12 @@ void arch_svm_do_resume(struct vcpu *v) void svm_migrate_timers(struct vcpu *v) { - struct hvm_time_info *time_info = &v->domain->arch.hvm_domain.vpit.time_info; - - migrate_timer(&time_info->pit_timer, v->processor); - migrate_timer(&v->arch.hvm_svm.hlt_timer, v->processor); + struct periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm); + + if ( pt->enabled ) { + migrate_timer( &pt->timer, v->processor ); + migrate_timer( &v->arch.hvm_svm.hlt_timer, v->processor ); + } if ( hvm_apic_support(v->domain) && VLAPIC( v )) migrate_timer( &(VLAPIC(v)->vlapic_timer ), v->processor ); } @@ -1901,14 +1902,8 @@ static inline void svm_do_msr_access(str regs->edx = 0; switch (regs->ecx) { case MSR_IA32_TIME_STAMP_COUNTER: - { - struct hvm_time_info *time_info; - - rdtscll(msr_content); - time_info = &v->domain->arch.hvm_domain.vpit.time_info; - msr_content += time_info->cache_tsc_offset; + msr_content = hvm_get_guest_time(v); break; - } case MSR_IA32_SYSENTER_CS: msr_content = vmcb->sysenter_cs; break; @@ -1975,7 +1970,7 @@ static inline void svm_vmexit_do_hlt(str static inline void svm_vmexit_do_hlt(struct vmcb_struct *vmcb) { struct vcpu *v = current; - struct hvm_virpit *vpit = &v->domain->arch.hvm_domain.vpit; + struct periodic_time *pt=&v->domain->arch.hvm_domain.pl_time.periodic_tm; s_time_t next_pit = -1, next_wakeup; __update_guest_eip(vmcb, 1); @@ -1985,7 +1980,7 @@ static inline void svm_vmexit_do_hlt(str return; if ( !v->vcpu_id ) - next_pit = get_pit_scheduled(v, vpit); + next_pit = get_scheduled(v, pt->irq, pt); next_wakeup = get_apictime_scheduled(v); if ( (next_pit != -1 && next_pit < next_wakeup) || next_wakeup == -1 ) next_wakeup = next_pit; diff -r f4f4dd936103 -r da7fe04d8e80 xen/arch/x86/hvm/svm/vmcb.c --- a/xen/arch/x86/hvm/svm/vmcb.c Thu May 25 16:00:09 2006 +0100 +++ b/xen/arch/x86/hvm/svm/vmcb.c Thu May 25 16:00:36 2006 +0100 @@ -442,19 +442,17 @@ void svm_do_resume(struct vcpu *v) void svm_do_resume(struct vcpu *v) { struct domain *d = v->domain; - struct hvm_virpit *vpit = &d->arch.hvm_domain.vpit; - struct hvm_time_info *time_info = &vpit->time_info; + struct periodic_time *pt = &d->arch.hvm_domain.pl_time.periodic_tm; svm_stts(v); /* pick up the elapsed PIT ticks and re-enable pit_timer */ - if ( time_info->first_injected ) { - if ( v->domain->arch.hvm_domain.guest_time ) { - svm_set_guest_time(v, v->domain->arch.hvm_domain.guest_time); - time_info->count_point = NOW(); - v->domain->arch.hvm_domain.guest_time = 0; + if ( pt->enabled && pt->first_injected ) { + if ( v->arch.hvm_vcpu.guest_time ) { + svm_set_guest_time(v, v->arch.hvm_vcpu.guest_time); + v->arch.hvm_vcpu.guest_time = 0; } - pickup_deactive_ticks(vpit); + pickup_deactive_ticks(pt); } if ( test_bit(iopacket_port(v), &d->shared_info->evtchn_pending[0]) || diff -r f4f4dd936103 -r da7fe04d8e80 xen/arch/x86/hvm/vmx/io.c --- a/xen/arch/x86/hvm/vmx/io.c Thu May 25 16:00:09 2006 +0100 +++ b/xen/arch/x86/hvm/vmx/io.c Thu May 25 16:00:36 2006 +0100 @@ -49,45 +49,33 @@ void __set_tsc_offset(u64 offset) #endif } -u64 get_guest_time(struct vcpu *v) -{ - struct hvm_time_info *time_info = &(v->domain->arch.hvm_domain.vpit.time_info); - u64 host_tsc; - - rdtscll(host_tsc); - return host_tsc + time_info->cache_tsc_offset; -} - void set_guest_time(struct vcpu *v, u64 gtime) { - struct hvm_time_info *time_info = &(v->domain->arch.hvm_domain.vpit.time_info); u64 host_tsc; rdtscll(host_tsc); - time_info->cache_tsc_offset = gtime - host_tsc; - __set_tsc_offset(time_info->cache_tsc_offset); + v->arch.hvm_vcpu.cache_tsc_offset = gtime - host_tsc; + __set_tsc_offset(v->arch.hvm_vcpu.cache_tsc_offset); } static inline void interrupt_post_injection(struct vcpu * v, int vector, int type) { - struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit); - struct hvm_time_info *time_info = &vpit->time_info; + struct periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm); if ( is_pit_irq(v, vector, type) ) { - if ( !time_info->first_injected ) { - time_info->pending_intr_nr = 0; - time_info->last_pit_gtime = get_guest_time(v); - time_info->first_injected = 1; + if ( !pt->first_injected ) { + pt->pending_intr_nr = 0; + pt->last_plt_gtime = hvm_get_guest_time(v); + pt->scheduled = NOW() + pt->period; + set_timer(&pt->timer, pt->scheduled); + pt->first_injected = 1; } else { - time_info->pending_intr_nr--; - } - time_info->count_advance = 0; - time_info->count_point = NOW(); - - time_info->last_pit_gtime += time_info->period_cycles; - set_guest_time(v, time_info->last_pit_gtime); + pt->pending_intr_nr--; + pt->last_plt_gtime += pt->period_cycles; + set_guest_time(v, pt->last_plt_gtime); + } } switch(type) @@ -151,7 +139,7 @@ asmlinkage void vmx_intr_assist(void) unsigned long eflags; struct vcpu *v = current; struct hvm_domain *plat=&v->domain->arch.hvm_domain; - struct hvm_time_info *time_info = &plat->vpit.time_info; + struct periodic_time *pt = &plat->pl_time.periodic_tm; struct hvm_virpic *pic= &plat->vpic; unsigned int idtv_info_field; unsigned long inst_len; @@ -160,9 +148,9 @@ asmlinkage void vmx_intr_assist(void) if ( v->vcpu_id == 0 ) hvm_pic_assist(v); - if ( (v->vcpu_id == 0) && time_info->pending_intr_nr ) { - pic_set_irq(pic, 0, 0); - pic_set_irq(pic, 0, 1); + if ( (v->vcpu_id == 0) && pt->enabled && pt->pending_intr_nr ) { + pic_set_irq(pic, pt->irq, 0); + pic_set_irq(pic, pt->irq, 1); } has_ext_irq = cpu_has_pending_irq(v); @@ -232,19 +220,17 @@ void vmx_do_resume(struct vcpu *v) void vmx_do_resume(struct vcpu *v) { struct domain *d = v->domain; - struct hvm_virpit *vpit = &v->domain->arch.hvm_domain.vpit; - struct hvm_time_info *time_info = &vpit->time_info; + struct periodic_time *pt = &v->domain->arch.hvm_domain.pl_time.periodic_tm; vmx_stts(); /* pick up the elapsed PIT ticks and re-enable pit_timer */ - if ( time_info->first_injected ) { - if ( v->domain->arch.hvm_domain.guest_time ) { - time_info->count_point = NOW(); - set_guest_time(v, v->domain->arch.hvm_domain.guest_time); - v->domain->arch.hvm_domain.guest_time = 0; - } - pickup_deactive_ticks(vpit); + if ( pt->enabled && pt->first_injected ) { + if ( v->arch.hvm_vcpu.guest_time ) { + set_guest_time(v, v->arch.hvm_vcpu.guest_time); + v->arch.hvm_vcpu.guest_time = 0; + } + pickup_deactive_ticks(pt); } if ( test_bit(iopacket_port(v), &d->shared_info->evtchn_pending[0]) || diff -r f4f4dd936103 -r da7fe04d8e80 xen/arch/x86/hvm/vmx/vmx.c --- a/xen/arch/x86/hvm/vmx/vmx.c Thu May 25 16:00:09 2006 +0100 +++ b/xen/arch/x86/hvm/vmx/vmx.c Thu May 25 16:00:36 2006 +0100 @@ -102,7 +102,7 @@ static void vmx_relinquish_guest_resourc } } - kill_timer(&d->arch.hvm_domain.vpit.time_info.pit_timer); + kill_timer(&d->arch.hvm_domain.pl_time.periodic_tm.timer); if ( d->arch.hvm_domain.shared_page_va ) unmap_domain_page_global( @@ -358,12 +358,11 @@ static inline int long_mode_do_msr_write static void vmx_freeze_time(struct vcpu *v) { - struct hvm_time_info *time_info = &(v->domain->arch.hvm_domain.vpit.time_info); + struct periodic_time *pt=&v->domain->arch.hvm_domain.pl_time.periodic_tm; - if ( time_info->first_injected && !v->domain->arch.hvm_domain.guest_time ) { - v->domain->arch.hvm_domain.guest_time = get_guest_time(v); - time_info->count_advance += (NOW() - time_info->count_point); - stop_timer(&(time_info->pit_timer)); + if ( pt->enabled && pt->first_injected && !v->arch.hvm_vcpu.guest_time ) { + v->arch.hvm_vcpu.guest_time = hvm_get_guest_time(v); + stop_timer(&(pt->timer)); } } @@ -393,10 +392,12 @@ int vmx_initialize_guest_resources(struc void vmx_migrate_timers(struct vcpu *v) { - struct hvm_time_info *time_info = &v->domain->arch.hvm_domain.vpit.time_info; - - migrate_timer(&time_info->pit_timer, v->processor); - migrate_timer(&v->arch.hvm_vmx.hlt_timer, v->processor); + struct periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm); + + if ( pt->enabled ) { + migrate_timer(&pt->timer, v->processor); + migrate_timer(&v->arch.hvm_vmx.hlt_timer, v->processor); + } if ( hvm_apic_support(v->domain) && VLAPIC(v)) migrate_timer(&(VLAPIC(v)->vlapic_timer), v->processor); } @@ -1861,14 +1862,8 @@ static inline void vmx_do_msr_read(struc (unsigned long)regs->edx); switch (regs->ecx) { case MSR_IA32_TIME_STAMP_COUNTER: - { - struct hvm_time_info *time_info; - - rdtscll(msr_content); - time_info = &(v->domain->arch.hvm_domain.vpit.time_info); - msr_content += time_info->cache_tsc_offset; - break; - } + msr_content = hvm_get_guest_time(v); + break; case MSR_IA32_SYSENTER_CS: __vmread(GUEST_SYSENTER_CS, (u32 *)&msr_content); break; @@ -1941,11 +1936,11 @@ void vmx_vmexit_do_hlt(void) void vmx_vmexit_do_hlt(void) { struct vcpu *v=current; - struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit); + struct periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm); s_time_t next_pit=-1,next_wakeup; if ( !v->vcpu_id ) - next_pit = get_pit_scheduled(v,vpit); + next_pit = get_scheduled(v, pt->irq, pt); next_wakeup = get_apictime_scheduled(v); if ( (next_pit != -1 && next_pit < next_wakeup) || next_wakeup == -1 ) next_wakeup = next_pit; diff -r f4f4dd936103 -r da7fe04d8e80 xen/include/asm-x86/hvm/domain.h --- a/xen/include/asm-x86/hvm/domain.h Thu May 25 16:00:09 2006 +0100 +++ b/xen/include/asm-x86/hvm/domain.h Thu May 25 16:00:36 2006 +0100 @@ -35,9 +35,9 @@ struct hvm_domain { unsigned int nr_vcpus; unsigned int apic_enabled; unsigned int pae_enabled; - - struct hvm_virpit vpit; - u64 guest_time; + s64 tsc_frequency; + struct pl_time pl_time; + struct hvm_virpic vpic; struct hvm_vioapic vioapic; struct hvm_io_handler io_handler; diff -r f4f4dd936103 -r da7fe04d8e80 xen/include/asm-x86/hvm/svm/intr.h --- a/xen/include/asm-x86/hvm/svm/intr.h Thu May 25 16:00:09 2006 +0100 +++ b/xen/include/asm-x86/hvm/svm/intr.h Thu May 25 16:00:36 2006 +0100 @@ -21,7 +21,6 @@ #ifndef __ASM_X86_HVM_SVM_INTR_H__ #define __ASM_X86_HVM_SVM_INTR_H__ -extern void svm_set_tsc_shift(struct vcpu *v, struct hvm_virpit *vpit); extern void svm_intr_assist(void); extern void svm_intr_assist_update(struct vcpu *v, int highest_vector); extern void svm_intr_assist_test_valid(struct vcpu *v, diff -r f4f4dd936103 -r da7fe04d8e80 xen/include/asm-x86/hvm/svm/svm.h --- a/xen/include/asm-x86/hvm/svm/svm.h Thu May 25 16:00:09 2006 +0100 +++ b/xen/include/asm-x86/hvm/svm/svm.h Thu May 25 16:00:36 2006 +0100 @@ -48,7 +48,6 @@ extern void svm_do_launch(struct vcpu *v extern void svm_do_launch(struct vcpu *v); extern void svm_do_resume(struct vcpu *v); extern void svm_set_guest_time(struct vcpu *v, u64 gtime); -extern u64 svm_get_guest_time(struct vcpu *v); extern void arch_svm_do_resume(struct vcpu *v); extern int load_vmcb(struct arch_svm_struct *arch_svm, u64 phys_hsa); /* For debugging. Remove when no longer needed. */ diff -r f4f4dd936103 -r da7fe04d8e80 xen/include/asm-x86/hvm/vcpu.h --- a/xen/include/asm-x86/hvm/vcpu.h Thu May 25 16:00:09 2006 +0100 +++ b/xen/include/asm-x86/hvm/vcpu.h Thu May 25 16:00:36 2006 +0100 @@ -32,6 +32,9 @@ struct hvm_vcpu { unsigned long ioflags; struct mmio_op mmio_op; struct vlapic *vlapic; + s64 cache_tsc_offset; + u64 guest_time; + /* For AP startup */ unsigned long init_sipi_sipi_state; diff -r f4f4dd936103 -r da7fe04d8e80 xen/include/asm-x86/hvm/vmx/vmx.h --- a/xen/include/asm-x86/hvm/vmx/vmx.h Thu May 25 16:00:09 2006 +0100 +++ b/xen/include/asm-x86/hvm/vmx/vmx.h Thu May 25 16:00:36 2006 +0100 @@ -34,7 +34,6 @@ extern void arch_vmx_do_launch(struct vc extern void arch_vmx_do_launch(struct vcpu *); extern void arch_vmx_do_resume(struct vcpu *); extern void set_guest_time(struct vcpu *v, u64 gtime); -extern u64 get_guest_time(struct vcpu *v); extern unsigned int cpu_rev; diff -r f4f4dd936103 -r da7fe04d8e80 xen/include/asm-x86/hvm/vpit.h --- a/xen/include/asm-x86/hvm/vpit.h Thu May 25 16:00:09 2006 +0100 +++ b/xen/include/asm-x86/hvm/vpit.h Thu May 25 16:00:36 2006 +0100 @@ -29,9 +29,7 @@ #include <asm/hvm/vpic.h> #define PIT_FREQ 1193181 - -#define PIT_BASE 0x40 -#define HVM_PIT_ACCEL_MODE 2 +#define PIT_BASE 0x40 typedef struct PITChannelState { int count; /* can be 65536 */ @@ -48,47 +46,56 @@ typedef struct PITChannelState { u8 gate; /* timer start */ s64 count_load_time; /* irq handling */ - s64 next_transition_time; - int irq; - struct hvm_time_info *hvm_time; - u32 period; /* period(ns) based on count */ + struct vcpu *vcpu; + struct periodic_time *pt; } PITChannelState; - -struct hvm_time_info { - /* extra info for the mode 2 channel */ - struct timer pit_timer; - struct vcpu *vcpu; /* which vcpu the ac_timer bound to */ - u64 period_cycles; /* pit frequency in cpu cycles */ - s_time_t count_advance; /* accumulated count advance since last fire */ - s_time_t count_point; /* last point accumulating count advance */ - unsigned int pending_intr_nr; /* the couner for pending timer interrupts */ - int first_injected; /* flag to prevent shadow window */ - s64 cache_tsc_offset; /* cache of VMCS TSC_OFFSET offset */ - u64 last_pit_gtime; /* guest time when last pit is injected */ + +/* + * Abstract layer of periodic time, one short time. + */ +struct periodic_time { + char enabled; /* enabled */ + char one_shot; /* one shot time */ + char irq; + char first_injected; /* flag to prevent shadow window */ + u32 pending_intr_nr; /* the couner for pending timer interrupts */ + u32 period; /* frequency in ns */ + u64 period_cycles; /* frequency in cpu cycles */ + s_time_t scheduled; /* scheduled timer interrupt */ + u64 last_plt_gtime; /* platform time when last IRQ is injected */ + struct timer timer; /* ac_timer */ }; -typedef struct hvm_virpit { +typedef struct PITState { PITChannelState channels[3]; - struct hvm_time_info time_info; int speaker_data_on; int dummy_refresh_clock; -}hvm_virpit; +} PITState; +struct pl_time { /* platform time */ + struct periodic_time periodic_tm; + struct PITState vpit; + /* TODO: RTC/ACPI time */ +}; -static __inline__ s_time_t get_pit_scheduled( - struct vcpu *v, - struct hvm_virpit *vpit) +static __inline__ s_time_t get_scheduled( + struct vcpu *v, int irq, + struct periodic_time *pt) { - struct PITChannelState *s = &(vpit->channels[0]); - if ( is_irq_enabled(v, 0) ) { - return s->next_transition_time; + if ( is_irq_enabled(v, irq) ) { + return pt->scheduled; } else return -1; } /* to hook the ioreq packet to get the PIT initialization info */ -extern void pit_init(struct hvm_virpit *pit, struct vcpu *v); -extern void pickup_deactive_ticks(struct hvm_virpit *vpit); +extern void hvm_hooks_assist(struct vcpu *v); +extern void pickup_deactive_ticks(struct periodic_time *vpit); +extern u64 hvm_get_guest_time(struct vcpu *v); +extern struct periodic_time *create_periodic_time(struct vcpu *v, u32 period, char irq, char one_shot); +extern void destroy_periodic_time(struct periodic_time *pt); +void pit_init(struct vcpu *v, unsigned long cpu_khz); +void pt_timer_fn(void *data); #endif /* __ASM_X86_HVM_VPIT_H__ */ _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |