From 03726227b71ae1730bf75d961dabd520a6182fb0 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 25 May 2021 12:26:58 +0100 Subject: [PATCH] uefi-capsule: Add FreeBSD ESRT support Based on a patch by Sergii Dmytruk , many thanks. --- plugins/uefi-capsule/fu-self-test.c | 10 ++ .../uefi-capsule/fu-uefi-backend-freebsd.c | 125 ++++++++++++++++++ plugins/uefi-capsule/meson.build | 2 + 3 files changed, 137 insertions(+) create mode 100644 plugins/uefi-capsule/fu-uefi-backend-freebsd.c diff --git a/plugins/uefi-capsule/fu-self-test.c b/plugins/uefi-capsule/fu-self-test.c index 01c1cb101..9ddb8b51d 100644 --- a/plugins/uefi-capsule/fu-self-test.c +++ b/plugins/uefi-capsule/fu-self-test.c @@ -162,6 +162,11 @@ fu_uefi_plugin_func (void) g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) devices = NULL; +#ifndef __linux__ + g_test_skip ("ESRT data is mocked only on Linux"); + return; +#endif + /* add each device */ ret = fu_backend_coldplug (backend, &error); g_assert_no_error (error); @@ -213,6 +218,11 @@ fu_uefi_update_info_func (void) g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) devices = NULL; +#ifndef __linux__ + g_test_skip ("ESRT data is mocked only on Linux"); + return; +#endif + /* add each device */ ret = fu_backend_coldplug (backend, &error); g_assert_no_error (error); diff --git a/plugins/uefi-capsule/fu-uefi-backend-freebsd.c b/plugins/uefi-capsule/fu-uefi-backend-freebsd.c new file mode 100644 index 000000000..7108c11eb --- /dev/null +++ b/plugins/uefi-capsule/fu-uefi-backend-freebsd.c @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2021 Richard Hughes + * Copyright (C) 2021 3mdeb Embedded Systems Consulting + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-uefi-common.h" +#include "fu-uefi-device.h" +#include "fu-uefi-backend.h" + +struct _FuUefiBackend { + FuBackend parent_instance; +}; + +G_DEFINE_TYPE (FuUefiBackend, fu_uefi_backend, FU_TYPE_BACKEND) + +static gchar * +fu_uefi_backend_get_sysctl_string (const gchar *name) +{ + gsize len = 0; + g_autofree gchar *value = NULL; + + if (sysctlbyname (name, NULL, &len, NULL, 0)) + return NULL; + value = g_malloc0 (len); + if (sysctlbyname (name, value, &len, NULL, 0)) + return NULL; + return g_steal_pointer (&value); +} + +static guint64 +fu_uefi_backend_get_sysctl_uint64 (const gchar *name) +{ + g_autofree gchar *value = fu_uefi_backend_get_sysctl_string (name); + if (value == NULL) + return G_MAXUINT64; + return fu_common_strtoull (value); +} + +/* yes, unsized uint_t */ +static guint +fu_uefi_backend_get_entry_field (const gchar *sysctl_name, const gchar *field_name) +{ + g_autofree gchar *name = g_build_path (".", sysctl_name, field_name, NULL); + return (guint) fu_uefi_backend_get_sysctl_uint64 (name); +} + +static FuUefiDevice * +fu_uefi_backend_device_new (guint64 idx) +{ + g_autoptr(FuUefiDevice) dev = NULL; + g_autofree gchar *fw_class = NULL; + g_autofree gchar *fw_class_fn = NULL; + g_autofree gchar *id = NULL; + g_autofree gchar *sysctl_name = NULL; + + sysctl_name = g_strdup_printf ("hw.efi.esrt.entry%u", (guint) idx); + fw_class_fn = g_build_path (".", sysctl_name, "fw_class", NULL); + fw_class = fu_uefi_backend_get_sysctl_string (fw_class_fn); + + /* create object */ + dev = g_object_new (FU_TYPE_UEFI_DEVICE, + "fw-class", fw_class, + "capsule-flags", fu_uefi_backend_get_entry_field (sysctl_name, "capsule_flags"), + "kind", fu_uefi_backend_get_entry_field (sysctl_name, "fw_type"), + "fw-version", fu_uefi_backend_get_entry_field (sysctl_name, "fw_version"), + "last-attempt-status", fu_uefi_backend_get_entry_field (sysctl_name, "last_attempt_status"), + "last-attempt-version", fu_uefi_backend_get_entry_field (sysctl_name, "last_attempt_version"), + "fw-version-lowest", fu_uefi_backend_get_entry_field (sysctl_name, "lowest_supported_fw_version"), + "fmp-hardware-instance", (guint64) 0x0, + "version-format", FWUPD_VERSION_FORMAT_NUMBER, + NULL); + + /* set ID */ + id = g_strdup_printf ("UEFI-%s-dev0", fw_class); + fu_device_set_id (FU_DEVICE (dev), id); + fu_device_set_physical_id (FU_DEVICE (dev), sysctl_name); + return g_steal_pointer (&dev); +} + +static gboolean +fu_uefi_backend_coldplug (FuBackend *backend, GError **error) +{ + guint64 entry_count = 0; + + entry_count = fu_uefi_backend_get_sysctl_uint64 ("hw.efi.esrt.fw_resource_count"); + if (entry_count == G_MAXUINT64) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "not supported"); + return FALSE; + } + for (guint i = 0; i < entry_count; i++) { + g_autoptr(FuUefiDevice) dev = fu_uefi_backend_device_new (i); + fu_backend_device_added (backend, FU_DEVICE (dev)); + } + + /* success */ + return TRUE; +} + +static void +fu_uefi_backend_init (FuUefiBackend *self) +{ +} + +static void +fu_uefi_backend_class_init (FuUefiBackendClass *klass) +{ + FuBackendClass *klass_backend = FU_BACKEND_CLASS (klass); + klass_backend->coldplug = fu_uefi_backend_coldplug; +} + +FuBackend * +fu_uefi_backend_new (void) +{ + return FU_BACKEND (g_object_new (FU_TYPE_UEFI_BACKEND, "name", "uefi", NULL)); +} diff --git a/plugins/uefi-capsule/meson.build b/plugins/uefi-capsule/meson.build index 16a937dde..e16241cc6 100644 --- a/plugins/uefi-capsule/meson.build +++ b/plugins/uefi-capsule/meson.build @@ -13,6 +13,8 @@ install_data(['uefi-capsule.quirk'], backend_srcs = [] if host_machine.system() == 'linux' backend_srcs += 'fu-uefi-backend-linux.c' +elif host_machine.system() == 'freebsd' + backend_srcs += 'fu-uefi-backend-freebsd.c' else error('no ESRT support for @0@'.format(host_machine.system())) endif