Compare commits

...

10 Commits

Author SHA1 Message Date
Simon Glass
6268c3c145 smbios: Add support for showing table types 16 and 19
In some cases it is useful to find out the location of physical memory,
e.g. so that the memory@ nodes can be correctly set up in the
devicetree. Add support for parsing this information from the SMBIOS
tables.

Series-to: concept
Series-cc: heinrich
Cover-letter:
smbios: Refactor the smbios command and parser
The 'smbios' command has its own code for parsing SMBIOS tables. There
in also lib/smbios-parser.c which parses tables, although only
version 2.

This series moved parsing to lib/ and rationalises the code a little. It
also adds support for a few more tables.

Finally, a hook is added so operation from coreboot can be tested on
ellesmere.
END

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-08-15 14:48:46 -06:00
Simon Glass
68aea48c74 smbios: coreboot: Update smbios_get_header() to use smbios_info
Use the smbios_info struct in this function, so it can deal with any
version of SMBIOS table.

Also update smbios_update_version_full() to work the same way.

Drop find_next_header() which is now unused.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-08-15 14:48:46 -06:00
Simon Glass
69f0425961 smbios: Pass smbios_info to smbios_next_table()
At present smbios_next_table() does not support SMBIOS v2 tables. Pass
in the info struct so that it can check for the end of the tables.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-08-15 14:48:45 -06:00
Simon Glass
31d89f2dac smbios: Create a function to locate the tables
The code in the smbios command is a nice implementation of finding the
tables. It supports both SMBIOS2 and SMBIOS3, which smbios-parser.c does
not.

Move this code over to the library, creating a struct to hold the
result.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-08-15 14:48:45 -06:00
Simon Glass
00b2d3ea4e smbios: Move some parsing code to smbios-parser.c
The 'smbios' command has some parsing code, as does the SMBIOS parser
in the lib/ directory. Start to unify these by moving over a few
functions.

Require CONFIG_SMBIOS_PARSER to be enabled when using the command.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-08-15 14:48:45 -06:00
Simon Glass
1ab7ea8419 smbios: Rename smbios_header()
This function has the same name as the struct, which is confusing.
Rename it to smbios_get_header() and update the function comment a
little.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-08-15 14:48:45 -06:00
Simon Glass
f5576bd01b smbios: x86: Enable command by default
If SMBIOS is enabled on x86, enable the 'smbios' command by default,
so that the tables can be examined.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-08-15 14:48:45 -06:00
Simon Glass
a63ecb45b7 coreboot: Increase the cyclic limit
This fails in CI sometimes, so increase the limit to 50ms:

 cyclic_run() cyclic function video_init took too long: 20725us vs 5000us max

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-08-15 14:48:10 -06:00
Simon Glass
8145d7ea4b hooks: Add ellesmere riscv64_spl board
Add a symlink for this board to the travis-ci board.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-08-15 13:06:46 -06:00
Simon Glass
e7408cafdd hooks: ellesmere: Add a coreboot board
Add a coreboot board which can run under QEMU on ellesmere.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-08-15 11:44:52 -06:00
12 changed files with 369 additions and 120 deletions

View File

