From ddb3f0b17fd4d3d7324322d69eb21ddb5646bec2 Mon Sep 17 00:00:00 2001 From: Matt DeVillier Date: Sat, 1 Nov 2025 11:42:36 -0500 Subject: [PATCH] drivers/hwid_dmi: Populate SMBIOS product name from CBFS hwid file Add driver to read 'hwid' file from CBFS and use it for SMBIOS product name. Processes the ChromeOS-format HWID string by removing prefix after colon, trimming whitespace, and extracting base name before any hyphen/space. Returned string is normalized to have the first character/letter capitalized, and the rest lower case. If no HWID file is found in CBFS, the fallback is CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME. This driver is intended to allow ChromeOS devices running upstream coreboot to persist their board's unique HWID and use it as the SMBIOS board name, but it is not limited to that function. TEST=tested in MrChromebox downstream. Multiple devices which use the same ChromeOS board but differ in HWID can use the same firmware image and still be properly identified. Change-Id: I1af1df4c79858d23ef71400abe72f41eec6c25c6 Signed-off-by: Matt DeVillier Reviewed-on: https://review.coreboot.org/c/coreboot/+/90063 Tested-by: build bot (Jenkins) Reviewed-by: Martin L Roth --- src/drivers/hwid_dmi/Kconfig | 12 ++++ src/drivers/hwid_dmi/Makefile.mk | 3 + src/drivers/hwid_dmi/hwid_dmi.c | 97 ++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 src/drivers/hwid_dmi/Kconfig create mode 100644 src/drivers/hwid_dmi/Makefile.mk create mode 100644 src/drivers/hwid_dmi/hwid_dmi.c diff --git a/src/drivers/hwid_dmi/Kconfig b/src/drivers/hwid_dmi/Kconfig new file mode 100644 index 0000000000..27aeca38da --- /dev/null +++ b/src/drivers/hwid_dmi/Kconfig @@ -0,0 +1,12 @@ +## SPDX-License-Identifier: GPL-2.0-only + +config DRIVERS_HWID_DMI + bool "HWID from CBFS for SMBIOS product name" + default n + help + Enable this option to read the hardware ID (HWID) from a + file in CBFS and use it to populate the SMBIOS product name. + The driver will read a file named 'hwid' from CBFS, process it + to extract the base HWID (trimming whitespace, removing 'hwid:' + prefix, and dropping everything after hyphen or space), and + use it as the SMBIOS system product name. diff --git a/src/drivers/hwid_dmi/Makefile.mk b/src/drivers/hwid_dmi/Makefile.mk new file mode 100644 index 0000000000..3af79a0236 --- /dev/null +++ b/src/drivers/hwid_dmi/Makefile.mk @@ -0,0 +1,3 @@ +## SPDX-License-Identifier: GPL-2.0-only + +ramstage-$(CONFIG_DRIVERS_HWID_DMI) += hwid_dmi.c diff --git a/src/drivers/hwid_dmi/hwid_dmi.c b/src/drivers/hwid_dmi/hwid_dmi.c new file mode 100644 index 0000000000..786f936253 --- /dev/null +++ b/src/drivers/hwid_dmi/hwid_dmi.c @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include +#include +#include + +#define MAX_HWID_LENGTH 0x100 + +/* + * Process the HWID string according to requirements: + * - If a colon is found, delete everything before it + * - Trim leading/trailing whitespace + * - Drop anything after hyphen or space + * + * Examples: + * - 'hardware_id: NOCTURNE D5B-A5F-B47-H6A-A5L' --> Nocturne + * - 'BANSHEE-UZTQ B4B-D3A-F3F-D8A-A7O' --> Banshee + */ +static void process_hwid(char *hwid) +{ + char *src = hwid; + char *dst = hwid; + char *colon; + char *end; + + if (!hwid || !*hwid) + return; + + /* Look for a colon and skip everything before it */ + colon = strchr(hwid, ':'); + if (colon) { + src = colon + 1; /* Start after the colon */ + } + + /* Trim leading whitespace */ + while (*src && isspace((unsigned char)*src)) + src++; + + /* Copy characters until we hit a hyphen, space, or end of string */ + while (*src && *src != '-' && !isspace((unsigned char)*src)) { + *dst++ = *src++; + } + + /* Null terminate */ + *dst = '\0'; + + /* Trim trailing whitespace (shouldn't be any based on the logic above, but just in case) */ + end = dst - 1; + while (end >= hwid && isspace((unsigned char)*end)) { + *end = '\0'; + end--; + } + + /* Normalize casing: capitalize first character, lowercase the rest */ + if (*hwid) { + char *p = hwid; + + *p = toupper((unsigned char)*p); + for (p = hwid + 1; *p; p++) + *p = tolower((unsigned char)*p); + } +} + +const char *smbios_system_product_name(void) +{ + static char hwid_str[MAX_HWID_LENGTH + 1] = {0}; + + /* Return cached value if already loaded */ + if (hwid_str[0] != '\0') + return hwid_str; + + /* Try to load HWID from CBFS */ + size_t hwid_len = cbfs_load("hwid", hwid_str, MAX_HWID_LENGTH); + + if (hwid_len > 0) { + /* Ensure null termination */ + hwid_str[hwid_len] = '\0'; + + /* Process the HWID string */ + process_hwid(hwid_str); + + /* Check if we have a valid string after processing */ + if (hwid_str[0] != '\0') { + printk(BIOS_INFO, "HWID: Using '%s' as product name\n", hwid_str); + return hwid_str; + } + } + + /* Fall back to default if file not found or processing resulted in empty string */ + printk(BIOS_WARNING, "HWID: File not found or invalid, using default product name\n"); + strncpy(hwid_str, CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME, MAX_HWID_LENGTH); + hwid_str[MAX_HWID_LENGTH] = '\0'; + + return hwid_str; +}