diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2018-12-05 18:02:52 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2018-12-05 18:02:52 +0000 |
commit | 48949173be5697ec93cd9ee272337c68423d765d (patch) | |
tree | 99cbc0073df9b88c3f6aa20a89e1f0c86ba51729 /sys/dev/pv | |
parent | 90a109b457252b795ff4238d2e09c31009a3b6cc (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.c | 27 |
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; |