diff options
author | Keir Fraser <keir@xensource.com> | 2007-06-15 15:30:49 +0100 |
---|---|---|
committer | Keir Fraser <keir@xensource.com> | 2007-06-15 15:30:49 +0100 |
commit | 34bef0e6d5f4db553c68bd482e5e0f9487dea300 (patch) | |
tree | 174d695b5c7d40e3bebb9a567aa7b301c91a5ebe /xen/arch/x86/hvm/hpet.c | |
parent | b010d6c68edcd9a057310240a97de6186db12437 (diff) | |
download | xen-34bef0e6d5f4db553c68bd482e5e0f9487dea300.tar.gz xen-34bef0e6d5f4db553c68bd482e5e0f9487dea300.tar.bz2 xen-34bef0e6d5f4db553c68bd482e5e0f9487dea300.zip |
hvm: Add locking to platform timers.
Handy for correctness.
Signed-off-by: Keir Fraser <keir@xensource.com>
Diffstat (limited to 'xen/arch/x86/hvm/hpet.c')
-rw-r--r-- | xen/arch/x86/hvm/hpet.c | 41 |
1 files changed, 39 insertions, 2 deletions
diff --git a/xen/arch/x86/hvm/hpet.c b/xen/arch/x86/hvm/hpet.c index 155dbffcc7..2b8935b47f 100644 --- a/xen/arch/x86/hvm/hpet.c +++ b/xen/arch/x86/hvm/hpet.c @@ -113,6 +113,8 @@ static inline int hpet_check_access_length( static inline uint64_t hpet_read_maincounter(HPETState *h) { + ASSERT(spin_is_locked(&h->lock)); + if ( hpet_enabled(h) ) return guest_time_hpet(h->vcpu) + h->mc_offset; else @@ -131,6 +133,8 @@ static unsigned long hpet_read( if ( hpet_check_access_length(addr, length) != 0 ) return ~0UL; + spin_lock(&h->lock); + val = hpet_read64(h, addr & ~7); if ( (addr & ~7) == HPET_COUNTER ) val = hpet_read_maincounter(h); @@ -139,12 +143,15 @@ static unsigned long hpet_read( if ( length != 8 ) result = (val >> ((addr & 7) * 8)) & ((1UL << (length * 8)) - 1); + spin_unlock(&h->lock); + return result; } static void hpet_stop_timer(HPETState *h, unsigned int tn) { ASSERT(tn < HPET_TIMER_NUM); + ASSERT(spin_is_locked(&h->lock)); stop_timer(&h->timers[tn]); } @@ -157,7 +164,8 @@ static void hpet_set_timer(HPETState *h, unsigned int tn) uint64_t tn_cmp, cur_tick, diff; ASSERT(tn < HPET_TIMER_NUM); - + ASSERT(spin_is_locked(&h->lock)); + if ( !hpet_enabled(h) || !timer_enabled(h, tn) ) return; @@ -213,6 +221,8 @@ static void hpet_write( if ( hpet_check_access_length(addr, length) != 0 ) return; + spin_lock(&h->lock); + old_val = hpet_read64(h, addr & ~7); if ( (addr & ~7) == HPET_COUNTER ) old_val = hpet_read_maincounter(h); @@ -302,6 +312,8 @@ static void hpet_write( /* Ignore writes to unsupported and reserved registers. */ break; } + + spin_unlock(&h->lock); } static int hpet_range(struct vcpu *v, unsigned long addr) @@ -321,6 +333,8 @@ static void hpet_route_interrupt(HPETState *h, unsigned int tn) unsigned int tn_int_route = timer_int_route(h, tn); struct domain *d = h->vcpu->domain; + ASSERT(spin_is_locked(&h->lock)); + if ( (tn <= 1) && (h->hpet.config & HPET_CFG_LEGACY) ) { /* if LegacyReplacementRoute bit is set, HPET specification requires @@ -352,8 +366,13 @@ static void hpet_timer_fn(void *opaque) HPETState *h = htfi->hs; unsigned int tn = htfi->tn; + spin_lock(&h->lock); + if ( !hpet_enabled(h) || !timer_enabled(h, tn) ) + { + spin_unlock(&h->lock); return; + } hpet_route_interrupt(h, tn); @@ -374,6 +393,8 @@ static void hpet_timer_fn(void *opaque) set_timer(&h->timers[tn], NOW() + hpet_tick_to_ns(h, h->hpet.period[tn])); } + + spin_unlock(&h->lock); } void hpet_migrate_timers(struct vcpu *v) @@ -391,12 +412,19 @@ void hpet_migrate_timers(struct vcpu *v) static int hpet_save(struct domain *d, hvm_domain_context_t *h) { HPETState *hp = &d->arch.hvm_domain.pl_time.vhpet; + int rc; + + spin_lock(&hp->lock); /* Write the proper value into the main counter */ hp->hpet.mc64 = hp->mc_offset + guest_time_hpet(hp->vcpu); /* Save the HPET registers */ - return hvm_save_entry(HPET, 0, h, &hp->hpet); + rc = hvm_save_entry(HPET, 0, h, &hp->hpet); + + spin_unlock(&hp->lock); + + return rc; } static int hpet_load(struct domain *d, hvm_domain_context_t *h) @@ -404,9 +432,14 @@ static int hpet_load(struct domain *d, hvm_domain_context_t *h) HPETState *hp = &d->arch.hvm_domain.pl_time.vhpet; int i; + spin_lock(&hp->lock); + /* Reload the HPET registers */ if ( hvm_load_entry(HPET, h, &hp->hpet) ) + { + spin_unlock(&hp->lock); return -EINVAL; + } /* Recalculate the offset between the main counter and guest time */ hp->mc_offset = hp->hpet.mc64 - guest_time_hpet(hp->vcpu); @@ -415,6 +448,8 @@ static int hpet_load(struct domain *d, hvm_domain_context_t *h) for ( i = 0; i < HPET_TIMER_NUM; i++ ) hpet_set_timer(hp, i); + spin_unlock(&hp->lock); + return 0; } @@ -427,6 +462,8 @@ void hpet_init(struct vcpu *v) memset(h, 0, sizeof(HPETState)); + spin_lock_init(&h->lock); + h->vcpu = v; h->tsc_freq = ticks_per_sec(v); |