1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG 5 * Author: Corvin Köhne <c.koehne@beckhoff.com> 6 */ 7 8 #include <sys/param.h> 9 #include <sys/endian.h> 10 #include <sys/queue.h> 11 #include <sys/stat.h> 12 13 #include <machine/vmm.h> 14 15 #include <err.h> 16 #include <errno.h> 17 #include <fcntl.h> 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <string.h> 21 #include <unistd.h> 22 23 #include "acpi_device.h" 24 #include "bhyverun.h" 25 #include "inout.h" 26 #ifdef __amd64__ 27 #include "amd64/pci_lpc.h" 28 #endif 29 #include "qemu_fwcfg.h" 30 31 #define QEMU_FWCFG_ACPI_DEVICE_NAME "FWCF" 32 #define QEMU_FWCFG_ACPI_HARDWARE_ID "QEMU0002" 33 34 #define QEMU_FWCFG_SELECTOR_PORT_NUMBER 0x510 35 #define QEMU_FWCFG_SELECTOR_PORT_SIZE 1 36 #define QEMU_FWCFG_SELECTOR_PORT_FLAGS IOPORT_F_INOUT 37 #define QEMU_FWCFG_DATA_PORT_NUMBER 0x511 38 #define QEMU_FWCFG_DATA_PORT_SIZE 1 39 #define QEMU_FWCFG_DATA_PORT_FLAGS \ 40 IOPORT_F_INOUT /* QEMU v2.4+ ignores writes */ 41 42 #define QEMU_FWCFG_ARCHITECTURE_MASK 0x0001 43 #define QEMU_FWCFG_INDEX_MASK 0x3FFF 44 45 #define QEMU_FWCFG_SELECT_READ 0 46 #define QEMU_FWCFG_SELECT_WRITE 1 47 48 #define QEMU_FWCFG_ARCHITECTURE_GENERIC 0 49 #define QEMU_FWCFG_ARCHITECTURE_SPECIFIC 1 50 51 #define QEMU_FWCFG_INDEX_SIGNATURE 0x00 52 #define QEMU_FWCFG_INDEX_ID 0x01 53 #define QEMU_FWCFG_INDEX_NB_CPUS 0x05 54 #define QEMU_FWCFG_INDEX_MAX_CPUS 0x0F 55 #define QEMU_FWCFG_INDEX_FILE_DIR 0x19 56 57 #define QEMU_FWCFG_FIRST_FILE_INDEX 0x20 58 59 #define QEMU_FWCFG_MIN_FILES 10 60 61 #pragma pack(1) 62 63 union qemu_fwcfg_selector { 64 struct { 65 uint16_t index : 14; 66 uint16_t writeable : 1; 67 uint16_t architecture : 1; 68 }; 69 uint16_t bits; 70 }; 71 72 struct qemu_fwcfg_signature { 73 uint8_t signature[4]; 74 }; 75 76 struct qemu_fwcfg_id { 77 uint32_t interface : 1; /* always set */ 78 uint32_t DMA : 1; 79 uint32_t reserved : 30; 80 }; 81 82 struct qemu_fwcfg_file { 83 uint32_t be_size; 84 uint16_t be_selector; 85 uint16_t reserved; 86 uint8_t name[QEMU_FWCFG_MAX_NAME]; 87 }; 88 89 struct qemu_fwcfg_directory { 90 uint32_t be_count; 91 struct qemu_fwcfg_file files[0]; 92 }; 93 94 #pragma pack() 95 96 struct qemu_fwcfg_softc { 97 struct acpi_device *acpi_dev; 98 99 uint32_t data_offset; 100 union qemu_fwcfg_selector selector; 101 struct qemu_fwcfg_item items[QEMU_FWCFG_MAX_ARCHS] 102 [QEMU_FWCFG_MAX_ENTRIES]; 103 struct qemu_fwcfg_directory *directory; 104 }; 105 106 static struct qemu_fwcfg_softc fwcfg_sc; 107 108 struct qemu_fwcfg_user_file { 109 STAILQ_ENTRY(qemu_fwcfg_user_file) chain; 110 uint8_t name[QEMU_FWCFG_MAX_NAME]; 111 uint32_t size; 112 void *data; 113 }; 114 static STAILQ_HEAD(qemu_fwcfg_user_file_list, 115 qemu_fwcfg_user_file) user_files = STAILQ_HEAD_INITIALIZER(user_files); 116 117 static int 118 qemu_fwcfg_selector_port_handler(struct vmctx *const ctx __unused, const int in, 119 const int port __unused, const int bytes, uint32_t *const eax, 120 void *const arg __unused) 121 { 122 if (bytes != sizeof(uint16_t)) { 123 warnx("%s: invalid size (%d) of IO port access", __func__, 124 bytes); 125 return (-1); 126 } 127 128 if (in) { 129 *eax = htole16(fwcfg_sc.selector.bits); 130 return (0); 131 } 132 133 fwcfg_sc.data_offset = 0; 134 fwcfg_sc.selector.bits = le16toh(*eax); 135 136 return (0); 137 } 138 139 static int 140 qemu_fwcfg_data_port_handler(struct vmctx *const ctx __unused, const int in, 141 const int port __unused, const int bytes, uint32_t *const eax, 142 void *const arg __unused) 143 { 144 if (bytes != sizeof(uint8_t)) { 145 warnx("%s: invalid size (%d) of IO port access", __func__, 146 bytes); 147 return (-1); 148 } 149 150 if (!in) { 151 warnx("%s: Writes to qemu fwcfg data port aren't allowed", 152 __func__); 153 return (-1); 154 } 155 156 /* get fwcfg item */ 157 struct qemu_fwcfg_item *const item = 158 &fwcfg_sc.items[fwcfg_sc.selector.architecture] 159 [fwcfg_sc.selector.index]; 160 if (item->data == NULL) { 161 warnx( 162 "%s: qemu fwcfg item doesn't exist (architecture %s index 0x%x)", 163 __func__, 164 fwcfg_sc.selector.architecture ? "specific" : "generic", 165 fwcfg_sc.selector.index); 166 *eax = 0x00; 167 return (0); 168 } else if (fwcfg_sc.data_offset >= item->size) { 169 warnx( 170 "%s: qemu fwcfg item read exceeds size (architecture %s index 0x%x size 0x%x offset 0x%x)", 171 __func__, 172 fwcfg_sc.selector.architecture ? "specific" : "generic", 173 fwcfg_sc.selector.index, item->size, fwcfg_sc.data_offset); 174 *eax = 0x00; 175 return (0); 176 } 177 178 /* return item data */ 179 *eax = item->data[fwcfg_sc.data_offset]; 180 fwcfg_sc.data_offset++; 181 182 return (0); 183 } 184 185 static int 186 qemu_fwcfg_add_item(const uint16_t architecture, const uint16_t index, 187 const uint32_t size, void *const data) 188 { 189 /* truncate architecture and index to their desired size */ 190 const uint16_t arch = architecture & QEMU_FWCFG_ARCHITECTURE_MASK; 191 const uint16_t idx = index & QEMU_FWCFG_INDEX_MASK; 192 193 /* get pointer to item specified by selector */ 194 struct qemu_fwcfg_item *const fwcfg_item = &fwcfg_sc.items[arch][idx]; 195 196 /* check if item is already used */ 197 if (fwcfg_item->data != NULL) { 198 warnx("%s: qemu fwcfg item exists (architecture %s index 0x%x)", 199 __func__, arch ? "specific" : "generic", idx); 200 return (EEXIST); 201 } 202 203 /* save data of the item */ 204 fwcfg_item->size = size; 205 fwcfg_item->data = data; 206 207 return (0); 208 } 209 210 static int 211 qemu_fwcfg_add_item_file_dir(void) 212 { 213 const size_t size = sizeof(struct qemu_fwcfg_directory) + 214 QEMU_FWCFG_MIN_FILES * sizeof(struct qemu_fwcfg_file); 215 struct qemu_fwcfg_directory *const fwcfg_directory = calloc(1, size); 216 if (fwcfg_directory == NULL) { 217 return (ENOMEM); 218 } 219 220 fwcfg_sc.directory = fwcfg_directory; 221 222 return (qemu_fwcfg_add_item(QEMU_FWCFG_ARCHITECTURE_GENERIC, 223 QEMU_FWCFG_INDEX_FILE_DIR, sizeof(struct qemu_fwcfg_directory), 224 (uint8_t *)fwcfg_sc.directory)); 225 } 226 227 static int 228 qemu_fwcfg_add_item_id(void) 229 { 230 struct qemu_fwcfg_id *const fwcfg_id = calloc(1, 231 sizeof(struct qemu_fwcfg_id)); 232 if (fwcfg_id == NULL) { 233 return (ENOMEM); 234 } 235 236 fwcfg_id->interface = 1; 237 fwcfg_id->DMA = 0; 238 239 uint32_t *const le_fwcfg_id_ptr = (uint32_t *)fwcfg_id; 240 *le_fwcfg_id_ptr = htole32(*le_fwcfg_id_ptr); 241 242 return (qemu_fwcfg_add_item(QEMU_FWCFG_ARCHITECTURE_GENERIC, 243 QEMU_FWCFG_INDEX_ID, sizeof(struct qemu_fwcfg_id), 244 (uint8_t *)fwcfg_id)); 245 } 246 247 static int 248 qemu_fwcfg_add_item_max_cpus(void) 249 { 250 uint16_t *fwcfg_max_cpus = calloc(1, sizeof(uint16_t)); 251 if (fwcfg_max_cpus == NULL) { 252 return (ENOMEM); 253 } 254 255 /* 256 * We don't support cpu hotplug yet. For that reason, use guest_ncpus instead 257 * of maxcpus. 258 */ 259 *fwcfg_max_cpus = htole16(guest_ncpus); 260 261 return (qemu_fwcfg_add_item(QEMU_FWCFG_ARCHITECTURE_GENERIC, 262 QEMU_FWCFG_INDEX_MAX_CPUS, sizeof(uint16_t), fwcfg_max_cpus)); 263 } 264 265 static int 266 qemu_fwcfg_add_item_nb_cpus(void) 267 { 268 uint16_t *fwcfg_max_cpus = calloc(1, sizeof(uint16_t)); 269 if (fwcfg_max_cpus == NULL) { 270 return (ENOMEM); 271 } 272 273 *fwcfg_max_cpus = htole16(guest_ncpus); 274 275 return (qemu_fwcfg_add_item(QEMU_FWCFG_ARCHITECTURE_GENERIC, 276 QEMU_FWCFG_INDEX_NB_CPUS, sizeof(uint16_t), fwcfg_max_cpus)); 277 } 278 279 static int 280 qemu_fwcfg_add_item_signature(void) 281 { 282 struct qemu_fwcfg_signature *const fwcfg_signature = calloc(1, 283 sizeof(struct qemu_fwcfg_signature)); 284 if (fwcfg_signature == NULL) { 285 return (ENOMEM); 286 } 287 288 fwcfg_signature->signature[0] = 'Q'; 289 fwcfg_signature->signature[1] = 'E'; 290 fwcfg_signature->signature[2] = 'M'; 291 fwcfg_signature->signature[3] = 'U'; 292 293 return (qemu_fwcfg_add_item(QEMU_FWCFG_ARCHITECTURE_GENERIC, 294 QEMU_FWCFG_INDEX_SIGNATURE, sizeof(struct qemu_fwcfg_signature), 295 (uint8_t *)fwcfg_signature)); 296 } 297 298 static int 299 qemu_fwcfg_register_port(const char *const name, const int port, const int size, 300 const int flags, const inout_func_t handler) 301 { 302 struct inout_port iop; 303 304 bzero(&iop, sizeof(iop)); 305 iop.name = name; 306 iop.port = port; 307 iop.size = size; 308 iop.flags = flags; 309 iop.handler = handler; 310 311 return (register_inout(&iop)); 312 } 313 314 int 315 qemu_fwcfg_add_file(const char *name, const uint32_t size, void *const data) 316 { 317 if (strlen(name) >= QEMU_FWCFG_MAX_NAME) 318 return (EINVAL); 319 320 /* 321 * QEMU specifies count as big endian. 322 * Convert it to host endian to work with it. 323 */ 324 const uint32_t count = be32toh(fwcfg_sc.directory->be_count) + 1; 325 326 /* add file to items list */ 327 const uint32_t index = QEMU_FWCFG_FIRST_FILE_INDEX + count - 1; 328 const int error = qemu_fwcfg_add_item(QEMU_FWCFG_ARCHITECTURE_GENERIC, 329 index, size, data); 330 if (error != 0) { 331 return (error); 332 } 333 334 /* 335 * files should be sorted alphabetical, get index for new file 336 */ 337 uint32_t file_index; 338 for (file_index = 0; file_index < count - 1; ++file_index) { 339 if (strcmp(name, fwcfg_sc.directory->files[file_index].name) < 340 0) 341 break; 342 } 343 344 if (count > QEMU_FWCFG_MIN_FILES) { 345 /* alloc new file directory */ 346 const uint64_t new_size = sizeof(struct qemu_fwcfg_directory) + 347 count * sizeof(struct qemu_fwcfg_file); 348 struct qemu_fwcfg_directory *const new_directory = calloc(1, 349 new_size); 350 if (new_directory == NULL) { 351 warnx( 352 "%s: Unable to allocate a new qemu fwcfg files directory (count %d)", 353 __func__, count); 354 return (ENOMEM); 355 } 356 357 /* copy files below file_index to new directory */ 358 memcpy(new_directory->files, fwcfg_sc.directory->files, 359 file_index * sizeof(struct qemu_fwcfg_file)); 360 361 /* copy files above file_index to directory */ 362 memcpy(&new_directory->files[file_index + 1], 363 &fwcfg_sc.directory->files[file_index], 364 (count - file_index) * sizeof(struct qemu_fwcfg_file)); 365 366 /* free old directory */ 367 free(fwcfg_sc.directory); 368 369 /* set directory pointer to new directory */ 370 fwcfg_sc.directory = new_directory; 371 372 /* adjust directory pointer */ 373 fwcfg_sc.items[0][QEMU_FWCFG_INDEX_FILE_DIR].data = 374 (uint8_t *)fwcfg_sc.directory; 375 } else { 376 /* shift files behind file_index */ 377 for (uint32_t i = QEMU_FWCFG_MIN_FILES - 1; i > file_index; 378 --i) { 379 memcpy(&fwcfg_sc.directory->files[i], 380 &fwcfg_sc.directory->files[i - 1], 381 sizeof(struct qemu_fwcfg_file)); 382 } 383 } 384 385 /* 386 * QEMU specifies count, size and index as big endian. 387 * Save these values in big endian to simplify guest reads of these 388 * values. 389 */ 390 fwcfg_sc.directory->be_count = htobe32(count); 391 fwcfg_sc.directory->files[file_index].be_size = htobe32(size); 392 fwcfg_sc.directory->files[file_index].be_selector = htobe16(index); 393 strcpy(fwcfg_sc.directory->files[file_index].name, name); 394 395 /* set new size for the fwcfg_file_directory */ 396 fwcfg_sc.items[0][QEMU_FWCFG_INDEX_FILE_DIR].size = 397 sizeof(struct qemu_fwcfg_directory) + 398 count * sizeof(struct qemu_fwcfg_file); 399 400 return (0); 401 } 402 403 static int 404 qemu_fwcfg_add_user_files(void) 405 { 406 const struct qemu_fwcfg_user_file *fwcfg_file; 407 int error; 408 409 STAILQ_FOREACH(fwcfg_file, &user_files, chain) { 410 error = qemu_fwcfg_add_file(fwcfg_file->name, fwcfg_file->size, 411 fwcfg_file->data); 412 if (error) 413 return (error); 414 } 415 416 return (0); 417 } 418 419 static const struct acpi_device_emul qemu_fwcfg_acpi_device_emul = { 420 .name = QEMU_FWCFG_ACPI_DEVICE_NAME, 421 .hid = QEMU_FWCFG_ACPI_HARDWARE_ID, 422 }; 423 424 int 425 qemu_fwcfg_init(struct vmctx *const ctx) 426 { 427 int error; 428 bool fwcfg_enabled; 429 430 /* 431 * The fwcfg implementation currently only provides an I/O port 432 * interface and thus is amd64-specific for now. An MMIO interface is 433 * required for other platforms. 434 */ 435 #ifdef __amd64__ 436 fwcfg_enabled = strcmp(lpc_fwcfg(), "qemu") == 0; 437 #else 438 fwcfg_enabled = false; 439 #endif 440 441 /* 442 * Bhyve supports fwctl (bhyve) and fwcfg (qemu) as firmware interfaces. 443 * Both are using the same ports. So, it's not possible to provide both 444 * interfaces at the same time to the guest. Therefore, only create acpi 445 * tables and register io ports for fwcfg, if it's used. 446 */ 447 if (fwcfg_enabled) { 448 error = acpi_device_create(&fwcfg_sc.acpi_dev, &fwcfg_sc, ctx, 449 &qemu_fwcfg_acpi_device_emul); 450 if (error) { 451 warnx("%s: failed to create ACPI device for QEMU FwCfg", 452 __func__); 453 goto done; 454 } 455 456 error = acpi_device_add_res_fixed_ioport(fwcfg_sc.acpi_dev, 457 QEMU_FWCFG_SELECTOR_PORT_NUMBER, 2); 458 if (error) { 459 warnx("%s: failed to add fixed IO port for QEMU FwCfg", 460 __func__); 461 goto done; 462 } 463 464 /* add handlers for fwcfg ports */ 465 if ((error = qemu_fwcfg_register_port("qemu_fwcfg_selector", 466 QEMU_FWCFG_SELECTOR_PORT_NUMBER, 467 QEMU_FWCFG_SELECTOR_PORT_SIZE, 468 QEMU_FWCFG_SELECTOR_PORT_FLAGS, 469 qemu_fwcfg_selector_port_handler)) != 0) { 470 warnx( 471 "%s: Unable to register qemu fwcfg selector port 0x%x", 472 __func__, QEMU_FWCFG_SELECTOR_PORT_NUMBER); 473 goto done; 474 } 475 if ((error = qemu_fwcfg_register_port("qemu_fwcfg_data", 476 QEMU_FWCFG_DATA_PORT_NUMBER, QEMU_FWCFG_DATA_PORT_SIZE, 477 QEMU_FWCFG_DATA_PORT_FLAGS, 478 qemu_fwcfg_data_port_handler)) != 0) { 479 warnx( 480 "%s: Unable to register qemu fwcfg data port 0x%x", 481 __func__, QEMU_FWCFG_DATA_PORT_NUMBER); 482 goto done; 483 } 484 } 485 486 /* add common fwcfg items */ 487 if ((error = qemu_fwcfg_add_item_signature()) != 0) { 488 warnx("%s: Unable to add signature item", __func__); 489 goto done; 490 } 491 if ((error = qemu_fwcfg_add_item_id()) != 0) { 492 warnx("%s: Unable to add id item", __func__); 493 goto done; 494 } 495 if ((error = qemu_fwcfg_add_item_nb_cpus()) != 0) { 496 warnx("%s: Unable to add nb_cpus item", __func__); 497 goto done; 498 } 499 if ((error = qemu_fwcfg_add_item_max_cpus()) != 0) { 500 warnx("%s: Unable to add max_cpus item", __func__); 501 goto done; 502 } 503 if ((error = qemu_fwcfg_add_item_file_dir()) != 0) { 504 warnx("%s: Unable to add file_dir item", __func__); 505 } 506 507 /* add user defined fwcfg files */ 508 if ((error = qemu_fwcfg_add_user_files()) != 0) { 509 warnx("%s: Unable to add user files", __func__); 510 goto done; 511 } 512 513 done: 514 if (error) { 515 acpi_device_destroy(fwcfg_sc.acpi_dev); 516 } 517 518 return (error); 519 } 520 521 static void 522 qemu_fwcfg_usage(const char *opt) 523 { 524 warnx("Invalid fw_cfg option \"%s\"", opt); 525 warnx("-f [name=]<name>,(string|file)=<value>"); 526 } 527 528 /* 529 * Parses the cmdline argument for user defined fw_cfg items. The cmdline 530 * argument has the format: 531 * "-f [name=]<name>,(string|file)=<value>" 532 * 533 * E.g.: "-f opt/com.page/example,string=Hello" 534 */ 535 int 536 qemu_fwcfg_parse_cmdline_arg(const char *opt) 537 { 538 struct qemu_fwcfg_user_file *fwcfg_file; 539 struct stat sb; 540 const char *opt_ptr, *opt_end; 541 ssize_t bytes_read; 542 int fd; 543 544 fwcfg_file = malloc(sizeof(*fwcfg_file)); 545 if (fwcfg_file == NULL) { 546 warnx("Unable to allocate fw_cfg_user_file"); 547 return (ENOMEM); 548 } 549 550 /* get pointer to <name> */ 551 opt_ptr = opt; 552 /* If [name=] is specified, skip it */ 553 if (strncmp(opt_ptr, "name=", sizeof("name=") - 1) == 0) { 554 opt_ptr += sizeof("name=") - 1; 555 } 556 557 /* get the end of <name> */ 558 opt_end = strchr(opt_ptr, ','); 559 if (opt_end == NULL) { 560 qemu_fwcfg_usage(opt); 561 return (EINVAL); 562 } 563 564 /* check if <name> is too long */ 565 if (opt_end - opt_ptr >= QEMU_FWCFG_MAX_NAME) { 566 warnx("fw_cfg name too long: \"%s\"", opt); 567 return (EINVAL); 568 } 569 570 /* save <name> */ 571 strncpy(fwcfg_file->name, opt_ptr, opt_end - opt_ptr); 572 fwcfg_file->name[opt_end - opt_ptr] = '\0'; 573 574 /* set opt_ptr and opt_end to <value> */ 575 opt_ptr = opt_end + 1; 576 opt_end = opt_ptr + strlen(opt_ptr); 577 578 if (strncmp(opt_ptr, "string=", sizeof("string=") - 1) == 0) { 579 opt_ptr += sizeof("string=") - 1; 580 fwcfg_file->data = strdup(opt_ptr); 581 if (fwcfg_file->data == NULL) { 582 warnx("Can't duplicate fw_cfg_user_file string \"%s\"", 583 opt_ptr); 584 return (ENOMEM); 585 } 586 fwcfg_file->size = strlen(opt_ptr) + 1; 587 } else if (strncmp(opt_ptr, "file=", sizeof("file=") - 1) == 0) { 588 opt_ptr += sizeof("file=") - 1; 589 590 fd = open(opt_ptr, O_RDONLY); 591 if (fd < 0) { 592 warn("Can't open fw_cfg_user_file file \"%s\"", 593 opt_ptr); 594 return (EINVAL); 595 } 596 597 if (fstat(fd, &sb) < 0) { 598 warn("Unable to get size of file \"%s\"", opt_ptr); 599 close(fd); 600 return (-1); 601 } 602 603 fwcfg_file->data = malloc(sb.st_size); 604 if (fwcfg_file->data == NULL) { 605 warnx( 606 "Can't allocate fw_cfg_user_file file \"%s\" (size: 0x%16lx)", 607 opt_ptr, sb.st_size); 608 close(fd); 609 return (ENOMEM); 610 } 611 bytes_read = read(fd, fwcfg_file->data, sb.st_size); 612 if (bytes_read < 0 || bytes_read != sb.st_size) { 613 warn("Unable to read file \"%s\"", opt_ptr); 614 free(fwcfg_file->data); 615 close(fd); 616 return (-1); 617 } 618 fwcfg_file->size = bytes_read; 619 620 close(fd); 621 } else { 622 qemu_fwcfg_usage(opt); 623 return (EINVAL); 624 } 625 626 STAILQ_INSERT_TAIL(&user_files, fwcfg_file, chain); 627 628 return (0); 629 } 630