[PATCH v2 00/10] smbios: Refactor the smbios command and parser

From: Simon Glass <sjg@chromium.org> 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. Changes in v2: - Fix the return values on error Simon Glass (10): hooks: ellesmere: Add a coreboot board hooks: Add ellesmere riscv64_spl board coreboot: Increase the cyclic limit smbios: x86: Enable command by default smbios: Rename smbios_header() smbios: Move some parsing code to smbios-parser.c smbios: Create a function to locate the tables smbios: Pass smbios_info to smbios_next_table() smbios: coreboot: Update smbios_get_header() to use smbios_info smbios: Add support for showing table types 16 and 19 board/coreboot/coreboot/sysinfo.c | 12 +- cmd/Kconfig | 1 + cmd/smbios.c | 184 +++++++++++------- configs/chromebook_link_defconfig | 1 + configs/coreboot_defconfig | 1 + include/smbios.h | 82 +++++++- include/smbios_def.h | 34 ++++ lib/Kconfig | 1 + lib/efi_loader/efi_tcg2.c | 3 +- lib/smbios-parser.c | 143 ++++++++++---- test/hooks/bin/ellesmere/conf.coreboot_qemu | 28 +++ .../bin/ellesmere/conf.qemu-riscv64_spl_na | 1 + 12 files changed, 370 insertions(+), 121 deletions(-) create mode 100644 test/hooks/bin/ellesmere/conf.coreboot_qemu create mode 120000 test/hooks/bin/ellesmere/conf.qemu-riscv64_spl_na -- 2.43.0 base-commit: 711a77d57380f21ddd90ba4884ce0a7ae8f0e591 branch: loado2

From: Simon Glass <sjg@chromium.org> Add a coreboot board which can run under QEMU on ellesmere. Signed-off-by: Simon Glass <sjg@chromium.org> --- (no changes since v1) test/hooks/bin/ellesmere/conf.coreboot_qemu | 28 +++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 test/hooks/bin/ellesmere/conf.coreboot_qemu diff --git a/test/hooks/bin/ellesmere/conf.coreboot_qemu b/test/hooks/bin/ellesmere/conf.coreboot_qemu new file mode 100644 index 00000000000..76d6927510f --- /dev/null +++ b/test/hooks/bin/ellesmere/conf.coreboot_qemu @@ -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 -- 2.43.0

From: Simon Glass <sjg@chromium.org> Add a symlink for this board to the travis-ci board. Signed-off-by: Simon Glass <sjg@chromium.org> --- (no changes since v1) test/hooks/bin/ellesmere/conf.qemu-riscv64_spl_na | 1 + 1 file changed, 1 insertion(+) create mode 120000 test/hooks/bin/ellesmere/conf.qemu-riscv64_spl_na diff --git a/test/hooks/bin/ellesmere/conf.qemu-riscv64_spl_na b/test/hooks/bin/ellesmere/conf.qemu-riscv64_spl_na new file mode 120000 index 00000000000..b6c3362b6bc --- /dev/null +++ b/test/hooks/bin/ellesmere/conf.qemu-riscv64_spl_na @@ -0,0 +1 @@ +../travis-ci/conf.qemu-riscv64_spl_na \ No newline at end of file -- 2.43.0

From: Simon Glass <sjg@chromium.org> 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> --- (no changes since v1) configs/coreboot_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/coreboot_defconfig b/configs/coreboot_defconfig index bd190e40ffc..d26ee565945 100644 --- a/configs/coreboot_defconfig +++ b/configs/coreboot_defconfig @@ -23,6 +23,7 @@ CONFIG_LOG=y CONFIG_LOGF_LINE=y CONFIG_LOGF_FUNC=y CONFIG_DISPLAY_BOARDINFO_LATE=y +CONFIG_CYCLIC_MAX_CPU_TIME_US=50000 CONFIG_PCI_INIT_R=y CONFIG_CMD_IDE=y CONFIG_CMD_MMC=y -- 2.43.0

