xref: /aosp_15_r20/external/coreboot/src/mainboard/emulation/qemu-i440fx/fw_cfg.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <endian.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <smbios.h>
7 #include <console/console.h>
8 #include <arch/io.h>
9 #include <acpi/acpi.h>
10 #include <commonlib/endian.h>
11 
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
17 #define FW_CFG_DMA_ADDR_HIGH  0x0514
18 #define FW_CFG_DMA_ADDR_LOW   0x0518
19 
20 static int fw_cfg_detected;
21 static uint8_t fw_ver;
22 
23 static void fw_cfg_dma(int control, void *buf, int len);
24 
fw_cfg_present(void)25 static int fw_cfg_present(void)
26 {
27 	static const char qsig[] = "QEMU";
28 	unsigned char sig[FW_CFG_SIG_SIZE];
29 	int detected = 0;
30 
31 	if (fw_cfg_detected == 0) {
32 		fw_cfg_get(FW_CFG_SIGNATURE, sig, sizeof(sig));
33 		detected = memcmp(sig, qsig, FW_CFG_SIG_SIZE) == 0;
34 		printk(BIOS_INFO, "QEMU: firmware config interface %s\n",
35 				detected ? "detected" : "not found");
36 		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 		}
40 		fw_cfg_detected = detected + 1;
41 	}
42 	return fw_cfg_detected - 1;
43 }
44 
fw_cfg_select(uint16_t entry)45 static void fw_cfg_select(uint16_t entry)
46 {
47 	if (fw_ver & FW_CFG_VERSION_DMA)
48 		fw_cfg_dma(FW_CFG_DMA_CTL_SELECT | entry << 16, NULL, 0);
49 	else
50 		outw(entry, FW_CFG_PORT_CTL);
51 }
52 
fw_cfg_read(void * dst,int dstlen)53 static void fw_cfg_read(void *dst, int dstlen)
54 {
55 	if (fw_ver & FW_CFG_VERSION_DMA)
56 		fw_cfg_dma(FW_CFG_DMA_CTL_READ, dst, dstlen);
57 	else
58 		insb(FW_CFG_PORT_DATA, dst, dstlen);
59 }
60 
fw_cfg_get(uint16_t entry,void * dst,int dstlen)61 void fw_cfg_get(uint16_t entry, void *dst, int dstlen)
62 {
63 	fw_cfg_select(entry);
64 	fw_cfg_read(dst, dstlen);
65 }
66 
fw_cfg_find_file(FWCfgFile * file,const char * name)67 static int fw_cfg_find_file(FWCfgFile *file, const char *name)
68 {
69 	uint32_t count = 0;
70 
71 	fw_cfg_select(FW_CFG_FILE_DIR);
72 	fw_cfg_read(&count, sizeof(count));
73 	count = be32_to_cpu(count);
74 
75 	for (int i = 0; i < count; i++) {
76 		fw_cfg_read(file, sizeof(*file));
77 		if (strcmp(file->name, name) == 0) {
78 			file->size = be32_to_cpu(file->size);
79 			file->select = be16_to_cpu(file->select);
80 			printk(BIOS_INFO, "QEMU: firmware config: Found '%s'\n", name);
81 			return 0;
82 		}
83 	}
84 	printk(BIOS_INFO, "QEMU: firmware config: Couldn't find '%s'\n", name);
85 	return -1;
86 }
87 
fw_cfg_check_file(FWCfgFile * file,const char * name)88 int fw_cfg_check_file(FWCfgFile *file, const char *name)
89 {
90 	if (!fw_cfg_present())
91 		return -1;
92 	return fw_cfg_find_file(file, name);
93 }
94 
fw_cfg_e820_select(uint32_t * size)95 static int fw_cfg_e820_select(uint32_t *size)
96 {
97 	FWCfgFile file;
98 
99 	if (!fw_cfg_present() || fw_cfg_find_file(&file, "etc/e820"))
100 		return -1;
101 	fw_cfg_select(file.select);
102 	*size = file.size;
103 	return 0;
104 }
105 
fw_cfg_e820_read(FwCfgE820Entry * entry,uint32_t * size,uint32_t * pos)106 static int fw_cfg_e820_read(FwCfgE820Entry *entry, uint32_t *size,
107 		uint32_t *pos)
108 {
109 	if (*pos + sizeof(*entry) > *size)
110 		return -1;
111 
112 	fw_cfg_read(entry, sizeof(*entry));
113 	*pos += sizeof(*entry);
114 	return 0;
115 }
116 
117 /* returns tolud on success or 0 on failure */
fw_cfg_tolud(void)118 uintptr_t fw_cfg_tolud(void)
119 {
120 	FwCfgE820Entry e;
121 	uint64_t top = 0;
122 	uint32_t size = 0, pos = 0;
123 
124 	if (fw_cfg_e820_select(&size) == 0) {
125 		while (!fw_cfg_e820_read(&e, &size, &pos)) {
126 			uint64_t limit = e.address + e.length;
127 			if (e.type == 1 && limit < 4ULL * GiB && limit > top)
128 				top = limit;
129 		}
130 	}
131 	return (uintptr_t)top;
132 }
133 
fw_cfg_max_cpus(void)134 int fw_cfg_max_cpus(void)
135 {
136 	unsigned short max_cpus;
137 
138 	if (!fw_cfg_present())
139 		return 0;
140 
141 	fw_cfg_get(FW_CFG_MAX_CPUS, &max_cpus, sizeof(max_cpus));
142 	return max_cpus;
143 }
144 
145 /* ---------------------------------------------------------------------- */
146 
147 /*
148  * Starting with release 1.7 qemu provides ACPI tables via fw_cfg.
149  * Main advantage is that new (virtual) hardware which needs acpi
150  * support JustWorks[tm] without having to patch & update the firmware
151  * (seabios, coreboot, ...) accordingly.
152  *
153  * Qemu provides a etc/table-loader file with instructions for the
154  * firmware:
155  *   - A "load" instruction to fetch ACPI data from fw_cfg.
156  *   - A "pointer" instruction to patch a pointer.  This is needed to
157  *     get table-to-table references right, it is basically a
158  *     primitive dynamic linker for ACPI tables.
159  *   - A "checksum" instruction to generate ACPI table checksums.
160  *
161  * If a etc/table-loader file is found we'll go try loading the acpi
162  * tables from fw_cfg, otherwise we'll fallback to the ACPI tables
163  * compiled in.
164  */
165 
166 #define BIOS_LINKER_LOADER_FILESZ 56
167 
168 struct BiosLinkerLoaderEntry {
169 	uint32_t command;
170 	union {
171 		/*
172 		 * COMMAND_ALLOCATE - allocate a table from @alloc.file
173 		 * subject to @alloc.align alignment (must be power of 2)
174 		 * and @alloc.zone (can be HIGH or FSEG) requirements.
175 		 *
176 		 * Must appear exactly once for each file, and before
177 		 * this file is referenced by any other command.
178 		 */
179 		struct {
180 			char file[BIOS_LINKER_LOADER_FILESZ];
181 			uint32_t align;
182 			uint8_t zone;
183 		} alloc;
184 
185 		/*
186 		 * COMMAND_ADD_POINTER - patch the table (originating from
187 		 * @dest_file) at @pointer.offset, by adding a pointer to the table
188 		 * originating from @src_file. 1,2,4 or 8 byte unsigned
189 		 * addition is used depending on @pointer.size.
190 		 */
191 		struct {
192 			char dest_file[BIOS_LINKER_LOADER_FILESZ];
193 			char src_file[BIOS_LINKER_LOADER_FILESZ];
194 			uint32_t offset;
195 			uint8_t size;
196 		} pointer;
197 
198 		/*
199 		 * COMMAND_ADD_CHECKSUM - calculate checksum of the range specified by
200 		 * @cksum_start and @cksum_length fields,
201 		 * and then add the value at @cksum.offset.
202 		 * Checksum simply sums -X for each byte X in the range
203 		 * using 8-bit math.
204 		 */
205 		struct {
206 			char file[BIOS_LINKER_LOADER_FILESZ];
207 			uint32_t offset;
208 			uint32_t start;
209 			uint32_t length;
210 		} cksum;
211 
212 		/* padding */
213 		char pad[124];
214 	};
215 } __packed;
216 typedef struct BiosLinkerLoaderEntry BiosLinkerLoaderEntry;
217 
218 enum {
219 	BIOS_LINKER_LOADER_COMMAND_ALLOCATE     = 0x1,
220 	BIOS_LINKER_LOADER_COMMAND_ADD_POINTER  = 0x2,
221 	BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM = 0x3,
222 };
223 
224 enum {
225 	BIOS_LINKER_LOADER_ALLOC_ZONE_HIGH = 0x1,
226 	BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG = 0x2,
227 };
228 
fw_cfg_acpi_tables(unsigned long start)229 unsigned long fw_cfg_acpi_tables(unsigned long start)
230 {
231 	FWCfgFile f;
232 	BiosLinkerLoaderEntry *s;
233 	unsigned long *addrs, current;
234 	uint8_t *ptr;
235 	int i, j, src, dst, max;
236 
237 	if (fw_cfg_check_file(&f, "etc/table-loader"))
238 		return 0;
239 
240 	printk(BIOS_DEBUG, "QEMU: found ACPI tables in fw_cfg.\n");
241 
242 	max = f.size / sizeof(*s);
243 	s = malloc(f.size);
244 	addrs = malloc(max * sizeof(*addrs));
245 	fw_cfg_get(f.select, s, f.size);
246 
247 	current = start;
248 	for (i = 0; i < max && s[i].command != 0; i++) {
249 		void *cksum_data;
250 		uint32_t cksum;
251 		uint32_t addr4;
252 		uint64_t addr8;
253 		switch (s[i].command) {
254 		case BIOS_LINKER_LOADER_COMMAND_ALLOCATE:
255 			current = ALIGN_UP(current, s[i].alloc.align);
256 			if (fw_cfg_check_file(&f, s[i].alloc.file))
257 				goto err;
258 
259 			printk(BIOS_DEBUG, "QEMU: loading \"%s\" to 0x%lx (len %d)\n",
260 			       s[i].alloc.file, current, f.size);
261 			fw_cfg_get(f.select, (void *)current, f.size);
262 			addrs[i] = current;
263 			current += f.size;
264 			break;
265 
266 		case BIOS_LINKER_LOADER_COMMAND_ADD_POINTER:
267 			src = -1; dst = -1;
268 			for (j = 0; j < i; j++) {
269 				if (s[j].command != BIOS_LINKER_LOADER_COMMAND_ALLOCATE)
270 					continue;
271 				if (strcmp(s[j].alloc.file, s[i].pointer.dest_file) == 0)
272 					dst = j;
273 				if (strcmp(s[j].alloc.file, s[i].pointer.src_file) == 0)
274 					src = j;
275 			}
276 			if (src == -1 || dst == -1)
277 				goto err;
278 
279 			switch (s[i].pointer.size) {
280 			case 4:
281 				ptr = (uint8_t *)addrs[dst];
282 				ptr += s[i].pointer.offset;
283 				addr4 = read_le32(ptr);
284 				addr4 += addrs[src];
285 				write_le32(ptr, addr4);
286 				break;
287 
288 			case 8:
289 				ptr = (uint8_t *)addrs[dst];
290 				ptr += s[i].pointer.offset;
291 				addr8 = read_le64(ptr);
292 				addr8 += addrs[src];
293 				write_le64(ptr, addr8);
294 				break;
295 
296 			default:
297 				/*
298 				 * Should not happen.  ACPI knows 1 and 2 byte ptrs
299 				 * too, but we are operating with 32bit offsets which
300 				 * would simply not fit in there ...
301 				 */
302 				printk(BIOS_DEBUG, "QEMU: acpi: unimplemented ptr size %d\n",
303 				       s[i].pointer.size);
304 				goto err;
305 			}
306 			break;
307 
308 		case BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM:
309 			dst = -1;
310 			for (j = 0; j < i; j++) {
311 				if (s[j].command != BIOS_LINKER_LOADER_COMMAND_ALLOCATE)
312 					continue;
313 				if (strcmp(s[j].alloc.file, s[i].cksum.file) == 0)
314 					dst = j;
315 			}
316 			if (dst == -1)
317 				goto err;
318 
319 			ptr = (uint8_t *)(addrs[dst] + s[i].cksum.offset);
320 			cksum_data = (void *)(addrs[dst] + s[i].cksum.start);
321 			cksum = acpi_checksum(cksum_data, s[i].cksum.length);
322 			write_le8(ptr, cksum);
323 			break;
324 
325 		default:
326 			printk(BIOS_DEBUG, "QEMU: acpi: unknown script cmd 0x%x @ %p\n",
327 			       s[i].command, s+i);
328 			goto err;
329 		};
330 	}
331 
332 	printk(BIOS_DEBUG, "QEMU: loaded ACPI tables from fw_cfg.\n");
333 	free(s);
334 	free(addrs);
335 	return ALIGN_UP(current, 16);
336 
337 err:
338 	printk(BIOS_DEBUG, "QEMU: loading ACPI tables from fw_cfg failed.\n");
339 	free(s);
340 	free(addrs);
341 	return 0;
342 }
343 
344 /* ---------------------------------------------------------------------- */
345 /* pick up smbios information from fw_cfg                                 */
346 
347 #if CONFIG(GENERATE_SMBIOS_TABLES)
348 static const char *type1_manufacturer;
349 static const char *type1_product_name;
350 static const char *type1_version;
351 static const char *type1_serial_number;
352 static const char *type1_family;
353 static u8 type1_uuid[16];
354 
fw_cfg_smbios_init(void)355 static void fw_cfg_smbios_init(void)
356 {
357 	static int done = 0;
358 	uint16_t i, count = 0;
359 	FwCfgSmbios entry;
360 	char *buf;
361 
362 	if (done)
363 		return;
364 	done = 1;
365 
366 	fw_cfg_get(FW_CFG_SMBIOS_ENTRIES, &count, sizeof(count));
367 	for (i = 0; i < count; i++) {
368 		fw_cfg_read(&entry, sizeof(entry));
369 		buf = malloc(entry.length - sizeof(entry));
370 		fw_cfg_read(buf, entry.length - sizeof(entry));
371 		if (entry.headertype == SMBIOS_FIELD_ENTRY &&
372 		    entry.tabletype == 1) {
373 			switch (entry.fieldoffset) {
374 			case offsetof(struct smbios_type1, manufacturer):
375 				type1_manufacturer = strdup(buf);
376 				break;
377 			case offsetof(struct smbios_type1, product_name):
378 				type1_product_name = strdup(buf);
379 				break;
380 			case offsetof(struct smbios_type1, version):
381 				type1_version = strdup(buf);
382 				break;
383 			case offsetof(struct smbios_type1, serial_number):
384 				type1_serial_number = strdup(buf);
385 				break;
386 			case offsetof(struct smbios_type1, family):
387 				type1_family = strdup(buf);
388 				break;
389 			case offsetof(struct smbios_type1, uuid):
390 				memcpy(type1_uuid, buf, 16);
391 				break;
392 			}
393 		}
394 		free(buf);
395 	}
396 }
397 
smbios_next(unsigned long current)398 static unsigned long smbios_next(unsigned long current)
399 {
400 	struct smbios_header *header;
401 	int l, count = 0;
402 	char *s;
403 
404 	header = (void *)current;
405 	current += header->length;
406 	for (;;) {
407 		s = (void *)current;
408 		l = strlen(s);
409 		if (!l)
410 			return current + (count ? 1 : 2);
411 		current += l + 1;
412 		count++;
413 	}
414 }
415 
416 /*
417  * Starting with version 2.1 qemu provides a full set of smbios tables
418  * for the virtual hardware emulated, except type 0 (bios information).
419  *
420  * What we are going to do here is find the type0 table, keep it, and
421  * override everything else generated by coreboot with the qemu smbios
422  * tables.
423  *
424  * It's a bit hackish, but qemu is a special case (compared to real
425  * hardware) and this way we don't need special qemu support in the
426  * generic smbios code.
427  */
fw_cfg_smbios_tables(int * handle,unsigned long * current)428 unsigned long fw_cfg_smbios_tables(int *handle, unsigned long *current)
429 {
430 	FWCfgFile f;
431 	struct smbios_header *header;
432 	unsigned long start, end;
433 	int ret, i, count = 1;
434 	char *str;
435 
436 	if (fw_cfg_check_file(&f, "etc/smbios/smbios-tables"))
437 		return 0;
438 
439 	printk(BIOS_DEBUG, "QEMU: found smbios tables in fw_cfg (len %d).\n", f.size);
440 
441 	/*
442 	 * Search backwards for "coreboot" (first string in type0 table,
443 	 * see src/arch/x86/boot/smbios.c), then find type0 table.
444 	 */
445 	for (i = 0; i < 16384; i++) {
446 		str = (char*)(*current - i);
447 		if (strcmp(str, "coreboot") == 0)
448 			break;
449 	}
450 	if (i == 16384)
451 		return 0;
452 	i += sizeof(struct smbios_type0) - 2;
453 	header = (struct smbios_header *)(*current - i);
454 	if (header->type != SMBIOS_BIOS_INFORMATION || header->handle != 0)
455 		return 0;
456 	printk(BIOS_DEBUG, "QEMU: coreboot type0 table found at 0x%lx.\n",
457 	       *current - i);
458 	start = smbios_next(*current - i);
459 
460 	/*
461 	 * Fetch smbios tables from qemu, go find the end marker.
462 	 * We'll exclude the end marker as coreboot will add one.
463 	 */
464 	printk(BIOS_DEBUG, "QEMU: loading smbios tables to 0x%lx\n", start);
465 	fw_cfg_get(f.select, (void *)start, f.size);
466 	end = start;
467 	do {
468 		header = (struct smbios_header *)end;
469 		if (header->type == SMBIOS_END_OF_TABLE)
470 			break;
471 		end = smbios_next(end);
472 		count++;
473 	} while (end < start + f.size);
474 
475 	/* final fixups. */
476 	ret = end - *current;
477 	*current = end;
478 	*handle = count;
479 	return ret;
480 }
481 
smbios_mainboard_manufacturer(void)482 const char *smbios_mainboard_manufacturer(void)
483 {
484 	fw_cfg_smbios_init();
485 	return type1_manufacturer ?: CONFIG_MAINBOARD_SMBIOS_MANUFACTURER;
486 }
487 
smbios_mainboard_product_name(void)488 const char *smbios_mainboard_product_name(void)
489 {
490 	fw_cfg_smbios_init();
491 	return type1_product_name ?: CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME;
492 }
493 
smbios_mainboard_version(void)494 const char *smbios_mainboard_version(void)
495 {
496 	fw_cfg_smbios_init();
497 	return type1_version ?: CONFIG_MAINBOARD_VERSION;
498 }
499 
smbios_mainboard_serial_number(void)500 const char *smbios_mainboard_serial_number(void)
501 {
502 	fw_cfg_smbios_init();
503 	return type1_serial_number ?: CONFIG_MAINBOARD_SERIAL_NUMBER;
504 }
505 
smbios_system_set_uuid(u8 * uuid)506 void smbios_system_set_uuid(u8 *uuid)
507 {
508 	fw_cfg_smbios_init();
509 	memcpy(uuid, type1_uuid, 16);
510 }
511 #endif /* CONFIG(GENERATE_SMBIOS_TABLES) */
512 
513 /*
514  * Configure DMA setup
515  */
516 
fw_cfg_dma(int control,void * buf,int len)517 static void fw_cfg_dma(int control, void *buf, int len)
518 {
519 	volatile FwCfgDmaAccess dma;
520 	uintptr_t dma_desc_addr;
521 	uint32_t dma_desc_addr_hi, dma_desc_addr_lo;
522 
523 	dma.control = be32_to_cpu(control);
524 	dma.length  = be32_to_cpu(len);
525 	dma.address = be64_to_cpu((uintptr_t)buf);
526 
527 	dma_desc_addr = (uintptr_t)&dma;
528 	dma_desc_addr_lo = (uint32_t)(dma_desc_addr & 0xFFFFFFFFU);
529 	dma_desc_addr_hi = sizeof(uintptr_t) > sizeof(uint32_t)
530 				? (uint32_t)(dma_desc_addr >> 32) : 0;
531 
532 	// Skip writing high half if unnecessary.
533 	if (dma_desc_addr_hi)
534 		outl(be32_to_cpu(dma_desc_addr_hi), FW_CFG_DMA_ADDR_HIGH);
535 	outl(be32_to_cpu(dma_desc_addr_lo), FW_CFG_DMA_ADDR_LOW);
536 
537 	while (be32_to_cpu(dma.control) & ~FW_CFG_DMA_CTL_ERROR)
538 		;
539 }
540