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