# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID 6fc0b68b0a9ca2ab6164ee02db7fcf70905665f0
# Parent a9ee400a5da98acc8da566a24ecae05902b2bed2
Fix both Xen and XenLinux to correctly handle 64-bit
time deltas. Good for robustness and future-proofing.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
diff -r a9ee400a5da9 -r 6fc0b68b0a9c
linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c
--- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c Mon Aug 8 09:13:19 2005
+++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c Mon Aug 8 10:59:22 2005
@@ -166,25 +166,34 @@
.delay = delay_tsc,
};
-static inline u32 down_shift(u64 time, int shift)
-{
+/*
+ * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
+ * yielding a 64-bit result.
+ */
+static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift)
+{
+ u64 product;
+ u32 tmp;
+
if ( shift < 0 )
- return (u32)(time >> -shift);
- return (u32)((u32)time << shift);
-}
-
-/*
- * 32-bit multiplication of integer multiplicand and fractional multiplier
- * yielding 32-bit integer product.
- */
-static inline u32 mul_frac(u32 multiplicand, u32 multiplier)
-{
- u32 product_int, product_frac;
+ delta >>= -shift;
+ else
+ delta <<= shift;
+
__asm__ (
- "mul %3"
- : "=a" (product_frac), "=d" (product_int)
- : "0" (multiplicand), "r" (multiplier) );
- return product_int;
+ "pushl %%edx ; "
+ "mull %3 ; "
+ "popl %%eax ; "
+ "pushl %%edx ; "
+ "mull %3 ; "
+ "popl %3 ; "
+ "addl %3,%%eax ; "
+ "xorl %3,%3 ; "
+ "adcl %3,%%edx ; "
+ : "=A" (product), "=r" (tmp)
+ : "A" (delta), "1" (mul_frac) );
+
+ return product;
}
void init_cpu_khz(void)
@@ -192,27 +201,28 @@
u64 __cpu_khz = 1000000ULL << 32;
struct vcpu_time_info *info = &HYPERVISOR_shared_info->vcpu_time[0];
do_div(__cpu_khz, info->tsc_to_system_mul);
- cpu_khz = down_shift(__cpu_khz, -info->tsc_shift);
+ if ( info->tsc_shift < 0 )
+ cpu_khz = __cpu_khz >> -info->tsc_shift;
+ else
+ cpu_khz = __cpu_khz << info->tsc_shift;
printk(KERN_INFO "Xen reported: %lu.%03lu MHz processor.\n",
cpu_khz / 1000, cpu_khz % 1000);
}
static u64 get_nsec_offset(struct shadow_time_info *shadow)
{
- u64 now;
- u32 delta;
+ u64 now, delta;
rdtscll(now);
- delta = down_shift(now - shadow->tsc_timestamp, shadow->tsc_shift);
- return mul_frac(delta, shadow->tsc_to_nsec_mul);
+ delta = now - shadow->tsc_timestamp;
+ return scale_delta(delta, shadow->tsc_to_nsec_mul, shadow->tsc_shift);
}
static unsigned long get_usec_offset(struct shadow_time_info *shadow)
{
- u64 now;
- u32 delta;
+ u64 now, delta;
rdtscll(now);
- delta = down_shift(now - shadow->tsc_timestamp, shadow->tsc_shift);
- return mul_frac(delta, shadow->tsc_to_usec_mul);
+ delta = now - shadow->tsc_timestamp;
+ return scale_delta(delta, shadow->tsc_to_usec_mul, shadow->tsc_shift);
}
static void update_wallclock(void)
diff -r a9ee400a5da9 -r 6fc0b68b0a9c xen/arch/x86/time.c
--- a/xen/arch/x86/time.c Mon Aug 8 09:13:19 2005
+++ b/xen/arch/x86/time.c Mon Aug 8 10:59:22 2005
@@ -67,13 +67,6 @@
static spinlock_t platform_timer_lock = SPIN_LOCK_UNLOCKED;
static u64 (*read_platform_count)(void);
-static inline u32 down_shift(u64 time, int shift)
-{
- if ( shift < 0 )
- return (u32)(time >> -shift);
- return (u32)((u32)time << shift);
-}
-
/*
* 32-bit division of integer dividend and integer divisor yielding
* 32-bit fractional quotient.
@@ -83,7 +76,7 @@
u32 quotient, remainder;
ASSERT(dividend < divisor);
__asm__ (
- "div %4"
+ "divl %4"
: "=a" (quotient), "=d" (remainder)
: "0" (0), "1" (dividend), "r" (divisor) );
return quotient;
@@ -101,6 +94,36 @@
: "=a" (product_frac), "=d" (product_int)
: "0" (multiplicand), "r" (multiplier) );
return product_int;
+}
+
+/*
+ * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
+ * yielding a 64-bit result.
+ */
+static inline u64 scale_delta(u64 delta, struct time_scale *scale)
+{
+ u64 product;
+ u32 tmp;
+
+ if ( scale->shift < 0 )
+ delta >>= -scale->shift;
+ else
+ delta <<= scale->shift;
+
+ __asm__ (
+ "pushl %%edx ; "
+ "mull %3 ; "
+ "popl %%eax ; "
+ "pushl %%edx ; "
+ "mull %3 ; "
+ "popl %3 ; "
+ "addl %3,%%eax ; "
+ "xorl %3,%3 ; "
+ "adcl %3,%%edx ; "
+ : "=A" (product), "=r" (tmp)
+ : "A" (delta), "1" (scale->mul_frac) );
+
+ return product;
}
void timer_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs)
@@ -486,11 +509,9 @@
static s_time_t __read_platform_stime(u64 platform_time)
{
- u64 diff64 = platform_time - platform_timer_stamp;
- u32 diff = down_shift(diff64, platform_timer_scale.shift);
+ u64 diff = platform_time - platform_timer_stamp;
ASSERT(spin_is_locked(&platform_timer_lock));
- return (stime_platform_stamp +
- (u64)mul_frac(diff, platform_timer_scale.mul_frac));
+ return (stime_platform_stamp + scale_delta(diff, &platform_timer_scale));
}
static s_time_t read_platform_stime(void)
@@ -619,13 +640,12 @@
s_time_t get_s_time(void)
{
struct cpu_time *t = &cpu_time[smp_processor_id()];
- u64 tsc;
- u32 delta;
+ u64 tsc, delta;
s_time_t now;
rdtscll(tsc);
- delta = down_shift(tsc - t->local_tsc_stamp, t->tsc_scale.shift);
- now = t->stime_local_stamp + (u64)mul_frac(delta, t->tsc_scale.mul_frac);
+ delta = tsc - t->local_tsc_stamp;
+ now = t->stime_local_stamp + scale_delta(delta, &t->tsc_scale);
return now;
}
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|