2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
5 * Author: Corvin Köhne <c.koehne@beckhoff.com>
10 #include <machine/vmm.h>
17 #include "acpi_device.h"
19 #include "qemu_fwcfg.h"
21 #define QEMU_FWCFG_ACPI_DEVICE_NAME "FWCF"
22 #define QEMU_FWCFG_ACPI_HARDWARE_ID "QEMU0002"
24 #define QEMU_FWCFG_SELECTOR_PORT_NUMBER 0x510
25 #define QEMU_FWCFG_SELECTOR_PORT_SIZE 1
26 #define QEMU_FWCFG_SELECTOR_PORT_FLAGS IOPORT_F_INOUT
27 #define QEMU_FWCFG_DATA_PORT_NUMBER 0x511
28 #define QEMU_FWCFG_DATA_PORT_SIZE 1
29 #define QEMU_FWCFG_DATA_PORT_FLAGS \
30 IOPORT_F_INOUT /* QEMU v2.4+ ignores writes */
32 #define QEMU_FWCFG_ARCHITECTURE_MASK 0x0001
33 #define QEMU_FWCFG_INDEX_MASK 0x3FFF
35 #define QEMU_FWCFG_SELECT_READ 0
36 #define QEMU_FWCFG_SELECT_WRITE 1
38 #define QEMU_FWCFG_ARCHITECTURE_GENERIC 0
39 #define QEMU_FWCFG_ARCHITECTURE_SPECIFIC 1
43 union qemu_fwcfg_selector {
46 uint16_t writeable : 1;
47 uint16_t architecture : 1;
54 struct qemu_fwcfg_softc {
55 struct acpi_device *acpi_dev;
58 union qemu_fwcfg_selector selector;
59 struct qemu_fwcfg_item items[QEMU_FWCFG_MAX_ARCHS]
60 [QEMU_FWCFG_MAX_ENTRIES];
63 static struct qemu_fwcfg_softc fwcfg_sc;
66 qemu_fwcfg_selector_port_handler(struct vmctx *const ctx __unused, const int in,
67 const int port __unused, const int bytes, uint32_t *const eax,
68 void *const arg __unused)
70 if (bytes != sizeof(uint16_t)) {
71 warnx("%s: invalid size (%d) of IO port access", __func__,
77 *eax = htole16(fwcfg_sc.selector.bits);
81 fwcfg_sc.data_offset = 0;
82 fwcfg_sc.selector.bits = le16toh(*eax);
88 qemu_fwcfg_data_port_handler(struct vmctx *const ctx __unused, const int in,
89 const int port __unused, const int bytes, uint32_t *const eax,
90 void *const arg __unused)
92 if (bytes != sizeof(uint8_t)) {
93 warnx("%s: invalid size (%d) of IO port access", __func__,
99 warnx("%s: Writes to qemu fwcfg data port aren't allowed",
105 struct qemu_fwcfg_item *const item =
106 &fwcfg_sc.items[fwcfg_sc.selector.architecture]
107 [fwcfg_sc.selector.index];
108 if (item->data == NULL) {
110 "%s: qemu fwcfg item doesn't exist (architecture %s index 0x%x)",
112 fwcfg_sc.selector.architecture ? "specific" : "generic",
113 fwcfg_sc.selector.index);
116 } else if (fwcfg_sc.data_offset >= item->size) {
118 "%s: qemu fwcfg item read exceeds size (architecture %s index 0x%x size 0x%x offset 0x%x)",
120 fwcfg_sc.selector.architecture ? "specific" : "generic",
121 fwcfg_sc.selector.index, item->size, fwcfg_sc.data_offset);
126 /* return item data */
127 *eax = item->data[fwcfg_sc.data_offset];
128 fwcfg_sc.data_offset++;
134 qemu_fwcfg_register_port(const char *const name, const int port, const int size,
135 const int flags, const inout_func_t handler)
137 struct inout_port iop;
139 bzero(&iop, sizeof(iop));
144 iop.handler = handler;
146 return (register_inout(&iop));
150 qemu_fwcfg_init(struct vmctx *const ctx)
154 error = acpi_device_create(&fwcfg_sc.acpi_dev, ctx,
155 QEMU_FWCFG_ACPI_DEVICE_NAME, QEMU_FWCFG_ACPI_HARDWARE_ID);
157 warnx("%s: failed to create ACPI device for QEMU FwCfg",
162 error = acpi_device_add_res_fixed_ioport(fwcfg_sc.acpi_dev,
163 QEMU_FWCFG_SELECTOR_PORT_NUMBER, 2);
165 warnx("%s: failed to add fixed IO port for QEMU FwCfg",
170 /* add handlers for fwcfg ports */
171 if ((error = qemu_fwcfg_register_port("qemu_fwcfg_selector",
172 QEMU_FWCFG_SELECTOR_PORT_NUMBER, QEMU_FWCFG_SELECTOR_PORT_SIZE,
173 QEMU_FWCFG_SELECTOR_PORT_FLAGS,
174 qemu_fwcfg_selector_port_handler)) != 0) {
175 warnx("%s: Unable to register qemu fwcfg selector port 0x%x",
176 __func__, QEMU_FWCFG_SELECTOR_PORT_NUMBER);
179 if ((error = qemu_fwcfg_register_port("qemu_fwcfg_data",
180 QEMU_FWCFG_DATA_PORT_NUMBER, QEMU_FWCFG_DATA_PORT_SIZE,
181 QEMU_FWCFG_DATA_PORT_FLAGS, qemu_fwcfg_data_port_handler)) != 0) {
182 warnx("%s: Unable to register qemu fwcfg data port 0x%x",
183 __func__, QEMU_FWCFG_DATA_PORT_NUMBER);
189 acpi_device_destroy(fwcfg_sc.acpi_dev);