aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>2005-08-12 13:06:23 +0000
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>2005-08-12 13:06:23 +0000
commit12313bf29fc0088ea31eb65dcdd5af4e4851b03a (patch)
treede1817eabbd1fb9d2d7c8bb44b44633e0e43747d
parent31f1ce4923d87282875dc0df2d8d2c649fa87911 (diff)
downloadxen-12313bf29fc0088ea31eb65dcdd5af4e4851b03a.tar.gz
xen-12313bf29fc0088ea31eb65dcdd5af4e4851b03a.tar.bz2
xen-12313bf29fc0088ea31eb65dcdd5af4e4851b03a.zip
Fix wallclock time when the offset relative to the epoch
(1 Jan 1970 00:00:00) is negative. This happens in some LTP tests, for example. Signed-off-by: Keir Fraser <keir@xensource.com>
-rw-r--r--linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c26
-rw-r--r--xen/arch/ia64/xentime.c2
-rw-r--r--xen/arch/x86/time.c38
-rw-r--r--xen/include/public/dom0_ops.h3
-rw-r--r--xen/include/public/xen.h7
-rw-r--r--xen/include/xen/time.h3
6 files changed, 56 insertions, 23 deletions
diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c b/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c
index 6b2fe1ccc5..536a8cc065 100644
--- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c
+++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c
@@ -231,18 +231,32 @@ static void __update_wallclock(time_t sec, long nsec)
{
long wtm_nsec, xtime_nsec;
time_t wtm_sec, xtime_sec;
- u64 tmp, wc_nsec;
+ s64 tmp, wc_nsec;
/* Adjust wall-clock time base based on wall_jiffies ticks. */
wc_nsec = processed_system_time;
- wc_nsec += (u64)sec * 1000000000ULL;
- wc_nsec += (u64)nsec;
+ wc_nsec += (sec * 1000000000LL) + nsec;
wc_nsec -= (jiffies - wall_jiffies) * (u64)(NSEC_PER_SEC / HZ);
/* Split wallclock base into seconds and nanoseconds. */
- tmp = wc_nsec;
- xtime_nsec = do_div(tmp, 1000000000);
- xtime_sec = (time_t)tmp;
+ if ( (tmp = wc_nsec) < 0 )
+ {
+ /* -ve UTC offset => -ve seconds, +ve nanoseconds. */
+ tmp = -tmp;
+ xtime_nsec = do_div(tmp, 1000000000);
+ tmp = -tmp;
+ if ( xtime_nsec != 0 )
+ {
+ xtime_nsec = 1000000000 - xtime_nsec;
+ tmp--;
+ }
+ }
+ else
+ {
+ /* +ve UTC offset => +ve seconds, +ve nanoseconds. */
+ xtime_nsec = do_div(tmp, 1000000000);
+ }
+ xtime_sec = (time_t)tmp;
wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - xtime_sec);
wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - xtime_nsec);
diff --git a/xen/arch/ia64/xentime.c b/xen/arch/ia64/xentime.c
index 25b220cbf9..f071136d5d 100644
--- a/xen/arch/ia64/xentime.c
+++ b/xen/arch/ia64/xentime.c
@@ -103,7 +103,7 @@ void update_dom_time(struct vcpu *v)
}
/* Set clock to <secs,usecs> after 00:00:00 UTC, 1 January, 1970. */
-void do_settime(unsigned long secs, unsigned long nsecs, u64 system_time_base)
+void do_settime(s64 secs, u32 nsecs, u64 system_time_base)
{
#ifdef CONFIG_VTI
u64 _nsecs;
diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c
index 81100e7a1c..6ca998bdb8 100644
--- a/xen/arch/x86/time.c
+++ b/xen/arch/x86/time.c
@@ -43,7 +43,10 @@ unsigned long hpet_address;
spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
int timer_ack = 0;
unsigned long volatile jiffies;
-static u32 wc_sec, wc_nsec; /* UTC time at last 'time update'. */
+
+/* UTC time at system boot. */
+static s64 wc_sec;
+static u32 wc_nsec;
static spinlock_t wc_lock = SPIN_LOCK_UNLOCKED;
struct time_scale {
@@ -693,18 +696,33 @@ void update_dom_time(struct vcpu *v)
}
/* Set clock to <secs,usecs> after 00:00:00 UTC, 1 January, 1970. */
-void do_settime(unsigned long secs, unsigned long nsecs, u64 system_time_base)
+void do_settime(s64 secs, u32 nsecs, u64 system_time_base)
{
- u64 x;
- u32 y, _wc_sec, _wc_nsec;
+ s64 x;
+ u32 y;
struct domain *d;
shared_info_t *s;
- x = (secs * 1000000000ULL) + (u64)nsecs - system_time_base;
- y = do_div(x, 1000000000);
+ x = (secs * 1000000000LL) + (u64)nsecs - system_time_base;
+ if ( x < 0 )
+ {
+ /* -ve UTC offset => -ve seconds, +ve nanoseconds. */
+ x = -x;
+ y = do_div(x, 1000000000);
+ x = -x;
+ if ( y != 0 )
+ {
+ y = 1000000000 - y;
+ x--;
+ }
+ }
+ else
+ {
+ y = do_div(x, 1000000000);
+ }
- wc_sec = _wc_sec = (u32)x;
- wc_nsec = _wc_nsec = (u32)y;
+ wc_sec = x;
+ wc_nsec = y;
read_lock(&domlist_lock);
spin_lock(&wc_lock);
@@ -713,8 +731,8 @@ void do_settime(unsigned long secs, unsigned long nsecs, u64 system_time_base)
{
s = d->shared_info;
version_update_begin(&s->wc_version);
- s->wc_sec = _wc_sec;
- s->wc_nsec = _wc_nsec;
+ s->wc_sec = x;
+ s->wc_nsec = y;
version_update_end(&s->wc_version);
}
diff --git a/xen/include/public/dom0_ops.h b/xen/include/public/dom0_ops.h
index 6f8cb22cac..ea1221cdaf 100644
--- a/xen/include/public/dom0_ops.h
+++ b/xen/include/public/dom0_ops.h
@@ -133,11 +133,12 @@ typedef struct {
/*
* Set clock such that it would read <secs,nsecs> after 00:00:00 UTC,
* 1 January, 1970 if the current system time was <system_time>.
+ * NB. <secs> can be negative, but <nsecs> must always be non-negative.
*/
#define DOM0_SETTIME 17
typedef struct {
/* IN variables. */
- u32 secs;
+ s64 secs;
u32 nsecs;
u64 system_time;
} dom0_settime_t;
diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h
index ca156ca4f5..ecdcced91e 100644
--- a/xen/include/public/xen.h
+++ b/xen/include/public/xen.h
@@ -399,11 +399,12 @@ typedef struct shared_info {
/*
* Wallclock time: updated only by control software. Guests should base
- * their gettimeofday() syscall on this wallclock-base value.
+ * their gettimeofday() syscall on this wallclock-base value, which
+ * indicates UTC when system_time == 0 (i.e., at boot).
*/
u32 wc_version; /* Version counter: see vcpu_time_info_t. */
- u32 wc_sec; /* Secs 00:00:00 UTC, Jan 1, 1970. */
- u32 wc_nsec; /* Nsecs 00:00:00 UTC, Jan 1, 1970. */
+ u32 wc_nsec; /* Nsecs since 00:00:00 UTC, Jan 1, 1970. */
+ s64 wc_sec; /* Secs since 00:00:00 UTC, Jan 1, 1970. */
arch_shared_info_t arch;
diff --git a/xen/include/xen/time.h b/xen/include/xen/time.h
index eec7f4082b..491f3e13ba 100644
--- a/xen/include/xen/time.h
+++ b/xen/include/xen/time.h
@@ -56,8 +56,7 @@ s_time_t get_s_time(void);
#define MICROSECS(_us) ((s_time_t)((_us) * 1000ULL))
extern void update_dom_time(struct vcpu *v);
-extern void do_settime(
- unsigned long secs, unsigned long nsecs, u64 system_time_base);
+extern void do_settime(s64 secs, u32 nsecs, u64 system_time_base);
#endif /* __XEN_TIME_H__ */