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.
This commit is contained in:
Richard Hughes 2016-01-31 10:18:40 +00:00
parent 92f903823d
commit df7950b8f3
2 changed files with 91 additions and 2 deletions

View File

@ -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}",

View File

@ -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);
}