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