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