smbios: Allow writing to the coreboot version string

When U-Boot is booted from coreboot the SMBIOS tables are written by
coreboot, not U-Boot. The existing method of updating the BIOS version
string does not work in that case, since gd->smbios_version is only set
when U-Boot writes the tables.

Add a new function which allows the version to be updated by parsing the
tables and writing the string in the correct place. Since coreboot
provides a pointer to the SMBIOS tables in its sysinfo structure, this
makes it easy to do the update.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass 2021-03-15 18:00:11 +13:00
parent 11a38a2573
commit 272e62cb83
3 changed files with 58 additions and 4 deletions

View File

@ -14,6 +14,10 @@
#define SMBIOS_MAJOR_VER 3
#define SMBIOS_MINOR_VER 0
enum {
SMBIOS_STR_MAX = 64, /* Maximum length allowed for a string */
};
/* SMBIOS structure types */
enum {
SMBIOS_BIOS_INFORMATION = 0,
@ -269,4 +273,20 @@ const char *smbios_string(const struct smbios_header *header, int index);
*/
int smbios_update_version(const char *version);
/**
* smbios_update_version_full() - Update the version string
*
* This can be called after the SMBIOS tables are written (e.g. after the U-Boot
* main loop has started) to update the BIOS version string (SMBIOS table 0).
* It scans for the correct place to put the version, so does not need U-Boot
* to have actually written the tables itself (e.g. if a previous bootloader
* did it).
*
* @smbios_tab: Start of SMBIOS tables
* @version: New version string to use
* @return 0 if OK, -ENOENT if no version string was previously written,
* -ENOSPC if the new string is too large to fit
*/
int smbios_update_version_full(void *smbios_tab, const char *version);
#endif /* _SMBIOS_H_ */

View File

@ -3,6 +3,8 @@
* Copyright (C) 2020, Bachmann electronic GmbH
*/
#define LOG_CATEGORY LOGC_BOOT
#include <common.h>
#include <smbios.h>
@ -94,3 +96,39 @@ const 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)
{
const struct smbios_header *hdr;
struct smbios_type0 *bios;
uint old_len, len;
char *ptr;
log_info("Updating SMBIOS table at %p\n", smbios_tab);
hdr = smbios_header(smbios_tab, SMBIOS_BIOS_INFORMATION);
if (!hdr)
return log_msg_ret("tab", -ENOENT);
bios = (struct smbios_type0 *)hdr;
ptr = (char *)smbios_string(hdr, bios->bios_ver);
if (!ptr)
return log_msg_ret("str", -ENOMEDIUM);
/*
* This string is supposed to have at least enough bytes and is
* padded with spaces. Update it, taking care not to move the
* \0 terminator, so that other strings in the string table
* are not disturbed. See smbios_add_string()
*/
old_len = strnlen(ptr, SMBIOS_STR_MAX);
len = strnlen(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);
#ifdef LOG_DEBUG
print_buffer((ulong)ptr, ptr, 1, old_len + 1, 0);
#endif
return 0;
}

View File

@ -20,10 +20,6 @@
DECLARE_GLOBAL_DATA_PTR;
enum {
SMBIOS_STR_MAX = 64, /* Maximum length allowed for a string */
};
/**
* struct smbios_ctx - context for writing SMBIOS tables
*