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