uefi: Show the stored capsule filename in fwupdate

This commit is contained in:
Richard Hughes 2018-06-26 16:41:06 +01:00
parent 57df956d7b
commit 7ecf0164de
11 changed files with 291 additions and 56 deletions

View File

@ -212,6 +212,32 @@ fu_uefi_plugin_func (void)
g_assert_cmpint (fu_uefi_device_get_status (dev), ==, FU_UEFI_DEVICE_STATUS_SUCCESS);
}
static void
fu_uefi_update_info_func (void)
{
g_autofree gchar *fn = NULL;
g_autoptr(FuUefiDevice) dev = NULL;
g_autoptr(FuUefiUpdateInfo) info = NULL;
g_autoptr(GError) error = NULL;
fn = fu_test_get_filename (TESTDATADIR, "efi/esrt/entries/entry0");
g_assert (fn != NULL);
dev = fu_uefi_device_new_from_entry (fn);
g_assert_nonnull (dev);
g_assert_cmpint (fu_uefi_device_get_kind (dev), ==, FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE);
g_assert_cmpstr (fu_uefi_device_get_guid (dev), ==, "ddc0ee61-e7f0-4e7d-acc5-c070a398838e");
info = fu_uefi_device_load_update_info (dev, &error);
g_assert_no_error (error);
g_assert_nonnull (info);
g_assert_cmpint (fu_uefi_update_info_get_version (info), ==, 0x7);
g_assert_cmpstr (fu_uefi_update_info_get_guid (info), ==, "697bd920-12cf-4da9-8385-996909bc6559");
g_assert_cmpint (fu_uefi_update_info_get_capsule_flags (info), ==, 0x50000);
g_assert_cmpint (fu_uefi_update_info_get_hw_inst (info), ==, 0x0);
g_assert_cmpint (fu_uefi_update_info_get_status (info), ==, FU_UEFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE);
g_assert_cmpstr (fu_uefi_update_info_get_capsule_fn (info), ==,
"/EFI/fedora/fw/fwupdate-697bd920-12cf-4da9-8385-996909bc6559.cap");
}
int
main (int argc, char **argv)
{
@ -229,6 +255,7 @@ main (int argc, char **argv)
g_test_add_func ("/uefi/framebuffer", fu_uefi_framebuffer_func);
g_test_add_func ("/uefi/bitmap", fu_uefi_bitmap_func);
g_test_add_func ("/uefi/device", fu_uefi_device_func);
g_test_add_func ("/uefi/update-info", fu_uefi_update_info_func);
g_test_add_func ("/uefi/plugin", fu_uefi_plugin_func);
return g_test_run ();
}

View File

@ -18,9 +18,6 @@ G_BEGIN_DECLS
#define EFI_CAPSULE_HEADER_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000
#define EFI_CAPSULE_HEADER_FLAGS_INITIATE_RESET 0x00040000
#define EFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE 0x00000001
#define EFI_UPDATE_INFO_STATUS_ATTEMPTED 0x00000002
typedef struct __attribute__((__packed__)) {
guint16 year;
guint8 month;

View File

@ -184,31 +184,13 @@ fu_uefi_device_set_efivar (FuUefiDevice *self,
error);
}
static gboolean
fu_uefi_device_info_from_databuf (efi_update_info_t *info,
const guint8 *data,
gsize sz,
GError **error)
{
if (sz < sizeof(efi_update_info_t)) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"EFI variable is corrupt");
return FALSE;
}
memcpy (info, data, sizeof(efi_update_info_t));
return TRUE;
}
gboolean
fu_uefi_device_get_update_info (FuUefiDevice *self,
efi_update_info_t *info,
GError **error)
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), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
@ -217,7 +199,9 @@ fu_uefi_device_get_update_info (FuUefiDevice *self,
if (!fu_uefi_vars_get_data (FU_UEFI_VARS_GUID_FWUPDATE, varname,
&data, &datasz, NULL, error))
return FALSE;
return fu_uefi_device_info_from_databuf (info, data, datasz, error);
if (!fu_uefi_update_info_parse (info, data, datasz, error))
return FALSE;
return g_steal_pointer (&info);
}
gboolean
@ -235,10 +219,16 @@ fu_uefi_device_clear_status (FuUefiDevice *self, GError **error)
if (!fu_uefi_vars_get_data (FU_UEFI_VARS_GUID_FWUPDATE, varname,
&data, &datasz, NULL, error))
return FALSE;
if (!fu_uefi_device_info_from_databuf (&info, data, datasz, error))
if (datasz < sizeof(efi_update_info_t)) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"EFI variable is corrupt");
return FALSE;
}
/* save it back */
/* 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_uefi_device_set_efivar (self, data, datasz, error);
@ -329,7 +319,7 @@ fu_uefi_device_write_firmware (FuDevice *device, GBytes *fw, GError **error)
/* set the blob header shared with fwup.efi */
memset (&info, 0x0, sizeof(info));
info.status = EFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE;
info.status = FU_UEFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE;
info.capsule_flags = self->capsule_flags;
info.update_info_version = 0x7;
info.hw_inst = self->fmp_hardware_instance;

