Skip to content

Commit e3da88b

Browse files
committed
ukvm,kernel: Replace pvclock with simplified tscclock
To enable multi-backend we need a clock that does not depend on any backend-specific device. This change replaces the use of pvclock by the ukvm target with: - a simplified TSC-only implementation of tscclock - a new hypercall to get wall clock time from the monitor (UKVM_HYPERCALL_WALLTIME). - a new arch-dependent section in struct ukvm_boot_info, used to pass the (x86) TSC frequency to the guest. Note that the monitor will now refuse to run on a host with an unstable TSC, see the implementation notes in kernel/ukvm/tscclock.c for an explanation. Related changes also part of this commit: - Add a simple test that the clock(s) work(s), in tests/test_time. The upper limit on how much is "too much" to sleep may need to be tweaked (or the test result ignored) on Travis. - hypercall_poll() now blocks all signals except SIGINT and SIGTERM rather than restarting the ppoll() call which was incorrectly assuming (*ts) would be modified by ppoll().
1 parent 682411f commit e3da88b

15 files changed

Lines changed: 282 additions & 15 deletions

File tree

kernel/Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ ee_printf.o \
2626
intr.o \
2727
lib.o \
2828
malloc.o \
29-
exit.o \
30-
pvclock.o
29+
exit.o
3130

3231
UKVM_COBJS=\
3332
ukvm/kernel.o \
@@ -37,6 +36,7 @@ ukvm/platform.o \
3736
ukvm/platform_intr.o \
3837
ukvm/mem.o \
3938
ukvm/time.o \
39+
ukvm/tscclock.o \
4040
$(COMMON_COBJS)
4141

4242
VIRTIO_COBJS=\
@@ -53,6 +53,7 @@ virtio/virtio_net.o \
5353
virtio/virtio_blk.o \
5454
virtio/tscclock.o \
5555
virtio/clock_subr.o \
56+
virtio/pvclock.o \
5657
$(COMMON_COBJS)
5758

5859
HEADERS=\

kernel/kernel.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,6 @@ void *calloc(size_t nmemb, size_t size);
104104
void *realloc(void *ptr, size_t size);
105105
void *memalign(size_t alignment, size_t bytes);
106106

107-
/* time.c: clocksource */
108-
void time_init(void);
109-
110107
/* ee_printf.c: a third-party printf slightly modified and with
111108
* snprintf added
112109
*/

kernel/ukvm/kernel.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ void _start(struct ukvm_boot_info *bi)
3333
mem_init(bi->mem_size, bi->kernel_end);
3434
intr_init();
3535

36-
time_init();
36+
time_init(bi->cpu.tsc_freq);
3737

3838
intr_enable();
3939

kernel/ukvm/kernel.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,10 @@ void tss_load(uint16_t tss);
3232

3333
void mem_init(uint64_t size, uint64_t _kernel_end);
3434

35+
void time_init(uint64_t tsc_freq);
36+
37+
/* tscclock.c: TSC-based clock */
38+
uint64_t tscclock_monotonic(void);
39+
int tscclock_init(uint64_t tsc_freq);
40+
uint64_t tscclock_epochoffset(void);
3541
#endif

kernel/ukvm/time.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,20 @@
2020

2121
#include "kernel.h"
2222

23-
void time_init(void)
23+
void time_init(uint64_t tsc_freq)
2424
{
25-
assert(pvclock_init() == 0);
25+
assert(tscclock_init(tsc_freq) == 0);
2626
}
2727

2828
uint64_t solo5_clock_monotonic(void)
2929
{
30-
return pvclock_monotonic();
30+
return tscclock_monotonic();
3131
}
3232

3333
/* return wall time in nsecs */
3434
uint64_t solo5_clock_wall(void)
3535
{
36-
return pvclock_monotonic() + pvclock_epochoffset();
36+
return tscclock_monotonic() + tscclock_epochoffset();
3737
}
3838

3939
int solo5_poll(uint64_t until_nsecs)

