mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-31 10:26:10 +01:00 
			
		
		
		
	In the SMBIOS 3 entry point the Structure Table Maximum Size field was incorrectly named max_struct_size. A Maximum Structure Size field only exists in the SMBIOS 2.1 entry point and has a different meaning. Call the Structure Table Length field table_maximum_size. Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
		
			
				
	
	
		
			198 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			198 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0-or-later
 | |
| /*
 | |
|  * (C) Copyright 2023 Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
 | |
|  */
 | |
| 
 | |
| #define LOG_CATEGORY UCLASS_QFW
 | |
| 
 | |
| #include <efi_loader.h>
 | |
| #include <errno.h>
 | |
| #include <log.h>
 | |
| #include <malloc.h>
 | |
| #include <mapmem.h>
 | |
| #include <qfw.h>
 | |
| #include <smbios.h>
 | |
| #include <tables_csum.h>
 | |
| #include <linux/sizes.h>
 | |
| #include <asm/global_data.h>
 | |
| 
 | |
| DECLARE_GLOBAL_DATA_PTR;
 | |
| 
 | |
| /**
 | |
|  * qfw_load_smbios_table() - load a QEMU firmware file
 | |
|  *
 | |
|  * @dev:	QEMU firmware device
 | |
|  * @size:	parameter to return the size of the loaded table
 | |
|  * @name:	name of the table to load
 | |
|  * Return:	address of the loaded table, NULL on error
 | |
|  */
 | |
| static void *qfw_load_smbios_table(struct udevice *dev, uint32_t *size,
 | |
| 				   char *name)
 | |
