1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 11 #include <machine/vmm.h> 12 13 #include <err.h> 14 #include <errno.h> 15 #include <stdlib.h> 16 #include <string.h> 17 18 #include "acpi_device.h" 19 #include "bhyverun.h" 20 #include "inout.h" 21 #include "pci_lpc.h" 22 #include "qemu_fwcfg.h" 23 24 #define QEMU_FWCFG_ACPI_DEVICE_NAME "FWCF" 25 #define QEMU_FWCFG_ACPI_HARDWARE_ID "QEMU0002" 26 27 #define QEMU_FWCFG_SELECTOR_PORT_NUMBER 0x510 28 #define QEMU_FWCFG_SELECTOR_PORT_SIZE 1 29 #define QEMU_FWCFG_SELECTOR_PORT_FLAGS IOPORT_F_INOUT 30 #define QEMU_FWCFG_DATA_PORT_NUMBER 0x511 31 #define QEMU_FWCFG_DATA_PORT_SIZE 1 32 #define QEMU_FWCFG_DATA_PORT_FLAGS \ 33 IOPORT_F_INOUT /* QEMU v2.4+ ignores writes */ 34 35 #define QEMU_FWCFG_ARCHITECTURE_MASK 0x0001 36 #define QEMU_FWCFG_INDEX_MASK 0x3FFF 37 38 #define QEMU_FWCFG_SELECT_READ 0 39 #define QEMU_FWCFG_SELECT_WRITE 1 40 41 #define QEMU_FWCFG_ARCHITECTURE_GENERIC 0 42 #define QEMU_FWCFG_ARCHITECTURE_SPECIFIC 1 43 44 #define QEMU_FWCFG_INDEX_SIGNATURE 0x00 45 #define QEMU_FWCFG_INDEX_ID 0x01 46 #define QEMU_FWCFG_INDEX_NB_CPUS 0x05 47 #define QEMU_FWCFG_INDEX_MAX_CPUS 0x0F 48 #define QEMU_FWCFG_INDEX_FILE_DIR 0x19 49 50 #define QEMU_FWCFG_FIRST_FILE_INDEX 0x20 51 52 #define QEMU_FWCFG_MIN_FILES 10 53 54 #pragma pack(1) 55 56 union qemu_fwcfg_selector { 57 struct { 58 uint16_t index : 14; 59 uint16_t writeable : 1; 60 uint16_t architecture : 1; 61 }; 62 uint16_t bits; 63 }; 64 65 struct qemu_fwcfg_signature { 66 uint8_t signature[4]; 67 }; 68 69 struct qemu_fwcfg_id { 70 uint32_t interface : 1; /* always set */ 71 uint32_t DMA : 1; 72 uint32_t reserved : 30; 73 }; 74 75 struct qemu_fwcfg_file { 76 uint32_t be_size; 77 uint16_t be_selector; 78 uint16_t reserved; 79 uint8_t name[QEMU_FWCFG_MAX_NAME]; 80 }; 81 82 struct qemu_fwcfg_directory { 83 uint32_t be_count; 84 struct qemu_fwcfg_file files[0]; 85 }; 86 87 #pragma pack() 88 89 struct qemu_fwcfg_softc { 90 struct acpi_device *acpi_dev; 91 92 uint32_t data_offset; 93 union qemu_fwcfg_selector selector; 94 struct qemu_fwcfg_item items[QEMU_FWCFG_MAX_ARCHS] 95 [QEMU_FWCFG_MAX_ENTRIES]; 96 struct qemu_fwcfg_directory *directory; 97 }; 98 99 static struct qemu_fwcfg_softc fwcfg_sc; 100 101 static int 102 qemu_fwcfg_selector_port_handler(struct vmctx *const ctx __unused, const int in, 103 const int port __unused, const int bytes, uint32_t *const eax, 104 void *const arg __unused) 105 { 106 if (bytes != sizeof(uint16_t)) { 107 warnx("%s: invalid size (%d) of IO port access", __func__, 108 bytes); 109 return (-1); 110 } 111 112 if (in) { 113 *eax = htole16(fwcfg_sc.selector.bits); 114 return (0); 115 } 116 117 fwcfg_sc.data_offset = 0; 118 fwcfg_sc.selector.bits = le16toh(*eax); 119 120 return (0); 121 } 122 123 static int 124 qemu_fwcfg_data_port_handler(struct vmctx *const ctx __unused, const int in, 125 const int port __unused, const int bytes, uint32_t *const eax, 126 void *const arg __unused) 127 { 128 if (bytes != sizeof(uint8_t)) { 129 warnx("%s: invalid size (%d) of IO port access", __func__, 130 bytes); 131 return (-1); 132 } 133 134 if (!in) { 135 warnx("%s: Writes to qemu fwcfg data port aren't allowed", 136 __func__); 137 return (-1); 138 } 139 140 /* get fwcfg item */ 141 struct qemu_fwcfg_item *const item = 142 &fwcfg_sc.items[fwcfg_sc.selector.architecture] 143 [fwcfg_sc.selector.index]; 144 if (item->data == NULL) { 145 warnx( 146 "%s: qemu fwcfg item doesn't exist (architecture %s index 0x%x)", 147 __func__, 148 fwcfg_sc.selector.architecture ? "specific" : "generic", 149 fwcfg_sc.selector.index); 150 *eax = 0x00; 151 return (0); 152 } else if (fwcfg_sc.data_offset >= item->size) { 153 warnx( 154 "%s: qemu fwcfg item read exceeds size (architecture %s index 0x%x size 0x%x offset 0x%x)", 155 __func__, 156 fwcfg_sc.selector.architecture ? "specific" : "generic", 157 fwcfg_sc.selector.index, item->size, fwcfg_sc.data_offset); 158 *eax = 0x00; 159 return (0); 160 } 161 162 /* return item data */ 163 *eax = item->data[fwcfg_sc.data_offset]; 164 fwcfg_sc.data_offset++; 165 166 return (0); 167 } 168 169 static int 170 qemu_fwcfg_add_item(const uint16_t architecture, const uint16_t index, 171 const uint32_t size, void *const data) 172 { 173 /* truncate architecture and index to their desired size */ 174 const uint16_t arch = architecture & QEMU_FWCFG_ARCHITECTURE_MASK; 175 const uint16_t idx = index & QEMU_FWCFG_INDEX_MASK; 176 177 /* get pointer to item specified by selector */ 178 struct qemu_fwcfg_item *const fwcfg_item = &fwcfg_sc.items[arch][idx]; 179 180 /* check if item is already used */ 181 if (fwcfg_item->data != NULL) { 182 warnx("%s: qemu fwcfg item exists (architecture %s index 0x%x)", 183 __func__, arch ? "specific" : "generic", idx); 184 return (EEXIST); 185 } 186 187 /* save data of the item */ 188 fwcfg_item->size = size; 189 fwcfg_item->data = data; 190 191 return (0); 192 } 193 194 static int 195 qemu_fwcfg_add_item_file_dir(void) 196 { 197 const size_t size = sizeof(struct qemu_fwcfg_directory) + 198 QEMU_FWCFG_MIN_FILES * sizeof(struct qemu_fwcfg_file); 199 struct qemu_fwcfg_directory *const fwcfg_directory = calloc(1, size); 200 if (fwcfg_directory == NULL) { 201 return (ENOMEM); 202 } 203 204 fwcfg_sc.directory = fwcfg_directory; 205 206 return (qemu_fwcfg_add_item(QEMU_FWCFG_ARCHITECTURE_GENERIC, 207 QEMU_FWCFG_INDEX_FILE_DIR, sizeof(struct qemu_fwcfg_directory), 208 (uint8_t *)fwcfg_sc.directory)); 209 } 210 211 static int 212 qemu_fwcfg_add_item_id(void) 213 { 214 struct qemu_fwcfg_id *const fwcfg_id = calloc(1, 215 sizeof(struct qemu_fwcfg_id)); 216 if (fwcfg_id == NULL) { 217 return (ENOMEM); 218 } 219 220 fwcfg_id->interface = 1; 221 fwcfg_id->DMA = 0; 222 223 uint32_t *const le_fwcfg_id_ptr = (uint32_t *)fwcfg_id; 224 *le_fwcfg_id_ptr = htole32(*le_fwcfg_id_ptr); 225 226 return (qemu_fwcfg_add_item(QEMU_FWCFG_ARCHITECTURE_GENERIC, 227 QEMU_FWCFG_INDEX_ID, sizeof(struct qemu_fwcfg_id), 228 (uint8_t *)fwcfg_id)); 229 } 230 231 static int 232 qemu_fwcfg_add_item_max_cpus(void) 233 { 234 uint16_t *fwcfg_max_cpus = calloc(1, sizeof(uint16_t)); 235 if (fwcfg_max_cpus == NULL) { 236 return (ENOMEM); 237 } 238 239 /* 240 * We don't support cpu hotplug yet. For that reason, use guest_ncpus instead 241 * of maxcpus. 242 */ 243 *fwcfg_max_cpus = htole16(guest_ncpus); 244 245 return (qemu_fwcfg_add_item(QEMU_FWCFG_ARCHITECTURE_GENERIC, 246 QEMU_FWCFG_INDEX_MAX_CPUS, sizeof(uint16_t), fwcfg_max_cpus)); 247 } 248 249 static int 250 qemu_fwcfg_add_item_nb_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 *fwcfg_max_cpus = htole16(guest_ncpus); 258 259 return (qemu_fwcfg_add_item(QEMU_FWCFG_ARCHITECTURE_GENERIC, 260 QEMU_FWCFG_INDEX_NB_CPUS, sizeof(uint16_t), fwcfg_max_cpus)); 261 } 262 263 static int 264 qemu_fwcfg_add_item_signature(void) 265 { 266 struct qemu_fwcfg_signature *const fwcfg_signature = calloc(1, 267 sizeof(struct qemu_fwcfg_signature)); 268 if (fwcfg_signature == NULL) { 269 return (ENOMEM); 270 } 271 272 fwcfg_signature->signature[0] = 'Q'; 273 fwcfg_signature->signature[1] = 'E'; 274 fwcfg_signature->signature[2] = 'M'; 275 fwcfg_signature->signature[3] = 'U'; 276 277 return (qemu_fwcfg_add_item(QEMU_FWCFG_ARCHITECTURE_GENERIC, 278 QEMU_FWCFG_INDEX_SIGNATURE, sizeof(struct qemu_fwcfg_signature), 279 (uint8_t *)fwcfg_signature)); 280 } 281 282 static int 283 qemu_fwcfg_register_port(const char *const name, const int port, const int size, 284 const int flags, const inout_func_t handler) 285 { 286 struct inout_port iop; 287 288 bzero(&iop, sizeof(iop)); 289 iop.name = name; 290 iop.port = port; 291 iop.size = size; 292 iop.flags = flags; 293 iop.handler = handler; 294 295 return (register_inout(&iop)); 296 } 297 298 int 299 qemu_fwcfg_add_file(const char *name, const uint32_t size, void *const data) 300 { 301 if (strlen(name) >= QEMU_FWCFG_MAX_NAME) 302 return (EINVAL); 303 304 /* 305 * QEMU specifies count as big endian. 306 * Convert it to host endian to work with it. 307 */ 308 const uint32_t count = be32toh(fwcfg_sc.directory->be_count) + 1; 309 310 /* add file to items list */ 311 const uint32_t index = QEMU_FWCFG_FIRST_FILE_INDEX + count - 1; 312 const int error = qemu_fwcfg_add_item(QEMU_FWCFG_ARCHITECTURE_GENERIC, 313 index, size, data); 314 if (error != 0) { 315 return (error); 316 } 317 318 /* 319 * files should be sorted alphabetical, get index for new file 320 */ 321 uint32_t file_index; 322 for (file_index = 0; file_index < count - 1; ++file_index) { 323 if (strcmp(name, fwcfg_sc.directory->files[file_index].name) < 324 0) 325 break; 326 } 327 328 if (count > QEMU_FWCFG_MIN_FILES) { 329 /* alloc new file directory */ 330 const uint64_t new_size = sizeof(struct qemu_fwcfg_directory) + 331 count * sizeof(struct qemu_fwcfg_file); 332 struct qemu_fwcfg_directory *const new_directory = calloc(1, 333 new_size); 334 if (new_directory == NULL) { 335 warnx( 336 "%s: Unable to allocate a new qemu fwcfg files directory (count %d)", 337 __func__, count); 338 return (ENOMEM); 339 } 340 341 /* copy files below file_index to new directory */ 342 memcpy(new_directory->files, fwcfg_sc.directory->files, 343 file_index * sizeof(struct qemu_fwcfg_file)); 344 345 /* copy files above file_index to directory */ 346 memcpy(&new_directory->files[file_index + 1], 347 &fwcfg_sc.directory->files[file_index], 348 (count - file_index) * sizeof(struct qemu_fwcfg_file)); 349 350 /* free old directory */ 351 free(fwcfg_sc.directory); 352 353 /* set directory pointer to new directory */ 354 fwcfg_sc.directory = new_directory; 355 356 /* adjust directory pointer */ 357 fwcfg_sc.items[0][QEMU_FWCFG_INDEX_FILE_DIR].data = 358 (uint8_t *)fwcfg_sc.directory; 359 } else { 360 /* shift files behind file_index */ 361 for (uint32_t i = QEMU_FWCFG_MIN_FILES - 1; i > file_index; 362 --i) { 363 memcpy(&fwcfg_sc.directory->files[i], 364 &fwcfg_sc.directory->files[i - 1], 365 sizeof(struct qemu_fwcfg_file)); 366 } 367 } 368 369 /* 370 * QEMU specifies count, size and index as big endian. 371 * Save these values in big endian to simplify guest reads of these 372 * values. 373 */ 374 fwcfg_sc.directory->be_count = htobe32(count); 375 fwcfg_sc.directory->files[file_index].be_size = htobe32(size); 376 fwcfg_sc.directory->files[file_index].be_selector = htobe16(index); 377 strcpy(fwcfg_sc.directory->files[file_index].name, name); 378 379 /* set new size for the fwcfg_file_directory */ 380 fwcfg_sc.items[0][QEMU_FWCFG_INDEX_FILE_DIR].size = 381 sizeof(struct qemu_fwcfg_directory) + 382 count * sizeof(struct qemu_fwcfg_file); 383 384 return (0); 385 } 386 387 static const struct acpi_device_emul qemu_fwcfg_acpi_device_emul = { 388 .name = QEMU_FWCFG_ACPI_DEVICE_NAME, 389 .hid = QEMU_FWCFG_ACPI_HARDWARE_ID, 390 }; 391 392 int 393 qemu_fwcfg_init(struct vmctx *const ctx) 394 { 395 int error; 396 397 /* 398 * Bhyve supports fwctl (bhyve) and fwcfg (qemu) as firmware interfaces. 399 * Both are using the same ports. So, it's not possible to provide both 400 * interfaces at the same time to the guest. Therefore, only create acpi 401 * tables and register io ports for fwcfg, if it's used. 402 */ 403 if (strcmp(lpc_fwcfg(), "qemu") == 0) { 404 error = acpi_device_create(&fwcfg_sc.acpi_dev, &fwcfg_sc, ctx, 405 &qemu_fwcfg_acpi_device_emul); 406 if (error) { 407 warnx("%s: failed to create ACPI device for QEMU FwCfg", 408 __func__); 409 goto done; 410 } 411 412 error = acpi_device_add_res_fixed_ioport(fwcfg_sc.acpi_dev, 413 QEMU_FWCFG_SELECTOR_PORT_NUMBER, 2); 414 if (error) { 415 warnx("%s: failed to add fixed IO port for QEMU FwCfg", 416 __func__); 417 goto done; 418 } 419 420 /* add handlers for fwcfg ports */ 421 if ((error = qemu_fwcfg_register_port("qemu_fwcfg_selector", 422 QEMU_FWCFG_SELECTOR_PORT_NUMBER, 423 QEMU_FWCFG_SELECTOR_PORT_SIZE, 424 QEMU_FWCFG_SELECTOR_PORT_FLAGS, 425 qemu_fwcfg_selector_port_handler)) != 0) { 426 warnx( 427 "%s: Unable to register qemu fwcfg selector port 0x%x", 428 __func__, QEMU_FWCFG_SELECTOR_PORT_NUMBER); 429 goto done; 430 } 431 if ((error = qemu_fwcfg_register_port("qemu_fwcfg_data", 432 QEMU_FWCFG_DATA_PORT_NUMBER, QEMU_FWCFG_DATA_PORT_SIZE, 433 QEMU_FWCFG_DATA_PORT_FLAGS, 434 qemu_fwcfg_data_port_handler)) != 0) { 435 warnx( 436 "%s: Unable to register qemu fwcfg data port 0x%x", 437 __func__, QEMU_FWCFG_DATA_PORT_NUMBER); 438 goto done; 439 } 440 } 441 442 /* add common fwcfg items */ 443 if ((error = qemu_fwcfg_add_item_signature()) != 0) { 444 warnx("%s: Unable to add signature item", __func__); 445 goto done; 446 } 447 if ((error = qemu_fwcfg_add_item_id()) != 0) { 448 warnx("%s: Unable to add id item", __func__); 449 goto done; 450 } 451 if ((error = qemu_fwcfg_add_item_nb_cpus()) != 0) { 452 warnx("%s: Unable to add nb_cpus item", __func__); 453 goto done; 454 } 455 if ((error = qemu_fwcfg_add_item_max_cpus()) != 0) { 456 warnx("%s: Unable to add max_cpus item", __func__); 457 goto done; 458 } 459 if ((error = qemu_fwcfg_add_item_file_dir()) != 0) { 460 warnx("%s: Unable to add file_dir item", __func__); 461 goto done; 462 } 463 464 done: 465 if (error) { 466 acpi_device_destroy(fwcfg_sc.acpi_dev); 467 } 468 469 return (error); 470 } 471