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