Provide timespec to guests rather than jiffies clock.
A non-periodic clock_event_device and the "jiffies" clock don't mix well:
tick_handle_periodic() can go into an infinite loop.
Currently lguest guests use the jiffies clock when the TSC is
unusable. Instead, make the Host write the current time into the lguest
page on every interrupt. This doesn't cost much but is more precise
and at least as accurate as the jiffies clock. It also gets rid of
the GET_WALLCLOCK hypercall.
Also, delay setting sched_clock until our clock is set up, otherwise
the early printk timestamps can go backwards (not harmful, just ugly).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
diff --git a/drivers/lguest/hypercalls.c b/drivers/lguest/hypercalls.c
index 7a5299f..db6caac 100644
--- a/drivers/lguest/hypercalls.c
+++ b/drivers/lguest/hypercalls.c
@@ -64,14 +64,6 @@
else
guest_pagetable_flush_user(lg);
break;
- case LHCALL_GET_WALLCLOCK: {
- /* The Guest wants to know the real time in seconds since 1970,
- * in good Unix tradition. */
- struct timespec ts;
- ktime_get_real_ts(&ts);
- regs->eax = ts.tv_sec;
- break;
- }
case LHCALL_BIND_DMA:
/* BIND_DMA really wants four arguments, but it's the only call
* which does. So the Guest packs the number of buffers and
@@ -235,6 +227,9 @@
|| put_user(lg->guestid, &lg->lguest_data->guestid))
kill_guest(lg, "bad guest page %p", lg->lguest_data);
+ /* We write the current time into the Guest's data page once now. */
+ write_timestamp(lg);
+
/* This is the one case where the above accesses might have been the
* first write to a Guest page. This may have caused a copy-on-write
* fault, but the Guest might be referring to the old (read-only)
@@ -293,3 +288,13 @@
clear_hcall(lg);
}
}
+
+/* This routine supplies the Guest with time: it's used for wallclock time at
+ * initial boot and as a rough time source if the TSC isn't available. */
+void write_timestamp(struct lguest *lg)
+{
+ struct timespec now;
+ ktime_get_real_ts(&now);
+ if (put_user(now, &lg->lguest_data->time))
+ kill_guest(lg, "Writing timestamp");
+}