1 /* $OpenBSD: pvbus.c,v 1.20 2020/01/24 05:14:51 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/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/rndvar.h> 42 43 #include <dev/pv/pvvar.h> 44 #include <dev/pv/pvreg.h> 45 46 int has_hv_cpuid = 0; 47 48 extern char *hw_vendor; 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 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 void 304 pvbus_hyperv(struct pvbus_hv *hv) 305 { 306 uint32_t regs[4]; 307 308 CPUID(hv->hv_base + CPUID_OFFSET_HYPERV_FEATURES, 309 regs[0], regs[1], regs[2], regs[3]); 310 hv->hv_features = regs[0]; 311 312 CPUID(hv->hv_base + CPUID_OFFSET_HYPERV_VERSION, 313 regs[0], regs[1], regs[2], regs[3]); 314 hv->hv_major = (regs[1] & HYPERV_VERSION_EBX_MAJOR_M) >> 315 HYPERV_VERSION_EBX_MAJOR_S; 316 hv->hv_minor = (regs[1] & HYPERV_VERSION_EBX_MINOR_M) >> 317 HYPERV_VERSION_EBX_MINOR_S; 318 } 319 320 void 321 pvbus_hyperv_print(struct pvbus_hv *hv) 322 { 323 printf(" %u.%u", hv->hv_major, hv->hv_minor); 324 } 325 326 void 327 pvbus_xen(struct pvbus_hv *hv) 328 { 329 uint32_t regs[4]; 330 331 CPUID(hv->hv_base + CPUID_OFFSET_XEN_VERSION, 332 regs[0], regs[1], regs[2], regs[3]); 333 hv->hv_major = regs[0] >> XEN_VERSION_MAJOR_S; 334 hv->hv_minor = regs[0] & XEN_VERSION_MINOR_M; 335 336 /* x2apic is broken in Xen 4.2 or older */ 337 if ((hv->hv_major < 4) || 338 (hv->hv_major == 4 && hv->hv_minor < 3)) { 339 /* Remove CPU flag for x2apic */ 340 cpu_ecxfeature &= ~CPUIDECX_X2APIC; 341 } 342 } 343 344 void 345 pvbus_xen_print(struct pvbus_hv *hv) 346 { 347 printf(" %u.%u", hv->hv_major, hv->hv_minor); 348 } 349 350 int 351 pvbus_minor(struct pvbus_softc *sc, dev_t dev) 352 { 353 int hvid, cnt; 354 struct pvbus_hv *hv; 355 356 for (hvid = 0, cnt = 0; hvid < PVBUS_MAX; hvid++) { 357 hv = &sc->pvbus_hv[hvid]; 358 if (hv->hv_base == 0) 359 continue; 360 if (minor(dev) == cnt++) 361 return (hvid); 362 } 363 364 return (-1); 365 } 366 367 int 368 pvbusopen(dev_t dev, int flags, int mode, struct proc *p) 369 { 370 if (pvbus_softc == NULL) 371 return (ENODEV); 372 if (pvbus_minor(pvbus_softc, dev) == -1) 373 return (ENXIO); 374 return (0); 375 } 376 377 int 378 pvbusclose(dev_t dev, int flags, int mode, struct proc *p) 379 { 380 if (pvbus_softc == NULL) 381 return (ENODEV); 382 if (pvbus_minor(pvbus_softc, dev) == -1) 383 return (ENXIO); 384 return (0); 385 } 386 387 int 388 pvbusgetstr(size_t srclen, const char *src, char **dstp) 389 { 390 int error = 0; 391 char *dst; 392 393 /* 394 * Reject size that is too short or obviously too long: 395 * - at least one byte for the nul terminator. 396 * - PAGE_SIZE is an arbitrary value, but known pv backends seem 397 * to have a hard (PAGE_SIZE - x) limit in their messaging. 398 */ 399 if (srclen < 1) 400 return (EINVAL); 401 else if (srclen > PAGE_SIZE) 402 return (ENAMETOOLONG); 403 404 *dstp = dst = malloc(srclen + 1, M_TEMP|M_ZERO, M_WAITOK); 405 if (src != NULL) { 406 error = copyin(src, dst, srclen); 407 dst[srclen] = '\0'; 408 } 409 410 return (error); 411 } 412 413 int 414 pvbusioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) 415 { 416 struct pvbus_req *pvr = (struct pvbus_req *)data; 417 struct pvbus_softc *sc = pvbus_softc; 418 char *value = NULL, *key = NULL; 419 const char *str = NULL; 420 size_t valuelen = 0, keylen = 0, sz; 421 int hvid, error = 0, op; 422 struct pvbus_hv *hv; 423 424 if (sc == NULL) 425 return (ENODEV); 426 if ((hvid = pvbus_minor(sc, dev)) == -1) 427 return (ENXIO); 428 429 switch (cmd) { 430 case PVBUSIOC_KVWRITE: 431 if ((flags & FWRITE) == 0) 432 return (EPERM); 433 case PVBUSIOC_KVREAD: 434 hv = &sc->pvbus_hv[hvid]; 435 if (hv->hv_base == 0 || hv->hv_kvop == NULL) 436 return (ENXIO); 437 break; 438 case PVBUSIOC_TYPE: 439 str = pvbus_types[hvid].name; 440 sz = strlen(str) + 1; 441 if (sz > pvr->pvr_keylen) 442 return (ENOMEM); 443 error = copyout(str, pvr->pvr_key, sz); 444 return (error); 445 default: 446 return (ENOTTY); 447 } 448 449 str = NULL; 450 op = PVBUS_KVREAD; 451 452 switch (cmd) { 453 case PVBUSIOC_KVWRITE: 454 str = pvr->pvr_value; 455 op = PVBUS_KVWRITE; 456 457 /* FALLTHROUGH */ 458 case PVBUSIOC_KVREAD: 459 keylen = pvr->pvr_keylen; 460 if ((error = pvbusgetstr(keylen, pvr->pvr_key, &key)) != 0) 461 break; 462 463 valuelen = pvr->pvr_valuelen; 464 if ((error = pvbusgetstr(valuelen, str, &value)) != 0) 465 break; 466 467 /* Call driver-specific callback */ 468 if ((error = (hv->hv_kvop)(hv->hv_arg, op, 469 key, value, valuelen)) != 0) 470 break; 471 472 sz = strlen(value) + 1; 473 if ((error = copyout(value, pvr->pvr_value, sz)) != 0) 474 break; 475 break; 476 default: 477 error = ENOTTY; 478 break; 479 } 480 481 free(key, M_TEMP, keylen + 1); 482 free(value, M_TEMP, valuelen + 1); 483 484 return (error); 485 } 486