diff -r c42fcc739fc4 tools/firmware/hvmloader/acpi/static_tables.c --- a/tools/firmware/hvmloader/acpi/static_tables.c Tue Oct 23 08:16:39 2007 -0400 +++ b/tools/firmware/hvmloader/acpi/static_tables.c Tue Oct 23 08:16:39 2007 -0400 @@ -93,7 +93,7 @@ struct acpi_20_fadt Fadt = { }, .x_pm_tmr_blk = { - .address_space_id = ACPI_SYSTEM_IO, + .address_space_id = 0xff, .register_bit_width = ACPI_PM_TMR_BLK_BIT_WIDTH, .register_bit_offset = ACPI_PM_TMR_BLK_BIT_OFFSET, .address = ACPI_PM_TMR_BLK_ADDRESS, diff -r c42fcc739fc4 xen/arch/x86/hvm/i8254.c --- a/xen/arch/x86/hvm/i8254.c Tue Oct 23 08:16:39 2007 -0400 +++ b/xen/arch/x86/hvm/i8254.c Tue Oct 23 08:16:39 2007 -0400 @@ -405,6 +405,8 @@ static void pit_info(PITState *pit) struct hvm_hw_pit_channel *s; struct periodic_time *pt; int i; + struct periodic_time *pt; + unsigned long now; for ( i = 0; i < 3; i++ ) { @@ -447,11 +449,18 @@ static int pit_save(struct domain *d, hv { PITState *pit = domain_vpit(d); int rc; + unsigned long now; + struct periodic_time *pt; spin_lock(&pit->lock); pit_info(pit); + pt = &pit->pt0; + rdtscll(now); + pit->hw.pt_delivered = pt->delivered - now; + pit->hw.pt_frozen = pt->frozen - now; + /* Save the PIT hardware state */ rc = hvm_save_entry(PIT, 0, h, &pit->hw); @@ -464,6 +473,8 @@ static int pit_load(struct domain *d, hv { PITState *pit = domain_vpit(d); int i; + struct periodic_time *pt; + unsigned long now; spin_lock(&pit->lock); @@ -481,6 +492,11 @@ static int pit_load(struct domain *d, hv for ( i = 0; i < 3; i++ ) pit_load_count(pit, i, pit->hw.channels[i].count); + pt = &pit->pt0; + rdtscll(now); + pt->delivered = now + pit->hw.pt_delivered; + pt->frozen = now + pit->hw.pt_frozen; + pit_info(pit); spin_unlock(&pit->lock); @@ -514,6 +530,18 @@ void pit_init(struct vcpu *v, unsigned l } spin_unlock(&pit->lock); +} + +struct periodic_time *pit_get_timer(struct vcpu *v) +{ + PITState *pit = &v->domain->arch.hvm_domain.pl_time.vpit; + struct periodic_time *pt; + + pt = &pit->pt0; + if ( pt->vcpu == v && pt->enabled ) + return pt; + else + return NULL; } void pit_deinit(struct domain *d) diff -r c42fcc739fc4 xen/arch/x86/hvm/vpt.c --- a/xen/arch/x86/hvm/vpt.c Tue Oct 23 08:16:39 2007 -0400 +++ b/xen/arch/x86/hvm/vpt.c Tue Oct 23 08:18:49 2007 -0400 @@ -54,16 +54,7 @@ static void missed_ticks(struct periodic return; missed_ticks = missed_ticks / (s_time_t) pt->period + 1; - if ( missed_ticks > 1000 ) - { - /* TODO: Adjust guest time together */ - pt->pending_intr_nr++; - } - else - { - pt->pending_intr_nr += missed_ticks; - } - + pt->pending_intr_nr += missed_ticks; pt->scheduled += missed_ticks * pt->period; } @@ -71,6 +62,7 @@ void pt_freeze_time(struct vcpu *v) { struct list_head *head = &v->arch.hvm_vcpu.tm_list; struct periodic_time *pt; + unsigned long now; if ( test_bit(_VPF_blocked, &v->pause_flags) ) return; @@ -79,8 +71,12 @@ void pt_freeze_time(struct vcpu *v) v->arch.hvm_vcpu.guest_time = hvm_get_guest_time(v); - list_for_each_entry ( pt, head, list ) + rdtscll(now); + list_for_each_entry ( pt, head, list ) + { stop_timer(&pt->timer); + pt->frozen = now; + } spin_unlock(&v->arch.hvm_vcpu.tm_lock); } @@ -89,6 +85,7 @@ void pt_thaw_time(struct vcpu *v) { struct list_head *head = &v->arch.hvm_vcpu.tm_list; struct periodic_time *pt; + unsigned long now, delta; spin_lock(&v->arch.hvm_vcpu.tm_lock); @@ -97,10 +94,14 @@ void pt_thaw_time(struct vcpu *v) hvm_set_guest_time(v, v->arch.hvm_vcpu.guest_time); v->arch.hvm_vcpu.guest_time = 0; + rdtscll(now); list_for_each_entry ( pt, head, list ) { missed_ticks(pt); set_timer(&pt->timer, pt->scheduled); + delta = now - pt->frozen; + if(pt->delivered) + pt->delivered += delta; } } @@ -158,6 +159,57 @@ void pt_update_irq(struct vcpu *v) hvm_isa_irq_assert(v->domain, irq); } } +#include +struct periodic_time *pit_get_timer(struct vcpu *v); +int pt_irq_subtract(struct vcpu *v, struct periodic_time *pt_handled) +{ + struct periodic_time *pt; + unsigned long delta_us; + unsigned long period_us; + int new_nr; + unsigned long now, delta; + unsigned long ticks, offset; + int ret = 0; + + /* 64bit Linux guests calculate missed ticks in the clock interrupt handler + * and bump jiffies accordingly while 32bit Linux guests do not. + * If the (64bit) guest cpu0 has interrupts disabled for longer than two clock + * periods, and cpu0 is running, then since the tsc continues, the guest will + * find missed_ticks > 1 at the first clock interrupt. But the pt timer has continued + * to expire regularly and accumulated the missed interrupts in pending_intr_nr. + * If we deliver these accumulated interrupts the guest will run fast. + * Here we subtract off the missed interrupts for 64 bit guests using pit. + */ + + if(v->arch.paging.mode->guest_levels != 4) + return ret; + pt = pit_get_timer(v); + if(pt) + ret = 1; + if(pt == pt_handled) { + rdtscll(now); + if(!pt->delivered) { + pt->delivered = now; + return ret; + } + delta = now - pt->delivered; + pt->delivered = now; + delta_us = (delta * 1000UL)/(unsigned long)cpu_khz; + period_us = pt->period/1000UL; /* ns to usec*/ + ticks = delta_us/period_us; + offset = delta_us % period_us; + if(ticks < 2) + return ret; + ticks -= 1; + pt->delivered = now - (offset * (unsigned long)cpu_khz)/1000UL; + new_nr = pt->pending_intr_nr - ticks; + if(new_nr < 1) + ticks = ticks + new_nr - 1; + pt->pending_intr_nr -= ticks; + pt->last_plt_gtime += ticks * pt->period_cycles; + } + return ret; +} static struct periodic_time *is_pt_irq( struct vcpu *v, struct hvm_intack intack) @@ -197,6 +249,7 @@ void pt_intr_post(struct vcpu *v, struct struct periodic_time *pt; time_cb *cb; void *cb_priv; + int pit_only; spin_lock(&v->arch.hvm_vcpu.tm_lock); @@ -207,6 +260,7 @@ void pt_intr_post(struct vcpu *v, struct return; } + pit_only = pt_irq_subtract(v, pt); if ( pt->one_shot ) { pt->enabled = 0; @@ -218,8 +272,12 @@ void pt_intr_post(struct vcpu *v, struct pt->last_plt_gtime += pt->period_cycles; } - if ( hvm_get_guest_time(v) < pt->last_plt_gtime ) - hvm_set_guest_time(v, pt->last_plt_gtime); + if(pit_only) { + if((pt == pit_get_timer(v)) && (hvm_get_guest_time(pt->vcpu) < pt->last_plt_gtime)) + hvm_set_guest_time(pt->vcpu, pt->last_plt_gtime); + } + else if(hvm_get_guest_time(pt->vcpu) < pt->last_plt_gtime) + hvm_set_guest_time(pt->vcpu, pt->last_plt_gtime); cb = pt->cb; cb_priv = pt->priv; diff -r c42fcc739fc4 xen/include/asm-x86/hvm/vpt.h --- a/xen/include/asm-x86/hvm/vpt.h Tue Oct 23 08:16:39 2007 -0400 +++ b/xen/include/asm-x86/hvm/vpt.h Tue Oct 23 08:16:39 2007 -0400 @@ -76,7 +76,7 @@ struct periodic_time { char one_shot; /* one shot time */ u8 irq; struct vcpu *vcpu; /* vcpu timer interrupt delivers to */ - u32 pending_intr_nr; /* the couner for pending timer interrupts */ + unsigned int pending_intr_nr; /* the couner for pending timer interrupts */ u64 period; /* frequency in ns */ u64 period_cycles; /* frequency in cpu cycles */ s_time_t scheduled; /* scheduled timer interrupt */ @@ -84,6 +84,8 @@ struct periodic_time { struct timer timer; /* ac_timer */ time_cb *cb; void *priv; /* point back to platform time source */ + unsigned long delivered; + unsigned long frozen; }; diff -r c42fcc739fc4 xen/include/public/arch-x86/hvm/save.h --- a/xen/include/public/arch-x86/hvm/save.h Tue Oct 23 08:16:39 2007 -0400 +++ b/xen/include/public/arch-x86/hvm/save.h Tue Oct 23 08:34:05 2007 -0400 @@ -156,6 +156,8 @@ struct hvm_hw_cpu { }; /* error code for pending event */ uint32_t error_code; + unsigned long pt_delivered; + unsigned long pt_frozen; }; DECLARE_HVM_SAVE_TYPE(CPU, 2, struct hvm_hw_cpu); @@ -342,6 +344,8 @@ struct hvm_hw_pit { } channels[3]; /* 3 x 16 bytes */ uint32_t speaker_data_on; uint32_t pad0; + unsigned long pt_delivered; + unsigned long pt_frozen; }; DECLARE_HVM_SAVE_TYPE(PIT, 10, struct hvm_hw_pit);