mirror of
https://git.proxmox.com/git/fwupd
synced 2025-06-12 23:04:19 +00:00
Refactor the hwids functionality
This refactors the code as it was getting very confusing; before FuSmbios was reading both SMBIOS and the kernel-provided DT -- and various things were injecting overrides in three different place. To properly support FDT remove one layer of indirection. This also lets us use the compatible strings to enable plugins specifying the flag _REQUIRE_HWID -- which means we only load the plugin if it's got a chance of working. e.g. [aspeed,ast2500]
This commit is contained in:
parent
72f5c1e01e
commit
2b0f92506b
@ -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
|
||||
|
@ -46,6 +46,7 @@ content_files = [
|
||||
"tutorial.md",
|
||||
"hsi.md",
|
||||
"ds20.md",
|
||||
"hwids.md",
|
||||
"bios-settings.md",
|
||||
@plugin_readme_outputs@,
|
||||
]
|
||||
|
85
docs/hwids.md
Normal file
85
docs/hwids.md
Normal file
@ -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.
|
@ -45,6 +45,9 @@
|
||||
<ul>
|
||||
<li><a href="libfwupdplugin/tutorial.html">Plugin tutorial</a></li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><a href="libfwupdplugin/hwids.html">Hardware IDs</a></li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><a href="libfwupdplugin/env.html">Environment variables</a></li>
|
||||
</ul>
|
||||
|
@ -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);
|
||||
|
48
libfwupdplugin/fu-hwids-config.c
Normal file
48
libfwupdplugin/fu-hwids-config.c
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* 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;
|
||||
}
|
71
libfwupdplugin/fu-hwids-dmi.c
Normal file
71
libfwupdplugin/fu-hwids-dmi.c
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* 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;
|
||||
}
|
73
libfwupdplugin/fu-hwids-fdt.c
Normal file
73
libfwupdplugin/fu-hwids-fdt.c
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* 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;
|
||||
}
|
44
libfwupdplugin/fu-hwids-kenv.c
Normal file
44
libfwupdplugin/fu-hwids-kenv.c
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* 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;
|
||||
}
|
25
libfwupdplugin/fu-hwids-private.h
Normal file
25
libfwupdplugin/fu-hwids-private.h
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* 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);
|
147
libfwupdplugin/fu-hwids-smbios.c
Normal file
147
libfwupdplugin/fu-hwids-smbios.c
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* 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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include <libfwupdplugin/fu-fit-firmware.h>
|
||||
#include <libfwupdplugin/fu-fmap-firmware.h>
|
||||
#include <libfwupdplugin/fu-hid-device.h>
|
||||
#include <libfwupdplugin/fu-hwids.h>
|
||||
#include <libfwupdplugin/fu-i2c-device.h>
|
||||
#include <libfwupdplugin/fu-ifd-bios.h>
|
||||
#include <libfwupdplugin/fu-ifd-firmware.h>
|
||||
|
@ -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: *;
|
||||
|
@ -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
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
../../devicetree/base/compatible
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
1.2.3-4
|
@ -1 +0,0 @@
|
||||
ColorHug
|
@ -1 +0,0 @@
|
||||
To Be Filled By O.E.M.
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
Hughski Limited
|
Binary file not shown.
Binary file not shown.
@ -1 +0,0 @@
|
||||
PCB-CH001
|
@ -1 +0,0 @@
|
||||
Richard Hughes
|
Binary file not shown.
Binary file not shown.
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user