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