@@ -55,15 +55,15 @@ static int cb_get_str(struct udevice *dev, int id, size_t size, char *val)
static int cb_detect(struct udevice *dev) static int cb_detect(struct udevice *dev)
{ {
struct cb_sysinfo_priv *priv = dev_get_priv(dev); struct cb_sysinfo_priv *priv = dev_get_priv(dev);
const struct smbios_entry *smbios; struct smbios_info info;
int ret;
smbios = smbios_entry(lib_sysinfo.smbios_start, ret = smbios_locate(lib_sysinfo.smbios_start, &info);
lib_sysinfo.smbios_size); if (ret)
if (!smbios)
return 0; return 0;
priv->bios = smbios_header(smbios, SMBIOS_BIOS_INFORMATION); priv->bios = smbios_get_header(&info, SMBIOS_BIOS_INFORMATION);
priv->system = smbios_header(smbios, SMBIOS_SYSTEM_INFORMATION); priv->system = smbios_get_header(&info, SMBIOS_SYSTEM_INFORMATION);
priv->t0 = (struct smbios_type0 *)priv->bios; priv->t0 = (struct smbios_type0 *)priv->bios;
priv->t1 = (struct smbios_type1 *)priv->system; priv->t1 = (struct smbios_type1 *)priv->system;

View File

@@ -267,6 +267,7 @@ config CMD_SBI
config CMD_SMBIOS config CMD_SMBIOS
bool "smbios" bool "smbios"
depends on SMBIOS depends on SMBIOS
select SMBIOS_PARSER
help help
Display the SMBIOS information. Display the SMBIOS information.

View File

@@ -6,6 +6,7 @@
*/ */
#include <command.h> #include <command.h>
#include <errno.h>
#include <hexdump.h> #include <hexdump.h>
#include <mapmem.h> #include <mapmem.h>
#include <smbios.h> #include <smbios.h>
@@ -116,45 +117,46 @@ static const struct str_lookup_table associativity_strings[] = {
{ SMBIOS_CACHE_ASSOC_48WAY, "48-way Set-Associative" }, { SMBIOS_CACHE_ASSOC_48WAY, "48-way Set-Associative" },
{ SMBIOS_CACHE_ASSOC_64WAY, "64-way Set-Associative" }, { SMBIOS_CACHE_ASSOC_64WAY, "64-way Set-Associative" },
{ SMBIOS_CACHE_ASSOC_20WAY, "20-way Set-Associative" }, { SMBIOS_CACHE_ASSOC_20WAY, "20-way Set-Associative" },
}; };
/** static const struct str_lookup_table mem_array_location_strings[] = {
* smbios_get_string() - get SMBIOS string from table { 0x01, "Other" },
* { 0x02, "Unknown" },
* @table: SMBIOS table { 0x03, "System board or motherboard" },
* @index: index of the string { 0x04, "ISA add-on card" },
* Return: address of string, may point to empty string { 0x05, "EISA add-on card" },
*/ { 0x06, "PCI add-on card" },
static const char *smbios_get_string(void *table, int index) { 0x07, "MCA add-on card" },
{ { 0x08, "PCMCIA add-on card" },
const char *str = (char *)table + { 0x09, "Proprietary add-on card" },
((struct smbios_header *)table)->length; { 0x0A, "NuBus" },
static const char fallback[] = ""; { 0xA0, "PC-98/C20 add-on card" },
{ 0xA1, "PC-98/C24 add-on card" },
{ 0xA2, "PC-98/E add-on card" },
{ 0xA3, "PC-98/Local bus add-on card" },
};
if (!index) static const struct str_lookup_table mem_array_use_strings[] = {
return fallback; { 0x01, "Other" },
{ 0x02, "Unknown" },
{ 0x03, "System memory" },
{ 0x04, "Video memory" },
{ 0x05, "Flash memory" },
{ 0x06, "Non-volatile RAM" },
{ 0x07, "Cache memory" },
};
if (!*str) static const struct str_lookup_table mem_err_corr_strings[] = {
++str; { 0x01, "Other" },
for (--index; *str && index; --index) { 0x02, "Unknown" },
str += strlen(str) + 1; { 0x03, "None" },
{ 0x04, "Parity" },
{ 0x05, "Single-bit ECC" },
{ 0x06, "Multi-bit ECC" },
{ 0x07, "CRC" },
};
return str; static void smbios_print_generic(const struct smbios_header *table)
}
static struct smbios_header *next_table(struct smbios_header *table)
{
const char *str;
if (table->type == SMBIOS_END_OF_TABLE)
return NULL;
str = smbios_get_string(table, -1);
return (struct smbios_header *)(++str);
}
static void smbios_print_generic(struct smbios_header *table)
{ {
char *str = (char *)table + table->length; char *str = (char *)table + table->length;
@@ -403,6 +405,62 @@ static void smbios_print_type7(struct smbios_type7 *table)
printf("\tInstalled Cache Size 2: 0x%08x\n", table->inst_size2.data); printf("\tInstalled Cache Size 2: 0x%08x\n", table->inst_size2.data);
} }
static void smbios_print_type16(struct smbios_type16 *table)
{
u64 capacity;
printf("Physical Memory Array\n");
smbios_print_lookup_str(mem_array_location_strings, table->location,
ARRAY_SIZE(mem_array_location_strings),
"Location");
smbios_print_lookup_str(mem_array_use_strings, table->use,
ARRAY_SIZE(mem_array_use_strings), "Use");
smbios_print_lookup_str(mem_err_corr_strings, table->error_correction,
ARRAY_SIZE(mem_err_corr_strings),
"Error Correction");
capacity = table->maximum_capacity;
if (capacity == 0x7fffffff &&
table->hdr.length >= offsetof(struct smbios_type16,
extended_maximum_capacity)) {
capacity = table->extended_maximum_capacity;
printf("\tMaximum Capacity: %llu GB\n", capacity >> 30);
} else if (capacity > 0) {
printf("\tMaximum Capacity: %llu MB\n", capacity >> 10);
} else {
printf("\tMaximum Capacity: No limit\n");
}
printf("\tError Information Handle: 0x%04x\n",
table->error_information_handle);
printf("\tNumber Of Devices: %u\n", table->number_of_memory_devices);
}
static void smbios_print_type19(struct smbios_type19 *table)
{
u64 start_addr, end_addr;
printf("Memory Array Mapped Address\n");
/* Check if extended address fields are present (SMBIOS v2.7+) */
if (table->hdr.length >= 0x1f) {
start_addr = table->extended_starting_address;
end_addr = table->extended_ending_address;
} else {
start_addr = table->starting_address;
end_addr = table->ending_address;
}
/* The ending address is the address of the last 1KB block */
if (end_addr != 0xffffffff && end_addr != 0xffffffffffffffff)
end_addr = (end_addr + 1) * 1024 - 1;
printf("\tStarting Address: 0x%016llx\n", start_addr);
printf("\tEnding Address: 0x%016llx\n", end_addr);
printf("\tMemory Array Handle: 0x%04x\n", table->memory_array_handle);
printf("\tPartition Width: %u\n", table->partition_width);
}
static void smbios_print_type127(struct smbios_type127 *table) static void smbios_print_type127(struct smbios_type127 *table)
{ {
printf("End Of Table\n"); printf("End Of Table\n");
@@ -411,55 +469,31 @@ static void smbios_print_type127(struct smbios_type127 *table)
static int do_smbios(struct cmd_tbl *cmdtp, int flag, int argc, static int do_smbios(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[]) char *const argv[])
{ {
ulong addr; struct smbios_info info;
void *entry; int ret;
u32 size;
char version[12];
struct smbios_header *table;
static const char smbios_sig[] = "_SM_";
static const char smbios3_sig[] = "_SM3_";
size_t count = 0;
u32 table_maximum_size;
addr = gd_smbios_start(); ret = smbios_locate(gd_smbios_start(), &info);
if (!addr) { if (ret == -ENOENT) {
log_warning("SMBIOS not available\n"); log_warning("SMBIOS not available\n");
return CMD_RET_FAILURE; return CMD_RET_FAILURE;
} }
entry = map_sysmem(addr, 0); if (ret == -EINVAL) {
if (!memcmp(entry, smbios3_sig, sizeof(smbios3_sig) - 1)) {
struct smbios3_entry *entry3 = entry;
table = (void *)(uintptr_t)entry3->struct_table_address;
snprintf(version, sizeof(version), "%d.%d.%d",
entry3->major_ver, entry3->minor_ver, entry3->doc_rev);
table = (void *)(uintptr_t)entry3->struct_table_address;
size = entry3->length;
table_maximum_size = entry3->table_maximum_size;
} else if (!memcmp(entry, smbios_sig, sizeof(smbios_sig) - 1)) {
struct smbios_entry *entry2 = entry;
snprintf(version, sizeof(version), "%d.%d",
entry2->major_ver, entry2->minor_ver);
table = (void *)(uintptr_t)entry2->struct_table_address;
size = entry2->length;
table_maximum_size = entry2->struct_table_length;
} else {
log_err("Unknown SMBIOS anchor format\n"); log_err("Unknown SMBIOS anchor format\n");
return CMD_RET_FAILURE; return CMD_RET_FAILURE;
} }
if (table_compute_checksum(entry, size)) { if (ret == -EIO) {
log_err("Invalid anchor checksum\n"); log_err("Invalid anchor checksum\n");
return CMD_RET_FAILURE; return CMD_RET_FAILURE;
} }
printf("SMBIOS %s present.\n", version); printf("SMBIOS %d.%d.%d present.\n", info.version >> 16,
(info.version >> 8) & 0xff, info.version & 0xff);
for (struct smbios_header *pos = table; pos; pos = next_table(pos)) printf("%d structures occupying %d bytes\n", info.count, info.max_size);
++count; printf("Table at 0x%llx\n",
printf("%zd structures occupying %d bytes\n", count, table_maximum_size); (unsigned long long)map_to_sysmem(info.table));
printf("Table at 0x%llx\n", (unsigned long long)map_to_sysmem(table));
for (struct smbios_header *pos = table; pos; pos = next_table(pos)) { for (struct smbios_header *pos = info.table; pos;
pos = smbios_next_table(&info, pos)) {
printf("\nHandle 0x%04x, DMI type %d, %d bytes at 0x%llx\n", printf("\nHandle 0x%04x, DMI type %d, %d bytes at 0x%llx\n",
pos->handle, pos->type, pos->length, pos->handle, pos->type, pos->length,
(unsigned long long)map_to_sysmem(pos)); (unsigned long long)map_to_sysmem(pos));
@@ -482,6 +516,12 @@ static int do_smbios(struct cmd_tbl *cmdtp, int flag, int argc,
case SMBIOS_CACHE_INFORMATION: case SMBIOS_CACHE_INFORMATION:
smbios_print_type7((struct smbios_type7 *)pos); smbios_print_type7((struct smbios_type7 *)pos);
break; break;
case SMBIOS_PHYS_MEMORY_ARRAY:
smbios_print_type16((struct smbios_type16 *)pos);
break;
case SMBIOS_MEMORY_ARRAY_MAPPED_ADDRESS:
smbios_print_type19((struct smbios_type19 *)pos);
break;
case SMBIOS_END_OF_TABLE: case SMBIOS_END_OF_TABLE:
smbios_print_type127((struct smbios_type127 *)pos); smbios_print_type127((struct smbios_type127 *)pos);
break; break;

View File

@@ -32,6 +32,7 @@ CONFIG_DISPLAY_BOARDINFO_LATE=y
CONFIG_MISC_INIT_R=y CONFIG_MISC_INIT_R=y
CONFIG_HUSH_PARSER=y CONFIG_HUSH_PARSER=y
CONFIG_CMD_CPU=y CONFIG_CMD_CPU=y
# CONFIG_CMD_SMBIOS is not set
CONFIG_CMD_GPIO=y CONFIG_CMD_GPIO=y
CONFIG_CMD_PART=y CONFIG_CMD_PART=y
CONFIG_CMD_SPI=y CONFIG_CMD_SPI=y

View File

@@ -23,6 +23,7 @@ CONFIG_LOG=y
CONFIG_LOGF_LINE=y CONFIG_LOGF_LINE=y
CONFIG_LOGF_FUNC=y CONFIG_LOGF_FUNC=y
CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_DISPLAY_BOARDINFO_LATE=y
CONFIG_CYCLIC_MAX_CPU_TIME_US=50000
CONFIG_PCI_INIT_R=y CONFIG_PCI_INIT_R=y
CONFIG_CMD_IDE=y CONFIG_CMD_IDE=y
CONFIG_CMD_MMC=y CONFIG_CMD_MMC=y

View File

@@ -15,6 +15,23 @@
#define SMBIOS_MAJOR_VER 3 #define SMBIOS_MAJOR_VER 3
#define SMBIOS_MINOR_VER 7 #define SMBIOS_MINOR_VER 7
/**
* struct smbios_info - Information about SMBIOS tables
*
* @table: Pointer to the first table
* @count: Number of tables
* @max_size: Maximum size of the tables pointed to by struct_table_address
* @version: table version in the form 0xMMmmrr, where MM is the major version
* number (2 or 3), mm is the minor version number and rr is * the revision
* (always 0 for major-version 2)
*/
struct smbios_info {
struct smbios_header *table;
int count;
int max_size;
int version;
};
enum { enum {
SMBIOS_STR_MAX = 64, /* Maximum length allowed for a string */ SMBIOS_STR_MAX = 64, /* Maximum length allowed for a string */
}; };
@@ -264,6 +281,31 @@ struct __packed smbios_type7 {
char eos[SMBIOS_STRUCT_EOS_BYTES]; char eos[SMBIOS_STRUCT_EOS_BYTES];
}; };
struct __packed smbios_type16 {
struct smbios_header hdr;
u8 location;
u8 use;
u8 error_correction;
u32 maximum_capacity;
u16 error_information_handle;
u16 number_of_memory_devices;
/* The following field is only present in SMBIOS v2.7+ */
u64 extended_maximum_capacity;
char eos[SMBIOS_STRUCT_EOS_BYTES];
};
struct __packed smbios_type19 {
struct smbios_header hdr;
u32 starting_address;
u32 ending_address;
u16 memory_array_handle;
u8 partition_width;
/* The following fields are only present in SMBIOS v2.7+ */
u64 extended_starting_address;
u64 extended_ending_address;
char eos[SMBIOS_STRUCT_EOS_BYTES];
};
struct __packed smbios_type32 { struct __packed smbios_type32 {
u8 type; u8 type;
u8 length; u8 length;
@@ -325,13 +367,14 @@ ulong write_smbios_table(ulong addr);
const struct smbios_entry *smbios_entry(u64 address, u32 size); const struct smbios_entry *smbios_entry(u64 address, u32 size);
/** /**
* smbios_header() - Search for SMBIOS header type * smbios_get_header() - Search for an SMBIOS header type
* *
* @entry: pointer to a struct smbios_entry * @entry: pointer to the first entry
* @type: SMBIOS type * @type: SMBIOS type
* @return: NULL or a valid pointer to a struct smbios_header * @return: NULL or a valid pointer to a struct smbios_header
*/ */
const struct smbios_header *smbios_header(const struct smbios_entry *entry, int type); const struct smbios_header *smbios_get_header(const struct smbios_info *info,
int type);
/** /**
* smbios_string() - Return string from SMBIOS * smbios_string() - Return string from SMBIOS
@@ -379,8 +422,39 @@ int smbios_update_version_full(void *smbios_tab, const char *version);
* *
* @entry: pointer to a struct smbios3_entry * @entry: pointer to a struct smbios3_entry
* @header: pointer to a struct smbios_header * @header: pointer to a struct smbios_header
* @table_maximum_size: number of bytes used by the tables at @header
*/ */
void smbios_prepare_measurement(const struct smbios3_entry *entry, void smbios_prepare_measurement(const struct smbios3_entry *entry,
struct smbios_header *header); struct smbios_header *smbios_copy,
int table_maximum_size);
/**
* smbios_get_string() - get SMBIOS string from table
*
* @table: SMBIOS table
* @index: index of the string
* Return: address of string, may point to empty string
*/
const char *smbios_get_string(void *table, int index);
/**
* smbios_next_table() - Find the next table
*
* @info: SMBIOS info
* @table: Table to start from
* Return: Pointer to the next table, or NULL if @table is the last
*/
struct smbios_header *smbios_next_table(const struct smbios_info *info,
struct smbios_header *table);
/**
* smbios_locate() - Locate the SMBIOS tables
*
* @addr: Address of SMBIOS table, typically gd_smbios_start()
* @info: Returns the SMBIOS info, on success
* Return: 0 if OK, -ENOENT if no table is present, -EINVAL if the header
* signature is not recognised, -EIO if the checksum is wrong
*/
int smbios_locate(ulong addr, struct smbios_info *info);
#endif /* _SMBIOS_H_ */ #endif /* _SMBIOS_H_ */

View File

@@ -191,4 +191,38 @@
#define SMBIOS_CACHE_ASSOC_64WAY 13 #define SMBIOS_CACHE_ASSOC_64WAY 13
#define SMBIOS_CACHE_ASSOC_20WAY 14 #define SMBIOS_CACHE_ASSOC_20WAY 14
/* Physical Memory Array */
#define SMBIOS_MEM_ARRAY_LOCATION_OTHER 0x01
#define SMBIOS_MEM_ARRAY_LOCATION_UNKNOWN 0x02
#define SMBIOS_MEM_ARRAY_LOCATION_SYSTEM_BOARD 0x03
#define SMBIOS_MEM_ARRAY_LOCATION_ISA_ADDON 0x04
#define SMBIOS_MEM_ARRAY_LOCATION_EISA_ADDON 0x05
#define SMBIOS_MEM_ARRAY_LOCATION_PCI_ADDON 0x06
#define SMBIOS_MEM_ARRAY_LOCATION_MCA_ADDON 0x07
#define SMBIOS_MEM_ARRAY_LOCATION_PCMCIA_ADDON 0x08
#define SMBIOS_MEM_ARRAY_LOCATION_PROPRIETARY_ADDON 0x09
#define SMBIOS_MEM_ARRAY_LOCATION_NUBUS 0x0a
#define SMBIOS_MEM_ARRAY_LOCATION_PC98_C20_ADDON 0xa0
#define SMBIOS_MEM_ARRAY_LOCATION_PC98_C24_ADDON 0xa1
#define SMBIOS_MEM_ARRAY_LOCATION_PC98_E_ADDON 0xa2
#define SMBIOS_MEM_ARRAY_LOCATION_PC98_LOCAL_BUS_ADDON 0xa3
#define SMBIOS_MEM_ARRAY_USE_OTHER 0x01
#define SMBIOS_MEM_ARRAY_USE_UNKNOWN 0x02
#define SMBIOS_MEM_ARRAY_USE_SYSTEM 0x03
#define SMBIOS_MEM_ARRAY_USE_VIDEO 0x04
#define SMBIOS_MEM_ARRAY_USE_FLASH 0x05
#define SMBIOS_MEM_ARRAY_USE_NON_VOLATILE_RAM 0x06
#define SMBIOS_MEM_ARRAY_USE_CACHE 0x07
#define SMBIOS_MEM_ERR_CORR_OTHER 0x01
#define SMBIOS_MEM_ERR_CORR_UNKNOWN 0x02
#define SMBIOS_MEM_ERR_CORR_NONE 0x03
#define SMBIOS_MEM_ERR_CORR_PARITY 0x04
#define SMBIOS_MEM_ERR_CORR_SINGLE_BIT_ECC 0x05
#define SMBIOS_MEM_ERR_CORR_MULTI_BIT_ECC 0x06
#define SMBIOS_MEM_ERR_CORR_CRC 0x07
#define SMBIOS_MEM_CAPACITY_EXTENDED 0x80000000
#endif /* _SMBIOS_DEF_H_ */ #endif /* _SMBIOS_DEF_H_ */

View File

@@ -1171,6 +1171,7 @@ config SMBIOS
depends on X86 || EFI_LOADER depends on X86 || EFI_LOADER
default y default y
select LAST_STAGE_INIT select LAST_STAGE_INIT
imply CMD_SMBIOS if X86
help help
Indicates that this platform can support System Management BIOS Indicates that this platform can support System Management BIOS
(SMBIOS) tables. These provide various pieces of information about (SMBIOS) tables. These provide various pieces of information about

View File

@@ -1127,7 +1127,8 @@ tcg2_measure_smbios(struct udevice *dev,
(void *)((uintptr_t)entry->struct_table_address), (void *)((uintptr_t)entry->struct_table_address),
entry->table_maximum_size); entry->table_maximum_size);
smbios_prepare_measurement(entry, smbios_copy); smbios_prepare_measurement(entry, smbios_copy,
entry->table_maximum_size);
ret = measure_event(dev, 1, EV_EFI_HANDOFF_TABLES2, event_size, ret = measure_event(dev, 1, EV_EFI_HANDOFF_TABLES2, event_size,
(u8 *)event); (u8 *)event);

View File

@@ -6,11 +6,46 @@
#define LOG_CATEGORY LOGC_BOOT #define LOG_CATEGORY LOGC_BOOT
#include <errno.h> #include <errno.h>
#include <mapmem.h>
#include <smbios.h> #include <smbios.h>
#include <string.h> #include <string.h>
#include <tables_csum.h> #include <tables_csum.h>
#include <asm/global_data.h>
#include <linux/kernel.h> #include <linux/kernel.h>
DECLARE_GLOBAL_DATA_PTR;
const char *smbios_get_string(void *table, int index)
{
const char *str = (char *)table +
((struct smbios_header *)table)->length;
static const char fallback[] = "";
if (!index)
return fallback;
if (!*str)
++str;
for (--index; *str && index; --index)
str += strlen(str) + 1;
return str;
}
struct smbios_header *smbios_next_table(const struct smbios_info *info,
struct smbios_header *table)
{
const char *str;
if ((ulong)table - (ulong)info->table >= info->max_size)
return NULL;
if (table->type == SMBIOS_END_OF_TABLE)
return NULL;
str = smbios_get_string(table, -1);
return (struct smbios_header *)(++str);
}
const struct smbios_entry *smbios_entry(u64 address, u32 size) const struct smbios_entry *smbios_entry(u64 address, u32 size)
{ {
const struct smbios_entry *entry = (struct smbios_entry *)(uintptr_t)address; const struct smbios_entry *entry = (struct smbios_entry *)(uintptr_t)address;
@@ -27,35 +62,17 @@ const struct smbios_entry *smbios_entry(u64 address, u32 size)
return entry; return entry;
} }
static u8 *find_next_header(u8 *pos) const struct smbios_header *smbios_get_header(const struct smbios_info *info,
int type)
{ {
/* search for _double_ NULL bytes */ struct smbios_header *header;
while (!((*pos == 0) && (*(pos + 1) == 0)))
pos++;
/* step behind the double NULL bytes */ for (header = info->table; header;
pos += 2; header = smbios_next_table(info, header)) {
return pos;
}
static struct smbios_header *get_next_header(const struct smbios_header *curr)
{
u8 *pos = ((u8 *)curr) + curr->length;
return (struct smbios_header *)find_next_header(pos);
}
const struct smbios_header *smbios_header(const struct smbios_entry *entry, int type)
{
const unsigned int num_header = entry->struct_count;
const struct smbios_header *header = (struct smbios_header *)((uintptr_t)entry->struct_table_address);
for (unsigned int i = 0; i < num_header; i++) {
if (header->type == type) if (header->type == type)
return header; return header;
header = get_next_header(header); header = smbios_next_table(info, header);
} }
return NULL; return NULL;
@@ -90,15 +107,21 @@ char *smbios_string(const struct smbios_header *header, int index)
return string_from_smbios_table(header, index); return string_from_smbios_table(header, index);
} }
int smbios_update_version_full(void *smbios_tab, const char *version) int smbios_update_version_full(void *smbios_tab, const char *new_version)
{ {
const struct smbios_header *hdr; const struct smbios_header *hdr;
struct smbios_info info;
struct smbios_type0 *bios; struct smbios_type0 *bios;
uint old_len, len; uint old_len, len;
char *ptr; char *ptr;
int ret;
ret = smbios_locate(map_to_sysmem(smbios_tab), &info);
if (ret)
return log_msg_ret("tab", -ENOENT);
log_info("Updating SMBIOS table at %p\n", smbios_tab); log_info("Updating SMBIOS table at %p\n", smbios_tab);
hdr = smbios_header(smbios_tab, SMBIOS_BIOS_INFORMATION); hdr = smbios_get_header(&info, SMBIOS_BIOS_INFORMATION);
if (!hdr) if (!hdr)
return log_msg_ret("tab", -ENOENT); return log_msg_ret("tab", -ENOENT);
bios = (struct smbios_type0 *)hdr; bios = (struct smbios_type0 *)hdr;
@@ -113,12 +136,12 @@ int smbios_update_version_full(void *smbios_tab, const char *version)
* are not disturbed. See smbios_add_string() * are not disturbed. See smbios_add_string()
*/ */
old_len = strnlen(ptr, SMBIOS_STR_MAX); old_len = strnlen(ptr, SMBIOS_STR_MAX);
len = strnlen(version, SMBIOS_STR_MAX); len = strnlen(new_version, SMBIOS_STR_MAX);
if (len > old_len) if (len > old_len)
return log_ret(-ENOSPC); return log_ret(-ENOSPC);
log_debug("Replacing SMBIOS type 0 version string '%s'\n", ptr); log_debug("Replacing SMBIOS type 0 version string '%s'\n", ptr);
memcpy(ptr, version, len); memcpy(ptr, new_version, len);
#ifdef LOG_DEBUG #ifdef LOG_DEBUG
print_buffer((ulong)ptr, ptr, 1, old_len + 1, 0); print_buffer((ulong)ptr, ptr, 1, old_len + 1, 0);
#endif #endif
@@ -224,23 +247,26 @@ static void clear_smbios_table(struct smbios_header *header,
} }
void smbios_prepare_measurement(const struct smbios3_entry *entry, void smbios_prepare_measurement(const struct smbios3_entry *entry,
struct smbios_header *smbios_copy) struct smbios_header *smbios_copy,
int table_maximum_size)
{ {
u32 i, j; struct smbios_info info;
void *table_end; u32 i;
struct smbios_header *header;
table_end = (void *)((u8 *)smbios_copy + entry->table_maximum_size); info.table = smbios_copy;
info.count = 0; /* unknown */
info.max_size = table_maximum_size;
info.version = 3 << 16;
for (i = 0; i < ARRAY_SIZE(smbios_filter_tables); i++) { for (i = 0; i < ARRAY_SIZE(smbios_filter_tables); i++) {
header = smbios_copy; struct smbios_header *header;
for (j = 0; (void *)header < table_end; j++) {
for (header = info.table; header;
header = smbios_next_table(&info, header)) {
if (header->type == smbios_filter_tables[i].type) if (header->type == smbios_filter_tables[i].type)
break; break;
header = get_next_header(header);
} }
if ((void *)header >= table_end) if (!header)
continue; continue;
clear_smbios_table(header, clear_smbios_table(header,
@@ -248,3 +274,44 @@ void smbios_prepare_measurement(const struct smbios3_entry *entry,
smbios_filter_tables[i].count); smbios_filter_tables[i].count);
} }
} }
int smbios_locate(ulong addr, struct smbios_info *info)
{
static const char smbios3_sig[] = "_SM3_";
static const char smbios_sig[] = "_SM_";
void *entry;
uint size;
if (!addr)
return -ENOENT;
entry = map_sysmem(addr, 0);
if (!memcmp(entry, smbios3_sig, sizeof(smbios3_sig) - 1)) {
struct smbios3_entry *entry3 = entry;
info->table = (void *)(uintptr_t)entry3->struct_table_address;
info->version = entry3->major_ver << 16 |
entry3->minor_ver << 8 | entry3->doc_rev;
size = entry3->length;
info->max_size = entry3->table_maximum_size;
} else if (!memcmp(entry, smbios_sig, sizeof(smbios_sig) - 1)) {
struct smbios_entry *entry2 = entry;
info->version = entry2->major_ver << 16 |
entry2->minor_ver << 8;
info->table = (void *)(uintptr_t)entry2->struct_table_address;
size = entry2->length;
info->max_size = entry2->struct_table_length;
} else {
return -EINVAL;
}
if (table_compute_checksum(entry, size))
return -EIO;
info->count = 0;
for (struct smbios_header *pos = info->table; pos;
pos = smbios_next_table(info, pos))
info->count++;
return 0;
}

View File

@@ -0,0 +1,28 @@
# Copyright (c) 2016 Konsulko Group. All rights reserved.
# Copyright 2021 Google LLC
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
console_impl=qemu
qemu_machine="pc"
qemu_binary="qemu-system-i386"
qemu_extra_args="-nographic -cpu qemu32 -netdev user,id=net0,tftp=${UBOOT_TRAVIS_BUILD_DIR} -device e1000,netdev=net0"
qemu_kernel_args="-bios ${U_BOOT_BUILD_DIR}/coreboot.rom"
reset_impl=none
flash_impl=none

View File

@@ -0,0 +1 @@
../travis-ci/conf.qemu-riscv64_spl_na