1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2014 Bryan Venteicher <bryanv@FreeBSD.org>
5 * Copyright (c) 2021 Mathieu Chouquet-Stringer
6 * Copyright (c) 2021 Juniper Networks, Inc.
7 * Copyright (c) 2021 Klara, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 /*
32 * Linux KVM paravirtual clock support
33 *
34 * References:
35 * - [1] https://www.kernel.org/doc/html/latest/virt/kvm/cpuid.html
36 * - [2] https://www.kernel.org/doc/html/latest/virt/kvm/msr.html
37 */
38
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD$");
41
42 #include <sys/param.h>
43 #include <sys/bus.h>
44 #include <sys/domainset.h>
45 #include <sys/kernel.h>
46 #include <sys/malloc.h>
47 #include <sys/module.h>
48 #include <sys/smp.h>
49
50 #include <vm/vm.h>
51 #include <vm/pmap.h>
52 #include <vm/vm_extern.h>
53
54 #include <machine/pvclock.h>
55 #include <x86/kvm.h>
56
57 #include "clock_if.h"
58
59 #define KVM_CLOCK_DEVNAME "kvmclock"
60 /*
61 * Note: Chosen to be (1) above HPET's value (always 950), (2) above the TSC's
62 * default value of 800, and (3) below the TSC's value when it supports the
63 * "Invariant TSC" feature and is believed to be synchronized across all CPUs.
64 */
65 #define KVM_CLOCK_TC_QUALITY 975
66
67 struct kvm_clock_softc {
68 struct pvclock pvc;
69 struct pvclock_wall_clock wc;
70 struct pvclock_vcpu_time_info *timeinfos;
71 u_int msr_tc;
72 u_int msr_wc;
73 };
74
75 static devclass_t kvm_clock_devclass;
76
77 static struct pvclock_wall_clock *kvm_clock_get_wallclock(void *arg);
78 static void kvm_clock_system_time_enable(struct kvm_clock_softc *sc);
79 static void kvm_clock_system_time_enable_pcpu(void *arg);
80
81 static struct pvclock_wall_clock *
82 kvm_clock_get_wallclock(void *arg)
83 {
84 struct kvm_clock_softc *sc = arg;
85
86 wrmsr(sc->msr_wc, vtophys(&sc->wc));
87 return (&sc->wc);
88 }
89
90 static void
91 kvm_clock_system_time_enable(struct kvm_clock_softc *sc)
92 {
93 smp_rendezvous(NULL, kvm_clock_system_time_enable_pcpu, NULL, sc);
94 }
95
96 static void
97 kvm_clock_system_time_enable_pcpu(void *arg)
98 {
99 struct kvm_clock_softc *sc = arg;
100
101 /*
102 * See [2]; the lsb of this MSR is the system time enable bit.
103 */
104 wrmsr(sc->msr_tc, vtophys(&(sc->timeinfos)[curcpu]) | 1);
105 }
106
107 static void
108 kvm_clock_identify(driver_t *driver, device_t parent)
109 {
110 u_int regs[4];
111
112 kvm_cpuid_get_features(regs);
113 if ((regs[0] &
114 (KVM_FEATURE_CLOCKSOURCE2 | KVM_FEATURE_CLOCKSOURCE)) == 0)
115 return;
116 if (device_find_child(parent, KVM_CLOCK_DEVNAME, -1))
117 return;
118 BUS_ADD_CHILD(parent, 0, KVM_CLOCK_DEVNAME, 0);
119 }
120
121 static int
122 kvm_clock_probe(device_t dev)
123 {
124 device_set_desc(dev, "KVM paravirtual clock");
125 return (BUS_PROBE_DEFAULT);
126 }
127
128 static int
129 kvm_clock_attach(device_t dev)
130 {
131 u_int regs[4];
132 struct kvm_clock_softc *sc = device_get_softc(dev);
133 bool stable_flag_supported;
134
135 /* Process KVM "features" CPUID leaf content: */
136 kvm_cpuid_get_features(regs);
137 if ((regs[0] & KVM_FEATURE_CLOCKSOURCE2) != 0) {
138 sc->msr_tc = KVM_MSR_SYSTEM_TIME_NEW;
139 sc->msr_wc = KVM_MSR_WALL_CLOCK_NEW;
140 } else {
141 KASSERT((regs[0] & KVM_FEATURE_CLOCKSOURCE) != 0,
142 ("Clocksource feature flags disappeared since "
143 "kvm_clock_identify: regs[0] %#0x.", regs[0]));
144 sc->msr_tc = KVM_MSR_SYSTEM_TIME;
145 sc->msr_wc = KVM_MSR_WALL_CLOCK;
146 }
147 stable_flag_supported =
148 (regs[0] & KVM_FEATURE_CLOCKSOURCE_STABLE_BIT) != 0;
149
150 /* Set up 'struct pvclock_vcpu_time_info' page(s): */
151 sc->timeinfos = (struct pvclock_vcpu_time_info *)kmem_malloc(mp_ncpus *
152 sizeof(struct pvclock_vcpu_time_info), M_WAITOK | M_ZERO);
153 kvm_clock_system_time_enable(sc);
154
155 /*
156 * Init pvclock; register KVM clock wall clock, register KVM clock
157 * timecounter, and set up the requisite infrastructure for vDSO access
158 * to this timecounter.
159 * Regarding 'tc_flags': Since the KVM MSR documentation does not
160 * specifically discuss suspend/resume scenarios, conservatively
161 * leave 'TC_FLAGS_SUSPEND_SAFE' cleared and assume that the system
162 * time must be re-inited in such cases.
163 */
164 sc->pvc.get_wallclock = kvm_clock_get_wallclock;
165 sc->pvc.get_wallclock_arg = sc;
166 sc->pvc.timeinfos = sc->timeinfos;
167 sc->pvc.stable_flag_supported = stable_flag_supported;
168 pvclock_init(&sc->pvc, dev, KVM_CLOCK_DEVNAME, KVM_CLOCK_TC_QUALITY, 0);
169 return (0);
170 }
171
172 static int
173 kvm_clock_detach(device_t dev)
174 {
175 struct kvm_clock_softc *sc = device_get_softc(dev);
176
177 return (pvclock_destroy(&sc->pvc));
178 }
179
180 static int
181 kvm_clock_suspend(device_t dev)
182 {
183 return (0);
184 }
185
186 static int
187 kvm_clock_resume(device_t dev)
188 {
189 /*
190 * See note in 'kvm_clock_attach()' regarding 'TC_FLAGS_SUSPEND_SAFE';
191 * conservatively assume that the system time must be re-inited in
192 * suspend/resume scenarios.
193 */
194 kvm_clock_system_time_enable(device_get_softc(dev));
195 pvclock_resume();
196 inittodr(time_second);
197 return (0);
198 }
199
200 static int
201 kvm_clock_gettime(device_t dev, struct timespec *ts)
202 {
203 struct kvm_clock_softc *sc = device_get_softc(dev);
204
205 pvclock_gettime(&sc->pvc, ts);
206 return (0);
207 }
208
209 static int
210 kvm_clock_settime(device_t dev, struct timespec *ts)
211 {
212 /*
213 * Even though it is not possible to set the KVM clock's wall clock, to
214 * avoid the possibility of periodic benign error messages from
215 * 'settime_task_func()', report success rather than, e.g., 'ENODEV'.
216 */
217 return (0);
218 }
219
220 static device_method_t kvm_clock_methods[] = {
221 DEVMETHOD(device_identify, kvm_clock_identify),
222 DEVMETHOD(device_probe, kvm_clock_probe),
223 DEVMETHOD(device_attach, kvm_clock_attach),
224 DEVMETHOD(device_detach, kvm_clock_detach),
225 DEVMETHOD(device_suspend, kvm_clock_suspend),
226 DEVMETHOD(device_resume, kvm_clock_resume),
227 /* clock interface */
228 DEVMETHOD(clock_gettime, kvm_clock_gettime),
229 DEVMETHOD(clock_settime, kvm_clock_settime),
230
231 DEVMETHOD_END
232 };
233
234 static driver_t kvm_clock_driver = {
235 KVM_CLOCK_DEVNAME,
236 kvm_clock_methods,
237 sizeof(struct kvm_clock_softc),
238 };
239
240 DRIVER_MODULE(kvm_clock, nexus, kvm_clock_driver, kvm_clock_devclass, 0, 0);
Cache object: e46e40fceeb06db368cfb2de733e3543
|