From 04cb360847b4f11560eba16ea06cc899f5784293 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 10 Sep 2019 21:11:32 +0100 Subject: [PATCH] uefi-recovery: Add a plugin to add a fake ESRT entry for device recovery The factory-shipped MinnowBoardMAX board has firmware that does not include the ESRT table. Create a 'fake' UEFI device with the lowest possible version so that it can be updated to any version firmware. All the HwId GUIDs are used for the fake UEFI device, and so should be used in the firmware metadata for releases that should recover the system. --- contrib/fwupd.spec.in | 1 + plugins/meson.build | 1 + plugins/uefi-recovery/README.md | 17 ++++++ .../uefi-recovery/fu-plugin-uefi-recovery.c | 53 +++++++++++++++++++ plugins/uefi-recovery/meson.build | 28 ++++++++++ plugins/uefi-recovery/uefi-recovery.quirk | 3 ++ plugins/uefi/fu-plugin-uefi.c | 3 +- 7 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 plugins/uefi-recovery/README.md create mode 100644 plugins/uefi-recovery/fu-plugin-uefi-recovery.c create mode 100644 plugins/uefi-recovery/meson.build create mode 100644 plugins/uefi-recovery/uefi-recovery.quirk diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index bc2603292..5c183936d 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -340,6 +340,7 @@ rm ${RPM_BUILD_ROOT}%{_sbindir}/flashrom %{_libdir}/fwupd-plugins-3/libfu_plugin_udev.so %if 0%{?have_uefi} %{_libdir}/fwupd-plugins-3/libfu_plugin_uefi.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_uefi_recovery.so %endif %{_libdir}/fwupd-plugins-3/libfu_plugin_unifying.so %{_libdir}/fwupd-plugins-3/libfu_plugin_upower.so diff --git a/plugins/meson.build b/plugins/meson.build index 68daba8c6..edc3519ae 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -57,6 +57,7 @@ endif if get_option('plugin_uefi') subdir('uefi') +subdir('uefi-recovery') endif if get_option('plugin_flashrom') diff --git a/plugins/uefi-recovery/README.md b/plugins/uefi-recovery/README.md new file mode 100644 index 000000000..311a2974f --- /dev/null +++ b/plugins/uefi-recovery/README.md @@ -0,0 +1,17 @@ +UEFI Support +============ + +Introduction +------------ + +Some devices have firmware bugs which mean they do not include a valid ESRT +table in old firmware versions. + +Create a 'fake' UEFI device with the lowest possible version so that it can be +updated to a version of firmware which does have an ESRT table. + +GUID Generation +--------------- + +All the HwId GUIDs are used for the fake UEFI device, and so should be used in +the firmware metadata for releases that should recover the system. diff --git a/plugins/uefi-recovery/fu-plugin-uefi-recovery.c b/plugins/uefi-recovery/fu-plugin-uefi-recovery.c new file mode 100644 index 000000000..cd2103b2a --- /dev/null +++ b/plugins/uefi-recovery/fu-plugin-uefi-recovery.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-device-metadata.h" +#include "fu-plugin-vfuncs.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + /* make sure that UEFI plugin is ready to receive devices */ + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "uefi"); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +gboolean +fu_plugin_startup (FuPlugin *plugin, GError **error) +{ + if (!fu_plugin_has_custom_flag (plugin, "requires-uefi-recovery")) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "not required"); + return FALSE; + } + return TRUE; +} + +gboolean +fu_plugin_coldplug (FuPlugin *plugin, GError **error) +{ + GPtrArray *hwids = fu_plugin_get_hwids (plugin); + g_autoptr(FuDevice) device = fu_device_new (); + fu_device_set_id (device, "uefi-recovery"); + fu_device_set_name (device, "System Firmware ESRT Recovery"); + fu_device_set_version (device, "0.0.0", FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_REQUIRE_AC); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT); + fu_device_set_metadata (device, FU_DEVICE_METADATA_UEFI_DEVICE_KIND, "system-firmware"); + fu_device_add_icon (device, "computer"); + for (guint i = 0; i < hwids->len; i++) { + const gchar *hwid = g_ptr_array_index (hwids, i); + fu_device_add_guid (device, hwid); + } + fu_plugin_device_register (plugin, device); + return TRUE; +} diff --git a/plugins/uefi-recovery/meson.build b/plugins/uefi-recovery/meson.build new file mode 100644 index 000000000..a674b2a57 --- /dev/null +++ b/plugins/uefi-recovery/meson.build @@ -0,0 +1,28 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginUefiRecovery"'] + +install_data(['uefi-recovery.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_uefi_recovery', + fu_hash, + sources : [ + 'fu-plugin-uefi-recovery.c', + ], + include_directories : [ + include_directories('../..'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + install : true, + install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], + c_args : [ + cargs, + ], + dependencies : [ + plugin_deps, + ], +) diff --git a/plugins/uefi-recovery/uefi-recovery.quirk b/plugins/uefi-recovery/uefi-recovery.quirk new file mode 100644 index 000000000..8370ecf40 --- /dev/null +++ b/plugins/uefi-recovery/uefi-recovery.quirk @@ -0,0 +1,3 @@ +# Silicom Minnowboard Turbot MNW2MAX1.X64.0100.R01.1811141729 +[HwId=ea358e00-39f1-55b6-97be-a39225a585e1] +Flags = requires-uefi-recovery diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index d4d4be5a4..96b476755 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -12,6 +12,7 @@ #include #include +#include "fu-device-metadata.h" #include "fu-plugin-vfuncs.h" #include "fu-uefi-bgrt.h" @@ -448,7 +449,7 @@ fu_plugin_uefi_register_proxy_device (FuPlugin *plugin, FuDevice *device) void fu_plugin_device_registered (FuPlugin *plugin, FuDevice *device) { - if (fu_device_get_metadata (device, "UefiDeviceKind") != NULL) { + if (fu_device_get_metadata (device, FU_DEVICE_METADATA_UEFI_DEVICE_KIND) != NULL) { if (fu_device_get_guid_default (device) == NULL) { g_autofree gchar *dbg = fu_device_to_string (device); g_warning ("cannot create proxy device as no GUID: %s", dbg);