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