mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-31 02:15:45 +01:00 
			
		
		
		
	smbios: copy QEMU tables
QEMU provides SMBIOS tables with detailed information. We should not try to replicate them in U-Boot. If we want to inform about U-Boot, we can add a Firmware Inventory Information (type 45) table in future. Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com> Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
		
				
					committed by
					
						 Tom Rini
						Tom Rini
					
				
			
			
				
	
			
			
			
						parent
						
							481ffca485
						
					
				
				
					commit
					1c5aab803c
				
			| @@ -62,7 +62,7 @@ static struct table_info table_list[] = { | |||||||
| #ifdef CONFIG_GENERATE_ACPI_TABLE | #ifdef CONFIG_GENERATE_ACPI_TABLE | ||||||
| 	{ "acpi", write_acpi_tables, BLOBLISTT_ACPI_TABLES, 0x10000, 0x1000}, | 	{ "acpi", write_acpi_tables, BLOBLISTT_ACPI_TABLES, 0x10000, 0x1000}, | ||||||
| #endif | #endif | ||||||
| #ifdef CONFIG_GENERATE_SMBIOS_TABLE | #if defined(CONFIG_GENERATE_SMBIOS_TABLE) && !defined(CONFIG_QFW_SMBIOS) | ||||||
| 	{ "smbios", write_smbios_table, BLOBLISTT_SMBIOS_TABLES, 0x1000, 0x100}, | 	{ "smbios", write_smbios_table, BLOBLISTT_SMBIOS_TABLES, 0x1000, 0x100}, | ||||||
| #endif | #endif | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -554,6 +554,13 @@ config QFW_MMIO | |||||||
| 	  Hidden option to enable MMIO QEMU fw_cfg interface. This will be | 	  Hidden option to enable MMIO QEMU fw_cfg interface. This will be | ||||||
| 	  selected by the appropriate QEMU board. | 	  selected by the appropriate QEMU board. | ||||||
|  |  | ||||||
|  | config QFW_SMBIOS | ||||||
|  | 	bool | ||||||
|  | 	default y | ||||||
|  | 	depends on QFW && SMBIOS && !SANDBOX | ||||||
|  | 	help | ||||||
|  | 	  Hidden option to read SMBIOS tables from QEMU. | ||||||
|  |  | ||||||
| config I2C_EEPROM | config I2C_EEPROM | ||||||
| 	bool "Enable driver for generic I2C-attached EEPROMs" | 	bool "Enable driver for generic I2C-attached EEPROMs" | ||||||
| 	depends on MISC | 	depends on MISC | ||||||
|   | |||||||
| @@ -65,6 +65,7 @@ obj-y += qfw.o | |||||||
| obj-$(CONFIG_QFW_ACPI) += qfw_acpi.o | obj-$(CONFIG_QFW_ACPI) += qfw_acpi.o | ||||||
| obj-$(CONFIG_QFW_PIO) += qfw_pio.o | obj-$(CONFIG_QFW_PIO) += qfw_pio.o | ||||||
| obj-$(CONFIG_QFW_MMIO) += qfw_mmio.o | obj-$(CONFIG_QFW_MMIO) += qfw_mmio.o | ||||||
|  | obj-$(CONFIG_QFW_SMBIOS) += qfw_smbios.o | ||||||
| obj-$(CONFIG_SANDBOX) += qfw_sandbox.o | obj-$(CONFIG_SANDBOX) += qfw_sandbox.o | ||||||
| endif | endif | ||||||
| obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o | obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o | ||||||
|   | |||||||
							
								
								
									
										197
									
								
								drivers/misc/qfw_smbios.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								drivers/misc/qfw_smbios.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,197 @@ | |||||||
|  | // 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->max_struct_size = entry2->max_struct_size; | ||||||
|  | 	} 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); | ||||||
| @@ -60,7 +60,9 @@ static int install_smbios_table(void) | |||||||
| 	ulong addr; | 	ulong addr; | ||||||
| 	void *buf; | 	void *buf; | ||||||
|  |  | ||||||
| 	if (!IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLE) || IS_ENABLED(CONFIG_X86)) | 	if (!IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLE) || | ||||||
|  | 	    IS_ENABLED(CONFIG_X86) || | ||||||
|  | 	    IS_ENABLED(CONFIG_QFW_SMBIOS)) | ||||||
| 		return 0; | 		return 0; | ||||||
|  |  | ||||||
| 	/* Align the table to a 4KB boundary to keep EFI happy */ | 	/* Align the table to a 4KB boundary to keep EFI happy */ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user