[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] Fix both Xen and XenLinux to correctly handle 64-bit



# 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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.