mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-20 11:55:03 +00: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:
parent
481ffca485
commit
1c5aab803c
5 changed files with 209 additions and 2 deletions
|
@ -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 */
|
||||||
|
|
Loading…
Add table
Reference in a new issue