
From: Simon Glass <sjg@chromium.org> Microsoft uses information from SMBIOS tables to determine the device Windows is running on. This same approach has been adopted by fwupd and other projects. The information is used to create a list of Computer Hardware Identifiers (CHIDs) which are used to select firmware builds, etc. The EFI app needs to support this approach so it can map CHIDs to the associated compatible string. Introduce a header file for CHIDs and a function which can extract the necessary information from the SMBIOS tables. Further work will deal with actually calculating CHIDs. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- include/chid.h | 106 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/Kconfig | 9 +++++ lib/Makefile | 2 + lib/chid.c | 73 ++++++++++++++++++++++++++++++++++ 4 files changed, 190 insertions(+) create mode 100644 include/chid.h create mode 100644 lib/chid.c diff --git a/include/chid.h b/include/chid.h new file mode 100644 index 00000000000..5746ba88c32 --- /dev/null +++ b/include/chid.h @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Computer Hardware Identifiers (Windows CHID) + * + * See: https://github.com/fwupd/fwupd/blob/main/docs/hwids.md + * + * Copyright 2025 Simon Glass <sjg@chromium.org> + */ + +#ifndef __chid_h +#define __chid_h + +#include <linux/types.h> + +/** + * enum chid_field_t - fields we pick up from SMBIOS tables + * + * Used as BIT(x) values that can be ORed together to define which fields are + * used in each CHID variant. + * + * The table and field name is shown here (see smbios.h). All are strings + * except those noted as int. + * + * @CHID_MANUF: SMBIOS Type 1 (System Information): manufacturer + * @CHID_FAMILY: SMBIOS Type 1 (System Information): family + * @CHID_PRODUCT_NAME: SMBIOS Type 1 (System Information): product_name + * @CHID_PRODUCT_SKU: SMBIOS Type 1 (System Information): sku_number + * @CHID_BOARD_MANUF: SMBIOS Type 2 (Baseboard Information): manufacturer + * @CHID_BOARD_PRODUCT: SMBIOS Type 2 (Baseboard Information): product_name + * @CHID_BIOS_VENDOR: SMBIOS Type 0 (BIOS Information): vendor + * @CHID_BIOS_VERSION: SMBIOS Type 0 (BIOS Information): bios_ver + * @CHID_BIOS_MAJOR: SMBIOS Type 0 (BIOS Information): bios_major_release (int) + * @CHID_BIOS_MINOR: SMBIOS Type 0 (BIOS Information): bios_minor_release (int) + * @CHID_ENCLOSURE_TYPE: SMBIOS Type 3 (System Enclosure): chassis_type (int) + * @CHID_COUNT: Number of CHID fields + */ +enum chid_field_t { + CHID_MANUF, + CHID_FAMILY, + CHID_PRODUCT_NAME, + CHID_PRODUCT_SKU, + CHID_BOARD_MANUF, + CHID_BOARD_PRODUCT, + CHID_BIOS_VENDOR, + CHID_BIOS_VERSION, + CHID_BIOS_MAJOR, + CHID_BIOS_MINOR, + CHID_ENCLOSURE_TYPE, + + CHID_COUNT, +}; + +/** + * struct chid_variant - defines which fields are used in each CHID variant + * + * @name: Human-readable name for debugging + * @fields: Bitmask of fields (BIT(CHID_xxx) values ORed together) + */ +struct chid_variant { + const char *name; + u32 fields; +}; + +/** + * struct chid_data - contains SMBIOS field values to use in calculating CHID + * + * There is one field here for each item in enum chid_field_t + * + * @manuf: System manufacturer string + * @family: Product family string + * @product_name: Product name string + * @product_sku: Product SKU string + * @board_manuf: Baseboard manufacturer string + * @board_product: Baseboard product string + * @bios_vendor: BIOS vendor string + * @bios_version: BIOS version string + * @bios_major: BIOS major version number + * @bios_minor: BIOS minor version number + * @enclosure_type: System enclosure type + */ +struct chid_data { + const char *manuf; + const char *family; + const char *product_name; + const char *product_sku; + const char *board_manuf; + const char *board_product; + const char *bios_vendor; + const char *bios_version; + u8 bios_major; + u8 bios_minor; + u8 enclosure_type; +}; + +/** + * chid_from_smbios() - Extract CHID data from SMBIOS tables + * + * @chid: Pointer to CHID data structure to fill + * + * Return: 0 if OK, -ENOENT if a required table is missing (SMBIOS types 0-1), + * other -ve error code if the SMBIOS tables cannot be found (see + * smbios_locate()) + */ +int chid_from_smbios(struct chid_data *chid); + +#endif diff --git a/lib/Kconfig b/lib/Kconfig index ed35c1f0b30..c45a98313aa 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -1187,6 +1187,15 @@ config SMBIOS_PARSER help A simple parser for SMBIOS data. +config CHID + bool "Support Microsoft Computer Hardware IDs (CHIDs)" + depends on SMBIOS_PARSER + default y if ARCH_EFI_ARM || SANDBOX + help + Provides support for Microsoft Computer Hardware IDs (CHIDs) which + can be used to identify a board so that the correct devicetree is + used with it. + source "lib/optee/Kconfig" config TEST_FDTDEC diff --git a/lib/Makefile b/lib/Makefile index bcca308e0d8..af191913873 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -29,6 +29,8 @@ obj-y += charset.o endif endif +obj-$(CONFIG_CHID) += chid.o + ifdef CONFIG_USB_TTY obj-y += circbuf.o else diff --git a/lib/chid.c b/lib/chid.c new file mode 100644 index 00000000000..10e9b8fecae --- /dev/null +++ b/lib/chid.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Computer Hardware Identifiers (Windows CHID) support + * + * This implements the Microsoft Computer Hardware ID specification + * used by Windows Update and fwupd for hardware identification. + * + * See: https://github.com/fwupd/fwupd/blob/main/docs/hwids.md + * See: https://docs.microsoft.com/en-us/windows-hardware/drivers/install/specifying... + * + * Copyright 2025 Simon Glass <sjg@chromium.org> + */ + +#define LOG_CATEGORY LOGC_ACPI + +#include <chid.h> +#include <errno.h> +#include <smbios.h> +#include <asm/global_data.h> + +DECLARE_GLOBAL_DATA_PTR; + +int chid_from_smbios(struct chid_data *chid) +{ + const struct smbios_type0 *bios; + const struct smbios_type1 *sys; + const struct smbios_type2 *board; + const struct smbios_type3 *encl; + struct smbios_info info; + int ret; + + /* Clear the structure first */ + memset(chid, '\0', sizeof(*chid)); + + ret = smbios_locate(gd_smbios_start(), &info); + if (ret) + return ret; + + /* Extract BIOS Information (Type 0) */ + bios = smbios_get_header(&info, SMBIOS_BIOS_INFORMATION); + if (!bios) + return log_msg_ret("cf0", -ENOENT); + + chid->bios_vendor = smbios_string(&bios->hdr, bios->vendor); + chid->bios_version = smbios_string(&bios->hdr, bios->bios_ver); + chid->bios_major = bios->bios_major_release; + chid->bios_minor = bios->bios_minor_release; + + /* Extract System Information (Type 1) */ + sys = smbios_get_header(&info, SMBIOS_SYSTEM_INFORMATION); + if (!sys) + return log_msg_ret("cf1", -ENOENT); + chid->manuf = smbios_string(&sys->hdr, sys->manufacturer); + chid->product_name = smbios_string(&sys->hdr, sys->product_name); + chid->family = smbios_string(&sys->hdr, sys->family); + chid->product_sku = smbios_string(&sys->hdr, sys->sku_number); + + /* Extract Baseboard Information (Type 2) */ + board = smbios_get_header(&info, SMBIOS_BOARD_INFORMATION); + if (board) { + chid->board_manuf = smbios_string(&board->hdr, + board->manufacturer); + chid->board_product = smbios_string(&board->hdr, + board->product_name); + } + + /* Extract System Enclosure Information (Type 3) */ + encl = smbios_get_header(&info, SMBIOS_SYSTEM_ENCLOSURE); + if (encl) + chid->enclosure_type = encl->chassis_type; + + return 0; +} -- 2.43.0