diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in
index 694369dcc..c06bc21d4 100644
--- a/contrib/fwupd.spec.in
+++ b/contrib/fwupd.spec.in
@@ -463,7 +463,8 @@ done
%if 0%{?have_uefi}
%{_datadir}/installed-tests/fwupd/efi
%endif
-%{_datadir}/installed-tests/fwupd/dmi
+%{_datadir}/installed-tests/fwupd/chassis_type
+%{_datadir}/installed-tests/fwupd/sys_vendor
%{_datadir}/fwupd/device-tests/*.json
%{_libexecdir}/installed-tests/fwupd/*
%dir %{_sysconfdir}/fwupd/remotes.d
diff --git a/docs/fwupdplugin.toml.in b/docs/fwupdplugin.toml.in
index 674b961c9..de9bd99e6 100644
--- a/docs/fwupdplugin.toml.in
+++ b/docs/fwupdplugin.toml.in
@@ -46,6 +46,7 @@ content_files = [
"tutorial.md",
"hsi.md",
"ds20.md",
+ "hwids.md",
"bios-settings.md",
@plugin_readme_outputs@,
]
diff --git a/docs/hwids.md b/docs/hwids.md
new file mode 100644
index 000000000..ad7fdc613
--- /dev/null
+++ b/docs/hwids.md
@@ -0,0 +1,85 @@
+---
+title: Hardware IDs
+---
+
+## Introduction
+
+Hardware IDs are used by fwupd to identify specific hardware.
+This is useful as the device-specific identifiers may be the same for different firmware streams.
+Each hardware ID has varying levels of specificity for the hardware, for instance matching only the
+system OEM, or matching up to 8 fields including the system BIOS version.
+
+For instance, Dell and Lenovo might ship a wireless broadband modem with the same chip vendor and
+product IDs of `USB\VID_0BDA&PID_5850` and although the two OEMs share the same internal device,
+the firmware may be different.
+To cover this case fwupd allows adding `hardware` requirements that mean we can deploy firmware that
+targets `USB\VID_0BDA&PID_5850`, but *only for Dell* or *only for Lenovo* systems.
+
+Microsoft calls these values "CHIDs" and they are generated on Windows from the SBMIOS tables using `ComputerHardwareIds.exe`
+binary which can be found [here](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/computerhardwareids).
+The list of CHIDs used in Microsoft Windows is:
+
+ HardwareID-0 ← Manufacturer + Family + Product Name + SKU Number + BIOS Vendor + BIOS Version + BIOS Major Release + BIOS Minor Release
+ HardwareID-1 ← Manufacturer + Family + Product Name + BIOS Vendor + BIOS Version + BIOS Major Release + BIOS Minor Release
+ HardwareID-2 ← Manufacturer + Product Name + BIOS Vendor + BIOS Version + BIOS Major Release + BIOS Minor Release
+ HardwareID-3 ← Manufacturer + Family + ProductName + SKU Number + Baseboard_Manufacturer + Baseboard_Product
+ HardwareID-4 ← Manufacturer + Family + ProductName + SKU Number
+ HardwareID-5 ← Manufacturer + Family + ProductName
+ HardwareID-6 ← Manufacturer + SKU Number + Baseboard_Manufacturer + Baseboard_Product
+ HardwareID-7 ← Manufacturer + SKU Number
+ HardwareID-8 ← Manufacturer + ProductName + Baseboard_Manufacturer + Baseboard_Product
+ HardwareID-9 ← Manufacturer + ProductName
+ HardwareID-10 ← Manufacturer + Family + Baseboard_Manufacturer + Baseboard_Product
+ HardwareID-11 ← Manufacturer + Family
+ HardwareID-12 ← Manufacturer + Enclosure Type
+ HardwareID-13 ← Manufacturer + Baseboard_Manufacturer + Baseboard_Product
+ HardwareID-14 ← Manufacturer
+
+On Windows, CHIDs are generated from the ASCII representation of SMBIOS strings, and on Linux the same
+mechanism is used. Additionally, on Linux, the Device Tree, DMI and `kenv` data sources
+are used to construct emulations of the Microsoft CHIDs.
+
+When installing firmware and drivers in Windows vendors *already use* the generated HardwareID GUIDs
+that match SMBIOS keys like the BIOS vendor and the product SKU.
+
+Both `fwupdtool hwids` and `ComputerHardwareIds.exe` only compute results that have the necessary
+data values available.
+If a data field is missing, then any related CHIDs are not generated.
+For example, if the SKU field is missing, then `HardwareID` 0, 3, 4 6 and 7 will not be available for
+that particular system.
+
+## Implementation
+
+Users with versions of fwupd newer than 1.1.1 can run `sudo fwupdtool hwids`. For example:
+
+ Computer Information
+ --------------------
+ BiosVendor: LENOVO
+ BiosVersion: GJET75WW (2.25 )
+ Manufacturer: LENOVO
+ Family: ThinkPad T440s
+ ProductName: 20ARS19C0C
+ ProductSku: LENOVO_MT_20AR_BU_Think_FM_ThinkPad T440s
+ EnclosureKind: 10
+ BaseboardManufacturer: LENOVO
+ BaseboardProduct: 20ARS19C0C
+
+ Hardware IDs
+ ------------
+ {c4159f74-3d2c-526f-b6d1-fe24a2fbc881} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease
+ {ff66cb74-5f5d-5669-875a-8a8f97be22c1} <- Manufacturer + Family + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease
+ {2e4dad4e-27a0-5de0-8e92-f395fc3fa5ba} <- Manufacturer + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease
+ {3faec92a-3ae3-5744-be88-495e90a7d541} <- Manufacturer + Family + ProductName + ProductSku + BaseboardManufacturer + BaseboardProduct
+ {660ccba8-1b78-5a33-80e6-9fb8354ee873} <- Manufacturer + Family + ProductName + ProductSku
+ {8dc9b7c5-f5d5-5850-9ab3-bd6f0549d814} <- Manufacturer + Family + ProductName
+ {178cd22d-ad9f-562d-ae0a-34009822cdbe} <- Manufacturer + ProductSku + BaseboardManufacturer + BaseboardProduct
+ {da1da9b6-62f5-5f22-8aaa-14db7eeda2a4} <- Manufacturer + ProductSku
+ {059eb22d-6dc7-59af-abd3-94bbe017f67c} <- Manufacturer + ProductName + BaseboardManufacturer + BaseboardProduct
+ {0cf8618d-9eff-537c-9f35-46861406eb9c} <- Manufacturer + ProductName
+ {f4275c1f-6130-5191-845c-3426247eb6a1} <- Manufacturer + Family + BaseboardManufacturer + BaseboardProduct
+ {db73af4c-4612-50f7-b8a7-787cf4871847} <- Manufacturer + Family
+ {5e820764-888e-529d-a6f9-dfd12bacb160} <- Manufacturer + EnclosureKind
+ {f8e1de5f-b68c-5f52-9d1a-f1ba52f1f773} <- Manufacturer + BaseboardManufacturer + BaseboardProduct
+ {6de5d951-d755-576b-bd09-c5cf66b27234} <- Manufacturer
+
+Which matches the output of `ComputerHardwareIds.exe` on the same hardware.
diff --git a/docs/index.html b/docs/index.html
index 512e14907..13086a6b4 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -45,6 +45,9 @@
+
diff --git a/libfwupdplugin/fu-context.c b/libfwupdplugin/fu-context.c
index 9f9f7ed13..b9deac1b7 100644
--- a/libfwupdplugin/fu-context.c
+++ b/libfwupdplugin/fu-context.c
@@ -11,7 +11,7 @@
#include "fu-bios-settings-private.h"
#include "fu-context-private.h"
#include "fu-fdt-firmware.h"
-#include "fu-hwids.h"
+#include "fu-hwids-private.h"
#include "fu-path.h"
#include "fu-smbios-private.h"
#include "fu-volume-private.h"
@@ -455,8 +455,11 @@ gchar *
fu_context_get_hwid_replace_value(FuContext *self, const gchar *keys, GError **error)
{
FuContextPrivate *priv = GET_PRIVATE(self);
+
g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
g_return_val_if_fail(keys != NULL, NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+
if (!priv->loaded_hwinfo) {
g_critical("cannot use HWIDs before calling ->load_hwinfo()");
g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_NOT_INITIALIZED, "no data");
@@ -786,21 +789,64 @@ fu_context_load_hwinfo(FuContext *self, FuContextHwidFlags flags, GError **error
g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ if ((flags & FU_CONTEXT_HWID_FLAG_LOAD_CONFIG) > 0) {
+ g_autoptr(GError) error_local = NULL;
+ if (!fu_hwids_config_setup(self, priv->hwids, &error_local)) {
+ if (!g_error_matches(error_local, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) {
+ g_propagate_prefixed_error(error,
+ g_steal_pointer(&error_local),
+ "Failed to load HWIDs config: ");
+ return FALSE;
+ }
+ }
+ }
+ if ((flags & FU_CONTEXT_HWID_FLAG_LOAD_DMI) > 0) {
+ g_autoptr(GError) error_local = NULL;
+ if (!fu_hwids_dmi_setup(self, priv->hwids, &error_local)) {
+ if (!g_error_matches(error_local, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) {
+ g_propagate_prefixed_error(error,
+ g_steal_pointer(&error_local),
+ "Failed to load HWIDs DMI: ");
+ return FALSE;
+ }
+ }
+ }
+ if ((flags & FU_CONTEXT_HWID_FLAG_LOAD_FDT) > 0) {
+ g_autoptr(GError) error_local = NULL;
+ if (!fu_hwids_fdt_setup(self, priv->hwids, &error_local)) {
+ if (!g_error_matches(error_local, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) {
+ g_propagate_prefixed_error(error,
+ g_steal_pointer(&error_local),
+ "Failed to load HWIDs FDT: ");
+ return FALSE;
+ }
+ }
+ }
+ if ((flags & FU_CONTEXT_HWID_FLAG_LOAD_KENV) > 0) {
+ g_autoptr(GError) error_local = NULL;
+ if (!fu_hwids_kenv_setup(self, priv->hwids, &error_local)) {
+ if (!g_error_matches(error_local, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) {
+ g_propagate_prefixed_error(error,
+ g_steal_pointer(&error_local),
+ "Failed to load HWIDs kenv: ");
+ return FALSE;
+ }
+ }
+ }
if ((flags & FU_CONTEXT_HWID_FLAG_LOAD_SMBIOS) > 0) {
g_autoptr(GError) error_local = NULL;
- if (!fu_smbios_setup(priv->smbios, &error_local)) {
- if (!g_error_matches(error_local, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED))
- g_warning("Failed to load SMBIOS: %s", error_local->message);
+ if (!fu_hwids_smbios_setup(self, priv->hwids, &error_local)) {
+ if (!g_error_matches(error_local, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) {
+ g_propagate_prefixed_error(error,
+ g_steal_pointer(&error_local),
+ "Failed to load SMBIOS: ");
+ return FALSE;
+ }
}
- fu_context_set_chassis_kind(self,
- fu_smbios_get_integer(priv->smbios,
- FU_SMBIOS_STRUCTURE_TYPE_CHASSIS,
- 0x05,
- NULL));
}
- if (!fu_hwids_setup(priv->hwids, priv->smbios, &error_hwids))
- g_warning("Failed to load HWIDs: %s", error_hwids->message);
priv->loaded_hwinfo = TRUE;
+ if (!fu_hwids_setup(priv->hwids, &error_hwids))
+ g_warning("Failed to load HWIDs: %s", error_hwids->message);
/* set the hwid flags */
guids = fu_context_get_hwid_guids(self);
diff --git a/libfwupdplugin/fu-hwids-config.c b/libfwupdplugin/fu-hwids-config.c
new file mode 100644
index 000000000..808440aa5
--- /dev/null
+++ b/libfwupdplugin/fu-hwids-config.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2021 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuContext"
+
+#include "config.h"
+
+#include "fu-context-private.h"
+#include "fu-hwids-private.h"
+#include "fu-path.h"
+
+gboolean
+fu_hwids_config_setup(FuContext *ctx, FuHwids *self, GError **error)
+{
+ g_autofree gchar *localstatedir = fu_path_from_kind(FU_PATH_KIND_LOCALSTATEDIR_PKG);
+ g_autofree gchar *sysconfigdir = fu_path_from_kind(FU_PATH_KIND_SYSCONFDIR_PKG);
+ g_autoptr(GKeyFile) kf = g_key_file_new();
+ g_autoptr(GPtrArray) fns = g_ptr_array_new_with_free_func(g_free);
+ g_autoptr(GPtrArray) keys = fu_hwids_get_keys(self);
+
+ /* per-system configuration and optional overrides */
+ g_ptr_array_add(fns, g_build_filename(sysconfigdir, "daemon.conf", NULL));
+ g_ptr_array_add(fns, g_build_filename(localstatedir, "daemon.conf", NULL));
+ for (guint i = 0; i < fns->len; i++) {
+ const gchar *fn = g_ptr_array_index(fns, i);
+ if (g_file_test(fn, G_FILE_TEST_EXISTS)) {
+ g_debug("loading HwId overrides from %s", fn);
+ if (!g_key_file_load_from_file(kf, fn, G_KEY_FILE_NONE, error))
+ return FALSE;
+ } else {
+ g_debug("not loading HwId overrides from %s", fn);
+ }
+ }
+
+ /* all keys are optional */
+ for (guint i = 0; i < keys->len; i++) {
+ const gchar *key = g_ptr_array_index(keys, i);
+ g_autofree gchar *value = g_key_file_get_string(kf, "fwupd", key, NULL);
+ if (value != NULL)
+ fu_hwids_add_value(self, key, value);
+ }
+
+ /* success */
+ return TRUE;
+}
diff --git a/libfwupdplugin/fu-hwids-dmi.c b/libfwupdplugin/fu-hwids-dmi.c
new file mode 100644
index 000000000..280795f67
--- /dev/null
+++ b/libfwupdplugin/fu-hwids-dmi.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2021 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuContext"
+
+#include "config.h"
+
+#include "fu-context-private.h"
+#include "fu-hwids-private.h"
+#include "fu-path.h"
+#include "fu-string.h"
+
+gboolean
+fu_hwids_dmi_setup(FuContext *ctx, FuHwids *self, GError **error)
+{
+ g_autofree gchar *path = fu_path_from_kind(FU_PATH_KIND_SYSFSDIR_DMI);
+ struct {
+ const gchar *hwid;
+ const gchar *key;
+ } map[] = {{FU_HWIDS_KEY_BASEBOARD_MANUFACTURER, "board_vendor"},
+ {FU_HWIDS_KEY_BASEBOARD_PRODUCT, "board_name"},
+ {FU_HWIDS_KEY_BIOS_VENDOR, "bios_vendor"},
+ {FU_HWIDS_KEY_BIOS_VERSION, "bios_version"},
+ {FU_HWIDS_KEY_FAMILY, "product_family"},
+ {FU_HWIDS_KEY_MANUFACTURER, "sys_vendor"},
+ {FU_HWIDS_KEY_PRODUCT_NAME, "product_name"},
+ {FU_HWIDS_KEY_PRODUCT_SKU, "product_sku"},
+ {FU_HWIDS_KEY_ENCLOSURE_KIND, "chassis_type"},
+ {NULL, NULL}};
+
+ /* the values the kernel parsed; these are world-readable */
+ if (!g_file_test(path, G_FILE_TEST_IS_DIR)) {
+ g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "no %s", path);
+ return FALSE;
+ }
+ for (guint i = 0; map[i].key != NULL; i++) {
+ gsize bufsz = 0;
+ g_autofree gchar *buf = NULL;
+ g_autofree gchar *fn = g_build_filename(path, map[i].key, NULL);
+ g_autoptr(GError) error_local = NULL;
+
+ if (!g_file_get_contents(fn, &buf, &bufsz, &error_local)) {
+ g_debug("unable to read SMBIOS data from %s: %s", fn, error_local->message);
+ continue;
+ }
+
+ /* trim trailing newline added by kernel */
+ if (buf[bufsz - 1] == '\n')
+ buf[bufsz - 1] = 0;
+ fu_hwids_add_value(self, map[i].hwid, buf);
+
+ if (g_strcmp0(map[i].hwid, FU_HWIDS_KEY_ENCLOSURE_KIND) == 0) {
+ guint64 val = 0;
+ if (!fu_strtoull(buf,
+ &val,
+ FU_SMBIOS_CHASSIS_KIND_OTHER,
+ FU_SMBIOS_CHASSIS_KIND_LAST,
+ &error_local)) {
+ g_warning("ignoring enclosure kind %s", buf);
+ continue;
+ }
+ fu_context_set_chassis_kind(ctx, val);
+ }
+ }
+
+ /* success */
+ return TRUE;
+}
diff --git a/libfwupdplugin/fu-hwids-fdt.c b/libfwupdplugin/fu-hwids-fdt.c
new file mode 100644
index 000000000..6bdd776a5
--- /dev/null
+++ b/libfwupdplugin/fu-hwids-fdt.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuContext"
+
+#include "config.h"
+
+#include "fu-context-private.h"
+#include "fu-fdt-firmware.h"
+#include "fu-hwids-private.h"
+
+gboolean
+fu_hwids_fdt_setup(FuContext *ctx, FuHwids *self, GError **error)
+{
+ g_auto(GStrv) compatible = NULL;
+ g_autoptr(FuFirmware) fdt_img = NULL;
+ g_autoptr(FuFdtImage) fdt_img_fwver = NULL;
+ g_autoptr(FuFirmware) fdt = NULL;
+ struct {
+ const gchar *hwid;
+ const gchar *key;
+ } map[] = {{FU_HWIDS_KEY_MANUFACTURER, "vendor"},
+ {FU_HWIDS_KEY_FAMILY, "model-name"},
+ {FU_HWIDS_KEY_PRODUCT_NAME, "model"},
+ {NULL, NULL}};
+
+ /* adds compatible GUIDs */
+ fdt = fu_context_get_fdt(ctx, error);
+ if (fdt == NULL)
+ return FALSE;
+ fdt_img = fu_firmware_get_image_by_id(fdt, NULL, error);
+ if (fdt_img == NULL)
+ return FALSE;
+ if (!fu_fdt_image_get_attr_strlist(FU_FDT_IMAGE(fdt_img), "compatible", &compatible, error))
+ return FALSE;
+ for (guint i = 0; compatible[i] != NULL; i++) {
+ g_autofree gchar *guid = fwupd_guid_hash_string(compatible[i]);
+ g_debug("using %s for DT compatible %s", guid, compatible[i]);
+ fu_hwids_add_guid(self, guid);
+ }
+
+ /* root node */
+ for (guint i = 0; map[i].key != NULL; i++) {
+ g_autofree gchar *tmp = NULL;
+ fu_fdt_image_get_attr_str(FU_FDT_IMAGE(fdt_img), map[i].key, &tmp, NULL);
+ fu_hwids_add_value(self, map[i].hwid, tmp);
+ }
+
+ /* fallback */
+ if (g_strv_length(compatible) > 0)
+ fu_hwids_add_value(self, FU_HWIDS_KEY_MANUFACTURER, compatible[0]);
+ if (g_strv_length(compatible) > 1)
+ fu_hwids_add_value(self, FU_HWIDS_KEY_PRODUCT_NAME, compatible[1]);
+ if (g_strv_length(compatible) > 2)
+ fu_hwids_add_value(self, FU_HWIDS_KEY_FAMILY, compatible[2]);
+ if (fu_context_get_chassis_kind(ctx) == FU_SMBIOS_CHASSIS_KIND_UNKNOWN) {
+ if (fu_fdt_image_get_attr_str(FU_FDT_IMAGE(fdt_img), "battery", NULL, NULL))
+ fu_context_set_chassis_kind(ctx, FU_SMBIOS_CHASSIS_KIND_PORTABLE);
+ }
+ fdt_img_fwver =
+ fu_fdt_firmware_get_image_by_path(FU_FDT_FIRMWARE(fdt), "ibm,firmware-versions", NULL);
+ if (fdt_img_fwver != NULL) {
+ g_autofree gchar *version = NULL;
+ fu_fdt_image_get_attr_str(FU_FDT_IMAGE(fdt_img), "version", &version, NULL);
+ fu_hwids_add_value(self, FU_HWIDS_KEY_BIOS_VERSION, version);
+ }
+
+ /* success */
+ return TRUE;
+}
diff --git a/libfwupdplugin/fu-hwids-kenv.c b/libfwupdplugin/fu-hwids-kenv.c
new file mode 100644
index 000000000..4d426c87f
--- /dev/null
+++ b/libfwupdplugin/fu-hwids-kenv.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuContext"
+
+#include "config.h"
+
+#include "fu-context-private.h"
+#include "fu-hwids-private.h"
+#include "fu-kenv.h"
+
+gboolean
+fu_hwids_kenv_setup(FuContext *ctx, FuHwids *self, GError **error)
+{
+#ifdef HAVE_KENV_H
+ struct {
+ const gchar *hwid;
+ const gchar *key;
+ } map[] = {{FU_HWIDS_KEY_BASEBOARD_MANUFACTURER, "smbios.planar.maker"},
+ {FU_HWIDS_KEY_BASEBOARD_PRODUCT, "smbios.planar.product"},
+ {FU_HWIDS_KEY_BIOS_VENDOR, "smbios.bios.vendor"},
+ {FU_HWIDS_KEY_BIOS_VERSION, "smbios.bios.version"},
+ {FU_HWIDS_KEY_FAMILY, "smbios.system.family"},
+ {FU_HWIDS_KEY_MANUFACTURER, "smbios.system.maker"},
+ {FU_HWIDS_KEY_PRODUCT_NAME, "smbios.system.product"},
+ {FU_HWIDS_KEY_PRODUCT_SKU, "smbios.system.sku"},
+ {{NULL, NULL}}};
+ for (guint i = 0; map[i].key != NULL; i++) {
+ g_autoptr(GError) error_local = NULL;
+ g_autofree gchar *value = fu_kenv_get_string(map[i].key, error_local);
+ if (value == NULL) {
+ g_debug("ignoring: %s", error_local->message);
+ continue;
+ }
+ fu_hwids_add_value(self, map[i].hwid, value);
+ }
+#endif
+
+ /* success */
+ return TRUE;
+}
diff --git a/libfwupdplugin/fu-hwids-private.h b/libfwupdplugin/fu-hwids-private.h
new file mode 100644
index 000000000..be2e28d1d
--- /dev/null
+++ b/libfwupdplugin/fu-hwids-private.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2023 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include "fu-context.h"
+#include "fu-hwids.h"
+
+FuHwids *
+fu_hwids_new(void);
+gboolean
+fu_hwids_setup(FuHwids *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fu_hwids_config_setup(FuContext *ctx, FuHwids *self, GError **error);
+gboolean
+fu_hwids_dmi_setup(FuContext *ctx, FuHwids *self, GError **error);
+gboolean
+fu_hwids_fdt_setup(FuContext *ctx, FuHwids *self, GError **error);
+gboolean
+fu_hwids_kenv_setup(FuContext *ctx, FuHwids *self, GError **error);
+gboolean
+fu_hwids_smbios_setup(FuContext *ctx, FuHwids *self, GError **error);
diff --git a/libfwupdplugin/fu-hwids-smbios.c b/libfwupdplugin/fu-hwids-smbios.c
new file mode 100644
index 000000000..130aee7e8
--- /dev/null
+++ b/libfwupdplugin/fu-hwids-smbios.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2021 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuContext"
+
+#include "config.h"
+
+#include "fu-context-private.h"
+#include "fu-hwids-private.h"
+#include "fu-smbios-private.h"
+#include "fu-string.h"
+
+typedef gchar *(*FuContextHwidConvertFunc)(FuSmbios *smbios,
+ guint8 type,
+ guint8 offset,
+ GError **error);
+
+static gchar *
+fu_hwids_smbios_convert_string_table_cb(FuSmbios *smbios,
+ guint8 type,
+ guint8 offset,
+ GError **error)
+{
+ const gchar *tmp = fu_smbios_get_string(smbios, type, offset, error);
+ if (tmp == NULL)
+ return NULL;
+ /* ComputerHardwareIds.exe seems to strip spaces */
+ return fu_strstrip(tmp);
+}
+
+static gchar *
+fu_hwids_smbios_convert_padded_integer_cb(FuSmbios *smbios,
+ guint8 type,
+ guint8 offset,
+ GError **error)
+{
+ guint tmp = fu_smbios_get_integer(smbios, type, offset, error);
+ if (tmp == G_MAXUINT)
+ return NULL;
+ return g_strdup_printf("%02x", tmp);
+}
+
+static gchar *
+fu_hwids_smbios_convert_integer_cb(FuSmbios *smbios, guint8 type, guint8 offset, GError **error)
+{
+ guint tmp = fu_smbios_get_integer(smbios, type, offset, error);
+ if (tmp == G_MAXUINT)
+ return NULL;
+ return g_strdup_printf("%x", tmp);
+}
+
+gboolean
+fu_hwids_smbios_setup(FuContext *ctx, FuHwids *self, GError **error)
+{
+ FuSmbios *smbios = fu_context_get_smbios(ctx);
+ struct {
+ const gchar *key;
+ guint8 type;
+ guint8 offset;
+ FuContextHwidConvertFunc func;
+ } map[] = {{FU_HWIDS_KEY_MANUFACTURER,
+ FU_SMBIOS_STRUCTURE_TYPE_SYSTEM,
+ 0x04,
+ fu_hwids_smbios_convert_string_table_cb},
+ {FU_HWIDS_KEY_ENCLOSURE_KIND,
+ FU_SMBIOS_STRUCTURE_TYPE_CHASSIS,
+ 0x05,
+ fu_hwids_smbios_convert_integer_cb},
+ {FU_HWIDS_KEY_FAMILY,
+ FU_SMBIOS_STRUCTURE_TYPE_SYSTEM,
+ 0x1a,
+ fu_hwids_smbios_convert_string_table_cb},
+ {FU_HWIDS_KEY_PRODUCT_NAME,
+ FU_SMBIOS_STRUCTURE_TYPE_SYSTEM,
+ 0x05,
+ fu_hwids_smbios_convert_string_table_cb},
+ {FU_HWIDS_KEY_PRODUCT_SKU,
+ FU_SMBIOS_STRUCTURE_TYPE_SYSTEM,
+ 0x19,
+ fu_hwids_smbios_convert_string_table_cb},
+ {FU_HWIDS_KEY_BIOS_VENDOR,
+ FU_SMBIOS_STRUCTURE_TYPE_BIOS,
+ 0x04,
+ fu_hwids_smbios_convert_string_table_cb},
+ {FU_HWIDS_KEY_BIOS_VERSION,
+ FU_SMBIOS_STRUCTURE_TYPE_BIOS,
+ 0x05,
+ fu_hwids_smbios_convert_string_table_cb},
+ {FU_HWIDS_KEY_BIOS_MAJOR_RELEASE,
+ FU_SMBIOS_STRUCTURE_TYPE_BIOS,
+ 0x14,
+ fu_hwids_smbios_convert_padded_integer_cb},
+ {FU_HWIDS_KEY_BIOS_MINOR_RELEASE,
+ FU_SMBIOS_STRUCTURE_TYPE_BIOS,
+ 0x15,
+ fu_hwids_smbios_convert_padded_integer_cb},
+ {FU_HWIDS_KEY_FIRMWARE_MAJOR_RELEASE,
+ FU_SMBIOS_STRUCTURE_TYPE_BIOS,
+ 0x16,
+ fu_hwids_smbios_convert_padded_integer_cb},
+ {FU_HWIDS_KEY_FIRMWARE_MINOR_RELEASE,
+ FU_SMBIOS_STRUCTURE_TYPE_BIOS,
+ 0x17,
+ fu_hwids_smbios_convert_padded_integer_cb},
+ {FU_HWIDS_KEY_BASEBOARD_MANUFACTURER,
+ FU_SMBIOS_STRUCTURE_TYPE_BASEBOARD,
+ 0x04,
+ fu_hwids_smbios_convert_string_table_cb},
+ {FU_HWIDS_KEY_BASEBOARD_PRODUCT,
+ FU_SMBIOS_STRUCTURE_TYPE_BASEBOARD,
+ 0x05,
+ fu_hwids_smbios_convert_string_table_cb},
+ {NULL, 0x00, 0x00, NULL}};
+
+ if (!fu_smbios_setup(smbios, error))
+ return FALSE;
+
+ /* get all DMI data from SMBIOS */
+ fu_context_set_chassis_kind(
+ ctx,
+ fu_smbios_get_integer(smbios, FU_SMBIOS_STRUCTURE_TYPE_CHASSIS, 0x05, NULL));
+ for (guint i = 0; map[i].key != NULL; i++) {
+ const gchar *contents_hdr = NULL;
+ g_autofree gchar *contents = NULL;
+ g_autoptr(GError) error_local = NULL;
+
+ contents = map[i].func(smbios, map[i].type, map[i].offset, &error_local);
+ if (contents == NULL) {
+ g_debug("ignoring %s: %s", map[i].key, error_local->message);
+ continue;
+ }
+ g_debug("smbios property %s=%s", map[i].key, contents);
+
+ /* weirdly, remove leading zeros */
+ contents_hdr = contents;
+ while (contents_hdr[0] == '0' &&
+ map[i].func != fu_hwids_smbios_convert_padded_integer_cb)
+ contents_hdr++;
+ fu_hwids_add_value(self, map[i].key, contents_hdr);
+ }
+
+ /* success */
+ return TRUE;
+}
diff --git a/libfwupdplugin/fu-hwids.c b/libfwupdplugin/fu-hwids.c
index 94dcfd97a..5192488b3 100644
--- a/libfwupdplugin/fu-hwids.c
+++ b/libfwupdplugin/fu-hwids.c
@@ -15,7 +15,7 @@
#include "fwupd-error.h"
#include "fu-common.h"
-#include "fu-hwids.h"
+#include "fu-hwids-private.h"
#include "fu-path.h"
#include "fu-string.h"
@@ -32,9 +32,8 @@
struct _FuHwids {
GObject parent_instance;
- GHashTable *hash_dmi_hw; /* BiosVersion->"1.2.3 " */
- GHashTable *hash_dmi_display; /* BiosVersion->"1.2.3" */
- GHashTable *hash_smbios_override; /* BiosVersion->"1.2.3" */
+ GHashTable *hash_values; /* BiosVersion->"1.2.3 " */
+ GHashTable *hash_values_display; /* BiosVersion->"1.2.3" */
GHashTable *hash_guid; /* a-c-b-d->1 */
GPtrArray *array_guids; /* a-c-b-d */
};
@@ -56,7 +55,7 @@ G_DEFINE_TYPE(FuHwids, fu_hwids, G_TYPE_OBJECT)
const gchar *
fu_hwids_get_value(FuHwids *self, const gchar *key)
{
- return g_hash_table_lookup(self->hash_dmi_display, key);
+ return g_hash_table_lookup(self->hash_values_display, key);
}
/**
@@ -121,6 +120,7 @@ fu_hwids_get_keys(FuHwids *self)
FU_HWIDS_KEY_BASEBOARD_MANUFACTURER,
FU_HWIDS_KEY_BASEBOARD_PRODUCT,
NULL};
+ g_return_val_if_fail(FU_IS_HWIDS(self), NULL);
for (guint i = 0; keys[i] != NULL; i++)
g_ptr_array_add(array, (gpointer)keys[i]);
return array;
@@ -219,6 +219,9 @@ fu_hwids_get_replace_keys(FuHwids *self, const gchar *key)
{"HardwareID-14", FU_HWIDS_KEY_MANUFACTURER},
{NULL, NULL}};
+ g_return_val_if_fail(FU_IS_HWIDS(self), NULL);
+ g_return_val_if_fail(key != NULL, NULL);
+
/* defined for Windows 10 */
for (guint i = 0; msdefined[i].search != NULL; i++) {
if (g_strcmp0(msdefined[i].search, key) == 0) {
@@ -231,23 +234,39 @@ fu_hwids_get_replace_keys(FuHwids *self, const gchar *key)
}
/**
- * fu_hwids_add_smbios_override:
+ * fu_hwids_add_value:
* @self: a #FuHwids
* @key: a key, e.g. %FU_HWIDS_KEY_PRODUCT_SKU
* @value: (nullable): a new value, e.g. `ExampleModel`
*
- * Sets SMBIOS override values so you can emulate another system.
+ * Sets override values so you can emulate another system.
*
* This function has no effect if called after fu_hwids_setup()
*
- * Since: 1.5.6
+ * Since: 1.8.10
**/
void
-fu_hwids_add_smbios_override(FuHwids *self, const gchar *key, const gchar *value)
+fu_hwids_add_value(FuHwids *self, const gchar *key, const gchar *value)
{
g_return_if_fail(FU_IS_HWIDS(self));
g_return_if_fail(key != NULL);
- g_hash_table_insert(self->hash_smbios_override, g_strdup(key), g_strdup(value));
+
+ /* does not replace; first value set wins */
+ if (g_hash_table_contains(self->hash_values, key))
+ return;
+ g_hash_table_insert(self->hash_values, g_strdup(key), g_strdup(value));
+
+ /* make suitable for display */
+ if (value != NULL) {
+ g_autofree gchar *value_safe = g_str_to_ascii(value, "C");
+ g_strdelimit(value_safe, "\n\r", '\0');
+ g_strchomp(value_safe);
+ g_hash_table_insert(self->hash_values_display,
+ g_strdup(key),
+ g_steal_pointer(&value_safe));
+ } else {
+ g_hash_table_insert(self->hash_values_display, g_strdup(key), NULL);
+ }
}
/**
@@ -278,7 +297,7 @@ fu_hwids_get_replace_values(FuHwids *self, const gchar *keys, GError **error)
/* get each part of the HWID */
split = g_strsplit(keys, "&", -1);
for (guint j = 0; split[j] != NULL; j++) {
- const gchar *tmp = g_hash_table_lookup(self->hash_dmi_hw, split[j]);
+ const gchar *tmp = g_hash_table_lookup(self->hash_values, split[j]);
if (tmp == NULL) {
g_set_error(error,
G_IO_ERROR,
@@ -321,199 +340,41 @@ fu_hwids_get_guid(FuHwids *self, const gchar *keys, GError **error)
return fu_hwids_get_guid_for_str(tmp, error);
}
-typedef gchar *(*FuHwidsConvertFunc)(FuSmbios *smbios, guint8 type, guint8 offset, GError **error);
-
-static gchar *
-fu_hwids_convert_string_table_cb(FuSmbios *smbios, guint8 type, guint8 offset, GError **error)
+/**
+ * fu_hwids_add_guid:
+ * @self: a #FuHwids
+ * @guid: a GUID
+ *
+ * Adds a HWID GUID value.
+ *
+ * Since: 1.8.10
+ **/
+void
+fu_hwids_add_guid(FuHwids *self, const gchar *guid)
{
- const gchar *tmp;
- tmp = fu_smbios_get_string(smbios, type, offset, error);
- if (tmp == NULL)
- return NULL;
- /* ComputerHardwareIds.exe seems to strip spaces */
- return fu_strstrip(tmp);
-}
-
-static gchar *
-fu_hwids_convert_padded_integer_cb(FuSmbios *smbios, guint8 type, guint8 offset, GError **error)
-{
- guint tmp = fu_smbios_get_integer(smbios, type, offset, error);
- if (tmp == G_MAXUINT)
- return NULL;
- return g_strdup_printf("%02x", tmp);
-}
-
-static gchar *
-fu_hwids_convert_integer_cb(FuSmbios *smbios, guint8 type, guint8 offset, GError **error)
-{
- guint tmp = fu_smbios_get_integer(smbios, type, offset, error);
- if (tmp == G_MAXUINT)
- return NULL;
- return g_strdup_printf("%x", tmp);
-}
-
-static gboolean
-fu_hwids_setup_overrides(FuHwids *self, GError **error)
-{
- g_autofree gchar *localstatedir = fu_path_from_kind(FU_PATH_KIND_LOCALSTATEDIR_PKG);
- g_autofree gchar *sysconfigdir = fu_path_from_kind(FU_PATH_KIND_SYSCONFDIR_PKG);
- g_autoptr(GKeyFile) kf = g_key_file_new();
- g_autoptr(GPtrArray) fns = g_ptr_array_new_with_free_func(g_free);
- g_autoptr(GPtrArray) keys = fu_hwids_get_keys(self);
-
- /* per-system configuration and optional overrides */
- g_ptr_array_add(fns, g_build_filename(sysconfigdir, "daemon.conf", NULL));
- g_ptr_array_add(fns, g_build_filename(localstatedir, "daemon.conf", NULL));
- for (guint i = 0; i < fns->len; i++) {
- const gchar *fn = g_ptr_array_index(fns, i);
- if (g_file_test(fn, G_FILE_TEST_EXISTS)) {
- g_debug("loading HwId overrides from %s", fn);
- if (!g_key_file_load_from_file(kf, fn, G_KEY_FILE_NONE, error))
- return FALSE;
- } else {
- g_debug("not loading HwId overrides from %s", fn);
- }
- }
-
- /* all keys are optional */
- for (guint i = 0; i < keys->len; i++) {
- const gchar *key = g_ptr_array_index(keys, i);
- g_autofree gchar *value = g_key_file_get_string(kf, "fwupd", key, NULL);
- if (value != NULL)
- fu_hwids_add_smbios_override(self, key, value);
- }
-
- /* success */
- return TRUE;
+ g_return_if_fail(FU_IS_HWIDS(self));
+ g_return_if_fail(guid != NULL);
+ g_hash_table_insert(self->hash_guid, g_strdup(guid), GUINT_TO_POINTER(1));
+ g_ptr_array_add(self->array_guids, g_strdup(guid));
}
/**
* fu_hwids_setup:
* @self: a #FuHwids
- * @smbios: (nullable): a #FuSmbios
* @error: (nullable): optional return location for an error
*
- * Reads all the SMBIOS values from the hardware.
+ * Adds all the `HardwareID` GUIDs from the previously supplied data.
*
* Returns: %TRUE for success
*
* Since: 0.9.3
**/
gboolean
-fu_hwids_setup(FuHwids *self, FuSmbios *smbios, GError **error)
+fu_hwids_setup(FuHwids *self, GError **error)
{
- struct {
- const gchar *key;
- guint8 type;
- guint8 offset;
- FuHwidsConvertFunc func;
- } map[] = {{FU_HWIDS_KEY_MANUFACTURER,
- FU_SMBIOS_STRUCTURE_TYPE_SYSTEM,
- 0x04,
- fu_hwids_convert_string_table_cb},
- {FU_HWIDS_KEY_ENCLOSURE_KIND,
- FU_SMBIOS_STRUCTURE_TYPE_CHASSIS,
- 0x05,
- fu_hwids_convert_integer_cb},
- {FU_HWIDS_KEY_FAMILY,
- FU_SMBIOS_STRUCTURE_TYPE_SYSTEM,
- 0x1a,
- fu_hwids_convert_string_table_cb},
- {FU_HWIDS_KEY_PRODUCT_NAME,
- FU_SMBIOS_STRUCTURE_TYPE_SYSTEM,
- 0x05,
- fu_hwids_convert_string_table_cb},
- {FU_HWIDS_KEY_PRODUCT_SKU,
- FU_SMBIOS_STRUCTURE_TYPE_SYSTEM,
- 0x19,
- fu_hwids_convert_string_table_cb},
- {FU_HWIDS_KEY_BIOS_VENDOR,
- FU_SMBIOS_STRUCTURE_TYPE_BIOS,
- 0x04,
- fu_hwids_convert_string_table_cb},
- {FU_HWIDS_KEY_BIOS_VERSION,
- FU_SMBIOS_STRUCTURE_TYPE_BIOS,
- 0x05,
- fu_hwids_convert_string_table_cb},
- {FU_HWIDS_KEY_BIOS_MAJOR_RELEASE,
- FU_SMBIOS_STRUCTURE_TYPE_BIOS,
- 0x14,
- fu_hwids_convert_padded_integer_cb},
- {FU_HWIDS_KEY_BIOS_MINOR_RELEASE,
- FU_SMBIOS_STRUCTURE_TYPE_BIOS,
- 0x15,
- fu_hwids_convert_padded_integer_cb},
- {FU_HWIDS_KEY_FIRMWARE_MAJOR_RELEASE,
- FU_SMBIOS_STRUCTURE_TYPE_BIOS,
- 0x16,
- fu_hwids_convert_padded_integer_cb},
- {FU_HWIDS_KEY_FIRMWARE_MINOR_RELEASE,
- FU_SMBIOS_STRUCTURE_TYPE_BIOS,
- 0x17,
- fu_hwids_convert_padded_integer_cb},
- {FU_HWIDS_KEY_BASEBOARD_MANUFACTURER,
- FU_SMBIOS_STRUCTURE_TYPE_BASEBOARD,
- 0x04,
- fu_hwids_convert_string_table_cb},
- {FU_HWIDS_KEY_BASEBOARD_PRODUCT,
- FU_SMBIOS_STRUCTURE_TYPE_BASEBOARD,
- 0x05,
- fu_hwids_convert_string_table_cb},
- {NULL, 0x00, 0x00, NULL}};
-
g_return_val_if_fail(FU_IS_HWIDS(self), FALSE);
- g_return_val_if_fail(FU_IS_SMBIOS(smbios) || smbios == NULL, FALSE);
g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
- /* override using a config file */
- if (!fu_hwids_setup_overrides(self, error))
- return FALSE;
-
- /* get all DMI data */
- for (guint i = 0; map[i].key != NULL; i++) {
- const gchar *contents_hdr = NULL;
- g_autofree gchar *contents = NULL;
- g_autofree gchar *contents_safe = NULL;
- g_autoptr(GError) error_local = NULL;
-
- /* get the data from a SMBIOS table unless an override exists */
- if (g_hash_table_lookup_extended(self->hash_smbios_override,
- map[i].key,
- NULL,
- (gpointer *)&contents_hdr)) {
- if (contents_hdr == NULL) {
- g_debug("ignoring %s", map[i].key);
- continue;
- }
- } else if (smbios != NULL) {
- contents = map[i].func(smbios, map[i].type, map[i].offset, &error_local);
- if (contents == NULL) {
- g_debug("ignoring %s: %s", map[i].key, error_local->message);
- continue;
- }
- contents_hdr = contents;
- } else {
- g_debug("ignoring %s", map[i].key);
- continue;
- }
- g_debug("smbios property %s=%s", map[i].key, contents_hdr);
-
- /* weirdly, remove leading zeros */
- while (contents_hdr[0] == '0' && map[i].func != fu_hwids_convert_padded_integer_cb)
- contents_hdr++;
- g_hash_table_insert(self->hash_dmi_hw,
- g_strdup(map[i].key),
- g_strdup(contents_hdr));
-
- /* make suitable for display */
- contents_safe = g_str_to_ascii(contents_hdr, "C");
- g_strdelimit(contents_safe, "\n\r", '\0');
- g_strchomp(contents_safe);
- g_hash_table_insert(self->hash_dmi_display,
- g_strdup(map[i].key),
- g_steal_pointer(&contents_safe));
- }
-
/* add GUIDs */
for (guint i = 0; i < 15; i++) {
g_autofree gchar *guid = NULL;
@@ -527,8 +388,7 @@ fu_hwids_setup(FuHwids *self, FuSmbios *smbios, GError **error)
g_debug("%s is not available, %s", key, error_local->message);
continue;
}
- g_hash_table_insert(self->hash_guid, g_strdup(guid), GUINT_TO_POINTER(1));
- g_ptr_array_add(self->array_guids, g_steal_pointer(&guid));
+ fu_hwids_add_guid(self, guid);
}
return TRUE;
@@ -541,9 +401,8 @@ fu_hwids_finalize(GObject *object)
g_return_if_fail(FU_IS_HWIDS(object));
self = FU_HWIDS(object);
- g_hash_table_unref(self->hash_dmi_hw);
- g_hash_table_unref(self->hash_dmi_display);
- g_hash_table_unref(self->hash_smbios_override);
+ g_hash_table_unref(self->hash_values);
+ g_hash_table_unref(self->hash_values_display);
g_hash_table_unref(self->hash_guid);
g_ptr_array_unref(self->array_guids);
@@ -560,9 +419,8 @@ fu_hwids_class_init(FuHwidsClass *klass)
static void
fu_hwids_init(FuHwids *self)
{
- self->hash_dmi_hw = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
- self->hash_dmi_display = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
- self->hash_smbios_override = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ self->hash_values = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ self->hash_values_display = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
self->hash_guid = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
self->array_guids = g_ptr_array_new_with_free_func(g_free);
}
diff --git a/libfwupdplugin/fu-hwids.h b/libfwupdplugin/fu-hwids.h
index eb82efaf2..990931d2f 100644
--- a/libfwupdplugin/fu-hwids.h
+++ b/libfwupdplugin/fu-hwids.h
@@ -117,14 +117,12 @@ G_DECLARE_FINAL_TYPE(FuHwids, fu_hwids, FU, HWIDS, GObject)
**/
#define FU_HWIDS_KEY_PRODUCT_SKU "ProductSku"
-FuHwids *
-fu_hwids_new(void);
GPtrArray *
fu_hwids_get_keys(FuHwids *self);
const gchar *
fu_hwids_get_value(FuHwids *self, const gchar *key);
void
-fu_hwids_add_smbios_override(FuHwids *self, const gchar *key, const gchar *value);
+fu_hwids_add_value(FuHwids *self, const gchar *key, const gchar *value);
const gchar *
fu_hwids_get_replace_keys(FuHwids *self, const gchar *key);
gchar *
@@ -135,7 +133,7 @@ gchar *
fu_hwids_get_guid(FuHwids *self, const gchar *keys, GError **error) G_GNUC_WARN_UNUSED_RESULT;
GPtrArray *
fu_hwids_get_guids(FuHwids *self);
+void
+fu_hwids_add_guid(FuHwids *self, const gchar *guid);
gboolean
fu_hwids_has_guid(FuHwids *self, const gchar *guid);
-gboolean
-fu_hwids_setup(FuHwids *self, FuSmbios *smbios, GError **error) G_GNUC_WARN_UNUSED_RESULT;
diff --git a/libfwupdplugin/fu-plugin.h b/libfwupdplugin/fu-plugin.h
index 03267391b..e34caeaff 100644
--- a/libfwupdplugin/fu-plugin.h
+++ b/libfwupdplugin/fu-plugin.h
@@ -17,7 +17,6 @@
#include "fu-context.h"
#include "fu-device-locker.h"
#include "fu-device.h"
-#include "fu-hwids.h"
#include "fu-plugin.h"
#include "fu-quirks.h"
#include "fu-security-attrs.h"
diff --git a/libfwupdplugin/fu-self-test.c b/libfwupdplugin/fu-self-test.c
index 80a12c719..35baf1522 100644
--- a/libfwupdplugin/fu-self-test.c
+++ b/libfwupdplugin/fu-self-test.c
@@ -416,84 +416,23 @@ fu_smbios3_func(void)
}
static void
-fu_smbios_dt_func(void)
+fu_context_hwids_dmi_func(void)
{
- const gchar *str;
- gboolean ret;
- g_autofree gchar *path = NULL;
- g_autoptr(FuSmbios) smbios = NULL;
+ g_autoptr(FuContext) ctx = fu_context_new();
g_autoptr(GError) error = NULL;
+ gboolean ret;
- path = g_test_build_filename(G_TEST_DIST, "tests", "devicetree", "base", NULL);
- smbios = fu_smbios_new();
- ret = fu_smbios_setup_from_path(smbios, path, &error);
+ ret = fu_context_load_hwinfo(ctx, FU_CONTEXT_HWID_FLAG_LOAD_DMI, &error);
g_assert_no_error(error);
g_assert_true(ret);
if (g_getenv("FWUPD_VERBOSE") != NULL) {
- g_autofree gchar *dump = fu_firmware_to_string(FU_FIRMWARE(smbios));
+ g_autofree gchar *dump =
+ fu_firmware_to_string(FU_FIRMWARE(fu_context_get_smbios(ctx)));
g_debug("%s", dump);
}
- /* get vendor */
- str = fu_smbios_get_string(smbios, FU_SMBIOS_STRUCTURE_TYPE_SYSTEM, 0x04, &error);
- g_assert_no_error(error);
- g_assert_cmpstr(str, ==, "Hughski Limited");
-}
-
-static void
-fu_smbios_dt_fallback_func(void)
-{
- const gchar *str;
- gboolean ret;
- g_autofree gchar *path = NULL;
- g_autoptr(FuSmbios) smbios = fu_smbios_new();
- g_autoptr(GError) error = NULL;
-
- path = g_test_build_filename(G_TEST_DIST, "tests", "devicetree-fallback", "base", NULL);
- ret = fu_smbios_setup_from_path(smbios, path, &error);
- g_assert_no_error(error);
- g_assert_true(ret);
- if (g_getenv("FWUPD_VERBOSE") != NULL) {
- g_autofree gchar *dump = fu_firmware_to_string(FU_FIRMWARE(smbios));
- g_debug("%s", dump);
- }
-
- /* get vendor */
- str = fu_smbios_get_string(smbios, FU_SMBIOS_STRUCTURE_TYPE_SYSTEM, 0x04, &error);
- g_assert_no_error(error);
- g_assert_cmpstr(str, ==, "solidrun");
-
- /* get model */
- str = fu_smbios_get_string(smbios, FU_SMBIOS_STRUCTURE_TYPE_SYSTEM, 0x05, &error);
- g_assert_no_error(error);
- g_assert_cmpstr(str, ==, "honeycomb");
-}
-
-static void
-fu_smbios_class_func(void)
-{
- g_autofree gchar *path = g_test_build_filename(G_TEST_DIST, "tests", "dmi", "class", NULL);
- g_autoptr(FuSmbios) smbios = fu_smbios_new();
- g_autoptr(GError) error = NULL;
- gboolean ret;
- const gchar *str;
- guint8 byte;
-
- ret = fu_smbios_setup_from_kernel(smbios, path, &error);
- g_assert_no_error(error);
- g_assert_true(ret);
- if (g_getenv("FWUPD_VERBOSE") != NULL) {
- g_autofree gchar *dump = fu_firmware_to_string(FU_FIRMWARE(smbios));
- g_debug("%s", dump);
- }
-
- str = fu_smbios_get_string(smbios, FU_SMBIOS_STRUCTURE_TYPE_SYSTEM, 4, &error);
- g_assert_no_error(error);
- g_assert_cmpstr(str, ==, "FwupdTest");
-
- byte = fu_smbios_get_integer(smbios, FU_SMBIOS_STRUCTURE_TYPE_CHASSIS, 5, &error);
- g_assert_no_error(error);
- g_assert_cmpuint(byte, ==, 16);
+ g_assert_cmpstr(fu_context_get_hwid_value(ctx, FU_HWIDS_KEY_MANUFACTURER), ==, "FwupdTest");
+ g_assert_cmpuint(fu_context_get_chassis_kind(ctx), ==, 16);
}
static gboolean
@@ -603,8 +542,7 @@ static void
fu_hwids_func(void)
{
g_autofree gchar *testdatadir = NULL;
- g_autoptr(FuHwids) hwids = NULL;
- g_autoptr(FuSmbios) smbios = NULL;
+ g_autoptr(FuContext) context = NULL;
g_autoptr(GError) error = NULL;
gboolean ret;
@@ -638,36 +576,42 @@ fu_hwids_func(void)
testdatadir = g_test_build_filename(G_TEST_DIST, "tests", NULL);
(void)g_setenv("FWUPD_SYSFSFWDIR", testdatadir, TRUE);
- smbios = fu_smbios_new();
- ret = fu_smbios_setup(smbios, &error);
+ context = fu_context_new();
+ ret = fu_context_load_hwinfo(context, FU_CONTEXT_HWID_FLAG_LOAD_SMBIOS, &error);
g_assert_no_error(error);
g_assert_true(ret);
- hwids = fu_hwids_new();
- ret = fu_hwids_setup(hwids, smbios, &error);
- g_assert_no_error(error);
- g_assert_true(ret);
-
- g_assert_cmpstr(fu_hwids_get_value(hwids, FU_HWIDS_KEY_MANUFACTURER), ==, "LENOVO");
- g_assert_cmpstr(fu_hwids_get_value(hwids, FU_HWIDS_KEY_ENCLOSURE_KIND), ==, "a");
- g_assert_cmpstr(fu_hwids_get_value(hwids, FU_HWIDS_KEY_FAMILY), ==, "ThinkPad T440s");
- g_assert_cmpstr(fu_hwids_get_value(hwids, FU_HWIDS_KEY_PRODUCT_NAME), ==, "20ARS19C0C");
- g_assert_cmpstr(fu_hwids_get_value(hwids, FU_HWIDS_KEY_BIOS_VENDOR), ==, "LENOVO");
- g_assert_cmpstr(fu_hwids_get_value(hwids, FU_HWIDS_KEY_BIOS_VERSION),
+ g_assert_cmpstr(fu_context_get_hwid_value(context, FU_HWIDS_KEY_MANUFACTURER),
+ ==,
+ "LENOVO");
+ g_assert_cmpstr(fu_context_get_hwid_value(context, FU_HWIDS_KEY_ENCLOSURE_KIND), ==, "a");
+ g_assert_cmpstr(fu_context_get_hwid_value(context, FU_HWIDS_KEY_FAMILY),
+ ==,
+ "ThinkPad T440s");
+ g_assert_cmpstr(fu_context_get_hwid_value(context, FU_HWIDS_KEY_PRODUCT_NAME),
+ ==,
+ "20ARS19C0C");
+ g_assert_cmpstr(fu_context_get_hwid_value(context, FU_HWIDS_KEY_BIOS_VENDOR), ==, "LENOVO");
+ g_assert_cmpstr(fu_context_get_hwid_value(context, FU_HWIDS_KEY_BIOS_VERSION),
==,
"GJET75WW (2.25 )");
- g_assert_cmpstr(fu_hwids_get_value(hwids, FU_HWIDS_KEY_BIOS_MAJOR_RELEASE), ==, "02");
- g_assert_cmpstr(fu_hwids_get_value(hwids, FU_HWIDS_KEY_BIOS_MINOR_RELEASE), ==, "19");
- g_assert_cmpstr(fu_hwids_get_value(hwids, FU_HWIDS_KEY_PRODUCT_SKU),
+ g_assert_cmpstr(fu_context_get_hwid_value(context, FU_HWIDS_KEY_BIOS_MAJOR_RELEASE),
+ ==,
+ "02");
+ g_assert_cmpstr(fu_context_get_hwid_value(context, FU_HWIDS_KEY_BIOS_MINOR_RELEASE),
+ ==,
+ "19");
+ g_assert_cmpstr(fu_context_get_hwid_value(context, FU_HWIDS_KEY_PRODUCT_SKU),
==,
"LENOVO_MT_20AR_BU_Think_FM_ThinkPad T440s");
for (guint i = 0; guids[i].key != NULL; i++) {
+ FuHwids *hwids = fu_context_get_hwids(context);
g_autofree gchar *guid = fu_hwids_get_guid(hwids, guids[i].key, &error);
g_assert_no_error(error);
g_assert_cmpstr(guid, ==, guids[i].value);
}
for (guint i = 0; guids[i].key != NULL; i++)
- g_assert_true(fu_hwids_has_guid(hwids, guids[i].value));
+ g_assert_true(fu_context_has_hwid_guid(context, guids[i].value));
}
static void
@@ -3800,6 +3744,7 @@ main(int argc, char **argv)
(void)g_setenv("FWUPD_LIBDIR_PKG", testdatadir, TRUE);
(void)g_setenv("FWUPD_SYSCONFDIR", testdatadir, TRUE);
(void)g_setenv("FWUPD_SYSFSFWATTRIBDIR", testdatadir, TRUE);
+ (void)g_setenv("FWUPD_SYSFSDMIDIR", testdatadir, TRUE);
(void)g_setenv("FWUPD_LOCALSTATEDIR", testdatadir, TRUE);
(void)g_setenv("FWUPD_OFFLINE_TRIGGER", "/tmp/fwupd-self-test/system-update", TRUE);
(void)g_setenv("FWUPD_LOCALSTATEDIR", "/tmp/fwupd-self-test/var", TRUE);
@@ -3845,11 +3790,9 @@ main(int argc, char **argv)
g_test_add_func("/fwupd/common{strsafe}", fu_strsafe_func);
g_test_add_func("/fwupd/efivar", fu_efivar_func);
g_test_add_func("/fwupd/hwids", fu_hwids_func);
+ g_test_add_func("/fwupd/context{hwids-dmi}", fu_context_hwids_dmi_func);
g_test_add_func("/fwupd/smbios", fu_smbios_func);
g_test_add_func("/fwupd/smbios3", fu_smbios3_func);
- g_test_add_func("/fwupd/smbios{dt}", fu_smbios_dt_func);
- g_test_add_func("/fwupd/smbios{dt-fallback}", fu_smbios_dt_fallback_func);
- g_test_add_func("/fwupd/smbios{class}", fu_smbios_class_func);
g_test_add_func("/fwupd/firmware", fu_firmware_func);
g_test_add_func("/fwupd/firmware{common}", fu_firmware_common_func);
g_test_add_func("/fwupd/firmware{archive}", fu_firmware_archive_func);
diff --git a/libfwupdplugin/fu-smbios-private.h b/libfwupdplugin/fu-smbios-private.h
index 8e5cb2488..cd42ae052 100644
--- a/libfwupdplugin/fu-smbios-private.h
+++ b/libfwupdplugin/fu-smbios-private.h
@@ -18,7 +18,3 @@ gboolean
fu_smbios_setup_from_file(FuSmbios *self,
const gchar *filename,
GError **error) G_GNUC_WARN_UNUSED_RESULT;
-gboolean
-fu_smbios_setup_from_kernel(FuSmbios *self,
- const gchar *path,
- GError **error) G_GNUC_WARN_UNUSED_RESULT;
diff --git a/libfwupdplugin/fu-smbios.c b/libfwupdplugin/fu-smbios.c
index f387aaeb3..229b3c7ca 100644
--- a/libfwupdplugin/fu-smbios.c
+++ b/libfwupdplugin/fu-smbios.c
@@ -20,7 +20,6 @@
#include "fu-byte-array.h"
#include "fu-common.h"
-#include "fu-kenv.h"
#include "fu-mem.h"
#include "fu-path.h"
#include "fu-smbios-private.h"
@@ -29,7 +28,7 @@
/**
* FuSmbios:
*
- * Enumerate the SMBIOS data on the system, either using DMI or Device Tree.
+ * Enumerate the SMBIOS data on the system.
*
* See also: [class@FuHwids]
*/
@@ -81,274 +80,6 @@ typedef struct {
G_DEFINE_TYPE(FuSmbios, fu_smbios, FU_TYPE_FIRMWARE)
-static void
-fu_smbios_set_integer(FuSmbios *self, guint8 type, guint8 offset, guint8 value)
-{
- FuSmbiosItem *item = g_ptr_array_index(self->items, type);
- for (guint i = item->buf->len; i < (guint)offset + 1; i++)
- fu_byte_array_append_uint8(item->buf, 0x0);
- item->buf->data[offset] = value;
-}
-
-static void
-fu_smbios_set_string(FuSmbios *self, guint8 type, guint8 offset, const gchar *buf, gssize bufsz)
-{
- FuSmbiosItem *item = g_ptr_array_index(self->items, type);
-
- /* NUL terminated UTF-8 */
- if (bufsz < 0)
- bufsz = strlen(buf);
-
- /* add value to string table */
- g_ptr_array_add(item->strings, g_strndup(buf, (gsize)bufsz));
- fu_smbios_set_integer(self, type, offset, item->strings->len);
-}
-
-static gboolean
-fu_smbios_convert_dt_string(FuSmbios *self,
- guint8 type,
- guint8 offset,
- const gchar *path,
- const gchar *subpath)
-{
- gsize bufsz = 0;
- g_autofree gchar *fn = g_build_filename(path, subpath, NULL);
- g_autofree gchar *buf = NULL;
-
- /* not found */
- if (!g_file_get_contents(fn, &buf, &bufsz, NULL))
- return FALSE;
- if (bufsz == 0)
- return FALSE;
- fu_smbios_set_string(self, type, offset, buf, (gssize)bufsz);
- return TRUE;
-}
-
-static gchar **
-fu_smbios_convert_dt_string_array(FuSmbios *self, const gchar *path, const gchar *subpath)
-{
- gsize bufsz = 0;
- g_autofree gchar *fn = g_build_filename(path, subpath, NULL);
- g_autofree gchar *buf = NULL;
- g_auto(GStrv) split = NULL;
-
- /* not found */
- if (!g_file_get_contents(fn, &buf, &bufsz, NULL))
- return NULL;
- if (bufsz == 0)
- return NULL;
-
- /* return only if valid */
- split = g_strsplit(buf, ",", -1);
- if (g_strv_length(split) == 0)
- return NULL;
-
- /* success */
- return g_steal_pointer(&split);
-}
-
-#ifdef HAVE_KENV_H
-
-static gboolean
-fu_smbios_convert_kenv_string(FuSmbios *self,
- guint8 type,
- guint8 offset,
- const gchar *sminfo,
- GError **error)
-{
- g_autofree gchar *value = fu_kenv_get_string(sminfo, error);
- if (value == NULL)
- return FALSE;
- fu_smbios_set_string(self, type, offset, value, -1);
- return TRUE;
-}
-
-static gboolean
-fu_smbios_setup_from_kenv(FuSmbios *self, GError **error)
-{
- gboolean is_valid = FALSE;
- g_autoptr(GError) error_local = NULL;
-
- /* add all four faked structures */
- for (guint i = 0; i < FU_SMBIOS_STRUCTURE_TYPE_LAST; i++) {
- FuSmbiosItem *item = g_new0(FuSmbiosItem, 1);
- item->type = i;
- item->buf = g_byte_array_new();
- item->strings = g_ptr_array_new_with_free_func(g_free);
- g_ptr_array_add(self->items, item);
- }
-
- /* DMI:Manufacturer */
- if (!fu_smbios_convert_kenv_string(self,
- FU_SMBIOS_STRUCTURE_TYPE_SYSTEM,
- 0x04,
- "smbios.bios.vendor",
- &error_local)) {
- g_debug("ignoring: %s", error_local->message);
- g_clear_error(&error_local);
- } else {
- is_valid = TRUE;
- }
-
- /* DMI:BiosVersion */
- if (!fu_smbios_convert_kenv_string(self,
- FU_SMBIOS_STRUCTURE_TYPE_BIOS,
- 0x05,
- "smbios.bios.version",
- &error_local)) {
- g_debug("ignoring: %s", error_local->message);
- g_clear_error(&error_local);
- } else {
- is_valid = TRUE;
- }
-
- /* DMI:Family */
- if (!fu_smbios_convert_kenv_string(self,
- FU_SMBIOS_STRUCTURE_TYPE_SYSTEM,
- 0x1a,
- "smbios.system.family",
- &error_local)) {
- g_debug("ignoring: %s", error_local->message);
- g_clear_error(&error_local);
- } else {
- is_valid = TRUE;
- }
-
- /* DMI:ProductName */
- if (!fu_smbios_convert_kenv_string(self,
- FU_SMBIOS_STRUCTURE_TYPE_SYSTEM,
- 0x05,
- "smbios.planar.product",
- &error_local)) {
- g_debug("ignoring: %s", error_local->message);
- g_clear_error(&error_local);
- } else {
- is_valid = TRUE;
- }
-
- /* DMI:BaseboardManufacturer */
- if (!fu_smbios_convert_kenv_string(self,
- FU_SMBIOS_STRUCTURE_TYPE_BASEBOARD,
- 0x04,
- "smbios.planar.maker",
- &error_local)) {
- g_debug("ignoring: %s", error_local->message);
- g_clear_error(&error_local);
- } else {
- is_valid = TRUE;
- }
-
- /* we got no data */
- if (!is_valid) {
- g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_READ, "no SMBIOS information provided");
- return FALSE;
- }
-
- /* success */
- return TRUE;
-}
-#endif
-
-static gboolean
-fu_smbios_setup_from_path_dt(FuSmbios *self, const gchar *path, GError **error)
-{
- gboolean has_family;
- gboolean has_model;
- gboolean has_vendor;
- g_autofree gchar *fn_battery = NULL;
-
- /* add all four faked structures */
- for (guint i = 0; i < FU_SMBIOS_STRUCTURE_TYPE_LAST; i++) {
- FuSmbiosItem *item = g_new0(FuSmbiosItem, 1);
- item->type = i;
- item->buf = g_byte_array_new();
- item->strings = g_ptr_array_new_with_free_func(g_free);
- g_ptr_array_add(self->items, item);
- }
-
- /* if it has a battery it is portable (probably a laptop) */
- fn_battery = g_build_filename(path, "battery", NULL);
- if (g_file_test(fn_battery, G_FILE_TEST_EXISTS)) {
- fu_smbios_set_integer(self,
- FU_SMBIOS_STRUCTURE_TYPE_CHASSIS,
- 0x05,
- FU_SMBIOS_CHASSIS_KIND_PORTABLE);
- }
-
- /* DMI:Manufacturer */
- has_vendor = fu_smbios_convert_dt_string(self,
- FU_SMBIOS_STRUCTURE_TYPE_SYSTEM,
- 0x04,
- path,
- "vendor");
-
- /* DMI:Family */
- has_family = fu_smbios_convert_dt_string(self,
- FU_SMBIOS_STRUCTURE_TYPE_SYSTEM,
- 0x1a,
- path,
- "model-name");
-
- /* DMI:ProductName */
- has_model =
- fu_smbios_convert_dt_string(self, FU_SMBIOS_STRUCTURE_TYPE_SYSTEM, 0x05, path, "model");
-
- /* fall back to the first compatible string if required */
- if (!has_vendor || !has_model || !has_family) {
- g_auto(GStrv) parts = NULL;
-
- /* NULL if invalid, otherwise we're sure this has size of exactly 3 */
- parts = fu_smbios_convert_dt_string_array(self, path, "compatible");
- if (parts != NULL) {
- if (!has_vendor && g_strv_length(parts) > 0) {
- fu_smbios_set_string(self,
- FU_SMBIOS_STRUCTURE_TYPE_SYSTEM,
- 0x4,
- parts[0],
- -1);
- }
- if (!has_model && g_strv_length(parts) > 1) {
- fu_smbios_set_string(self,
- FU_SMBIOS_STRUCTURE_TYPE_SYSTEM,
- 0x05,
- parts[1],
- -1);
- }
- if (!has_family && g_strv_length(parts) > 2) {
- fu_smbios_set_string(self,
- FU_SMBIOS_STRUCTURE_TYPE_SYSTEM,
- 0x1a,
- parts[2],
- -1);
- }
- }
- }
-
- /* DMI:BiosVersion */
- fu_smbios_convert_dt_string(self,
- FU_SMBIOS_STRUCTURE_TYPE_BIOS,
- 0x05,
- path,
- "ibm,firmware-versions/version");
-
- /* DMI:BaseboardManufacturer */
- fu_smbios_convert_dt_string(self,
- FU_SMBIOS_STRUCTURE_TYPE_BASEBOARD,
- 0x04,
- path,
- "vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/vendor");
-
- /* DMI:BaseboardProduct */
- fu_smbios_convert_dt_string(
- self,
- FU_SMBIOS_STRUCTURE_TYPE_BASEBOARD,
- 0x05,
- path,
- "vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/part-number");
-
- return TRUE;
-}
-
static gboolean
fu_smbios_setup_from_data(FuSmbios *self, const guint8 *buf, gsize sz, GError **error)
{
@@ -425,172 +156,17 @@ fu_smbios_setup_from_file(FuSmbios *self, const gchar *filename, GError **error)
{
gsize sz = 0;
g_autofree gchar *buf = NULL;
- g_autofree gchar *basename = NULL;
g_return_val_if_fail(FU_IS_SMBIOS(self), FALSE);
g_return_val_if_fail(filename != NULL, FALSE);
g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
- /* use a heuristic */
- basename = g_path_get_basename(filename);
- if (g_strcmp0(basename, "base") == 0)
- return fu_smbios_setup_from_path_dt(self, filename, error);
-
/* DMI blob */
if (!g_file_get_contents(filename, &buf, &sz, error))
return FALSE;
return fu_smbios_setup_from_data(self, (guint8 *)buf, sz, error);
}
-static gboolean
-fu_smbios_encode_string_from_kernel(FuSmbios *self,
- const gchar *file_contents,
- guint8 type,
- guint8 offset,
- GError **error)
-{
- fu_smbios_set_string(self, type, offset, file_contents, -1);
- return TRUE;
-}
-
-static gboolean
-fu_smbios_encode_byte_from_kernel(FuSmbios *self,
- const gchar *file_contents,
- guint8 type,
- guint8 offset,
- GError **error)
-{
- gchar *endp;
- gint64 value = g_ascii_strtoll(file_contents, &endp, 10);
-
- if (*endp != 0) {
- g_set_error(error,
- FWUPD_ERROR,
- FWUPD_ERROR_NOT_SUPPORTED,
- "non-numeric values in numeric string: %s",
- endp);
- return FALSE;
- }
- if (value < 0 || value > G_MAXUINT8) {
- g_set_error(error,
- FWUPD_ERROR,
- FWUPD_ERROR_NOT_SUPPORTED,
- "value \"%s\" is not representable in a byte",
- file_contents);
- return FALSE;
- }
-
- fu_smbios_set_integer(self, type, offset, value);
- return TRUE;
-}
-
-/*
- * The mapping from SMBIOS field to sysfs name can be found by mapping
- * the field to a kernel property name in dmi_decode()
- * (drivers/firmware/dmi_scan.c), then the property name to sysfs entry
- * in dmi_id_init_attr_table() (drivers/firmware/dmi-id.c). This table
- * lists each attribute exposed in /sys/class/dmi when CONFIG_DMIID is
- * enabled, mapping to the SMBIOS field and a function that can convert
- * the textual version of the field back into the raw SMBIOS table
- * representation.
- */
-#define SYSFS_DMI_FIELD(_name, _type, offset_ignored, kind) \
- { \
- .name = _name, .type = _type, .offset = offset_ignored, \
- .encode = fu_smbios_encode_##kind##_from_kernel \
- }
-const struct kernel_dmi_field {
- const gchar *name;
- gboolean (*encode)(FuSmbios *, const gchar *, guint8, guint8, GError **);
- guint8 type;
- guint8 offset;
-} KERNEL_DMI_FIELDS[] = {
- SYSFS_DMI_FIELD("bios_vendor", 0, 4, string),
- SYSFS_DMI_FIELD("bios_version", 0, 5, string),
- SYSFS_DMI_FIELD("bios_date", 0, 8, string),
- SYSFS_DMI_FIELD("sys_vendor", 1, 4, string),
- SYSFS_DMI_FIELD("product_name", 1, 5, string),
- SYSFS_DMI_FIELD("product_version", 1, 6, string),
- SYSFS_DMI_FIELD("product_serial", 1, 7, string),
- /* SYSFS_DMI_FIELD("product_uuid", 1, 8, uuid) */
- SYSFS_DMI_FIELD("product_family", 1, 26, string),
- SYSFS_DMI_FIELD("product_sku", 1, 25, string),
- SYSFS_DMI_FIELD("board_vendor", 2, 4, string),
- SYSFS_DMI_FIELD("board_name", 2, 5, string),
- SYSFS_DMI_FIELD("board_version", 2, 6, string),
- SYSFS_DMI_FIELD("board_serial", 2, 7, string),
- SYSFS_DMI_FIELD("board_asset_tag", 2, 8, string),
- SYSFS_DMI_FIELD("chassis_vendor", 3, 4, string),
- SYSFS_DMI_FIELD("chassis_type", 3, 5, byte),
- SYSFS_DMI_FIELD("chassis_version", 3, 6, string),
- SYSFS_DMI_FIELD("chassis_serial", 3, 7, string),
- SYSFS_DMI_FIELD("chassis_asset_tag", 3, 8, string),
-};
-
-/**
- * fu_smbios_setup_from_kernel:
- * @self: a #FuSmbios
- * @path: a directory path
- * @error: (nullable): optional return location for an error
- *
- * Reads SMBIOS value from DMI values provided by the kernel, such as in
- * /sys/class/dmi on Linux.
- *
- * Returns: %TRUE for success
- *
- * Since: 1.6.2
- **/
-gboolean
-fu_smbios_setup_from_kernel(FuSmbios *self, const gchar *path, GError **error)
-{
- gboolean any_success = FALSE;
-
- /* add fake structures */
- for (guint i = 0; i < FU_SMBIOS_STRUCTURE_TYPE_LAST; i++) {
- FuSmbiosItem *item = g_new0(FuSmbiosItem, 1);
- item->type = i;
- item->buf = g_byte_array_new();
- item->strings = g_ptr_array_new_with_free_func(g_free);
- g_ptr_array_add(self->items, item);
- }
-
- /* parse every known field from the corresponding file */
- for (gsize i = 0; i < G_N_ELEMENTS(KERNEL_DMI_FIELDS); i++) {
- const struct kernel_dmi_field *field = &KERNEL_DMI_FIELDS[i];
- gsize bufsz = 0;
- g_autofree gchar *buf = NULL;
- g_autofree gchar *fn = g_build_filename(path, field->name, NULL);
- g_autoptr(GError) local_error = NULL;
-
- if (!g_file_get_contents(fn, &buf, &bufsz, &local_error)) {
- g_debug("unable to read SMBIOS data from %s: %s", fn, local_error->message);
- continue;
- }
-
- /* trim trailing newline added by kernel */
- if (buf[bufsz - 1] == '\n')
- buf[bufsz - 1] = 0;
-
- if (!field->encode(self, buf, field->type, field->offset, &local_error)) {
- g_warning("failed to parse SMBIOS data from %s: %s",
- fn,
- local_error->message);
- continue;
- }
-
- any_success = TRUE;
- }
- if (!any_success) {
- g_set_error(error,
- FWUPD_ERROR,
- FWUPD_ERROR_NOT_SUPPORTED,
- "failed to read any SMBIOS values from %s",
- path);
- return FALSE;
- }
- return TRUE;
-}
-
static gboolean
fu_smbios_parse_ep32(FuSmbios *self, const gchar *buf, gsize sz, GError **error)
{
@@ -685,8 +261,20 @@ fu_smbios_parse_ep64(FuSmbios *self, const gchar *buf, gsize sz, GError **error)
return TRUE;
}
-static gboolean
-fu_smbios_setup_from_path_dmi(FuSmbios *self, const gchar *path, GError **error)
+/**
+ * fu_smbios_setup_from_path:
+ * @self: a #FuSmbios
+ * @path: a path, e.g. `/sys/firmware/dmi/tables`
+ * @error: (nullable): optional return location for an error
+ *
+ * Reads all the SMBIOS values from a specific path.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.0.0
+ **/
+gboolean
+fu_smbios_setup_from_path(FuSmbios *self, const gchar *path, GError **error)
{
gsize sz = 0;
g_autofree gchar *dmi_fn = NULL;
@@ -695,6 +283,8 @@ fu_smbios_setup_from_path_dmi(FuSmbios *self, const gchar *path, GError **error)
g_autofree gchar *ep_raw = NULL;
g_return_val_if_fail(FU_IS_SMBIOS(self), FALSE);
+ g_return_val_if_fail(path != NULL, FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
/* get the smbios entry point */
ep_fn = g_build_filename(path, "smbios_entry_point", NULL);
@@ -763,34 +353,6 @@ fu_smbios_parse(FuFirmware *firmware,
return fu_smbios_setup_from_data(self, buf, bufsz, error);
}
-/**
- * fu_smbios_setup_from_path:
- * @self: a #FuSmbios
- * @path: a path, e.g. `/sys/firmware/dmi/tables`
- * @error: (nullable): optional return location for an error
- *
- * Reads all the SMBIOS values from a specific path.
- *
- * Returns: %TRUE for success
- *
- * Since: 1.0.0
- **/
-gboolean
-fu_smbios_setup_from_path(FuSmbios *self, const gchar *path, GError **error)
-{
- g_autofree gchar *basename = NULL;
-
- g_return_val_if_fail(FU_IS_SMBIOS(self), FALSE);
- g_return_val_if_fail(path != NULL, FALSE);
- g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
-
- /* use a heuristic */
- basename = g_path_get_basename(path);
- if (g_strcmp0(basename, "base") == 0)
- return fu_smbios_setup_from_path_dt(self, path, error);
- return fu_smbios_setup_from_path_dmi(self, path, error);
-}
-
#ifdef _WIN32
#define FU_SMBIOS_FT_SIG_ACPI 0x41435049
#define FU_SMBIOS_FT_SIG_FIRM 0x4649524D
@@ -850,51 +412,33 @@ fu_smbios_setup(FuSmbios *self, GError **error)
error);
#else
g_autofree gchar *path = NULL;
- g_autofree gchar *path_dt = NULL;
g_autofree gchar *sysfsfwdir = NULL;
- const gchar *path_dmi_class = "/sys/class/dmi/id";
+ g_autoptr(GError) error_local = NULL;
g_return_val_if_fail(FU_IS_SMBIOS(self), FALSE);
g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
- sysfsfwdir = fu_path_from_kind(FU_PATH_KIND_SYSFSDIR_FW);
-
/* DMI */
+ sysfsfwdir = fu_path_from_kind(FU_PATH_KIND_SYSFSDIR_FW);
path = g_build_filename(sysfsfwdir, "dmi", "tables", NULL);
- if (g_file_test(path, G_FILE_TEST_EXISTS)) {
- g_autoptr(GError) error_local = NULL;
- if (!fu_smbios_setup_from_path(self, path, &error_local)) {
- if (!g_error_matches(error_local, G_FILE_ERROR, G_FILE_ERROR_ACCES)) {
- g_propagate_error(error, g_steal_pointer(&error_local));
- return FALSE;
- }
- g_debug("ignoring %s", error_local->message);
- } else
- return TRUE;
- }
-
- /* the values the kernel parsed; these are world-readable */
- if (g_file_test(path_dmi_class, G_FILE_TEST_IS_DIR)) {
- g_debug("trying to read %s", path_dmi_class);
- return fu_smbios_setup_from_kernel(self, path_dmi_class, error);
- }
-
- /* DT */
- path_dt = g_build_filename(sysfsfwdir, "devicetree", "base", NULL);
- if (g_file_test(path_dt, G_FILE_TEST_EXISTS))
- return fu_smbios_setup_from_path(self, path_dt, error);
-
-#ifdef HAVE_KENV_H
- /* kenv */
- return fu_smbios_setup_from_kenv(self, error);
-#endif
-
- /* neither found */
- g_set_error_literal(error,
+ if (!g_file_test(path, G_FILE_TEST_EXISTS)) {
+ g_set_error(error,
FWUPD_ERROR,
- FWUPD_ERROR_INVALID_FILE,
- "neither SMBIOS or DT found");
- return FALSE;
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "SMBIOS tables not found at %s",
+ path);
+ return FALSE;
+ }
+ if (!fu_smbios_setup_from_path(self, path, &error_local)) {
+ if (!g_error_matches(error_local, G_FILE_ERROR, G_FILE_ERROR_ACCES)) {
+ g_propagate_error(error, g_steal_pointer(&error_local));
+ return FALSE;
+ }
+ g_debug("ignoring %s", error_local->message);
+ }
+
+ /* success */
+ return TRUE;
#endif
}
diff --git a/libfwupdplugin/fwupdplugin.h b/libfwupdplugin/fwupdplugin.h
index 6932122ae..721810d3e 100644
--- a/libfwupdplugin/fwupdplugin.h
+++ b/libfwupdplugin/fwupdplugin.h
@@ -45,6 +45,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map
index d3f26d893..d3682ff3e 100644
--- a/libfwupdplugin/fwupdplugin.map
+++ b/libfwupdplugin/fwupdplugin.map
@@ -63,8 +63,6 @@ LIBFWUPDPLUGIN_0.9.3 {
fu_hwids_get_type;
fu_hwids_get_value;
fu_hwids_has_guid;
- fu_hwids_new;
- fu_hwids_setup;
local: *;
} LIBFWUPDPLUGIN_0.8.0;
@@ -540,7 +538,6 @@ LIBFWUPDPLUGIN_1.5.6 {
fu_firmware_strparse_uint32_safe;
fu_firmware_strparse_uint4_safe;
fu_firmware_strparse_uint8_safe;
- fu_hwids_add_smbios_override;
fu_hwids_get_keys;
fu_plugin_get_devices;
fu_plugin_runner_backend_device_added;
@@ -719,7 +716,6 @@ LIBFWUPDPLUGIN_1.6.2 {
fu_ifd_region_to_name;
fu_ifd_region_to_string;
fu_plugin_add_udev_subsystem;
- fu_smbios_setup_from_kernel;
fu_udev_device_get_children_with_subsystem;
fu_udev_device_set_dev;
local: *;
@@ -1159,6 +1155,8 @@ LIBFWUPDPLUGIN_1.8.10 {
fu_context_get_smbios;
fu_context_load_hwinfo;
fu_context_set_chassis_kind;
+ fu_hwids_add_guid;
+ fu_hwids_add_value;
fu_pefile_firmware_get_type;
fu_pefile_firmware_new;
local: *;
diff --git a/libfwupdplugin/meson.build b/libfwupdplugin/meson.build
index 4c8152388..ac8c15ea5 100644
--- a/libfwupdplugin/meson.build
+++ b/libfwupdplugin/meson.build
@@ -48,6 +48,11 @@ fwupdplugin_src = [
'fu-dfuse-firmware.c', # fuzzing
'fu-fmap-firmware.c', # fuzzing
'fu-hwids.c', # fuzzing
+ 'fu-hwids-config.c', # fuzzing
+ 'fu-hwids-dmi.c', # fuzzing
+ 'fu-hwids-fdt.c', # fuzzing
+ 'fu-hwids-kenv.c', # fuzzing
+ 'fu-hwids-smbios.c', # fuzzing
'fu-ihex-firmware.c', # fuzzing
'fu-io-channel.c', # fuzzing
'fu-plugin.c',
@@ -363,22 +368,22 @@ if get_option('tests')
test('fwupdplugin-self-test', e, is_parallel: false, timeout: 180, env: env)
install_data([
- 'tests/dmi/class/chassis_type',
- 'tests/dmi/class/sys_vendor',
+ 'tests/chassis_type',
+ 'tests/sys_vendor',
],
- install_dir: join_paths(installed_test_datadir, 'dmi/class'),
+ install_dir: installed_test_datadir,
)
install_data([
'tests/dmi/tables/DMI',
'tests/dmi/tables/smbios_entry_point',
],
- install_dir: join_paths(installed_test_datadir, 'dmi/tables'),
+ install_dir: join_paths(installed_test_datadir, 'tests/dmi/tables'),
)
install_data([
'tests/dmi/tables64/DMI',
'tests/dmi/tables64/smbios_entry_point',
],
- install_dir: join_paths(installed_test_datadir, 'dmi/tables64'),
+ install_dir: join_paths(installed_test_datadir, 'tests/dmi/tables64'),
)
endif
diff --git a/libfwupdplugin/tests/dmi/class/chassis_type b/libfwupdplugin/tests/chassis_type
similarity index 100%
rename from libfwupdplugin/tests/dmi/class/chassis_type
rename to libfwupdplugin/tests/chassis_type
diff --git a/libfwupdplugin/tests/devicetree-fallback/base/compatible b/libfwupdplugin/tests/devicetree-fallback/base/compatible
deleted file mode 120000
index abcb73dbb..000000000
--- a/libfwupdplugin/tests/devicetree-fallback/base/compatible
+++ /dev/null
@@ -1 +0,0 @@
-../../devicetree/base/compatible
\ No newline at end of file
diff --git a/libfwupdplugin/tests/devicetree/base/compatible b/libfwupdplugin/tests/devicetree/base/compatible
deleted file mode 100644
index 33529460d..000000000
Binary files a/libfwupdplugin/tests/devicetree/base/compatible and /dev/null differ
diff --git a/libfwupdplugin/tests/devicetree/base/ibm,firmware-versions/version b/libfwupdplugin/tests/devicetree/base/ibm,firmware-versions/version
deleted file mode 100644
index 94b2bd66d..000000000
--- a/libfwupdplugin/tests/devicetree/base/ibm,firmware-versions/version
+++ /dev/null
@@ -1 +0,0 @@
-1.2.3-4
\ No newline at end of file
diff --git a/libfwupdplugin/tests/devicetree/base/model b/libfwupdplugin/tests/devicetree/base/model
deleted file mode 100644
index 86c8a128b..000000000
--- a/libfwupdplugin/tests/devicetree/base/model
+++ /dev/null
@@ -1 +0,0 @@
-ColorHug
\ No newline at end of file
diff --git a/libfwupdplugin/tests/devicetree/base/model-name b/libfwupdplugin/tests/devicetree/base/model-name
deleted file mode 100644
index 9d37fc1ac..000000000
--- a/libfwupdplugin/tests/devicetree/base/model-name
+++ /dev/null
@@ -1 +0,0 @@
-To Be Filled By O.E.M.
\ No newline at end of file
diff --git a/libfwupdplugin/tests/devicetree/base/name b/libfwupdplugin/tests/devicetree/base/name
deleted file mode 100644
index f76dd238a..000000000
Binary files a/libfwupdplugin/tests/devicetree/base/name and /dev/null differ
diff --git a/libfwupdplugin/tests/devicetree/base/vendor b/libfwupdplugin/tests/devicetree/base/vendor
deleted file mode 100644
index 1555d1a5c..000000000
--- a/libfwupdplugin/tests/devicetree/base/vendor
+++ /dev/null
@@ -1 +0,0 @@
-Hughski Limited
\ No newline at end of file
diff --git a/libfwupdplugin/tests/devicetree/base/vpd/name b/libfwupdplugin/tests/devicetree/base/vpd/name
deleted file mode 100644
index b8acbc9ee..000000000
Binary files a/libfwupdplugin/tests/devicetree/base/vpd/name and /dev/null differ
diff --git a/libfwupdplugin/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/name b/libfwupdplugin/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/name
deleted file mode 100644
index 1f22cb8d6..000000000
Binary files a/libfwupdplugin/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/name and /dev/null differ
diff --git a/libfwupdplugin/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/part-number b/libfwupdplugin/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/part-number
deleted file mode 100644
index e00c9e144..000000000
--- a/libfwupdplugin/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/part-number
+++ /dev/null
@@ -1 +0,0 @@
-PCB-CH001
\ No newline at end of file
diff --git a/libfwupdplugin/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/vendor b/libfwupdplugin/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/vendor
deleted file mode 100644
index ffbb9e015..000000000
--- a/libfwupdplugin/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/vendor
+++ /dev/null
@@ -1 +0,0 @@
-Richard Hughes
\ No newline at end of file
diff --git a/libfwupdplugin/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/name b/libfwupdplugin/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/name
deleted file mode 100644
index 88600030b..000000000
Binary files a/libfwupdplugin/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/name and /dev/null differ
diff --git a/libfwupdplugin/tests/devicetree/base/vpd/root-node-vpd@a000/name b/libfwupdplugin/tests/devicetree/base/vpd/root-node-vpd@a000/name
deleted file mode 100644
index c6f7bd989..000000000
Binary files a/libfwupdplugin/tests/devicetree/base/vpd/root-node-vpd@a000/name and /dev/null differ
diff --git a/libfwupdplugin/tests/dmi/class/sys_vendor b/libfwupdplugin/tests/sys_vendor
similarity index 100%
rename from libfwupdplugin/tests/dmi/class/sys_vendor
rename to libfwupdplugin/tests/sys_vendor
diff --git a/src/fu-tool.c b/src/fu-tool.c
index 8271984f1..9437571ca 100644
--- a/src/fu-tool.c
+++ b/src/fu-tool.c
@@ -34,7 +34,6 @@
#include "fu-device-private.h"
#include "fu-engine.h"
#include "fu-history.h"
-#include "fu-hwids.h"
#include "fu-plugin-private.h"
#include "fu-progressbar.h"
#include "fu-security-attr-common.h"
@@ -1974,8 +1973,8 @@ fu_util_activate(FuUtilPrivate *priv, gchar **values, GError **error)
static gboolean
fu_util_export_hwids(FuUtilPrivate *priv, gchar **values, GError **error)
{
- g_autoptr(FuHwids) hwids = fu_hwids_new();
- g_autoptr(FuSmbios) smbios = fu_smbios_new();
+ FuContext *ctx = fu_engine_get_context(priv->engine);
+ FuHwids *hwids = fu_context_get_hwids(ctx);
g_autoptr(GKeyFile) kf = g_key_file_new();
g_autoptr(GPtrArray) hwid_keys = NULL;
@@ -1989,9 +1988,7 @@ fu_util_export_hwids(FuUtilPrivate *priv, gchar **values, GError **error)
}
/* setup default hwids */
- if (!fu_smbios_setup(smbios, error))
- return FALSE;
- if (!fu_hwids_setup(hwids, smbios, error))
+ if (!fu_context_load_hwinfo(ctx, FU_CONTEXT_HWID_FLAG_LOAD_ALL, error))
return FALSE;
/* save all keys */
@@ -2009,39 +2006,23 @@ fu_util_export_hwids(FuUtilPrivate *priv, gchar **values, GError **error)
static gboolean
fu_util_hwids(FuUtilPrivate *priv, gchar **values, GError **error)
{
- g_autoptr(FuSmbios) smbios = NULL;
- g_autoptr(FuHwids) hwids = fu_hwids_new();
+ FuContext *ctx = fu_engine_get_context(priv->engine);
+ FuHwids *hwids = fu_context_get_hwids(ctx);
g_autoptr(GPtrArray) hwid_keys = fu_hwids_get_keys(hwids);
- /* read DMI data */
- if (g_strv_length(values) == 0) {
- smbios = fu_smbios_new();
- if (!fu_smbios_setup(smbios, error))
- return FALSE;
- } else if (g_strv_length(values) == 1) {
- /* a keyfile with overrides */
+ /* a keyfile with overrides */
+ if (g_strv_length(values) == 1) {
g_autoptr(GKeyFile) kf = g_key_file_new();
- if (g_key_file_load_from_file(kf, values[0], G_KEY_FILE_NONE, NULL)) {
- for (guint i = 0; i < hwid_keys->len; i++) {
- const gchar *hwid_key = g_ptr_array_index(hwid_keys, i);
- g_autofree gchar *tmp = NULL;
- tmp = g_key_file_get_string(kf, "HwIds", hwid_key, NULL);
- fu_hwids_add_smbios_override(hwids, hwid_key, tmp);
- }
- /* a DMI blob */
- } else {
- smbios = fu_smbios_new();
- if (!fu_smbios_setup_from_file(smbios, values[0], error))
- return FALSE;
+ if (!g_key_file_load_from_file(kf, values[0], G_KEY_FILE_NONE, error))
+ return FALSE;
+ for (guint i = 0; i < hwid_keys->len; i++) {
+ const gchar *hwid_key = g_ptr_array_index(hwid_keys, i);
+ g_autofree gchar *tmp = NULL;
+ tmp = g_key_file_get_string(kf, "HwIds", hwid_key, NULL);
+ fu_hwids_add_value(hwids, hwid_key, tmp);
}
- } else {
- g_set_error_literal(error,
- FWUPD_ERROR,
- FWUPD_ERROR_INVALID_ARGS,
- "Invalid arguments");
- return FALSE;
}
- if (!fu_hwids_setup(hwids, smbios, error))
+ if (!fu_context_load_hwinfo(ctx, FU_CONTEXT_HWID_FLAG_LOAD_ALL, error))
return FALSE;
/* show debug output */