# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1211617623 -3600
# Node ID 6c4cab061af414160b3fdafc7ca8855e3dc44af1
# Parent 30bf34f5a414d5400028ec094688be696234fcdf
hvm: Build guest timers on monotonic system time.
Move hvm platform timers from underlying physical CPU TSC to Xen
system time and ensure domain-wide monotonicity. TSC on many systems
may skew between processors leading to 'time going backwards' messages
from some guests.
Signed-off-by: Dan Magenheimer <dan.magenheimer@xxxxxxxxxx>
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
xen/arch/x86/hvm/hpet.c | 18 +++++++++---------
xen/arch/x86/hvm/hvm.c | 8 +++++---
xen/arch/x86/hvm/i8254.c | 9 +++++----
xen/arch/x86/hvm/pmtimer.c | 2 +-
xen/arch/x86/hvm/svm/svm.c | 4 ++--
xen/arch/x86/hvm/vlapic.c | 1 -
xen/arch/x86/hvm/vmx/vmx.c | 4 ++--
xen/arch/x86/hvm/vpt.c | 32 +++++++++++++++++++++++++++++++-
xen/include/asm-x86/hvm/hvm.h | 6 ++++--
xen/include/asm-x86/hvm/vcpu.h | 3 +++
xen/include/asm-x86/hvm/vmx/vmx.h | 1 -
xen/include/asm-x86/hvm/vpt.h | 7 ++++++-
xen/include/xen/time.h | 1 +
13 files changed, 69 insertions(+), 27 deletions(-)
diff -r 30bf34f5a414 -r 6c4cab061af4 xen/arch/x86/hvm/hpet.c
--- a/xen/arch/x86/hvm/hpet.c Sat May 24 08:54:59 2008 +0100
+++ b/xen/arch/x86/hvm/hpet.c Sat May 24 09:27:03 2008 +0100
@@ -29,9 +29,9 @@
#define S_TO_NS 1000000000ULL /* 1s = 10^9 ns */
#define S_TO_FS 1000000000000000ULL /* 1s = 10^15 fs */
-/* Frequency_of_TSC / frequency_of_HPET = 32 */
-#define TSC_PER_HPET_TICK 32
-#define guest_time_hpet(v) (hvm_get_guest_time(v) / TSC_PER_HPET_TICK)
+/* Frequency_of_Xen_systeme_time / frequency_of_HPET = 16 */
+#define STIME_PER_HPET_TICK 16
+#define guest_time_hpet(v) (hvm_get_guest_time(v) / STIME_PER_HPET_TICK)
#define HPET_ID 0x000
#define HPET_PERIOD 0x004
@@ -192,7 +192,7 @@ static void hpet_stop_timer(HPETState *h
/* the number of HPET tick that stands for
* 1/(2^10) second, namely, 0.9765625 milliseconds */
-#define HPET_TINY_TIME_SPAN ((h->tsc_freq >> 10) / TSC_PER_HPET_TICK)
+#define HPET_TINY_TIME_SPAN ((h->stime_freq >> 10) / STIME_PER_HPET_TICK)
static void hpet_set_timer(HPETState *h, unsigned int tn)
{
@@ -558,17 +558,17 @@ void hpet_init(struct vcpu *v)
spin_lock_init(&h->lock);
h->vcpu = v;
- h->tsc_freq = ticks_per_sec(v);
-
- h->hpet_to_ns_scale = ((S_TO_NS * TSC_PER_HPET_TICK) << 10) / h->tsc_freq;
+ h->stime_freq = S_TO_NS;
+
+ h->hpet_to_ns_scale = ((S_TO_NS * STIME_PER_HPET_TICK) << 10) /
h->stime_freq;
h->hpet_to_ns_limit = ~0ULL / h->hpet_to_ns_scale;
/* 64-bit main counter; 3 timers supported; LegacyReplacementRoute. */
h->hpet.capability = 0x8086A201ULL;
/* This is the number of femptoseconds per HPET tick. */
- /* Here we define HPET's frequency to be 1/32 of the TSC's */
- h->hpet.capability |= ((S_TO_FS*TSC_PER_HPET_TICK/h->tsc_freq) << 32);
+ /* Here we define HPET's frequency to be 1/16 of Xen system time */
+ h->hpet.capability |= ((S_TO_FS*STIME_PER_HPET_TICK/h->stime_freq) << 32);
for ( i = 0; i < HPET_TIMER_NUM; i++ )
{
diff -r 30bf34f5a414 -r 6c4cab061af4 xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c Sat May 24 08:54:59 2008 +0100
+++ b/xen/arch/x86/hvm/hvm.c Sat May 24 09:27:03 2008 +0100
@@ -296,6 +296,8 @@ int hvm_domain_initialise(struct domain
spin_lock_init(&d->arch.hvm_domain.irq_lock);
spin_lock_init(&d->arch.hvm_domain.uc_lock);
+ hvm_init_guest_time(d);
+
d->arch.hvm_domain.params[HVM_PARAM_HPET_ENABLED] = 1;
hvm_init_cacheattr_region_list(d);
@@ -661,7 +663,7 @@ int hvm_vcpu_initialise(struct vcpu *v)
hpet_init(v);
/* Init guest TSC to start from zero. */
- hvm_set_guest_time(v, 0);
+ hvm_set_guest_tsc(v, 0);
/* Can start up without SIPI-SIPI or setvcpucontext domctl. */
v->is_initialised = 1;
@@ -1632,7 +1634,7 @@ int hvm_msr_read_intercept(struct cpu_us
switch ( ecx )
{
case MSR_IA32_TSC:
- msr_content = hvm_get_guest_time(v);
+ msr_content = hvm_get_guest_tsc(v);
break;
case MSR_IA32_APICBASE:
@@ -1725,7 +1727,7 @@ int hvm_msr_write_intercept(struct cpu_u
switch ( ecx )
{
case MSR_IA32_TSC:
- hvm_set_guest_time(v, msr_content);
+ hvm_set_guest_tsc(v, msr_content);
pt_reset(v);
break;
diff -r 30bf34f5a414 -r 6c4cab061af4 xen/arch/x86/hvm/i8254.c
--- a/xen/arch/x86/hvm/i8254.c Sat May 24 08:54:59 2008 +0100
+++ b/xen/arch/x86/hvm/i8254.c Sat May 24 09:27:03 2008 +0100
@@ -31,6 +31,7 @@
#include <xen/lib.h>
#include <xen/errno.h>
#include <xen/sched.h>
+#include <asm/time.h>
#include <asm/hvm/hvm.h>
#include <asm/hvm/io.h>
#include <asm/hvm/support.h>
@@ -87,7 +88,7 @@ static int pit_get_count(PITState *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));
+ PIT_FREQ, SYSTEM_TIME_HZ);
switch ( c->mode )
{
@@ -118,7 +119,7 @@ static int pit_get_out(PITState *pit, in
ASSERT(spin_is_locked(&pit->lock));
d = muldiv64(hvm_get_guest_time(v) - pit->count_load_time[channel],
- PIT_FREQ, ticks_per_sec(v));
+ PIT_FREQ, SYSTEM_TIME_HZ);
switch ( s->mode )
{
@@ -195,11 +196,11 @@ static void pit_load_count(PITState *pit
val = 0x10000;
if ( v == NULL )
- rdtscll(pit->count_load_time[channel]);
+ pit->count_load_time[channel] = 0;
else
pit->count_load_time[channel] = hvm_get_guest_time(v);
s->count = val;
- period = DIV_ROUND((val * 1000000000ULL), PIT_FREQ);
+ period = DIV_ROUND(val * SYSTEM_TIME_HZ, PIT_FREQ);
if ( (v == NULL) || !is_hvm_vcpu(v) || (channel != 0) )
return;
diff -r 30bf34f5a414 -r 6c4cab061af4 xen/arch/x86/hvm/pmtimer.c
--- a/xen/arch/x86/hvm/pmtimer.c Sat May 24 08:54:59 2008 +0100
+++ b/xen/arch/x86/hvm/pmtimer.c Sat May 24 09:27:03 2008 +0100
@@ -257,7 +257,7 @@ void pmtimer_init(struct vcpu *v)
spin_lock_init(&s->lock);
- s->scale = ((uint64_t)FREQUENCE_PMTIMER << 32) / ticks_per_sec(v);
+ s->scale = ((uint64_t)FREQUENCE_PMTIMER << 32) / SYSTEM_TIME_HZ;
s->vcpu = v;
/* Intercept port I/O (need two handlers because PM1a_CNT is between
diff -r 30bf34f5a414 -r 6c4cab061af4 xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c Sat May 24 08:54:59 2008 +0100
+++ b/xen/arch/x86/hvm/svm/svm.c Sat May 24 09:27:03 2008 +0100
@@ -299,7 +299,7 @@ static void svm_save_cpu_state(struct vc
data->msr_efer = v->arch.hvm_vcpu.guest_efer;
data->msr_flags = -1ULL;
- data->tsc = hvm_get_guest_time(v);
+ data->tsc = hvm_get_guest_tsc(v);
}
@@ -315,7 +315,7 @@ static void svm_load_cpu_state(struct vc
v->arch.hvm_vcpu.guest_efer = data->msr_efer;
svm_update_guest_efer(v);
- hvm_set_guest_time(v, data->tsc);
+ hvm_set_guest_tsc(v, data->tsc);
}
static void svm_save_vmcb_ctxt(struct vcpu *v, struct hvm_hw_cpu *ctxt)
diff -r 30bf34f5a414 -r 6c4cab061af4 xen/arch/x86/hvm/vlapic.c
--- a/xen/arch/x86/hvm/vlapic.c Sat May 24 08:54:59 2008 +0100
+++ b/xen/arch/x86/hvm/vlapic.c Sat May 24 09:27:03 2008 +0100
@@ -473,7 +473,6 @@ static uint32_t vlapic_get_tmcct(struct
uint64_t counter_passed;
counter_passed = ((hvm_get_guest_time(v) - vlapic->timer_last_update)
- * 1000000000ULL / ticks_per_sec(v)
/ APIC_BUS_CYCLE_NS / vlapic->hw.timer_divisor);
tmcct = tmict - counter_passed;
diff -r 30bf34f5a414 -r 6c4cab061af4 xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c Sat May 24 08:54:59 2008 +0100
+++ b/xen/arch/x86/hvm/vmx/vmx.c Sat May 24 09:27:03 2008 +0100
@@ -607,7 +607,7 @@ static void vmx_save_cpu_state(struct vc
data->msr_syscall_mask = guest_state->msrs[VMX_INDEX_MSR_SYSCALL_MASK];
#endif
- data->tsc = hvm_get_guest_time(v);
+ data->tsc = hvm_get_guest_tsc(v);
}
static void vmx_load_cpu_state(struct vcpu *v, struct hvm_hw_cpu *data)
@@ -625,7 +625,7 @@ static void vmx_load_cpu_state(struct vc
v->arch.hvm_vmx.shadow_gs = data->shadow_gs;
#endif
- hvm_set_guest_time(v, data->tsc);
+ hvm_set_guest_tsc(v, data->tsc);
}
diff -r 30bf34f5a414 -r 6c4cab061af4 xen/arch/x86/hvm/vpt.c
--- a/xen/arch/x86/hvm/vpt.c Sat May 24 08:54:59 2008 +0100
+++ b/xen/arch/x86/hvm/vpt.c Sat May 24 09:27:03 2008 +0100
@@ -25,6 +25,36 @@
#define mode_is(d, name) \
((d)->arch.hvm_domain.params[HVM_PARAM_TIMER_MODE] == HVMPTM_##name)
+void hvm_init_guest_time(struct domain *d)
+{
+ struct pl_time *pl = &d->arch.hvm_domain.pl_time;
+
+ spin_lock_init(&pl->pl_time_lock);
+ pl->stime_offset = -(u64)get_s_time();
+ pl->last_guest_time = 0;
+}
+
+u64 hvm_get_guest_time(struct vcpu *v)
+{
+ struct pl_time *pl = &v->domain->arch.hvm_domain.pl_time;
+ u64 now;
+
+ spin_lock(&pl->pl_time_lock);
+ now = get_s_time() + pl->stime_offset;
+ if ( (int64_t)(now - pl->last_guest_time) >= 0 )
+ pl->last_guest_time = now;
+ else
+ now = pl->last_guest_time;
+ spin_unlock(&pl->pl_time_lock);
+
+ return now + v->arch.hvm_vcpu.stime_offset;
+}
+
+void hvm_set_guest_time(struct vcpu *v, u64 guest_time)
+{
+ v->arch.hvm_vcpu.stime_offset += guest_time - hvm_get_guest_time(v);
+}
+
static int pt_irq_vector(struct periodic_time *pt, enum hvm_intsrc src)
{
struct vcpu *v = pt->vcpu;
@@ -348,7 +378,7 @@ void create_periodic_time(
pt->vcpu = v;
pt->last_plt_gtime = hvm_get_guest_time(pt->vcpu);
pt->irq = irq;
- pt->period_cycles = (u64)period * cpu_khz / 1000000L;
+ pt->period_cycles = (u64)period;
pt->one_shot = one_shot;
pt->scheduled = NOW() + period;
/*
diff -r 30bf34f5a414 -r 6c4cab061af4 xen/include/asm-x86/hvm/hvm.h
--- a/xen/include/asm-x86/hvm/hvm.h Sat May 24 08:54:59 2008 +0100
+++ b/xen/include/asm-x86/hvm/hvm.h Sat May 24 09:27:03 2008 +0100
@@ -147,8 +147,10 @@ void hvm_send_assist_req(struct vcpu *v)
void hvm_set_guest_tsc(struct vcpu *v, u64 guest_tsc);
u64 hvm_get_guest_tsc(struct vcpu *v);
-#define hvm_set_guest_time(vcpu, gtime) hvm_set_guest_tsc(vcpu, gtime)
-#define hvm_get_guest_time(vcpu) hvm_get_guest_tsc(vcpu)
+
+void hvm_init_guest_time(struct domain *d);
+void hvm_set_guest_time(struct vcpu *v, u64 guest_time);
+u64 hvm_get_guest_time(struct vcpu *v);
#define hvm_paging_enabled(v) \
(!!((v)->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PG))
diff -r 30bf34f5a414 -r 6c4cab061af4 xen/include/asm-x86/hvm/vcpu.h
--- a/xen/include/asm-x86/hvm/vcpu.h Sat May 24 08:54:59 2008 +0100
+++ b/xen/include/asm-x86/hvm/vcpu.h Sat May 24 09:27:03 2008 +0100
@@ -68,6 +68,9 @@ struct hvm_vcpu {
struct mtrr_state mtrr;
u64 pat_cr;
+ /* In mode delay_for_missed_ticks, VCPUs have differing guest times. */
+ int64_t stime_offset;
+
/* Which cache mode is this VCPU in (CR0:CD/NW)? */
u8 cache_mode;
diff -r 30bf34f5a414 -r 6c4cab061af4 xen/include/asm-x86/hvm/vmx/vmx.h
--- a/xen/include/asm-x86/hvm/vmx/vmx.h Sat May 24 08:54:59 2008 +0100
+++ b/xen/include/asm-x86/hvm/vmx/vmx.h Sat May 24 09:27:03 2008 +0100
@@ -49,7 +49,6 @@ void vmx_asm_do_vmentry(void);
void vmx_asm_do_vmentry(void);
void vmx_intr_assist(void);
void vmx_do_resume(struct vcpu *);
-void set_guest_time(struct vcpu *v, u64 gtime);
void vmx_vlapic_msr_changed(struct vcpu *v);
void vmx_realmode(struct cpu_user_regs *regs);
diff -r 30bf34f5a414 -r 6c4cab061af4 xen/include/asm-x86/hvm/vpt.h
--- a/xen/include/asm-x86/hvm/vpt.h Sat May 24 08:54:59 2008 +0100
+++ b/xen/include/asm-x86/hvm/vpt.h Sat May 24 09:27:03 2008 +0100
@@ -57,7 +57,7 @@ typedef struct HPETState {
typedef struct HPETState {
struct hpet_registers hpet;
struct vcpu *vcpu;
- uint64_t tsc_freq;
+ uint64_t stime_freq;
uint64_t hpet_to_ns_scale; /* hpet ticks to ns (multiplied by 2^10) */
uint64_t hpet_to_ns_limit; /* max hpet ticks convertable to ns */
uint64_t mc_offset;
@@ -137,6 +137,11 @@ struct pl_time { /* platform time */
struct RTCState vrtc;
struct HPETState vhpet;
struct PMTState vpmt;
+ /* guest_time = Xen sys time + stime_offset */
+ int64_t stime_offset;
+ /* Ensures monotonicity in appropriate timer modes. */
+ uint64_t last_guest_time;
+ spinlock_t pl_time_lock;
};
#define ticks_per_sec(v) (v->domain->arch.hvm_domain.tsc_frequency)
diff -r 30bf34f5a414 -r 6c4cab061af4 xen/include/xen/time.h
--- a/xen/include/xen/time.h Sat May 24 08:54:59 2008 +0100
+++ b/xen/include/xen/time.h Sat May 24 09:27:03 2008 +0100
@@ -47,6 +47,7 @@ struct tm {
};
struct tm gmtime(unsigned long t);
+#define SYSTEM_TIME_HZ 1000000000ULL
#define NOW() ((s_time_t)get_s_time())
#define SECONDS(_s) ((s_time_t)((_s) * 1000000000ULL))
#define MILLISECS(_ms) ((s_time_t)((_ms) * 1000000ULL))
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|