xref: /openbsd/sys/dev/pv/pvbus.c (revision 9e6efb0a)
1 /*	$OpenBSD: pvbus.c,v 1.28 2024/05/24 10:05:55 jsg Exp $	*/
2 
3 /*
4  * Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #if !defined(__i386__) && !defined(__amd64__)
20 #error pvbus(4) is currently only supported on i386 and amd64
21 #endif
22 
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/malloc.h>
26 #include <sys/signalvar.h>
27 #include <sys/syslog.h>
28 #include <sys/proc.h>
29 #include <sys/ioctl.h>
30 #include <sys/fcntl.h>
31 
32 #include <machine/specialreg.h>
33 #include <machine/cpu.h>
34 #include <machine/conf.h>
35 #include <machine/bus.h>
36 #include <machine/vmmvar.h>
37 
38 #include <dev/pv/pvvar.h>
39 #include <dev/pv/pvreg.h>
40 #include <dev/pv/hypervreg.h>
41 
42 #include "hyperv.h"
43 
44 int has_hv_cpuid = 0;
45 
46 extern void rdrand(void *);
47 
48 int	 pvbus_activate(struct device *, int);
49 int	 pvbus_match(struct device *, void *, void *);
50 void	 pvbus_attach(struct device *, struct device *, void *);
51 int	 pvbus_print(void *, const char *);
52 int	 pvbus_search(struct device *, void *, void *);
53 
54 void	 pvbus_kvm(struct pvbus_hv *);
55 void	 pvbus_hyperv(struct pvbus_hv *);
56 void	 pvbus_hyperv_print(struct pvbus_hv *);
57 void	 pvbus_xen(struct pvbus_hv *);
58 void	 pvbus_xen_print(struct pvbus_hv *);
59 
60 int	 pvbus_minor(struct pvbus_softc *, dev_t);
61 int	 pvbusgetstr(size_t, const char *, char **);
62 
63 const struct cfattach pvbus_ca = {
64 	sizeof(struct pvbus_softc),
65 	pvbus_match,
66 	pvbus_attach,
67 	NULL,
68 	pvbus_activate
69 };
70 
71 struct cfdriver pvbus_cd = {
72 	NULL,
73 	"pvbus",
74 	DV_DULL
75 };
76 
77 struct pvbus_type {
78 	const char	*signature;
79 	const char	*name;
80 	void		(*init)(struct pvbus_hv *);
81 	void		(*print)(struct pvbus_hv *);
82 } pvbus_types[PVBUS_MAX] = {
83 	{ "KVMKVMKVM\0\0\0",	"KVM",	pvbus_kvm },
84 	{ "Microsoft Hv",	"Hyper-V", pvbus_hyperv, pvbus_hyperv_print },
85 	{ "VMwareVMware",	"VMware" },
86 	{ "XenVMMXenVMM",	"Xen",	pvbus_xen, pvbus_xen_print },
87 	{ "bhyve bhyve ",	"bhyve" },
88 	{ VMM_HV_SIGNATURE,	"OpenBSD", pvbus_kvm },
89 };
90 
91 struct bus_dma_tag pvbus_dma_tag = {
92 	NULL,
93 	_bus_dmamap_create,
94 	_bus_dmamap_destroy,
95 	_bus_dmamap_load,
96 	_bus_dmamap_load_mbuf,
97 	_bus_dmamap_load_uio,
98 	_bus_dmamap_load_raw,
99 	_bus_dmamap_unload,
100 	_bus_dmamap_sync,
101 	_bus_dmamem_alloc,
102 	_bus_dmamem_alloc_range,
103 	_bus_dmamem_free,
104 	_bus_dmamem_map,
105 	_bus_dmamem_unmap,
106 	_bus_dmamem_mmap,
107 };
108 
109 struct pvbus_hv pvbus_hv[PVBUS_MAX];
110 struct pvbus_softc *pvbus_softc;
111 
112 int
113 pvbus_probe(void)
114 {
115 	/* Must be set in identcpu */
116 	if (!has_hv_cpuid)
117 		return (0);
118 	return (1);
119 }
120 
121 int
122 pvbus_match(struct device *parent, void *match, void *aux)
123 {
124 	const char **busname = (const char **)aux;
125 	return (strcmp(*busname, pvbus_cd.cd_name) == 0);
126 }
127 
128 void
129 pvbus_attach(struct device *parent, struct device *self, void *aux)
130 {
131 	struct pvbus_softc *sc = (struct pvbus_softc *)self;
132 	int i, cnt;
133 
134 	sc->pvbus_hv = pvbus_hv;
135 	pvbus_softc = sc;
136 
137 	printf(":");
138 	for (i = 0, cnt = 0; i < PVBUS_MAX; i++) {
139 		if (pvbus_hv[i].hv_base == 0)
140 			continue;
141 		if (cnt++)
142 			printf(",");
143 		printf(" %s", pvbus_types[i].name);
144 		if (pvbus_types[i].print != NULL)
145 			(pvbus_types[i].print)(&pvbus_hv[i]);
146 	}
147 
148 	printf("\n");
149 	config_search(pvbus_search, self, sc);
150 }
151 
152 void
153 pvbus_identify(void)
154 {
155 	struct pvbus_hv *hv;
156 	uint32_t reg0, base;
157 	union {
158 		uint32_t	regs[3];
159 		char		str[CPUID_HV_SIGNATURE_STRLEN];
160 	} r;
161 	int i, cnt;
162 	const char *pv_name;
163 
164 	for (base = CPUID_HV_SIGNATURE_START, cnt = 0;
165 	    base < CPUID_HV_SIGNATURE_END;
166 	    base += CPUID_HV_SIGNATURE_STEP) {
167 		CPUID(base, reg0, r.regs[0], r.regs[1], r.regs[2]);
168 		for (i = 0; i < 4; i++) {
169 			/*
170 			 * Check if first 4 chars are printable ASCII as
171 			 * minimal validity check
172 			 */
173 			if (r.str[i] < 32 || r.str[i] > 126)
174 				goto out;
175 		}
176 
177 		for (i = 0; i < PVBUS_MAX; i++) {
178 			if (pvbus_types[i].signature == NULL ||
179 			    memcmp(pvbus_types[i].signature, r.str,
180 			    CPUID_HV_SIGNATURE_STRLEN) != 0)
181 				continue;
182 			hv = &pvbus_hv[i];
183 			hv->hv_base = base;
184 			if (pvbus_types[i].init != NULL)
185 				(pvbus_types[i].init)(hv);
186 			if (hw_vendor == NULL) {
187 				pv_name = pvbus_types[i].name;
188 
189 				/*
190 				 * Use the HV name as a fallback if we didn't
191 				 * get the vendor name from the firmware/BIOS.
192 				 */
193 				if ((hw_vendor = malloc(strlen(pv_name) + 1,
194 	                            M_DEVBUF, M_NOWAIT)) != NULL) {
195 					strlcpy(hw_vendor, pv_name,
196 					    strlen(pv_name) + 1);
197 				}
198 			}
199 			cnt++;
200 		}
201 	}
202 
203  out:
204 	if (cnt)
205 		has_hv_cpuid = 1;
206 }
207 
208 void
209 pvbus_init_cpu(void)
210 {
211 	int i;
212 
213 	for (i = 0; i < PVBUS_MAX; i++) {
214 		if (pvbus_hv[i].hv_base == 0)
215 			continue;
216 		if (pvbus_hv[i].hv_init_cpu != NULL)
217 			(pvbus_hv[i].hv_init_cpu)(&pvbus_hv[i]);
218 	}
219 }
220 
221 int
222 pvbus_activate(struct device *self, int act)
223 {
224 	int rv = 0;
225 
226 	switch (act) {
227 	case DVACT_SUSPEND:
228 		rv = config_activate_children(self, act);
229 		break;
230 	case DVACT_RESUME:
231 		rv = config_activate_children(self, act);
232 		break;
233 	case DVACT_POWERDOWN:
234 		rv = config_activate_children(self, act);
235 		break;
236 	default:
237 		rv = config_activate_children(self, act);
238 		break;
239 	}
240 
241 	return (rv);
242 }
243 
244 int
245 pvbus_search(struct device *parent, void *arg, void *aux)
246 {
247 	struct pvbus_softc *sc = (struct pvbus_softc *)aux;
248 	struct cfdata		*cf = arg;
249 	struct pv_attach_args	 pva;
250 
251 	pva.pva_busname = cf->cf_driver->cd_name;
252 	pva.pva_hv = sc->pvbus_hv;
253 	pva.pva_dmat = &pvbus_dma_tag;
254 
255 	if (cf->cf_attach->ca_match(parent, cf, &pva) > 0)
256 		config_attach(parent, cf, &pva, pvbus_print);
257 
258 	return (0);
259 }
260 
261 int
262 pvbus_print(void *aux, const char *pnp)
263 {
264 	struct pv_attach_args	*pva = aux;
265 	if (pnp)
266 		printf("%s at %s", pva->pva_busname, pnp);
267 	return (UNCONF);
268 }
269 
270 void
271 pvbus_shutdown(struct device *dev)
272 {
273 	suspend_randomness();
274 
275 	log(LOG_KERN | LOG_NOTICE, "Shutting down in response to request"
276 	    " from %s host\n", dev->dv_xname);
277 	prsignal(initprocess, SIGUSR2);
278 }
279 
280 void
281 pvbus_reboot(struct device *dev)
282 {
283 	suspend_randomness();
284 
285 	log(LOG_KERN | LOG_NOTICE, "Rebooting in response to request"
286 	    " from %s host\n", dev->dv_xname);
287 	prsignal(initprocess, SIGINT);
288 }
289 
290 void
291 pvbus_kvm(struct pvbus_hv *hv)
292 {
293 	uint32_t regs[4];
294 
295 	CPUID(hv->hv_base + CPUID_OFFSET_KVM_FEATURES,
296 	    regs[0], regs[1], regs[2], regs[3]);
297 	hv->hv_features = regs[0];
298 }
299 
300 extern void hv_delay(int usecs);
301 
302 void
303 pvbus_hyperv(struct pvbus_hv *hv)
304 {
305 	uint32_t regs[4];
306 
307 	CPUID(hv->hv_base + CPUID_OFFSET_HYPERV_FEATURES,
308 	    regs[0], regs[1], regs[2], regs[3]);
309 	hv->hv_features = regs[0];
310 
311 	CPUID(hv->hv_base + CPUID_OFFSET_HYPERV_VERSION,
312 	    regs[0], regs[1], regs[2], regs[3]);
313 	hv->hv_major = (regs[1] & HYPERV_VERSION_EBX_MAJOR_M) >>
314 	    HYPERV_VERSION_EBX_MAJOR_S;
315 	hv->hv_minor = (regs[1] & HYPERV_VERSION_EBX_MINOR_M) >>
316 	    HYPERV_VERSION_EBX_MINOR_S;
317 
318 #if NHYPERV > 0
319 	if (hv->hv_features & CPUID_HV_MSR_TIME_REFCNT)
320 		delay_init(hv_delay, 4000);
321 #endif
322 }
323 
324 void
325 pvbus_hyperv_print(struct pvbus_hv *hv)
326 {
327 	printf(" %u.%u", hv->hv_major, hv->hv_minor);
328 }
329 
330 void
331 pvbus_xen(struct pvbus_hv *hv)
332 {
333 	uint32_t regs[4];
334 
335 	CPUID(hv->hv_base + CPUID_OFFSET_XEN_VERSION,
336 	    regs[0], regs[1], regs[2], regs[3]);
337 	hv->hv_major = regs[0] >> XEN_VERSION_MAJOR_S;
338 	hv->hv_minor = regs[0] & XEN_VERSION_MINOR_M;
339 
340 	/* x2apic is broken in Xen 4.2 or older */
341 	if ((hv->hv_major < 4) ||
342 	    (hv->hv_major == 4 && hv->hv_minor < 3)) {
343 		/* Remove CPU flag for x2apic */
344 		cpu_ecxfeature &= ~CPUIDECX_X2APIC;
345 	}
346 }
347 
348 void
349 pvbus_xen_print(struct pvbus_hv *hv)
350 {
351 	printf(" %u.%u", hv->hv_major, hv->hv_minor);
352 }
353 
354 int
355 pvbus_minor(struct pvbus_softc *sc, dev_t dev)
356 {
357 	int hvid, cnt;
358 	struct pvbus_hv *hv;
359 
360 	for (hvid = 0, cnt = 0; hvid < PVBUS_MAX; hvid++) {
361 		hv = &sc->pvbus_hv[hvid];
362 		if (hv->hv_base == 0)
363 			continue;
364 		if (minor(dev) == cnt++)
365 			return (hvid);
366 	}
367 
368 	return (-1);
369 }
370 
371 int
372 pvbusopen(dev_t dev, int flags, int mode, struct proc *p)
373 {
374 	if (pvbus_softc == NULL)
375 		return (ENODEV);
376 	if (pvbus_minor(pvbus_softc, dev) == -1)
377 		return (ENXIO);
378 	return (0);
379 }
380 
381 int
382 pvbusclose(dev_t dev, int flags, int mode, struct proc *p)
383 {
384 	if (pvbus_softc == NULL)
385 		return (ENODEV);
386 	if (pvbus_minor(pvbus_softc, dev) == -1)
387 		return (ENXIO);
388 	return (0);
389 }
390 
391 int
392 pvbusgetstr(size_t srclen, const char *src, char **dstp)
393 {
394 	int error = 0;
395 	char *dst;
396 
397 	/*
398 	 * Reject size that is too short or obviously too long:
399 	 * - Known pv backends other than vmware have a hard limit smaller than
400 	 *   PVBUS_KVOP_MAXSIZE in their messaging.  vmware has a software
401 	 *   limit at 1MB, but current open-vm-tools has a limit at 64KB
402 	 *   (=PVBUS_KVOP_MAXSIZE).
403 	 */
404 	if (srclen < 1)
405 		return (EINVAL);
406 	else if (srclen > PVBUS_KVOP_MAXSIZE)
407 		return (ENAMETOOLONG);
408 
409 	*dstp = dst = malloc(srclen + 1, M_TEMP, M_WAITOK | M_ZERO);
410 	if (src != NULL) {
411 		error = copyin(src, dst, srclen);
412 		dst[srclen] = '\0';
413 	}
414 
415 	return (error);
416 }
417 
418 int
419 pvbusioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
420 {
421 	struct pvbus_req *pvr = (struct pvbus_req *)data;
422 	struct pvbus_softc *sc = pvbus_softc;
423 	char *value = NULL, *key = NULL;
424 	const char *str = NULL;
425 	size_t valuelen = 0, keylen = 0, sz;
426 	int hvid, error = 0, op;
427 	struct pvbus_hv *hv;
428 
429 	if (sc == NULL)
430 		return (ENODEV);
431 	if ((hvid = pvbus_minor(sc, dev)) == -1)
432 		return (ENXIO);
433 
434 	switch (cmd) {
435 	case PVBUSIOC_KVWRITE:
436 		if ((flags & FWRITE) == 0)
437 			return (EPERM);
438 	case PVBUSIOC_KVREAD:
439 		hv = &sc->pvbus_hv[hvid];
440 		if (hv->hv_base == 0 || hv->hv_kvop == NULL)
441 			return (ENXIO);
442 		break;
443 	case PVBUSIOC_TYPE:
444 		str = pvbus_types[hvid].name;
445 		sz = strlen(str) + 1;
446 		if (sz > pvr->pvr_keylen)
447 			return (ENOMEM);
448 		error = copyout(str, pvr->pvr_key, sz);
449 		return (error);
450 	default:
451 		return (ENOTTY);
452 	}
453 
454 	str = NULL;
455 	op = PVBUS_KVREAD;
456 
457 	switch (cmd) {
458 	case PVBUSIOC_KVWRITE:
459 		str = pvr->pvr_value;
460 		op = PVBUS_KVWRITE;
461 
462 		/* FALLTHROUGH */
463 	case PVBUSIOC_KVREAD:
464 		keylen = pvr->pvr_keylen;
465 		if ((error = pvbusgetstr(keylen, pvr->pvr_key, &key)) != 0)
466 			break;
467 
468 		valuelen = pvr->pvr_valuelen;
469 		if ((error = pvbusgetstr(valuelen, str, &value)) != 0)
470 			break;
471 
472 		/* Call driver-specific callback */
473 		if ((error = (hv->hv_kvop)(hv->hv_arg, op,
474 		    key, value, valuelen)) != 0)
475 			break;
476 
477 		sz = strlen(value) + 1;
478 		if ((error = copyout(value, pvr->pvr_value, sz)) != 0)
479 			break;
480 		break;
481 	default:
482 		error = ENOTTY;
483 		break;
484 	}
485 
486 	free(key, M_TEMP, keylen + 1);
487 	free(value, M_TEMP, valuelen + 1);
488 
489 	return (error);
490 }
491