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