[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH] xen/time: fix system_time for vtsc=1 PV guests
For vtsc=1 PV guests, rdtsc is trapped and calculated from get_s_time() using gtime_to_gtsc. Similarly the tsc_timestamp, part of struct vcpu_time_info, is calculated from stime_local_stamp using gtime_to_gtsc. However gtime_to_gtsc can return 0, if time < vtsc_offset, which can actually happen when gtime_to_gtsc is called passing stime_local_stamp (the caller function is __update_vcpu_system_time). In that case the pvclock protocol doesn't work properly and the guest is unable to calculate the system time correctly. As a consequence when the guest tries to set a timer event (for example calling the VCPUOP_set_singleshot_timer hypercall), the event will be in the past causing Linux to hang. The purpose of the pvclock protocol is to allow the guest to calculate the system_time in nanosec correctly. The guest calculates as follow: from_vtsc_scale(rdtsc - vcpu_time_info.tsc_timestamp) + vcpu_time_info.system_time Given that with vtsc=1: rdtsc = to_vtsc_scale(NOW() - vtsc_offset) vcpu_time_info.tsc_timestamp = to_vtsc_scale(vcpu_time_info.system_time - vtsc_offset) The expression evaluates to NOW(), which is what we want. However when stime_local_stamp < vtsc_offset, vcpu_time_info.tsc_timestamp is actually 0, because it cannot be negative (the field is uint64_t). As a consequence the calculated overall system_time is not correct. This patch fixes the issue by passing vtsc_offset as system_time when vcpu_time_info.tsc_timestamp is 0: rdtsc = to_vtsc_scale(NOW() - vtsc_offset) vcpu_time_info.tsc_timestamp = 0 vcpu_time_info.system_time = vtsc_offset The pvclock expression evaluates to NOW(), which is what we want. Signed-off-by: Stefano Stabellini <sstabellini@xxxxxxxxxx> diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c index 687e39b..27b0e5c 100644 --- a/xen/arch/x86/time.c +++ b/xen/arch/x86/time.c @@ -784,7 +784,7 @@ static void __update_vcpu_system_time(struct vcpu *v, int force) struct cpu_time *t; struct vcpu_time_info *u, _u = {}; struct domain *d = v->domain; - s_time_t tsc_stamp; + s_time_t stime_stamp, tsc_stamp = 0; if ( v->vcpu_info == NULL ) return; @@ -792,6 +792,7 @@ static void __update_vcpu_system_time(struct vcpu *v, int force) t = &this_cpu(cpu_time); u = &vcpu_info(v, time); + stime_stamp = t->stime_local_stamp; if ( d->arch.vtsc ) { s_time_t stime = t->stime_local_stamp; @@ -807,7 +808,11 @@ static void __update_vcpu_system_time(struct vcpu *v, int force) tsc_stamp = -gtime_to_gtsc(d, -stime); } else + { tsc_stamp = gtime_to_gtsc(d, stime); + if (!tsc_stamp) + stime_stamp = d->arch.vtsc_offset; + } _u.tsc_to_system_mul = d->arch.vtsc_to_ns.mul_frac; _u.tsc_shift = d->arch.vtsc_to_ns.shift; @@ -829,7 +834,7 @@ static void __update_vcpu_system_time(struct vcpu *v, int force) } _u.tsc_timestamp = tsc_stamp; - _u.system_time = t->stime_local_stamp; + _u.system_time = stime_stamp; if ( is_hvm_domain(d) ) _u.tsc_timestamp += v->arch.hvm_vcpu.cache_tsc_offset; _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |