mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
More time fixes. Now time is set properly in domU's, and
settimeofday() is simplified and fixed. Signed-off-by: Keir Fraser <keir@xensource.com>
This commit is contained in:
1 parent
3140b13b50
commit
e20872cf5e
4 files changed
+66
-69
No files matched your search
@@ -227,12 +227,38 @@ static unsigned long get_usec_offset(struct shadow_time_info *shadow)
|
||||
return scale_delta(delta, shadow->tsc_to_usec_mul, shadow->tsc_shift);
|
||||
}
|
||||
|
||||
static void __update_wallclock(time_t sec, long nsec)
|
||||
{
|
||||
long wtm_nsec, xtime_nsec;
|
||||
time_t wtm_sec, xtime_sec;
|
||||
u64 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 -= (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;
|
||||
|
||||
wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - xtime_sec);
|
||||
wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - xtime_nsec);
|
||||
|
||||
set_normalized_timespec(&xtime, xtime_sec, xtime_nsec);
|
||||
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
|
||||
|
||||
time_adjust = 0; /* stop active adjtime() */
|
||||
time_status |= STA_UNSYNC;
|
||||
time_maxerror = NTP_PHASE_LIMIT;
|
||||
time_esterror = NTP_PHASE_LIMIT;
|
||||
}
|
||||
|
||||
static void update_wallclock(void)
|
||||
{
|
||||
shared_info_t *s = HYPERVISOR_shared_info;
|
||||
long wtm_nsec, xtime_nsec;
|
||||
time_t wtm_sec, xtime_sec;
|
||||
u64 tmp, nsec;
|
||||
|
||||
do {
|
||||
shadow_tv_version = s->wc_version;
|
||||
@@ -243,25 +269,8 @@ static void update_wallclock(void)
|
||||
}
|
||||
while ((s->wc_version & 1) | (shadow_tv_version ^ s->wc_version));
|
||||
|
||||
if (independent_wallclock)
|
||||
return;
|
||||
|
||||
/* Adjust wall-clock time base based on wall_jiffies ticks. */
|
||||
nsec = processed_system_time;
|
||||
nsec += (u64)shadow_tv.tv_sec * 1000000000ULL;
|
||||
nsec += (u64)shadow_tv.tv_nsec;
|
||||
nsec -= (jiffies - wall_jiffies) * (u64)(NSEC_PER_SEC / HZ);
|
||||
|
||||
/* Split wallclock base into seconds and nanoseconds. */
|
||||
tmp = nsec;
|
||||
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);
|
||||
|
||||
set_normalized_timespec(&xtime, xtime_sec, xtime_nsec);
|
||||
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
|
||||
if (!independent_wallclock)
|
||||
__update_wallclock(shadow_tv.tv_sec, shadow_tv.tv_nsec);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -408,19 +417,15 @@ EXPORT_SYMBOL(do_gettimeofday);
|
||||
|
||||
int do_settimeofday(struct timespec *tv)
|
||||
{
|
||||
time_t wtm_sec, sec = tv->tv_sec;
|
||||
long wtm_nsec;
|
||||
time_t sec;
|
||||
s64 nsec;
|
||||
struct timespec xentime;
|
||||
unsigned int cpu;
|
||||
struct shadow_time_info *shadow;
|
||||
dom0_op_t op;
|
||||
|
||||
if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
|
||||
return -EINVAL;
|
||||
|
||||
if (!independent_wallclock && !(xen_start_info.flags & SIF_INITDOMAIN))
|
||||
return 0; /* Silent failure? */
|
||||
|
||||
cpu = get_cpu();
|
||||
shadow = &per_cpu(shadow_time, cpu);
|
||||
|
||||
@@ -431,51 +436,30 @@ int do_settimeofday(struct timespec *tv)
|
||||
* overflows. If that were to happen then our shadow time values would
|
||||
* be stale, so we can retry with fresh ones.
|
||||
*/
|
||||
again:
|
||||
nsec = (s64)tv->tv_nsec - (s64)get_nsec_offset(shadow);
|
||||
if (unlikely(!time_values_up_to_date(cpu))) {
|
||||
for ( ; ; ) {
|
||||
nsec = (s64)tv->tv_nsec - (s64)get_nsec_offset(shadow);
|
||||
if (time_values_up_to_date(cpu))
|
||||
break;
|
||||
get_time_values_from_xen();
|
||||
goto again;
|
||||
}
|
||||
|
||||
sec = tv->tv_sec;
|
||||
__normalize_time(&sec, &nsec);
|
||||
set_normalized_timespec(&xentime, sec, nsec);
|
||||
|
||||
/*
|
||||
* This is revolting. We need to set "xtime" correctly. However, the
|
||||
* value in this location is the value at the most recent update of
|
||||
* wall time. Discover what correction gettimeofday() would have
|
||||
* made, and then undo it!
|
||||
*/
|
||||
nsec -= (jiffies - wall_jiffies) * TICK_NSEC;
|
||||
|
||||
nsec -= (shadow->system_timestamp - processed_system_time);
|
||||
|
||||
__normalize_time(&sec, &nsec);
|
||||
wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
|
||||
wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
|
||||
|
||||
set_normalized_timespec(&xtime, sec, nsec);
|
||||
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
|
||||
|
||||
time_adjust = 0; /* stop active adjtime() */
|
||||
time_status |= STA_UNSYNC;
|
||||
time_maxerror = NTP_PHASE_LIMIT;
|
||||
time_esterror = NTP_PHASE_LIMIT;
|
||||
|
||||
#ifdef CONFIG_XEN_PRIVILEGED_GUEST
|
||||
if ((xen_start_info.flags & SIF_INITDOMAIN) &&
|
||||
!independent_wallclock) {
|
||||
dom0_op_t op;
|
||||
op.cmd = DOM0_SETTIME;
|
||||
op.u.settime.secs = xentime.tv_sec;
|
||||
op.u.settime.nsecs = xentime.tv_nsec;
|
||||
op.u.settime.secs = sec;
|
||||
op.u.settime.nsecs = nsec;
|
||||
op.u.settime.system_time = shadow->system_timestamp;
|
||||
write_sequnlock_irq(&xtime_lock);
|
||||
HYPERVISOR_dom0_op(&op);
|
||||
} else
|
||||
#endif
|
||||
write_sequnlock_irq(&xtime_lock);
|
||||
update_wallclock();
|
||||
} else if (independent_wallclock) {
|
||||
nsec -= shadow->system_timestamp;
|
||||
__normalize_time(&sec, &nsec);
|
||||
__update_wallclock(sec, nsec);
|
||||
}
|
||||
|
||||
write_sequnlock_irq(&xtime_lock);
|
||||
|
||||
put_cpu();
|
||||
|
||||
@@ -492,6 +476,9 @@ static int set_rtc_mmss(unsigned long nowtime)
|
||||
|
||||
WARN_ON(irqs_disabled());
|
||||
|
||||
if (!(xen_start_info.flags & SIF_INITDOMAIN))
|
||||
return 0;
|
||||
|
||||
/* gets recalled with irq locally disabled */
|
||||
spin_lock_irq(&rtc_lock);
|
||||
if (efi_enabled)
|
||||
@@ -603,8 +590,10 @@ static inline void do_timer_interrupt(int irq, void *dev_id,
|
||||
profile_tick(CPU_PROFILING, regs);
|
||||
}
|
||||
|
||||
if (unlikely(shadow_tv_version != HYPERVISOR_shared_info->wc_version))
|
||||
if (shadow_tv_version != HYPERVISOR_shared_info->wc_version) {
|
||||
update_wallclock();
|
||||
clock_was_set();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -279,8 +279,6 @@ void arch_do_createdomain(struct vcpu *v)
|
||||
|
||||
shadow_lock_init(d);
|
||||
INIT_LIST_HEAD(&d->arch.free_shadow_frames);
|
||||
|
||||
init_domain_time(d);
|
||||
}
|
||||
|
||||
void arch_do_boot_vcpu(struct vcpu *v)
|
||||
@@ -481,7 +479,10 @@ int arch_set_info_guest(
|
||||
}
|
||||
|
||||
update_pagetables(v);
|
||||
|
||||
|
||||
if ( v->vcpu_id == 0 )
|
||||
init_domain_time(d);
|
||||
|
||||
/* Don't redo final setup */
|
||||
set_bit(_VCPUF_initialised, &v->vcpu_flags);
|
||||
|
||||
|
||||
@@ -618,6 +618,8 @@ int construct_dom0(struct domain *d,
|
||||
/* DOM0 gets access to everything. */
|
||||
physdev_init_dom0(d);
|
||||
|
||||
init_domain_time(d);
|
||||
|
||||
set_bit(_DOMF_constructed, &d->domain_flags);
|
||||
|
||||
new_thread(v, dsi.v_kernentry, vstack_end, vstartinfo_start);
|
||||
|
||||
+6
-1
@@ -44,6 +44,7 @@ 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'. */
|
||||
static spinlock_t wc_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
struct time_scale {
|
||||
int shift;
|
||||
@@ -699,13 +700,14 @@ void do_settime(unsigned long secs, unsigned long nsecs, u64 system_time_base)
|
||||
struct domain *d;
|
||||
shared_info_t *s;
|
||||
|
||||
x = (secs * 1000000000ULL) + (u64)nsecs + system_time_base;
|
||||
x = (secs * 1000000000ULL) + (u64)nsecs - system_time_base;
|
||||
y = do_div(x, 1000000000);
|
||||
|
||||
wc_sec = _wc_sec = (u32)x;
|
||||
wc_nsec = _wc_nsec = (u32)y;
|
||||
|
||||
read_lock(&domlist_lock);
|
||||
spin_lock(&wc_lock);
|
||||
|
||||
for_each_domain ( d )
|
||||
{
|
||||
@@ -716,15 +718,18 @@ void do_settime(unsigned long secs, unsigned long nsecs, u64 system_time_base)
|
||||
version_update_end(&s->wc_version);
|
||||
}
|
||||
|
||||
spin_unlock(&wc_lock);
|
||||
read_unlock(&domlist_lock);
|
||||
}
|
||||
|
||||
void init_domain_time(struct domain *d)
|
||||
{
|
||||
spin_lock(&wc_lock);
|
||||
version_update_begin(&d->shared_info->wc_version);
|
||||
d->shared_info->wc_sec = wc_sec;
|
||||
d->shared_info->wc_nsec = wc_nsec;
|
||||
version_update_end(&d->shared_info->wc_version);
|
||||
spin_unlock(&wc_lock);
|
||||
}
|
||||
|
||||
static void local_time_calibration(void *unused)
|
||||
|
||||