View File

@ -13,6 +13,7 @@
#include "fu-plugin.h"
#include "fu-uefi-device.h"
#include "fu-uefi-update-info.h"
G_BEGIN_DECLS
@ -55,8 +56,7 @@ guint64 fu_uefi_device_get_hardware_instance (FuUefiDevice *self);
FuUefiDeviceStatus fu_uefi_device_get_status (FuUefiDevice *self);
const gchar *fu_uefi_device_kind_to_string (FuUefiDeviceKind kind);
const gchar *fu_uefi_device_status_to_string (FuUefiDeviceStatus status);
gboolean fu_uefi_device_get_update_info (FuUefiDevice *self,
efi_update_info_t *info,
FuUefiUpdateInfo *fu_uefi_device_load_update_info (FuUefiDevice *self,
GError **error);
G_END_DECLS

View File

@ -17,6 +17,7 @@
#include "fu-ucs2.h"
#include "fu-uefi-common.h"
#include "fu-uefi-device.h"
#include "fu-uefi-update-info.h"
#include "fu-uefi-vars.h"
/* custom return code */
@ -47,16 +48,6 @@ fu_util_private_free (FuUtilPrivate *priv)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuUtilPrivate, fu_util_private_free)
#pragma clang diagnostic pop
static const gchar *
fu_uefi_update_info_status_to_string (guint32 update_info_status)
{
if (update_info_status == EFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE)
return "attempt-update";
if (update_info_status == EFI_UPDATE_INFO_STATUS_ATTEMPTED)
return "attempted";
return "unknown";
}
int
main (int argc, char *argv[])
{
@ -241,29 +232,30 @@ main (int argc, char *argv[])
/* show the information of firmware update status */
if (action_info) {
efi_update_info_t info;
g_autofree gchar *guid = NULL;
for (guint i = 0; i < devices->len; i++) {
FuUefiDevice *dev = g_ptr_array_index (devices, i);
efi_guid_t guid_tmp;
g_autoptr(FuUefiUpdateInfo) info = NULL;
g_autoptr(GError) error_local = NULL;
if (!fu_uefi_device_get_update_info (dev, &info, &error_local)) {
/* load any existing update info */
info = fu_uefi_device_load_update_info (dev, &error_local);
if (info == NULL) {
g_printerr ("failed: %s\n", error_local->message);
continue;
}
memcpy (&guid_tmp, &info.guid, sizeof(efi_guid_t));
if (efi_guid_to_str (&guid_tmp, &guid) < 0) {
g_printerr ("failed to convert GUID: %s\n",
error_local->message);
continue;
}
g_print ("Information for the update status entry %u:\n", i);
g_print (" Information Version: %" G_GUINT32_FORMAT "\n", info.update_info_version);
g_print (" Firmware GUID: {%s}\n", guid);
g_print (" Capsule Flags: 0x%08" G_GUINT32_FORMAT "x\n", info.capsule_flags);
g_print (" Hardware Instance: %" G_GUINT64_FORMAT "\n", info.hw_inst);
g_print (" Update Status: %s\n", fu_uefi_update_info_status_to_string (info.status));
//g_print (" Capsule File Path: %s\n\n", info.capsule_fn);
g_print (" Information Version: %" G_GUINT32_FORMAT "\n",
fu_uefi_update_info_get_version (info));
g_print (" Firmware GUID: {%s}\n",
fu_uefi_update_info_get_guid (info));
g_print (" Capsule Flags: 0x%08" G_GUINT32_FORMAT "x\n",
fu_uefi_update_info_get_capsule_flags (info));
g_print (" Hardware Instance: %" G_GUINT64_FORMAT "\n",
fu_uefi_update_info_get_hw_inst (info));
g_print (" Update Status: %s\n",
fu_uefi_update_info_status_to_string (fu_uefi_update_info_get_status (info)));
g_print (" Capsule File Path: %s\n\n",
fu_uefi_update_info_get_capsule_fn (info));
}
}

View File

@ -0,0 +1,186 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2018 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include "config.h"
#include <gio/gio.h>
#include "fu-common.h"
#include "fu-uefi-update-info.h"
#include "fu-uefi-common.h"
#include "fu-ucs2.h"
#include "fwupd-error.h"
struct _FuUefiUpdateInfo {
GObject parent_instance;
guint32 version;
gchar *guid;
gchar *capsule_fn;
guint32 capsule_flags;
guint64 hw_inst;
FuUefiUpdateInfoStatus status;
};
G_DEFINE_TYPE (FuUefiUpdateInfo, fu_uefi_update_info, G_TYPE_OBJECT)
const gchar *
fu_uefi_update_info_status_to_string (FuUefiUpdateInfoStatus status)
{
if (status == FU_UEFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE)
return "attempt-update";
if (status == FU_UEFI_UPDATE_INFO_STATUS_ATTEMPTED)
return "attempted";
return "unknown";
}
static gchar *
fu_uefi_update_info_parse_dp (const guint8 *buf, gsize sz)
{
const_efidp idp;
guint16 ucs2sz = 0;
g_autofree gchar *relpath = NULL;
g_autofree guint16 *ucs2file = NULL;
g_return_val_if_fail (buf != NULL, NULL);
g_return_val_if_fail (sz != 0, NULL);
/* find UCS2 string */
idp = (const_efidp) buf;
while (1) {
if (efidp_type (idp) == EFIDP_END_TYPE &&
efidp_subtype (idp) == EFIDP_END_ENTIRE)
break;
if (efidp_type(idp) != EFIDP_MEDIA_TYPE ||
efidp_subtype (idp) != EFIDP_MEDIA_FILE) {
if (efidp_next_node (idp, &idp) < 0)
break;
continue;
}
ucs2sz = efidp_node_size (idp) - 4;
ucs2file = g_new0 (guint16, (ucs2sz / 2) + 1);
memcpy (ucs2file, (guint8 *)idp + 4, ucs2sz);
break;
}
/* nothing found */
if (ucs2file == NULL || ucs2sz == 0)
return NULL;
/* convert to something sane */
relpath = fu_ucs2_to_uft8 (ucs2file, ucs2sz / sizeof (guint16));
if (relpath == NULL)
return NULL;
g_strdelimit (relpath, "\\", '/');
return g_steal_pointer (&relpath);
}
gboolean
fu_uefi_update_info_parse (FuUefiUpdateInfo *self, const guint8 *buf, gsize sz, GError **error)
{
efi_update_info_t info;
efi_guid_t guid_tmp;
g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), FALSE);
if (sz < sizeof(efi_update_info_t)) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"EFI variable is corrupt");
return FALSE;
}
memcpy (&info, buf, sizeof(info));
self->version = info.update_info_version;
self->capsule_flags = info.capsule_flags;
self->hw_inst = info.hw_inst;
self->status = info.status;
memcpy (&guid_tmp, &info.guid, sizeof(efi_guid_t));
if (efi_guid_to_str (&guid_tmp, &self->guid) < 0) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"failed to convert GUID");
return FALSE;
}
if (sz > sizeof(efi_update_info_t)) {
self->capsule_fn = fu_uefi_update_info_parse_dp (buf + sizeof(efi_update_info_t),
sz - sizeof(efi_update_info_t));
}
return TRUE;
}
const gchar *
fu_uefi_update_info_get_guid (FuUefiUpdateInfo *self)
{
g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), NULL);
return self->guid;
}
const gchar *
fu_uefi_update_info_get_capsule_fn (FuUefiUpdateInfo *self)
{
g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), NULL);
return self->capsule_fn;
}
guint32
fu_uefi_update_info_get_version (FuUefiUpdateInfo *self)
{
g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), 0);
return self->version;
}
guint32
fu_uefi_update_info_get_capsule_flags (FuUefiUpdateInfo *self)
{
g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), 0);
return self->capsule_flags;
}
guint64
fu_uefi_update_info_get_hw_inst (FuUefiUpdateInfo *self)
{
g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), 0);
return self->hw_inst;
}
FuUefiUpdateInfoStatus
fu_uefi_update_info_get_status (FuUefiUpdateInfo *self)
{
g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), 0);
return self->status;
}
static void
fu_uefi_update_info_finalize (GObject *object)
{
FuUefiUpdateInfo *self = FU_UEFI_UPDATE_INFO (object);
g_free (self->guid);
g_free (self->capsule_fn);
G_OBJECT_CLASS (fu_uefi_update_info_parent_class)->finalize (object);
}
static void
fu_uefi_update_info_class_init (FuUefiUpdateInfoClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = fu_uefi_update_info_finalize;
}
static void
fu_uefi_update_info_init (FuUefiUpdateInfo *self)
{
}
FuUefiUpdateInfo *
fu_uefi_update_info_new (void)
{
FuUefiUpdateInfo *self;
self = g_object_new (FU_TYPE_UEFI_UPDATE_INFO, NULL);
return FU_UEFI_UPDATE_INFO (self);
}

