blob: 0f217ccca056817dbbd448dc7fe14c91445f94f2 [file] [log] [blame]
Angel Pons585495e2020-04-03 01:21:38 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Gerd Hoffmann2b962032013-05-30 15:41:48 +02002
Kyösti Mälkki36955932019-03-03 17:43:29 +02003#include <endian.h>
Elyes HAOUAS70a03dd2019-12-02 20:47:50 +01004#include <stdlib.h>
Gerd Hoffmann2b962032013-05-30 15:41:48 +02005#include <string.h>
Gerd Hoffmanne851a682013-11-13 12:56:30 +01006#include <smbios.h>
Gerd Hoffmann2b962032013-05-30 15:41:48 +02007#include <console/console.h>
8#include <arch/io.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -07009#include <acpi/acpi.h>
Ryan Salsamendid4f994b2017-06-11 19:39:06 -070010#include <commonlib/endian.h>
Gerd Hoffmann2b962032013-05-30 15:41:48 +020011
12#include "fw_cfg.h"
13#include "fw_cfg_if.h"
14
15#define FW_CFG_PORT_CTL 0x0510
16#define FW_CFG_PORT_DATA 0x0511
Himanshu Sahdev8dc95dd2019-09-12 12:02:54 +053017#define FW_CFG_DMA_ADDR_HIGH 0x0514
18#define FW_CFG_DMA_ADDR_LOW 0x0518
Gerd Hoffmann2b962032013-05-30 15:41:48 +020019
Thomas Heijligen0065b692019-01-10 19:42:21 +010020static int fw_cfg_detected;
Himanshu Sahdev8dc95dd2019-09-12 12:02:54 +053021static uint8_t fw_ver;
22
23static void fw_cfg_dma(int control, void *buf, int len);
Gerd Hoffmann2b962032013-05-30 15:41:48 +020024
25static int fw_cfg_present(void)
26{
27 static const char qsig[] = "QEMU";
Himanshu Sahdev8dc95dd2019-09-12 12:02:54 +053028 unsigned char sig[FW_CFG_SIG_SIZE];
Thomas Heijligen0065b692019-01-10 19:42:21 +010029 int detected = 0;
Gerd Hoffmann2b962032013-05-30 15:41:48 +020030
Thomas Heijligen0065b692019-01-10 19:42:21 +010031 if (fw_cfg_detected == 0) {
Gerd Hoffmann2b962032013-05-30 15:41:48 +020032 fw_cfg_get(FW_CFG_SIGNATURE, sig, sizeof(sig));
Himanshu Sahdev8dc95dd2019-09-12 12:02:54 +053033 detected = memcmp(sig, qsig, FW_CFG_SIG_SIZE) == 0;
Gerd Hoffmann2b962032013-05-30 15:41:48 +020034 printk(BIOS_INFO, "QEMU: firmware config interface %s\n",
Thomas Heijligen0065b692019-01-10 19:42:21 +010035 detected ? "detected" : "not found");
Himanshu Sahdev8dc95dd2019-09-12 12:02:54 +053036 if (detected) {
37 fw_cfg_get(FW_CFG_ID, &fw_ver, sizeof(fw_ver));
38 printk(BIOS_INFO, "Firmware config version id: %d\n", fw_ver);
39 }
Thomas Heijligen0065b692019-01-10 19:42:21 +010040 fw_cfg_detected = detected + 1;
Gerd Hoffmann2b962032013-05-30 15:41:48 +020041 }
Thomas Heijligen0065b692019-01-10 19:42:21 +010042 return fw_cfg_detected - 1;
Gerd Hoffmann2b962032013-05-30 15:41:48 +020043}
44
Thomas Heijligena05f8a92019-01-10 12:55:59 +010045static void fw_cfg_select(uint16_t entry)
Gerd Hoffmann2b962032013-05-30 15:41:48 +020046{
47 outw(entry, FW_CFG_PORT_CTL);
Thomas Heijligena05f8a92019-01-10 12:55:59 +010048}
49
50static void fw_cfg_read(void *dst, int dstlen)
51{
Himanshu Sahdev8dc95dd2019-09-12 12:02:54 +053052 if (fw_ver & FW_CFG_VERSION_DMA)
53 fw_cfg_dma(FW_CFG_DMA_CTL_READ, dst, dstlen);
54 else
55 insb(FW_CFG_PORT_DATA, dst, dstlen);
Gerd Hoffmann2b962032013-05-30 15:41:48 +020056}
57
Thomas Heijligena05f8a92019-01-10 12:55:59 +010058void fw_cfg_get(uint16_t entry, void *dst, int dstlen)
59{
60 fw_cfg_select(entry);
61 fw_cfg_read(dst, dstlen);
62}
63
Thomas Heijligen721c8b42019-01-10 17:39:00 +010064static int fw_cfg_find_file(FWCfgFile *file, const char *name)
Gerd Hoffmann289b45f2013-06-12 10:18:58 +020065{
Thomas Heijligen721c8b42019-01-10 17:39:00 +010066 uint32_t count = 0;
Gerd Hoffmann289b45f2013-06-12 10:18:58 +020067
Thomas Heijligen721c8b42019-01-10 17:39:00 +010068 fw_cfg_select(FW_CFG_FILE_DIR);
69 fw_cfg_read(&count, sizeof(count));
70 count = be32_to_cpu(count);
Gerd Hoffmann289b45f2013-06-12 10:18:58 +020071
Thomas Heijligen721c8b42019-01-10 17:39:00 +010072 for (int i = 0; i < count; i++) {
73 fw_cfg_read(file, sizeof(*file));
74 if (strcmp(file->name, name) == 0) {
75 file->size = be32_to_cpu(file->size);
76 file->select = be16_to_cpu(file->select);
Nico Huberef59c932020-07-14 12:19:07 +020077 printk(BIOS_INFO, "QEMU: firmware config: Found '%s'\n", name);
Thomas Heijligen721c8b42019-01-10 17:39:00 +010078 return 0;
79 }
Gerd Hoffmann289b45f2013-06-12 10:18:58 +020080 }
Nico Huberef59c932020-07-14 12:19:07 +020081 printk(BIOS_INFO, "QEMU: firmware config: Couldn't find '%s'\n", name);
Thomas Heijligen721c8b42019-01-10 17:39:00 +010082 return -1;
Gerd Hoffmann289b45f2013-06-12 10:18:58 +020083}
84
Thomas Heijligenbcd84fe2019-01-10 16:53:34 +010085int fw_cfg_check_file(FWCfgFile *file, const char *name)
Gerd Hoffmann289b45f2013-06-12 10:18:58 +020086{
Gerd Hoffmann289b45f2013-06-12 10:18:58 +020087 if (!fw_cfg_present())
88 return -1;
Thomas Heijligen721c8b42019-01-10 17:39:00 +010089 return fw_cfg_find_file(file, name);
Gerd Hoffmann289b45f2013-06-12 10:18:58 +020090}
91
Thomas Heijligenda9aa6d2019-01-10 18:19:06 +010092static int fw_cfg_e820_select(uint32_t *size)
93{
94 FWCfgFile file;
95
96 if (!fw_cfg_present() || fw_cfg_find_file(&file, "etc/e820"))
97 return -1;
98 fw_cfg_select(file.select);
99 *size = file.size;
100 return 0;
101}
102
103static int fw_cfg_e820_read(FwCfgE820Entry *entry, uint32_t *size,
104 uint32_t *pos)
105{
106 if (*pos + sizeof(*entry) > *size)
107 return -1;
108
109 fw_cfg_read(entry, sizeof(*entry));
110 *pos += sizeof(*entry);
111 return 0;
112}
113
114/* returns tolud on success or 0 on failure */
115uintptr_t fw_cfg_tolud(void)
116{
117 FwCfgE820Entry e;
118 uint64_t top = 0;
119 uint32_t size = 0, pos = 0;
120
Nico Huberd2245d82020-07-14 12:21:19 +0200121 if (fw_cfg_e820_select(&size) == 0) {
Thomas Heijligenda9aa6d2019-01-10 18:19:06 +0100122 while (!fw_cfg_e820_read(&e, &size, &pos)) {
123 uint64_t limit = e.address + e.length;
124 if (e.type == 1 && limit < 4ULL * GiB && limit > top)
125 top = limit;
126 }
127 }
128 return (uintptr_t)top;
129}
130
Gerd Hoffmann2b962032013-05-30 15:41:48 +0200131int fw_cfg_max_cpus(void)
132{
133 unsigned short max_cpus;
134
135 if (!fw_cfg_present())
Angel Ponsd16d00b2021-11-03 16:42:48 +0100136 return 0;
Gerd Hoffmann2b962032013-05-30 15:41:48 +0200137
138 fw_cfg_get(FW_CFG_MAX_CPUS, &max_cpus, sizeof(max_cpus));
139 return max_cpus;
140}
Gerd Hoffmannd69da842013-07-25 15:59:07 +0200141
142/* ---------------------------------------------------------------------- */
Gerd Hoffmann590e8d42013-12-03 09:40:39 +0100143
Gerd Hoffmannd69da842013-07-25 15:59:07 +0200144/*
Elyes HAOUAS8ab989e2016-07-30 17:46:17 +0200145 * Starting with release 1.7 qemu provides ACPI tables via fw_cfg.
Gerd Hoffmannd69da842013-07-25 15:59:07 +0200146 * Main advantage is that new (virtual) hardware which needs acpi
147 * support JustWorks[tm] without having to patch & update the firmware
148 * (seabios, coreboot, ...) accordingly.
149 *
150 * Qemu provides a etc/table-loader file with instructions for the
151 * firmware:
Elyes HAOUAS8ab989e2016-07-30 17:46:17 +0200152 * - A "load" instruction to fetch ACPI data from fw_cfg.
Gerd Hoffmannd69da842013-07-25 15:59:07 +0200153 * - A "pointer" instruction to patch a pointer. This is needed to
154 * get table-to-table references right, it is basically a
Elyes HAOUAS8ab989e2016-07-30 17:46:17 +0200155 * primitive dynamic linker for ACPI tables.
156 * - A "checksum" instruction to generate ACPI table checksums.
Gerd Hoffmannd69da842013-07-25 15:59:07 +0200157 *
158 * If a etc/table-loader file is found we'll go try loading the acpi
Elyes HAOUAS8ab989e2016-07-30 17:46:17 +0200159 * tables from fw_cfg, otherwise we'll fallback to the ACPI tables
Gerd Hoffmannd69da842013-07-25 15:59:07 +0200160 * compiled in.
161 */
162
163#define BIOS_LINKER_LOADER_FILESZ 56
164
165struct BiosLinkerLoaderEntry {
166 uint32_t command;
167 union {
168 /*
169 * COMMAND_ALLOCATE - allocate a table from @alloc.file
170 * subject to @alloc.align alignment (must be power of 2)
171 * and @alloc.zone (can be HIGH or FSEG) requirements.
172 *
173 * Must appear exactly once for each file, and before
174 * this file is referenced by any other command.
175 */
176 struct {
177 char file[BIOS_LINKER_LOADER_FILESZ];
178 uint32_t align;
179 uint8_t zone;
180 } alloc;
181
182 /*
183 * COMMAND_ADD_POINTER - patch the table (originating from
184 * @dest_file) at @pointer.offset, by adding a pointer to the table
185 * originating from @src_file. 1,2,4 or 8 byte unsigned
186 * addition is used depending on @pointer.size.
187 */
188 struct {
189 char dest_file[BIOS_LINKER_LOADER_FILESZ];
190 char src_file[BIOS_LINKER_LOADER_FILESZ];
191 uint32_t offset;
192 uint8_t size;
193 } pointer;
194
195 /*
196 * COMMAND_ADD_CHECKSUM - calculate checksum of the range specified by
197 * @cksum_start and @cksum_length fields,
198 * and then add the value at @cksum.offset.
199 * Checksum simply sums -X for each byte X in the range
200 * using 8-bit math.
201 */
202 struct {
203 char file[BIOS_LINKER_LOADER_FILESZ];
204 uint32_t offset;
205 uint32_t start;
206 uint32_t length;
207 } cksum;
208
209 /* padding */
210 char pad[124];
211 };
Stefan Reinauer6a001132017-07-13 02:20:27 +0200212} __packed;
Gerd Hoffmannd69da842013-07-25 15:59:07 +0200213typedef struct BiosLinkerLoaderEntry BiosLinkerLoaderEntry;
214
215enum {
216 BIOS_LINKER_LOADER_COMMAND_ALLOCATE = 0x1,
217 BIOS_LINKER_LOADER_COMMAND_ADD_POINTER = 0x2,
218 BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM = 0x3,
219};
220
221enum {
222 BIOS_LINKER_LOADER_ALLOC_ZONE_HIGH = 0x1,
223 BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG = 0x2,
224};
225
226unsigned long fw_cfg_acpi_tables(unsigned long start)
227{
Thomas Heijligenbcd84fe2019-01-10 16:53:34 +0100228 FWCfgFile f;
Gerd Hoffmannd69da842013-07-25 15:59:07 +0200229 BiosLinkerLoaderEntry *s;
230 unsigned long *addrs, current;
Ryan Salsamendid4f994b2017-06-11 19:39:06 -0700231 uint8_t *ptr;
Thomas Heijligenbcd84fe2019-01-10 16:53:34 +0100232 int i, j, src, dst, max;
Gerd Hoffmannd69da842013-07-25 15:59:07 +0200233
Thomas Heijligenbcd84fe2019-01-10 16:53:34 +0100234 if (fw_cfg_check_file(&f, "etc/table-loader"))
Gerd Hoffmannd69da842013-07-25 15:59:07 +0200235 return 0;
236
Elyes HAOUAS8ab989e2016-07-30 17:46:17 +0200237 printk(BIOS_DEBUG, "QEMU: found ACPI tables in fw_cfg.\n");
Gerd Hoffmannd69da842013-07-25 15:59:07 +0200238
Thomas Heijligenbcd84fe2019-01-10 16:53:34 +0100239 max = f.size / sizeof(*s);
240 s = malloc(f.size);
Gerd Hoffmannd69da842013-07-25 15:59:07 +0200241 addrs = malloc(max * sizeof(*addrs));
Thomas Heijligenbcd84fe2019-01-10 16:53:34 +0100242 fw_cfg_get(f.select, s, f.size);
Gerd Hoffmannd69da842013-07-25 15:59:07 +0200243
244 current = start;
245 for (i = 0; i < max && s[i].command != 0; i++) {
Ryan Salsamendid4f994b2017-06-11 19:39:06 -0700246 void *cksum_data;
247 uint32_t cksum;
248 uint32_t addr4;
249 uint64_t addr8;
Gerd Hoffmannd69da842013-07-25 15:59:07 +0200250 switch (s[i].command) {
251 case BIOS_LINKER_LOADER_COMMAND_ALLOCATE:
Elyes Haouasd6b6b222022-10-10 12:34:21 +0200252 current = ALIGN_UP(current, s[i].alloc.align);
Thomas Heijligenbcd84fe2019-01-10 16:53:34 +0100253 if (fw_cfg_check_file(&f, s[i].alloc.file))
Gerd Hoffmannd69da842013-07-25 15:59:07 +0200254 goto err;
Thomas Heijligenbcd84fe2019-01-10 16:53:34 +0100255
Gerd Hoffmannacfe1e52014-08-27 13:21:43 +0200256 printk(BIOS_DEBUG, "QEMU: loading \"%s\" to 0x%lx (len %d)\n",
Thomas Heijligenbcd84fe2019-01-10 16:53:34 +0100257 s[i].alloc.file, current, f.size);
Patrick Rudolph87abccd2019-02-23 11:45:01 +0100258 fw_cfg_get(f.select, (void *)current, f.size);
Gerd Hoffmannd69da842013-07-25 15:59:07 +0200259 addrs[i] = current;
Thomas Heijligenbcd84fe2019-01-10 16:53:34 +0100260 current += f.size;
Gerd Hoffmannd69da842013-07-25 15:59:07 +0200261 break;
262
263 case BIOS_LINKER_LOADER_COMMAND_ADD_POINTER:
264 src = -1; dst = -1;
265 for (j = 0; j < i; j++) {
266 if (s[j].command != BIOS_LINKER_LOADER_COMMAND_ALLOCATE)
267 continue;
268 if (strcmp(s[j].alloc.file, s[i].pointer.dest_file) == 0)
269 dst = j;
270 if (strcmp(s[j].alloc.file, s[i].pointer.src_file) == 0)
271 src = j;
272 }
273 if (src == -1 || dst == -1)
274 goto err;
275
276 switch (s[i].pointer.size) {
277 case 4:
Ryan Salsamendid4f994b2017-06-11 19:39:06 -0700278 ptr = (uint8_t *)addrs[dst];
279 ptr += s[i].pointer.offset;
280 addr4 = read_le32(ptr);
281 addr4 += addrs[src];
282 write_le32(ptr, addr4);
Gerd Hoffmannd69da842013-07-25 15:59:07 +0200283 break;
284
285 case 8:
Ryan Salsamendid4f994b2017-06-11 19:39:06 -0700286 ptr = (uint8_t *)addrs[dst];
287 ptr += s[i].pointer.offset;
288 addr8 = read_le64(ptr);
289 addr8 += addrs[src];
290 write_le64(ptr, addr8);
Gerd Hoffmannd69da842013-07-25 15:59:07 +0200291 break;
292
293 default:
294 /*
Elyes HAOUAS8ab989e2016-07-30 17:46:17 +0200295 * Should not happen. ACPI knows 1 and 2 byte ptrs
Gerd Hoffmannd69da842013-07-25 15:59:07 +0200296 * too, but we are operating with 32bit offsets which
297 * would simply not fit in there ...
298 */
299 printk(BIOS_DEBUG, "QEMU: acpi: unimplemented ptr size %d\n",
300 s[i].pointer.size);
301 goto err;
302 }
303 break;
304
305 case BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM:
306 dst = -1;
307 for (j = 0; j < i; j++) {
308 if (s[j].command != BIOS_LINKER_LOADER_COMMAND_ALLOCATE)
309 continue;
310 if (strcmp(s[j].alloc.file, s[i].cksum.file) == 0)
311 dst = j;
312 }
313 if (dst == -1)
314 goto err;
315
Ryan Salsamendid4f994b2017-06-11 19:39:06 -0700316 ptr = (uint8_t *)(addrs[dst] + s[i].cksum.offset);
317 cksum_data = (void *)(addrs[dst] + s[i].cksum.start);
318 cksum = acpi_checksum(cksum_data, s[i].cksum.length);
Oleksii Kurochko4886a652018-04-20 15:38:57 +0300319 write_le8(ptr, cksum);
Gerd Hoffmannd69da842013-07-25 15:59:07 +0200320 break;
321
322 default:
323 printk(BIOS_DEBUG, "QEMU: acpi: unknown script cmd 0x%x @ %p\n",
324 s[i].command, s+i);
325 goto err;
326 };
327 }
328
Elyes HAOUAS8ab989e2016-07-30 17:46:17 +0200329 printk(BIOS_DEBUG, "QEMU: loaded ACPI tables from fw_cfg.\n");
Gerd Hoffmannd69da842013-07-25 15:59:07 +0200330 free(s);
331 free(addrs);
Elyes Haouasd6b6b222022-10-10 12:34:21 +0200332 return ALIGN_UP(current, 16);
Gerd Hoffmannd69da842013-07-25 15:59:07 +0200333
334err:
Elyes HAOUAS8ab989e2016-07-30 17:46:17 +0200335 printk(BIOS_DEBUG, "QEMU: loading ACPI tables from fw_cfg failed.\n");
Gerd Hoffmannd69da842013-07-25 15:59:07 +0200336 free(s);
337 free(addrs);
338 return 0;
339}
Gerd Hoffmanne851a682013-11-13 12:56:30 +0100340
341/* ---------------------------------------------------------------------- */
342/* pick up smbios information from fw_cfg */
343
Alper Nebi Yasakdd634182024-02-06 23:09:33 +0300344#if CONFIG(GENERATE_SMBIOS_TABLES)
Gerd Hoffmanne851a682013-11-13 12:56:30 +0100345static const char *type1_manufacturer;
346static const char *type1_product_name;
347static const char *type1_version;
348static const char *type1_serial_number;
349static const char *type1_family;
350static u8 type1_uuid[16];
351
352static void fw_cfg_smbios_init(void)
353{
354 static int done = 0;
355 uint16_t i, count = 0;
356 FwCfgSmbios entry;
357 char *buf;
358
359 if (done)
360 return;
361 done = 1;
362
363 fw_cfg_get(FW_CFG_SMBIOS_ENTRIES, &count, sizeof(count));
364 for (i = 0; i < count; i++) {
365 insb(FW_CFG_PORT_DATA, &entry, sizeof(entry));
366 buf = malloc(entry.length - sizeof(entry));
367 insb(FW_CFG_PORT_DATA, buf, entry.length - sizeof(entry));
368 if (entry.headertype == SMBIOS_FIELD_ENTRY &&
369 entry.tabletype == 1) {
370 switch (entry.fieldoffset) {
371 case offsetof(struct smbios_type1, manufacturer):
372 type1_manufacturer = strdup(buf);
373 break;
374 case offsetof(struct smbios_type1, product_name):
375 type1_product_name = strdup(buf);
376 break;
377 case offsetof(struct smbios_type1, version):
378 type1_version = strdup(buf);
379 break;
380 case offsetof(struct smbios_type1, serial_number):
381 type1_serial_number = strdup(buf);
382 break;
383 case offsetof(struct smbios_type1, family):
384 type1_family = strdup(buf);
385 break;
386 case offsetof(struct smbios_type1, uuid):
387 memcpy(type1_uuid, buf, 16);
388 break;
389 }
390 }
391 free(buf);
392 }
393}
394
Gerd Hoffmanndb9d1692014-08-27 11:25:13 +0200395static unsigned long smbios_next(unsigned long current)
396{
Angel Ponsfff1b2f2021-06-28 19:09:22 +0200397 struct smbios_header *header;
Gerd Hoffmanndb9d1692014-08-27 11:25:13 +0200398 int l, count = 0;
399 char *s;
400
Angel Ponsfff1b2f2021-06-28 19:09:22 +0200401 header = (void *)current;
402 current += header->length;
Gerd Hoffmanndb9d1692014-08-27 11:25:13 +0200403 for (;;) {
Angel Ponsfff1b2f2021-06-28 19:09:22 +0200404 s = (void *)current;
Gerd Hoffmanndb9d1692014-08-27 11:25:13 +0200405 l = strlen(s);
406 if (!l)
407 return current + (count ? 1 : 2);
408 current += l + 1;
409 count++;
410 }
411}
412
413/*
414 * Starting with version 2.1 qemu provides a full set of smbios tables
415 * for the virtual hardware emulated, except type 0 (bios information).
416 *
417 * What we are going to do here is find the type0 table, keep it, and
418 * override everything else generated by coreboot with the qemu smbios
419 * tables.
420 *
421 * It's a bit hackish, but qemu is a special case (compared to real
422 * hardware) and this way we don't need special qemu support in the
423 * generic smbios code.
424 */
425unsigned long fw_cfg_smbios_tables(int *handle, unsigned long *current)
426{
Thomas Heijligenbcd84fe2019-01-10 16:53:34 +0100427 FWCfgFile f;
Angel Ponsfff1b2f2021-06-28 19:09:22 +0200428 struct smbios_header *header;
Gerd Hoffmanndb9d1692014-08-27 11:25:13 +0200429 unsigned long start, end;
Thomas Heijligenbcd84fe2019-01-10 16:53:34 +0100430 int ret, i, count = 1;
Gerd Hoffmanndb9d1692014-08-27 11:25:13 +0200431 char *str;
432
Thomas Heijligenbcd84fe2019-01-10 16:53:34 +0100433 if (fw_cfg_check_file(&f, "etc/smbios/smbios-tables"))
Gerd Hoffmanndb9d1692014-08-27 11:25:13 +0200434 return 0;
Thomas Heijligenbcd84fe2019-01-10 16:53:34 +0100435
436 printk(BIOS_DEBUG, "QEMU: found smbios tables in fw_cfg (len %d).\n", f.size);
Gerd Hoffmanndb9d1692014-08-27 11:25:13 +0200437
438 /*
439 * Search backwards for "coreboot" (first string in type0 table,
440 * see src/arch/x86/boot/smbios.c), then find type0 table.
441 */
442 for (i = 0; i < 16384; i++) {
443 str = (char*)(*current - i);
444 if (strcmp(str, "coreboot") == 0)
445 break;
446 }
447 if (i == 16384)
448 return 0;
449 i += sizeof(struct smbios_type0) - 2;
Angel Ponsfff1b2f2021-06-28 19:09:22 +0200450 header = (struct smbios_header *)(*current - i);
451 if (header->type != SMBIOS_BIOS_INFORMATION || header->handle != 0)
Gerd Hoffmanndb9d1692014-08-27 11:25:13 +0200452 return 0;
453 printk(BIOS_DEBUG, "QEMU: coreboot type0 table found at 0x%lx.\n",
454 *current - i);
455 start = smbios_next(*current - i);
456
457 /*
458 * Fetch smbios tables from qemu, go find the end marker.
459 * We'll exclude the end marker as coreboot will add one.
460 */
461 printk(BIOS_DEBUG, "QEMU: loading smbios tables to 0x%lx\n", start);
Patrick Rudolph87abccd2019-02-23 11:45:01 +0100462 fw_cfg_get(f.select, (void *)start, f.size);
Gerd Hoffmanndb9d1692014-08-27 11:25:13 +0200463 end = start;
464 do {
Angel Ponsfff1b2f2021-06-28 19:09:22 +0200465 header = (struct smbios_header *)end;
466 if (header->type == SMBIOS_END_OF_TABLE)
Gerd Hoffmanndb9d1692014-08-27 11:25:13 +0200467 break;
468 end = smbios_next(end);
469 count++;
Thomas Heijligenbcd84fe2019-01-10 16:53:34 +0100470 } while (end < start + f.size);
Gerd Hoffmanndb9d1692014-08-27 11:25:13 +0200471
472 /* final fixups. */
473 ret = end - *current;
474 *current = end;
475 *handle = count;
476 return ret;
477}
478
Gerd Hoffmanne851a682013-11-13 12:56:30 +0100479const char *smbios_mainboard_manufacturer(void)
480{
481 fw_cfg_smbios_init();
482 return type1_manufacturer ?: CONFIG_MAINBOARD_SMBIOS_MANUFACTURER;
483}
484
485const char *smbios_mainboard_product_name(void)
486{
487 fw_cfg_smbios_init();
488 return type1_product_name ?: CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME;
489}
490
491const char *smbios_mainboard_version(void)
492{
493 fw_cfg_smbios_init();
494 return type1_version ?: CONFIG_MAINBOARD_VERSION;
495}
496
497const char *smbios_mainboard_serial_number(void)
498{
499 fw_cfg_smbios_init();
500 return type1_serial_number ?: CONFIG_MAINBOARD_SERIAL_NUMBER;
501}
502
Nico Huberebd8a4f2017-11-01 09:49:16 +0100503void smbios_system_set_uuid(u8 *uuid)
Gerd Hoffmanne851a682013-11-13 12:56:30 +0100504{
505 fw_cfg_smbios_init();
506 memcpy(uuid, type1_uuid, 16);
507}
Alper Nebi Yasakdd634182024-02-06 23:09:33 +0300508#endif /* CONFIG(GENERATE_SMBIOS_TABLES) */
Himanshu Sahdev8dc95dd2019-09-12 12:02:54 +0530509
510/*
511 * Configure DMA setup
512 */
513
514static void fw_cfg_dma(int control, void *buf, int len)
515{
516 volatile FwCfgDmaAccess dma;
517 uintptr_t dma_desc_addr;
518 uint32_t dma_desc_addr_hi, dma_desc_addr_lo;
519
520 dma.control = be32_to_cpu(control);
521 dma.length = be32_to_cpu(len);
522 dma.address = be64_to_cpu((uintptr_t)buf);
523
524 dma_desc_addr = (uintptr_t)&dma;
525 dma_desc_addr_lo = (uint32_t)(dma_desc_addr & 0xFFFFFFFFU);
526 dma_desc_addr_hi = sizeof(uintptr_t) > sizeof(uint32_t)
527 ? (uint32_t)(dma_desc_addr >> 32) : 0;
528
529 // Skip writing high half if unnecessary.
530 if (dma_desc_addr_hi)
531 outl(be32_to_cpu(dma_desc_addr_hi), FW_CFG_DMA_ADDR_HIGH);
532 outl(be32_to_cpu(dma_desc_addr_lo), FW_CFG_DMA_ADDR_LOW);
533
534 while (be32_to_cpu(dma.control) & ~FW_CFG_DMA_CTL_ERROR)
535 ;
536}