[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] hvm: Add locking to platform timers.
# HG changeset patch # User Keir Fraser <keir@xxxxxxxxxxxxx> # Date 1181917849 -3600 # Node ID 8ad38aaaeb89bfa67fc30ca5c4b2d3a78af219ce # Parent f1ba2e652724cb505a85eef64eaafe9774421011 hvm: Add locking to platform timers. Handy for correctness. Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx> --- xen/arch/x86/hvm/hpet.c | 43 ++++++++++++++++++-- xen/arch/x86/hvm/hvm.c | 1 xen/arch/x86/hvm/i8254.c | 87 +++++++++++++++++++++++++++++++---------- xen/arch/x86/hvm/pmtimer.c | 62 +++++++++++++++++++---------- xen/arch/x86/hvm/rtc.c | 64 +++++++++++++++++++++++++----- xen/arch/x86/hvm/vpt.c | 85 +++++++++++++++++++++++++++++++++++----- xen/common/timer.c | 2 xen/include/asm-x86/hvm/vcpu.h | 3 + xen/include/asm-x86/hvm/vpt.h | 6 +- 9 files changed, 288 insertions(+), 65 deletions(-) diff -r f1ba2e652724 -r 8ad38aaaeb89 xen/arch/x86/hvm/hpet.c --- a/xen/arch/x86/hvm/hpet.c Fri Jun 15 11:50:54 2007 +0100 +++ b/xen/arch/x86/hvm/hpet.c Fri Jun 15 15:30:49 2007 +0100 @@ -113,6 +113,8 @@ static inline int hpet_check_access_leng 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, 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; @@ -212,6 +220,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 ) @@ -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) @@ -320,6 +332,8 @@ static void hpet_route_interrupt(HPETSta { 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) ) { @@ -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) ) - return; + { + 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 @@ static int hpet_save(struct domain *d, h 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, 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, h for ( i = 0; i < HPET_TIMER_NUM; i++ ) hpet_set_timer(hp, i); + spin_unlock(&hp->lock); + return 0; } @@ -426,6 +461,8 @@ void hpet_init(struct vcpu *v) int i; memset(h, 0, sizeof(HPETState)); + + spin_lock_init(&h->lock); h->vcpu = v; h->tsc_freq = ticks_per_sec(v); diff -r f1ba2e652724 -r 8ad38aaaeb89 xen/arch/x86/hvm/hvm.c --- a/xen/arch/x86/hvm/hvm.c Fri Jun 15 11:50:54 2007 +0100 +++ b/xen/arch/x86/hvm/hvm.c Fri Jun 15 15:30:49 2007 +0100 @@ -401,6 +401,7 @@ int hvm_vcpu_initialise(struct vcpu *v) get_ioreq(v)->vp_eport = v->arch.hvm_vcpu.xen_port; spin_unlock(&v->domain->arch.hvm_domain.ioreq.lock); + spin_lock_init(&v->arch.hvm_vcpu.tm_lock); INIT_LIST_HEAD(&v->arch.hvm_vcpu.tm_list); if ( v->vcpu_id == 0 ) diff -r f1ba2e652724 -r 8ad38aaaeb89 xen/arch/x86/hvm/i8254.c --- a/xen/arch/x86/hvm/i8254.c Fri Jun 15 11:50:54 2007 +0100 +++ b/xen/arch/x86/hvm/i8254.c Fri Jun 15 15:30:49 2007 +0100 @@ -82,6 +82,8 @@ static int pit_get_count(PITState *pit, struct hvm_hw_pit_channel *c = &pit->hw.channels[channel]; struct vcpu *v = vpit_vcpu(pit); + ASSERT(spin_is_locked(&pit->lock)); + d = muldiv64(hvm_get_guest_time(v) - pit->count_load_time[channel], PIT_FREQ, ticks_per_sec(v)); @@ -111,6 +113,8 @@ static int pit_get_out(PITState *pit, in int out; struct vcpu *v = vpit_vcpu(pit); + ASSERT(spin_is_locked(&pit->lock)); + d = muldiv64(hvm_get_guest_time(v) - pit->count_load_time[channel], PIT_FREQ, ticks_per_sec(v)); @@ -142,6 +146,8 @@ static void pit_set_gate(PITState *pit, { struct hvm_hw_pit_channel *s = &pit->hw.channels[channel]; struct vcpu *v = vpit_vcpu(pit); + + ASSERT(spin_is_locked(&pit->lock)); switch ( s->mode ) { @@ -165,6 +171,7 @@ static void pit_set_gate(PITState *pit, int pit_get_gate(PITState *pit, int channel) { + ASSERT(spin_is_locked(&pit->lock)); return pit->hw.channels[channel].gate; } @@ -181,10 +188,15 @@ static void pit_load_count(PITState *pit struct periodic_time *pt = &pit->pt[channel]; struct vcpu *v = vpit_vcpu(pit); + ASSERT(spin_is_locked(&pit->lock)); + if ( val == 0 ) val = 0x10000; - pit->count_load_time[channel] = hvm_get_guest_time(pt->vcpu); + if ( v == NULL ) + rdtscll(pit->count_load_time[channel]); + else + pit->count_load_time[channel] = hvm_get_guest_time(v); s->count = val; period = DIV_ROUND((val * 1000000000ULL), PIT_FREQ); @@ -209,23 +221,29 @@ static void pit_load_count(PITState *pit } } -static void pit_latch_count(PITState *s, int channel) -{ - struct hvm_hw_pit_channel *c = &s->hw.channels[channel]; +static void pit_latch_count(PITState *pit, int channel) +{ + struct hvm_hw_pit_channel *c = &pit->hw.channels[channel]; + + ASSERT(spin_is_locked(&pit->lock)); + if ( !c->count_latched ) { - c->latched_count = pit_get_count(s, channel); + c->latched_count = pit_get_count(pit, channel); c->count_latched = c->rw_mode; } } -static void pit_latch_status(PITState *s, int channel) -{ - struct hvm_hw_pit_channel *c = &s->hw.channels[channel]; +static void pit_latch_status(PITState *pit, int channel) +{ + struct hvm_hw_pit_channel *c = &pit->hw.channels[channel]; + + ASSERT(spin_is_locked(&pit->lock)); + if ( !c->status_latched ) { /* TODO: Return NULL COUNT (bit 6). */ - c->status = ((pit_get_out(s, channel) << 7) | + c->status = ((pit_get_out(pit, channel) << 7) | (c->rw_mode << 4) | (c->mode << 1) | c->bcd); @@ -240,6 +258,8 @@ static void pit_ioport_write(struct PITS val &= 0xff; addr &= 3; + + spin_lock(&pit->lock); if ( addr == 3 ) { @@ -304,6 +324,8 @@ static void pit_ioport_write(struct PITS break; } } + + spin_unlock(&pit->lock); } static uint32_t pit_ioport_read(struct PITState *pit, uint32_t addr) @@ -313,6 +335,8 @@ static uint32_t pit_ioport_read(struct P addr &= 3; s = &pit->hw.channels[addr]; + + spin_lock(&pit->lock); if ( s->status_latched ) { @@ -364,12 +388,16 @@ static uint32_t pit_ioport_read(struct P } } + spin_unlock(&pit->lock); + return ret; } void pit_stop_channel0_irq(PITState *pit) { + spin_lock(&pit->lock); destroy_periodic_time(&pit->pt[0]); + spin_unlock(&pit->lock); } #ifdef HVM_DEBUG_SUSPEND @@ -422,11 +450,18 @@ static int pit_save(struct domain *d, hv static int pit_save(struct domain *d, hvm_domain_context_t *h) { PITState *pit = domain_vpit(d); + int rc; + + spin_lock(&pit->lock); pit_info(pit); /* Save the PIT hardware state */ - return hvm_save_entry(PIT, 0, h, &pit->hw); + rc = hvm_save_entry(PIT, 0, h, &pit->hw); + + spin_unlock(&pit->lock); + + return rc; } static int pit_load(struct domain *d, hvm_domain_context_t *h) @@ -434,9 +469,14 @@ static int pit_load(struct domain *d, hv PITState *pit = domain_vpit(d); int i; + spin_lock(&pit->lock); + /* Restore the PIT hardware state */ if ( hvm_load_entry(PIT, h, &pit->hw) ) + { + spin_unlock(&pit->lock); return 1; + } /* Recreate platform timers from hardware state. There will be some * time jitter here, but the wall-clock will have jumped massively, so @@ -448,6 +488,9 @@ static int pit_load(struct domain *d, hv } pit_info(pit); + + spin_unlock(&pit->lock); + return 0; } @@ -456,17 +499,15 @@ void pit_init(struct vcpu *v, unsigned l void pit_init(struct vcpu *v, unsigned long cpu_khz) { PITState *pit = vcpu_vpit(v); - struct periodic_time *pt; struct hvm_hw_pit_channel *s; int i; - pt = &pit->pt[0]; - pt[0].vcpu = v; - pt[1].vcpu = v; - pt[2].vcpu = v; + spin_lock_init(&pit->lock); + + /* Some sub-functions assert that they are called with the lock held. */ + spin_lock(&pit->lock); register_portio_handler(v->domain, PIT_BASE, 4, handle_pit_io); - /* register the speaker port */ register_portio_handler(v->domain, 0x61, 1, handle_speaker_io); ticks_per_sec(v) = cpu_khz * (int64_t)1000; @@ -477,6 +518,8 @@ void pit_init(struct vcpu *v, unsigned l s->gate = (i != 2); pit_load_count(pit, i, 0); } + + spin_unlock(&pit->lock); } void pit_deinit(struct domain *d) @@ -492,10 +535,10 @@ static int handle_pit_io(ioreq_t *p) if ( (p->size != 1) || p->data_is_ptr || (p->type != IOREQ_TYPE_PIO) ) { - gdprintk(XENLOG_WARNING, "HVM_PIT bad access\n"); + gdprintk(XENLOG_WARNING, "PIT bad access\n"); return 1; } - + if ( p->dir == IOREQ_WRITE ) { pit_ioport_write(vpit, p->addr, p->data); @@ -505,7 +548,7 @@ static int handle_pit_io(ioreq_t *p) if ( (p->addr & 3) != 3 ) p->data = pit_ioport_read(vpit, p->addr); else - gdprintk(XENLOG_WARNING, "HVM_PIT: read A1:A0=3!\n"); + gdprintk(XENLOG_WARNING, "PIT: read A1:A0=3!\n"); } return 1; @@ -533,14 +576,18 @@ static int handle_speaker_io(ioreq_t *p) if ( (p->size != 1) || p->data_is_ptr || (p->type != IOREQ_TYPE_PIO) ) { - gdprintk(XENLOG_WARNING, "HVM_SPEAKER bad access\n"); + gdprintk(XENLOG_WARNING, "PIT_SPEAKER bad access\n"); return 1; } + + spin_lock(&vpit->lock); if ( p->dir == IOREQ_WRITE ) speaker_ioport_write(vpit, p->addr, p->data); else p->data = speaker_ioport_read(vpit, p->addr); + + spin_unlock(&vpit->lock); return 1; } diff -r f1ba2e652724 -r 8ad38aaaeb89 xen/arch/x86/hvm/pmtimer.c --- a/xen/arch/x86/hvm/pmtimer.c Fri Jun 15 11:50:54 2007 +0100 +++ b/xen/arch/x86/hvm/pmtimer.c Fri Jun 15 15:30:49 2007 +0100 @@ -53,6 +53,8 @@ /* Dispatch SCIs based on the PM1a_STS and PM1a_EN registers */ static void pmt_update_sci(PMTState *s) { + ASSERT(spin_is_locked(&s->lock)); + if ( s->pm.pm1a_en & s->pm.pm1a_sts & SCI_MASK ) hvm_isa_irq_assert(s->vcpu->domain, SCI_IRQ); else @@ -66,6 +68,8 @@ static void pmt_update_time(PMTState *s) uint64_t curr_gtime; uint32_t msb = s->pm.tmr_val & TMR_VAL_MSB; + ASSERT(spin_is_locked(&s->lock)); + /* Update the timer */ curr_gtime = hvm_get_guest_time(s->vcpu); s->pm.tmr_val += ((curr_gtime - s->last_gtime) * s->scale) >> 32; @@ -89,6 +93,8 @@ static void pmt_timer_callback(void *opa uint32_t pmt_cycles_until_flip; uint64_t time_until_flip; + spin_lock(&s->lock); + /* Recalculate the timer and make sure we get an SCI if we need one */ pmt_update_time(s); @@ -103,8 +109,9 @@ static void pmt_timer_callback(void *opa /* Wake up again near the next bit-flip */ set_timer(&s->timer, NOW() + time_until_flip + MILLISECS(1)); -} - + + spin_unlock(&s->lock); +} /* Handle port I/O to the PM1a_STS and PM1a_EN registers */ static int handle_evt_io(ioreq_t *p) @@ -114,7 +121,9 @@ static int handle_evt_io(ioreq_t *p) uint32_t addr, data, byte; int i; - if ( p->dir == 0 ) /* Write */ + spin_lock(&s->lock); + + if ( p->dir == IOREQ_WRITE ) { /* Handle this I/O one byte at a time */ for ( i = p->size, addr = p->addr, data = p->data; @@ -122,7 +131,7 @@ static int handle_evt_io(ioreq_t *p) i--, addr++, data >>= 8 ) { byte = data & 0xff; - switch(addr) + switch ( addr ) { /* PM1a_STS register bits are write-to-clear */ case PM1a_STS_ADDR: @@ -149,7 +158,7 @@ static int handle_evt_io(ioreq_t *p) /* Fix up the SCI state to match the new register state */ pmt_update_sci(s); } - else /* Read */ + else /* p->dir == IOREQ_READ */ { data = s->pm.pm1a_sts | (((uint32_t) s->pm.pm1a_en) << 16); data >>= 8 * (p->addr - PM1a_STS_ADDR); @@ -157,6 +166,9 @@ static int handle_evt_io(ioreq_t *p) else if ( p->size == 2 ) data &= 0xffff; p->data = data; } + + spin_unlock(&s->lock); + return 1; } @@ -167,29 +179,31 @@ static int handle_pmt_io(ioreq_t *p) struct vcpu *v = current; PMTState *s = &v->domain->arch.hvm_domain.pl_time.vpmt; - if (p->size != 4 || - p->data_is_ptr || - p->type != IOREQ_TYPE_PIO){ - printk("HVM_PMT: wrong PM timer IO\n"); + if ( (p->size != 4) || p->data_is_ptr || (p->type != IOREQ_TYPE_PIO) ) + { + gdprintk(XENLOG_WARNING, "HVM_PMT bad access\n"); return 1; } - if (p->dir == 0) { /* write */ - /* PM_TMR_BLK is read-only */ - return 1; - } else if (p->dir == 1) { /* read */ + if ( p->dir == IOREQ_READ ) + { + spin_lock(&s->lock); pmt_update_time(s); p->data = s->pm.tmr_val; + spin_unlock(&s->lock); return 1; } + return 0; } static int pmtimer_save(struct domain *d, hvm_domain_context_t *h) { PMTState *s = &d->arch.hvm_domain.pl_time.vpmt; - uint32_t msb = s->pm.tmr_val & TMR_VAL_MSB; - uint32_t x; + uint32_t x, msb = s->pm.tmr_val & TMR_VAL_MSB; + int rc; + + spin_lock(&s->lock); /* Update the counter to the guest's current time. We always save * with the domain paused, so the saved time should be after the @@ -202,22 +216,33 @@ static int pmtimer_save(struct domain *d /* No point in setting the SCI here because we'll already have saved the * IRQ and *PIC state; we'll fix it up when we restore the domain */ - return hvm_save_entry(PMTIMER, 0, h, &s->pm); + rc = hvm_save_entry(PMTIMER, 0, h, &s->pm); + + spin_unlock(&s->lock); + + return rc; } static int pmtimer_load(struct domain *d, hvm_domain_context_t *h) { PMTState *s = &d->arch.hvm_domain.pl_time.vpmt; + + spin_lock(&s->lock); /* Reload the registers */ if ( hvm_load_entry(PMTIMER, h, &s->pm) ) + { + spin_unlock(&s->lock); return -EINVAL; + } /* Calculate future counter values from now. */ s->last_gtime = hvm_get_guest_time(s->vcpu); /* Set the SCI state from the registers */ pmt_update_sci(s); + + spin_unlock(&s->lock); return 0; } @@ -225,14 +250,11 @@ HVM_REGISTER_SAVE_RESTORE(PMTIMER, pmtim HVM_REGISTER_SAVE_RESTORE(PMTIMER, pmtimer_save, pmtimer_load, 1, HVMSR_PER_DOM); - void pmtimer_init(struct vcpu *v) { PMTState *s = &v->domain->arch.hvm_domain.pl_time.vpmt; - s->pm.tmr_val = 0; - s->pm.pm1a_sts = 0; - s->pm.pm1a_en = 0; + spin_lock_init(&s->lock); s->scale = ((uint64_t)FREQUENCE_PMTIMER << 32) / ticks_per_sec(v); s->vcpu = v; diff -r f1ba2e652724 -r 8ad38aaaeb89 xen/arch/x86/hvm/rtc.c --- a/xen/arch/x86/hvm/rtc.c Fri Jun 15 11:50:54 2007 +0100 +++ b/xen/arch/x86/hvm/rtc.c Fri Jun 15 15:30:49 2007 +0100 @@ -34,10 +34,12 @@ arch.hvm_domain.pl_time.vrtc)) #define vrtc_vcpu(rtc) (vrtc_domain(rtc)->vcpu[0]) -void rtc_periodic_cb(struct vcpu *v, void *opaque) +static void rtc_periodic_cb(struct vcpu *v, void *opaque) { RTCState *s = opaque; + spin_lock(&s->lock); s->hw.cmos_data[RTC_REG_C] |= 0xc0; + spin_unlock(&s->lock); } int is_rtc_periodic_irq(void *opaque) @@ -54,6 +56,8 @@ static void rtc_timer_update(RTCState *s { int period_code, period; struct vcpu *v = vrtc_vcpu(s); + + ASSERT(spin_is_locked(&s->lock)); period_code = s->hw.cmos_data[RTC_REG_A] & RTC_RATE_SELECT; if ( (period_code != 0) && (s->hw.cmos_data[RTC_REG_B] & RTC_PIE) ) @@ -78,14 +82,21 @@ static int rtc_ioport_write(void *opaque { RTCState *s = opaque; + spin_lock(&s->lock); + if ( (addr & 1) == 0 ) { - s->hw.cmos_index = data & 0x7f; - return (s->hw.cmos_index < RTC_CMOS_SIZE); + data &= 0x7f; + s->hw.cmos_index = data; + spin_unlock(&s->lock); + return (data < RTC_CMOS_SIZE); } if ( s->hw.cmos_index >= RTC_CMOS_SIZE ) + { + spin_unlock(&s->lock); return 0; + } switch ( s->hw.cmos_index ) { @@ -134,6 +145,8 @@ static int rtc_ioport_write(void *opaque break; } + spin_unlock(&s->lock); + return 1; } @@ -158,6 +171,8 @@ static void rtc_set_time(RTCState *s) struct tm *tm = &s->current_tm; unsigned long before, after; /* XXX s_time_t */ + ASSERT(spin_is_locked(&s->lock)); + before = mktime(tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); @@ -182,6 +197,8 @@ static void rtc_copy_date(RTCState *s) const struct tm *tm = &s->current_tm; struct domain *d = vrtc_domain(s); + ASSERT(spin_is_locked(&s->lock)); + if ( s->time_offset_seconds != d->time_offset_seconds ) { s->current_tm = gmtime(get_localtime(d)); @@ -230,6 +247,8 @@ static void rtc_next_second(RTCState *s) struct tm *tm = &s->current_tm; int days_in_month; struct domain *d = vrtc_domain(s); + + ASSERT(spin_is_locked(&s->lock)); if ( s->time_offset_seconds != d->time_offset_seconds ) { @@ -279,6 +298,8 @@ static void rtc_update_second(void *opaq { RTCState *s = opaque; + spin_lock(&s->lock); + /* if the oscillator is not in normal operation, we do not update */ if ( (s->hw.cmos_data[RTC_REG_A] & RTC_DIV_CTL) != RTC_REF_CLCK_32KHZ ) { @@ -295,12 +316,16 @@ static void rtc_update_second(void *opaq /* Delay time before update cycle */ set_timer(&s->second_timer2, s->next_second_time + 244000); } + + spin_unlock(&s->lock); } static void rtc_update_second2(void *opaque) { RTCState *s = opaque; struct domain *d = vrtc_domain(s); + + spin_lock(&s->lock); if ( !(s->hw.cmos_data[RTC_REG_B] & RTC_SET) ) rtc_copy_date(s); @@ -337,15 +362,18 @@ static void rtc_update_second2(void *opa s->next_second_time += 1000000000ULL; set_timer(&s->second_timer, s->next_second_time); -} - -static uint32_t rtc_ioport_read(void *opaque, uint32_t addr) -{ - RTCState *s = opaque; + + spin_unlock(&s->lock); +} + +static uint32_t rtc_ioport_read(RTCState *s, uint32_t addr) +{ int ret; if ( (addr & 1) == 0 ) return 0xff; + + spin_lock(&s->lock); switch ( s->hw.cmos_index ) { @@ -371,6 +399,8 @@ static uint32_t rtc_ioport_read(void *op break; } + spin_unlock(&s->lock); + return ret; } @@ -413,7 +443,11 @@ static int rtc_save(struct domain *d, hv static int rtc_save(struct domain *d, hvm_domain_context_t *h) { RTCState *s = domain_vrtc(d); - return hvm_save_entry(RTC, 0, h, &s->hw); + int rc; + spin_lock(&s->lock); + rc = hvm_save_entry(RTC, 0, h, &s->hw); + spin_unlock(&s->lock); + return rc; } /* Reload the hardware state from a saved domain */ @@ -421,9 +455,14 @@ static int rtc_load(struct domain *d, hv { RTCState *s = domain_vrtc(d); + spin_lock(&s->lock); + /* Restore the registers */ if ( hvm_load_entry(RTC, h, &s->hw) != 0 ) + { + spin_unlock(&s->lock); return -EINVAL; + } /* Reset the wall-clock time. In normal running, this runs with host * time, so let's keep doing that. */ @@ -436,6 +475,8 @@ static int rtc_load(struct domain *d, hv /* Reset the periodic interrupt timer based on the registers */ rtc_timer_update(s); + spin_unlock(&s->lock); + return 0; } @@ -445,6 +486,8 @@ void rtc_init(struct vcpu *v, int base) void rtc_init(struct vcpu *v, int base) { RTCState *s = vcpu_vrtc(v); + + spin_lock_init(&s->lock); s->hw.cmos_data[RTC_REG_A] = RTC_REF_CLCK_32KHZ | 6; /* ~1kHz */ s->hw.cmos_data[RTC_REG_B] = RTC_24H; @@ -452,7 +495,10 @@ void rtc_init(struct vcpu *v, int base) s->hw.cmos_data[RTC_REG_D] = RTC_VRT; s->current_tm = gmtime(get_localtime(v->domain)); + + spin_lock(&s->lock); rtc_copy_date(s); + spin_unlock(&s->lock); init_timer(&s->second_timer, rtc_update_second, s, v->processor); init_timer(&s->second_timer2, rtc_update_second2, s, v->processor); diff -r f1ba2e652724 -r 8ad38aaaeb89 xen/arch/x86/hvm/vpt.c --- a/xen/arch/x86/hvm/vpt.c Fri Jun 15 11:50:54 2007 +0100 +++ b/xen/arch/x86/hvm/vpt.c Fri Jun 15 15:30:49 2007 +0100 @@ -17,11 +17,31 @@ * Place - Suite 330, Boston, MA 02111-1307 USA. * */ + #include <xen/time.h> #include <asm/hvm/support.h> #include <asm/hvm/vpt.h> #include <asm/event.h> +static void pt_lock(struct periodic_time *pt) +{ + struct vcpu *v; + + for ( ; ; ) + { + v = pt->vcpu; + spin_lock(&v->arch.hvm_vcpu.tm_lock); + if ( likely(pt->vcpu == v) ) + break; + spin_unlock(&v->arch.hvm_vcpu.tm_lock); + } +} + +static void pt_unlock(struct periodic_time *pt) +{ + spin_unlock(&pt->vcpu->arch.hvm_vcpu.tm_lock); +} + static void missed_ticks(struct periodic_time *pt) { s_time_t missed_ticks; @@ -52,16 +72,22 @@ void pt_freeze_time(struct vcpu *v) if ( test_bit(_VPF_blocked, &v->pause_flags) ) return; + spin_lock(&v->arch.hvm_vcpu.tm_lock); + v->arch.hvm_vcpu.guest_time = hvm_get_guest_time(v); list_for_each_entry ( pt, head, list ) stop_timer(&pt->timer); + + spin_unlock(&v->arch.hvm_vcpu.tm_lock); } void pt_thaw_time(struct vcpu *v) { struct list_head *head = &v->arch.hvm_vcpu.tm_list; struct periodic_time *pt; + + spin_lock(&v->arch.hvm_vcpu.tm_lock); if ( v->arch.hvm_vcpu.guest_time ) { @@ -74,11 +100,15 @@ void pt_thaw_time(struct vcpu *v) set_timer(&pt->timer, pt->scheduled); } } + + spin_unlock(&v->arch.hvm_vcpu.tm_lock); } static void pt_timer_fn(void *data) { struct periodic_time *pt = data; + + pt_lock(pt); pt->pending_intr_nr++; pt->scheduled += pt->period; @@ -89,6 +119,8 @@ static void pt_timer_fn(void *data) set_timer(&pt->timer, pt->scheduled); vcpu_kick(pt->vcpu); + + pt_unlock(pt); } void pt_update_irq(struct vcpu *v) @@ -98,6 +130,8 @@ void pt_update_irq(struct vcpu *v) uint64_t max_lag = -1ULL; int irq = -1; + spin_lock(&v->arch.hvm_vcpu.tm_lock); + list_for_each_entry ( pt, head, list ) { if ( !is_isa_irq_masked(v, pt->irq) && pt->pending_intr_nr && @@ -108,6 +142,8 @@ void pt_update_irq(struct vcpu *v) } } + spin_unlock(&v->arch.hvm_vcpu.tm_lock); + if ( is_lvtt(v, irq) ) { vlapic_set_irq(vcpu_vlapic(v), irq, 0); @@ -119,7 +155,7 @@ void pt_update_irq(struct vcpu *v) } } -struct periodic_time *is_pt_irq(struct vcpu *v, int vector, int type) +static struct periodic_time *is_pt_irq(struct vcpu *v, int vector, int type) { struct list_head *head = &v->arch.hvm_vcpu.tm_list; struct periodic_time *pt; @@ -152,25 +188,42 @@ struct periodic_time *is_pt_irq(struct v void pt_intr_post(struct vcpu *v, int vector, int type) { - struct periodic_time *pt = is_pt_irq(v, vector, type); - + struct periodic_time *pt; + time_cb *cb; + void *cb_priv; + + spin_lock(&v->arch.hvm_vcpu.tm_lock); + + pt = is_pt_irq(v, vector, type); if ( pt == NULL ) - return; + { + spin_unlock(&v->arch.hvm_vcpu.tm_lock); + return; + } + + ASSERT(pt->vcpu == v); pt->pending_intr_nr--; pt->last_plt_gtime += pt->period_cycles; - if ( hvm_get_guest_time(pt->vcpu) < pt->last_plt_gtime ) - hvm_set_guest_time(pt->vcpu, pt->last_plt_gtime); - - if ( pt->cb != NULL ) - pt->cb(pt->vcpu, pt->priv); + if ( hvm_get_guest_time(v) < pt->last_plt_gtime ) + hvm_set_guest_time(v, pt->last_plt_gtime); + + cb = pt->cb; + cb_priv = pt->priv; + + spin_unlock(&v->arch.hvm_vcpu.tm_lock); + + if ( cb != NULL ) + cb(v, cb_priv); } void pt_reset(struct vcpu *v) { struct list_head *head = &v->arch.hvm_vcpu.tm_list; struct periodic_time *pt; + + spin_lock(&v->arch.hvm_vcpu.tm_lock); list_for_each_entry ( pt, head, list ) { @@ -182,18 +235,24 @@ void pt_reset(struct vcpu *v) set_timer(&pt->timer, pt->scheduled); } } + + spin_unlock(&v->arch.hvm_vcpu.tm_lock); } void pt_migrate(struct vcpu *v) { struct list_head *head = &v->arch.hvm_vcpu.tm_list; struct periodic_time *pt; + + spin_lock(&v->arch.hvm_vcpu.tm_lock); list_for_each_entry ( pt, head, list ) { if ( pt->enabled ) migrate_timer(&pt->timer, v->processor); } + + spin_unlock(&v->arch.hvm_vcpu.tm_lock); } void create_periodic_time( @@ -201,6 +260,8 @@ void create_periodic_time( uint8_t irq, char one_shot, time_cb *cb, void *data) { destroy_periodic_time(pt); + + spin_lock(&v->arch.hvm_vcpu.tm_lock); init_timer(&pt->timer, pt_timer_fn, pt, v->processor); pt->enabled = 1; @@ -223,6 +284,8 @@ void create_periodic_time( list_add(&pt->list, &v->arch.hvm_vcpu.tm_list); set_timer(&pt->timer, pt->scheduled); + + spin_unlock(&v->arch.hvm_vcpu.tm_lock); } void destroy_periodic_time(struct periodic_time *pt) @@ -230,8 +293,10 @@ void destroy_periodic_time(struct period if ( !pt->enabled ) return; + pt_lock(pt); pt->enabled = 0; pt->pending_intr_nr = 0; list_del(&pt->list); kill_timer(&pt->timer); -} + pt_unlock(pt); +} diff -r f1ba2e652724 -r 8ad38aaaeb89 xen/common/timer.c --- a/xen/common/timer.c Fri Jun 15 11:50:54 2007 +0100 +++ b/xen/common/timer.c Fri Jun 15 15:30:49 2007 +0100 @@ -183,7 +183,7 @@ static inline void timer_lock(struct tim static inline void timer_unlock(struct timer *timer) { - spin_unlock(&per_cpu(timers, timer->cpu).lock); + spin_unlock(&per_cpu(timers, timer->cpu).lock); } #define timer_unlock_irq(t) \ diff -r f1ba2e652724 -r 8ad38aaaeb89 xen/include/asm-x86/hvm/vcpu.h --- a/xen/include/asm-x86/hvm/vcpu.h Fri Jun 15 11:50:54 2007 +0100 +++ b/xen/include/asm-x86/hvm/vcpu.h Fri Jun 15 15:30:49 2007 +0100 @@ -35,6 +35,9 @@ struct hvm_vcpu { struct vlapic vlapic; s64 cache_tsc_offset; u64 guest_time; + + /* Lock and list for virtual platform timers. */ + spinlock_t tm_lock; struct list_head tm_list; /* For AP startup */ diff -r f1ba2e652724 -r 8ad38aaaeb89 xen/include/asm-x86/hvm/vpt.h --- a/xen/include/asm-x86/hvm/vpt.h Fri Jun 15 11:50:54 2007 +0100 +++ b/xen/include/asm-x86/hvm/vpt.h Fri Jun 15 15:30:49 2007 +0100 @@ -31,7 +31,6 @@ #include <asm/hvm/vpic.h> #include <public/hvm/save.h> - struct HPETState; struct HPET_timer_fn_info { struct HPETState *hs; @@ -45,6 +44,7 @@ typedef struct HPETState { uint64_t mc_offset; struct timer timers[HPET_TIMER_NUM]; struct HPET_timer_fn_info timer_fn_info[HPET_TIMER_NUM]; + spinlock_t lock; } HPETState; @@ -80,6 +80,7 @@ typedef struct PITState { int64_t count_load_time[3]; /* irq handling */ struct periodic_time pt[3]; + spinlock_t lock; } PITState; typedef struct RTCState { @@ -93,6 +94,7 @@ typedef struct RTCState { struct timer second_timer2; struct periodic_time pt; int32_t time_offset_seconds; + spinlock_t lock; } RTCState; #define FREQUENCE_PMTIMER 3579545 /* Timer should run at 3.579545 MHz */ @@ -102,6 +104,7 @@ typedef struct PMTState { uint64_t last_gtime; /* Last (guest) time we updated the timer */ uint64_t scale; /* Multiplier to get from tsc to timer ticks */ struct timer timer; /* To make sure we send SCIs */ + spinlock_t lock; } PMTState; struct pl_time { /* platform time */ @@ -116,7 +119,6 @@ void pt_freeze_time(struct vcpu *v); void pt_freeze_time(struct vcpu *v); void pt_thaw_time(struct vcpu *v); void pt_update_irq(struct vcpu *v); -struct periodic_time *is_pt_irq(struct vcpu *v, int vector, int type); void pt_intr_post(struct vcpu *v, int vector, int type); void pt_reset(struct vcpu *v); void pt_migrate(struct vcpu *v); _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |