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