update-capsule: Move FuUefiDevice to a derivable for future use

This commit is contained in:
Richard Hughes 2021-07-16 12:01:19 +01:00
parent 924aa5a44b
commit d562c007a3
2 changed files with 113 additions and 80 deletions

View File

@ -18,8 +18,7 @@
#include "fu-uefi-bootmgr.h"
#include "fu-uefi-pcrs.h"
struct _FuUefiDevice {
FuDevice parent_instance;
typedef struct {
FuVolume *esp;
FuDeviceLocker *esp_locker;
gchar *fw_class;
@ -33,9 +32,11 @@ struct _FuUefiDevice {
gboolean missing_header;
gboolean automounted_esp;
gboolean requires_header;
};
} FuUefiDevicePrivate;
G_DEFINE_TYPE (FuUefiDevice, fu_uefi_device, FU_TYPE_DEVICE)
G_DEFINE_TYPE_WITH_PRIVATE (FuUefiDevice, fu_uefi_device, FU_TYPE_DEVICE)
#define GET_PRIVATE(o) (fu_uefi_device_get_instance_private (o))
enum {
PROP_0,
@ -53,9 +54,10 @@ enum {
void
fu_uefi_device_set_esp (FuUefiDevice *self, FuVolume *esp)
{
FuUefiDevicePrivate *priv = GET_PRIVATE (self);
g_return_if_fail (FU_IS_UEFI_DEVICE (self));
g_return_if_fail (FU_IS_VOLUME (esp));
g_set_object (&self->esp, esp);
g_set_object (&priv->esp, esp);
}
const gchar *
@ -118,17 +120,18 @@ static void
fu_uefi_device_to_string (FuDevice *device, guint idt, GString *str)
{
FuUefiDevice *self = FU_UEFI_DEVICE (device);
fu_common_string_append_kv (str, idt, "Kind", fu_uefi_device_kind_to_string (self->kind));
fu_common_string_append_kv (str, idt, "FwClass", self->fw_class);
fu_common_string_append_kx (str, idt, "CapsuleFlags", self->capsule_flags);
fu_common_string_append_kx (str, idt, "FwVersion", self->fw_version);
fu_common_string_append_kx (str, idt, "FwVersionLowest", self->fw_version_lowest);
FuUefiDevicePrivate *priv = GET_PRIVATE (self);
fu_common_string_append_kv (str, idt, "Kind", fu_uefi_device_kind_to_string (priv->kind));
fu_common_string_append_kv (str, idt, "FwClass", priv->fw_class);
fu_common_string_append_kx (str, idt, "CapsuleFlags", priv->capsule_flags);
fu_common_string_append_kx (str, idt, "FwVersion", priv->fw_version);
fu_common_string_append_kx (str, idt, "FwVersionLowest", priv->fw_version_lowest);
fu_common_string_append_kv (str, idt, "LastAttemptStatus",
fu_uefi_device_status_to_string (self->last_attempt_status));
fu_common_string_append_kx (str, idt, "LastAttemptVersion", self->last_attempt_version);
if (self->esp != NULL) {
fu_uefi_device_status_to_string (priv->last_attempt_status));
fu_common_string_append_kx (str, idt, "LastAttemptVersion", priv->last_attempt_version);
if (priv->esp != NULL) {
fu_common_string_append_kv (str, idt, "EspId",
fu_volume_get_id (self->esp));
fu_volume_get_id (priv->esp));
}
fu_common_string_append_ku (str, idt, "RequireESPFreeSpace",
fu_device_get_metadata_integer (device, "RequireESPFreeSpace"));
@ -140,94 +143,105 @@ static void
fu_uefi_device_report_metadata_pre (FuDevice *device, GHashTable *metadata)
{
FuUefiDevice *self = FU_UEFI_DEVICE (device);
FuUefiDevicePrivate *priv = GET_PRIVATE (self);
/* record if we had an invalid header during update */
g_hash_table_insert (metadata,
g_strdup ("MissingCapsuleHeader"),
g_strdup (self->missing_header ? "True" : "False"));
g_strdup (priv->missing_header ? "True" : "False"));
/* where the ESP was mounted during installation */
g_hash_table_insert (metadata,
g_strdup ("EspPath"),
fu_volume_get_mount_point (self->esp));
fu_volume_get_mount_point (priv->esp));
}
static void
fu_uefi_device_report_metadata_post (FuDevice *device, GHashTable *metadata)
{
FuUefiDevice *self = FU_UEFI_DEVICE (device);
FuUefiDevicePrivate *priv = GET_PRIVATE (self);
/* the actual last_attempt values */
g_hash_table_insert (metadata,
g_strdup ("LastAttemptStatus"),
g_strdup_printf ("0x%x", self->last_attempt_status));
g_strdup_printf ("0x%x", priv->last_attempt_status));
g_hash_table_insert (metadata,
g_strdup ("LastAttemptVersion"),
g_strdup_printf ("0x%x", self->last_attempt_version));
g_strdup_printf ("0x%x", priv->last_attempt_version));
}
FuUefiDeviceKind
fu_uefi_device_get_kind (FuUefiDevice *self)
{
FuUefiDevicePrivate *priv = GET_PRIVATE (self);
g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0);
return self->kind;
return priv->kind;
}
guint32
fu_uefi_device_get_version (FuUefiDevice *self)
{
FuUefiDevicePrivate *priv = GET_PRIVATE (self);
g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0x0);
return self->fw_version;
return priv->fw_version;
}
guint32
fu_uefi_device_get_version_lowest (FuUefiDevice *self)
{
FuUefiDevicePrivate *priv = GET_PRIVATE (self);
g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0x0);
return self->fw_version_lowest;
return priv->fw_version_lowest;
}
guint32
fu_uefi_device_get_version_error (FuUefiDevice *self)
{
FuUefiDevicePrivate *priv = GET_PRIVATE (self);
g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0x0);
return self->last_attempt_version;
return priv->last_attempt_version;
}
guint64
fu_uefi_device_get_hardware_instance (FuUefiDevice *self)
{
FuUefiDevicePrivate *priv = GET_PRIVATE (self);
g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0x0);
return self->fmp_hardware_instance;
return priv->fmp_hardware_instance;
}
FuUefiDeviceStatus
fu_uefi_device_get_status (FuUefiDevice *self)
{
FuUefiDevicePrivate *priv = GET_PRIVATE (self);
g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0);
return self->last_attempt_status;
return priv->last_attempt_status;
}
guint32
fu_uefi_device_get_capsule_flags (FuUefiDevice *self)
{
FuUefiDevicePrivate *priv = GET_PRIVATE (self);
g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0x0);
return self->capsule_flags;
return priv->capsule_flags;
}
const gchar *
fu_uefi_device_get_guid (FuUefiDevice *self)
{
FuUefiDevicePrivate *priv = GET_PRIVATE (self);
g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), NULL);
return self->fw_class;
return priv->fw_class;
}
static gchar *
fu_uefi_device_build_varname (FuUefiDevice *self)
{
FuUefiDevicePrivate *priv = GET_PRIVATE (self);
return g_strdup_printf ("fwupd-%s-%"G_GUINT64_FORMAT,
self->fw_class,
self->fmp_hardware_instance);
priv->fw_class,
priv->fmp_hardware_instance);
}
FuUefiUpdateInfo *
@ -348,11 +362,12 @@ static GBytes *
fu_uefi_device_fixup_firmware (FuDevice *device, GBytes *fw, GError **error)
{
FuUefiDevice *self = FU_UEFI_DEVICE (device);
FuUefiDevicePrivate *priv = GET_PRIVATE (self);
gsize fw_length;
const guint8 *data = g_bytes_get_data (fw, &fw_length);
g_autofree gchar *guid_new = NULL;
self->missing_header = FALSE;
priv->missing_header = FALSE;
/* GUID is the first 16 bytes */
if (fw_length < sizeof(fwupd_guid_t)) {
@ -367,7 +382,7 @@ fu_uefi_device_fixup_firmware (FuDevice *device, GBytes *fw, GError **error)
g_debug ("ESRT matches payload GUID");
return g_bytes_ref (fw);
/* Type that doesn't require a header */
} else if (!self->requires_header) {
} else if (!priv->requires_header) {
return g_bytes_ref (fw);
/* Missing, add a header */
} else {
@ -378,8 +393,8 @@ fu_uefi_device_fixup_firmware (FuDevice *device, GBytes *fw, GError **error)
efi_capsule_header_t *header = (efi_capsule_header_t *) new_data;
g_warning ("missing or invalid embedded capsule header");
self->missing_header = TRUE;
header->flags = self->capsule_flags;
priv->missing_header = TRUE;
header->flags = priv->capsule_flags;
header->header_size = header_size;
header->capsule_image_size = fw_length + header_size;
if (!fwupd_guid_from_string (fu_uefi_device_get_guid (self), &esrt_guid,
@ -401,6 +416,7 @@ fu_uefi_device_write_update_info (FuUefiDevice *self,
const gchar *guid,
GError **error)
{
FuUefiDevicePrivate *priv = GET_PRIVATE (self);
gsize datasz = 0;
gsize dp_bufsz = 0;
g_autofree guint8 *data = NULL;
@ -408,8 +424,8 @@ fu_uefi_device_write_update_info (FuUefiDevice *self,
efi_update_info_t info = {
.update_info_version = 0x7,
.guid = { 0x0 },
.capsule_flags = self->capsule_flags,
.hw_inst = self->fmp_hardware_instance,
.capsule_flags = priv->capsule_flags,
.hw_inst = priv->fmp_hardware_instance,
.time_attempted = { 0x0 },
.status = FU_UEFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE,
};
@ -444,12 +460,13 @@ static gboolean
fu_uefi_device_check_esp_free (FuDevice *device, GError **error)
{
FuUefiDevice *self = FU_UEFI_DEVICE (device);
FuUefiDevicePrivate *priv = GET_PRIVATE (self);
guint64 sz_reqd = fu_device_get_metadata_integer (device, "RequireESPFreeSpace");
if (sz_reqd == G_MAXUINT) {
g_debug ("maximum size is not configured");
return TRUE;
}
return fu_volume_check_free_space (self->esp, sz_reqd, error);
return fu_volume_check_free_space (priv->esp, sz_reqd, error);
}
static gboolean
@ -469,7 +486,8 @@ static gboolean
fu_uefi_device_cleanup_esp (FuDevice *device, GError **error)
{
FuUefiDevice *self = FU_UEFI_DEVICE (device);
g_autofree gchar *esp_path = fu_volume_get_mount_point (self->esp);
FuUefiDevicePrivate *priv = GET_PRIVATE (self);
g_autofree gchar *esp_path = fu_volume_get_mount_point (priv->esp);
g_autofree gchar *pattern = NULL;
g_autoptr(GPtrArray) files = NULL;
@ -505,10 +523,11 @@ fu_uefi_device_prepare (FuDevice *device,
GError **error)
{
FuUefiDevice *self = FU_UEFI_DEVICE (device);
FuUefiDevicePrivate *priv = GET_PRIVATE (self);
/* mount if required */
self->esp_locker = fu_volume_locker (self->esp, error);
if (self->esp_locker == NULL)
priv->esp_locker = fu_volume_locker (priv->esp, error);
if (priv->esp_locker == NULL)
return FALSE;
/* sanity checks */
@ -528,11 +547,12 @@ fu_uefi_device_cleanup (FuDevice *device,
GError **error)
{
FuUefiDevice *self = FU_UEFI_DEVICE (device);
FuUefiDevicePrivate *priv = GET_PRIVATE (self);
/* unmount ESP if we opened it */
if (!fu_device_locker_close (self->esp_locker, error))
if (!fu_device_locker_close (priv->esp_locker, error))
return FALSE;
g_clear_object (&self->esp_locker);
g_clear_object (&priv->esp_locker);
return TRUE;
}
@ -544,9 +564,10 @@ fu_uefi_device_write_firmware (FuDevice *device,
GError **error)
{
FuUefiDevice *self = FU_UEFI_DEVICE (device);
FuUefiDevicePrivate *priv = GET_PRIVATE (self);
FuUefiBootmgrFlags flags = FU_UEFI_BOOTMGR_FLAG_NONE;
const gchar *bootmgr_desc = "Linux Firmware Updater";
g_autofree gchar *esp_path = fu_volume_get_mount_point (self->esp);
g_autofree gchar *esp_path = fu_volume_get_mount_point (priv->esp);
g_autoptr(GBytes) fixed_fw = NULL;
g_autoptr(GBytes) fw = NULL;
g_autofree gchar *basename = NULL;
@ -555,7 +576,7 @@ fu_uefi_device_write_firmware (FuDevice *device,
g_autofree gchar *varname = fu_uefi_device_build_varname (self);
/* ensure we have the existing state */
if (self->fw_class == NULL) {
if (priv->fw_class == NULL) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
@ -570,7 +591,7 @@ fu_uefi_device_write_firmware (FuDevice *device,
/* save the blob to the ESP */
directory = fu_uefi_get_esp_path_for_os (device, esp_path);
basename = g_strdup_printf ("fwupd-%s.cap", self->fw_class);
basename = g_strdup_printf ("fwupd-%s.cap", priv->fw_class);
fn = g_build_filename (directory, "fw", basename, NULL);
if (!fu_common_mkdir_parent (fn, error))
return FALSE;
@ -593,7 +614,7 @@ fu_uefi_device_write_firmware (FuDevice *device,
}
/* set the blob header shared with fwupd.efi */
if (!fu_uefi_device_write_update_info (self, fn, varname, self->fw_class, error))
if (!fu_uefi_device_write_update_info (self, fn, varname, priv->fw_class, error))
return FALSE;
/* update the firmware before the bootloader runs */
@ -656,6 +677,7 @@ static gboolean
fu_uefi_device_probe (FuDevice *device, GError **error)
{
FuUefiDevice *self = FU_UEFI_DEVICE (device);
FuUefiDevicePrivate *priv = GET_PRIVATE (self);
FwupdVersionFormat version_format;
g_autofree gchar *devid = NULL;
g_autofree gchar *guid_strup = NULL;
@ -663,7 +685,7 @@ fu_uefi_device_probe (FuDevice *device, GError **error)
g_autofree gchar *version = NULL;
/* broken sysfs? */
if (self->fw_class == NULL) {
if (priv->fw_class == NULL) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
@ -672,27 +694,27 @@ fu_uefi_device_probe (FuDevice *device, GError **error)
}
/* this is invalid */
if (!fwupd_guid_is_valid (self->fw_class)) {
if (!fwupd_guid_is_valid (priv->fw_class)) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"ESRT GUID '%s' was not valid", self->fw_class);
"ESRT GUID '%s' was not valid", priv->fw_class);
return FALSE;
}
/* add GUID first, as quirks may set the version format */
fu_device_add_guid (device, self->fw_class);
fu_device_add_guid (device, priv->fw_class);
/* set versions */
version_format = fu_device_get_version_format (device);
version = fu_common_version_from_uint32 (self->fw_version, version_format);
version = fu_common_version_from_uint32 (priv->fw_version, version_format);
fu_device_set_version_format (device, version_format);
fu_device_set_version_raw (device, self->fw_version);
fu_device_set_version_raw (device, priv->fw_version);
fu_device_set_version (device, version);
if (self->fw_version_lowest != 0) {
version_lowest = fu_common_version_from_uint32 (self->fw_version_lowest,
if (priv->fw_version_lowest != 0) {
version_lowest = fu_common_version_from_uint32 (priv->fw_version_lowest,
version_format);
fu_device_set_version_lowest_raw (device, self->fw_version_lowest);
fu_device_set_version_lowest_raw (device, priv->fw_version_lowest);
fu_device_set_version_lowest (device, version_lowest);
}
@ -704,7 +726,7 @@ fu_uefi_device_probe (FuDevice *device, GError **error)
fu_device_add_internal_flag (device, FU_DEVICE_INTERNAL_FLAG_MD_SET_ICON);
/* add icons */
if (self->kind == FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE) {
if (priv->kind == FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE) {
/* nothing better in the icon naming spec */
fu_device_add_icon (device, "audio-card");
} else {
@ -714,7 +736,7 @@ fu_uefi_device_probe (FuDevice *device, GError **error)
}
/* set the PCR0 as the device checksum */
if (self->kind == FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE) {
if (priv->kind == FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE) {
g_autoptr(GError) error_local = NULL;
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_CAN_VERIFY);
if (!fu_uefi_device_add_system_checksum (device, &error_local))
@ -722,15 +744,15 @@ fu_uefi_device_probe (FuDevice *device, GError **error)
}
/* whether to create a missing header */
if (self->kind == FU_UEFI_DEVICE_KIND_FMP ||
self->kind == FU_UEFI_DEVICE_KIND_DELL_TPM_FIRMWARE)
self->requires_header = FALSE;
if (priv->kind == FU_UEFI_DEVICE_KIND_FMP ||
priv->kind == FU_UEFI_DEVICE_KIND_DELL_TPM_FIRMWARE)
priv->requires_header = FALSE;
else
self->requires_header = TRUE;
priv->requires_header = TRUE;
/* Windows seems to be case insensitive, but for convenience we'll
* match the upper case values typically specified in the .inf file */
guid_strup = g_ascii_strup (self->fw_class, -1);
guid_strup = g_ascii_strup (priv->fw_class, -1);
devid = g_strdup_printf ("UEFI\\RES_{%s}", guid_strup);
fu_device_add_instance_id (device, devid);
return TRUE;
@ -741,30 +763,31 @@ fu_uefi_device_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
FuUefiDevice *self = FU_UEFI_DEVICE (object);
FuUefiDevicePrivate *priv = GET_PRIVATE (self);
switch (prop_id) {
case PROP_FW_CLASS:
self->fw_class = g_value_dup_string (value);
priv->fw_class = g_value_dup_string (value);
break;
case PROP_KIND:
self->kind = g_value_get_uint (value);
priv->kind = g_value_get_uint (value);
break;
case PROP_CAPSULE_FLAGS:
self->capsule_flags = g_value_get_uint (value);
priv->capsule_flags = g_value_get_uint (value);
break;
case PROP_FW_VERSION:
self->fw_version = g_value_get_uint (value);
priv->fw_version = g_value_get_uint (value);
break;
case PROP_FW_VERSION_LOWEST:
self->fw_version_lowest = g_value_get_uint (value);
priv->fw_version_lowest = g_value_get_uint (value);
break;
case PROP_LAST_ATTEMPT_STATUS:
self->last_attempt_status = g_value_get_uint (value);
priv->last_attempt_status = g_value_get_uint (value);
break;
case PROP_LAST_ATTEMPT_VERSION:
self->last_attempt_version = g_value_get_uint (value);
priv->last_attempt_version = g_value_get_uint (value);
break;
case PROP_FMP_HARDWARE_INSTANCE:
self->fmp_hardware_instance = g_value_get_uint64 (value);
priv->fmp_hardware_instance = g_value_get_uint64 (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -792,12 +815,13 @@ static void
fu_uefi_device_finalize (GObject *object)
{
FuUefiDevice *self = FU_UEFI_DEVICE (object);
FuUefiDevicePrivate *priv = GET_PRIVATE (self);
g_free (self->fw_class);
if (self->esp != NULL)
g_object_unref (self->esp);
if (self->esp_locker != NULL)
g_object_unref (self->esp_locker);
g_free (priv->fw_class);
if (priv->esp != NULL)
g_object_unref (priv->esp);
if (priv->esp_locker != NULL)
g_object_unref (priv->esp_locker);
G_OBJECT_CLASS (fu_uefi_device_parent_class)->finalize (object);
}
@ -877,18 +901,20 @@ fu_uefi_device_new_from_dev (FuDevice *dev)
{
const gchar *tmp;
FuUefiDevice *self;
FuUefiDevicePrivate *priv;
g_return_val_if_fail (fu_device_get_guid_default (dev) != NULL, NULL);
/* create virtual object not backed by an ESRT entry */
self = g_object_new (FU_TYPE_UEFI_DEVICE, NULL);
fu_device_incorporate (FU_DEVICE (self), dev);
self->fw_class = g_strdup (fu_device_get_guid_default (dev));
priv = GET_PRIVATE (self);
priv->fw_class = g_strdup (fu_device_get_guid_default (dev));
tmp = fu_device_get_metadata (dev, FU_DEVICE_METADATA_UEFI_DEVICE_KIND);
self->kind = fu_uefi_device_kind_from_string (tmp);
self->capsule_flags = fu_device_get_metadata_integer (dev, FU_DEVICE_METADATA_UEFI_CAPSULE_FLAGS);
self->fw_version = fu_device_get_metadata_integer (dev, FU_DEVICE_METADATA_UEFI_FW_VERSION);
g_assert (self->fw_class != NULL);
priv->kind = fu_uefi_device_kind_from_string (tmp);
priv->capsule_flags = fu_device_get_metadata_integer (dev, FU_DEVICE_METADATA_UEFI_CAPSULE_FLAGS);
priv->fw_version = fu_device_get_metadata_integer (dev, FU_DEVICE_METADATA_UEFI_FW_VERSION);
g_assert (priv->fw_class != NULL);
return self;
}
@ -896,8 +922,10 @@ FuUefiDevice *
fu_uefi_device_new_from_guid (const gchar *guid)
{
FuUefiDevice *self;
FuUefiDevicePrivate *priv;
self = g_object_new (FU_TYPE_UEFI_DEVICE, NULL);
self->fw_class = g_strdup (guid);
priv = GET_PRIVATE (self);
priv->fw_class = g_strdup (guid);
fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_NUMBER);
return self;
}

View File

@ -13,7 +13,12 @@
#include "fu-uefi-update-info.h"
#define FU_TYPE_UEFI_DEVICE (fu_uefi_device_get_type ())
G_DECLARE_FINAL_TYPE (FuUefiDevice, fu_uefi_device, FU, UEFI_DEVICE, FuDevice)
G_DECLARE_DERIVABLE_TYPE (FuUefiDevice, fu_uefi_device, FU, UEFI_DEVICE, FuDevice)
struct _FuUefiDeviceClass
{
FuDeviceClass parent_class;
};
typedef enum {
FU_UEFI_DEVICE_KIND_UNKNOWN,