fwupd/plugins/optionrom/fu-optionrom-device.c
Richard Hughes fbd8b5d325 Add fu_device_dump_firmware()
Conceptually we were trying to stuff subtly different actions into one vfunc:

 * Read firmware from the device to update the verification checksums

 * Read a firmware blob from the device for debugging

For the first action we might want to mask out the sections of the flash with
serial numbers (so the verification hashes match the ones published on the LVFS)
and for the second we want just a raw ROM file from the hardware with no
pre-processing that we can compare against an external SPI dumper.

Split out ->dump_firmware to get the raw blob, and allow plugins to also
implement ->read_firmware() if they have to mask out specific offsets or remove
specific images from the FuFirmware container.

In the common case when masking is not required, fall back to using a 'binary'
FuFirmware automatically to make most plugins simpler.
2020-09-24 10:54:27 -05:00

128 lines
3.6 KiB
C

/*
* Copyright (C) 2015-2019 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include "config.h"
#include "fu-rom.h"
#include "fu-optionrom-device.h"
struct _FuOptionromDevice {
FuUdevDevice parent_instance;
};
G_DEFINE_TYPE (FuOptionromDevice, fu_optionrom_device, FU_TYPE_UDEV_DEVICE)
static gboolean
fu_optionrom_device_probe (FuUdevDevice *device, GError **error)
{
g_autofree gchar *fn = NULL;
/* does the device even have ROM? */
fn = g_build_filename (fu_udev_device_get_sysfs_path (device), "rom", NULL);
if (!g_file_test (fn, G_FILE_TEST_EXISTS)) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"Unable to read firmware from device");
return FALSE;
}
/* set the physical ID */
if (!fu_udev_device_set_physical_id (device, "pci", error))
return FALSE;
return TRUE;
}
static GBytes *
fu_optionrom_device_dump_firmware (FuDevice *device, GError **error)
{
FuUdevDevice *udev_device = FU_UDEV_DEVICE (device);
g_autoptr(GFile) file = NULL;
g_autofree gchar *rom_fn = NULL;
/* open the file */
rom_fn = g_build_filename (fu_udev_device_get_sysfs_path (udev_device), "rom", NULL);
if (rom_fn == NULL) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"Unable to read firmware from device");
return NULL;
}
file = g_file_new_for_path (rom_fn);
return fu_rom_dump_firmware (file, NULL, error);
}
static FuFirmware *
fu_optionrom_device_read_firmware (FuDevice *device, GError **error)
{
g_autofree gchar *guid = NULL;
g_autoptr(FuRom) rom = NULL;
g_autoptr(GBytes) blob = NULL;
g_autoptr(GBytes) fw = NULL;
/* open the file */
blob = fu_optionrom_device_dump_firmware (device, error);
if (blob == NULL)
return NULL;
rom = fu_rom_new ();
if (!fu_rom_load_data (rom, blob, FU_ROM_LOAD_FLAG_BLANK_PPID, NULL, error))
return NULL;
/* update version */
if (g_strcmp0 (fu_device_get_version (device),
fu_rom_get_version (rom)) != 0) {
g_debug ("changing version of %s from %s to %s",
fu_device_get_id (device),
fu_device_get_version (device),
fu_rom_get_version (rom));
fu_device_set_version (device, fu_rom_get_version (rom));
}
/* Also add the GUID from the firmware as the firmware may be more
* generic, which also allows us to match the GUID when doing 'verify'
* on a device with a different PID to the firmware */
/* update guid */
guid = g_strdup_printf ("PCI\\VEN_%04X&DEV_%04X",
fu_rom_get_vendor (rom),
fu_rom_get_model (rom));
fu_device_add_guid (device, guid);
/* get new data */
fw = fu_rom_get_data (rom);
return fu_firmware_new_from_bytes (fw);
}
static void
fu_optionrom_device_init (FuOptionromDevice *self)
{
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL);
fu_device_add_icon (FU_DEVICE (self), "audio-card");
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE);
fu_udev_device_set_flags (FU_UDEV_DEVICE (self),
FU_UDEV_DEVICE_FLAG_OPEN_READ |
FU_UDEV_DEVICE_FLAG_VENDOR_FROM_PARENT);
}
static void
fu_optionrom_device_finalize (GObject *object)
{
G_OBJECT_CLASS (fu_optionrom_device_parent_class)->finalize (object);
}
static void
fu_optionrom_device_class_init (FuOptionromDeviceClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
FuUdevDeviceClass *klass_udev_device = FU_UDEV_DEVICE_CLASS (klass);
object_class->finalize = fu_optionrom_device_finalize;
klass_device->read_firmware = fu_optionrom_device_read_firmware;
klass_device->dump_firmware = fu_optionrom_device_dump_firmware;
klass_udev_device->probe = fu_optionrom_device_probe;
}