mirror of
https://git.proxmox.com/git/fwupd
synced 2025-07-27 11:09:28 +00:00
Release fwupd 1.8.10
-----BEGIN PGP SIGNATURE----- iQFIBAABCAAyFiEEFj61ARkiXbPfj0nqF6y6jfqXDhcFAmPOXskUHHJpY2hhcmRA aHVnaHNpZS5jb20ACgkQF6y6jfqXDhdyBAf/YXQ8w8giq39B2Bn1AnMhjQ1Raox7 4+dgbabmHY8yP1zEDk7g2SkkXP19Ur76pYfJHg9nlo4zuGj5QlxgHwTfIeDrJE+O pZVytRS1sKZpSJOzGXRsKbJHEr7scNap02wlSqoyzku3X1lfv8B2oKQT5aMFLxPH E6eFN4v3V1XGeAybpTTu4UNJB3mWAZoq2oeyeavxehkznCLh9oPW+HURjtO6T1nO RxFQC2Nu7wOc/IwE5h77OvsycC0g9VAjPFmQgP8MqT2lP3MkeIWpXH0cPBvjw+97 TvAZADAa2VEIJPVkFsIUCHxCXC2/Lo4WlrYXvW1/zWf97Kp+BtzGi9xg4Q== =nLs4 -----END PGP SIGNATURE----- Merge tag '1.8.10' into debian Release fwupd 1.8.10
This commit is contained in:
commit
0a1f339298
4
RELEASE
4
RELEASE
@ -10,7 +10,7 @@ To make sure it's done right, you can reference commit 433e809318c68c9ab6d4ae50e
|
||||
|
||||
Write release entries:
|
||||
|
||||
git log --format="%s" --cherry-pick --right-only 1.8.8... | grep -i -v trivial | grep -v Merge | sort | uniq
|
||||
git log --format="%s" --cherry-pick --right-only 1.8.9... | grep -i -v trivial | grep -v Merge | sort | uniq
|
||||
Add any user visible changes into ../data/org.freedesktop.fwupd.metainfo.xml
|
||||
appstream-util appdata-to-news ../data/org.freedesktop.fwupd.metainfo.xml > NEWS
|
||||
|
||||
@ -25,7 +25,7 @@ git add ../po/*.po
|
||||
2. Commit changes to git:
|
||||
|
||||
# MAKE SURE THIS IS CORRECT
|
||||
export release_ver="1.8.9"
|
||||
export release_ver="1.8.10"
|
||||
|
||||
git commit -a -m "Release fwupd ${release_ver}" --no-verify
|
||||
git tag -s -f -m "Release fwupd ${release_ver}" "${release_ver}"
|
||||
|
@ -87,7 +87,6 @@ def build_install(revision):
|
||||
"--prefix=/usr",
|
||||
"--libdir=lib",
|
||||
"-Dauto_features=disabled",
|
||||
"-Ddocs=none",
|
||||
"-Db_coverage=false",
|
||||
"-Dgusb:docs=false",
|
||||
"-Dtests=false",
|
||||
|
@ -178,7 +178,7 @@ def install_packages(os, variant, yes, debugging, packages):
|
||||
installer += packages
|
||||
if debugging:
|
||||
print(installer)
|
||||
subprocess.call(installer)
|
||||
subprocess.check_call(installer)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -463,6 +463,8 @@ done
|
||||
%if 0%{?have_uefi}
|
||||
%{_datadir}/installed-tests/fwupd/efi
|
||||
%endif
|
||||
%{_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
|
||||
|
@ -191,6 +191,9 @@ FirmwareSizeMax = 0x20000
|
||||
[CFI\FLASHID_EF4018]
|
||||
Name = W25Q128
|
||||
FirmwareSizeMax = 0x1000000
|
||||
[CFI\FLASHID_EF4019]
|
||||
Name = W25Q256
|
||||
FirmwareSizeMax = 0x2000000
|
||||
|
||||
# Fidelix
|
||||
[CFI\FLASHID_F8]
|
||||
|
@ -33,6 +33,36 @@
|
||||
<binary>fwupdtool</binary>
|
||||
</provides>
|
||||
<releases>
|
||||
<release version="1.8.10" date="2023-01-23">
|
||||
<description>
|
||||
<p>
|
||||
This release adds the following features:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Add a PE/COFF firmware parser to allow reading coSWID SBoM data</li>
|
||||
<li>Allow dumping CFI SPI chips using devices like CH341a</li>
|
||||
<li>Refactor the HWIDs functionality to include FDT data</li>
|
||||
</ul>
|
||||
<p>This release fixes the following bugs:</p>
|
||||
<ul>
|
||||
<li>Add back a legacy eMMC GUID to fix a regression</li>
|
||||
<li>Always search for uSWID SBoM data in the image</li>
|
||||
<li>Do not allow LZX compressed cabinet archives</li>
|
||||
<li>Fallback to the checksum if the metadata artifact is invalid</li>
|
||||
<li>Improve FDT parsing compatibility with new OpenBMC images</li>
|
||||
<li>Never call grub2-probe without arguments</li>
|
||||
<li>Respect user requested paths for the ESP even if they are not volumes</li>
|
||||
<li>Speed up ChromeOS startup by a huge amount when using directory remotes</li>
|
||||
<li>Verify the Synaptics RMI signature in more cases</li>
|
||||
</ul>
|
||||
<p>This release adds support for the following hardware:</p>
|
||||
<ul>
|
||||
<li>Quectel RM520</li>
|
||||
<li>StarBook Mk VI</li>
|
||||
<li>System76 launch_heavy_1</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="1.8.9" date="2023-01-03">
|
||||
<description>
|
||||
<p>
|
||||
|
@ -1,4 +1,6 @@
|
||||
# fwupd BOS DS20 Specification
|
||||
---
|
||||
title: BOS DS20 Specification
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
|
@ -85,6 +85,7 @@ for details.
|
||||
* `FWUPD_OFFLINE_TRIGGER`
|
||||
* `FWUPD_PROCFS`
|
||||
* `FWUPD_SYSCONFDIR`
|
||||
* `FWUPD_SYSFSDMIDIR`
|
||||
* `FWUPD_SYSFSDRIVERDIR`
|
||||
* `FWUPD_SYSFSFWATTRIBDIR`
|
||||
* `FWUPD_SYSFSFWDIR`
|
||||
|
@ -46,7 +46,9 @@ content_files = [
|
||||
"tutorial.md",
|
||||
"hsi.md",
|
||||
"ds20.md",
|
||||
"hwids.md",
|
||||
"bios-settings.md",
|
||||
@plugin_readme_outputs@,
|
||||
]
|
||||
content_images = [
|
||||
"architecture-plan.svg",
|
||||
|
@ -5,6 +5,11 @@
|
||||
"AMD SOCs include the ability to prevent a rollback attack by a rollback protection feature on the secure processor.",
|
||||
"This feature prevents an attacker from loading an older firmware onto the part after a security vulnerability has been fixed."
|
||||
],
|
||||
"more-information": [
|
||||
"This particular check is not for the Microsoft Pluton Security processor which is present on some chips.",
|
||||
"End users are not able to directly modify rollback protection, this is controlled by the manufacturer.",
|
||||
"On Lenovo systems it has been reported that if this is disabled it may potentially be enabled by loading 'OS Optimized Defaults' in BIOS setup."
|
||||
],
|
||||
"failure-impact": [
|
||||
"SOCs without this feature may be attacked by an attacker installing an older firmware that takes advantage of a well-known vulnerability."
|
||||
],
|
||||
@ -16,7 +21,10 @@
|
||||
},
|
||||
"hsi-level": 4,
|
||||
"references": {
|
||||
"https://www.psacertified.org/blog/anti-rollback-explained/": "Rollback protection"
|
||||
"https://www.psacertified.org/blog/anti-rollback-explained/": "Rollback protection",
|
||||
"https://www.amd.com/en/technologies/pro-security": "AMD Secure Processor",
|
||||
"https://forums.lenovo.com/t5/Fedora/AMD-Rollback-protection-not-detected-by-fwupd-on-T14-G3-AMD/m-p/5182708?page=1#5810366":
|
||||
"Loading OS Optimized Defaults on Lenovo systems"
|
||||
},
|
||||
"fwupd-version": "1.8.0"
|
||||
}
|
||||
|
@ -15,6 +15,12 @@
|
||||
"success-results" : {
|
||||
"valid" : "the CPU platform is supported and has HSI tests"
|
||||
},
|
||||
"more-information": [
|
||||
"On AMD APUs or CPUs this information is reported on kernel 5.19 or later via the `ccp` kernel module. ",
|
||||
"If the kernel module is enabled but is not being auto-loaded, this is a kernel bug and should be reported to kernel bugzilla. ",
|
||||
"If the kernel module has loaded but you still don't have data this is NOT a fwupd bug. You will have to contact ",
|
||||
"your motherboard or system manufacturer to enable reporting this information."
|
||||
],
|
||||
"hsi-level" : 1,
|
||||
"fwupd-version" : "1.8.0"
|
||||
}
|
||||
|
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>
|
||||
|
@ -1,3 +1,16 @@
|
||||
plugin_readme_targets = []
|
||||
plugin_readme_outputs = []
|
||||
foreach plugin: plugins
|
||||
plugin_readme_output = '@0@-README.md'.format(plugin)
|
||||
plugin_readme_targets += custom_target('doc-plugin-@0@'.format(plugin),
|
||||
input: join_paths(meson.project_source_root(), 'plugins', plugin, 'README.md'),
|
||||
output: plugin_readme_output,
|
||||
command: ['ln', '-sf', '@INPUT0@', '@OUTPUT@'],
|
||||
build_by_default: true,
|
||||
)
|
||||
plugin_readme_outputs += '"@0@"'.format(plugin_readme_output)
|
||||
endforeach
|
||||
|
||||
if build_docs and introspection.allowed()
|
||||
toml_conf = configuration_data()
|
||||
docgen_version = source_version
|
||||
@ -5,6 +18,7 @@ if build_docs and introspection.allowed()
|
||||
docgen_version = run_command([git, 'branch', '--show-current'], check: true).stdout().strip()
|
||||
endif
|
||||
toml_conf.set('version', docgen_version)
|
||||
toml_conf.set('plugin_readme_outputs', ','.join(plugin_readme_outputs))
|
||||
|
||||
fwupd_toml = configure_file(
|
||||
input: 'fwupd.toml.in',
|
||||
@ -89,6 +103,7 @@ if build_docs and introspection.allowed()
|
||||
depends: [
|
||||
fwupdplugin_gir[0],
|
||||
hsi_md,
|
||||
plugin_readme_targets,
|
||||
],
|
||||
build_by_default: true,
|
||||
install: true,
|
||||
|
@ -59,6 +59,10 @@ fu_backend_device_added(FuBackend *self, FuDevice *device)
|
||||
if (priv->ctx != NULL)
|
||||
fu_device_set_context(device, priv->ctx);
|
||||
|
||||
/* set backend ID if required */
|
||||
if (fu_device_get_backend_id(device) == NULL)
|
||||
fu_device_set_backend_id(device, priv->name);
|
||||
|
||||
/* add */
|
||||
g_hash_table_insert(priv->devices,
|
||||
g_strdup(fu_device_get_backend_id(device)),
|
||||
|
@ -13,7 +13,6 @@ G_DECLARE_DERIVABLE_TYPE(FuBluezDevice, fu_bluez_device, FU, BLUEZ_DEVICE, FuDev
|
||||
|
||||
struct _FuBluezDeviceClass {
|
||||
FuDeviceClass parent_class;
|
||||
gpointer __reserved[31];
|
||||
};
|
||||
|
||||
GByteArray *
|
||||
|
@ -69,6 +69,10 @@ fu_cabinet_init(FuCabinet *self)
|
||||
{
|
||||
self->size_max = 1024 * 1024 * 100;
|
||||
self->gcab_cabinet = gcab_cabinet_new();
|
||||
#ifdef HAVE_GCAB_CABINET_ADD_ALLOWED_COMPRESSION
|
||||
gcab_cabinet_add_allowed_compression(self->gcab_cabinet, GCAB_COMPRESSION_NONE);
|
||||
gcab_cabinet_add_allowed_compression(self->gcab_cabinet, GCAB_COMPRESSION_MSZIP);
|
||||
#endif
|
||||
self->builder = xb_builder_new();
|
||||
self->jcat_file = jcat_file_new();
|
||||
self->jcat_context = jcat_context_new();
|
||||
|
@ -14,7 +14,6 @@ G_DECLARE_DERIVABLE_TYPE(FuCfiDevice, fu_cfi_device, FU, CFI_DEVICE, FuDevice)
|
||||
struct _FuCfiDeviceClass {
|
||||
FuDeviceClass parent_class;
|
||||
gboolean (*chip_select)(FuCfiDevice *self, gboolean value, GError **error);
|
||||
gpointer __reserved[30];
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -11,12 +11,22 @@
|
||||
#include "fu-quirks.h"
|
||||
#include "fu-volume.h"
|
||||
|
||||
typedef enum {
|
||||
FU_CONTEXT_HWID_FLAG_NONE = 0,
|
||||
FU_CONTEXT_HWID_FLAG_LOAD_CONFIG = 1 << 0,
|
||||
FU_CONTEXT_HWID_FLAG_LOAD_SMBIOS = 1 << 1,
|
||||
FU_CONTEXT_HWID_FLAG_LOAD_FDT = 1 << 2,
|
||||
FU_CONTEXT_HWID_FLAG_LOAD_DMI = 1 << 3,
|
||||
FU_CONTEXT_HWID_FLAG_LOAD_KENV = 1 << 4,
|
||||
FU_CONTEXT_HWID_FLAG_LOAD_ALL = G_MAXUINT,
|
||||
} FuContextHwidFlags;
|
||||
|
||||
FuContext *
|
||||
fu_context_new(void);
|
||||
gboolean
|
||||
fu_context_reload_bios_settings(FuContext *self, GError **error);
|
||||
gboolean
|
||||
fu_context_load_hwinfo(FuContext *self, GError **error);
|
||||
fu_context_load_hwinfo(FuContext *self, FuContextHwidFlags flags, GError **error);
|
||||
gboolean
|
||||
fu_context_load_quirks(FuContext *self, FuQuirksLoadFlags flags, GError **error);
|
||||
void
|
||||
@ -35,3 +45,9 @@ GPtrArray *
|
||||
fu_context_get_udev_subsystems(FuContext *self);
|
||||
void
|
||||
fu_context_add_esp_volume(FuContext *self, FuVolume *volume);
|
||||
FuSmbios *
|
||||
fu_context_get_smbios(FuContext *self);
|
||||
FuHwids *
|
||||
fu_context_get_hwids(FuContext *self);
|
||||
void
|
||||
fu_context_set_chassis_kind(FuContext *self, FuSmbiosChassisKind chassis_kind);
|
||||
|
@ -10,7 +10,9 @@
|
||||
|
||||
#include "fu-bios-settings-private.h"
|
||||
#include "fu-context-private.h"
|
||||
#include "fu-hwids.h"
|
||||
#include "fu-fdt-firmware.h"
|
||||
#include "fu-hwids-private.h"
|
||||
#include "fu-path.h"
|
||||
#include "fu-smbios-private.h"
|
||||
#include "fu-volume-private.h"
|
||||
|
||||
@ -25,6 +27,7 @@ typedef struct {
|
||||
FuContextFlags flags;
|
||||
FuHwids *hwids;
|
||||
FuSmbios *smbios;
|
||||
FuSmbiosChassisKind chassis_kind;
|
||||
FuQuirks *quirks;
|
||||
GHashTable *runtime_versions;
|
||||
GHashTable *compile_versions;
|
||||
@ -38,6 +41,7 @@ typedef struct {
|
||||
guint battery_threshold;
|
||||
FuBiosSettings *host_bios_settings;
|
||||
gboolean loaded_hwinfo;
|
||||
FuFirmware *fdt; /* optional */
|
||||
} FuContextPrivate;
|
||||
|
||||
enum { SIGNAL_SECURITY_CHANGED, SIGNAL_LAST };
|
||||
@ -48,6 +52,7 @@ enum {
|
||||
PROP_LID_STATE,
|
||||
PROP_BATTERY_LEVEL,
|
||||
PROP_BATTERY_THRESHOLD,
|
||||
PROP_FLAGS,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
@ -57,11 +62,116 @@ G_DEFINE_TYPE_WITH_PRIVATE(FuContext, fu_context, G_TYPE_OBJECT)
|
||||
|
||||
#define GET_PRIVATE(o) (fu_context_get_instance_private(o))
|
||||
|
||||
static GFile *
|
||||
fu_context_get_fdt_file(GError **error)
|
||||
{
|
||||
g_autofree gchar *fdtfn_local = NULL;
|
||||
g_autofree gchar *fdtfn_sys = NULL;
|
||||
g_autofree gchar *localstatedir_pkg = fu_path_from_kind(FU_PATH_KIND_LOCALSTATEDIR_PKG);
|
||||
g_autofree gchar *sysfsdir = NULL;
|
||||
|
||||
/* look for override first, fall back to system value */
|
||||
fdtfn_local = g_build_filename(localstatedir_pkg, "system.dtb", NULL);
|
||||
if (g_file_test(fdtfn_local, G_FILE_TEST_EXISTS))
|
||||
return g_file_new_for_path(fdtfn_local);
|
||||
|
||||
/* actual hardware value */
|
||||
sysfsdir = fu_path_from_kind(FU_PATH_KIND_SYSFSDIR_FW);
|
||||
fdtfn_sys = g_build_filename(sysfsdir, "fdt", NULL);
|
||||
if (g_file_test(fdtfn_sys, G_FILE_TEST_EXISTS))
|
||||
return g_file_new_for_path(fdtfn_sys);
|
||||
|
||||
/* failed */
|
||||
g_set_error(error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_NOT_SUPPORTED,
|
||||
"cannot find %s or override %s",
|
||||
fdtfn_sys,
|
||||
fdtfn_local);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_context_get_fdt:
|
||||
* @self: a #FuContext
|
||||
* @error: (nullable): optional return location for an error
|
||||
*
|
||||
* Gets and parses the system FDT, aka. the Flat Device Tree.
|
||||
*
|
||||
* The results are cached internally to the context, and subsequent calls to this function
|
||||
* returns the pre-parsed object.
|
||||
*
|
||||
* Returns: (transfer full): a #FuFdtFirmware, or %NULL
|
||||
*
|
||||
* Since: 1.8.10
|
||||
**/
|
||||
FuFirmware *
|
||||
fu_context_get_fdt(FuContext *self, GError **error)
|
||||
{
|
||||
FuContextPrivate *priv = GET_PRIVATE(self);
|
||||
|
||||
g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
|
||||
g_return_val_if_fail(error == NULL || *error == NULL, NULL);
|
||||
|
||||
/* load if not already parsed */
|
||||
if (priv->fdt == NULL) {
|
||||
g_autoptr(FuFirmware) fdt_tmp = fu_fdt_firmware_new();
|
||||
g_autoptr(GFile) file = fu_context_get_fdt_file(error);
|
||||
if (file == NULL)
|
||||
return NULL;
|
||||
if (!fu_firmware_parse_file(fdt_tmp, file, FWUPD_INSTALL_FLAG_NO_SEARCH, error)) {
|
||||
g_prefix_error(error, "failed to parse FDT: ");
|
||||
return NULL;
|
||||
}
|
||||
priv->fdt = g_steal_pointer(&fdt_tmp);
|
||||
}
|
||||
|
||||
/* success */
|
||||
return g_object_ref(priv->fdt);
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_context_get_smbios:
|
||||
* @self: a #FuContext
|
||||
*
|
||||
* Gets the SMBIOS store.
|
||||
*
|
||||
* Returns: (transfer none): a #FuSmbios
|
||||
*
|
||||
* Since: 1.8.10
|
||||
**/
|
||||
FuSmbios *
|
||||
fu_context_get_smbios(FuContext *self)
|
||||
{
|
||||
FuContextPrivate *priv = GET_PRIVATE(self);
|
||||
g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
|
||||
return priv->smbios;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_context_get_hwids:
|
||||
* @self: a #FuContext
|
||||
*
|
||||
* Gets the HWIDs store.
|
||||
*
|
||||
* Returns: (transfer none): a #FuHwids
|
||||
*
|
||||
* Since: 1.8.10
|
||||
**/
|
||||
FuHwids *
|
||||
fu_context_get_hwids(FuContext *self)
|
||||
{
|
||||
FuContextPrivate *priv = GET_PRIVATE(self);
|
||||
g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
|
||||
return priv->hwids;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_context_get_smbios_string:
|
||||
* @self: a #FuContext
|
||||
* @structure_type: a SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
|
||||
* @offset: a SMBIOS offset
|
||||
* @error: (nullable): optional return location for an error
|
||||
*
|
||||
* Gets a hardware SMBIOS string.
|
||||
*
|
||||
@ -73,7 +183,7 @@ G_DEFINE_TYPE_WITH_PRIVATE(FuContext, fu_context, G_TYPE_OBJECT)
|
||||
* Since: 1.6.0
|
||||
**/
|
||||
const gchar *
|
||||
fu_context_get_smbios_string(FuContext *self, guint8 structure_type, guint8 offset)
|
||||
fu_context_get_smbios_string(FuContext *self, guint8 structure_type, guint8 offset, GError **error)
|
||||
{
|
||||
FuContextPrivate *priv = GET_PRIVATE(self);
|
||||
g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
|
||||
@ -81,7 +191,7 @@ fu_context_get_smbios_string(FuContext *self, guint8 structure_type, guint8 offs
|
||||
g_critical("cannot use SMBIOS before calling ->load_hwinfo()");
|
||||
return NULL;
|
||||
}
|
||||
return fu_smbios_get_string(priv->smbios, structure_type, offset, NULL);
|
||||
return fu_smbios_get_string(priv->smbios, structure_type, offset, error);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -125,6 +235,7 @@ fu_context_get_smbios_data(FuContext *self, guint8 structure_type, GError **erro
|
||||
* @self: a #FuContext
|
||||
* @type: a structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
|
||||
* @offset: a structure offset
|
||||
* @error: (nullable): optional return location for an error
|
||||
*
|
||||
* Reads an integer value from the SMBIOS string table of a specific structure.
|
||||
*
|
||||
@ -136,7 +247,7 @@ fu_context_get_smbios_data(FuContext *self, guint8 structure_type, GError **erro
|
||||
* Since: 1.6.0
|
||||
**/
|
||||
guint
|
||||
fu_context_get_smbios_integer(FuContext *self, guint8 type, guint8 offset)
|
||||
fu_context_get_smbios_integer(FuContext *self, guint8 type, guint8 offset, GError **error)
|
||||
{
|
||||
FuContextPrivate *priv = GET_PRIVATE(self);
|
||||
g_return_val_if_fail(FU_IS_CONTEXT(self), G_MAXUINT);
|
||||
@ -144,7 +255,7 @@ fu_context_get_smbios_integer(FuContext *self, guint8 type, guint8 offset)
|
||||
g_critical("cannot use SMBIOS before calling ->load_hwinfo()");
|
||||
return G_MAXUINT;
|
||||
}
|
||||
return fu_smbios_get_integer(priv->smbios, type, offset, NULL);
|
||||
return fu_smbios_get_integer(priv->smbios, type, offset, error);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -222,6 +333,41 @@ fu_context_get_bios_setting_pending_reboot(FuContext *self)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_context_get_chassis_kind:
|
||||
* @self: a #FuContext
|
||||
*
|
||||
* Gets the chassis kind, if known.
|
||||
*
|
||||
* Returns: a #FuSmbiosChassisKind, e.g. %FU_SMBIOS_CHASSIS_KIND_LAPTOP
|
||||
*
|
||||
* Since: 1.8.10
|
||||
**/
|
||||
FuSmbiosChassisKind
|
||||
fu_context_get_chassis_kind(FuContext *self)
|
||||
{
|
||||
FuContextPrivate *priv = GET_PRIVATE(self);
|
||||
g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
|
||||
return priv->chassis_kind;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_context_set_chassis_kind:
|
||||
* @self: a #FuContext
|
||||
* @chassis_kind: a #FuSmbiosChassisKind, e.g. %FU_SMBIOS_CHASSIS_KIND_TABLET
|
||||
*
|
||||
* Sets the chassis kind.
|
||||
*
|
||||
* Since: 1.8.10
|
||||
**/
|
||||
void
|
||||
fu_context_set_chassis_kind(FuContext *self, FuSmbiosChassisKind chassis_kind)
|
||||
{
|
||||
FuContextPrivate *priv = GET_PRIVATE(self);
|
||||
g_return_if_fail(FU_IS_CONTEXT(self));
|
||||
priv->chassis_kind = chassis_kind;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_context_has_hwid_guid:
|
||||
* @self: a #FuContext
|
||||
@ -310,8 +456,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");
|
||||
@ -621,31 +770,84 @@ fu_context_security_changed(FuContext *self)
|
||||
/**
|
||||
* fu_context_load_hwinfo:
|
||||
* @self: a #FuContext
|
||||
* @flags: a #FuContextHwidFlags, e.g. %FU_CONTEXT_HWID_FLAG_LOAD_SMBIOS
|
||||
* @error: (nullable): optional return location for an error
|
||||
*
|
||||
* Loads all hardware information parts of the context.
|
||||
*
|
||||
* Returns: %TRUE for success
|
||||
*
|
||||
* Since: 1.6.0
|
||||
* Since: 1.8.10
|
||||
**/
|
||||
gboolean
|
||||
fu_context_load_hwinfo(FuContext *self, GError **error)
|
||||
fu_context_load_hwinfo(FuContext *self, FuContextHwidFlags flags, GError **error)
|
||||
{
|
||||
FuContextPrivate *priv = GET_PRIVATE(self);
|
||||
GPtrArray *guids;
|
||||
g_autoptr(GError) error_smbios = NULL;
|
||||
g_autoptr(GError) error_hwids = NULL;
|
||||
g_autoptr(GError) error_bios_settings = NULL;
|
||||
|
||||
g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
|
||||
g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
|
||||
|
||||
if (!fu_smbios_setup(priv->smbios, &error_smbios))
|
||||
g_warning("Failed to load SMBIOS: %s", error_smbios->message);
|
||||
if (!fu_hwids_setup(priv->hwids, priv->smbios, &error_hwids))
|
||||
g_warning("Failed to load HWIDs: %s", error_hwids->message);
|
||||
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_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
@ -891,7 +1093,30 @@ fu_context_add_flag(FuContext *context, FuContextFlags flag)
|
||||
{
|
||||
FuContextPrivate *priv = GET_PRIVATE(context);
|
||||
g_return_if_fail(FU_IS_CONTEXT(context));
|
||||
if (priv->flags & flag)
|
||||
return;
|
||||
priv->flags |= flag;
|
||||
g_object_notify(G_OBJECT(context), "flags");
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_context_remove_flag:
|
||||
* @context: a #FuContext
|
||||
* @flag: the context flag
|
||||
*
|
||||
* Removes a specific flag from the context.
|
||||
*
|
||||
* Since: 1.8.10
|
||||
**/
|
||||
void
|
||||
fu_context_remove_flag(FuContext *context, FuContextFlags flag)
|
||||
{
|
||||
FuContextPrivate *priv = GET_PRIVATE(context);
|
||||
g_return_if_fail(FU_IS_CONTEXT(context));
|
||||
if ((priv->flags & flag) == 0)
|
||||
return;
|
||||
priv->flags &= ~flag;
|
||||
g_object_notify(G_OBJECT(context), "flags");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1039,6 +1264,9 @@ fu_context_get_property(GObject *object, guint prop_id, GValue *value, GParamSpe
|
||||
case PROP_BATTERY_THRESHOLD:
|
||||
g_value_set_uint(value, priv->battery_threshold);
|
||||
break;
|
||||
case PROP_FLAGS:
|
||||
g_value_set_uint64(value, priv->flags);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
||||
break;
|
||||
@ -1049,6 +1277,7 @@ static void
|
||||
fu_context_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
FuContext *self = FU_CONTEXT(object);
|
||||
FuContextPrivate *priv = GET_PRIVATE(self);
|
||||
switch (prop_id) {
|
||||
case PROP_BATTERY_STATE:
|
||||
fu_context_set_battery_state(self, g_value_get_uint(value));
|
||||
@ -1062,6 +1291,9 @@ fu_context_set_property(GObject *object, guint prop_id, const GValue *value, GPa
|
||||
case PROP_BATTERY_THRESHOLD:
|
||||
fu_context_set_battery_threshold(self, g_value_get_uint(value));
|
||||
break;
|
||||
case PROP_FLAGS:
|
||||
priv->flags = g_value_get_uint64(value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
||||
break;
|
||||
@ -1078,6 +1310,8 @@ fu_context_finalize(GObject *object)
|
||||
g_hash_table_unref(priv->runtime_versions);
|
||||
if (priv->compile_versions != NULL)
|
||||
g_hash_table_unref(priv->compile_versions);
|
||||
if (priv->fdt != NULL)
|
||||
g_object_unref(priv->fdt);
|
||||
g_object_unref(priv->hwids);
|
||||
g_hash_table_unref(priv->hwid_flags);
|
||||
g_object_unref(priv->quirks);
|
||||
@ -1163,6 +1397,22 @@ fu_context_class_init(FuContextClass *klass)
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
|
||||
g_object_class_install_property(object_class, PROP_BATTERY_THRESHOLD, pspec);
|
||||
|
||||
/**
|
||||
* FuContext:flags:
|
||||
*
|
||||
* The context flags.
|
||||
*
|
||||
* Since: 1.8.10
|
||||
*/
|
||||
pspec = g_param_spec_uint64("flags",
|
||||
NULL,
|
||||
NULL,
|
||||
FU_CONTEXT_FLAG_NONE,
|
||||
G_MAXUINT64,
|
||||
FU_CONTEXT_FLAG_NONE,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
|
||||
g_object_class_install_property(object_class, PROP_FLAGS, pspec);
|
||||
|
||||
/**
|
||||
* FuContext::security-changed:
|
||||
* @self: the #FuContext instance that emitted the signal
|
||||
@ -1190,6 +1440,7 @@ static void
|
||||
fu_context_init(FuContext *self)
|
||||
{
|
||||
FuContextPrivate *priv = GET_PRIVATE(self);
|
||||
priv->chassis_kind = FU_SMBIOS_CHASSIS_KIND_UNKNOWN;
|
||||
priv->battery_level = FWUPD_BATTERY_LEVEL_INVALID;
|
||||
priv->battery_threshold = FWUPD_BATTERY_LEVEL_INVALID;
|
||||
priv->smbios = fu_smbios_new();
|
||||
|
@ -10,6 +10,8 @@
|
||||
|
||||
#include "fu-bios-settings.h"
|
||||
#include "fu-common.h"
|
||||
#include "fu-firmware.h"
|
||||
#include "fu-smbios.h"
|
||||
|
||||
#define FU_TYPE_CONTEXT (fu_context_get_type())
|
||||
G_DECLARE_DERIVABLE_TYPE(FuContext, fu_context, FU, CONTEXT, GObject)
|
||||
@ -61,13 +63,15 @@ typedef guint64 FuContextFlags;
|
||||
|
||||
void
|
||||
fu_context_add_flag(FuContext *context, FuContextFlags flag);
|
||||
void
|
||||
fu_context_remove_flag(FuContext *context, FuContextFlags flag);
|
||||
gboolean
|
||||
fu_context_has_flag(FuContext *context, FuContextFlags flag);
|
||||
|
||||
const gchar *
|
||||
fu_context_get_smbios_string(FuContext *self, guint8 structure_type, guint8 offset);
|
||||
fu_context_get_smbios_string(FuContext *self, guint8 structure_type, guint8 offset, GError **error);
|
||||
guint
|
||||
fu_context_get_smbios_integer(FuContext *self, guint8 type, guint8 offset);
|
||||
fu_context_get_smbios_integer(FuContext *self, guint8 type, guint8 offset, GError **error);
|
||||
GBytes *
|
||||
fu_context_get_smbios_data(FuContext *self, guint8 structure_type, GError **error);
|
||||
gboolean
|
||||
@ -124,3 +128,7 @@ fu_context_get_bios_setting(FuContext *self, const gchar *name);
|
||||
|
||||
GPtrArray *
|
||||
fu_context_get_esp_volumes(FuContext *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
|
||||
FuFirmware *
|
||||
fu_context_get_fdt(FuContext *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
|
||||
FuSmbiosChassisKind
|
||||
fu_context_get_chassis_kind(FuContext *self);
|
||||
|
@ -169,7 +169,7 @@ fu_fdt_firmware_get_image_by_path(FuFdtFirmware *self, const gchar *path, GError
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_fdt_firmware_parse_dt_struct(FuFdtFirmware *self, GBytes *fw, GHashTable *strtab, GError **error)
|
||||
fu_fdt_firmware_parse_dt_struct(FuFdtFirmware *self, GBytes *fw, GBytes *strtab, GError **error)
|
||||
{
|
||||
gsize bufsz = 0;
|
||||
gsize offset = 0;
|
||||
@ -258,8 +258,8 @@ fu_fdt_firmware_parse_dt_struct(FuFdtFirmware *self, GBytes *fw, GHashTable *str
|
||||
if (token == FDT_PROP) {
|
||||
guint32 prop_len = 0;
|
||||
guint32 prop_nameoff = 0;
|
||||
gpointer value = NULL;
|
||||
g_autoptr(GBytes) blob = NULL;
|
||||
g_autoptr(GString) str = NULL;
|
||||
|
||||
/* sanity check */
|
||||
if (firmware_current == FU_FIRMWARE(self)) {
|
||||
@ -288,23 +288,18 @@ fu_fdt_firmware_parse_dt_struct(FuFdtFirmware *self, GBytes *fw, GHashTable *str
|
||||
offset += sizeof(FuFdtProp);
|
||||
|
||||
/* add property */
|
||||
if (!g_hash_table_lookup_extended(strtab,
|
||||
GINT_TO_POINTER(prop_nameoff),
|
||||
NULL,
|
||||
&value)) {
|
||||
g_set_error(error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_DATA,
|
||||
"invalid strtab offset 0x%x",
|
||||
prop_nameoff);
|
||||
str = fu_string_new_safe(g_bytes_get_data(strtab, NULL),
|
||||
g_bytes_get_size(strtab),
|
||||
prop_nameoff,
|
||||
error);
|
||||
if (str == NULL) {
|
||||
g_prefix_error(error, "invalid strtab offset 0x%x: ", prop_nameoff);
|
||||
return FALSE;
|
||||
}
|
||||
blob = fu_bytes_new_offset(fw, offset, prop_len, error);
|
||||
if (blob == NULL)
|
||||
return FALSE;
|
||||
fu_fdt_image_set_attr(FU_FDT_IMAGE(firmware_current),
|
||||
(const gchar *)value,
|
||||
blob);
|
||||
fu_fdt_image_set_attr(FU_FDT_IMAGE(firmware_current), str->str, blob);
|
||||
offset += prop_len;
|
||||
continue;
|
||||
}
|
||||
@ -332,43 +327,6 @@ fu_fdt_firmware_parse_dt_struct(FuFdtFirmware *self, GBytes *fw, GHashTable *str
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_fdt_firmware_parse_dt_strings(FuFdtFirmware *self,
|
||||
GBytes *fw,
|
||||
GHashTable *strtab,
|
||||
GError **error)
|
||||
{
|
||||
gsize bufsz = 0;
|
||||
const guint8 *buf = g_bytes_get_data(fw, &bufsz);
|
||||
|
||||
/* debug */
|
||||
if (g_getenv("FU_FDT_FIRMWARE_VERBOSE") != NULL)
|
||||
fu_dump_bytes(G_LOG_DOMAIN, "dt_strings", fw);
|
||||
|
||||
/* parse */
|
||||
for (gsize offset = 0; offset < bufsz; offset++) {
|
||||
g_autoptr(GString) str = NULL;
|
||||
str = fu_string_new_safe(buf, bufsz, offset, error);
|
||||
if (str == NULL)
|
||||
return FALSE;
|
||||
if (str->len == 0) {
|
||||
g_set_error(error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_DATA,
|
||||
"strtab invalid @0x%x",
|
||||
(guint)offset);
|
||||
return FALSE;
|
||||
}
|
||||
if (g_getenv("FU_FDT_FIRMWARE_VERBOSE") != NULL)
|
||||
g_debug("strtab: %s", str->str);
|
||||
g_hash_table_insert(strtab, GINT_TO_POINTER(offset), g_strdup(str->str));
|
||||
offset += str->len;
|
||||
}
|
||||
|
||||
/* success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_fdt_firmware_parse_mem_rsvmap(FuFdtFirmware *self,
|
||||
const guint8 *buf,
|
||||
@ -451,7 +409,6 @@ fu_fdt_firmware_parse(FuFirmware *firmware,
|
||||
guint32 size_dt_strings = 0;
|
||||
guint32 size_dt_struct = 0;
|
||||
const guint8 *buf = g_bytes_get_data(fw, &bufsz);
|
||||
g_autoptr(GHashTable) strtab = NULL; /* uint:str */
|
||||
|
||||
/* sanity check */
|
||||
if (!fu_memread_uint32_safe(buf,
|
||||
@ -472,8 +429,7 @@ fu_fdt_firmware_parse(FuFirmware *firmware,
|
||||
}
|
||||
fu_firmware_set_size(firmware, totalsize);
|
||||
|
||||
/* read string table */
|
||||
strtab = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free);
|
||||
/* read header */
|
||||
if (!fu_memread_uint32_safe(buf,
|
||||
bufsz,
|
||||
offset + G_STRUCT_OFFSET(FuFdtHeader, off_dt_strings),
|
||||
@ -488,17 +444,6 @@ fu_fdt_firmware_parse(FuFirmware *firmware,
|
||||
G_BIG_ENDIAN,
|
||||
error))
|
||||
return FALSE;
|
||||
if (size_dt_strings != 0x0) {
|
||||
g_autoptr(GBytes) dt_strings = NULL;
|
||||
dt_strings =
|
||||
fu_bytes_new_offset(fw, offset + off_dt_strings, size_dt_strings, error);
|
||||
if (dt_strings == NULL)
|
||||
return FALSE;
|
||||
if (!fu_fdt_firmware_parse_dt_strings(self, dt_strings, strtab, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* read out DT struct */
|
||||
if (!fu_memread_uint32_safe(buf,
|
||||
bufsz,
|
||||
offset + G_STRUCT_OFFSET(FuFdtHeader, off_dt_struct),
|
||||
@ -513,16 +458,6 @@ fu_fdt_firmware_parse(FuFirmware *firmware,
|
||||
G_BIG_ENDIAN,
|
||||
error))
|
||||
return FALSE;
|
||||
if (size_dt_struct != 0x0) {
|
||||
g_autoptr(GBytes) dt_struct = NULL;
|
||||
dt_struct = fu_bytes_new_offset(fw, offset + off_dt_struct, size_dt_struct, error);
|
||||
if (dt_struct == NULL)
|
||||
return FALSE;
|
||||
if (!fu_fdt_firmware_parse_dt_struct(self, dt_struct, strtab, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* read out reserved map */
|
||||
if (!fu_memread_uint32_safe(buf,
|
||||
bufsz,
|
||||
offset + G_STRUCT_OFFSET(FuFdtHeader, off_mem_rsvmap),
|
||||
@ -538,8 +473,6 @@ fu_fdt_firmware_parse(FuFirmware *firmware,
|
||||
error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* read in CPUID */
|
||||
if (!fu_memread_uint32_safe(buf,
|
||||
bufsz,
|
||||
offset + G_STRUCT_OFFSET(FuFdtHeader, boot_cpuid_phys),
|
||||
@ -547,8 +480,6 @@ fu_fdt_firmware_parse(FuFirmware *firmware,
|
||||
G_BIG_ENDIAN,
|
||||
error))
|
||||
return FALSE;
|
||||
|
||||
/* header version */
|
||||
if (!fu_memread_uint32_safe(buf,
|
||||
bufsz,
|
||||
offset + G_STRUCT_OFFSET(FuFdtHeader, last_comp_version),
|
||||
@ -573,6 +504,23 @@ fu_fdt_firmware_parse(FuFirmware *firmware,
|
||||
error))
|
||||
return FALSE;
|
||||
fu_firmware_set_version_raw(firmware, version);
|
||||
|
||||
/* parse device tree struct */
|
||||
if (size_dt_struct != 0x0 && size_dt_strings != 0x0) {
|
||||
g_autoptr(GBytes) dt_strings = NULL;
|
||||
g_autoptr(GBytes) dt_struct = NULL;
|
||||
dt_strings =
|
||||
fu_bytes_new_offset(fw, offset + off_dt_strings, size_dt_strings, error);
|
||||
if (dt_strings == NULL)
|
||||
return FALSE;
|
||||
dt_struct = fu_bytes_new_offset(fw, offset + off_dt_struct, size_dt_struct, error);
|
||||
if (dt_struct == NULL)
|
||||
return FALSE;
|
||||
if (!fu_fdt_firmware_parse_dt_struct(self, dt_struct, dt_strings, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -1392,6 +1392,7 @@ gboolean
|
||||
fu_firmware_write_file(FuFirmware *self, GFile *file, GError **error)
|
||||
{
|
||||
g_autoptr(GBytes) blob = NULL;
|
||||
g_autoptr(GFile) parent = NULL;
|
||||
|
||||
g_return_val_if_fail(FU_IS_FIRMWARE(self), FALSE);
|
||||
g_return_val_if_fail(G_IS_FILE(file), FALSE);
|
||||
@ -1400,6 +1401,11 @@ fu_firmware_write_file(FuFirmware *self, GFile *file, GError **error)
|
||||
blob = fu_firmware_write(self, error);
|
||||
if (blob == NULL)
|
||||
return FALSE;
|
||||
parent = g_file_get_parent(file);
|
||||
if (!g_file_query_exists(parent, NULL)) {
|
||||
if (!g_file_make_directory_with_parents(parent, NULL, error))
|
||||
return FALSE;
|
||||
}
|
||||
return g_file_replace_contents(file,
|
||||
g_bytes_get_data(blob, NULL),
|
||||
g_bytes_get_size(blob),
|
||||
|
@ -13,7 +13,6 @@ G_DECLARE_DERIVABLE_TYPE(FuHidDevice, fu_hid_device, FU, HID_DEVICE, FuUsbDevice
|
||||
|
||||
struct _FuHidDeviceClass {
|
||||
FuUsbDeviceClass parent_class;
|
||||
gpointer __reserved[31];
|
||||
};
|
||||
|
||||
/**
|
||||
|
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;
|
||||
}
|
94
libfwupdplugin/fu-hwids-fdt.c
Normal file
94
libfwupdplugin/fu-hwids-fdt.c
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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_autofree gchar *chassis_type = NULL;
|
||||
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);
|
||||
}
|
||||
|
||||
/* chassis kind */
|
||||
fu_fdt_image_get_attr_str(FU_FDT_IMAGE(fdt_img), "chassis-type", &chassis_type, NULL);
|
||||
if (chassis_type != NULL) {
|
||||
struct {
|
||||
FuSmbiosChassisKind chassis_kind;
|
||||
const gchar *dt;
|
||||
} chassis_map[] = {{FU_SMBIOS_CHASSIS_KIND_CONVERTIBLE, "convertible"},
|
||||
{FU_SMBIOS_CHASSIS_KIND_EMBEDDED_PC, "embedded"},
|
||||
{FU_SMBIOS_CHASSIS_KIND_HAND_HELD, "handset"},
|
||||
{FU_SMBIOS_CHASSIS_KIND_LAPTOP, "laptop"},
|
||||
{FU_SMBIOS_CHASSIS_KIND_TABLET, "tablet"},
|
||||
{FU_SMBIOS_CHASSIS_KIND_UNKNOWN, NULL}};
|
||||
for (guint i = 0; chassis_map[i].dt != NULL; i++) {
|
||||
if (g_strcmp0(chassis_type, chassis_map[i].dt) == 0) {
|
||||
fu_context_set_chassis_kind(ctx, chassis_map[i].chassis_kind);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
@ -13,7 +13,6 @@ G_DECLARE_DERIVABLE_TYPE(FuI2cDevice, fu_i2c_device, FU, I2C_DEVICE, FuUdevDevic
|
||||
|
||||
struct _FuI2cDeviceClass {
|
||||
FuUdevDeviceClass parent_class;
|
||||
gpointer __reserved[31];
|
||||
};
|
||||
|
||||
guint
|
||||
|
@ -13,7 +13,6 @@ G_DECLARE_DERIVABLE_TYPE(FuMeiDevice, fu_mei_device, FU, MEI_DEVICE, FuUdevDevic
|
||||
|
||||
struct _FuMeiDeviceClass {
|
||||
FuUdevDeviceClass parent_class;
|
||||
gpointer __reserved[31];
|
||||
};
|
||||
|
||||
gboolean
|
||||
|
@ -292,6 +292,12 @@ fu_path_from_kind(FuPathKind path_kind)
|
||||
if (tmp != NULL)
|
||||
return g_strdup(tmp);
|
||||
return g_strdup("/sys/kernel/security");
|
||||
/* /sys/class/dmi/id */
|
||||
case FU_PATH_KIND_SYSFSDIR_DMI:
|
||||
tmp = g_getenv("FWUPD_SYSFSDMIDIR");
|
||||
if (tmp != NULL)
|
||||
return g_strdup(tmp);
|
||||
return g_strdup("/sys/class/dmi/id");
|
||||
/* /sys/firmware/acpi/tables */
|
||||
case FU_PATH_KIND_ACPI_TABLES:
|
||||
tmp = g_getenv("FWUPD_ACPITABLESDIR");
|
||||
|
@ -44,6 +44,7 @@
|
||||
* /var/lib/fwupd/remotes.d)
|
||||
* @FU_PATH_KIND_WIN32_BASEDIR: The root of the install directory on Windows
|
||||
* @FU_PATH_KIND_LOCALCONFDIR_PKG: The package configuration override (IE /var/etc/fwupd)
|
||||
* @FU_PATH_KIND_SYSFSDIR_DMI: The sysfs DMI location, (IE /sys/class/dmi/id)
|
||||
*
|
||||
* Path types to use when dynamically determining a path at runtime
|
||||
**/
|
||||
@ -73,6 +74,7 @@ typedef enum {
|
||||
FU_PATH_KIND_LOCALSTATEDIR_REMOTES,
|
||||
FU_PATH_KIND_WIN32_BASEDIR,
|
||||
FU_PATH_KIND_LOCALCONFDIR_PKG,
|
||||
FU_PATH_KIND_SYSFSDIR_DMI,
|
||||
/*< private >*/
|
||||
FU_PATH_KIND_LAST
|
||||
} FuPathKind;
|
||||
|
212
libfwupdplugin/fu-pefile-firmware.c
Normal file
212
libfwupdplugin/fu-pefile-firmware.c
Normal file
@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "FuFirmware"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "fu-bytes.h"
|
||||
#include "fu-coswid-firmware.h"
|
||||
#include "fu-dump.h"
|
||||
#include "fu-mem.h"
|
||||
#include "fu-pefile-firmware.h"
|
||||
#include "fu-string.h"
|
||||
|
||||
/**
|
||||
* FuPefileFirmware:
|
||||
*
|
||||
* A PE file consists of a Microsoft MS-DOS stub, the PE signature, the COFF file header, and an
|
||||
* optional header, followed by section data.
|
||||
*
|
||||
* Documented:
|
||||
* https://learn.microsoft.com/en-gb/windows/win32/debug/pe-format
|
||||
*/
|
||||
|
||||
G_DEFINE_TYPE(FuPefileFirmware, fu_pefile_firmware, FU_TYPE_FIRMWARE)
|
||||
|
||||
static gboolean
|
||||
fu_pefile_firmware_check_magic(FuFirmware *firmware, GBytes *fw, gsize offset, GError **error)
|
||||
{
|
||||
guint16 magic = 0x0;
|
||||
|
||||
if (!fu_memread_uint16_safe(g_bytes_get_data(fw, NULL),
|
||||
g_bytes_get_size(fw),
|
||||
offset,
|
||||
&magic,
|
||||
G_LITTLE_ENDIAN,
|
||||
error)) {
|
||||
g_prefix_error(error, "failed to read magic: ");
|
||||
return FALSE;
|
||||
}
|
||||
if (magic != 0x5A4D) {
|
||||
g_set_error_literal(error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_INVALID_FILE,
|
||||
"invalid magic for file");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_pefile_firmware_parse(FuFirmware *firmware,
|
||||
GBytes *fw,
|
||||
gsize offset,
|
||||
FwupdInstallFlags flags,
|
||||
GError **error)
|
||||
{
|
||||
gsize bufsz = 0;
|
||||
gsize hdr_offset = offset;
|
||||
guint16 opt_hdrsz = 0x0;
|
||||
guint32 nr_sections = 0x0;
|
||||
guint32 offset_sig = 0x0;
|
||||
guint32 signature = 0x0;
|
||||
const guint8 *buf = g_bytes_get_data(fw, &bufsz);
|
||||
|
||||
/* we already checked the MS-DOS magic, check the signature now */
|
||||
if (!fu_memread_uint32_safe(buf,
|
||||
bufsz,
|
||||
hdr_offset + 0x3C,
|
||||
&offset_sig,
|
||||
G_LITTLE_ENDIAN,
|
||||
error))
|
||||
return FALSE;
|
||||
hdr_offset += offset_sig;
|
||||
if (!fu_memread_uint32_safe(buf, bufsz, hdr_offset, &signature, G_LITTLE_ENDIAN, error))
|
||||
return FALSE;
|
||||
if (signature != 0x4550) {
|
||||
g_set_error_literal(error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_INVALID_FILE,
|
||||
"invalid signature for file");
|
||||
return FALSE;
|
||||
}
|
||||
hdr_offset += 4;
|
||||
|
||||
/* read number of sections */
|
||||
if (!fu_memread_uint32_safe(buf,
|
||||
bufsz,
|
||||
hdr_offset + 0x02,
|
||||
&nr_sections,
|
||||
G_LITTLE_ENDIAN,
|
||||
error))
|
||||
return FALSE;
|
||||
if (nr_sections == 0) {
|
||||
g_set_error_literal(error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_INVALID_FILE,
|
||||
"invalid number of sections");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* read optional extra header size */
|
||||
if (!fu_memread_uint16_safe(buf,
|
||||
bufsz,
|
||||
hdr_offset + 0x10,
|
||||
&opt_hdrsz,
|
||||
G_LITTLE_ENDIAN,
|
||||
error))
|
||||
return FALSE;
|
||||
hdr_offset += 0x14 + opt_hdrsz;
|
||||
|
||||
/* read out COFF header */
|
||||
for (guint idx = 0; idx < nr_sections; idx++) {
|
||||
guint32 sect_length = 0x0;
|
||||
guint32 sect_offset = 0x0;
|
||||
guint8 name[8] = {0x0};
|
||||
g_autofree gchar *sect_id = NULL;
|
||||
g_autoptr(FuFirmware) fw_sect = NULL;
|
||||
g_autoptr(GBytes) sect_blob = NULL;
|
||||
|
||||
/* read the section name */
|
||||
if (!fu_memcpy_safe(name,
|
||||
sizeof(name),
|
||||
0x0,
|
||||
buf,
|
||||
bufsz,
|
||||
hdr_offset,
|
||||
sizeof(name),
|
||||
error))
|
||||
return FALSE;
|
||||
sect_id = fu_strsafe((const gchar *)name, sizeof(name));
|
||||
if (sect_id == NULL) {
|
||||
g_set_error_literal(error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_INVALID_FILE,
|
||||
"no section name");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* create new firmware */
|
||||
if (g_strcmp0(sect_id, ".sbom") == 0) {
|
||||
fw_sect = fu_coswid_firmware_new();
|
||||
} else {
|
||||
fw_sect = fu_firmware_new();
|
||||
}
|
||||
fu_firmware_set_idx(fw_sect, idx);
|
||||
fu_firmware_set_id(fw_sect, sect_id);
|
||||
|
||||
/* add data */
|
||||
if (!fu_memread_uint32_safe(buf,
|
||||
bufsz,
|
||||
hdr_offset + 0x08,
|
||||
§_length,
|
||||
G_LITTLE_ENDIAN,
|
||||
error))
|
||||
return FALSE;
|
||||
fu_firmware_set_size(fw_sect, sect_length);
|
||||
if (!fu_memread_uint32_safe(buf,
|
||||
bufsz,
|
||||
hdr_offset + 0x14,
|
||||
§_offset,
|
||||
G_LITTLE_ENDIAN,
|
||||
error))
|
||||
return FALSE;
|
||||
fu_firmware_set_offset(fw_sect, sect_offset);
|
||||
sect_blob = fu_bytes_new_offset(fw, sect_offset, sect_length, error);
|
||||
if (sect_blob == NULL) {
|
||||
g_prefix_error(error, "failed to get raw data for %s: ", sect_id);
|
||||
return FALSE;
|
||||
}
|
||||
if (!fu_firmware_parse(fw_sect, sect_blob, flags, error))
|
||||
return FALSE;
|
||||
fu_firmware_add_image(firmware, fw_sect);
|
||||
|
||||
/* next! */
|
||||
hdr_offset += 0x28;
|
||||
}
|
||||
|
||||
/* success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
fu_pefile_firmware_init(FuPefileFirmware *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
fu_pefile_firmware_class_init(FuPefileFirmwareClass *klass)
|
||||
{
|
||||
FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS(klass);
|
||||
klass_firmware->check_magic = fu_pefile_firmware_check_magic;
|
||||
klass_firmware->parse = fu_pefile_firmware_parse;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_pefile_firmware_new:
|
||||
*
|
||||
* Creates a new #FuPefileFirmware
|
||||
*
|
||||
* Since: 1.8.10
|
||||
**/
|
||||
FuFirmware *
|
||||
fu_pefile_firmware_new(void)
|
||||
{
|
||||
return FU_FIRMWARE(g_object_new(FU_TYPE_PEFILE_FIRMWARE, NULL));
|
||||
}
|
19
libfwupdplugin/fu-pefile-firmware.h
Normal file
19
libfwupdplugin/fu-pefile-firmware.h
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fu-firmware.h"
|
||||
|
||||
#define FU_TYPE_PEFILE_FIRMWARE (fu_pefile_firmware_get_type())
|
||||
G_DECLARE_DERIVABLE_TYPE(FuPefileFirmware, fu_pefile_firmware, FU, PEFILE_FIRMWARE, FuFirmware)
|
||||
|
||||
struct _FuPefileFirmwareClass {
|
||||
FuFirmwareClass parent_class;
|
||||
};
|
||||
|
||||
FuFirmware *
|
||||
fu_pefile_firmware_new(void);
|
@ -891,16 +891,33 @@ fu_plugin_runner_startup(FuPlugin *self, FuProgress *progress, GError **error)
|
||||
/* ensure the configure file is set to the correct permission */
|
||||
if (fu_plugin_has_flag(self, FWUPD_PLUGIN_FLAG_SECURE_CONFIG)) {
|
||||
if (g_file_test(config_filename, G_FILE_TEST_EXISTS)) {
|
||||
gint rc = g_chmod(config_filename, FU_PLUGIN_FILE_MODE_SECURE);
|
||||
GStatBuf st = {0x0};
|
||||
gint rc = g_stat(config_filename, &st);
|
||||
if (rc != 0) {
|
||||
g_set_error(error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"failed to change permission of %s",
|
||||
"failed to get permission of %s",
|
||||
config_filename);
|
||||
fu_plugin_add_flag(self, FWUPD_PLUGIN_FLAG_FAILED_OPEN);
|
||||
return FALSE;
|
||||
}
|
||||
st.st_mode &= 0777;
|
||||
if (st.st_mode != FU_PLUGIN_FILE_MODE_SECURE) {
|
||||
g_debug("mode was 0%o, and needs to be 0%o",
|
||||
st.st_mode,
|
||||
(guint)FU_PLUGIN_FILE_MODE_SECURE);
|
||||
rc = g_chmod(config_filename, FU_PLUGIN_FILE_MODE_SECURE);
|
||||
if (rc != 0) {
|
||||
g_set_error(error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"failed to change permission of %s",
|
||||
config_filename);
|
||||
fu_plugin_add_flag(self, FWUPD_PLUGIN_FLAG_FAILED_OPEN);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,39 @@ fu_smbios3_func(void)
|
||||
}
|
||||
|
||||
static void
|
||||
fu_smbios_dt_func(void)
|
||||
fu_context_flags_func(void)
|
||||
{
|
||||
const gchar *str;
|
||||
gboolean ret;
|
||||
g_autofree gchar *path = NULL;
|
||||
g_autoptr(FuSmbios) smbios = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(FuContext) ctx = fu_context_new();
|
||||
|
||||
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);
|
||||
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, ==, "Hughski Limited");
|
||||
g_assert_false(fu_context_has_flag(ctx, FU_CONTEXT_FLAG_SAVE_EVENTS));
|
||||
fu_context_add_flag(ctx, FU_CONTEXT_FLAG_SAVE_EVENTS);
|
||||
g_assert_true(fu_context_has_flag(ctx, FU_CONTEXT_FLAG_SAVE_EVENTS));
|
||||
fu_context_remove_flag(ctx, FU_CONTEXT_FLAG_SAVE_EVENTS);
|
||||
fu_context_remove_flag(ctx, FU_CONTEXT_FLAG_SAVE_EVENTS);
|
||||
g_assert_false(fu_context_has_flag(ctx, FU_CONTEXT_FLAG_SAVE_EVENTS));
|
||||
fu_context_add_flag(ctx, FU_CONTEXT_FLAG_SAVE_EVENTS);
|
||||
fu_context_add_flag(ctx, FU_CONTEXT_FLAG_SAVE_EVENTS);
|
||||
g_assert_true(fu_context_has_flag(ctx, FU_CONTEXT_FLAG_SAVE_EVENTS));
|
||||
}
|
||||
|
||||
static void
|
||||
fu_smbios_dt_fallback_func(void)
|
||||
fu_context_hwids_dmi_func(void)
|
||||
{
|
||||
const gchar *str;
|
||||
gboolean ret;
|
||||
g_autofree gchar *path = NULL;
|
||||
g_autoptr(FuSmbios) smbios = fu_smbios_new();
|
||||
g_autoptr(FuContext) ctx = fu_context_new();
|
||||
g_autoptr(GError) error = NULL;
|
||||
gboolean ret;
|
||||
|
||||
path = g_test_build_filename(G_TEST_DIST, "tests", "devicetree-fallback", "base", NULL);
|
||||
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, ==, "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 +558,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 +592,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
|
||||
@ -838,6 +798,47 @@ fu_plugin_delay_func(void)
|
||||
g_clear_object(&device_tmp);
|
||||
}
|
||||
|
||||
static void
|
||||
fu_plugin_fdt_func(void)
|
||||
{
|
||||
gboolean ret;
|
||||
g_autofree gchar *compatible = NULL;
|
||||
g_autoptr(FuContext) ctx = fu_context_new();
|
||||
g_autoptr(FuFirmware) fdt = NULL;
|
||||
g_autoptr(FuFirmware) fdt_root = NULL;
|
||||
g_autoptr(FuFirmware) fdt_tmp = fu_fdt_firmware_new();
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GFile) file =
|
||||
g_file_new_for_path("/tmp/fwupd-self-test/var/lib/fwupd/system.dtb");
|
||||
|
||||
/* write file */
|
||||
ret = fu_firmware_build_from_xml(
|
||||
FU_FIRMWARE(fdt_tmp),
|
||||
"<firmware gtype=\"FuFdtFirmware\">\n"
|
||||
" <firmware gtype=\"FuFdtImage\">\n"
|
||||
" <metadata key=\"compatible\" format=\"str\">pine64,rockpro64-v2.1</metadata>\n"
|
||||
" </firmware>\n"
|
||||
"</firmware>\n",
|
||||
&error);
|
||||
g_assert_no_error(error);
|
||||
g_assert_true(ret);
|
||||
ret = fu_firmware_write_file(FU_FIRMWARE(fdt_tmp), file, &error);
|
||||
g_assert_no_error(error);
|
||||
g_assert_true(ret);
|
||||
|
||||
/* get compatible from the context */
|
||||
fdt = fu_context_get_fdt(ctx, &error);
|
||||
g_assert_no_error(error);
|
||||
g_assert_nonnull(fdt);
|
||||
fdt_root = fu_firmware_get_image_by_id(fdt, NULL, &error);
|
||||
g_assert_no_error(error);
|
||||
g_assert_nonnull(fdt_root);
|
||||
ret = fu_fdt_image_get_attr_str(FU_FDT_IMAGE(fdt_root), "compatible", &compatible, &error);
|
||||
g_assert_no_error(error);
|
||||
g_assert_true(ret);
|
||||
g_assert_cmpstr(compatible, ==, "pine64,rockpro64-v2.1");
|
||||
}
|
||||
|
||||
static void
|
||||
fu_plugin_quirks_func(void)
|
||||
{
|
||||
@ -3759,6 +3760,8 @@ 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);
|
||||
(void)g_setenv("FWUPD_PROFILE", "1", TRUE);
|
||||
@ -3780,6 +3783,7 @@ main(int argc, char **argv)
|
||||
fu_plugin_device_inhibit_children_func);
|
||||
g_test_add_func("/fwupd/plugin{delay}", fu_plugin_delay_func);
|
||||
g_test_add_func("/fwupd/plugin{quirks}", fu_plugin_quirks_func);
|
||||
g_test_add_func("/fwupd/plugin{fdt}", fu_plugin_fdt_func);
|
||||
g_test_add_func("/fwupd/plugin{quirks-performance}", fu_plugin_quirks_performance_func);
|
||||
g_test_add_func("/fwupd/plugin{quirks-device}", fu_plugin_quirks_device_func);
|
||||
g_test_add_func("/fwupd/backend", fu_backend_func);
|
||||
@ -3802,11 +3806,10 @@ 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{flags}", fu_context_flags_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
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,6 @@ G_DECLARE_DERIVABLE_TYPE(FuUdevDevice, fu_udev_device, FU, UDEV_DEVICE, FuDevice
|
||||
|
||||
struct _FuUdevDeviceClass {
|
||||
FuDeviceClass parent_class;
|
||||
gpointer __reserved[31];
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -24,7 +24,6 @@ G_DECLARE_DERIVABLE_TYPE(FuUsbDevice, fu_usb_device, FU, USB_DEVICE, FuDevice)
|
||||
|
||||
struct _FuUsbDeviceClass {
|
||||
FuDeviceClass parent_class;
|
||||
gpointer __reserved[31];
|
||||
};
|
||||
|
||||
FuUsbDevice *
|
||||
|
@ -319,6 +319,7 @@ fu_uswid_firmware_init(FuUswidFirmware *self)
|
||||
priv->hdrver = USWID_HEADER_VERSION_V1;
|
||||
priv->compressed = FALSE;
|
||||
fu_firmware_add_flag(FU_FIRMWARE(self), FU_FIRMWARE_FLAG_HAS_STORED_SIZE);
|
||||
fu_firmware_add_flag(FU_FIRMWARE(self), FU_FIRMWARE_FLAG_ALWAYS_SEARCH);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -725,6 +725,10 @@ fu_volume_new_esp_for_path(const gchar *esp_path, GError **error)
|
||||
if (g_strcmp0(basename, vol_basename) == 0)
|
||||
return g_object_ref(vol);
|
||||
}
|
||||
if (g_file_test(esp_path, G_FILE_TEST_IS_DIR)) {
|
||||
g_debug("Using user requested path %s for ESP", esp_path);
|
||||
return fu_volume_new_from_mount_path(esp_path);
|
||||
}
|
||||
g_set_error(error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_FILENAME,
|
||||
|
@ -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>
|
||||
@ -61,11 +62,13 @@
|
||||
#include <libfwupdplugin/fu-mem.h>
|
||||
#include <libfwupdplugin/fu-oprom-firmware.h>
|
||||
#include <libfwupdplugin/fu-path.h>
|
||||
#include <libfwupdplugin/fu-pefile-firmware.h>
|
||||
#include <libfwupdplugin/fu-plugin-vfuncs.h>
|
||||
#include <libfwupdplugin/fu-plugin.h>
|
||||
#include <libfwupdplugin/fu-progress.h>
|
||||
#include <libfwupdplugin/fu-security-attr.h>
|
||||
#include <libfwupdplugin/fu-security-attrs.h>
|
||||
#include <libfwupdplugin/fu-smbios.h>
|
||||
#include <libfwupdplugin/fu-srec-firmware.h>
|
||||
#include <libfwupdplugin/fu-string.h>
|
||||
#include <libfwupdplugin/fu-sum.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;
|
||||
@ -603,7 +600,6 @@ LIBFWUPDPLUGIN_1.6.0 {
|
||||
fu_context_get_type;
|
||||
fu_context_get_udev_subsystems;
|
||||
fu_context_has_hwid_guid;
|
||||
fu_context_load_hwinfo;
|
||||
fu_context_load_quirks;
|
||||
fu_context_lookup_quirk_by_id;
|
||||
fu_context_lookup_quirk_by_id_iter;
|
||||
@ -720,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: *;
|
||||
@ -1151,3 +1146,19 @@ LIBFWUPDPLUGIN_1.8.9 {
|
||||
fu_version_from_uint24;
|
||||
local: *;
|
||||
} LIBFWUPDPLUGIN_1.8.7;
|
||||
|
||||
LIBFWUPDPLUGIN_1.8.10 {
|
||||
global:
|
||||
fu_context_get_chassis_kind;
|
||||
fu_context_get_fdt;
|
||||
fu_context_get_hwids;
|
||||
fu_context_get_smbios;
|
||||
fu_context_load_hwinfo;
|
||||
fu_context_remove_flag;
|
||||
fu_context_set_chassis_kind;
|
||||
fu_hwids_add_guid;
|
||||
fu_hwids_add_value;
|
||||
fu_pefile_firmware_get_type;
|
||||
fu_pefile_firmware_new;
|
||||
local: *;
|
||||
} LIBFWUPDPLUGIN_1.8.9;
|
||||
|
@ -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',
|
||||
@ -74,6 +79,7 @@ fwupdplugin_src = [
|
||||
'fu-uswid-firmware.c', # fuzzing
|
||||
'fu-coswid-common.c', # fuzzing
|
||||
'fu-coswid-firmware.c', # fuzzing
|
||||
'fu-pefile-firmware.c', # fuzzing
|
||||
'fu-efivar.c',
|
||||
'fu-udev-device.c',
|
||||
'fu-i2c-device.c',
|
||||
@ -149,6 +155,7 @@ fwupdplugin_headers = [
|
||||
'fu-ifd-firmware.h',
|
||||
'fu-uswid-firmware.h',
|
||||
'fu-coswid-firmware.h',
|
||||
'fu-pefile-firmware.h',
|
||||
'fu-ifd-image.h',
|
||||
'fu-linear-firmware.h',
|
||||
'fu-volume.h',
|
||||
@ -359,6 +366,25 @@ if get_option('tests')
|
||||
],
|
||||
)
|
||||
test('fwupdplugin-self-test', e, is_parallel: false, timeout: 180, env: env)
|
||||
|
||||
install_data([
|
||||
'tests/chassis_type',
|
||||
'tests/sys_vendor',
|
||||
],
|
||||
install_dir: installed_test_datadir,
|
||||
)
|
||||
install_data([
|
||||
'tests/dmi/tables/DMI',
|
||||
'tests/dmi/tables/smbios_entry_point',
|
||||
],
|
||||
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, 'tests/dmi/tables64'),
|
||||
)
|
||||
endif
|
||||
|
||||
fwupdplugin_incdir = include_directories('.')
|
||||
|
@ -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.
15
meson.build
15
meson.build
@ -1,5 +1,5 @@
|
||||
project('fwupd', 'c',
|
||||
version: '1.8.9',
|
||||
version: '1.8.10',
|
||||
license: 'LGPL-2.1+',
|
||||
meson_version: '>=0.61.0',
|
||||
default_options: ['warning_level=2', 'c_std=c11'],
|
||||
@ -219,7 +219,7 @@ hsi = get_option('hsi').disable_auto_if(host_machine.system() != 'linux').disabl
|
||||
if hsi
|
||||
conf.set('HAVE_HSI', '1')
|
||||
endif
|
||||
libxmlb = dependency('xmlb', version: '>= 0.1.13', fallback: ['libxmlb', 'libxmlb_dep'])
|
||||
libxmlb = dependency('xmlb', version: '>= 0.1.15', fallback: ['libxmlb', 'libxmlb_dep'])
|
||||
gusb = dependency('gusb', version: '>= 0.3.0', fallback: ['gusb', 'gusb_dep'], required: get_option('gusb'))
|
||||
if gusb.found()
|
||||
conf.set('HAVE_GUSB', '1')
|
||||
@ -267,8 +267,13 @@ if build_daemon
|
||||
endif
|
||||
libm = cc.find_library('m', required: false)
|
||||
libgcab = dependency('libgcab-1.0', version: '>= 1.0', fallback: ['gcab', 'gcab_dep'])
|
||||
if libgcab.type_name() == 'pkgconfig' and cc.has_function('gcab_file_set_bytes', dependencies: libgcab)
|
||||
conf.set('HAVE_GCAB_FILE_SET_BYTES', '1')
|
||||
if libgcab.type_name() == 'pkgconfig'
|
||||
if cc.has_function('gcab_file_set_bytes', dependencies: libgcab)
|
||||
conf.set('HAVE_GCAB_FILE_SET_BYTES', '1')
|
||||
endif
|
||||
if cc.has_function('gcab_cabinet_add_allowed_compression', dependencies: libgcab)
|
||||
conf.set('HAVE_GCAB_CABINET_ADD_ALLOWED_COMPRESSION', '1')
|
||||
endif
|
||||
endif
|
||||
|
||||
bashcomp = dependency('bash-completion', required: false)
|
||||
@ -608,7 +613,7 @@ custom_target('builtin-quirk-gz',
|
||||
install_dir: join_paths(datadir, 'fwupd', 'quirks.d'),
|
||||
)
|
||||
|
||||
if build_daemon and libsystemd.found()
|
||||
if build_daemon and libsystemd.found() and offline.allowed()
|
||||
install_symlink('fwupd-offline-update.service',
|
||||
install_dir: join_paths(systemdunitdir, 'system-update.target.wants'),
|
||||
pointing_to: join_paths('..', 'fwupd-offline-update.service')
|
||||
|
@ -1,4 +1,6 @@
|
||||
# DMA Protection
|
||||
---
|
||||
title: Plugin: ACPI DMAR — DMA Protection
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
# ACPI FACP
|
||||
---
|
||||
title: Plugin: ACPI FACP — Fixed ACPI Description Table
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
# DMA Protection
|
||||
---
|
||||
title: Plugin: ACPI IVRS — DMA Protection
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
# Platform Health Assessment Table
|
||||
---
|
||||
title: Plugin: ACPI PHAT — Platform Health Assessment Table
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
# AMD PMC
|
||||
---
|
||||
title: Plugin: AMD PMC
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
# Analogix
|
||||
---
|
||||
title: Plugin: Analogix
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
@ -15,7 +17,7 @@ a Intel Hex file format. The resulting binary image is either:
|
||||
|
||||
This plugin supports the following protocol ID:
|
||||
|
||||
* com.analogix.bb
|
||||
* `com.analogix.bb`
|
||||
|
||||
## GUID Generation
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
# Android Bootloaders
|
||||
---
|
||||
title: Plugin: Android Boot
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
@ -13,7 +15,7 @@ to flash from the device itself rather than external device.
|
||||
|
||||
This plugin supports the following protocol ID:
|
||||
|
||||
* com.google.android_boot
|
||||
* `com.google.android_boot`
|
||||
|
||||
## GUID Generation
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
# ATA
|
||||
---
|
||||
title: Plugin: ATA
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
@ -18,7 +20,7 @@ an unspecified binary file format.
|
||||
|
||||
This plugin supports the following protocol ID:
|
||||
|
||||
* org.t13.ata
|
||||
* `org.t13.ata`
|
||||
|
||||
## GUID Generation
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
# BCM57xx
|
||||
---
|
||||
title: Plugin: BCM57xx
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
|
11
plugins/bios/README.md
Normal file
11
plugins/bios/README.md
Normal file
@ -0,0 +1,11 @@
|
||||
---
|
||||
title: Plugin: BIOS
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
This plugin checks UEFI capsules are available, and if missing a HSI failure is reported.
|
||||
|
||||
## External Interface Access
|
||||
|
||||
This plugin requires read only access to attributes located within `/sys/firmware/efi/esrt`.
|
@ -1,4 +1,6 @@
|
||||
# Infineon Technologies
|
||||
---
|
||||
title: Plugin: CCGX
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
@ -9,10 +11,10 @@ controller family of devices used in docks.
|
||||
|
||||
This plugin supports the following protocol IDs:
|
||||
|
||||
* com.cypress.ccgx
|
||||
* com.cypress.ccgx.dmc
|
||||
* com.infineon.ccgx
|
||||
* com.infineon.ccgx.dmc
|
||||
* `com.cypress.ccgx` (deprecated)
|
||||
* `com.cypress.ccgx.dmc` (deprecated)
|
||||
* `com.infineon.ccgx`
|
||||
* `com.infineon.ccgx.dmc`
|
||||
|
||||
## Device Flash
|
||||
|
||||
@ -101,7 +103,7 @@ The vendor ID is set from the USB vendor, for example set to `USB:0x04B4`
|
||||
|
||||
This plugin uses the following plugin-specific quirks:
|
||||
|
||||
### Trigger Code
|
||||
### CcgxDmcTriggerCode
|
||||
|
||||
DMC devices need a specified trigger code to request the device to update
|
||||
the firmware and the trigger code depends on the devices.
|
||||
|
@ -1,4 +1,6 @@
|
||||
# Component Firmware update
|
||||
---
|
||||
title: Plugin: CFU - Component Firmware Update
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
@ -13,7 +15,7 @@ details.
|
||||
|
||||
This plugin supports the following protocol ID:
|
||||
|
||||
* com.microsoft.cfu
|
||||
* `com.microsoft.cfu`
|
||||
|
||||
## GUID Generation
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
# CH341A
|
||||
---
|
||||
title: Plugin: CH341A
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
@ -22,7 +24,7 @@ The daemon will decompress the cabinet archive and extract a firmware blob of un
|
||||
|
||||
This plugin supports the following protocol ID:
|
||||
|
||||
- com.winchiphead.ch341a
|
||||
- `com.winchiphead.ch341a`
|
||||
|
||||
## GUID Generation
|
||||
|
||||
|
@ -106,14 +106,17 @@ fu_ch341a_cfi_device_read_jedec(FuCh341aCfiDevice *self, GError **error)
|
||||
g_set_error_literal(error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_NOT_SUPPORTED,
|
||||
"flash ID non-valid");
|
||||
"flash ID non-valid, got 0x000000");
|
||||
return FALSE;
|
||||
}
|
||||
if (buf[1] == 0xFF && buf[2] == 0xFF && buf[3] == 0xFF) {
|
||||
g_set_error_literal(error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_NOT_SUPPORTED,
|
||||
"device not detected");
|
||||
g_set_error(error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_NOT_SUPPORTED,
|
||||
"device not detected, flash ID 0x%02X%02X%02X",
|
||||
buf[1],
|
||||
buf[2],
|
||||
buf[3]);
|
||||
return FALSE;
|
||||
}
|
||||
g_string_append_printf(flash_id, "%02X", buf[1]);
|
||||
@ -426,6 +429,7 @@ fu_ch341a_cfi_device_init(FuCh341aCfiDevice *self)
|
||||
fu_device_add_protocol(FU_DEVICE(self), "org.jedec.cfi");
|
||||
fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_UPDATABLE);
|
||||
fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_UNSIGNED_PAYLOAD);
|
||||
fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1,4 +1,6 @@
|
||||
# ColorHug
|
||||
---
|
||||
title: Plugin: ColorHug
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
@ -16,7 +18,7 @@ a packed binary file format.
|
||||
|
||||
This plugin supports the following protocol ID:
|
||||
|
||||
* com.hughski.colorhug
|
||||
* `com.hughski.colorhug`
|
||||
|
||||
## GUID Generation
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
# Corsair
|
||||
---
|
||||
title: Plugin: Corsair
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
# CPU Microcode
|
||||
---
|
||||
title: Plugin: CPU Microcode
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
# Chrome OS EC
|
||||
---
|
||||
title: Plugin: Chrome OS EC
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
@ -19,7 +21,7 @@ the Google [fmap file format](https://www.chromium.org/chromium-os/firmware-port
|
||||
|
||||
This plugin supports the following protocol ID:
|
||||
|
||||
* com.google.usb.crosec
|
||||
* `com.google.usb.crosec`
|
||||
|
||||
## GUID Generation
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
# Dell USB-C Dock
|
||||
---
|
||||
title: Plugin: Dell USB-C Dock
|
||||
---
|
||||
|
||||
## Dell System
|
||||
|
||||
@ -35,8 +37,8 @@ blobs with an unspecified binary file format.
|
||||
|
||||
This plugin supports the following protocol ID:
|
||||
|
||||
* com.dell.dock
|
||||
* com.synaptics.mst
|
||||
* `com.dell.dock`
|
||||
* `com.synaptics.mst`
|
||||
|
||||
## GUID Generation
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
# Dell ESRT Support
|
||||
---
|
||||
title: Plugin: Dell ESRT
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
# Dell Support
|
||||
---
|
||||
title: Plugin: Dell
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
|
@ -147,9 +147,9 @@ static gboolean
|
||||
fu_dell_supported(FuPlugin *plugin, GError **error)
|
||||
{
|
||||
FuContext *ctx = fu_plugin_get_context(plugin);
|
||||
FuSmbiosChassisKind chassis_kind = fu_context_get_chassis_kind(ctx);
|
||||
g_autoptr(GBytes) de_table = NULL;
|
||||
g_autoptr(GBytes) da_table = NULL;
|
||||
g_autoptr(GBytes) enclosure = NULL;
|
||||
guint8 value = 0;
|
||||
struct da_structure da_values = {0x0};
|
||||
|
||||
@ -194,19 +194,8 @@ fu_dell_supported(FuPlugin *plugin, GError **error)
|
||||
}
|
||||
|
||||
/* only run on intended Dell hw types */
|
||||
enclosure = fu_context_get_smbios_data(ctx, FU_SMBIOS_STRUCTURE_TYPE_CHASSIS, error);
|
||||
if (enclosure == NULL)
|
||||
return FALSE;
|
||||
if (!fu_memread_uint8_safe(g_bytes_get_data(enclosure, NULL),
|
||||
g_bytes_get_size(enclosure),
|
||||
0x0,
|
||||
&value,
|
||||
error)) {
|
||||
g_prefix_error(error, "invalid enclosure data: ");
|
||||
return FALSE;
|
||||
}
|
||||
for (guint i = 0; i < G_N_ELEMENTS(enclosure_allowlist); i++) {
|
||||
if (enclosure_allowlist[i] == value)
|
||||
if (enclosure_allowlist[i] == chassis_kind)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
# DFU CSR
|
||||
---
|
||||
title: Plugin: DFU CSR — Cambridge Silicon Radio
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
@ -21,7 +23,7 @@ DFU file format.
|
||||
|
||||
This plugin supports the following protocol ID:
|
||||
|
||||
* com.qualcomm.dfu
|
||||
* `com.qualcomm.dfu`
|
||||
|
||||
## GUID Generation
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
# DFU
|
||||
---
|
||||
title: Plugin: DFU
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
@ -12,8 +14,8 @@ DFU or DfuSe file format.
|
||||
|
||||
This plugin supports the following protocol IDs:
|
||||
|
||||
* org.usb.dfu
|
||||
* com.st.dfuse
|
||||
* `org.usb.dfu`
|
||||
* `com.st.dfuse`
|
||||
|
||||
## GUID Generation
|
||||
|
||||
@ -32,6 +34,42 @@ the device again re-enumerates back to the runtime mode.
|
||||
For this reason the `REPLUG_MATCH_GUID` internal device flag is used so that
|
||||
the bootloader and runtime modes are treated as the same device.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The runtime mode is just as important as the DFU mode from the point of view of
|
||||
fwupd and should be included if firmware updates are to "just work". Without a
|
||||
DFU runtime interface we can match the device with `Flags = no-dfu-runtime` but
|
||||
will need a suitably new fwupd version before the device is recognized.
|
||||
|
||||
The USB interface revision (`REV`) is used as the BCD version number, as DFU has
|
||||
no way of representing a firmware version number. A new firmware version should
|
||||
always increment the USB REV of the *runtime* interface as fwupd will **not** switch
|
||||
the device into *DFU mode* during enumeration to read the version number.
|
||||
The version number of the DFU mode should represent the *bootloader version* and
|
||||
this should not change as the firmware is updated.
|
||||
|
||||
The runtime USB interface should have a unique vendor ID and product ID for the
|
||||
specific firmware stream. A different version of software should have a unique
|
||||
VID/PID USB descriptor pair. The microcontroller example VID/PID should **never**
|
||||
be used in the runtime mode otherwise fwupd would not know what firmware to match.
|
||||
|
||||
Ideally, the bootloader should also have a unique USB vendor ID and product ID.
|
||||
This allows fwupd to more easily recognize the runtime interface *going away* and
|
||||
the DFU interface *coming back*. If the VID/PID is the same in runtime and DFU
|
||||
modes then the quirk `Flags = no-pid-change` is required.
|
||||
|
||||
If the bootloader VID/PID is not customized (as might be the default for the supplied
|
||||
MCU) then fwupd can match the runtime VID/PID to the bootloader VID/PID. Where this
|
||||
fails is when the device is *stuck* in the DFU mode, perhaps because the user removed
|
||||
the USB cable before the device had completed updating.
|
||||
With a unique VID/PID fwupd can *recover* the device stuck in DFU mode, reflashing the
|
||||
device with the latest matching firmware and then attaching it back into runtime mode.
|
||||
|
||||
Using a *generic* VID/PID for the bootloader means fwupd does not know how to recover
|
||||
the device back into runtime mode as the client does not know what firmware to choose
|
||||
and the user is forced to either RMA the device, or to download the correct file manually
|
||||
from the vendor vebsite and use low-level commands like `sudo fwupdtool install-blob`.
|
||||
|
||||
## Vendor ID Security
|
||||
|
||||
The vendor ID is set from the USB vendor, for example `USB:0x0A12`
|
||||
|
@ -1,4 +1,6 @@
|
||||
# 8BitDo
|
||||
---
|
||||
title: Plugin: 8BitDo
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
@ -18,7 +20,7 @@ that is used when flashing the image.
|
||||
|
||||
This plugin supports the following protocol ID:
|
||||
|
||||
* com.8bitdo
|
||||
* `com.8bitdo`
|
||||
|
||||
## GUID Generation
|
||||
|
||||
|
@ -1,23 +1,21 @@
|
||||
Elan Fingerprint Sensor Support
|
||||
=================================
|
||||
---
|
||||
title: Plugin: Elan Fingerprint Sensor
|
||||
---
|
||||
|
||||
Introduction
|
||||
------------
|
||||
## Introduction
|
||||
|
||||
The plugin used for update firmware for fingerprint sensors from Elan.
|
||||
|
||||
Firmware Format
|
||||
---------------
|
||||
## Firmware Format
|
||||
|
||||
The daemon will decompress the cabinet archive and extract a firmware blob in
|
||||
a packed binary file format.
|
||||
|
||||
This plugin supports the following protocol ID:
|
||||
|
||||
* tw.com.emc.elanfp
|
||||
* `tw.com.emc.elanfp`
|
||||
|
||||
GUID Generation
|
||||
---------------
|
||||
## GUID Generation
|
||||
|
||||
These devices use the standard USB DeviceInstanceId values, e.g.
|
||||
|
||||
@ -25,7 +23,6 @@ These devices use the standard USB DeviceInstanceId values, e.g.
|
||||
* `USB\VID_04F3&PID_0C7E`
|
||||
* `USB\VID_04F3`
|
||||
|
||||
Vendor ID Security
|
||||
------------------
|
||||
## Vendor ID Security
|
||||
|
||||
The vendor ID is set from the USB vendor, in this instance set to `USB:0x04F3`
|
||||
|
@ -1,4 +1,6 @@
|
||||
# Elan TouchPad
|
||||
---
|
||||
title: Plugin: Elan TouchPad
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
@ -13,7 +15,7 @@ an unspecified binary file format.
|
||||
|
||||
This plugin supports the following protocol ID:
|
||||
|
||||
* tw.com.emc.elantp
|
||||
* `tw.com.emc.elantp`
|
||||
|
||||
## GUID Generation
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
# eMMC
|
||||
---
|
||||
title: Plugin: eMMC
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
@ -13,12 +15,16 @@ eMMC devices support the `org.jedec.mmc` protocol.
|
||||
|
||||
These devices use the following instance values:
|
||||
|
||||
* `EMMC\%NAME%`
|
||||
* `EMMC\%NAME%&%REV%`
|
||||
* `EMMC\%MANFID%&%OEMID%`
|
||||
* `EMMC\%MANFID%&%OEMID%&%NAME%`
|
||||
* `EMMC\%MANFID%&%NAME%&%REV%`
|
||||
* `EMMC\%MANFID%&%OEMID%&%NAME%&%REV%`
|
||||
* `EMMC\NAME_%name%`
|
||||
* `EMMC\NAME_%name%&REV_%rev%`
|
||||
* `EMMC\MAN_%manfid%&OEM_%oemid%`
|
||||
* `EMMC\MAN_%manfid%&OEM_%oemid%&NAME_%name%`
|
||||
* `EMMC\MAN_%manfid%&NAME_%name%&REV_%rev%`
|
||||
* `EMMC\MAN_%manfid%&OEM_%oemid%&NAME_%name%&REV_%rev%`
|
||||
|
||||
One deprecated instance ID is also added; new firmware should not use this.
|
||||
|
||||
* `EMMC\%manfid%&%oemid%&%name%`
|
||||
|
||||
## Update Behavior
|
||||
|
||||
|
@ -136,6 +136,7 @@ fu_emmc_device_probe(FuDevice *device, GError **error)
|
||||
guint64 manfid = 0;
|
||||
const gchar *tmp;
|
||||
g_autoptr(GUdevDevice) udev_parent = NULL;
|
||||
g_autofree gchar *man_oem_name = NULL;
|
||||
g_autofree gchar *vendor_id = NULL;
|
||||
g_autoptr(GRegex) dev_regex = NULL;
|
||||
|
||||
@ -221,6 +222,13 @@ fu_emmc_device_probe(FuDevice *device, GError **error)
|
||||
fu_device_build_instance_id(device, NULL, "EMMC", "MAN", "NAME", "REV", NULL);
|
||||
fu_device_build_instance_id(device, NULL, "EMMC", "MAN", "OEM", "NAME", "REV", NULL);
|
||||
|
||||
/* this is a (invalid!) instance ID added for legacy compatibility */
|
||||
man_oem_name = g_strdup_printf("EMMC\\%04" G_GUINT64_FORMAT "&%04" G_GUINT64_FORMAT "&%s",
|
||||
manfid,
|
||||
oemid,
|
||||
fu_device_get_name(device));
|
||||
fu_device_add_instance_id(device, man_oem_name);
|
||||
|
||||
/* set the vendor */
|
||||
tmp = g_udev_device_get_sysfs_attr(udev_parent, "manfid");
|
||||
vendor_id = g_strdup_printf("EMMC:%s", tmp);
|
||||
|
@ -1,4 +1,6 @@
|
||||
# Explore EP963x
|
||||
---
|
||||
title: Plugin: EP963x
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
@ -11,7 +13,7 @@ a packed binary file format.
|
||||
|
||||
This plugin supports the following protocol ID:
|
||||
|
||||
* tw.com.exploretech.ep963x
|
||||
* `tw.com.exploretech.ep963x`
|
||||
|
||||
## GUID Generation
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
# Fastboot
|
||||
---
|
||||
title: Plugin: Fastboot
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
@ -17,7 +19,7 @@ be updated.
|
||||
|
||||
This plugin supports the following protocol ID:
|
||||
|
||||
* com.google.fastboot
|
||||
* `com.google.fastboot`
|
||||
|
||||
## GUID Generation
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
# Flashrom
|
||||
---
|
||||
title: Plugin: Flashrom
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
@ -15,7 +17,7 @@ EEPROM programmer.
|
||||
|
||||
This plugin supports the following protocol ID:
|
||||
|
||||
* org.flashrom
|
||||
* `org.flashrom`
|
||||
|
||||
## Coreboot Version String
|
||||
|
||||
|
@ -99,11 +99,16 @@ Branch = coreboot
|
||||
Flags = reset-cmos
|
||||
PciBcrAddr = 0x0
|
||||
|
||||
# StarBook Mk VI - Intel (AMI GUID)
|
||||
[1292e166-a66f-5e11-b2bb-53265a8f53d9]
|
||||
FirmwareSizeMax = 0x2000000
|
||||
|
||||
# StarBook Mk VI - Intel (coreboot GUID)
|
||||
[8c994a92-7ef8-5d68-80b5-99ead7cf4686]
|
||||
Branch = coreboot
|
||||
Flags = reset-cmos
|
||||
PciBcrAddr = 0x0
|
||||
FirmwareSizeMax = 0x2000000
|
||||
|
||||
# NovaCustom NV4x (HwId)
|
||||
[25b6ea34-8f52-598e-a27a-31e03014dbe3]
|
||||
|
@ -1,4 +1,6 @@
|
||||
# Focal TouchPad
|
||||
---
|
||||
title: Plugin: Focal TouchPad
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
@ -12,7 +14,7 @@ an unspecified binary file format.
|
||||
|
||||
This plugin supports the following protocol ID:
|
||||
|
||||
* tw.com.focalfp
|
||||
* `tw.com.focalfp`
|
||||
|
||||
## GUID Generation
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user