From df7950b8f3e20bb056e0deaffe0a093f512964bd Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 31 Jan 2016 10:18:40 +0000 Subject: [PATCH] Support vendor-specific UEFI version encodings This allows vendors such as Dell to use encodings such as AA.BB.CC.DD rather than the default of AA.BB.CCDD which is used by Intel and Microsoft. Existing metainfo.xml files with version numbers prefixed with '0x' are automatically converted to the new scheme. Based on a patch Mario Limonciello, many thanks. --- src/fu-main.c | 57 ++++++++++++++++++++++++++++++++++++++++++ src/fu-provider-uefi.c | 36 ++++++++++++++++++++++++-- 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/src/fu-main.c b/src/fu-main.c index 6e732c451..7c0b9c3e9 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -436,6 +436,54 @@ fu_main_get_guids_from_store (AsStore *store) return g_string_free (str, FALSE); } +/** + * fu_main_vendor_quirk_release_version: + **/ +static void +fu_main_vendor_quirk_release_version (AsApp *app) +{ + AsVersionParseFlag flags = AS_VERSION_PARSE_FLAG_USE_TRIPLET; + GPtrArray *releases; + guint i; + + /* no quirk required */ + if (as_app_get_id_kind (app) != AS_ID_KIND_FIRMWARE) + return; + + /* Dell uses AA.BB.CC.DD rather than AA.BB.CCDD */ + if (g_str_has_prefix (as_app_get_id (app), "com.dell.uefi")) + flags = AS_VERSION_PARSE_FLAG_NONE; + + /* fix each release */ + releases = as_app_get_releases (app); + for (i = 0; i < releases->len; i++) { + AsRelease *rel; + const gchar *version; + guint64 ver_uint32; + g_autofree gchar *version_new = NULL; + + rel = g_ptr_array_index (releases, i); + version = as_release_get_version (rel); + if (version == NULL) + continue; + if (g_strstr_len (version, -1, ".") != NULL) + continue; + + /* metainfo files use hex and the LVFS uses decimal */ + if (g_str_has_prefix (version, "0x")) { + ver_uint32 = g_ascii_strtoull (version + 2, NULL, 16); + } else { + ver_uint32 = g_ascii_strtoull (version, NULL, 10); + } + if (ver_uint32 == 0) + continue; + + /* convert to dotted decimal */ + version_new = as_utils_version_from_uint32 (ver_uint32, flags); + as_release_set_version (rel, version_new); + } +} + /** * fu_main_update_helper: **/ @@ -521,6 +569,9 @@ fu_main_update_helper (FuMainAuthHelper *helper, GError **error) return FALSE; } + /* possibly convert the version from 0x to dotted */ + fu_main_vendor_quirk_release_version (app); + version = as_release_get_version (rel); fu_device_set_metadata (helper->device, FU_DEVICE_KEY_UPDATE_VERSION, version); @@ -872,6 +923,9 @@ fu_main_get_updates (FuMainPrivate *priv, GError **error) if (app == NULL) continue; + /* possibly convert the version from 0x to dotted */ + fu_main_vendor_quirk_release_version (app); + /* get latest release */ rel = as_app_get_release_default (app); if (rel == NULL) { @@ -1409,6 +1463,9 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, return; } + /* possibly convert the version from 0x to dotted */ + fu_main_vendor_quirk_release_version (app); + /* create an array with all the metadata in */ g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); g_variant_builder_add (&builder, "{sv}", diff --git a/src/fu-provider-uefi.c b/src/fu-provider-uefi.c index 6060d9507..edf704bad 100644 --- a/src/fu-provider-uefi.c +++ b/src/fu-provider-uefi.c @@ -248,12 +248,43 @@ out: return ret; } +/** + * fu_provider_uefi_get_version_format: + **/ +static AsVersionParseFlag +fu_provider_uefi_get_version_format (void) +{ + guint i; + g_autofree gchar *content = NULL; + struct { + const gchar *sys_vendor; + AsVersionParseFlag flags; + } version_flags[] = { + { "Dell Inc.", AS_VERSION_PARSE_FLAG_NONE }, + { NULL, AS_VERSION_PARSE_FLAG_NONE } + }; + + /* any vendors match */ + if (!g_file_get_contents ("/sys/class/dmi/id/sys_vendor", + &content, NULL, NULL)) + return AS_VERSION_PARSE_FLAG_USE_TRIPLET; + g_strchomp (content); + for (i = 0; version_flags[i].sys_vendor != NULL; i++) { + if (g_strcmp0 (content, version_flags[i].sys_vendor) == 0) + return version_flags[i].flags; + } + + /* fall back */ + return AS_VERSION_PARSE_FLAG_USE_TRIPLET; +} + /** * fu_provider_uefi_coldplug: **/ static gboolean fu_provider_uefi_coldplug (FuProvider *provider, GError **error) { + AsVersionParseFlag parse_flags; fwup_resource_iter *iter = NULL; fwup_resource *re; g_autofree gchar *guid = NULL; @@ -279,6 +310,7 @@ fu_provider_uefi_coldplug (FuProvider *provider, GError **error) /* add each device */ guid = g_strdup ("00000000-0000-0000-0000-000000000000"); + parse_flags = fu_provider_uefi_get_version_format (); while (fwup_resource_iter_next (iter, &re) > 0) { efi_guid_t *guid_raw; guint32 version_raw; @@ -295,7 +327,7 @@ fu_provider_uefi_coldplug (FuProvider *provider, GError **error) } fwup_get_fw_version(re, &version_raw); version = as_utils_version_from_uint32 (version_raw, - AS_VERSION_PARSE_FLAG_USE_TRIPLET); + parse_flags); id = g_strdup_printf ("UEFI-%s-dev%" G_GUINT64_FORMAT, guid, hardware_instance); @@ -306,7 +338,7 @@ fu_provider_uefi_coldplug (FuProvider *provider, GError **error) fwup_get_lowest_supported_fw_version (re, &version_raw); if (version_raw != 0) { version_lowest = as_utils_version_from_uint32 (version_raw, - AS_VERSION_PARSE_FLAG_USE_TRIPLET); + parse_flags); fu_device_set_metadata (dev, FU_DEVICE_KEY_VERSION_LOWEST, version_lowest); }