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