summaryrefslogtreecommitdiff
path: root/sys/dev/pv
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2018-12-05 18:02:52 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2018-12-05 18:02:52 +0000
commit48949173be5697ec93cd9ee272337c68423d765d (patch)
tree99cbc0073df9b88c3f6aa20a89e1f0c86ba51729 /sys/dev/pv
parent90a109b457252b795ff4238d2e09c31009a3b6cc (diff)
Correctly disable pvclock(4) on old hardware that lack a stable clock
I falsely assumed that the KVM_FEATURE_CLOCKSOURCE_STABLE_BIT indicates that the actual clock values are stable, but it turned out that this isn't always the case. To detect if the clock value is stable, we now read it once in pvclock_attach() and check for the PVCLOCK_FLAG_TSC_STABLE flag. This needs further investigation. Reported and fix tested by johnw.mail at gmail.com OK chris@ phessler@
Diffstat (limited to 'sys/dev/pv')
-rw-r--r--sys/dev/pv/pvclock.c27
1 files changed, 24 insertions, 3 deletions
diff --git a/sys/dev/pv/pvclock.c b/sys/dev/pv/pvclock.c
index 123efab610d..05eebf783c2 100644
--- a/sys/dev/pv/pvclock.c
+++ b/sys/dev/pv/pvclock.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pvclock.c,v 1.2 2018/11/24 13:12:29 phessler Exp $ */
+/* $OpenBSD: pvclock.c,v 1.3 2018/12/05 18:02:51 reyk Exp $ */
/*
* Copyright (c) 2018 Reyk Floeter <reyk@openbsd.org>
@@ -70,6 +70,11 @@ uint pvclock_get_timecount(struct timecounter *);
void pvclock_read_time_info(struct pvclock_softc *,
struct pvclock_time_info *);
+static inline uint32_t
+ pvclock_read_begin(const struct pvclock_time_info *);
+static inline int
+ pvclock_read_done(const struct pvclock_time_info *, uint32_t);
+
struct cfattach pvclock_ca = {
sizeof(struct pvclock_softc),
pvclock_match,
@@ -127,8 +132,11 @@ pvclock_match(struct device *parent, void *match, void *aux)
void
pvclock_attach(struct device *parent, struct device *self, void *aux)
{
- struct pvclock_softc *sc = (struct pvclock_softc *)self;
- paddr_t pa;
+ struct pvclock_softc *sc = (struct pvclock_softc *)self;
+ struct pvclock_time_info *ti;
+ paddr_t pa;
+ uint32_t version;
+ uint8_t flags;
if ((sc->sc_time = km_alloc(PAGE_SIZE,
&kv_any, &kp_zero, &kd_nowait)) == NULL) {
@@ -144,6 +152,19 @@ pvclock_attach(struct device *parent, struct device *self, void *aux)
wrmsr(KVM_MSR_SYSTEM_TIME, pa | PVCLOCK_SYSTEM_TIME_ENABLE);
sc->sc_paddr = pa;
+ ti = sc->sc_time;
+ do {
+ version = pvclock_read_begin(ti);
+ flags = ti->ti_flags;
+ } while (!pvclock_read_done(ti, version));
+
+ if ((flags & PVCLOCK_FLAG_TSC_STABLE) == 0) {
+ wrmsr(KVM_MSR_SYSTEM_TIME, pa & ~PVCLOCK_SYSTEM_TIME_ENABLE);
+ km_free(sc->sc_time, PAGE_SIZE, &kv_any, &kp_zero);
+ printf(": unstable clock\n");
+ return;
+ }
+
sc->sc_tc = &pvclock_timecounter;
sc->sc_tc->tc_name = DEVNAME(sc);
sc->sc_tc->tc_frequency = 1000000000ULL;