2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2022 Beckhoff Automation GmbH & Co. KG
5 * Author: Corvin Köhne <c.koehne@beckhoff.com>
10 #include <sys/endian.h>
11 #include <sys/queue.h>
13 #include <machine/vmm.h>
22 #include "qemu_fwcfg.h"
23 #include "qemu_loader.h"
25 struct qemu_loader_entry {
29 uint8_t name[QEMU_FWCFG_MAX_NAME];
30 uint32_t alignment_le;
34 uint8_t dest_name[QEMU_FWCFG_MAX_NAME];
35 uint8_t src_name[QEMU_FWCFG_MAX_NAME];
40 uint8_t name[QEMU_FWCFG_MAX_NAME];
46 uint8_t dest_name[QEMU_FWCFG_MAX_NAME];
47 uint8_t src_name[QEMU_FWCFG_MAX_NAME];
58 enum qemu_loader_command {
59 QEMU_LOADER_CMD_ALLOC = 0x1,
60 QEMU_LOADER_CMD_ADD_POINTER = 0x2,
61 QEMU_LOADER_CMD_ADD_CHECKSUM = 0x3,
62 QEMU_LOADER_CMD_WRITE_POINTER = 0x4,
65 struct qemu_loader_element {
66 STAILQ_ENTRY(qemu_loader_element) chain;
67 struct qemu_loader_entry entry;
71 uint8_t fwcfg_name[QEMU_FWCFG_MAX_NAME];
72 STAILQ_HEAD(qemu_loader_list, qemu_loader_element) list;
76 qemu_loader_alloc(struct qemu_loader *const loader, const uint8_t *name,
77 const uint32_t alignment, const enum qemu_loader_zone zone)
79 struct qemu_loader_element *element;
81 if (strlen(name) >= QEMU_FWCFG_MAX_NAME)
84 element = calloc(1, sizeof(struct qemu_loader_element));
85 if (element == NULL) {
86 warnx("%s: failed to allocate command", __func__);
90 element->entry.cmd_le = htole32(QEMU_LOADER_CMD_ALLOC);
91 strncpy(element->entry.alloc.name, name, QEMU_FWCFG_MAX_NAME);
92 element->entry.alloc.alignment_le = htole32(alignment);
93 element->entry.alloc.zone = zone;
96 * The guest always works on copies of the fwcfg item, which where
97 * loaded into guest memory. Loading a fwcfg item is caused by ALLOC.
98 * For that reason, ALLOC should be scheduled in front of any other
101 STAILQ_INSERT_HEAD(&loader->list, element, chain);
107 qemu_loader_add_checksum(struct qemu_loader *const loader, const uint8_t *name,
108 const uint32_t off, const uint32_t start, const uint32_t len)
110 struct qemu_loader_element *element;
112 if (strlen(name) >= QEMU_FWCFG_MAX_NAME)
115 element = calloc(1, sizeof(struct qemu_loader_element));
116 if (element == NULL) {
117 warnx("%s: failed to allocate command", __func__);
121 element->entry.cmd_le = htole32(QEMU_LOADER_CMD_ADD_CHECKSUM);
122 strncpy(element->entry.add_checksum.name, name, QEMU_FWCFG_MAX_NAME);
123 element->entry.add_checksum.off_le = htole32(off);
124 element->entry.add_checksum.start_le = htole32(start);
125 element->entry.add_checksum.len_le = htole32(len);
127 STAILQ_INSERT_TAIL(&loader->list, element, chain);
133 qemu_loader_add_pointer(struct qemu_loader *const loader,
134 const uint8_t *dest_name, const uint8_t *src_name, const uint32_t off,
137 struct qemu_loader_element *element;
139 if (strlen(dest_name) >= QEMU_FWCFG_MAX_NAME ||
140 strlen(src_name) >= QEMU_FWCFG_MAX_NAME)
143 element = calloc(1, sizeof(struct qemu_loader_element));
144 if (element == NULL) {
145 warnx("%s: failed to allocate command", __func__);
149 element->entry.cmd_le = htole32(QEMU_LOADER_CMD_ADD_POINTER);
150 strncpy(element->entry.add_pointer.dest_name, dest_name,
151 QEMU_FWCFG_MAX_NAME);
152 strncpy(element->entry.add_pointer.src_name, src_name,
153 QEMU_FWCFG_MAX_NAME);
154 element->entry.add_pointer.off_le = htole32(off);
155 element->entry.add_pointer.size = size;
157 STAILQ_INSERT_TAIL(&loader->list, element, chain);
163 qemu_loader_create(struct qemu_loader **const new_loader,
164 const uint8_t *fwcfg_name)
166 struct qemu_loader *loader;
168 if (new_loader == NULL || strlen(fwcfg_name) >= QEMU_FWCFG_MAX_NAME) {
172 loader = calloc(1, sizeof(struct qemu_loader));
173 if (loader == NULL) {
174 warnx("%s: failed to allocate loader", __func__);
178 strncpy(loader->fwcfg_name, fwcfg_name, QEMU_FWCFG_MAX_NAME);
179 STAILQ_INIT(&loader->list);
181 *new_loader = loader;
186 static const uint8_t *
187 qemu_loader_get_zone_name(const enum qemu_loader_zone zone)
190 case QEMU_LOADER_ALLOC_HIGH:
192 case QEMU_LOADER_ALLOC_FSEG:
200 qemu_loader_dump_entry(const struct qemu_loader_entry *const entry)
202 switch (le32toh(entry->cmd_le)) {
203 case QEMU_LOADER_CMD_ALLOC:
204 printf("CMD_ALLOC\n\r");
205 printf(" name : %s\n\r", entry->alloc.name);
206 printf(" alignment: %8x\n\r",
207 le32toh(entry->alloc.alignment_le));
208 printf(" zone : %s\n\r",
209 qemu_loader_get_zone_name(entry->alloc.zone));
211 case QEMU_LOADER_CMD_ADD_POINTER:
212 printf("CMD_ADD_POINTER\n\r");
213 printf(" dest_name: %s\n\r", entry->add_pointer.dest_name);
214 printf(" src_name : %s\n\r", entry->add_pointer.src_name);
215 printf(" off : %8x\n\r",
216 le32toh(entry->add_pointer.off_le));
217 printf(" size : %8x\n\r", entry->add_pointer.size);
219 case QEMU_LOADER_CMD_ADD_CHECKSUM:
220 printf("CMD_ADD_CHECKSUM\n\r");
221 printf(" name : %s\n\r", entry->add_checksum.name);
222 printf(" off : %8x\n\r",
223 le32toh(entry->add_checksum.off_le));
224 printf(" start : %8x\n\r",
225 le32toh(entry->add_checksum.start_le));
226 printf(" length : %8x\n\r",
227 le32toh(entry->add_checksum.len_le));
229 case QEMU_LOADER_CMD_WRITE_POINTER:
230 printf("CMD_WRITE_POINTER\n\r");
231 printf(" dest_name: %s\n\r", entry->write_pointer.dest_name);
232 printf(" src_name : %s\n\r", entry->write_pointer.src_name);
233 printf(" dest_off : %8x\n\r",
234 le32toh(entry->write_pointer.dest_off_le));
235 printf(" src_off : %8x\n\r",
236 le32toh(entry->write_pointer.src_off_le));
237 printf(" size : %8x\n\r", entry->write_pointer.size);
240 printf("UNKNOWN\n\r");
246 qemu_loader_finish(struct qemu_loader *const loader)
248 struct qemu_loader_element *element;
249 struct qemu_loader_entry *data;
252 STAILQ_FOREACH(element, &loader->list, chain) {
253 len += sizeof(struct qemu_loader_entry);
256 warnx("%s: bios loader empty", __func__);
260 data = calloc(1, len);
262 warnx("%s: failed to allocate fwcfg data", __func__);
267 STAILQ_FOREACH(element, &loader->list, chain) {
268 memcpy(&data[i], &element->entry,
269 sizeof(struct qemu_loader_entry));
273 return (qemu_fwcfg_add_file(loader->fwcfg_name, len, data));