View File

@ -0,0 +1,39 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2018 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef __FU_UEFI_UPDATE_INFO_H
#define __FU_UEFI_UPDATE_INFO_H
#include <glib-object.h>
G_BEGIN_DECLS
#define FU_TYPE_UEFI_UPDATE_INFO (fu_uefi_update_info_get_type ())
G_DECLARE_FINAL_TYPE (FuUefiUpdateInfo, fu_uefi_update_info, FU, UEFI_UPDATE_INFO, GObject)
typedef enum {
FU_UEFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE = 0x00000001,
FU_UEFI_UPDATE_INFO_STATUS_ATTEMPTED = 0x00000002,
} FuUefiUpdateInfoStatus;
const gchar *fu_uefi_update_info_status_to_string (FuUefiUpdateInfoStatus status);
FuUefiUpdateInfo *fu_uefi_update_info_new (void);
gboolean fu_uefi_update_info_parse (FuUefiUpdateInfo *self,
const guint8 *buf,
gsize sz,
GError **error);
guint32 fu_uefi_update_info_get_version (FuUefiUpdateInfo *self);
const gchar *fu_uefi_update_info_get_guid (FuUefiUpdateInfo *self);
const gchar *fu_uefi_update_info_get_capsule_fn (FuUefiUpdateInfo *self);
guint32 fu_uefi_update_info_get_capsule_flags (FuUefiUpdateInfo *self);
guint64 fu_uefi_update_info_get_hw_inst (FuUefiUpdateInfo *self);
FuUefiUpdateInfoStatus fu_uefi_update_info_get_status (FuUefiUpdateInfo *self);
G_END_DECLS
#endif /* __FU_UEFI_UPDATE_INFO_H */

View File

@ -11,6 +11,7 @@ shared_module('fu_plugin_uefi',
'fu-uefi-bootmgr.c',
'fu-uefi-common.c',
'fu-uefi-device.c',
'fu-uefi-update-info.c',
'fu-uefi-vars.c',
],
include_directories : [
@ -38,6 +39,7 @@ executable(
'fu-uefi-bootmgr.c',
'fu-uefi-common.c',
'fu-uefi-device.c',
'fu-uefi-update-info.c',
'fu-uefi-vars.c',
],
include_directories : [
@ -75,6 +77,7 @@ if get_option('tests')
'fu-uefi-bootmgr.c',
'fu-uefi-common.c',
'fu-uefi-device.c',
'fu-uefi-update-info.c',
'fu-uefi-vars.c',
'fu-ucs2.c',
],

View File

@ -1 +1,2 @@
EFI
efi/efivars/fwupdate-c34cb672-a81e-5d32-9d89-cbcabe8ec37b-0-0abba7dc-e516-4167-bbf5-4d9d1c739416