From: Simon Glass <sjg@chromium.org> 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> --- (no changes since v1) configs/chromebook_link_defconfig | 1 + lib/Kconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/configs/chromebook_link_defconfig b/configs/chromebook_link_defconfig index a2231cc314f..05d81f516fc 100644 --- a/configs/chromebook_link_defconfig +++ b/configs/chromebook_link_defconfig @@ -32,6 +32,7 @@ CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_MISC_INIT_R=y CONFIG_HUSH_PARSER=y CONFIG_CMD_CPU=y +# CONFIG_CMD_SMBIOS is not set CONFIG_CMD_GPIO=y CONFIG_CMD_PART=y CONFIG_CMD_SPI=y diff --git a/lib/Kconfig b/lib/Kconfig index ed93f798f69..0834d46fbb4 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -1171,6 +1171,7 @@ config SMBIOS depends on X86 || EFI_LOADER default y select LAST_STAGE_INIT + imply CMD_SMBIOS if X86 help Indicates that this platform can support System Management BIOS (SMBIOS) tables. These provide various pieces of information about -- 2.43.0

From: Simon Glass <sjg@chromium.org> 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> --- (no changes since v1) board/coreboot/coreboot/sysinfo.c | 4 ++-- include/smbios.h | 7 ++++--- lib/smbios-parser.c | 5 +++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/board/coreboot/coreboot/sysinfo.c b/board/coreboot/coreboot/sysinfo.c index d6b19530023..5cf5cf3e286 100644 --- a/board/coreboot/coreboot/sysinfo.c +++ b/board/coreboot/coreboot/sysinfo.c @@ -62,8 +62,8 @@ static int cb_detect(struct udevice *dev) if (!smbios) return 0; - priv->bios = smbios_header(smbios, SMBIOS_BIOS_INFORMATION); - priv->system = smbios_header(smbios, SMBIOS_SYSTEM_INFORMATION); + priv->bios = smbios_get_header(smbios, SMBIOS_BIOS_INFORMATION); + priv->system = smbios_get_header(smbios, SMBIOS_SYSTEM_INFORMATION); priv->t0 = (struct smbios_type0 *)priv->bios; priv->t1 = (struct smbios_type1 *)priv->system; diff --git a/include/smbios.h b/include/smbios.h index b5fed57aba2..41e25bd31b3 100644 --- a/include/smbios.h +++ b/include/smbios.h @@ -325,13 +325,14 @@ ulong write_smbios_table(ulong addr); 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 * @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_entry *entry, int type); /** * smbios_string() - Return string from SMBIOS diff --git a/lib/smbios-parser.c b/lib/smbios-parser.c index 9a62b3c760d..2db90d8235b 100644 --- a/lib/smbios-parser.c +++ b/lib/smbios-parser.c @@ -46,7 +46,8 @@ static struct smbios_header *get_next_header(const struct smbios_header *curr) return (struct smbios_header *)find_next_header(pos); } -const struct smbios_header *smbios_header(const struct smbios_entry *entry, int type) +const struct smbios_header *smbios_get_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); @@ -98,7 +99,7 @@ int smbios_update_version_full(void *smbios_tab, const char *version) char *ptr; log_info("Updating SMBIOS table at %p\n", smbios_tab); - hdr = smbios_header(smbios_tab, SMBIOS_BIOS_INFORMATION); + hdr = smbios_get_header(smbios_tab, SMBIOS_BIOS_INFORMATION); if (!hdr) return log_msg_ret("tab", -ENOENT); bios = (struct smbios_type0 *)hdr; -- 2.43.0

From: Simon Glass <sjg@chromium.org> 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> --- (no changes since v1) cmd/Kconfig | 1 + cmd/smbios.c | 44 ++++++-------------------------------------- include/smbios.h | 17 +++++++++++++++++ lib/smbios-parser.c | 28 ++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 38 deletions(-) diff --git a/cmd/Kconfig b/cmd/Kconfig index 37f47e5976e..4d564ab5ac6 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -267,6 +267,7 @@ config CMD_SBI config CMD_SMBIOS bool "smbios" depends on SMBIOS + select SMBIOS_PARSER help Display the SMBIOS information. diff --git a/cmd/smbios.c b/cmd/smbios.c index 562dd7959be..8dd31190a01 100644 --- a/cmd/smbios.c +++ b/cmd/smbios.c @@ -6,6 +6,7 @@ */ #include <command.h> +#include <errno.h> #include <hexdump.h> #include <mapmem.h> #include <smbios.h> @@ -119,42 +120,7 @@ static const struct str_lookup_table associativity_strings[] = { }; -/** - * 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 - */ -static 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; -} - -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) +static void smbios_print_generic(const struct smbios_header *table) { char *str = (char *)table + table->length; @@ -454,12 +420,14 @@ static int do_smbios(struct cmd_tbl *cmdtp, int flag, int argc, } printf("SMBIOS %s present.\n", version); - for (struct smbios_header *pos = table; pos; pos = next_table(pos)) + for (struct smbios_header *pos = table; pos; + pos = smbios_next_table(pos)) ++count; printf("%zd structures occupying %d bytes\n", count, table_maximum_size); 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 = table; pos; + pos = smbios_next_table(pos)) { printf("\nHandle 0x%04x, DMI type %d, %d bytes at 0x%llx\n", pos->handle, pos->type, pos->length, (unsigned long long)map_to_sysmem(pos)); diff --git a/include/smbios.h b/include/smbios.h index 41e25bd31b3..1415de1c5d0 100644 --- a/include/smbios.h +++ b/include/smbios.h @@ -384,4 +384,21 @@ int smbios_update_version_full(void *smbios_tab, const char *version); void smbios_prepare_measurement(const struct smbios3_entry *entry, struct smbios_header *header); +/** + * 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 + * + * @table: Table to start from + * Return: Pointer to the next table, or NULL if @table is the last + */ +struct smbios_header *smbios_next_table(struct smbios_header *table); + #endif /* _SMBIOS_H_ */ diff --git a/lib/smbios-parser.c b/lib/smbios-parser.c index 2db90d8235b..42c095f3d08 100644 --- a/lib/smbios-parser.c +++ b/lib/smbios-parser.c @@ -11,6 +11,34 @@ #include <tables_csum.h> #include <linux/kernel.h> +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(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); +} + const struct smbios_entry *smbios_entry(u64 address, u32 size) { const struct smbios_entry *entry = (struct smbios_entry *)(uintptr_t)address; -- 2.43.0

