/* * Copyright (C) 2018 Richard Hughes * Copyright (C) 2015 Peter Jones * * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" #include #include #include #include #include "fu-uefi-common.h" #include "fu-uefi-device.h" #include "fu-uefi-devpath.h" #include "fu-uefi-pcrs.h" typedef struct { FuVolume *esp; FuDeviceLocker *esp_locker; gchar *fw_class; FuUefiDeviceKind kind; guint32 capsule_flags; guint32 fw_version; guint32 fw_version_lowest; FuUefiDeviceStatus last_attempt_status; guint32 last_attempt_version; guint64 fmp_hardware_instance; gboolean missing_header; gboolean automounted_esp; gboolean requires_header; } FuUefiDevicePrivate; 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, PROP_FW_CLASS, PROP_KIND, PROP_CAPSULE_FLAGS, PROP_FW_VERSION, PROP_FW_VERSION_LOWEST, PROP_LAST_ATTEMPT_STATUS, PROP_LAST_ATTEMPT_VERSION, PROP_FMP_HARDWARE_INSTANCE, PROP_LAST }; 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(&priv->esp, esp); } const gchar * fu_uefi_device_kind_to_string(FuUefiDeviceKind kind) { if (kind == FU_UEFI_DEVICE_KIND_UNKNOWN) return "unknown"; if (kind == FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE) return "system-firmware"; if (kind == FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE) return "device-firmware"; if (kind == FU_UEFI_DEVICE_KIND_UEFI_DRIVER) return "uefi-driver"; if (kind == FU_UEFI_DEVICE_KIND_FMP) return "fmp"; if (kind == FU_UEFI_DEVICE_KIND_DELL_TPM_FIRMWARE) return "dell-tpm-firmware"; return NULL; } FuUefiDeviceKind fu_uefi_device_kind_from_string(const gchar *kind) { if (g_strcmp0(kind, "system-firmware") == 0) return FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE; if (g_strcmp0(kind, "device-firmware") == 0) return FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE; if (g_strcmp0(kind, "uefi-driver") == 0) return FU_UEFI_DEVICE_KIND_UEFI_DRIVER; if (g_strcmp0(kind, "fmp") == 0) return FU_UEFI_DEVICE_KIND_FMP; if (g_strcmp0(kind, "dell-tpm-firmware") == 0) return FU_UEFI_DEVICE_KIND_DELL_TPM_FIRMWARE; return FU_UEFI_DEVICE_KIND_UNKNOWN; } const gchar * fu_uefi_device_status_to_string(FuUefiDeviceStatus status) { if (status == FU_UEFI_DEVICE_STATUS_SUCCESS) return "success"; if (status == FU_UEFI_DEVICE_STATUS_ERROR_UNSUCCESSFUL) return "unsuccessful"; if (status == FU_UEFI_DEVICE_STATUS_ERROR_INSUFFICIENT_RESOURCES) return "insufficient resources"; if (status == FU_UEFI_DEVICE_STATUS_ERROR_INCORRECT_VERSION) return "incorrect version"; if (status == FU_UEFI_DEVICE_STATUS_ERROR_INVALID_FORMAT) return "invalid firmware format"; if (status == FU_UEFI_DEVICE_STATUS_ERROR_AUTH_ERROR) return "authentication signing error"; if (status == FU_UEFI_DEVICE_STATUS_ERROR_PWR_EVT_AC) return "AC power required"; if (status == FU_UEFI_DEVICE_STATUS_ERROR_PWR_EVT_BATT) return "battery level is too low"; return NULL; } static void fu_uefi_device_to_string(FuDevice *device, guint idt, GString *str) { FuUefiDevice *self = FU_UEFI_DEVICE(device); 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(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(priv->esp)); } fu_common_string_append_ku(str, idt, "RequireESPFreeSpace", fu_device_get_metadata_integer(device, "RequireESPFreeSpace")); } 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(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(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", priv->last_attempt_status)); g_hash_table_insert(metadata, g_strdup("LastAttemptVersion"), 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 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 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 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 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 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 priv->last_attempt_status; } void fu_uefi_device_set_status(FuUefiDevice *self, FuUefiDeviceStatus status) { FuUefiDevicePrivate *priv = GET_PRIVATE(self); const gchar *tmp; g_autofree gchar *err_msg = NULL; g_autofree gchar *version_str = NULL; g_return_if_fail(FU_IS_UEFI_DEVICE(self)); /* cache for later */ priv->last_attempt_status = status; /* all good */ if (status == FU_UEFI_DEVICE_STATUS_SUCCESS) { fu_device_set_update_state(FU_DEVICE(self), FWUPD_UPDATE_STATE_SUCCESS); return; } /* something went wrong */ if (status == FU_UEFI_DEVICE_STATUS_ERROR_PWR_EVT_AC || status == FU_UEFI_DEVICE_STATUS_ERROR_PWR_EVT_BATT) { fu_device_set_update_state(FU_DEVICE(self), FWUPD_UPDATE_STATE_FAILED_TRANSIENT); } else { fu_device_set_update_state(FU_DEVICE(self), FWUPD_UPDATE_STATE_FAILED); } version_str = g_strdup_printf("%u", priv->last_attempt_version); tmp = fu_uefi_device_status_to_string(status); if (tmp == NULL) { err_msg = g_strdup_printf("failed to update to %s", version_str); } else { err_msg = g_strdup_printf("failed to update to %s: %s", version_str, tmp); } fu_device_set_update_error(FU_DEVICE(self), err_msg); } 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 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 priv->fw_class; } gchar * fu_uefi_device_build_varname(FuUefiDevice *self) { FuUefiDevicePrivate *priv = GET_PRIVATE(self); return g_strdup_printf("fwupd-%s-%" G_GUINT64_FORMAT, priv->fw_class, priv->fmp_hardware_instance); } FuUefiUpdateInfo * fu_uefi_device_load_update_info(FuUefiDevice *self, GError **error) { gsize datasz = 0; g_autofree gchar *varname = fu_uefi_device_build_varname(self); g_autofree guint8 *data = NULL; g_autoptr(FuUefiUpdateInfo) info = fu_uefi_update_info_new(); g_return_val_if_fail(FU_IS_UEFI_DEVICE(self), NULL); g_return_val_if_fail(error == NULL || *error == NULL, NULL); /* get the existing status */ if (!fu_efivar_get_data(FU_EFIVAR_GUID_FWUPDATE, varname, &data, &datasz, NULL, error)) return NULL; if (!fu_uefi_update_info_parse(info, data, datasz, error)) return NULL; return g_steal_pointer(&info); } gboolean fu_uefi_device_clear_status(FuUefiDevice *self, GError **error) { efi_update_info_t info; gsize datasz = 0; g_autofree gchar *varname = fu_uefi_device_build_varname(self); g_autofree guint8 *data = NULL; g_return_val_if_fail(FU_IS_UEFI_DEVICE(self), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* get the existing status */ if (!fu_efivar_get_data(FU_EFIVAR_GUID_FWUPDATE, varname, &data, &datasz, NULL, error)) return FALSE; if (datasz < sizeof(efi_update_info_t)) { g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "EFI variable is corrupt"); return FALSE; } /* just copy the efi_update_info_t, ignore devpath then save it back */ memcpy(&info, data, sizeof(info)); info.status = FU_UEFI_DEVICE_STATUS_SUCCESS; memcpy(data, &info, sizeof(info)); return fu_efivar_set_data(FU_EFIVAR_GUID_FWUPDATE, varname, data, datasz, FU_EFIVAR_ATTR_NON_VOLATILE | FU_EFIVAR_ATTR_BOOTSERVICE_ACCESS | FU_EFIVAR_ATTR_RUNTIME_ACCESS, error); } static guint8 * fu_uefi_device_build_dp_buf(const gchar *path, gsize *bufsz, GError **error) { gssize req; gssize sz; g_autofree guint8 *dp_buf = NULL; g_autoptr(GPtrArray) dps = NULL; /* get the size of the path first */ req = efi_generate_file_device_path(NULL, 0, path, EFIBOOT_OPTIONS_IGNORE_FS_ERROR | EFIBOOT_ABBREV_HD); if (req < 0) { g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "failed to efi_generate_file_device_path(%s)", path); return NULL; } /* if we just have an end device path, it's not going to work */ if (req <= 4) { g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "failed to get valid device_path for (%s)", path); return NULL; } /* actually get the path this time */ dp_buf = g_malloc0(req); sz = efi_generate_file_device_path(dp_buf, req, path, EFIBOOT_OPTIONS_IGNORE_FS_ERROR | EFIBOOT_ABBREV_HD); if (sz < 0) { g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "failed to efi_generate_file_device_path(%s)", path); return NULL; } /* parse what we got back from efivar */ dps = fu_uefi_devpath_parse(dp_buf, (gsize)sz, FU_UEFI_DEVPATH_PARSE_FLAG_NONE, error); if (dps == NULL) { fu_common_dump_raw(G_LOG_DOMAIN, "dp_buf", dp_buf, (gsize)sz); return NULL; } /* success */ if (bufsz != NULL) *bufsz = sz; return g_steal_pointer(&dp_buf); } GBytes * fu_uefi_device_fixup_firmware(FuUefiDevice *self, GBytes *fw, GError **error) { FuUefiDevicePrivate *priv = GET_PRIVATE(self); gsize fw_length; const guint8 *data = g_bytes_get_data(fw, &fw_length); g_autofree gchar *guid_new = NULL; priv->missing_header = FALSE; /* GUID is the first 16 bytes */ if (fw_length < sizeof(fwupd_guid_t)) { g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Invalid payload"); return NULL; } guid_new = fwupd_guid_to_string((fwupd_guid_t *)data, FWUPD_GUID_FLAG_MIXED_ENDIAN); /* ESRT header matches payload */ if (g_strcmp0(fu_uefi_device_get_guid(self), guid_new) == 0) { g_debug("ESRT matches payload GUID"); return g_bytes_ref(fw); /* Type that doesn't require a header */ } else if (!priv->requires_header) { return g_bytes_ref(fw); /* Missing, add a header */ } else { guint header_size = getpagesize(); guint8 *new_data = g_malloc(fw_length + header_size); guint8 *capsule = new_data + header_size; fwupd_guid_t esrt_guid = {0x0}; efi_capsule_header_t *header = (efi_capsule_header_t *)new_data; g_warning("missing or invalid embedded capsule header"); 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, FWUPD_GUID_FLAG_MIXED_ENDIAN, error)) { g_prefix_error(error, "Invalid ESRT GUID: "); return NULL; } memcpy(&header->guid, &esrt_guid, sizeof(fwupd_guid_t)); memcpy(capsule, data, fw_length); return g_bytes_new_take(new_data, fw_length + header_size); } } gboolean fu_uefi_device_write_update_info(FuUefiDevice *self, const gchar *filename, const gchar *varname, const gchar *guid, GError **error) { FuUefiDevicePrivate *priv = GET_PRIVATE(self); gsize datasz = 0; gsize dp_bufsz = 0; g_autofree guint8 *data = NULL; g_autofree guint8 *dp_buf = NULL; efi_update_info_t info = { .update_info_version = 0x7, .guid = {0x0}, .capsule_flags = priv->capsule_flags, .hw_inst = priv->fmp_hardware_instance, .time_attempted = {0x0}, .status = FU_UEFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE, }; /* set the body as the device path */ if (g_getenv("FWUPD_UEFI_TEST") != NULL) { g_debug("not building device path, in tests...."); return TRUE; } /* convert to EFI device path */ dp_buf = fu_uefi_device_build_dp_buf(filename, &dp_bufsz, error); if (dp_buf == NULL) return FALSE; /* save this header and body to the hardware */ if (!fwupd_guid_from_string(guid, &info.guid, FWUPD_GUID_FLAG_MIXED_ENDIAN, error)) return FALSE; datasz = sizeof(info) + dp_bufsz; data = g_malloc0(datasz); memcpy(data, &info, sizeof(info)); memcpy(data + sizeof(info), dp_buf, dp_bufsz); return fu_efivar_set_data(FU_EFIVAR_GUID_FWUPDATE, varname, data, datasz, FU_EFIVAR_ATTR_NON_VOLATILE | FU_EFIVAR_ATTR_BOOTSERVICE_ACCESS | FU_EFIVAR_ATTR_RUNTIME_ACCESS, error); } 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(priv->esp, sz_reqd, error); } static gboolean fu_uefi_check_asset(FuDevice *device, GError **error) { g_autofree gchar *source_app = fu_uefi_get_built_app_path(error); if (source_app == NULL) { if (fu_efivar_secure_boot_enabled()) g_prefix_error(error, "missing signed bootloader for secure boot: "); return FALSE; } return TRUE; } static gboolean fu_uefi_device_cleanup_esp(FuDevice *device, GError **error) { FuUefiDevice *self = FU_UEFI_DEVICE(device); 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; /* in case we call capsule install twice before reboot */ if (fu_efivar_exists(FU_EFIVAR_GUID_EFI_GLOBAL, "BootNext")) return TRUE; /* delete any files matching the glob in the ESP */ files = fu_common_get_files_recursive(esp_path, error); if (files == NULL) return FALSE; pattern = g_build_filename(esp_path, "EFI/*/fw/fwupd*.cap", NULL); for (guint i = 0; i < files->len; i++) { const gchar *fn = g_ptr_array_index(files, i); if (fu_common_fnmatch(pattern, fn)) { g_autoptr(GFile) file = g_file_new_for_path(fn); g_debug("deleting %s", fn); if (!g_file_delete(file, NULL, error)) return FALSE; } } /* delete any old variables */ if (!fu_efivar_delete_with_glob(FU_EFIVAR_GUID_FWUPDATE, "fwupd*-*", error)) return FALSE; return TRUE; } static gboolean fu_uefi_device_prepare(FuDevice *device, FwupdInstallFlags flags, GError **error) { FuUefiDevice *self = FU_UEFI_DEVICE(device); FuUefiDevicePrivate *priv = GET_PRIVATE(self); /* mount if required */ priv->esp_locker = fu_volume_locker(priv->esp, error); if (priv->esp_locker == NULL) return FALSE; /* sanity checks */ if (!fu_uefi_device_cleanup_esp(device, error)) return FALSE; if (!fu_uefi_device_check_esp_free(device, error)) return FALSE; if (!fu_uefi_check_asset(device, error)) return FALSE; return TRUE; } static gboolean fu_uefi_device_cleanup(FuDevice *device, FwupdInstallFlags flags, GError **error) { FuUefiDevice *self = FU_UEFI_DEVICE(device); FuUefiDevicePrivate *priv = GET_PRIVATE(self); /* unmount ESP if we opened it */ if (!fu_device_locker_close(priv->esp_locker, error)) return FALSE; g_clear_object(&priv->esp_locker); return TRUE; } static gboolean fu_uefi_device_add_system_checksum(FuDevice *device, GError **error) { g_autoptr(FuUefiPcrs) pcrs = fu_uefi_pcrs_new(); g_autoptr(GError) error_local = NULL; g_autoptr(GPtrArray) pcr0s = NULL; /* get all the PCRs */ if (!fu_uefi_pcrs_setup(pcrs, &error_local)) { if (g_error_matches(error_local, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED) || g_error_matches(error_local, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND)) { g_debug("%s", error_local->message); return TRUE; } g_propagate_error(error, g_steal_pointer(&error_local)); return FALSE; } /* get all the PCR0s */ pcr0s = fu_uefi_pcrs_get_checksums(pcrs, 0); if (pcr0s->len == 0) { g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "no PCR0s detected"); return FALSE; } for (guint i = 0; i < pcr0s->len; i++) { const gchar *checksum = g_ptr_array_index(pcr0s, i); fu_device_add_checksum(device, checksum); } /* success */ return TRUE; } 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; g_autofree gchar *version_lowest = NULL; g_autofree gchar *version = NULL; /* broken sysfs? */ if (priv->fw_class == NULL) { g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "failed to read fw_class"); return FALSE; } /* this is invalid */ if (!fwupd_guid_is_valid(priv->fw_class)) { g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "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, priv->fw_class); /* set versions */ version_format = fu_device_get_version_format(device); 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, priv->fw_version); fu_device_set_version(device, version); 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, priv->fw_version_lowest); fu_device_set_version_lowest(device, version_lowest); } /* set flags */ fu_device_add_flag(device, FWUPD_DEVICE_FLAG_INTERNAL); fu_device_add_flag(device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT); fu_device_add_flag(device, FWUPD_DEVICE_FLAG_REQUIRE_AC); fu_device_add_internal_flag(device, FU_DEVICE_INTERNAL_FLAG_MD_SET_VERFMT); fu_device_add_internal_flag(device, FU_DEVICE_INTERNAL_FLAG_MD_SET_ICON); /* add icons */ if (priv->kind == FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE) { /* nothing better in the icon naming spec */ fu_device_add_icon(device, "audio-card"); } else { /* this is probably system firmware */ fu_device_add_icon(device, "computer"); fu_device_add_instance_id(device, "main-system-firmware"); } /* set the PCR0 as the device checksum */ 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)) g_warning("Failed to get PCR0s: %s", error_local->message); } /* whether to create a missing header */ if (priv->kind == FU_UEFI_DEVICE_KIND_FMP || priv->kind == FU_UEFI_DEVICE_KIND_DELL_TPM_FIRMWARE) priv->requires_header = FALSE; else 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(priv->fw_class, -1); devid = g_strdup_printf("UEFI\\RES_{%s}", guid_strup); fu_device_add_instance_id(device, devid); return TRUE; } static gboolean fu_uefi_device_get_results(FuDevice *device, GError **error) { FuUefiDevice *self = FU_UEFI_DEVICE(device); FuUefiDevicePrivate *priv = GET_PRIVATE(self); /* just set the update error */ fu_uefi_device_set_status(self, priv->last_attempt_status); return TRUE; } gchar * fu_uefi_device_get_esp_path(FuUefiDevice *self) { FuUefiDevicePrivate *priv = GET_PRIVATE(self); return fu_volume_get_mount_point(priv->esp); } static void 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: priv->fw_class = g_value_dup_string(value); break; case PROP_KIND: priv->kind = g_value_get_uint(value); break; case PROP_CAPSULE_FLAGS: priv->capsule_flags = g_value_get_uint(value); break; case PROP_FW_VERSION: priv->fw_version = g_value_get_uint(value); break; case PROP_FW_VERSION_LOWEST: priv->fw_version_lowest = g_value_get_uint(value); break; case PROP_LAST_ATTEMPT_STATUS: fu_uefi_device_set_status(self, g_value_get_uint(value)); break; case PROP_LAST_ATTEMPT_VERSION: priv->last_attempt_version = g_value_get_uint(value); break; case PROP_FMP_HARDWARE_INSTANCE: priv->fmp_hardware_instance = g_value_get_uint64(value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } static void fu_uefi_device_init(FuUefiDevice *self) { fu_device_set_summary(FU_DEVICE(self), "UEFI ESRT device"); fu_device_add_protocol(FU_DEVICE(self), "org.uefi.capsule"); fu_device_register_private_flag(FU_DEVICE(self), FU_UEFI_DEVICE_FLAG_NO_UX_CAPSULE, "no-ux-capsule"); fu_device_register_private_flag(FU_DEVICE(self), FU_UEFI_DEVICE_FLAG_USE_SHIM_UNIQUE, "use-shim-unique"); fu_device_register_private_flag(FU_DEVICE(self), FU_UEFI_DEVICE_FLAG_USE_LEGACY_BOOTMGR_DESC, "use-legacy-bootmgr-desc"); fu_device_register_private_flag(FU_DEVICE(self), FU_UEFI_DEVICE_FLAG_SUPPORTS_BOOT_ORDER_LOCK, "supports-boot-order-lock"); fu_device_register_private_flag(FU_DEVICE(self), FU_UEFI_DEVICE_FLAG_USE_SHIM_FOR_SB, "use-shim-for-sb"); fu_device_register_private_flag(FU_DEVICE(self), FU_UEFI_DEVICE_FLAG_FALLBACK_TO_REMOVABLE_PATH, "fallback-to-removable-path"); fu_device_register_private_flag(FU_DEVICE(self), FU_UEFI_DEVICE_FLAG_NO_RT_SET_VARIABLE, "no-rt-set-variable"); } static void fu_uefi_device_finalize(GObject *object) { FuUefiDevice *self = FU_UEFI_DEVICE(object); FuUefiDevicePrivate *priv = GET_PRIVATE(self); 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); } static void fu_uefi_device_class_init(FuUefiDeviceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); GParamSpec *pspec; FuDeviceClass *klass_device = FU_DEVICE_CLASS(klass); object_class->set_property = fu_uefi_device_set_property; object_class->finalize = fu_uefi_device_finalize; klass_device->to_string = fu_uefi_device_to_string; klass_device->probe = fu_uefi_device_probe; klass_device->prepare = fu_uefi_device_prepare; klass_device->cleanup = fu_uefi_device_cleanup; klass_device->report_metadata_pre = fu_uefi_device_report_metadata_pre; klass_device->report_metadata_post = fu_uefi_device_report_metadata_post; klass_device->get_results = fu_uefi_device_get_results; pspec = g_param_spec_string("fw-class", NULL, NULL, NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME); g_object_class_install_property(object_class, PROP_FW_CLASS, pspec); pspec = g_param_spec_uint("kind", NULL, NULL, FU_UEFI_DEVICE_KIND_UNKNOWN, FU_UEFI_DEVICE_KIND_LAST - 1, FU_UEFI_DEVICE_KIND_UNKNOWN, G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME); g_object_class_install_property(object_class, PROP_KIND, pspec); pspec = g_param_spec_uint("capsule-flags", NULL, NULL, 0, G_MAXUINT32, 0, G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME); g_object_class_install_property(object_class, PROP_CAPSULE_FLAGS, pspec); pspec = g_param_spec_uint("fw-version", NULL, NULL, 0, G_MAXUINT32, 0, G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME); g_object_class_install_property(object_class, PROP_FW_VERSION, pspec); pspec = g_param_spec_uint("fw-version-lowest", NULL, NULL, 0, G_MAXUINT32, 0, G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME); g_object_class_install_property(object_class, PROP_FW_VERSION_LOWEST, pspec); pspec = g_param_spec_uint("last-attempt-status", NULL, NULL, FU_UEFI_DEVICE_STATUS_SUCCESS, FU_UEFI_DEVICE_STATUS_LAST - 1, FU_UEFI_DEVICE_STATUS_SUCCESS, G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME); g_object_class_install_property(object_class, PROP_LAST_ATTEMPT_STATUS, pspec); pspec = g_param_spec_uint("last-attempt-version", NULL, NULL, 0, G_MAXUINT32, 0, G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME); g_object_class_install_property(object_class, PROP_LAST_ATTEMPT_VERSION, pspec); pspec = g_param_spec_uint64("fmp-hardware-instance", NULL, NULL, 0, G_MAXUINT64, 0, G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME); g_object_class_install_property(object_class, PROP_FMP_HARDWARE_INSTANCE, pspec); }