kernel/ukvm/tscclock.c

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright (c) 2015-2017 Contributors as noted in the AUTHORS file
3+
*
4+
* This file is part of Solo5, a unikernel base layer.
5+
*
6+
* Permission to use, copy, modify, and/or distribute this software
7+
* for any purpose with or without fee is hereby granted, provided
8+
* that the above copyright notice and this permission notice appear
9+
* in all copies.
10+
*
11+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
12+
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
13+
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
14+
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
15+
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
16+
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
17+
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
18+
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19+
*/
20+
21+
#include "kernel.h"
22+
23+
/* Wall clock offset at monotonic time base. */
24+
static uint64_t wc_epochoffset;
25+
26+
/* Base time values at the last call to tscclock_monotonic(). */
27+
static uint64_t time_base;
28+
static uint64_t tsc_base;
29+
30+
/* Multiplier for converting TSC ticks to nsecs. (0.32) fixed point. */
31+
static uint32_t tsc_mult;
32+
33+
/*
34+
* Beturn monotonic time using TSC clock.
35+
*/
36+
uint64_t tscclock_monotonic(void)
37+
{
38+
uint64_t tsc_now, tsc_delta;
39+
40+
/*
41+
* Update time_base (monotonic time) and tsc_base (TSC time).
42+
*/
43+
tsc_now = cpu_rdtsc();
44+
tsc_delta = tsc_now - tsc_base;
45+
time_base += mul64_32(tsc_delta, tsc_mult);
46+
tsc_base = tsc_now;
47+
48+
return time_base;
49+
}
50+
51+
/*
52+
* Initialise TSC clock.
53+
*
54+
* Implementation notes: This is a purely TSC-based clock with the following
55+
* requirements:
56+
*
57+
* 1. The host TSC MUST be invariant, as defined in Intel SDM section 17.15.1
58+
* "Invariant TSC".
59+
* 2. The host hypervisor MUST NOT implement any RDTSC emulation.
60+
*
61+
* It is up to the monitor to ensure that these requirements are met, and to
62+
* supply the TSC frequency to the guest.
63+
*/
64+
int tscclock_init(uint64_t tsc_freq)
65+
{
66+
/*
67+
* Calculate TSC scaling multiplier.
68+
*
69+
* (0.32) tsc_mult = NSEC_PER_SEC (32.32) / tsc_freq (32.0)
70+
*/
71+
tsc_mult = (NSEC_PER_SEC << 32) / tsc_freq;
72+
73+
/*
74+
* Monotonic time begins at tsc_base (first read of TSC before
75+
* calibration).
76+
*/
77+
tsc_base = cpu_rdtsc();
78+
time_base = mul64_32(tsc_base, tsc_mult);
79+
80+
/*
81+
* Compute wall clock epoch offset by subtracting monotonic time_base from
82+
* wall time at boot.
83+
*
84+
* TODO: This arrangement minimises the use of hypercalls, but is subject
85+
* to clock skew over time and cannot get corrections from the host (via
86+
* e.g. NTP).
87+
*/
88+
struct ukvm_walltime t;
89+
ukvm_do_hypercall(UKVM_HYPERCALL_WALLTIME, &t);
90+
wc_epochoffset = t.nsecs - time_base;
91+
92+
return 0;
93+
}
94+
95+
/*
96+
* Return epoch offset (wall time offset to monotonic clock start).
97+
*/
98+
uint64_t tscclock_epochoffset(void)
99+
{
100+
return wc_epochoffset;
101+
}

kernel/virtio/kernel.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ void mem_init(struct multiboot_info *mb);
3030
void serial_init(void);
3131
void serial_putc(char a);
3232

33+
void time_init(void);
34+
3335
/* tscclock.c: TSC/PIT-based clock and sleep */
3436
int tscclock_init(void);
3537
uint64_t tscclock_monotonic(void);

tests/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
1717
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1818

19-
TESTDIRS=test_hello test_globals test_ping_serve test_blk test_exception test_fpu
19+
TESTDIRS=test_hello test_globals test_ping_serve test_blk test_exception test_fpu test_time
2020

2121
UKVM_TESTS=$(subst test, _test_ukvm, $(TESTDIRS))
2222
VIRTIO_TESTS=$(subst test, _test_virtio, $(TESTDIRS))

tests/run-tests.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ if [ -n "${BUILD_UKVM}" ]; then
238238
add_test test_globals.ukvm
239239
add_test test_exception.ukvm:-a
240240
add_test test_fpu.ukvm
241+
add_test test_time.ukvm
241242
add_test test_blk.ukvm:-d
242243
add_test test_ping_serve.ukvm:-n:limit
243244
fi
@@ -246,6 +247,7 @@ if [ -n "${BUILD_VIRTIO}" ]; then
246247
add_test test_globals.virtio
247248
add_test test_exception.virtio:-a
248249
add_test test_fpu.virtio
250+
add_test test_time.virtio
249251
add_test test_blk.virtio:-d
250252
add_test test_ping_serve.virtio:-n:limit
251253
fi

0 commit comments

Comments
 (0)