From: Simon Glass <sjg@chromium.org> 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> --- Changes in v2: - Fix the return values on error cmd/smbios.c | 52 ++++++++++++--------------------------------- include/smbios.h | 27 +++++++++++++++++++++++ lib/smbios-parser.c | 45 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 39 deletions(-) diff --git a/cmd/smbios.c b/cmd/smbios.c index 8dd31190a01..830cd513ad7 100644 --- a/cmd/smbios.c +++ b/cmd/smbios.c @@ -377,56 +377,30 @@ static void smbios_print_type127(struct smbios_type127 *table) static int do_smbios(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - ulong addr; - void *entry; - 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(); - if (!addr) { + struct smbios_info info; + int ret; + + ret = smbios_locate(gd_smbios_start(), &info); + if (ret == -ENOENT) { log_warning("SMBIOS not available\n"); return CMD_RET_FAILURE; } - entry = map_sysmem(addr, 0); - 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 { + if (ret == -EINVAL) { log_err("Unknown SMBIOS anchor format\n"); return CMD_RET_FAILURE; } - if (table_compute_checksum(entry, size)) { + if (ret == -EIO) { log_err("Invalid anchor checksum\n"); 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 = smbios_next_table(pos)) - ++count; - printf("%zd structures occupying %d bytes\n", count, table_maximum_size); - printf("Table at 0x%llx\n", (unsigned long long)map_to_sysmem(table)); + printf("%d structures occupying %d bytes\n", info.count, info.max_size); + printf("Table at 0x%llx\n", + (unsigned long long)map_to_sysmem(info.table)); - for (struct smbios_header *pos = table; pos; + for (struct smbios_header *pos = info.table; pos; pos = smbios_next_table(pos)) { printf("\nHandle 0x%04x, DMI type %d, %d bytes at 0x%llx\n", pos->handle, pos->type, pos->length, diff --git a/include/smbios.h b/include/smbios.h index 1415de1c5d0..44f16309a8d 100644 --- a/include/smbios.h +++ b/include/smbios.h @@ -15,6 +15,23 @@ #define SMBIOS_MAJOR_VER 3 #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 { SMBIOS_STR_MAX = 64, /* Maximum length allowed for a string */ }; @@ -401,4 +418,14 @@ const char *smbios_get_string(void *table, int index); */ struct smbios_header *smbios_next_table(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, -EINVAL if the address is 0, -NOENT 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_ */ diff --git a/lib/smbios-parser.c b/lib/smbios-parser.c index 42c095f3d08..918dd3bef48 100644 --- a/lib/smbios-parser.c +++ b/lib/smbios-parser.c @@ -6,11 +6,15 @@ #define LOG_CATEGORY LOGC_BOOT #include <errno.h> +#include <mapmem.h> #include <smbios.h> #include <string.h> #include <tables_csum.h> +#include <asm/global_data.h> #include <linux/kernel.h> +DECLARE_GLOBAL_DATA_PTR; + const char *smbios_get_string(void *table, int index) { const char *str = (char *)table + @@ -277,3 +281,44 @@ void smbios_prepare_measurement(const struct smbios3_entry *entry, 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 -EINVAL; + + 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 -ENOENT; + } + if (table_compute_checksum(entry, size)) + return -EIO; + + info->count = 0; + for (struct smbios_header *pos = info->table; pos; + pos = smbios_next_table(pos)) + info->count++; + + return 0; +} -- 2.43.0

From: Simon Glass <sjg@chromium.org> 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> --- (no changes since v1) cmd/smbios.c | 2 +- include/smbios.h | 4 +++- lib/smbios-parser.c | 7 +++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/cmd/smbios.c b/cmd/smbios.c index 830cd513ad7..5d1d9eadb11 100644 --- a/cmd/smbios.c +++ b/cmd/smbios.c @@ -401,7 +401,7 @@ static int do_smbios(struct cmd_tbl *cmdtp, int flag, int argc, (unsigned long long)map_to_sysmem(info.table)); for (struct smbios_header *pos = info.table; pos; - pos = smbios_next_table(pos)) { + pos = smbios_next_table(&info, pos)) { printf("\nHandle 0x%04x, DMI type %d, %d bytes at 0x%llx\n", pos->handle, pos->type, pos->length, (unsigned long long)map_to_sysmem(pos)); diff --git a/include/smbios.h b/include/smbios.h index 44f16309a8d..e0e9f6a0a40 100644 --- a/include/smbios.h +++ b/include/smbios.h @@ -413,10 +413,12 @@ 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(struct smbios_header *table); +struct smbios_header *smbios_next_table(const struct smbios_info *info, + struct smbios_header *table); /** * smbios_locate() - Locate the SMBIOS tables diff --git a/lib/smbios-parser.c b/lib/smbios-parser.c index 918dd3bef48..8bf22854980 100644 --- a/lib/smbios-parser.c +++ b/lib/smbios-parser.c @@ -32,10 +32,13 @@ const char *smbios_get_string(void *table, int index) return str; } -struct smbios_header *smbios_next_table(struct smbios_header *table) +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; @@ -317,7 +320,7 @@ int smbios_locate(ulong addr, struct smbios_info *info) info->count = 0; for (struct smbios_header *pos = info->table; pos; - pos = smbios_next_table(pos)) + pos = smbios_next_table(info, pos)) info->count++; return 0; -- 2.43.0

From: Simon Glass <sjg@chromium.org> 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> --- (no changes since v1) board/coreboot/coreboot/sysinfo.c | 12 +++--- include/smbios.h | 8 ++-- lib/efi_loader/efi_tcg2.c | 3 +- lib/smbios-parser.c | 66 +++++++++++++------------------ 4 files changed, 41 insertions(+), 48 deletions(-) diff --git a/board/coreboot/coreboot/sysinfo.c b/board/coreboot/coreboot/sysinfo.c index 5cf5cf3e286..2fb68cbfa92 100644 --- a/board/coreboot/coreboot/sysinfo.c +++ b/board/coreboot/coreboot/sysinfo.c @@ -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) { 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, - lib_sysinfo.smbios_size); - if (!smbios) + ret = smbios_locate(lib_sysinfo.smbios_start, &info); + if (ret) return 0; - priv->bios = smbios_get_header(smbios, SMBIOS_BIOS_INFORMATION); - priv->system = smbios_get_header(smbios, SMBIOS_SYSTEM_INFORMATION); + priv->bios = smbios_get_header(&info, SMBIOS_BIOS_INFORMATION); + priv->system = smbios_get_header(&info, SMBIOS_SYSTEM_INFORMATION); priv->t0 = (struct smbios_type0 *)priv->bios; priv->t1 = (struct smbios_type1 *)priv->system; diff --git a/include/smbios.h b/include/smbios.h index e0e9f6a0a40..ac71056114d 100644 --- a/include/smbios.h +++ b/include/smbios.h @@ -348,8 +348,8 @@ const struct smbios_entry *smbios_entry(u64 address, u32 size); * @type: SMBIOS type * @return: NULL or a valid pointer to a struct smbios_header */ -const struct smbios_header * -smbios_get_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 @@ -397,9 +397,11 @@ int smbios_update_version_full(void *smbios_tab, const char *version); * * @entry: pointer to a struct smbios3_entry * @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, - struct smbios_header *header); + struct smbios_header *smbios_copy, + int table_maximum_size); /** * smbios_get_string() - get SMBIOS string from table diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c index 1832eeb5dce..f1276ca7293 100644 --- a/lib/efi_loader/efi_tcg2.c +++ b/lib/efi_loader/efi_tcg2.c @@ -1127,7 +1127,8 @@ tcg2_measure_smbios(struct udevice *dev, (void *)((uintptr_t)entry->struct_table_address), 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, (u8 *)event); diff --git a/lib/smbios-parser.c b/lib/smbios-parser.c index 8bf22854980..575472f95a2 100644 --- a/lib/smbios-parser.c +++ b/lib/smbios-parser.c @@ -62,36 +62,17 @@ const struct smbios_entry *smbios_entry(u64 address, u32 size) return entry; } -static u8 *find_next_header(u8 *pos) -{ - /* search for _double_ NULL bytes */ - while (!((*pos == 0) && (*(pos + 1) == 0))) - pos++; - - /* step behind the double NULL bytes */ - pos += 2; - - 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_get_header(const struct smbios_entry *entry, +const struct smbios_header *smbios_get_header(const struct smbios_info *info, int type) { - const unsigned int num_header = entry->struct_count; - const struct smbios_header *header = (struct smbios_header *)((uintptr_t)entry->struct_table_address); + struct smbios_header *header; - for (unsigned int i = 0; i < num_header; i++) { + for (header = info->table; header; + header = smbios_next_table(info, header)) { if (header->type == type) return header; - header = get_next_header(header); + header = smbios_next_table(info, header); } return NULL; @@ -126,15 +107,21 @@ char *smbios_string(const struct smbios_header *header, int 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; + struct smbios_info info; struct smbios_type0 *bios; uint old_len, len; 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); - hdr = smbios_get_header(smbios_tab, SMBIOS_BIOS_INFORMATION); + hdr = smbios_get_header(&info, SMBIOS_BIOS_INFORMATION); if (!hdr) return log_msg_ret("tab", -ENOENT); bios = (struct smbios_type0 *)hdr; @@ -149,12 +136,12 @@ int smbios_update_version_full(void *smbios_tab, const char *version) * are not disturbed. See smbios_add_string() */ old_len = strnlen(ptr, SMBIOS_STR_MAX); - len = strnlen(version, SMBIOS_STR_MAX); + len = strnlen(new_version, SMBIOS_STR_MAX); if (len > old_len) return log_ret(-ENOSPC); log_debug("Replacing SMBIOS type 0 version string '%s'\n", ptr); - memcpy(ptr, version, len); + memcpy(ptr, new_version, len); #ifdef LOG_DEBUG print_buffer((ulong)ptr, ptr, 1, old_len + 1, 0); #endif @@ -260,23 +247,26 @@ static void clear_smbios_table(struct smbios_header *header, } 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; - void *table_end; - struct smbios_header *header; + struct smbios_info info; + u32 i; - 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++) { - header = smbios_copy; - for (j = 0; (void *)header < table_end; j++) { + struct smbios_header *header; + + for (header = info.table; header; + header = smbios_next_table(&info, header)) { if (header->type == smbios_filter_tables[i].type) break; - - header = get_next_header(header); } - if ((void *)header >= table_end) + if (!header) continue; clear_smbios_table(header, -- 2.43.0

From: Simon Glass <sjg@chromium.org> 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. Signed-off-by: Simon Glass <sjg@chromium.org> --- (no changes since v1) cmd/smbios.c | 98 ++++++++++++++++++++++++++++++++++++++++++++ include/smbios.h | 25 +++++++++++ include/smbios_def.h | 34 +++++++++++++++ 3 files changed, 157 insertions(+) diff --git a/cmd/smbios.c b/cmd/smbios.c index 5d1d9eadb11..4f672d3f4ad 100644 --- a/cmd/smbios.c +++ b/cmd/smbios.c @@ -117,7 +117,43 @@ static const struct str_lookup_table associativity_strings[] = { { SMBIOS_CACHE_ASSOC_48WAY, "48-way Set-Associative" }, { SMBIOS_CACHE_ASSOC_64WAY, "64-way Set-Associative" }, { SMBIOS_CACHE_ASSOC_20WAY, "20-way Set-Associative" }, +}; + +static const struct str_lookup_table mem_array_location_strings[] = { + { 0x01, "Other" }, + { 0x02, "Unknown" }, + { 0x03, "System board or motherboard" }, + { 0x04, "ISA add-on card" }, + { 0x05, "EISA add-on card" }, + { 0x06, "PCI add-on card" }, + { 0x07, "MCA add-on card" }, + { 0x08, "PCMCIA add-on card" }, + { 0x09, "Proprietary add-on card" }, + { 0x0A, "NuBus" }, + { 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" }, +}; + +static const struct str_lookup_table mem_array_use_strings[] = { + { 0x01, "Other" }, + { 0x02, "Unknown" }, + { 0x03, "System memory" }, + { 0x04, "Video memory" }, + { 0x05, "Flash memory" }, + { 0x06, "Non-volatile RAM" }, + { 0x07, "Cache memory" }, +}; +static const struct str_lookup_table mem_err_corr_strings[] = { + { 0x01, "Other" }, + { 0x02, "Unknown" }, + { 0x03, "None" }, + { 0x04, "Parity" }, + { 0x05, "Single-bit ECC" }, + { 0x06, "Multi-bit ECC" }, + { 0x07, "CRC" }, }; static void smbios_print_generic(const struct smbios_header *table) @@ -369,6 +405,62 @@ static void smbios_print_type7(struct smbios_type7 *table) 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) { printf("End Of Table\n"); @@ -424,6 +516,12 @@ static int do_smbios(struct cmd_tbl *cmdtp, int flag, int argc, case SMBIOS_CACHE_INFORMATION: smbios_print_type7((struct smbios_type7 *)pos); 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: smbios_print_type127((struct smbios_type127 *)pos); break; diff --git a/include/smbios.h b/include/smbios.h index ac71056114d..1bae4d99b05 100644 --- a/include/smbios.h +++ b/include/smbios.h @@ -281,6 +281,31 @@ struct __packed smbios_type7 { 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 { u8 type; u8 length; diff --git a/include/smbios_def.h b/include/smbios_def.h index 81c5781217f..287f5bf9eac 100644 --- a/include/smbios_def.h +++ b/include/smbios_def.h @@ -191,4 +191,38 @@ #define SMBIOS_CACHE_ASSOC_64WAY 13 #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_ */ -- 2.43.0
participants (1)
-
Simon Glass