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