|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] Big Bug:Time in VM goes slower; foud Solution but demand Judgement! A Interesting Story!
>>> On 10.08.12 at 17:17, tupeng212 <tupeng212@xxxxxxxxx> wrote:
> 2 Bug in xen
> JVM is OK, so left the bug to xen, I have found both the reason and
> solution. As Jan mentioned avoiding call create_periodic_time, it got much
> better. so I modified it like this, if the pt timer is created before,
> setting RegA down is just changing the period value, so I do nothing except
What you describe doesn't sound accurate (i.e. I'm getting the
impression that you might have suppressed the call in cases
where you shouldn't).
Below/attached a first draft of a patch to fix not only this issue,
but a few more with the RTC emulation. Would you give this a
try?
Keir, Tim, others - the change to xen/arch/x86/hvm/vpt.c really
looks more like a hack than a solution, but I don't see another
way without much more intrusive changes. The point is that we
want the RTC code to decide whether to generate an interrupt
(so that RTC_PF can become set correctly even without RTC_PIE
getting enabled by the guest).
Jan
x86/HVM: assorted RTC emulation adjustments
- don't call rtc_timer_update() on REG_A writes when the value didn't
change (doing the call always was reported to cause wall clock time
lagging with the JVM under Windows)
- in the same spirit, don't call rtc_timer_update() or
alarm_timer_update() on REG_B writes when the respective RTC_xIE bit
didn't change
- raise the RTC IRQ not only when RTC_UIE gets set while RTC_UF was
already set, but generalize this to alarm and periodic interrupts as
well
- properly handle RTC_PF when the guest is not also setting RTC_PIE
- also handle the two other clock bases
--- a/xen/arch/x86/hvm/rtc.c
+++ b/xen/arch/x86/hvm/rtc.c
@@ -50,11 +50,24 @@ static void rtc_set_time(RTCState *s);
static inline int from_bcd(RTCState *s, int a);
static inline int convert_hour(RTCState *s, int hour);
-static void rtc_periodic_cb(struct vcpu *v, void *opaque)
+static void rtc_toggle_irq(RTCState *s)
+{
+ struct domain *d = vrtc_domain(s);
+
+ ASSERT(spin_is_locked(&s->lock));
+ s->hw.cmos_data[RTC_REG_C] |= RTC_IRQF;
+ hvm_isa_irq_deassert(d, RTC_IRQ);
+ hvm_isa_irq_assert(d, RTC_IRQ);
+}
+
+void rtc_periodic_interrupt(void *opaque)
{
RTCState *s = opaque;
+
spin_lock(&s->lock);
- s->hw.cmos_data[RTC_REG_C] |= 0xc0;
+ s->hw.cmos_data[RTC_REG_C] |= RTC_PF;
+ if ( s->hw.cmos_data[RTC_REG_B] & RTC_PIE )
+ rtc_toggle_irq(s);
spin_unlock(&s->lock);
}
@@ -68,19 +81,25 @@ static void rtc_timer_update(RTCState *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) )
+ switch ( s->hw.cmos_data[RTC_REG_A] & RTC_DIV_CTL )
{
- if ( period_code <= 2 )
+ case RTC_REF_CLCK_32KHZ:
+ if ( (period_code != 0) && (period_code <= 2) )
period_code += 7;
-
- period = 1 << (period_code - 1); /* period in 32 Khz cycles */
- period = DIV_ROUND((period * 1000000000ULL), 32768); /* period in ns */
- create_periodic_time(v, &s->pt, period, period, RTC_IRQ,
- rtc_periodic_cb, s);
- }
- else
- {
+ /* fall through */
+ case RTC_REF_CLCK_1MHZ:
+ case RTC_REF_CLCK_4MHZ:
+ if ( period_code != 0 )
+ {
+ period = 1 << (period_code - 1); /* period in 32 Khz cycles */
+ period = DIV_ROUND(period * 1000000000ULL, 32768); /* in ns */
+ create_periodic_time(v, &s->pt, period, period, RTC_IRQ, NULL, s);
+ break;
+ }
+ /* fall through */
+ default:
destroy_periodic_time(&s->pt);
+ break;
}
}
@@ -144,7 +163,6 @@ static void rtc_update_timer(void *opaqu
static void rtc_update_timer2(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))
@@ -152,11 +170,7 @@ static void rtc_update_timer2(void *opaq
s->hw.cmos_data[RTC_REG_C] |= RTC_UF;
s->hw.cmos_data[RTC_REG_A] &= ~RTC_UIP;
if ((s->hw.cmos_data[RTC_REG_B] & RTC_UIE))
- {
- s->hw.cmos_data[RTC_REG_C] |= RTC_IRQF;
- hvm_isa_irq_deassert(d, RTC_IRQ);
- hvm_isa_irq_assert(d, RTC_IRQ);
- }
+ rtc_toggle_irq(s);
check_update_timer(s);
}
spin_unlock(&s->lock);
@@ -343,7 +357,6 @@ static void alarm_timer_update(RTCState
static void rtc_alarm_cb(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))
@@ -351,11 +364,7 @@ static void rtc_alarm_cb(void *opaque)
s->hw.cmos_data[RTC_REG_C] |= RTC_AF;
/* alarm interrupt */
if (s->hw.cmos_data[RTC_REG_B] & RTC_AIE)
- {
- s->hw.cmos_data[RTC_REG_C] |= RTC_IRQF;
- hvm_isa_irq_deassert(d, RTC_IRQ);
- hvm_isa_irq_assert(d, RTC_IRQ);
- }
+ rtc_toggle_irq(s);
alarm_timer_update(s);
}
spin_unlock(&s->lock);
@@ -365,6 +374,7 @@ static int rtc_ioport_write(void *opaque
{
RTCState *s = opaque;
struct domain *d = vrtc_domain(s);
+ uint32_t orig, mask;
spin_lock(&s->lock);
@@ -382,6 +392,7 @@ static int rtc_ioport_write(void *opaque
return 0;
}
+ orig = s->hw.cmos_data[s->hw.cmos_index];
switch ( s->hw.cmos_index )
{
case RTC_SECONDS_ALARM:
@@ -405,9 +416,9 @@ static int rtc_ioport_write(void *opaque
break;
case RTC_REG_A:
/* UIP bit is read only */
- s->hw.cmos_data[RTC_REG_A] = (data & ~RTC_UIP) |
- (s->hw.cmos_data[RTC_REG_A] & RTC_UIP);
- rtc_timer_update(s);
+ s->hw.cmos_data[RTC_REG_A] = (data & ~RTC_UIP) | (orig & RTC_UIP);
+ if ( (data ^ orig) & (RTC_RATE_SELECT | RTC_DIV_CTL) )
+ rtc_timer_update(s);
break;
case RTC_REG_B:
if ( data & RTC_SET )
@@ -415,7 +426,7 @@ static int rtc_ioport_write(void *opaque
/* set mode: reset UIP mode */
s->hw.cmos_data[RTC_REG_A] &= ~RTC_UIP;
/* adjust cmos before stopping */
- if (!(s->hw.cmos_data[RTC_REG_B] & RTC_SET))
+ if (!(orig & RTC_SET))
{
s->current_tm = gmtime(get_localtime(d));
rtc_copy_date(s);
@@ -424,21 +435,27 @@ static int rtc_ioport_write(void *opaque
else
{
/* if disabling set mode, update the time */
- if ( s->hw.cmos_data[RTC_REG_B] & RTC_SET )
+ if ( orig & RTC_SET )
rtc_set_time(s);
}
- /* if the interrupt is already set when the interrupt become
- * enabled, raise an interrupt immediately*/
- if ((data & RTC_UIE) && !(s->hw.cmos_data[RTC_REG_B] & RTC_UIE))
- if (s->hw.cmos_data[RTC_REG_C] & RTC_UF)
+ /*
+ * If the interrupt is already set when the interrupt becomes
+ * enabled, raise an interrupt immediately.
+ * NB: RTC_{A,P,U}IE == RTC_{A,P,U}F respectively.
+ */
+ for ( mask = RTC_UIE; mask <= RTC_PIE; mask <<= 1 )
+ if ( (data & mask) && !(orig & mask) &&
+ (s->hw.cmos_data[RTC_REG_C] & mask) )
{
- hvm_isa_irq_deassert(d, RTC_IRQ);
- hvm_isa_irq_assert(d, RTC_IRQ);
+ rtc_toggle_irq(s);
+ break;
}
s->hw.cmos_data[RTC_REG_B] = data;
- rtc_timer_update(s);
+ if ( (data ^ orig) & RTC_PIE )
+ rtc_timer_update(s);
check_update_timer(s);
- alarm_timer_update(s);
+ if ( (data ^ orig) & RTC_AIE )
+ alarm_timer_update(s);
break;
case RTC_REG_C:
case RTC_REG_D:
--- a/xen/arch/x86/hvm/vpt.c
+++ b/xen/arch/x86/hvm/vpt.c
@@ -22,6 +22,7 @@
#include <asm/hvm/vpt.h>
#include <asm/event.h>
#include <asm/apic.h>
+#include <asm/mc146818rtc.h>
#define mode_is(d, name) \
((d)->arch.hvm_domain.params[HVM_PARAM_TIMER_MODE] == HVMPTM_##name)
@@ -218,6 +219,7 @@ void pt_update_irq(struct vcpu *v)
struct periodic_time *pt, *temp, *earliest_pt = NULL;
uint64_t max_lag = -1ULL;
int irq, is_lapic;
+ void *pt_priv;
spin_lock(&v->arch.hvm_vcpu.tm_lock);
@@ -251,13 +253,14 @@ void pt_update_irq(struct vcpu *v)
earliest_pt->irq_issued = 1;
irq = earliest_pt->irq;
is_lapic = (earliest_pt->source == PTSRC_lapic);
+ pt_priv = earliest_pt->priv;
spin_unlock(&v->arch.hvm_vcpu.tm_lock);
if ( is_lapic )
- {
vlapic_set_irq(vcpu_vlapic(v), irq, 0);
- }
+ else if ( irq == RTC_IRQ )
+ rtc_periodic_interrupt(pt_priv);
else
{
hvm_isa_irq_deassert(v->domain, irq);
--- a/xen/include/asm-x86/hvm/vpt.h
+++ b/xen/include/asm-x86/hvm/vpt.h
@@ -181,6 +181,7 @@ void rtc_migrate_timers(struct vcpu *v);
void rtc_deinit(struct domain *d);
void rtc_reset(struct domain *d);
void rtc_update_clock(struct domain *d);
+void rtc_periodic_interrupt(void *);
void pmtimer_init(struct vcpu *v);
void pmtimer_deinit(struct domain *d);
Attachment:
x86-hvm-rtc.patch _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |