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 "qemu_fwcfg.h" 21 22 #define QEMU_FWCFG_ACPI_DEVICE_NAME "FWCF" 23 #define QEMU_FWCFG_ACPI_HARDWARE_ID "QEMU0002" 24 25 #define QEMU_FWCFG_SELECTOR_PORT_NUMBER 0x510 26 #define QEMU_FWCFG_SELECTOR_PORT_SIZE 1 27 #define QEMU_FWCFG_SELECTOR_PORT_FLAGS IOPORT_F_INOUT 28 #define QEMU_FWCFG_DATA_PORT_NUMBER 0x511 29 #define QEMU_FWCFG_DATA_PORT_SIZE 1 30 #define QEMU_FWCFG_DATA_PORT_FLAGS \ 31 IOPORT_F_INOUT /* QEMU v2.4+ ignores writes */ 32 33 #define QEMU_FWCFG_ARCHITECTURE_MASK 0x0001 34 #define QEMU_FWCFG_INDEX_MASK 0x3FFF 35 36 #define QEMU_FWCFG_SELECT_READ 0 37 #define QEMU_FWCFG_SELECT_WRITE 1 38 39 #define QEMU_FWCFG_ARCHITECTURE_GENERIC 0 40 #define QEMU_FWCFG_ARCHITECTURE_SPECIFIC 1 41 42 #define QEMU_FWCFG_INDEX_SIGNATURE 0x00 43 #define QEMU_FWCFG_INDEX_ID 0x01 44 #define QEMU_FWCFG_INDEX_FILE_DIR 0x19 45 46 #define QEMU_FWCFG_MIN_FILES 10 47 48 #pragma pack(1) 49 50 union qemu_fwcfg_selector { 51 struct { 52 uint16_t index : 14; 53 uint16_t writeable : 1; 54 uint16_t architecture : 1; 55 }; 56 uint16_t bits; 57 }; 58 59 struct qemu_fwcfg_signature { 60 uint8_t signature[4]; 61 }; 62 63 struct qemu_fwcfg_id { 64 uint32_t interface : 1; /* always set */ 65 uint32_t DMA : 1; 66 uint32_t reserved : 30; 67 }; 68 69 struct qemu_fwcfg_file { 70 uint32_t be_size; 71 uint16_t be_selector; 72 uint16_t reserved; 73 uint8_t name[QEMU_FWCFG_MAX_NAME]; 74 }; 75 76 struct qemu_fwcfg_directory { 77 uint32_t be_count; 78 struct qemu_fwcfg_file files[0]; 79 }; 80 81 #pragma pack() 82 83 struct qemu_fwcfg_softc { 84 struct acpi_device *acpi_dev; 85 86 uint32_t data_offset; 87 union qemu_fwcfg_selector selector; 88 struct qemu_fwcfg_item items[QEMU_FWCFG_MAX_ARCHS] 89 [QEMU_FWCFG_MAX_ENTRIES]; 90 }; 91 92 static struct qemu_fwcfg_softc fwcfg_sc; 93 94 static int 95 qemu_fwcfg_selector_port_handler(struct vmctx *const ctx __unused, const int in, 96 const int port __unused, const int bytes, uint32_t *const eax, 97 void *const arg __unused) 98 { 99 if (bytes != sizeof(uint16_t)) { 100 warnx("%s: invalid size (%d) of IO port access", __func__, 101 bytes); 102 return (-1); 103 } 104 105 if (in) { 106 *eax = htole16(fwcfg_sc.selector.bits); 107 return (0); 108 } 109 110 fwcfg_sc.data_offset = 0; 111 fwcfg_sc.selector.bits = le16toh(*eax); 112 113 return (0); 114 } 115 116 static int 117 qemu_fwcfg_data_port_handler(struct vmctx *const ctx __unused, const int in, 118 const int port __unused, const int bytes, uint32_t *const eax, 119 void *const arg __unused) 120 { 121 if (bytes != sizeof(uint8_t)) { 122 warnx("%s: invalid size (%d) of IO port access", __func__, 123 bytes); 124 return (-1); 125 } 126 127 if (!in) { 128 warnx("%s: Writes to qemu fwcfg data port aren't allowed", 129 __func__); 130 return (-1); 131 } 132 133 /* get fwcfg item */ 134 struct qemu_fwcfg_item *const item = 135 &fwcfg_sc.items[fwcfg_sc.selector.architecture] 136 [fwcfg_sc.selector.index]; 137 if (item->data == NULL) { 138 warnx( 139 "%s: qemu fwcfg item doesn't exist (architecture %s index 0x%x)", 140 __func__, 141 fwcfg_sc.selector.architecture ? "specific" : "generic", 142 fwcfg_sc.selector.index); 143 *eax = 0x00; 144 return (0); 145 } else if (fwcfg_sc.data_offset >= item->size) { 146 warnx( 147 "%s: qemu fwcfg item read exceeds size (architecture %s index 0x%x size 0x%x offset 0x%x)", 148 __func__, 149 fwcfg_sc.selector.architecture ? "specific" : "generic", 150 fwcfg_sc.selector.index, item->size, fwcfg_sc.data_offset); 151 *eax = 0x00; 152 return (0); 153 } 154 155 /* return item data */ 156 *eax = item->data[fwcfg_sc.data_offset]; 157 fwcfg_sc.data_offset++; 158 159 return (0); 160 } 161 162 static int 163 qemu_fwcfg_add_item(const uint16_t architecture, const uint16_t index, 164 const uint32_t size, void *const data) 165 { 166 /* truncate architecture and index to their desired size */ 167 const uint16_t arch = architecture & QEMU_FWCFG_ARCHITECTURE_MASK; 168 const uint16_t idx = index & QEMU_FWCFG_INDEX_MASK; 169 170 /* get pointer to item specified by selector */ 171 struct qemu_fwcfg_item *const fwcfg_item = &fwcfg_sc.items[arch][idx]; 172 173 /* check if item is already used */ 174 if (fwcfg_item->data != NULL) { 175 warnx("%s: qemu fwcfg item exists (architecture %s index 0x%x)", 176 __func__, arch ? "specific" : "generic", idx); 177 return (-1); 178 } 179 180 /* save data of the item */ 181 fwcfg_item->size = size; 182 fwcfg_item->data = data; 183 184 return (0); 185 } 186 187 static int 188 qemu_fwcfg_add_item_file_dir(void) 189 { 190 const size_t size = sizeof(struct qemu_fwcfg_directory) + 191 QEMU_FWCFG_MIN_FILES * sizeof(struct qemu_fwcfg_file); 192 struct qemu_fwcfg_directory *const fwcfg_directory = calloc(1, size); 193 if (fwcfg_directory == NULL) { 194 return (ENOMEM); 195 } 196 197 fwcfg_sc.directory = fwcfg_directory; 198 199 return (qemu_fwcfg_add_item(QEMU_FWCFG_ARCHITECTURE_GENERIC, 200 QEMU_FWCFG_INDEX_FILE_DIR, sizeof(struct qemu_fwcfg_directory), 201 (uint8_t *)fwcfg_sc.directory)); 202 } 203 204 static int 205 qemu_fwcfg_add_item_id(void) 206 { 207 struct qemu_fwcfg_id *const fwcfg_id = calloc(1, 208 sizeof(struct qemu_fwcfg_id)); 209 if (fwcfg_id == NULL) { 210 return (ENOMEM); 211 } 212 213 fwcfg_id->interface = 1; 214 fwcfg_id->DMA = 0; 215 216 uint32_t *const le_fwcfg_id_ptr = (uint32_t *)fwcfg_id; 217 *le_fwcfg_id_ptr = htole32(*le_fwcfg_id_ptr); 218 219 return (qemu_fwcfg_add_item(QEMU_FWCFG_ARCHITECTURE_GENERIC, 220 QEMU_FWCFG_INDEX_ID, sizeof(struct qemu_fwcfg_id), 221 (uint8_t *)fwcfg_id)); 222 } 223 224 static int 225 qemu_fwcfg_add_item_signature(void) 226 { 227 struct qemu_fwcfg_signature *const fwcfg_signature = calloc(1, 228 sizeof(struct qemu_fwcfg_signature)); 229 if (fwcfg_signature == NULL) { 230 return (ENOMEM); 231 } 232 233 fwcfg_signature->signature[0] = 'Q'; 234 fwcfg_signature->signature[1] = 'E'; 235 fwcfg_signature->signature[2] = 'M'; 236 fwcfg_signature->signature[3] = 'U'; 237 238 return (qemu_fwcfg_add_item(QEMU_FWCFG_ARCHITECTURE_GENERIC, 239 QEMU_FWCFG_INDEX_SIGNATURE, sizeof(struct qemu_fwcfg_signature), 240 (uint8_t *)fwcfg_signature)); 241 } 242 243 static int 244 qemu_fwcfg_register_port(const char *const name, const int port, const int size, 245 const int flags, const inout_func_t handler) 246 { 247 struct inout_port iop; 248 249 bzero(&iop, sizeof(iop)); 250 iop.name = name; 251 iop.port = port; 252 iop.size = size; 253 iop.flags = flags; 254 iop.handler = handler; 255 256 return (register_inout(&iop)); 257 } 258 259 int 260 qemu_fwcfg_init(struct vmctx *const ctx) 261 { 262 int error; 263 264 error = acpi_device_create(&fwcfg_sc.acpi_dev, ctx, 265 QEMU_FWCFG_ACPI_DEVICE_NAME, QEMU_FWCFG_ACPI_HARDWARE_ID); 266 if (error) { 267 warnx("%s: failed to create ACPI device for QEMU FwCfg", 268 __func__); 269 goto done; 270 } 271 272 error = acpi_device_add_res_fixed_ioport(fwcfg_sc.acpi_dev, 273 QEMU_FWCFG_SELECTOR_PORT_NUMBER, 2); 274 if (error) { 275 warnx("%s: failed to add fixed IO port for QEMU FwCfg", 276 __func__); 277 goto done; 278 } 279 280 /* add handlers for fwcfg ports */ 281 if ((error = qemu_fwcfg_register_port("qemu_fwcfg_selector", 282 QEMU_FWCFG_SELECTOR_PORT_NUMBER, QEMU_FWCFG_SELECTOR_PORT_SIZE, 283 QEMU_FWCFG_SELECTOR_PORT_FLAGS, 284 qemu_fwcfg_selector_port_handler)) != 0) { 285 warnx("%s: Unable to register qemu fwcfg selector port 0x%x", 286 __func__, QEMU_FWCFG_SELECTOR_PORT_NUMBER); 287 goto done; 288 } 289 if ((error = qemu_fwcfg_register_port("qemu_fwcfg_data", 290 QEMU_FWCFG_DATA_PORT_NUMBER, QEMU_FWCFG_DATA_PORT_SIZE, 291 QEMU_FWCFG_DATA_PORT_FLAGS, qemu_fwcfg_data_port_handler)) != 0) { 292 warnx("%s: Unable to register qemu fwcfg data port 0x%x", 293 __func__, QEMU_FWCFG_DATA_PORT_NUMBER); 294 goto done; 295 } 296 297 /* add common fwcfg items */ 298 if ((error = qemu_fwcfg_add_item_signature()) != 0) { 299 warnx("%s: Unable to add signature item", __func__); 300 goto done; 301 } 302 if ((error = qemu_fwcfg_add_item_id()) != 0) { 303 warnx("%s: Unable to add id item", __func__); 304 goto done; 305 } 306 if ((error = qemu_fwcfg_add_item_file_dir()) != 0) { 307 warnx("%s: Unable to add file_dir item", __func__); 308 goto done; 309 } 310 311 done: 312 if (error) { 313 acpi_device_destroy(fwcfg_sc.acpi_dev); 314 } 315 316 return (error); 317 } 318