| {
 | |
| 	struct fw_file *file;
 | |
| 	struct bios_linker_entry *table;
 | |
| 
 | |
| 	file = qfw_find_file(dev, name);
 | |
| 	if (!file) {
 | |
| 		log_debug("Can't find %s\n", name);
 | |
| 		return NULL;
 | |
| 	}
 | |
| 
 | |
| 	*size = be32_to_cpu(file->cfg.size);
 | |
| 
 | |
| 	table = malloc(*size);
 | |
| 	if (!table) {
 | |
| 		log_err("Out of memory\n");
 | |
| 		return NULL;
 | |
| 	}
 | |
| 
 | |
| 	qfw_read_entry(dev, be16_to_cpu(file->cfg.select), *size, table);
 | |
| 
 | |
| 	return table;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * qfw_parse_smbios_anchor() - parse QEMU's SMBIOS anchor
 | |
|  *
 | |
|  * @dev:	QEMU firmware device
 | |
|  * @entry:	SMBIOS 3 structure to be filled from QEMU's anchor
 | |
|  * Return:	0 for success, -ve on error
 | |
|  */
 | |
| static int qfw_parse_smbios_anchor(struct udevice *dev,
 | |
| 				   struct smbios3_entry *entry)
 | |
| {
 | |
| 	void *table;
 | |
| 	uint32_t size;
 | |
| 	struct smbios_entry *entry2;
 | |
| 	struct smbios3_entry *entry3;
 | |
| 	const char smbios_sig[] = "_SM_";
 | |
| 	const char smbios3_sig[] = "_SM3_";
 | |
| 	int ret = 0;
 | |
| 
 | |
| 	table = qfw_load_smbios_table(dev, &size, "etc/smbios/smbios-anchor");
 | |
| 	if (!table)
 | |
| 		return -ENOMEM;
 | |
| 	if (!memcmp(table, smbios3_sig, sizeof(smbios3_sig) - 1)) {
 | |
| 		entry3 = table;
 | |
| 		if (entry3->length != sizeof(struct smbios3_entry)) {
 | |
| 			ret = -ENOENT;
 | |
| 			goto out;
 | |
| 		}
 | |
| 		memcpy(entry, entry3, sizeof(struct smbios3_entry));
 | |
| 	} else if (!memcmp(table, smbios_sig, sizeof(smbios_sig) - 1)) {
 | |
| 		entry2 = table;
 | |
| 		if (entry2->length != sizeof(struct smbios_entry)) {
 | |
| 			ret = -ENOENT;
 | |
| 			goto out;
 | |
| 		}
 | |
| 		memset(entry, 0, sizeof(struct smbios3_entry));
 | |
| 		memcpy(entry, smbios3_sig, sizeof(smbios3_sig));
 | |
| 		entry->length = sizeof(struct smbios3_entry);
 | |
| 		entry->major_ver = entry2->major_ver;
 | |
| 		entry->minor_ver = entry2->minor_ver;
 | |
| 		entry->table_maximum_size = entry2->struct_table_length;
 | |
| 	} else {
 | |
| 		ret = -ENOENT;
 | |
| 		goto out;
 | |
| 	}
 | |
| 	ret = 0;
 | |
| out:
 | |
| 	free(table);
 | |
| 
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * qfw_write_smbios_tables() - copy SMBIOS tables from QEMU
 | |
|  *
 | |
|  * @addr:	target buffer
 | |
|  * @size:	size of target buffer
 | |
|  * Return:	0 for success, -ve on error
 | |
|  */
 | |
| static int qfw_write_smbios_tables(u8 *addr, uint32_t size)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct udevice *dev;
 | |
| 	struct smbios3_entry *entry = (void *)addr;
 | |
| 	void *table;
 | |
| 	uint32_t table_size;
 | |
| 
 | |
| 	ret = qfw_get_dev(&dev);
 | |
| 	if (ret) {
 | |
| 		log_err("No QEMU firmware device\n");
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
| 	ret = qfw_read_firmware_list(dev);
 | |
| 	if (ret) {
 | |
| 		log_err("Can't read firmware file list\n");
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
| 	ret = qfw_parse_smbios_anchor(dev, entry);
 | |
| 	if (ret) {
 | |
| 		log_debug("Can't parse anchor\n");
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
| 	addr += entry->length;
 | |
| 	entry->struct_table_address = (uintptr_t)addr;
 | |
| 	entry->checksum = 0;
 | |
| 	entry->checksum = table_compute_checksum(entry,
 | |
| 						 sizeof(struct smbios3_entry));
 | |
| 
 | |
| 	table = qfw_load_smbios_table(dev, &table_size,
 | |
| 				      "etc/smbios/smbios-tables");
 | |
| 	if (table_size + sizeof(struct smbios3_entry) > size) {
 | |
| 		free(table);
 | |
| 		return -ENOMEM;
 | |
| 	}
 | |
| 	memcpy(addr, table, table_size);
 | |
| 	free(table);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * qfw_evt_write_smbios_tables() - event handler for copying QEMU SMBIOS tables
 | |
|  *
 | |
|  * Return:	0 on success, -ve on error (only out of memory)
 | |
|  */
 | |
| static int qfw_evt_write_smbios_tables(void)
 | |
| {
 | |
| 	phys_addr_t addr;
 | |
| 	void *ptr;
 | |
| 	int ret;
 | |
| 	/*
 | |
| 	 * TODO:
 | |
| 	 * This size is currently hard coded in lib/efi_loader/efi_smbios.c.
 | |
| 	 * We need a field in global data for the size.
 | |
| 	 */
 | |
| 	uint32_t size = SZ_4K;
 | |
| 
 | |
| 	/* Reserve 64K for SMBIOS tables, aligned to a 4K boundary */
 | |
| 	ptr = memalign(SZ_4K, size);
 | |
| 	if (!ptr) {
 | |
| 		log_err("Out of memory\n");
 | |
| 		return -ENOMEM;
 | |
| 	}
 | |
| 	addr = map_to_sysmem(ptr);
 | |
| 
 | |
| 	/* Generate SMBIOS tables */
 | |
| 	ret = qfw_write_smbios_tables(ptr, size);
 | |
| 	if (ret) {
 | |
| 		if (CONFIG_IS_ENABLED(GENERATE_SMBIOS_TABLE)) {
 | |
| 			log_info("Falling back to U-Boot generated SMBIOS tables\n");
 | |
| 			write_smbios_table(addr);
 | |
| 		}
 | |
| 	} else {
 | |
| 		log_debug("SMBIOS tables copied from QEMU\n");
 | |
| 	}
 | |
| 
 | |
| 	gd_set_smbios_start(addr);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| EVENT_SPY_SIMPLE(EVT_LAST_STAGE_INIT, qfw_evt_write_smbios_tables);
 |