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 uint8_t name[QEMU_FWCFG_MAX_NAME], 265 const uint32_t size, void *const data) 266 { 267 /* 268 * QEMU specifies count as big endian. 269 * Convert it to host endian to work with it. 270 */ 271 const uint32_t count = be32toh(fwcfg_sc.directory->be_count) + 1; 272 273 /* add file to items list */ 274 const uint32_t index = QEMU_FWCFG_FIRST_FILE_INDEX + count - 1; 275 const int error = qemu_fwcfg_add_item(QEMU_FWCFG_ARCHITECTURE_GENERIC, 276 index, size, data); 277 if (error != 0) { 278 return (error); 279 } 280 281 /* 282 * files should be sorted alphabetical, get index for new file 283 */ 284 uint32_t file_index; 285 for (file_index = 0; file_index < count - 1; ++file_index) { 286 if (strcmp(name, fwcfg_sc.directory->files[file_index].name) < 287 0) 288 break; 289 } 290 291 if (count > QEMU_FWCFG_MIN_FILES) { 292 /* alloc new file directory */ 293 const uint64_t new_size = sizeof(struct qemu_fwcfg_directory) + 294 count * sizeof(struct qemu_fwcfg_file); 295 struct qemu_fwcfg_directory *const new_directory = calloc(1, 296 new_size); 297 if (new_directory == NULL) { 298 warnx( 299 "%s: Unable to allocate a new qemu fwcfg files directory (count %d)", 300 __func__, count); 301 return (-ENOMEM); 302 } 303 304 /* copy files below file_index to new directory */ 305 memcpy(new_directory->files, fwcfg_sc.directory->files, 306 file_index * sizeof(struct qemu_fwcfg_file)); 307 308 /* copy files above file_index to directory */ 309 memcpy(&new_directory->files[file_index + 1], 310 &fwcfg_sc.directory->files[file_index], 311 (count - file_index) * sizeof(struct qemu_fwcfg_file)); 312 313 /* free old directory */ 314 free(fwcfg_sc.directory); 315 316 /* set directory pointer to new directory */ 317 fwcfg_sc.directory = new_directory; 318 319 /* adjust directory pointer */ 320 fwcfg_sc.items[0][QEMU_FWCFG_INDEX_FILE_DIR].data = 321 (uint8_t *)fwcfg_sc.directory; 322 } else { 323 /* shift files behind file_index */ 324 for (uint32_t i = QEMU_FWCFG_MIN_FILES - 1; i > file_index; 325 --i) { 326 memcpy(&fwcfg_sc.directory->files[i], 327 &fwcfg_sc.directory->files[i - 1], 328 sizeof(struct qemu_fwcfg_file)); 329 } 330 } 331 332 /* 333 * QEMU specifies count, size and index as big endian. 334 * Save these values in big endian to simplify guest reads of these 335 * values. 336 */ 337 fwcfg_sc.directory->be_count = htobe32(count); 338 fwcfg_sc.directory->files[file_index].be_size = htobe32(size); 339 fwcfg_sc.directory->files[file_index].be_selector = htobe16(index); 340 strcpy(fwcfg_sc.directory->files[file_index].name, name); 341 342 /* set new size for the fwcfg_file_directory */ 343 fwcfg_sc.items[0][QEMU_FWCFG_INDEX_FILE_DIR].size = 344 sizeof(struct qemu_fwcfg_directory) + 345 count * sizeof(struct qemu_fwcfg_file); 346 347 return (0); 348 } 349 350 int 351 qemu_fwcfg_init(struct vmctx *const ctx) 352 { 353 int error; 354 355 /* 356 * Bhyve supports fwctl (bhyve) and fwcfg (qemu) as firmware interfaces. 357 * Both are using the same ports. So, it's not possible to provide both 358 * interfaces at the same time to the guest. Therefore, only create acpi 359 * tables and register io ports for fwcfg, if it's used. 360 */ 361 if (strcmp(lpc_fwcfg(), "qemu") == 0) { 362 error = acpi_device_create(&fwcfg_sc.acpi_dev, ctx, 363 QEMU_FWCFG_ACPI_DEVICE_NAME, QEMU_FWCFG_ACPI_HARDWARE_ID); 364 if (error) { 365 warnx("%s: failed to create ACPI device for QEMU FwCfg", 366 __func__); 367 goto done; 368 } 369 370 error = acpi_device_add_res_fixed_ioport(fwcfg_sc.acpi_dev, 371 QEMU_FWCFG_SELECTOR_PORT_NUMBER, 2); 372 if (error) { 373 warnx("%s: failed to add fixed IO port for QEMU FwCfg", 374 __func__); 375 goto done; 376 } 377 378 /* add handlers for fwcfg ports */ 379 if ((error = qemu_fwcfg_register_port("qemu_fwcfg_selector", 380 QEMU_FWCFG_SELECTOR_PORT_NUMBER, 381 QEMU_FWCFG_SELECTOR_PORT_SIZE, 382 QEMU_FWCFG_SELECTOR_PORT_FLAGS, 383 qemu_fwcfg_selector_port_handler)) != 0) { 384 warnx( 385 "%s: Unable to register qemu fwcfg selector port 0x%x", 386 __func__, QEMU_FWCFG_SELECTOR_PORT_NUMBER); 387 goto done; 388 } 389 if ((error = qemu_fwcfg_register_port("qemu_fwcfg_data", 390 QEMU_FWCFG_DATA_PORT_NUMBER, QEMU_FWCFG_DATA_PORT_SIZE, 391 QEMU_FWCFG_DATA_PORT_FLAGS, 392 qemu_fwcfg_data_port_handler)) != 0) { 393 warnx( 394 "%s: Unable to register qemu fwcfg data port 0x%x", 395 __func__, QEMU_FWCFG_DATA_PORT_NUMBER); 396 goto done; 397 } 398 } 399 400 /* add common fwcfg items */ 401 if ((error = qemu_fwcfg_add_item_signature()) != 0) { 402 warnx("%s: Unable to add signature item", __func__); 403 goto done; 404 } 405 if ((error = qemu_fwcfg_add_item_id()) != 0) { 406 warnx("%s: Unable to add id item", __func__); 407 goto done; 408 } 409 if ((error = qemu_fwcfg_add_item_file_dir()) != 0) { 410 warnx("%s: Unable to add file_dir item", __func__); 411 goto done; 412 } 413 414 done: 415 if (error) { 416 acpi_device_destroy(fwcfg_sc.acpi_dev); 417 } 418 419 return (error); 420 } 421