diff --git a/plugins/dfu/tests/firmware.bin b/data/tests/firmware.bin similarity index 100% rename from plugins/dfu/tests/firmware.bin rename to data/tests/firmware.bin diff --git a/plugins/dfu/tests/firmware.hex b/data/tests/firmware.hex similarity index 100% rename from plugins/dfu/tests/firmware.hex rename to data/tests/firmware.hex diff --git a/data/tests/firmware.shex b/data/tests/firmware.shex new file mode 100644 index 000000000..041286463 --- /dev/null +++ b/data/tests/firmware.shex @@ -0,0 +1,11 @@ +:100000003DEF20F000000000FACF01F0FBCF02F03E +:10001000E9CF03F0EACF04F0E1CF05F0E2CF06F03C +:10002000D9CF07F0DACF08F0F3CF09F0F4CF0AF018 +:10003000F6CF0BF0F7CF0CF0F8CF0DF0F5CF0EF0B8 +:100040000EC0F5FF0DC0F8FF0CC0F7FF0BC0F6FFA8 +:100050000AC0F4FF09C0F3FF08C0DAFF07C0D9FFE8 +:1000600006C0E2FF05C0E1FF04C0EAFF03C0E9FFEC +:1000700002C0FBFF01C0FAFF11003FEF20F00001BA +:0800800042EF20F03DEF20F0FB +:080000FD6465616462656566DB +:00000001FF diff --git a/plugins/dfu/tests/firmware.srec b/data/tests/firmware.srec similarity index 100% rename from plugins/dfu/tests/firmware.srec rename to data/tests/firmware.srec diff --git a/plugins/altos/fu-altos-device.c b/plugins/altos/fu-altos-device.c index 2dda22e2c..300f3aa2a 100644 --- a/plugins/altos/fu-altos-device.c +++ b/plugins/altos/fu-altos-device.c @@ -268,19 +268,31 @@ fu_altos_device_write_page (FuAltosDevice *self, return TRUE; } +static FuFirmware * +fu_altos_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuFirmware) firmware = fu_altos_firmware_new (); + if (!fu_firmware_parse (firmware, fw, flags, error)) + return FALSE; + return g_steal_pointer (&firmware); +} + static gboolean fu_altos_device_write_firmware (FuDevice *device, - GBytes *fw, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { FuAltosDevice *self = FU_ALTOS_DEVICE (device); - GBytes *fw_blob; const gchar *data; const gsize data_len; guint flash_len; - g_autoptr(FuAltosFirmware) altos_firmware = NULL; g_autoptr(FuDeviceLocker) locker = NULL; + g_autoptr(FuFirmwareImage) img = NULL; + g_autoptr(GBytes) fw = NULL; g_autoptr(GString) buf = g_string_new (NULL); /* check kind */ @@ -312,25 +324,27 @@ fu_altos_device_write_firmware (FuDevice *device, } /* load ihex blob */ - altos_firmware = fu_altos_firmware_new (); - if (!fu_altos_firmware_parse (altos_firmware, fw, error)) + img = fu_firmware_get_image_default (firmware, error); + if (img == NULL) return FALSE; /* check the start address */ - if (fu_altos_firmware_get_address (altos_firmware) != self->addr_base) { + if (fu_firmware_image_get_addr (img) != self->addr_base) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "start address not correct %" G_GUINT64_FORMAT ":" "%" G_GUINT64_FORMAT, - fu_altos_firmware_get_address (altos_firmware), + fu_firmware_image_get_addr (img), self->addr_base); return FALSE; } /* check firmware will fit */ - fw_blob = fu_altos_firmware_get_data (altos_firmware); - data = g_bytes_get_data (fw_blob, (gsize *) &data_len); + fw = fu_firmware_image_get_bytes (img, error); + if (fw == NULL) + return FALSE; + data = g_bytes_get_data (fw, (gsize *) &data_len); if (data_len > flash_len) { g_set_error (error, FWUPD_ERROR, @@ -628,6 +642,7 @@ fu_altos_device_class_init (FuAltosDeviceClass *klass) GObjectClass *object_class = G_OBJECT_CLASS (klass); FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); klass_device->probe = fu_altos_device_probe; + klass_device->prepare_firmware = fu_altos_device_prepare_firmware; klass_device->write_firmware = fu_altos_device_write_firmware; klass_device->read_firmware = fu_altos_device_read_firmware; object_class->finalize = fu_altos_device_finalize; diff --git a/plugins/altos/fu-altos-firmware.c b/plugins/altos/fu-altos-firmware.c index 79af716c3..5b2d24fab 100644 --- a/plugins/altos/fu-altos-firmware.c +++ b/plugins/altos/fu-altos-firmware.c @@ -1,45 +1,34 @@ /* - * Copyright (C) 2017 Richard Hughes + * Copyright (C) 2017-2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" -#include #include #include #include "fu-altos-firmware.h" -#include "fwupd-error.h" struct _FuAltosFirmware { - GObject parent_instance; - GBytes *data; - guint64 address; + FuFirmware parent_instance; }; -G_DEFINE_TYPE (FuAltosFirmware, fu_altos_firmware, G_TYPE_OBJECT) +G_DEFINE_TYPE (FuAltosFirmware, fu_altos_firmware, FU_TYPE_FIRMWARE) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC(Elf, elf_end); #pragma clang diagnostic pop -GBytes * -fu_altos_firmware_get_data (FuAltosFirmware *self) -{ - return self->data; -} - -guint64 -fu_altos_firmware_get_address (FuAltosFirmware *self) -{ - return self->address; -} - -gboolean -fu_altos_firmware_parse (FuAltosFirmware *self, GBytes *blob, GError **error) +static gboolean +fu_altos_firmware_parse (FuFirmware *firmware, + GBytes *blob, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) { const gchar *name; Elf_Scn *scn = NULL; @@ -99,8 +88,12 @@ fu_altos_firmware_parse (FuAltosFirmware *self, GBytes *blob, GError **error) if (g_strcmp0 (name, ".text") == 0) { Elf_Data *data = elf_getdata (scn, NULL); if (data != NULL && data->d_buf != NULL) { - self->data = g_bytes_new (data->d_buf, data->d_size); - self->address = shdr.sh_addr; + g_autoptr(FuFirmwareImage) img = NULL; + g_autoptr(GBytes) bytes = NULL; + bytes = g_bytes_new (data->d_buf, data->d_size); + img = fu_firmware_image_new (bytes); + fu_firmware_image_set_addr (img, shdr.sh_addr); + fu_firmware_add_image (firmware, img); } return TRUE; } @@ -112,22 +105,11 @@ fu_altos_firmware_parse (FuAltosFirmware *self, GBytes *blob, GError **error) return FALSE; } -static void -fu_altos_firmware_finalize (GObject *object) -{ - FuAltosFirmware *self = FU_ALTOS_FIRMWARE (object); - - if (self->data != NULL) - g_bytes_unref (self->data); - - G_OBJECT_CLASS (fu_altos_firmware_parent_class)->finalize (object); -} - static void fu_altos_firmware_class_init (FuAltosFirmwareClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->finalize = fu_altos_firmware_finalize; + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + klass_firmware->parse = fu_altos_firmware_parse; } static void @@ -135,10 +117,8 @@ fu_altos_firmware_init (FuAltosFirmware *self) { } -FuAltosFirmware * +FuFirmware * fu_altos_firmware_new (void) { - FuAltosFirmware *self; - self = g_object_new (FU_TYPE_ALTOS_FIRMWARE, NULL); - return FU_ALTOS_FIRMWARE (self); + return FU_FIRMWARE (g_object_new (FU_TYPE_ALTOS_FIRMWARE, NULL)); } diff --git a/plugins/altos/fu-altos-firmware.h b/plugins/altos/fu-altos-firmware.h index 9051161ef..939a86336 100644 --- a/plugins/altos/fu-altos-firmware.h +++ b/plugins/altos/fu-altos-firmware.h @@ -1,22 +1,19 @@ /* - * Copyright (C) 2017 Richard Hughes + * Copyright (C) 2017-2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ #pragma once +#include "fu-firmware.h" + G_BEGIN_DECLS #define FU_TYPE_ALTOS_FIRMWARE (fu_altos_firmware_get_type ()) -G_DECLARE_FINAL_TYPE (FuAltosFirmware, fu_altos_firmware, FU, ALTOS_FIRMWARE, GObject) +G_DECLARE_FINAL_TYPE (FuAltosFirmware, fu_altos_firmware, FU, ALTOS_FIRMWARE, FuFirmware) -FuAltosFirmware *fu_altos_firmware_new (void); -GBytes *fu_altos_firmware_get_data (FuAltosFirmware *self); -guint64 fu_altos_firmware_get_address (FuAltosFirmware *self); -gboolean fu_altos_firmware_parse (FuAltosFirmware *self, - GBytes *blob, - GError **error); +FuFirmware *fu_altos_firmware_new (void); G_END_DECLS diff --git a/plugins/ata/fu-ata-device.c b/plugins/ata/fu-ata-device.c index 53db4a4eb..73858d4ab 100644 --- a/plugins/ata/fu-ata-device.c +++ b/plugins/ata/fu-ata-device.c @@ -578,15 +578,21 @@ fu_ata_device_fw_download (FuAtaDevice *self, static gboolean fu_ata_device_write_firmware (FuDevice *device, - GBytes *fw, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { FuAtaDevice *self = FU_ATA_DEVICE (device); guint32 chunksz = (guint32) self->transfer_blocks * FU_ATA_BLOCK_SIZE; guint max_size = 0xffff * FU_ATA_BLOCK_SIZE; + g_autoptr(GBytes) fw = NULL; g_autoptr(GPtrArray) chunks = NULL; + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + /* only one block allowed */ if (self->transfer_mode == ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNK) max_size = 0xffff; diff --git a/plugins/colorhug/fu-colorhug-device.c b/plugins/colorhug/fu-colorhug-device.c index cfc4d95c4..1a393ab91 100644 --- a/plugins/colorhug/fu-colorhug-device.c +++ b/plugins/colorhug/fu-colorhug-device.c @@ -328,13 +328,19 @@ ch_colorhug_device_calculate_checksum (const guint8 *data, guint32 len) static gboolean fu_colorhug_device_write_firmware (FuDevice *device, - GBytes *fw, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { FuColorhugDevice *self = FU_COLORHUG_DEVICE (device); + g_autoptr(GBytes) fw = NULL; g_autoptr(GPtrArray) chunks = NULL; + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + /* build packets */ chunks = fu_chunk_array_new_from_bytes (fw, self->start_addr, diff --git a/plugins/csr/fu-csr-device.c b/plugins/csr/fu-csr-device.c index 6a96e3a1f..559a93cd6 100644 --- a/plugins/csr/fu-csr-device.c +++ b/plugins/csr/fu-csr-device.c @@ -10,9 +10,9 @@ #include "fu-chunk.h" #include "fu-csr-device.h" +#include "fu-ihex-firmware.h" #include "dfu-common.h" -#include "dfu-firmware.h" /** * FU_CSR_DEVICE_QUIRK_FLAG_REQUIRE_DELAY: @@ -416,71 +416,44 @@ fu_csr_device_download_chunk (FuCsrDevice *self, guint16 idx, GBytes *chunk, GEr return TRUE; } -static GBytes * -_dfu_firmware_get_default_element_data (DfuFirmware *firmware) -{ - DfuElement *element; - DfuImage *image; - image = dfu_firmware_get_image_default (firmware); - if (image == NULL) - return NULL; - element = dfu_image_get_element_default (image); - if (element == NULL) - return NULL; - return dfu_element_get_contents (element); -} - -static GBytes * +static FuFirmware * fu_csr_device_prepare_firmware (FuDevice *device, GBytes *fw, FwupdInstallFlags flags, GError **error) { - GBytes *blob_noftr; - g_autoptr(DfuFirmware) dfu_firmware = dfu_firmware_new (); + g_autoptr(FuFirmware) firmware = fu_ihex_firmware_new (); /* parse the file */ - if (!dfu_firmware_parse_data (dfu_firmware, fw, - DFU_FIRMWARE_PARSE_FLAG_NONE, error)) + if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL) { g_autofree gchar *fw_str = NULL; - fw_str = dfu_firmware_to_string (dfu_firmware); + fw_str = fu_firmware_to_string (firmware); g_debug ("%s", fw_str); } - if (dfu_firmware_get_format (dfu_firmware) != DFU_FIRMWARE_FORMAT_DFU) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "expected DFU firmware"); - return NULL; - } - - /* get the blob from the firmware file */ - blob_noftr = _dfu_firmware_get_default_element_data (dfu_firmware); - if (blob_noftr == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "firmware contained no data"); - return NULL; - } /* success */ - return g_bytes_ref (blob_noftr); + return g_steal_pointer (&firmware); } static gboolean fu_csr_device_download (FuDevice *device, - GBytes *blob, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { FuCsrDevice *self = FU_CSR_DEVICE (device); guint16 idx; g_autoptr(GBytes) blob_empty = NULL; + g_autoptr(GBytes) blob = NULL; g_autoptr(GPtrArray) chunks = NULL; + /* get default image */ + blob = fu_firmware_get_image_default_bytes (firmware, error); + if (blob == NULL) + return FALSE; + /* notify UI */ fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); diff --git a/plugins/dell-dock/fu-dell-dock-hub.c b/plugins/dell-dock/fu-dell-dock-hub.c index 4f4bc4a20..41516976a 100644 --- a/plugins/dell-dock/fu-dell-dock-hub.c +++ b/plugins/dell-dock/fu-dell-dock-hub.c @@ -46,22 +46,29 @@ fu_dell_dock_hub_probe (FuDevice *device, GError **error) static gboolean fu_dell_dock_hub_write_fw (FuDevice *device, - GBytes *blob_fw, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { FuDellDockHub *self = FU_DELL_DOCK_HUB (device); gsize fw_size = 0; - const guint8 *data = g_bytes_get_data (blob_fw, &fw_size); + const guint8 *data; gsize write_size = (fw_size / HIDI2C_MAX_WRITE) >= 1 ? HIDI2C_MAX_WRITE : fw_size; gsize nwritten = 0; guint32 address = 0; gboolean result = FALSE; g_autofree gchar *dynamic_version = NULL; + g_autoptr(GBytes) fw = NULL; g_return_val_if_fail (device != NULL, FALSE); - g_return_val_if_fail (blob_fw != NULL, FALSE); + g_return_val_if_fail (FU_IS_FIRMWARE (firmware), FALSE); + + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + data = g_bytes_get_data (fw, &fw_size); dynamic_version = g_strdup_printf ("%02x.%02x", data[self->blob_major_offset], diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.c b/plugins/dell-dock/fu-dell-dock-i2c-ec.c index e4c22ba32..6d3c9a5cb 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.c @@ -745,7 +745,7 @@ fu_dell_dock_ec_commit_package (FuDevice *device, GBytes *blob_fw, static gboolean fu_dell_dock_ec_write_fw (FuDevice *device, - GBytes *blob_fw, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { @@ -753,15 +753,22 @@ fu_dell_dock_ec_write_fw (FuDevice *device, FuDellDockECFWUpdateStatus status = FW_UPDATE_IN_PROGRESS; guint8 progress1 = 0, progress0 = 0; gsize fw_size = 0; - const guint8 *data = g_bytes_get_data (blob_fw, &fw_size); + const guint8 *data; gsize write_size = (fw_size / HIDI2C_MAX_WRITE) >= 1 ? HIDI2C_MAX_WRITE : fw_size; gsize nwritten = 0; guint32 address = 0 | 0xff << 24; g_autofree gchar *dynamic_version = NULL; + g_autoptr(GBytes) fw = NULL; g_return_val_if_fail (device != NULL, FALSE); - g_return_val_if_fail (blob_fw != NULL, FALSE); + g_return_val_if_fail (FU_IS_FIRMWARE (firmware), FALSE); + + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + data = g_bytes_get_data (fw, &fw_size); dynamic_version = g_strndup ((gchar *) data + self->blob_version_offset, 11); g_debug ("writing EC firmware version %s", dynamic_version); diff --git a/plugins/dell-dock/fu-dell-dock-i2c-mst.c b/plugins/dell-dock/fu-dell-dock-i2c-mst.c index c42c2ec50..c8eb4d4f2 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-mst.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-mst.c @@ -735,7 +735,7 @@ fu_dell_dock_mst_invalidate_bank (FuDevice *symbiote, MSTBank bank_in_use, static gboolean fu_dell_dock_mst_write_fw (FuDevice *device, - GBytes *blob_fw, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { @@ -745,13 +745,20 @@ fu_dell_dock_mst_write_fw (FuDevice *device, gboolean checksum = FALSE; guint8 order[2] = {ESM, Bank0}; guint16 chip_id; - const guint8* data = g_bytes_get_data (blob_fw, NULL); + const guint8 *data; g_autofree gchar *dynamic_version = NULL; + g_autoptr(GBytes) fw = NULL; g_return_val_if_fail (device != NULL, FALSE); - g_return_val_if_fail (blob_fw != NULL, FALSE); + g_return_val_if_fail (FU_IS_FIRMWARE (firmware), FALSE); g_return_val_if_fail (self->symbiote != NULL, FALSE); + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + data = g_bytes_get_data (fw, NULL); + dynamic_version = g_strdup_printf ("%02x.%02x.%02x", data[self->blob_major_offset], data[self->blob_minor_offset], @@ -787,7 +794,7 @@ fu_dell_dock_mst_write_fw (FuDevice *device, for (guint phase = 0; phase < 2; phase++) { g_debug ("MST: Checking bank %u", order[phase]); if (!fu_dell_dock_mst_checksum_bank (self->symbiote, - blob_fw, + fw, order[phase], &checksum, error)) return FALSE; @@ -804,11 +811,11 @@ fu_dell_dock_mst_write_fw (FuDevice *device, error)) return FALSE; fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); - if (!fu_dell_dock_write_flash_bank (device, blob_fw, + if (!fu_dell_dock_write_flash_bank (device, fw, order[phase], error)) return FALSE; if (!fu_dell_dock_mst_checksum_bank (self->symbiote, - blob_fw, + fw, order[phase], &checksum, error)) diff --git a/plugins/dell-dock/fu-dell-dock-i2c-tbt.c b/plugins/dell-dock/fu-dell-dock-i2c-tbt.c index 8b0db5935..79c00834b 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-tbt.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-tbt.c @@ -53,20 +53,27 @@ G_DEFINE_TYPE (FuDellDockTbt, fu_dell_dock_tbt, FU_TYPE_DEVICE) static gboolean fu_dell_dock_tbt_write_fw (FuDevice *device, - GBytes *blob_fw, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { FuDellDockTbt *self = FU_DELL_DOCK_TBT (device); guint32 start_offset = 0; - gsize image_size; - const guint8 *buffer = g_bytes_get_data (blob_fw, &image_size); + gsize image_size = 0; + const guint8 *buffer; guint16 target_system = 0; g_autoptr(GTimer) timer = g_timer_new (); g_autofree gchar *dynamic_version = NULL; + g_autoptr(GBytes) fw = NULL; g_return_val_if_fail (device != NULL, FALSE); - g_return_val_if_fail (blob_fw != NULL, FALSE); + g_return_val_if_fail (FU_IS_FIRMWARE (firmware), FALSE); + + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + buffer = g_bytes_get_data (fw, &image_size); dynamic_version = g_strdup_printf ("%02x.%02x", buffer[self->blob_major_offset], diff --git a/plugins/dell-dock/fu-dell-dock-status.c b/plugins/dell-dock/fu-dell-dock-status.c index 3565a4c11..9c803bfbd 100644 --- a/plugins/dell-dock/fu-dell-dock-status.c +++ b/plugins/dell-dock/fu-dell-dock-status.c @@ -58,7 +58,7 @@ fu_dell_dock_status_setup (FuDevice *device, GError **error) static gboolean fu_dell_dock_status_write (FuDevice *device, - GBytes *blob_fw, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { @@ -66,18 +66,25 @@ fu_dell_dock_status_write (FuDevice *device, FuDevice *parent; gsize length = 0; guint32 status_version = 0; - const guint8 *data = g_bytes_get_data (blob_fw, &length); + const guint8 *data; g_autofree gchar *dynamic_version = NULL; + g_autoptr(GBytes) fw = NULL; g_return_val_if_fail (device != NULL, FALSE); - g_return_val_if_fail (blob_fw != NULL, FALSE); + g_return_val_if_fail (FU_IS_FIRMWARE (firmware), FALSE); + + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + data = g_bytes_get_data (fw, &length); memcpy (&status_version, data + self->blob_version_offset, sizeof (guint32)); dynamic_version = fu_dell_dock_status_ver_string (status_version); g_debug ("writing status firmware version %s", dynamic_version); parent = fu_device_get_parent (device); - if (!fu_dell_dock_ec_commit_package (parent, blob_fw, error)) + if (!fu_dell_dock_ec_commit_package (parent, fw, error)) return FALSE; /* dock will reboot to re-read; this is to appease the daemon */ diff --git a/plugins/dfu/dfu-common.c b/plugins/dfu/dfu-common.c index b0acab376..f0d9df69b 100644 --- a/plugins/dfu/dfu-common.c +++ b/plugins/dfu/dfu-common.c @@ -176,157 +176,3 @@ dfu_utils_bytes_join_array (GPtrArray *chunks) } return g_bytes_new_take (buffer, total_size); } - -/** - * dfu_utils_bytes_pad: - * @bytes: a #GBytes - * @sz: the desired size in bytes - * - * Pads a GBytes to a given @sz with `0xff`. - * - * Return value: (transfer full): a #GBytes - **/ -GBytes * -dfu_utils_bytes_pad (GBytes *bytes, gsize sz) -{ - gsize bytes_sz; - - g_return_val_if_fail (g_bytes_get_size (bytes) <= sz, NULL); - - /* pad */ - bytes_sz = g_bytes_get_size (bytes); - if (bytes_sz < sz) { - const guint8 *data = g_bytes_get_data (bytes, NULL); - guint8 *data_new = g_malloc (sz); - memcpy (data_new, data, bytes_sz); - memset (data_new + bytes_sz, 0xff, sz - bytes_sz); - return g_bytes_new_take (data_new, sz); - } - - /* exactly right */ - return g_bytes_ref (bytes); -} - -/** - * dfu_utils_buffer_parse_uint4: - * @data: a string - * - * Parses a base 16 number from a string. - * - * The string MUST be at least 1 byte long as this function cannot check the - * length of @data. Checking the size must be done in the caller. - * - * Return value: A parsed value, or 0 for error - **/ -guint8 -dfu_utils_buffer_parse_uint4 (const gchar *data) -{ - gchar buffer[2]; - memcpy (buffer, data, 1); - buffer[1] = '\0'; - return (guint8) g_ascii_strtoull (buffer, NULL, 16); -} - -/** - * dfu_utils_buffer_parse_uint8: - * @data: a string - * - * Parses a base 16 number from a string. - * - * The string MUST be at least 2 bytes long as this function cannot check the - * length of @data. Checking the size must be done in the caller. - * - * Return value: A parsed value, or 0 for error - **/ -guint8 -dfu_utils_buffer_parse_uint8 (const gchar *data) -{ - gchar buffer[3]; - memcpy (buffer, data, 2); - buffer[2] = '\0'; - return (guint8) g_ascii_strtoull (buffer, NULL, 16); -} - -/** - * dfu_utils_buffer_parse_uint16: - * @data: a string - * - * Parses a base 16 number from a string. - * - * The string MUST be at least 4 bytes long as this function cannot check the - * length of @data. Checking the size must be done in the caller. - * - * Return value: A parsed value, or 0 for error - **/ -guint16 -dfu_utils_buffer_parse_uint16 (const gchar *data) -{ - gchar buffer[5]; - memcpy (buffer, data, 4); - buffer[4] = '\0'; - return (guint16) g_ascii_strtoull (buffer, NULL, 16); -} - -/** - * dfu_utils_buffer_parse_uint24: - * @data: a string - * - * Parses a base 16 number from a string. - * - * The string MUST be at least 6 bytes long as this function cannot check the - * length of @data. Checking the size must be done in the caller. - * - * Return value: A parsed value, or 0 for error - **/ -guint32 -dfu_utils_buffer_parse_uint24 (const gchar *data) -{ - gchar buffer[7]; - memcpy (buffer, data, 6); - buffer[6] = '\0'; - return (guint32) g_ascii_strtoull (buffer, NULL, 16); -} - -/** - * dfu_utils_buffer_parse_uint32: - * @data: a string - * - * Parses a base 16 number from a string. - * - * The string MUST be at least 8 bytes long as this function cannot check the - * length of @data. Checking the size must be done in the caller. - * - * Return value: A parsed value, or 0 for error - **/ -guint32 -dfu_utils_buffer_parse_uint32 (const gchar *data) -{ - gchar buffer[9]; - memcpy (buffer, data, 8); - buffer[8] = '\0'; - return (guint32) g_ascii_strtoull (buffer, NULL, 16); -} - -/** - * dfu_utils_strnsplit: - * @str: a string to split - * @sz: size of @str - * @delimiter: a string which specifies the places at which to split the string - * @max_tokens: the maximum number of pieces to split @str into - * - * Splits a string into a maximum of @max_tokens pieces, using the given - * delimiter. If @max_tokens is reached, the remainder of string is appended - * to the last token. - * - * Return value: a newly-allocated NULL-terminated array of strings - **/ -gchar ** -dfu_utils_strnsplit (const gchar *str, gsize sz, - const gchar *delimiter, gint max_tokens) -{ - if (str[sz - 1] != '\0') { - g_autofree gchar *str2 = g_strndup (str, sz); - return g_strsplit (str2, delimiter, max_tokens); - } - return g_strsplit (str, delimiter, max_tokens); -} diff --git a/plugins/dfu/dfu-common.h b/plugins/dfu/dfu-common.h index 19a782eff..148a30b86 100644 --- a/plugins/dfu/dfu-common.h +++ b/plugins/dfu/dfu-common.h @@ -156,16 +156,5 @@ const gchar *dfu_version_to_string (DfuVersion version); /* helpers */ GBytes *dfu_utils_bytes_join_array (GPtrArray *chunks); -GBytes *dfu_utils_bytes_pad (GBytes *bytes, - gsize sz); -guint8 dfu_utils_buffer_parse_uint4 (const gchar *data); -guint8 dfu_utils_buffer_parse_uint8 (const gchar *data); -guint16 dfu_utils_buffer_parse_uint16 (const gchar *data); -guint32 dfu_utils_buffer_parse_uint24 (const gchar *data); -guint32 dfu_utils_buffer_parse_uint32 (const gchar *data); -gchar **dfu_utils_strnsplit (const gchar *str, - gsize sz, - const gchar *delimiter, - gint max_tokens); G_END_DECLS diff --git a/plugins/dfu/dfu-device.c b/plugins/dfu/dfu-device.c index f55c23f14..4a50d4ad0 100644 --- a/plugins/dfu/dfu-device.c +++ b/plugins/dfu/dfu-device.c @@ -86,6 +86,7 @@ #include "dfu-target-stm.h" #include "fu-device-locker.h" +#include "fu-firmware-common.h" #include "fwupd-error.h" @@ -1120,8 +1121,8 @@ dfu_device_detach (DfuDevice *device, GError **error) g_autoptr(GError) error_jabra = NULL; /* parse string and create magic packet */ - rep = dfu_utils_buffer_parse_uint8 (priv->jabra_detach + 0); - adr = dfu_utils_buffer_parse_uint8 (priv->jabra_detach + 2); + rep = fu_firmware_strparse_uint8 (priv->jabra_detach + 0); + adr = fu_firmware_strparse_uint8 (priv->jabra_detach + 2); buf[0] = rep; buf[1] = adr; buf[2] = 0x00; @@ -2052,7 +2053,7 @@ dfu_device_set_quirk_kv (FuDevice *device, } if (g_strcmp0 (key, FU_QUIRKS_DFU_FORCE_VERSION) == 0) { if (value != NULL && strlen (value) == 4) { - priv->force_version = dfu_utils_buffer_parse_uint16 (value); + priv->force_version = fu_firmware_strparse_uint16 (value); return TRUE; } g_set_error_literal (error, diff --git a/plugins/dfu/dfu-element.c b/plugins/dfu/dfu-element.c index aa146fc52..23f015065 100644 --- a/plugins/dfu/dfu-element.c +++ b/plugins/dfu/dfu-element.c @@ -239,60 +239,3 @@ dfu_element_set_target_size (DfuElement *element, guint32 target_size) g_bytes_unref (priv->contents); priv->contents = g_bytes_new_take (buf, target_size); } - -/** - * dfu_element_get_contents_chunk: - * @element: a #DfuElement - * @address: an address greater than dfu_element_get_address() - * @chunk_sz_max: the size of the new chunk - * @error: a #GError, or %NULL - * - * Gets a block of data from the @element. If the contents of the element is - * smaller than the requested chunk size then the #GBytes will be smaller - * than @chunk_sz_max. Use dfu_utils_bytes_pad() if padding is required. - * - * If the @address is larger than the size of the @element then an error is returned. - * - * Return value: (transfer full): a #GBytes, or %NULL - **/ -GBytes * -dfu_element_get_contents_chunk (DfuElement *element, - guint32 address, - guint32 chunk_sz_max, - GError **error) -{ - GBytes *blob; - gsize chunk_left; - guint32 offset; - - /* check address requested is larger than base address */ - if (address < dfu_element_get_address (element)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "requested address 0x%x less than base address 0x%x", - (guint) address, (guint) dfu_element_get_address (element)); - return NULL; - } - - /* offset into data */ - offset = address - dfu_element_get_address (element); - blob = dfu_element_get_contents (element); - if (offset > g_bytes_get_size (blob)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "offset 0x%x larger than data size 0x%x", - (guint) offset, - (guint) g_bytes_get_size (blob)); - return NULL; - } - - /* if we have less data than requested */ - chunk_left = g_bytes_get_size (blob) - offset; - if (chunk_sz_max > chunk_left) - return g_bytes_new_from_bytes (blob, offset, chunk_left); - - /* check chunk */ - return g_bytes_new_from_bytes (blob, offset, chunk_sz_max); -} diff --git a/plugins/dfu/dfu-element.h b/plugins/dfu/dfu-element.h index b6a60a1d0..ee838c49b 100644 --- a/plugins/dfu/dfu-element.h +++ b/plugins/dfu/dfu-element.h @@ -23,11 +23,6 @@ DfuElement *dfu_element_new (void); GBytes *dfu_element_get_contents (DfuElement *element); guint32 dfu_element_get_address (DfuElement *element); -GBytes *dfu_element_get_contents_chunk (DfuElement *element, - guint32 address, - guint32 chunk_sz_max, - GError **error); - void dfu_element_set_contents (DfuElement *element, GBytes *contents); void dfu_element_set_address (DfuElement *element, diff --git a/plugins/dfu/dfu-format-ihex.c b/plugins/dfu/dfu-format-ihex.c index 22f5dda29..9bea8a763 100644 --- a/plugins/dfu/dfu-format-ihex.c +++ b/plugins/dfu/dfu-format-ihex.c @@ -15,6 +15,9 @@ #include "dfu-format-ihex.h" #include "dfu-image.h" +#include "fu-firmware-common.h" +#include "fu-ihex-firmware.h" + #include "fwupd-error.h" /** @@ -46,34 +49,6 @@ dfu_firmware_detect_ihex (GBytes *bytes) return DFU_FIRMWARE_FORMAT_UNKNOWN; } -#define DFU_INHX32_RECORD_TYPE_DATA 0x00 -#define DFU_INHX32_RECORD_TYPE_EOF 0x01 -#define DFU_INHX32_RECORD_TYPE_EXTENDED_SEGMENT 0x02 -#define DFU_INHX32_RECORD_TYPE_START_SEGMENT 0x03 -#define DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR 0x04 -#define DFU_INHX32_RECORD_TYPE_START_LINEAR 0x05 -#define DFU_INHX32_RECORD_TYPE_SIGNATURE 0xfd - -static const gchar * -dfu_firmware_ihex_record_type_to_string (guint8 record_type) -{ - if (record_type == DFU_INHX32_RECORD_TYPE_DATA) - return "DATA"; - if (record_type == DFU_INHX32_RECORD_TYPE_EOF) - return "EOF"; - if (record_type == DFU_INHX32_RECORD_TYPE_EXTENDED_SEGMENT) - return "EXTENDED_SEGMENT"; - if (record_type == DFU_INHX32_RECORD_TYPE_START_SEGMENT) - return "START_SEGMENT"; - if (record_type == DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR) - return "EXTENDED_LINEAR"; - if (record_type == DFU_INHX32_RECORD_TYPE_START_LINEAR) - return "ADDR32"; - if (record_type == DFU_INHX32_RECORD_TYPE_SIGNATURE) - return "SIGNATURE"; - return NULL; -} - /** * dfu_firmware_from_ihex: (skip) * @firmware: a #DfuFirmware @@ -91,315 +66,28 @@ dfu_firmware_from_ihex (DfuFirmware *firmware, DfuFirmwareParseFlags flags, GError **error) { - const gchar *data; - gboolean got_eof = FALSE; - gsize sz = 0; - guint32 abs_addr = 0x0; - guint32 addr_last = 0x0; - guint32 base_addr = G_MAXUINT32; - guint32 seg_addr = 0x0; - g_auto(GStrv) lines = NULL; - g_autoptr(DfuElement) element = NULL; - g_autoptr(DfuImage) image = NULL; - g_autoptr(GBytes) contents = NULL; - g_autoptr(GString) buf = g_string_new (NULL); - g_autoptr(GString) buf_signature = g_string_new (NULL); + g_autoptr(FuFirmware) firmware_new = fu_ihex_firmware_new (); + g_autoptr(GPtrArray) imgs = NULL; + FwupdInstallFlags flags_new = FWUPD_INSTALL_FLAG_NONE; - g_return_val_if_fail (bytes != NULL, FALSE); - - /* create element */ - image = dfu_image_new (); - dfu_image_set_name (image, "ihex"); - element = dfu_element_new (); - - /* parse records */ - data = g_bytes_get_data (bytes, &sz); - lines = dfu_utils_strnsplit (data, sz, "\n", -1); - for (guint ln = 0; lines[ln] != NULL; ln++) { - const gchar *line = lines[ln]; - gsize linesz; - guint32 addr; - guint8 byte_cnt; - guint8 record_type; - guint line_end; - - /* ignore comments */ - if (g_str_has_prefix (line, ";")) - continue; - - /* ignore blank lines */ - g_strdelimit (lines[ln], "\r\x1a", '\0'); - linesz = strlen (line); - if (linesz == 0) - continue; - - /* check starting token */ - if (line[0] != ':') { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "invalid starting token on line %u: %s", - ln + 1, line); - return FALSE; - } - - /* check there's enough data for the smallest possible record */ - if (linesz < 11) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "line %u is incomplete, length %u", - ln + 1, (guint) linesz); - return FALSE; - } - - /* length, 16-bit address, type */ - byte_cnt = dfu_utils_buffer_parse_uint8 (line + 1); - addr = dfu_utils_buffer_parse_uint16 (line + 3); - record_type = dfu_utils_buffer_parse_uint8 (line + 7); - g_debug ("%s:", dfu_firmware_ihex_record_type_to_string (record_type)); - g_debug (" addr_start:\t0x%04x", addr); - g_debug (" length:\t0x%02x", byte_cnt); - addr += seg_addr; - addr += abs_addr; - g_debug (" addr:\t0x%08x", addr); - - /* position of checksum */ - line_end = 9 + byte_cnt * 2; - if (line_end > (guint) linesz) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "line %u malformed, length: %u", - ln + 1, line_end); - return FALSE; - } - - /* verify checksum */ - if ((flags & DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST) == 0) { - guint8 checksum = 0; - for (guint i = 1; i < line_end + 2; i += 2) { - guint8 data_tmp = dfu_utils_buffer_parse_uint8 (line + i); - checksum += data_tmp; - } - if (checksum != 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "line %u has invalid checksum (0x%02x)", - ln + 1, checksum); - return FALSE; - } - } - - /* process different record types */ - switch (record_type) { - case DFU_INHX32_RECORD_TYPE_DATA: - /* base address for element */ - if (base_addr == G_MAXUINT32) - base_addr = addr; - - /* does not make sense */ - if (addr < addr_last) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "invalid address 0x%x, last was 0x%x", - (guint) addr, - (guint) addr_last); - return FALSE; - } - - /* parse bytes from line */ - g_debug ("writing data 0x%08x", (guint32) addr); - for (guint i = 9; i < line_end; i += 2) { - /* any holes in the hex record */ - guint32 len_hole = addr - addr_last; - guint8 data_tmp; - if (addr_last > 0 && len_hole > 0x100000) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "hole of 0x%x bytes too large to fill", - (guint) len_hole); - return FALSE; - } - if (addr_last > 0x0 && len_hole > 1) { - g_debug ("filling address 0x%08x to 0x%08x", - addr_last + 1, addr_last + len_hole - 1); - for (guint j = 1; j < len_hole; j++) { - /* although 0xff might be clearer, - * we can't write 0xffff to pic14 */ - g_string_append_c (buf, 0x00); - } - } - /* write into buf */ - data_tmp = dfu_utils_buffer_parse_uint8 (line + i); - g_string_append_c (buf, (gchar) data_tmp); - addr_last = addr++; - } - break; - case DFU_INHX32_RECORD_TYPE_EOF: - if (got_eof) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "duplicate EOF, perhaps " - "corrupt file"); - return FALSE; - } - got_eof = TRUE; - break; - case DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR: - abs_addr = dfu_utils_buffer_parse_uint16 (line + 9) << 16; - g_debug (" abs_addr:\t0x%02x", abs_addr); - break; - case DFU_INHX32_RECORD_TYPE_START_LINEAR: - abs_addr = dfu_utils_buffer_parse_uint32 (line + 9); - g_debug (" abs_addr:\t0x%08x", abs_addr); - break; - case DFU_INHX32_RECORD_TYPE_EXTENDED_SEGMENT: - /* segment base address, so ~1Mb addressable */ - seg_addr = dfu_utils_buffer_parse_uint16 (line + 9) * 16; - g_debug (" seg_addr:\t0x%08x", seg_addr); - break; - case DFU_INHX32_RECORD_TYPE_START_SEGMENT: - /* initial content of the CS:IP registers */ - seg_addr = dfu_utils_buffer_parse_uint32 (line + 9); - g_debug (" seg_addr:\t0x%02x", seg_addr); - break; - case DFU_INHX32_RECORD_TYPE_SIGNATURE: - for (guint i = 9; i < line_end; i += 2) { - guint8 tmp_c = dfu_utils_buffer_parse_uint8 (line + i); - g_string_append_c (buf_signature, tmp_c); - } - break; - default: - /* vendors sneak in nonstandard sections past the EOF */ - if (got_eof) - break; - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "invalid ihex record type %i", - record_type); - return FALSE; - } - } - - /* no EOF */ - if (!got_eof) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "no EOF, perhaps truncated file"); + /* make a native objects from the abstract firmware */ + if (flags & DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST) + flags_new |= FWUPD_INSTALL_FLAG_FORCE; + if (!fu_firmware_parse (firmware_new, bytes, flags_new, error)) return FALSE; - } + imgs = fu_firmware_get_images (firmware_new); + for (guint i = 0; i < imgs->len; i++) { + FuFirmwareImage *img = g_ptr_array_index (imgs, i); + g_autoptr(DfuElement) element = dfu_element_new (); + g_autoptr(DfuImage) image = dfu_image_new (); + dfu_element_set_contents (element, fu_firmware_image_get_bytes (img, NULL)); + dfu_element_set_address (element, fu_firmware_image_get_addr (img)); + dfu_image_add_element (image, element); + dfu_image_set_name (image, "ihex"); + dfu_firmware_add_image (firmware, image); - /* add single image */ - contents = g_bytes_new (buf->str, buf->len); - dfu_element_set_contents (element, contents); - if (base_addr != G_MAXUINT32) - dfu_element_set_address (element, base_addr); - dfu_image_add_element (image, element); - dfu_firmware_add_image (firmware, image); + } dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_INTEL_HEX); - - /* add optional signature */ - if (buf_signature->len > 0) { - g_autoptr(DfuElement) element_sig = dfu_element_new (); - g_autoptr(DfuImage) image_sig = dfu_image_new (); - g_autoptr(GBytes) data_sig = g_bytes_new_static (buf_signature->str, buf_signature->len); - dfu_element_set_contents (element_sig, data_sig); - dfu_image_add_element (image_sig, element_sig); - dfu_image_set_name (image_sig, "signature"); - dfu_firmware_add_image (firmware, image_sig); - } - return TRUE; -} - -static void -dfu_firmware_ihex_emit_chunk (GString *str, - guint16 address, - guint8 record_type, - const guint8 *data, - gsize sz) -{ - guint8 checksum = 0x00; - g_string_append_printf (str, ":%02X%04X%02X", - (guint) sz, - (guint) address, - (guint) record_type); - for (gsize j = 0; j < sz; j++) - g_string_append_printf (str, "%02X", data[j]); - checksum = (guint8) sz; - checksum += (guint8) ((address & 0xff00) >> 8); - checksum += (guint8) (address & 0xff); - checksum += record_type; - for (gsize j = 0; j < sz; j++) - checksum += data[j]; - g_string_append_printf (str, "%02X\n", (guint) (((~checksum) + 0x01) & 0xff)); -} - -static void -dfu_firmware_to_ihex_bytes (GString *str, guint8 record_type, - guint32 address, GBytes *contents) -{ - const guint8 *data; - const guint chunk_size = 16; - gsize len; - guint32 address_offset_last = 0x0; - - /* get number of chunks */ - data = g_bytes_get_data (contents, &len); - for (gsize i = 0; i < len; i += chunk_size) { - guint32 address_tmp = address + i; - guint32 address_offset = (address_tmp >> 16) & 0xffff; - gsize chunk_len = MIN (len - i, 16); - - /* need to offset */ - if (address_offset != address_offset_last) { - guint8 buf[2]; - fu_common_write_uint16 (buf, address_offset, G_BIG_ENDIAN); - dfu_firmware_ihex_emit_chunk (str, 0x0, - DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR, - buf, 2); - address_offset_last = address_offset; - } - address_tmp &= 0xffff; - dfu_firmware_ihex_emit_chunk (str, address_tmp, - record_type, data + i, chunk_len); - } -} - -static gboolean -dfu_firmware_to_ihex_element (DfuElement *element, GString *str, - guint8 record_type, GError **error) -{ - GBytes *contents = dfu_element_get_contents (element); - dfu_firmware_to_ihex_bytes (str, record_type, - dfu_element_get_address (element), - contents); - return TRUE; -} - -static gboolean -dfu_firmware_to_ihex_image (DfuImage *image, GString *str, GError **error) -{ - GPtrArray *elements; - guint8 record_type = DFU_INHX32_RECORD_TYPE_DATA; - - if (g_strcmp0 (dfu_image_get_name (image), "signature") == 0) - record_type = DFU_INHX32_RECORD_TYPE_SIGNATURE; - elements = dfu_image_get_elements (image); - for (guint i = 0; i < elements->len; i++) { - DfuElement *element = g_ptr_array_index (elements, i); - if (!dfu_firmware_to_ihex_element (element, - str, - record_type, - error)) - return FALSE; - } return TRUE; } @@ -416,18 +104,21 @@ GBytes * dfu_firmware_to_ihex (DfuFirmware *firmware, GError **error) { GPtrArray *images; - g_autoptr(GString) str = NULL; + g_autoptr(FuFirmware) firmware_new = fu_ihex_firmware_new (); - /* write all the element data */ - str = g_string_new (""); + /* make a new object from the native firmware */ images = dfu_firmware_get_images (firmware); for (guint i = 0; i < images->len; i++) { DfuImage *image = g_ptr_array_index (images, i); - if (!dfu_firmware_to_ihex_image (image, str, error)) - return NULL; + GPtrArray *elements = dfu_image_get_elements (image); + for (guint j = 0; j < elements->len; j++) { + DfuElement *element = g_ptr_array_index (elements, j); + g_autoptr(FuFirmwareImage) img = NULL; + img = fu_firmware_image_new (dfu_element_get_contents (element)); + fu_firmware_image_set_id (img, dfu_image_get_name (image)); + fu_firmware_image_set_addr (img, dfu_element_get_address (element)); + fu_firmware_add_image (firmware_new, img); + } } - - /* add EOF */ - dfu_firmware_ihex_emit_chunk (str, 0x0, DFU_INHX32_RECORD_TYPE_EOF, NULL, 0); - return g_bytes_new (str->str, str->len); + return fu_firmware_write (firmware_new, error); } diff --git a/plugins/dfu/dfu-format-srec.c b/plugins/dfu/dfu-format-srec.c index bfcd49bc6..cfeacdfa8 100644 --- a/plugins/dfu/dfu-format-srec.c +++ b/plugins/dfu/dfu-format-srec.c @@ -10,11 +10,13 @@ #include "fu-common.h" -#include "dfu-element.h" #include "dfu-firmware.h" #include "dfu-format-srec.h" #include "dfu-image.h" +#include "fu-firmware-common.h" +#include "fu-srec-firmware.h" + #include "fwupd-error.h" /** @@ -38,282 +40,6 @@ dfu_firmware_detect_srec (GBytes *bytes) return DFU_FIRMWARE_FORMAT_SREC; } -/** - * dfu_firmware_from_srec: (skip) - * @firmware: a #DfuFirmware - * @bytes: data to parse - * @flags: some #DfuFirmwareParseFlags - * @error: a #GError, or %NULL - * - * Unpacks into a firmware object from raw data. - * - * Returns: %TRUE for success - **/ -gboolean -dfu_image_from_srec (DfuImage *image, - GBytes *bytes, - guint32 start_addr, - DfuFirmwareParseFlags flags, - GError **error) -{ - const gchar *data; - gboolean got_eof = FALSE; - gboolean got_hdr = FALSE; - gsize sz = 0; - guint16 data_cnt = 0; - guint32 addr32_last = 0; - guint32 element_address = 0; - g_auto(GStrv) lines = NULL; - g_autoptr(DfuElement) element = dfu_element_new (); - g_autoptr(GBytes) contents = NULL; - g_autoptr(GString) outbuf = g_string_new (NULL); - - g_return_val_if_fail (bytes != NULL, FALSE); - - /* parse records */ - data = g_bytes_get_data (bytes, &sz); - lines = dfu_utils_strnsplit (data, sz, "\n", -1); - for (guint ln = 0; lines[ln] != NULL; ln++) { - const gchar *line = lines[ln]; - gsize linesz; - guint32 rec_addr32; - guint8 addrsz = 0; /* bytes */ - guint8 rec_count; /* words */ - guint8 rec_kind; - - /* ignore blank lines */ - g_strdelimit (lines[ln], "\r", '\0'); - linesz = strlen (line); - if (linesz == 0) - continue; - - /* check starting token */ - if (line[0] != 'S') { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "invalid starting token, got '%c' at line %u", - line[0], ln); - return FALSE; - } - - /* check there's enough data for the smallest possible record */ - if (linesz < 10) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "record incomplete at line %u, length %u", - ln, (guint) linesz); - return FALSE; - } - - /* kind, count, address, (data), checksum, linefeed */ - rec_kind = line[1] - '0'; - rec_count = dfu_utils_buffer_parse_uint8 (line + 2); - if (rec_count * 2 != linesz - 4) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "count incomplete at line %u, " - "length %u, expected %u", - ln, (guint) linesz - 4, (guint) rec_count * 2); - return FALSE; - } - - /* checksum check */ - if ((flags & DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST) == 0) { - guint8 rec_csum = 0; - guint8 rec_csum_expected; - for (guint8 i = 0; i < rec_count; i++) - rec_csum += dfu_utils_buffer_parse_uint8 (line + (i * 2) + 2); - rec_csum ^= 0xff; - rec_csum_expected = dfu_utils_buffer_parse_uint8 (line + (rec_count * 2) + 2); - if (rec_csum != rec_csum_expected) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "checksum incorrect line %u, " - "expected %02x, got %02x", - ln, rec_csum_expected, rec_csum); - return FALSE; - } - } - - /* set each command settings */ - switch (rec_kind) { - case 0: - addrsz = 2; - if (got_hdr) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "duplicate header record"); - return FALSE; - } - got_hdr = TRUE; - break; - case 1: - addrsz = 2; - break; - case 2: - addrsz = 3; - break; - case 3: - addrsz = 4; - break; - case 5: - addrsz = 2; - got_eof = TRUE; - break; - case 6: - addrsz = 3; - break; - case 7: - addrsz = 4; - got_eof = TRUE; - break; - case 8: - addrsz = 3; - got_eof = TRUE; - break; - case 9: - addrsz = 2; - got_eof = TRUE; - break; - default: - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "invalid srec record type S%c", - line[1]); - return FALSE; - } - - /* parse address */ - switch (addrsz) { - case 2: - rec_addr32 = dfu_utils_buffer_parse_uint16 (line + 4); - break; - case 3: - rec_addr32 = dfu_utils_buffer_parse_uint24 (line + 4); - break; - case 4: - rec_addr32 = dfu_utils_buffer_parse_uint32 (line + 4); - break; - default: - g_assert_not_reached (); - } - - /* header */ - if (rec_kind == 0) { - g_autoptr(GString) modname = g_string_new (NULL); - if (rec_addr32 != 0x0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "invalid header record address, got %04x", - rec_addr32); - return FALSE; - } - - /* could be anything, lets assume text */ - for (guint8 i = 4 + (addrsz * 2); i <= rec_count * 2; i += 2) { - guint8 tmp = dfu_utils_buffer_parse_uint8 (line + i); - if (!g_ascii_isgraph (tmp)) - break; - g_string_append_c (modname, tmp); - } - if (modname->len != 0) - dfu_image_set_name (image, modname->str); - continue; - } - - /* verify we got all records */ - if (rec_kind == 5) { - if (rec_addr32 != data_cnt) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "count record was not valid, got 0x%02x expected 0x%02x", - (guint) rec_addr32, (guint) data_cnt); - return FALSE; - } - } - - /* data */ - if (rec_kind == 1 || rec_kind == 2 || rec_kind == 3) { - /* invalid */ - if (!got_hdr) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "missing header record"); - return FALSE; - } - /* does not make sense */ - if (rec_addr32 < addr32_last) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "invalid address 0x%x, last was 0x%x", - (guint) rec_addr32, - (guint) addr32_last); - return FALSE; - } - if (rec_addr32 < start_addr) { - g_debug ("ignoring data at 0x%x as before start address 0x%x", - (guint) rec_addr32, (guint) start_addr); - } else { - guint bytecnt = 0; - guint32 len_hole = rec_addr32 - addr32_last; - - /* fill any holes, but only up to 1Mb to avoid a DoS */ - if (addr32_last > 0 && len_hole > 0x100000) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "hole of 0x%x bytes too large to fill", - (guint) len_hole); - return FALSE; - } - if (addr32_last > 0x0 && len_hole > 1) { - g_debug ("filling address 0x%08x to 0x%08x", - addr32_last + 1, addr32_last + len_hole - 1); - for (guint j = 0; j < len_hole; j++) - g_string_append_c (outbuf, 0xff); - } - - /* add data */ - for (guint8 i = 4 + (addrsz * 2); i <= rec_count * 2; i += 2) { - guint8 tmp = dfu_utils_buffer_parse_uint8 (line + i); - g_string_append_c (outbuf, tmp); - bytecnt++; - } - if (element_address == 0x0) - element_address = rec_addr32; - addr32_last = rec_addr32 + bytecnt; - } - data_cnt++; - } - } - - /* no EOF */ - if (!got_eof) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "no EOF, perhaps truncated file"); - return FALSE; - } - - /* add single image */ - contents = g_bytes_new (outbuf->str, outbuf->len); - dfu_element_set_contents (element, contents); - dfu_element_set_address (element, element_address); - dfu_image_add_element (image, element); - return TRUE; -} - /** * dfu_firmware_from_srec: (skip) * @firmware: a #DfuFirmware @@ -331,15 +57,26 @@ dfu_firmware_from_srec (DfuFirmware *firmware, DfuFirmwareParseFlags flags, GError **error) { - g_autoptr(DfuImage) image = NULL; + g_autoptr(FuFirmware) firmware_new = fu_srec_firmware_new (); + g_autoptr(GPtrArray) imgs = NULL; + FwupdInstallFlags flags_new = FWUPD_INSTALL_FLAG_NONE; - g_return_val_if_fail (bytes != NULL, FALSE); - - /* add single image */ - image = dfu_image_new (); - if (!dfu_image_from_srec (image, bytes, 0x0, flags, error)) + /* make a native objects from the abstract firmware */ + if (flags & DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST) + flags_new |= FWUPD_INSTALL_FLAG_FORCE; + if (!fu_firmware_parse (firmware_new, bytes, flags_new, error)) return FALSE; - dfu_firmware_add_image (firmware, image); + imgs = fu_firmware_get_images (firmware_new); + for (guint i = 0; i < imgs->len; i++) { + FuFirmwareImage *img = g_ptr_array_index (imgs, i); + g_autoptr(DfuElement) element = dfu_element_new (); + g_autoptr(DfuImage) image = dfu_image_new (); + dfu_element_set_contents (element, fu_firmware_image_get_bytes (img, NULL)); + dfu_element_set_address (element, fu_firmware_image_get_addr (img)); + dfu_image_add_element (image, element); + dfu_firmware_add_image (firmware, image); + + } dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_SREC); return TRUE; } diff --git a/plugins/dfu/dfu-format-srec.h b/plugins/dfu/dfu-format-srec.h index 18be5054f..b5a9a87e3 100644 --- a/plugins/dfu/dfu-format-srec.h +++ b/plugins/dfu/dfu-format-srec.h @@ -20,10 +20,5 @@ gboolean dfu_firmware_from_srec (DfuFirmware *firmware, GBytes *bytes, DfuFirmwareParseFlags flags, GError **error); -gboolean dfu_image_from_srec (DfuImage *image, - GBytes *bytes, - guint32 start_addr, - DfuFirmwareParseFlags flags, - GError **error); G_END_DECLS diff --git a/plugins/dfu/dfu-self-test.c b/plugins/dfu/dfu-self-test.c index 1232b6aab..fb9e1be15 100644 --- a/plugins/dfu/dfu-self-test.c +++ b/plugins/dfu/dfu-self-test.c @@ -320,209 +320,6 @@ dfu_firmware_metadata_func (void) g_assert_true (ret); } -static void -dfu_firmware_intel_hex_offset_func (void) -{ - DfuElement *element_verify; - DfuImage *image_verify; - const guint8 *data; - gboolean ret; - gsize len; - g_autofree gchar *str = NULL; - g_autoptr(DfuElement) element = NULL; - g_autoptr(DfuFirmware) firmware = NULL; - g_autoptr(DfuFirmware) firmware_verify = NULL; - g_autoptr(DfuImage) image = NULL; - g_autoptr(GBytes) data_bin = NULL; - g_autoptr(GBytes) data_dummy = NULL; - g_autoptr(GError) error = NULL; - - /* add a 4 byte image in high memory */ - element = dfu_element_new (); - data_dummy = g_bytes_new_static ("foo", 4); - dfu_element_set_address (element, 0x80000000); - dfu_element_set_contents (element, data_dummy); - image = dfu_image_new (); - dfu_image_add_element (image, element); - firmware = dfu_firmware_new (); - dfu_firmware_add_image (firmware, image); - dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_INTEL_HEX); - data_bin = dfu_firmware_write_data (firmware, &error); - g_assert_no_error (error); - g_assert (data_bin != NULL); - data = g_bytes_get_data (data_bin, &len); - str = g_strndup ((const gchar *) data, len); - g_assert_cmpstr (str, ==, - ":0200000480007A\n" - ":04000000666F6F00B8\n" - ":00000001FF\n"); - - /* check we can load it too */ - firmware_verify = dfu_firmware_new (); - ret = dfu_firmware_parse_data (firmware_verify, data_bin, DFU_FIRMWARE_PARSE_FLAG_NONE, &error); - g_assert_no_error (error); - g_assert (ret); - image_verify = dfu_firmware_get_image_default (firmware_verify); - g_assert (image_verify != NULL); - element_verify = dfu_image_get_element_default (image); - g_assert (element_verify != NULL); - g_assert_cmpint (dfu_element_get_address (element_verify), ==, 0x80000000); - g_assert_cmpint (g_bytes_get_size (dfu_element_get_contents (element_verify)), ==, 0x4); -} - -static void -dfu_firmware_srec_func (void) -{ - gboolean ret; - g_autofree gchar *filename_hex = NULL; - g_autofree gchar *filename_ref = NULL; - g_autoptr(DfuFirmware) firmware = NULL; - g_autoptr(GBytes) data_bin = NULL; - g_autoptr(GBytes) data_ref = NULL; - g_autoptr(GError) error = NULL; - g_autoptr(GFile) file_bin = NULL; - g_autoptr(GFile) file_hex = NULL; - - filename_hex = dfu_test_get_filename ("firmware.srec"); - g_assert (filename_hex != NULL); - file_hex = g_file_new_for_path (filename_hex); - firmware = dfu_firmware_new (); - ret = dfu_firmware_parse_file (firmware, file_hex, - DFU_FIRMWARE_PARSE_FLAG_NONE, - &error); - g_assert_no_error (error); - g_assert (ret); - g_assert_cmpint (dfu_firmware_get_size (firmware), ==, 136); - - dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_RAW); - data_bin = dfu_firmware_write_data (firmware, &error); - g_assert_no_error (error); - g_assert (data_bin != NULL); - - /* did we match the reference file? */ - filename_ref = dfu_test_get_filename ("firmware.bin"); - g_assert (filename_ref != NULL); - file_bin = g_file_new_for_path (filename_ref); - data_ref = dfu_self_test_get_bytes_for_file (file_bin, &error); - g_assert_no_error (error); - g_assert (data_ref != NULL); - ret = fu_common_bytes_compare (data_bin, data_ref, &error); - g_assert_no_error (error); - g_assert_true (ret); -} - -static void -dfu_firmware_intel_hex_func (void) -{ - const guint8 *data; - gboolean ret; - gsize len; - g_autofree gchar *filename_hex = NULL; - g_autofree gchar *filename_ref = NULL; - g_autofree gchar *str = NULL; - g_autoptr(DfuFirmware) firmware = NULL; - g_autoptr(GBytes) data_bin2 = NULL; - g_autoptr(GBytes) data_bin = NULL; - g_autoptr(GBytes) data_hex = NULL; - g_autoptr(GBytes) data_ref = NULL; - g_autoptr(GError) error = NULL; - g_autoptr(GFile) file_bin = NULL; - g_autoptr(GFile) file_hex = NULL; - - /* load a Intel hex32 file */ - filename_hex = dfu_test_get_filename ("firmware.hex"); - g_assert (filename_hex != NULL); - file_hex = g_file_new_for_path (filename_hex); - firmware = dfu_firmware_new (); - ret = dfu_firmware_parse_file (firmware, file_hex, - DFU_FIRMWARE_PARSE_FLAG_NONE, - &error); - g_assert_no_error (error); - g_assert (ret); - g_assert_cmpint (dfu_firmware_get_size (firmware), ==, 136); - dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_RAW); - data_bin = dfu_firmware_write_data (firmware, &error); - g_assert_no_error (error); - g_assert (data_bin != NULL); - - /* did we match the reference file? */ - filename_ref = dfu_test_get_filename ("firmware.bin"); - g_assert (filename_ref != NULL); - file_bin = g_file_new_for_path (filename_ref); - data_ref = dfu_self_test_get_bytes_for_file (file_bin, &error); - g_assert_no_error (error); - g_assert (data_ref != NULL); - ret = fu_common_bytes_compare (data_bin, data_ref, &error); - g_assert_no_error (error); - g_assert_true (ret); - - /* export a ihex file (which will be slightly different due to - * non-continous regions being expanded */ - dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_INTEL_HEX); - data_hex = dfu_firmware_write_data (firmware, &error); - g_assert_no_error (error); - g_assert (data_hex != NULL); - data = g_bytes_get_data (data_hex, &len); - str = g_strndup ((const gchar *) data, len); - g_assert_cmpstr (str, ==, - ":104000003DEF20F000000000FACF01F0FBCF02F0FE\n" - ":10401000E9CF03F0EACF04F0E1CF05F0E2CF06F0FC\n" - ":10402000D9CF07F0DACF08F0F3CF09F0F4CF0AF0D8\n" - ":10403000F6CF0BF0F7CF0CF0F8CF0DF0F5CF0EF078\n" - ":104040000EC0F5FF0DC0F8FF0CC0F7FF0BC0F6FF68\n" - ":104050000AC0F4FF09C0F3FF08C0DAFF07C0D9FFA8\n" - ":1040600006C0E2FF05C0E1FF04C0EAFF03C0E9FFAC\n" - ":1040700002C0FBFF01C0FAFF11003FEF20F000017A\n" - ":0840800042EF20F03DEF20F0BB\n" - ":00000001FF\n"); - - /* do we match the binary file again */ - dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_RAW); - data_bin2 = dfu_firmware_write_data (firmware, &error); - g_assert_no_error (error); - g_assert (data_bin2 != NULL); - ret = fu_common_bytes_compare (data_bin, data_bin2, &error); - g_assert_no_error (error); - g_assert_true (ret); -} - -static void -dfu_firmware_intel_hex_signed_func (void) -{ - DfuElement *element; - DfuImage *image; - GBytes *data_sig; - const guint8 *data; - gboolean ret; - gsize len; - g_autofree gchar *filename_hex = NULL; - g_autoptr(DfuFirmware) firmware = NULL; - g_autoptr(GError) error = NULL; - g_autoptr(GFile) file_hex = NULL; - - /* load a Intel hex32 file */ - filename_hex = dfu_test_get_filename ("firmware.shex"); - g_assert (filename_hex != NULL); - file_hex = g_file_new_for_path (filename_hex); - firmware = dfu_firmware_new (); - ret = dfu_firmware_parse_file (firmware, file_hex, - DFU_FIRMWARE_PARSE_FLAG_NONE, - &error); - g_assert_no_error (error); - g_assert (ret); - g_assert_cmpint (dfu_firmware_get_size (firmware), ==, 144); - - /* get the signed image element */ - image = dfu_firmware_get_image_by_name (firmware, "signature"); - g_assert (image != NULL); - element = dfu_image_get_element_default (image); - data_sig = dfu_element_get_contents (element); - g_assert (data_sig != NULL); - data = g_bytes_get_data (data_sig, &len); - g_assert_cmpint (len, ==, 8); - g_assert (data != NULL); -} - static gchar * dfu_target_sectors_to_string (DfuTarget *target) { @@ -794,7 +591,6 @@ main (int argc, char **argv) g_setenv ("G_MESSAGES_DEBUG", "all", FALSE); /* tests go here */ - g_test_add_func ("/dfu/firmware{srec}", dfu_firmware_srec_func); g_test_add_func ("/dfu/patch", dfu_patch_func); g_test_add_func ("/dfu/patch{merges}", dfu_patch_merges_func); g_test_add_func ("/dfu/patch{apply}", dfu_patch_apply_func); @@ -806,9 +602,6 @@ main (int argc, char **argv) g_test_add_func ("/dfu/firmware{dfuse}", dfu_firmware_dfuse_func); g_test_add_func ("/dfu/firmware{xdfu}", dfu_firmware_xdfu_func); g_test_add_func ("/dfu/firmware{metadata}", dfu_firmware_metadata_func); - g_test_add_func ("/dfu/firmware{intel-hex-offset}", dfu_firmware_intel_hex_offset_func); - g_test_add_func ("/dfu/firmware{intel-hex}", dfu_firmware_intel_hex_func); - g_test_add_func ("/dfu/firmware{intel-hex-signed}", dfu_firmware_intel_hex_signed_func); return g_test_run (); } diff --git a/plugins/dfu/tests/firmware.shex b/plugins/dfu/tests/firmware.shex deleted file mode 100644 index 4de1fa6b2..000000000 Binary files a/plugins/dfu/tests/firmware.shex and /dev/null differ diff --git a/plugins/dfu/tests/firmware.sig b/plugins/dfu/tests/firmware.sig deleted file mode 100644 index e8b5f8233..000000000 --- a/plugins/dfu/tests/firmware.sig +++ /dev/null @@ -1 +0,0 @@ -deadbeef \ No newline at end of file diff --git a/plugins/ebitdo/fu-ebitdo-device.c b/plugins/ebitdo/fu-ebitdo-device.c index 5ebc52a5a..6ee60e2a5 100644 --- a/plugins/ebitdo/fu-ebitdo-device.c +++ b/plugins/ebitdo/fu-ebitdo-device.c @@ -348,7 +348,7 @@ fu_ebitdo_device_get_serial (FuEbitdoDevice *self) static gboolean fu_ebitdo_device_write_firmware (FuDevice *device, - GBytes *fw, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { @@ -358,6 +358,7 @@ fu_ebitdo_device_write_firmware (FuDevice *device, const guint chunk_sz = 32; guint32 payload_len; guint32 serial_new[3]; + g_autoptr(GBytes) fw = NULL; g_autoptr(GError) error_local = NULL; const guint32 app_key_index[16] = { 0x186976e5, 0xcac67acd, 0x38f27fee, 0x0a4948f1, @@ -408,6 +409,11 @@ fu_ebitdo_device_write_firmware (FuDevice *device, return FALSE; } + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + /* corrupt */ if (g_bytes_get_size (fw) < sizeof (FuEbitdoFirmwareHeader)) { g_set_error_literal (error, diff --git a/plugins/fastboot/fu-fastboot-device.c b/plugins/fastboot/fu-fastboot-device.c index d41b254d7..db9482b19 100644 --- a/plugins/fastboot/fu-fastboot-device.c +++ b/plugins/fastboot/fu-fastboot-device.c @@ -595,11 +595,17 @@ fu_fastboot_device_write_qfil (FuDevice *device, FuArchive* archive, GError **er static gboolean fu_fastboot_device_write_firmware (FuDevice *device, - GBytes *fw, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { g_autoptr(FuArchive) archive = NULL; + g_autoptr(GBytes) fw = NULL; + + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; /* decompress entire archive ahead of time */ archive = fu_archive_new (fw, FU_ARCHIVE_FLAG_IGNORE_PATH, error); diff --git a/plugins/modem-manager/fu-mm-device.c b/plugins/modem-manager/fu-mm-device.c index a61d638bd..86ccdc0f5 100644 --- a/plugins/modem-manager/fu-mm-device.c +++ b/plugins/modem-manager/fu-mm-device.c @@ -600,15 +600,21 @@ fu_mm_device_write_firmware_qmi_pdc (FuDevice *device, GBytes *fw, GArray **acti static gboolean fu_mm_device_write_firmware (FuDevice *device, - GBytes *fw, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { FuMmDevice *self = FU_MM_DEVICE (device); g_autoptr(FuDeviceLocker) locker = NULL; g_autoptr(FuArchive) archive = NULL; + g_autoptr(GBytes) fw = NULL; g_autoptr(GPtrArray) array = NULL; + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + /* lock device */ locker = fu_device_locker_new (device, error); if (locker == NULL) diff --git a/plugins/nvme/fu-nvme-device.c b/plugins/nvme/fu-nvme-device.c index ef3a6b65c..e4b4504be 100644 --- a/plugins/nvme/fu-nvme-device.c +++ b/plugins/nvme/fu-nvme-device.c @@ -395,16 +395,22 @@ fu_nvme_device_close (FuDevice *device, GError **error) static gboolean fu_nvme_device_write_firmware (FuDevice *device, - GBytes *fw, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { FuNvmeDevice *self = FU_NVME_DEVICE (device); g_autoptr(GBytes) fw2 = NULL; + g_autoptr(GBytes) fw = NULL; g_autoptr(GPtrArray) chunks = NULL; guint64 block_size = self->write_block_size > 0 ? self->write_block_size : 0x1000; + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + /* some vendors provide firmware files whose sizes are not multiples * of blksz *and* the device won't accept blocks of different sizes */ if (fu_device_has_custom_flag (device, "force-align")) { diff --git a/plugins/rts54hid/fu-rts54hid-device.c b/plugins/rts54hid/fu-rts54hid-device.c index 79b262fa9..66b105e02 100644 --- a/plugins/rts54hid/fu-rts54hid-device.c +++ b/plugins/rts54hid/fu-rts54hid-device.c @@ -315,13 +315,19 @@ fu_rts54hid_device_close (FuUsbDevice *device, GError **error) static gboolean fu_rts54hid_device_write_firmware (FuDevice *device, - GBytes *fw, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { FuRts54HidDevice *self = FU_RTS54HID_DEVICE (device); + g_autoptr(GBytes) fw = NULL; g_autoptr(GPtrArray) chunks = NULL; + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + /* set MCU to high clock rate for better ISP performance */ if (!fu_rts54hid_device_set_clock_mode (self, TRUE, error)) return FALSE; diff --git a/plugins/rts54hid/fu-rts54hid-module.c b/plugins/rts54hid/fu-rts54hid-module.c index b8155eaa9..d7e86ee4c 100644 --- a/plugins/rts54hid/fu-rts54hid-module.c +++ b/plugins/rts54hid/fu-rts54hid-module.c @@ -212,13 +212,19 @@ fu_rts54hid_module_close (FuDevice *device, GError **error) static gboolean fu_rts54hid_module_write_firmware (FuDevice *module, - GBytes *fw, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { FuRts54HidModule *self = FU_RTS54HID_MODULE (module); + g_autoptr(GBytes) fw = NULL; g_autoptr(GPtrArray) chunks = NULL; + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + /* build packets */ chunks = fu_chunk_array_new_from_bytes (fw, 0x00, /* start addr */ diff --git a/plugins/rts54hub/fu-rts54hub-device.c b/plugins/rts54hub/fu-rts54hub-device.c index 75f47b91d..ba0d819ee 100644 --- a/plugins/rts54hub/fu-rts54hub-device.c +++ b/plugins/rts54hub/fu-rts54hub-device.c @@ -309,13 +309,19 @@ fu_rts54hub_device_close (FuUsbDevice *device, GError **error) static gboolean fu_rts54hub_device_write_firmware (FuDevice *device, - GBytes *fw, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { FuRts54HubDevice *self = FU_RTS54HUB_DEVICE (device); + g_autoptr(GBytes) fw = NULL; g_autoptr(GPtrArray) chunks = NULL; + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + /* enable vendor commands */ if (!fu_rts54hub_device_vendor_cmd (self, FU_RTS54HUB_VENDOR_CMD_STATUS | @@ -383,7 +389,7 @@ fu_rts54hub_device_write_firmware (FuDevice *device, return TRUE; } -static GBytes * +static FuFirmware * fu_rts54hub_device_prepare_firmware (FuDevice *device, GBytes *fw, FwupdInstallFlags flags, @@ -405,7 +411,7 @@ fu_rts54hub_device_prepare_firmware (FuDevice *device, "firmware needs to be dual bank"); return NULL; } - return g_bytes_ref (fw); + return fu_firmware_new_from_bytes (fw); } static void diff --git a/plugins/solokey/fu-solokey-device.c b/plugins/solokey/fu-solokey-device.c index 0fcb7ca5c..d7759f389 100644 --- a/plugins/solokey/fu-solokey-device.c +++ b/plugins/solokey/fu-solokey-device.c @@ -7,11 +7,10 @@ #include "config.h" #include -#include -#include "dfu-firmware.h" #include "fu-chunk.h" #include "fu-solokey-device.h" +#include "fu-solokey-firmware.h" struct _FuSolokeyDevice { FuUsbDevice parent_instance; @@ -396,30 +395,15 @@ fu_solokey_device_setup (FuDevice *device, GError **error) return TRUE; } -static GByteArray * -_g_base64_decode_to_byte_array (const gchar *text) -{ - gsize out_len = 0; - guchar *out = g_base64_decode (text, &out_len); - return g_byte_array_new_take ((guint8 *) out, out_len); -} - -static GBytes * -_g_base64_decode_to_bytes (const gchar *text) -{ - gsize out_len = 0; - guchar *out = g_base64_decode (text, &out_len); - return g_bytes_new_take ((guint8 *) out, out_len); -} - static gboolean -fu_solokey_device_verify (FuSolokeyDevice *self, const gchar *base64, GError **error) +fu_solokey_device_verify (FuSolokeyDevice *self, GBytes *fw_sig, GError **error) { g_autoptr(GByteArray) req = g_byte_array_new (); g_autoptr(GByteArray) res = NULL; - g_autoptr(GByteArray) sig = _g_base64_decode_to_byte_array (base64); + g_autoptr(GByteArray) sig = g_byte_array_new (); fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_VERIFY); + g_byte_array_append (sig, g_bytes_get_data (fw_sig, NULL), g_bytes_get_size (fw_sig)); fu_solokey_device_exchange (req, SOLO_BOOTLOADER_DONE, 0x00, sig); res = fu_solokey_device_packet (self, SOLO_BOOTLOADER_HID_CMD_BOOT, req, error); if (res == NULL) @@ -427,75 +411,42 @@ fu_solokey_device_verify (FuSolokeyDevice *self, const gchar *base64, GError **e return TRUE; } +static FuFirmware * +fu_solokey_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuFirmware) firmware = fu_solokey_firmware_new (); + fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); + if (!fu_firmware_parse (firmware, fw, flags, error)) + return NULL; + return g_steal_pointer (&firmware); +} + static gboolean fu_solokey_device_write_firmware (FuDevice *device, - GBytes *fw, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { FuSolokeyDevice *self = FU_SOLOKEY_DEVICE (device); - DfuElement *element; - DfuImage *image; - JsonNode *json_root; - JsonObject *json_obj; - const gchar *base64; - g_autoptr(DfuFirmware) firmware = dfu_firmware_new (); - g_autoptr(GBytes) fw_ihex = NULL; + g_autoptr(FuFirmwareImage) img = NULL; + g_autoptr(GBytes) fw = NULL; + g_autoptr(GBytes) fw_sig = NULL; g_autoptr(GPtrArray) chunks = NULL; - g_autoptr(GString) base64_websafe = NULL; - g_autoptr(JsonParser) parser = json_parser_new (); - /* parse JSON */ - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); - if (!json_parser_load_from_data (parser, - (const gchar *) g_bytes_get_data (fw, NULL), - (gssize) g_bytes_get_size (fw), - error)) { - g_prefix_error (error, "firmware not in JSON format: "); + /* get main image */ + img = fu_firmware_get_image_by_id (firmware, NULL, error); + if (img == NULL) return FALSE; - } - json_root = json_parser_get_root (parser); - json_obj = json_node_get_object (json_root); - if (!json_object_has_member (json_obj, "firmware")) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "JSON invalid as has no 'firmware'"); - return FALSE; - } - if (!json_object_has_member (json_obj, "signature")) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "JSON invalid as has no 'signature'"); - return FALSE; - } - - /* decode */ - base64 = json_object_get_string_member (json_obj, "firmware"); - fw_ihex = _g_base64_decode_to_bytes (base64); - if (!dfu_firmware_parse_data (firmware, fw_ihex, DFU_FIRMWARE_PARSE_FLAG_NONE, error)) - return FALSE; - image = dfu_firmware_get_image_default (firmware); - if (image == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "No image data"); - return FALSE; - } - element = dfu_image_get_element_default (image); - if (element == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "No element data"); - return FALSE; - } /* build packets */ - chunks = fu_chunk_array_new_from_bytes (dfu_element_get_contents (element), - dfu_element_get_address (element), + fw = fu_firmware_image_get_bytes (img, error); + if (fw == NULL) + return FALSE; + chunks = fu_chunk_array_new_from_bytes (fw, + fu_firmware_image_get_addr (img), 0x00, /* page_sz */ 2048); @@ -525,11 +476,10 @@ fu_solokey_device_write_firmware (FuDevice *device, } /* verify the signature and reboot back to runtime */ - base64_websafe = g_string_new (json_object_get_string_member (json_obj, "signature")); - fu_common_string_replace (base64_websafe, "-", "+"); - fu_common_string_replace (base64_websafe, "_", "/"); - g_string_append (base64_websafe, "=="); - return fu_solokey_device_verify (self, base64_websafe->str, error); + fw_sig = fu_firmware_get_image_by_id_bytes (firmware, "signature", error); + if (fw_sig == NULL) + return FALSE; + return fu_solokey_device_verify (self, fw_sig, error); } static void @@ -549,6 +499,7 @@ fu_solokey_device_class_init (FuSolokeyDeviceClass *klass) FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); klass_device->write_firmware = fu_solokey_device_write_firmware; + klass_device->prepare_firmware = fu_solokey_device_prepare_firmware; klass_device->setup = fu_solokey_device_setup; klass_usb_device->open = fu_solokey_device_open; klass_usb_device->close = fu_solokey_device_close; diff --git a/plugins/solokey/fu-solokey-firmware.c b/plugins/solokey/fu-solokey-firmware.c new file mode 100644 index 000000000..9fc856699 --- /dev/null +++ b/plugins/solokey/fu-solokey-firmware.c @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-ihex-firmware.h" + +#include "fu-solokey-firmware.h" + +struct _FuSolokeyFirmware { + FuFirmware parent_instance; +}; + +G_DEFINE_TYPE (FuSolokeyFirmware, fu_solokey_firmware, FU_TYPE_FIRMWARE) + +static GBytes * +_g_base64_decode_to_bytes (const gchar *text) +{ + gsize out_len = 0; + guchar *out = g_base64_decode (text, &out_len); + return g_bytes_new_take ((guint8 *) out, out_len); +} + +static gboolean +fu_solokey_firmware_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + JsonNode *json_root; + JsonObject *json_obj; + const gchar *base64; + g_autoptr(FuFirmware) ihex_firmware = fu_ihex_firmware_new (); + g_autoptr(FuFirmwareImage) img = NULL; + g_autoptr(FuFirmwareImage) img_sig = fu_firmware_image_new (NULL); + g_autoptr(GBytes) fw_ihex = NULL; + g_autoptr(GBytes) fw_sig = NULL; + g_autoptr(GString) base64_websafe = NULL; + g_autoptr(JsonParser) parser = json_parser_new (); + + /* parse JSON */ + if (!json_parser_load_from_data (parser, + (const gchar *) g_bytes_get_data (fw, NULL), + (gssize) g_bytes_get_size (fw), + error)) { + g_prefix_error (error, "firmware not in JSON format: "); + return FALSE; + } + json_root = json_parser_get_root (parser); + json_obj = json_node_get_object (json_root); + if (!json_object_has_member (json_obj, "firmware")) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "JSON invalid as has no 'firmware'"); + return FALSE; + } + if (!json_object_has_member (json_obj, "signature")) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "JSON invalid as has no 'signature'"); + return FALSE; + } + + /* decode */ + base64 = json_object_get_string_member (json_obj, "firmware"); + fw_ihex = _g_base64_decode_to_bytes (base64); + if (!fu_firmware_parse (ihex_firmware, fw_ihex, flags, error)) + return FALSE; + img = fu_firmware_get_image_default (ihex_firmware, error); + if (img == NULL) + return FALSE; + fu_firmware_add_image (firmware, img); + + /* signature */ + base64_websafe = g_string_new (json_object_get_string_member (json_obj, "signature")); + fu_common_string_replace (base64_websafe, "-", "+"); + fu_common_string_replace (base64_websafe, "_", "/"); + g_string_append (base64_websafe, "=="); + fw_sig = _g_base64_decode_to_bytes (base64_websafe->str); + fu_firmware_image_set_bytes (img_sig, fw_sig); + fu_firmware_image_set_id (img_sig, "signature"); + fu_firmware_add_image (firmware, img_sig); + return TRUE; +} + +static void +fu_solokey_firmware_init (FuSolokeyFirmware *self) +{ +} + +static void +fu_solokey_firmware_class_init (FuSolokeyFirmwareClass *klass) +{ + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + klass_firmware->parse = fu_solokey_firmware_parse; +} + +FuFirmware * +fu_solokey_firmware_new (void) +{ + return FU_FIRMWARE (g_object_new (FU_TYPE_SOLOKEY_FIRMWARE, NULL)); +} diff --git a/plugins/solokey/fu-solokey-firmware.h b/plugins/solokey/fu-solokey-firmware.h new file mode 100644 index 000000000..7bf9110a5 --- /dev/null +++ b/plugins/solokey/fu-solokey-firmware.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware.h" + +G_BEGIN_DECLS + +#define FU_TYPE_SOLOKEY_FIRMWARE (fu_solokey_firmware_get_type ()) +G_DECLARE_FINAL_TYPE (FuSolokeyFirmware, fu_solokey_firmware, FU, SOLOKEY_FIRMWARE, FuFirmware) + +FuFirmware *fu_solokey_firmware_new (void); + +G_END_DECLS diff --git a/plugins/solokey/meson.build b/plugins/solokey/meson.build index 868efa368..b4e3b115a 100644 --- a/plugins/solokey/meson.build +++ b/plugins/solokey/meson.build @@ -10,11 +10,11 @@ shared_module('fu_plugin_solokey', fu_hash, sources : [ 'fu-solokey-device.c', + 'fu-solokey-firmware.c', 'fu-plugin-solokey.c', ], include_directories : [ include_directories('../..'), - include_directories('../dfu'), include_directories('../../src'), include_directories('../../libfwupd'), ], @@ -22,7 +22,6 @@ shared_module('fu_plugin_solokey', install_dir: plugin_dir, link_with : [ libfwupdprivate, - dfu, ], c_args : cargs, dependencies : [ diff --git a/plugins/superio/fu-superio-device.c b/plugins/superio/fu-superio-device.c index 632a19afa..64d4d5292 100644 --- a/plugins/superio/fu-superio-device.c +++ b/plugins/superio/fu-superio-device.c @@ -362,7 +362,7 @@ fu_superio_device_setup (FuDevice *device, GError **error) return TRUE; } -static GBytes * +static FuFirmware * fu_superio_device_prepare_firmware (FuDevice *device, GBytes *fw, FwupdInstallFlags flags, @@ -378,7 +378,7 @@ fu_superio_device_prepare_firmware (FuDevice *device, if (memcmp (&buf[off], sig1, sizeof(sig1)) == 0 && memcmp (&buf[off + 8], sig2, sizeof(sig2)) == 0) { g_debug ("found signature at 0x%04x", (guint) off); - return g_bytes_ref (fw); + return fu_firmware_new_from_bytes (fw); } } g_set_error_literal (error, diff --git a/plugins/superio/fu-superio-it89-device.c b/plugins/superio/fu-superio-it89-device.c index 530df9550..f8d324224 100644 --- a/plugins/superio/fu-superio-it89-device.c +++ b/plugins/superio/fu-superio-it89-device.c @@ -591,13 +591,14 @@ fu_superio_it89_device_get_jedec_id (FuSuperioDevice *self, guint8 *id, GError * static gboolean fu_superio_it89_device_write_firmware (FuDevice *device, - GBytes *fw, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); guint8 id[4] = { 0x0 }; g_autoptr(GBytes) fw_fixed = NULL; + g_autoptr(GBytes) fw = NULL; g_autoptr(GPtrArray) chunks = NULL; /* check JEDEC ID */ @@ -618,6 +619,11 @@ fu_superio_it89_device_write_firmware (FuDevice *device, if (!fu_superio_it89_device_check_eflash (self, error)) return FALSE; + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + /* disable the mirroring of e-flash */ if (g_getenv ("FWUPD_SUPERIO_DISABLE_MIRROR") != NULL) { fw_fixed = fu_plugin_superio_fix_signature (self, fw, error); diff --git a/plugins/synaptics-prometheus/fu-dump.c b/plugins/synaptics-prometheus/fu-dump.c index 2499c428b..acc2893aa 100644 --- a/plugins/synaptics-prometheus/fu-dump.c +++ b/plugins/synaptics-prometheus/fu-dump.c @@ -14,12 +14,11 @@ fu_dump_parse (const gchar *filename, GError **error) gchar *data = NULL; gsize len = 0; g_autoptr(GBytes) blob = NULL; - g_autoptr(GPtrArray) array = NULL; + g_autoptr(FuFirmware) firmware = fu_synaprom_firmware_new (); if (!g_file_get_contents (filename, &data, &len, error)) return FALSE; blob = g_bytes_new_take (data, len); - array = fu_synaprom_firmware_new (blob, error); - return array != NULL; + return fu_firmware_parse (firmware, blob, 0, error); } static gboolean @@ -28,7 +27,10 @@ fu_dump_generate (const gchar *filename, GError **error) const gchar *data; gsize len = 0; g_autoptr(GBytes) blob = NULL; - blob = fu_synaprom_firmware_generate (); + g_autoptr(FuFirmware) firmware = fu_synaprom_firmware_new (); + blob = fu_firmware_write (firmware, error); + if (blob == NULL) + return FALSE; data = g_bytes_get_data (blob, &len); return g_file_set_contents (filename, data, len, error); } diff --git a/plugins/synaptics-prometheus/fu-self-test.c b/plugins/synaptics-prometheus/fu-self-test.c index 0ab70c925..651a68d00 100644 --- a/plugins/synaptics-prometheus/fu-self-test.c +++ b/plugins/synaptics-prometheus/fu-self-test.c @@ -18,6 +18,7 @@ static void fu_test_synaprom_firmware_func (void) { const guint8 *buf; + gboolean ret; gsize sz = 0; g_autofree gchar *filename = NULL; g_autoptr(FuSynapromDevice) device = fu_synaprom_device_new (NULL); @@ -25,7 +26,8 @@ fu_test_synaprom_firmware_func (void) g_autoptr(GBytes) blob2 = NULL; g_autoptr(GBytes) fw = NULL; g_autoptr(GError) error = NULL; - g_autoptr(GPtrArray) firmware = NULL; + g_autoptr(FuFirmware) firmware2 = NULL; + g_autoptr(FuFirmware) firmware = fu_synaprom_firmware_new (); filename = fu_test_get_filename (TESTDATADIR, "test.pkg"); g_assert_nonnull (filename); @@ -36,22 +38,18 @@ fu_test_synaprom_firmware_func (void) g_assert_cmpint (sz, ==, 294); g_assert_cmpint (buf[0], ==, 0x01); g_assert_cmpint (buf[1], ==, 0x00); - firmware = fu_synaprom_firmware_new (fw, &error); + ret = fu_firmware_parse (firmware, fw, 0, &error); g_assert_no_error (error); - g_assert_nonnull (firmware); + g_assert_true (ret); /* does not exist */ - blob1 = fu_synaprom_firmware_get_bytes_by_tag (firmware, 0, NULL); + blob1 = fu_firmware_get_image_by_id_bytes (firmware, "NotGoingToExist", NULL); g_assert_null (blob1); - blob1 = fu_synaprom_firmware_get_bytes_by_tag (firmware, - FU_SYNAPROM_FIRMWARE_TAG_CFG_HEADER, - NULL); + blob1 = fu_firmware_get_image_by_id_bytes (firmware, "cfg-update-header", NULL); g_assert_null (blob1); /* header needs to exist */ - blob1 = fu_synaprom_firmware_get_bytes_by_tag (firmware, - FU_SYNAPROM_FIRMWARE_TAG_MFW_HEADER, - &error); + blob1 = fu_firmware_get_image_by_id_bytes (firmware, "mfw-update-header", &error); g_assert_no_error (error); g_assert_nonnull (blob1); buf = g_bytes_get_data (blob1, &sz); @@ -64,8 +62,11 @@ fu_test_synaprom_firmware_func (void) /* payload needs to exist */ fu_synaprom_device_set_version (device, 10, 1, 1234); - blob2 = fu_synaprom_device_prepare_fw (FU_DEVICE (device), fw, - FWUPD_INSTALL_FLAG_NONE, &error); + firmware2 = fu_synaprom_device_prepare_fw (FU_DEVICE (device), fw, + FWUPD_INSTALL_FLAG_NONE, &error); + g_assert_no_error (error); + g_assert_nonnull (firmware2); + blob2 = fu_firmware_get_image_by_id_bytes (firmware2, "mfw-update-payload", &error); g_assert_no_error (error); g_assert_nonnull (blob2); buf = g_bytes_get_data (blob2, &sz); diff --git a/plugins/synaptics-prometheus/fu-synaprom-config.c b/plugins/synaptics-prometheus/fu-synaprom-config.c index a9b510047..f0b9c365d 100644 --- a/plugins/synaptics-prometheus/fu-synaprom-config.c +++ b/plugins/synaptics-prometheus/fu-synaprom-config.c @@ -112,7 +112,7 @@ fu_synaprom_config_setup (FuDevice *device, GError **error) return TRUE; } -static GBytes * +static FuFirmware * fu_synaprom_config_prepare_firmware (FuDevice *device, GBytes *fw, FwupdInstallFlags flags, @@ -121,20 +121,17 @@ fu_synaprom_config_prepare_firmware (FuDevice *device, FuSynapromConfig *self = FU_SYNAPROM_CONFIG (device); FuSynapromFirmwareCfgHeader hdr; g_autoptr(GBytes) blob = NULL; - g_autoptr(GPtrArray) firmware = NULL; + g_autoptr(FuFirmware) firmware = fu_synaprom_firmware_new (); guint32 product; guint32 id1; /* parse the firmware */ fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); - firmware = fu_synaprom_firmware_new (fw, error); - if (firmware == NULL) + if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; /* check the update header product and version */ - blob = fu_synaprom_firmware_get_bytes_by_tag (firmware, - FU_SYNAPROM_FIRMWARE_TAG_CFG_HEADER, - error); + blob = fu_firmware_get_image_by_id_bytes (firmware, "cfg-update-header", error); if (blob == NULL) return NULL; if (g_bytes_get_size (blob) != sizeof(hdr)) { @@ -178,19 +175,24 @@ fu_synaprom_config_prepare_firmware (FuDevice *device, } } - /* get payload */ - return fu_synaprom_firmware_get_bytes_by_tag (firmware, - FU_SYNAPROM_FIRMWARE_TAG_CFG_PAYLOAD, - error); + /* success */ + return g_steal_pointer (&firmware); } static gboolean fu_synaprom_config_write_firmware (FuDevice *device, - GBytes *fw, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { FuSynapromConfig *self = FU_SYNAPROM_CONFIG (device); + g_autoptr(GBytes) fw = NULL; + + /* get default image */ + fw = fu_firmware_get_image_by_id_bytes (firmware, "cfg-update-payload", error); + if (fw == NULL) + return FALSE; + /* I assume the CFG/MFW difference is detected in the device...*/ return fu_synaprom_device_write_fw (self->device, fw, error); } diff --git a/plugins/synaptics-prometheus/fu-synaprom-device.c b/plugins/synaptics-prometheus/fu-synaprom-device.c index 298e20a78..74906a874 100644 --- a/plugins/synaptics-prometheus/fu-synaprom-device.c +++ b/plugins/synaptics-prometheus/fu-synaprom-device.c @@ -230,7 +230,7 @@ fu_synaprom_device_cmd_download_chunk (FuSynapromDevice *device, return fu_synaprom_device_cmd_send (device, request, reply, 20000, error); } -GBytes * +FuFirmware * fu_synaprom_device_prepare_fw (FuDevice *device, GBytes *fw, FwupdInstallFlags flags, @@ -240,18 +240,15 @@ fu_synaprom_device_prepare_fw (FuDevice *device, FuSynapromFirmwareMfwHeader hdr; guint32 product; g_autoptr(GBytes) blob = NULL; - g_autoptr(GPtrArray) firmware = NULL; + g_autoptr(FuFirmware) firmware = fu_synaprom_firmware_new (); /* parse the firmware */ fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); - firmware = fu_synaprom_firmware_new (fw, error); - if (firmware == NULL) + if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; /* check the update header product and version */ - blob = fu_synaprom_firmware_get_bytes_by_tag (firmware, - FU_SYNAPROM_FIRMWARE_TAG_MFW_HEADER, - error); + blob = fu_firmware_get_image_by_id_bytes (firmware, "mfw-update-header", error); if (blob == NULL) return NULL; if (g_bytes_get_size (blob) != sizeof(hdr)) { @@ -296,10 +293,8 @@ fu_synaprom_device_prepare_fw (FuDevice *device, } } - /* get payload */ - return fu_synaprom_firmware_get_bytes_by_tag (firmware, - FU_SYNAPROM_FIRMWARE_TAG_MFW_PAYLOAD, - error); + /* success */ + return g_steal_pointer (&firmware); } gboolean @@ -352,11 +347,18 @@ fu_synaprom_device_write_fw (FuSynapromDevice *self, GBytes *fw, GError **error) static gboolean fu_synaprom_device_write_firmware (FuDevice *device, - GBytes *fw, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { FuSynapromDevice *self = FU_SYNAPROM_DEVICE (device); + g_autoptr(GBytes) fw = NULL; + + /* get default image */ + fw = fu_firmware_get_image_by_id_bytes (firmware, "mfw-update-payload", error); + if (fw == NULL) + return FALSE; + return fu_synaprom_device_write_fw (self, fw, error); } diff --git a/plugins/synaptics-prometheus/fu-synaprom-device.h b/plugins/synaptics-prometheus/fu-synaprom-device.h index 2d91b8481..e363715e9 100644 --- a/plugins/synaptics-prometheus/fu-synaprom-device.h +++ b/plugins/synaptics-prometheus/fu-synaprom-device.h @@ -37,7 +37,7 @@ void fu_synaprom_device_set_version (FuSynapromDevice *self, guint8 vmajor, guint8 vminor, guint32 buildnum); -GBytes *fu_synaprom_device_prepare_fw (FuDevice *device, +FuFirmware *fu_synaprom_device_prepare_fw (FuDevice *device, GBytes *fw, FwupdInstallFlags flags, GError **error); diff --git a/plugins/synaptics-prometheus/fu-synaprom-firmware.c b/plugins/synaptics-prometheus/fu-synaprom-firmware.c index 0f219de0b..ac0b0603d 100644 --- a/plugins/synaptics-prometheus/fu-synaprom-firmware.c +++ b/plugins/synaptics-prometheus/fu-synaprom-firmware.c @@ -11,27 +11,21 @@ #include "fu-synaprom-firmware.h" +struct _FuSynapromFirmware { + FuFirmware parent_instance; +}; + +G_DEFINE_TYPE (FuSynapromFirmware, fu_synaprom_firmware, FU_TYPE_FIRMWARE) + typedef struct __attribute__((packed)) { guint16 tag; guint32 bufsz; } FuSynapromFirmwareHdr; -typedef struct { - guint16 tag; - GBytes *bytes; -} FuSynapromFirmwareItem; - /* use only first 12 bit of 16 bits as tag value */ #define FU_SYNAPROM_FIRMWARE_TAG_MAX 0xfff0 #define FU_SYNAPROM_FIRMWARE_SIGSIZE 0x0100 -static void -fu_synaprom_firmware_item_free (FuSynapromFirmwareItem *item) -{ - g_bytes_unref (item->bytes); - g_free (item); -} - static const gchar * fu_synaprom_firmware_tag_to_string (guint16 tag) { @@ -46,18 +40,21 @@ fu_synaprom_firmware_tag_to_string (guint16 tag) return NULL; } -GPtrArray * -fu_synaprom_firmware_new (GBytes *blob, GError **error) +static gboolean +fu_synaprom_firmware_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) { const guint8 *buf; gsize bufsz = 0; gsize offset = 0; - g_autoptr(GPtrArray) firmware = NULL; - g_return_val_if_fail (blob != NULL, NULL); + g_return_val_if_fail (fw != NULL, FALSE); - firmware = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_synaprom_firmware_item_free); - buf = g_bytes_get_data (blob, &bufsz); + buf = g_bytes_get_data (fw, &bufsz); /* 256 byte signature as footer */ if (bufsz < FU_SYNAPROM_FIRMWARE_SIGSIZE + sizeof(FuSynapromFirmwareHdr)) { @@ -65,7 +62,7 @@ fu_synaprom_firmware_new (GBytes *blob, GError **error) G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "blob is too small to be firmware"); - return NULL; + return FALSE; } bufsz -= FU_SYNAPROM_FIRMWARE_SIGSIZE; @@ -73,19 +70,20 @@ fu_synaprom_firmware_new (GBytes *blob, GError **error) while (offset != bufsz) { FuSynapromFirmwareHdr header; guint32 hdrsz; - g_autofree FuSynapromFirmwareItem *item = NULL; + guint32 tag; + g_autoptr(GBytes) bytes = NULL; + g_autoptr(FuFirmwareImage) img = NULL; /* verify item header */ memcpy (&header, buf, sizeof(header)); - item = g_new0 (FuSynapromFirmwareItem, 1); - item->tag = GUINT16_FROM_LE(header.tag); - if (item->tag >= FU_SYNAPROM_FIRMWARE_TAG_MAX) { + tag = GUINT16_FROM_LE(header.tag); + if (tag >= FU_SYNAPROM_FIRMWARE_TAG_MAX) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "tag 0x%04x is too large", - item->tag); - return NULL; + tag); + return FALSE; } hdrsz = GUINT32_FROM_LE(header.bufsz); offset += sizeof(header) + hdrsz; @@ -95,41 +93,29 @@ fu_synaprom_firmware_new (GBytes *blob, GError **error) G_IO_ERROR_INVALID_DATA, "data is corrupted 0x%04x > 0x%04x", (guint) offset, (guint) bufsz); - return NULL; + return FALSE; } /* move pointer to data */ buf += sizeof(header); - item->bytes = g_bytes_new (buf, hdrsz); + bytes = g_bytes_new (buf, hdrsz); g_debug ("adding 0x%04x (%s) with size 0x%04x", - item->tag, - fu_synaprom_firmware_tag_to_string (item->tag), + tag, + fu_synaprom_firmware_tag_to_string (tag), hdrsz); - g_ptr_array_add (firmware, g_steal_pointer (&item)); + img = fu_firmware_image_new (bytes); + fu_firmware_image_set_idx (img, tag); + fu_firmware_image_set_id (img, fu_synaprom_firmware_tag_to_string (tag)); + fu_firmware_add_image (firmware, img); /* next item */ buf += hdrsz; } - return g_steal_pointer (&firmware); + return TRUE; } -GBytes * -fu_synaprom_firmware_get_bytes_by_tag (GPtrArray *firmware, guint16 tag, GError **error) -{ - for (guint i = 0; i < firmware->len; i++) { - FuSynapromFirmwareItem *item = g_ptr_array_index (firmware, i); - if (item->tag == tag) - return g_bytes_ref (item->bytes); - } - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_ARGUMENT, - "no item with tag 0x%04x", tag); - return NULL; -} - -GBytes * -fu_synaprom_firmware_generate (void) +static GBytes * +fu_synaprom_firmware_write (FuFirmware *self, GError **error) { GByteArray *blob = g_byte_array_new (); const guint8 data[] = { 'R', 'H' }; @@ -163,3 +149,22 @@ fu_synaprom_firmware_generate (void) } return g_byte_array_free_to_bytes (blob); } + +static void +fu_synaprom_firmware_init (FuSynapromFirmware *self) +{ +} + +static void +fu_synaprom_firmware_class_init (FuSynapromFirmwareClass *klass) +{ + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + klass_firmware->parse = fu_synaprom_firmware_parse; + klass_firmware->write = fu_synaprom_firmware_write; +} + +FuFirmware * +fu_synaprom_firmware_new (void) +{ + return FU_FIRMWARE (g_object_new (FU_TYPE_SYNAPROM_FIRMWARE, NULL)); +} diff --git a/plugins/synaptics-prometheus/fu-synaprom-firmware.h b/plugins/synaptics-prometheus/fu-synaprom-firmware.h index aa33974f1..96a8f80ec 100644 --- a/plugins/synaptics-prometheus/fu-synaprom-firmware.h +++ b/plugins/synaptics-prometheus/fu-synaprom-firmware.h @@ -7,7 +7,12 @@ #pragma once -#include +#include "fu-firmware.h" + +G_BEGIN_DECLS + +#define FU_TYPE_SYNAPROM_FIRMWARE (fu_synaprom_firmware_get_type ()) +G_DECLARE_FINAL_TYPE (FuSynapromFirmware, fu_synaprom_firmware, FU, SYNAPROM_FIRMWARE, FuFirmware) #define FU_SYNAPROM_FIRMWARE_TAG_MFW_HEADER 0x0001 #define FU_SYNAPROM_FIRMWARE_TAG_MFW_PAYLOAD 0x0002 @@ -34,9 +39,6 @@ typedef struct __attribute__((packed)) { guint8 unused[2]; } FuSynapromFirmwareCfgHeader; -GPtrArray *fu_synaprom_firmware_new (GBytes *blob, - GError **error); -GBytes *fu_synaprom_firmware_get_bytes_by_tag (GPtrArray *firmware, - guint16 tag, - GError **error); -GBytes *fu_synaprom_firmware_generate (void); +FuFirmware *fu_synaprom_firmware_new (void); + +G_END_DECLS diff --git a/plugins/synaptics-prometheus/meson.build b/plugins/synaptics-prometheus/meson.build index e819d266a..8fc887def 100644 --- a/plugins/synaptics-prometheus/meson.build +++ b/plugins/synaptics-prometheus/meson.build @@ -66,10 +66,15 @@ if get_option('tests') ], include_directories : [ include_directories('../..'), + include_directories('../../src'), + include_directories('../../libfwupd'), ], dependencies : [ gio, ], + link_with : [ + libfwupdprivate, + ], c_args : cargs ) endif diff --git a/plugins/uefi/fu-uefi-device.c b/plugins/uefi/fu-uefi-device.c index 1d50c5123..ab5d96de8 100644 --- a/plugins/uefi/fu-uefi-device.c +++ b/plugins/uefi/fu-uefi-device.c @@ -401,7 +401,7 @@ fu_uefi_device_write_update_info (FuUefiDevice *self, static gboolean fu_uefi_device_write_firmware (FuDevice *device, - GBytes *fw, + FuFirmware *firmware, FwupdInstallFlags install_flags, GError **error) { @@ -411,6 +411,7 @@ fu_uefi_device_write_firmware (FuDevice *device, const gchar *esp_path = fu_device_get_metadata (device, "EspPath"); efi_guid_t guid; g_autoptr(GBytes) fixed_fw = NULL; + g_autoptr(GBytes) fw = NULL; g_autofree gchar *basename = NULL; g_autofree gchar *directory = NULL; g_autofree gchar *fn = NULL; @@ -425,6 +426,11 @@ fu_uefi_device_write_firmware (FuDevice *device, return FALSE; } + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + /* save the blob to the ESP */ directory = fu_uefi_get_esp_path_for_os (esp_path); basename = g_strdup_printf ("fwupd-%s.cap", self->fw_class); diff --git a/plugins/unifying/fu-unifying-bootloader-nordic.c b/plugins/unifying/fu-unifying-bootloader-nordic.c index e933708f6..bbf58b889 100644 --- a/plugins/unifying/fu-unifying-bootloader-nordic.c +++ b/plugins/unifying/fu-unifying-bootloader-nordic.c @@ -196,15 +196,21 @@ fu_unifying_bootloader_nordic_erase (FuUnifyingBootloader *self, guint16 addr, G static gboolean fu_unifying_bootloader_nordic_write_firmware (FuDevice *device, - GBytes *fw, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { FuUnifyingBootloader *self = FU_UNIFYING_BOOTLOADER (device); const FuUnifyingBootloaderRequest *payload; guint16 addr; + g_autoptr(GBytes) fw = NULL; g_autoptr(GPtrArray) reqs = NULL; + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + /* erase firmware pages up to the bootloader */ fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); for (addr = fu_unifying_bootloader_get_addr_lo (self); diff --git a/plugins/unifying/fu-unifying-bootloader-texas.c b/plugins/unifying/fu-unifying-bootloader-texas.c index e4ba61c43..a0e5c7d1b 100644 --- a/plugins/unifying/fu-unifying-bootloader-texas.c +++ b/plugins/unifying/fu-unifying-bootloader-texas.c @@ -109,15 +109,21 @@ fu_unifying_bootloader_texas_clear_ram_buffer (FuUnifyingBootloader *self, GErro static gboolean fu_unifying_bootloader_texas_write_firmware (FuDevice *device, - GBytes *fw, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { FuUnifyingBootloader *self = FU_UNIFYING_BOOTLOADER (device); const FuUnifyingBootloaderRequest *payload; + g_autoptr(GBytes) fw = NULL; g_autoptr(GPtrArray) reqs = NULL; g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new (); + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + /* transfer payload */ reqs = fu_unifying_bootloader_parse_requests (self, fw, error); if (reqs == NULL) diff --git a/plugins/unifying/fu-unifying-peripheral.c b/plugins/unifying/fu-unifying-peripheral.c index 4d98ed7ef..e63eaede0 100644 --- a/plugins/unifying/fu-unifying-peripheral.c +++ b/plugins/unifying/fu-unifying-peripheral.c @@ -882,7 +882,7 @@ fu_unifying_peripheral_write_firmware_pkt (FuUnifyingPeripheral *self, static gboolean fu_unifying_peripheral_write_firmware (FuDevice *device, - GBytes *fw, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { @@ -891,6 +891,7 @@ fu_unifying_peripheral_write_firmware (FuDevice *device, const guint8 *data; guint8 cmd = 0x04; guint8 idx; + g_autoptr(GBytes) fw = NULL; /* if we're in bootloader mode, we should be able to get this feature */ idx = fu_unifying_peripheral_feature_get_idx (self, HIDPP_FEATURE_DFU); @@ -902,6 +903,11 @@ fu_unifying_peripheral_write_firmware (FuDevice *device, return FALSE; } + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + /* flash hardware */ data = g_bytes_get_data (fw, &sz); fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); diff --git a/plugins/wacom-raw/fu-wacom-device.c b/plugins/wacom-raw/fu-wacom-device.c index 7f66d0c22..aa09103a8 100644 --- a/plugins/wacom-raw/fu-wacom-device.c +++ b/plugins/wacom-raw/fu-wacom-device.c @@ -14,9 +14,9 @@ #include #include "fu-chunk.h" +#include "fu-ihex-firmware.h" #include "fu-wacom-common.h" #include "fu-wacom-device.h" -#include "dfu-firmware.h" typedef struct { @@ -216,69 +216,56 @@ fu_wacom_device_set_version_bootloader (FuWacomDevice *self, GError **error) return TRUE; } +static FuFirmware * +fu_wacom_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuFirmware) firmware = fu_ihex_firmware_new (); + if (!fu_firmware_parse (firmware, fw, flags, error)) + return NULL; + return g_steal_pointer (&firmware); +} + static gboolean fu_wacom_device_write_firmware (FuDevice *device, - GBytes *fw, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { FuWacomDevice *self = FU_WACOM_DEVICE (device); FuWacomDevicePrivate *priv = GET_PRIVATE (self); FuWacomDeviceClass *klass = FU_WACOM_DEVICE_GET_CLASS (device); - DfuElement *element; - DfuImage *image; - GBytes *fw_new; - g_autoptr(DfuFirmware) firmware = dfu_firmware_new (); + g_autoptr(FuFirmwareImage) img = NULL; + g_autoptr(GBytes) fw = NULL; g_autoptr(GPtrArray) chunks = NULL; - /* parse hex file */ - if (!dfu_firmware_parse_data (firmware, fw, DFU_FIRMWARE_PARSE_FLAG_NONE, error)) - return FALSE; - if (dfu_firmware_get_format (firmware) != DFU_FIRMWARE_FORMAT_INTEL_HEX) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "expected firmware format is 'ihex', got '%s'", - dfu_firmware_format_to_string (dfu_firmware_get_format (firmware))); - return FALSE; - } - /* use the correct image from the firmware */ - image = dfu_firmware_get_image_default (firmware); - if (image == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "no firmware image"); + img = fu_firmware_get_image_default (firmware, error); + if (img == NULL) return FALSE; - } - element = dfu_image_get_element_default (image); - if (element == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "no element in image"); - return FALSE; - } g_debug ("using element at addr 0x%0x", - (guint) dfu_element_get_address (element)); + (guint) fu_firmware_image_get_addr (img)); /* check start address and size */ - if (dfu_element_get_address (element) != priv->flash_base_addr) { + if (fu_firmware_image_get_addr (img) != priv->flash_base_addr) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "base addr invalid: 0x%05x", - (guint) dfu_element_get_address (element)); + (guint) fu_firmware_image_get_addr (img)); return FALSE; } - fw_new = dfu_element_get_contents (element); - if (g_bytes_get_size (fw_new) > priv->flash_size) { + fw = fu_firmware_image_get_bytes (img, error); + if (fw == NULL) + return FALSE; + if (g_bytes_get_size (fw) > priv->flash_size) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "size is invalid: 0x%05x", - (guint) g_bytes_get_size (fw_new)); + (guint) g_bytes_get_size (fw)); return FALSE; } @@ -289,7 +276,7 @@ fu_wacom_device_write_firmware (FuDevice *device, return FALSE; /* flash chunks */ - chunks = fu_chunk_array_new_from_bytes (fw_new, priv->flash_base_addr, + chunks = fu_chunk_array_new_from_bytes (fw, priv->flash_base_addr, 0x00, /* page_sz */ priv->flash_block_size); return klass->write_firmware (device, chunks, error); @@ -415,6 +402,7 @@ fu_wacom_device_class_init (FuWacomDeviceClass *klass) klass_device->to_string = fu_wacom_device_to_string; klass_device->open = fu_wacom_device_open; klass_device->close = fu_wacom_device_close; + klass_device->prepare_firmware = fu_wacom_device_prepare_firmware; klass_device->write_firmware = fu_wacom_device_write_firmware; klass_device->attach = fu_wacom_device_attach; klass_device->detach = fu_wacom_device_detach; diff --git a/plugins/wacom-raw/fu-wacom-device.h b/plugins/wacom-raw/fu-wacom-device.h index 0959eede7..ff0948c71 100644 --- a/plugins/wacom-raw/fu-wacom-device.h +++ b/plugins/wacom-raw/fu-wacom-device.h @@ -8,7 +8,6 @@ #include "fu-wacom-common.h" #include "fu-udev-device.h" -#include "dfu-element.h" G_BEGIN_DECLS diff --git a/plugins/wacom-raw/meson.build b/plugins/wacom-raw/meson.build index ec0b63f70..1a27f7c4d 100644 --- a/plugins/wacom-raw/meson.build +++ b/plugins/wacom-raw/meson.build @@ -15,7 +15,6 @@ shared_module('fu_plugin_wacom_raw', ], include_directories : [ include_directories('../..'), - include_directories('../dfu'), include_directories('../../src'), include_directories('../../libfwupd'), ], @@ -26,6 +25,6 @@ shared_module('fu_plugin_wacom_raw', plugin_deps, ], link_with : [ - dfu, + libfwupdprivate, ], ) diff --git a/plugins/wacom-usb/fu-self-test.c b/plugins/wacom-usb/fu-self-test.c index 2e271baa9..25926fb3c 100644 --- a/plugins/wacom-usb/fu-self-test.c +++ b/plugins/wacom-usb/fu-self-test.c @@ -19,11 +19,10 @@ static void fu_wac_firmware_parse_func (void) { - DfuElement *element; - DfuImage *image; gboolean ret; g_autofree gchar *fn = NULL; - g_autoptr(DfuFirmware) firmware = dfu_firmware_new (); + g_autoptr(FuFirmware) firmware = fu_wac_firmware_new (); + g_autoptr(FuFirmwareImage) img = NULL; g_autoptr(GBytes) blob_block = NULL; g_autoptr(GBytes) bytes = NULL; g_autoptr(GError) error = NULL; @@ -37,20 +36,17 @@ fu_wac_firmware_parse_func (void) bytes = fu_common_get_contents_bytes (fn, &error); g_assert_no_error (error); g_assert_nonnull (bytes); - ret = fu_wac_firmware_parse_data (firmware, bytes, - DFU_FIRMWARE_PARSE_FLAG_NONE, &error); + ret = fu_firmware_parse (firmware, bytes, FWUPD_INSTALL_FLAG_NONE, &error); g_assert_no_error (error); g_assert_true (ret); /* get image data */ - image = dfu_firmware_get_image (firmware, 0); - g_assert_nonnull (image); - element = dfu_image_get_element_default (image); - g_assert_nonnull (element); + img = fu_firmware_get_image_default (firmware, &error); + g_assert_no_error (error); + g_assert_nonnull (img); /* get block */ - blob_block = dfu_element_get_contents_chunk (element, 0x8008000, - 1024, &error); + blob_block = fu_firmware_image_get_bytes_chunk (img, 0x8008000, 1024, &error); g_assert_no_error (error); g_assert_nonnull (blob_block); fu_wac_buffer_dump ("IMG", FU_WAC_REPORT_ID_MODULE, diff --git a/plugins/wacom-usb/fu-wac-device.c b/plugins/wacom-usb/fu-wac-device.c index b698c4ce6..8f1556582 100644 --- a/plugins/wacom-usb/fu-wac-device.c +++ b/plugins/wacom-usb/fu-wac-device.c @@ -15,9 +15,6 @@ #include "fu-wac-module-bluetooth.h" #include "fu-wac-module-touch.h" -#include "dfu-common.h" -#include "dfu-firmware.h" - typedef struct __attribute__((packed)) { guint32 start_addr; guint32 block_sz; @@ -481,34 +478,37 @@ fu_wac_device_switch_to_flash_loader (FuWacDevice *self, GError **error) error); } +static FuFirmware * +fu_wac_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuFirmware) firmware = fu_wac_firmware_new (); + fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); + if (!fu_firmware_parse (firmware, fw, flags, error)) + return NULL; + return g_steal_pointer (&firmware); +} + static gboolean fu_wac_device_write_firmware (FuDevice *device, - GBytes *blob, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { - DfuElement *element; - DfuImage *image; FuWacDevice *self = FU_WAC_DEVICE (device); gsize blocks_done = 0; gsize blocks_total = 0; - g_autoptr(DfuFirmware) firmware = dfu_firmware_new (); - g_autoptr(GHashTable) fd_blobs = NULL; g_autofree guint32 *csum_local = NULL; + g_autoptr(FuFirmwareImage) img = NULL; + g_autoptr(GHashTable) fd_blobs = NULL; - /* load .wac file, including metadata */ - if (!fu_wac_firmware_parse_data (firmware, blob, - DFU_FIRMWARE_PARSE_FLAG_NONE, - error)) + /* use the correct image from the firmware */ + img = fu_firmware_get_image_by_idx (firmware, self->firmware_index == 1 ? 1 : 0, error); + if (img == NULL) return FALSE; - if (dfu_firmware_get_format (firmware) != DFU_FIRMWARE_FORMAT_SREC) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "expected firmware format is 'srec', got '%s'", - dfu_firmware_format_to_string (dfu_firmware_get_format (firmware))); - return FALSE; - } + g_debug ("using image at addr 0x%0x", (guint) fu_firmware_image_get_addr (img)); /* enter flash mode */ if (!fu_wac_device_switch_to_flash_loader (self, error)) @@ -518,28 +518,6 @@ fu_wac_device_write_firmware (FuDevice *device, if (!fu_wac_device_ensure_firmware_index (self, error)) return FALSE; - /* use the correct image from the firmware */ - image = dfu_firmware_get_image (firmware, self->firmware_index == 1 ? 1 : 0); - if (image == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "no firmware image for index %" G_GUINT16_FORMAT, - self->firmware_index); - return FALSE; - } - element = dfu_image_get_element_default (image); - if (element == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "no element in image %" G_GUINT16_FORMAT, - self->firmware_index); - return FALSE; - } - g_debug ("using element at addr 0x%0x", - (guint) dfu_element_get_address (element)); - /* get firmware parameters (page sz and transfer sz) */ if (!fu_wac_device_ensure_parameters (self, error)) return FALSE; @@ -572,13 +550,13 @@ fu_wac_device_write_firmware (FuDevice *device, if (fu_wav_device_flash_descriptor_is_wp (fd)) continue; - blob_tmp = dfu_element_get_contents_chunk (element, - fd->start_addr, - fd->block_sz, - NULL); + blob_tmp = fu_firmware_image_get_bytes_chunk (img, + fd->start_addr, + fd->block_sz, + NULL); if (blob_tmp == NULL) break; - blob_block = dfu_utils_bytes_pad (blob_tmp, fd->block_sz); + blob_block = fu_common_bytes_pad (blob_tmp, fd->block_sz); g_hash_table_insert (fd_blobs, fd, blob_block); } @@ -898,6 +876,7 @@ fu_wac_device_class_init (FuWacDeviceClass *klass) FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); object_class->finalize = fu_wac_device_finalize; + klass_device->prepare_firmware = fu_wac_device_prepare_firmware; klass_device->write_firmware = fu_wac_device_write_firmware; klass_device->to_string = fu_wac_device_to_string; klass_device->setup = fu_wac_device_setup; diff --git a/plugins/wacom-usb/fu-wac-firmware.c b/plugins/wacom-usb/fu-wac-firmware.c index e9b35673d..15e94a55f 100644 --- a/plugins/wacom-usb/fu-wac-firmware.c +++ b/plugins/wacom-usb/fu-wac-firmware.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright (C) 2018-2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -8,47 +8,42 @@ #include -#include "dfu-element.h" -#include "dfu-format-srec.h" -#include "dfu-image.h" - +#include "fu-common.h" +#include "fu-srec-firmware.h" +#include "fu-firmware-common.h" #include "fu-wac-firmware.h" #include "fwupd-error.h" +struct _FuWacFirmware { + FuFirmware parent_instance; +}; + +G_DEFINE_TYPE (FuWacFirmware, fu_wac_firmware, FU_TYPE_FIRMWARE) + typedef struct { guint32 addr; guint32 sz; guint32 prog_start_addr; -} DfuFirmwareWacHeaderRecord; +} FuFirmwareWacHeaderRecord; -/** - * fu_wac_firmware_parse_data: - * @firmware: a #DfuFirmware - * @bytes: data to parse - * @flags: some #DfuFirmwareParseFlags - * @error: a #GError, or %NULL - * - * Unpacks into a firmware object from DfuSe data. - * - * Returns: %TRUE for success - **/ -gboolean -fu_wac_firmware_parse_data (DfuFirmware *firmware, - GBytes *bytes, - DfuFirmwareParseFlags flags, - GError **error) +static gboolean +fu_wac_firmware_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) { gsize len; guint8 *data; - g_auto(GStrv) lines = NULL; - g_autoptr(GString) image_buffer = NULL; - g_autofree gchar *data_str = NULL; guint8 images_cnt = 0; + g_auto(GStrv) lines = NULL; g_autoptr(GPtrArray) header_infos = g_ptr_array_new_with_free_func (g_free); + g_autoptr(GString) image_buffer = NULL; /* check the prefix (BE) */ - data = (guint8 *) g_bytes_get_data (bytes, &len); + data = (guint8 *) g_bytes_get_data (fw, &len); if (memcmp (data, "WACOM", 5) != 0) { g_set_error_literal (error, FWUPD_ERROR, @@ -58,8 +53,7 @@ fu_wac_firmware_parse_data (DfuFirmware *firmware, } /* parse each line */ - data_str = g_strndup ((const gchar *) data, len); - lines = g_strsplit (data_str, "\n", -1); + lines = fu_common_strnsplit ((const gchar *) data, len, "\n", -1); for (guint i = 0; lines[i] != NULL; i++) { g_autofree gchar *cmd = g_strndup (lines[i], 2); @@ -81,11 +75,11 @@ fu_wac_firmware_parse_data (DfuFirmware *firmware, cmdlen); return FALSE; } - header_image_cnt = dfu_utils_buffer_parse_uint4 (lines[i] + 5); + header_image_cnt = fu_firmware_strparse_uint4 (lines[i] + 5); for (guint j = 0; j < header_image_cnt; j++) { - DfuFirmwareWacHeaderRecord *hdr = g_new0 (DfuFirmwareWacHeaderRecord, 1); - hdr->addr = dfu_utils_buffer_parse_uint32 (lines[i] + (j * 16) + 6); - hdr->sz = dfu_utils_buffer_parse_uint32 (lines[i] + (j * 16) + 14); + FuFirmwareWacHeaderRecord *hdr = g_new0 (FuFirmwareWacHeaderRecord, 1); + hdr->addr = fu_firmware_strparse_uint32 (lines[i] + (j * 16) + 6); + hdr->sz = fu_firmware_strparse_uint32 (lines[i] + (j * 16) + 14); g_ptr_array_add (header_infos, hdr); g_debug ("header_fw%u_addr: 0x%x", j, hdr->addr); g_debug ("header_fw%u_sz: 0x%x", j, hdr->sz); @@ -95,8 +89,8 @@ fu_wac_firmware_parse_data (DfuFirmware *firmware, /* firmware headline record */ if (cmdlen == 13) { - DfuFirmwareWacHeaderRecord *hdr; - guint8 idx = dfu_utils_buffer_parse_uint4 (lines[i] + 2); + FuFirmwareWacHeaderRecord *hdr; + guint8 idx = fu_firmware_strparse_uint4 (lines[i] + 2); if (idx == 0) { g_set_error (error, FWUPD_ERROR, @@ -114,7 +108,7 @@ fu_wac_firmware_parse_data (DfuFirmware *firmware, return FALSE; } hdr = g_ptr_array_index (header_infos, idx - 1); - hdr->prog_start_addr = dfu_utils_buffer_parse_uint32 (lines[i] + 3); + hdr->prog_start_addr = fu_firmware_strparse_uint32 (lines[i] + 3); if (hdr->prog_start_addr != hdr->addr) { g_set_error (error, FWUPD_ERROR, @@ -168,8 +162,9 @@ fu_wac_firmware_parse_data (DfuFirmware *firmware, /* end */ if (g_strcmp0 (cmd, "S7") == 0) { g_autoptr(GBytes) blob = NULL; - g_autoptr(DfuImage) image = dfu_image_new (); - DfuFirmwareWacHeaderRecord *hdr; + g_autoptr(FuFirmware) firmware_srec = fu_srec_firmware_new (); + g_autoptr(FuFirmwareImage) img = NULL; + FuFirmwareWacHeaderRecord *hdr; /* get the correct relocated start address */ if (images_cnt >= header_infos->len) { @@ -191,12 +186,13 @@ fu_wac_firmware_parse_data (DfuFirmware *firmware, /* parse SREC file and add as image */ blob = g_bytes_new (image_buffer->str, image_buffer->len); - if (!dfu_image_from_srec (image, blob, hdr->addr, flags, error)) + if (!fu_firmware_parse_full (firmware_srec, blob, hdr->addr, 0x0, flags, error)) return FALSE; - - /* the alt-setting is used for the firmware index */ - dfu_image_set_alt_setting (image, images_cnt); - dfu_firmware_add_image (firmware, image); + img = fu_firmware_get_image_default (firmware_srec, error); + if (img == NULL) + return FALSE; + fu_firmware_image_set_idx (img, images_cnt); + fu_firmware_add_image (firmware, img); images_cnt++; /* clear the image buffer */ @@ -226,6 +222,23 @@ fu_wac_firmware_parse_data (DfuFirmware *firmware, } /* success */ - dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_SREC); return TRUE; } + +static void +fu_wac_firmware_init (FuWacFirmware *self) +{ +} + +static void +fu_wac_firmware_class_init (FuWacFirmwareClass *klass) +{ + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + klass_firmware->parse = fu_wac_firmware_parse; +} + +FuFirmware * +fu_wac_firmware_new (void) +{ + return FU_FIRMWARE (g_object_new (FU_TYPE_WAC_FIRMWARE, NULL)); +} diff --git a/plugins/wacom-usb/fu-wac-firmware.h b/plugins/wacom-usb/fu-wac-firmware.h index 29221a44e..03d8c2b3b 100644 --- a/plugins/wacom-usb/fu-wac-firmware.h +++ b/plugins/wacom-usb/fu-wac-firmware.h @@ -1,20 +1,18 @@ /* - * Copyright (C) 2018 Richard Hughes + * Copyright (C) 2018-2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -#include - -#include "dfu-firmware.h" +#include "fu-firmware.h" G_BEGIN_DECLS -gboolean fu_wac_firmware_parse_data (DfuFirmware *firmware, - GBytes *bytes, - DfuFirmwareParseFlags flags, - GError **error); +#define FU_TYPE_WAC_FIRMWARE (fu_wac_firmware_get_type ()) +G_DECLARE_FINAL_TYPE (FuWacFirmware, fu_wac_firmware, FU, WAC_FIRMWARE, FuFirmware) + +FuFirmware *fu_wac_firmware_new (void); G_END_DECLS diff --git a/plugins/wacom-usb/fu-wac-module-bluetooth.c b/plugins/wacom-usb/fu-wac-module-bluetooth.c index f8a2c2de5..d4d07b673 100644 --- a/plugins/wacom-usb/fu-wac-module-bluetooth.c +++ b/plugins/wacom-usb/fu-wac-module-bluetooth.c @@ -106,7 +106,7 @@ fu_wac_module_bluetooth_parse_blocks (const guint8 *data, gsize sz, gboolean ski static gboolean fu_wac_module_bluetooth_write_firmware (FuDevice *device, - GBytes *blob, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { @@ -117,9 +117,15 @@ fu_wac_module_bluetooth_write_firmware (FuDevice *device, const guint8 buf_start[] = { 0x00 }; g_autoptr(GPtrArray) blocks = NULL; g_autoptr(GBytes) blob_start = g_bytes_new_static (buf_start, 1); + g_autoptr(GBytes) fw = NULL; + + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; /* build each data packet */ - data = g_bytes_get_data (blob, &len); + data = g_bytes_get_data (fw, &len); blocks = fu_wac_module_bluetooth_parse_blocks (data, len, TRUE); blocks_total = blocks->len + 2; diff --git a/plugins/wacom-usb/fu-wac-module-touch.c b/plugins/wacom-usb/fu-wac-module-touch.c index e39e288dc..f9fd494d7 100644 --- a/plugins/wacom-usb/fu-wac-module-touch.c +++ b/plugins/wacom-usb/fu-wac-module-touch.c @@ -12,7 +12,7 @@ #include "fu-wac-module-touch.h" #include "fu-chunk.h" -#include "dfu-firmware.h" +#include "fu-ihex-firmware.h" struct _FuWacModuleTouch { @@ -21,57 +21,43 @@ struct _FuWacModuleTouch G_DEFINE_TYPE (FuWacModuleTouch, fu_wac_module_touch, FU_TYPE_WAC_MODULE) +static FuFirmware * +fu_wac_module_touch_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuFirmware) firmware = fu_ihex_firmware_new (); + if (!fu_firmware_parse (firmware, fw, flags, error)) + return NULL; + return g_steal_pointer (&firmware); +} + static gboolean fu_wac_module_touch_write_firmware (FuDevice *device, - GBytes *blob, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { - DfuElement *element; - DfuImage *image; FuWacModule *self = FU_WAC_MODULE (device); gsize blocks_total = 0; + g_autoptr(FuFirmwareImage) img = NULL; + g_autoptr(GBytes) fw = NULL; g_autoptr(GPtrArray) chunks = NULL; - g_autoptr(DfuFirmware) firmware = dfu_firmware_new (); - - /* load .hex file */ - if (!dfu_firmware_parse_data (firmware, blob, DFU_FIRMWARE_PARSE_FLAG_NONE, error)) - return FALSE; - - /* check type */ - if (dfu_firmware_get_format (firmware) != DFU_FIRMWARE_FORMAT_INTEL_HEX) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "expected firmware format is 'ihex', got '%s'", - dfu_firmware_format_to_string (dfu_firmware_get_format (firmware))); - return FALSE; - } /* use the correct image from the firmware */ - image = dfu_firmware_get_image (firmware, 0); - if (image == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "no firmware image"); + img = fu_firmware_get_image_default (firmware, error); + if (img == NULL) return FALSE; - } - element = dfu_image_get_element_default (image); - if (element == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "no firmware element"); - return FALSE; - } g_debug ("using element at addr 0x%0x", - (guint) dfu_element_get_address (element)); - blob = dfu_element_get_contents (element); + (guint) fu_firmware_image_get_addr (img)); + fw = fu_firmware_image_get_bytes (img, error); + if (fw == NULL) + return FALSE; /* build each data packet */ - chunks = fu_chunk_array_new_from_bytes (blob, - dfu_element_get_address (element), + chunks = fu_chunk_array_new_from_bytes (fw, + fu_firmware_image_get_addr (img), 0x0, /* page_sz */ 128); /* packet_sz */ blocks_total = chunks->len + 2; @@ -129,6 +115,7 @@ static void fu_wac_module_touch_class_init (FuWacModuleTouchClass *klass) { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + klass_device->prepare_firmware = fu_wac_module_touch_prepare_firmware; klass_device->write_firmware = fu_wac_module_touch_write_firmware; } diff --git a/plugins/wacom-usb/fu-wac-module.c b/plugins/wacom-usb/fu-wac-module.c index 11e666a6e..033f56bb4 100644 --- a/plugins/wacom-usb/fu-wac-module.c +++ b/plugins/wacom-usb/fu-wac-module.c @@ -12,9 +12,6 @@ #include "fu-wac-common.h" #include "fu-wac-device.h" -#include "dfu-common.h" -#include "dfu-firmware.h" - #define FU_WAC_MODULE_STATUS_OK 0 #define FU_WAC_MODULE_STATUS_BUSY 1 #define FU_WAC_MODULE_STATUS_ERR_CRC 2 diff --git a/plugins/wacom-usb/meson.build b/plugins/wacom-usb/meson.build index fd92ed4bf..3090aa0ae 100644 --- a/plugins/wacom-usb/meson.build +++ b/plugins/wacom-usb/meson.build @@ -17,7 +17,6 @@ shared_module('fu_plugin_wacom_usb', ], include_directories : [ include_directories('../..'), - include_directories('../dfu'), include_directories('../../src'), include_directories('../../libfwupd'), ], @@ -29,7 +28,6 @@ shared_module('fu_plugin_wacom_usb', ], link_with : [ libfwupdprivate, - dfu, ], ) @@ -46,7 +44,6 @@ if get_option('tests') ], include_directories : [ include_directories('..'), - include_directories('../dfu'), include_directories('../..'), include_directories('../../libfwupd'), include_directories('../../src'), @@ -59,7 +56,6 @@ if get_option('tests') libm, ], link_with : [ - dfu, libfwupdprivate, ], c_args : cargs diff --git a/src/fu-common.c b/src/fu-common.c index 205af83de..e2803c240 100644 --- a/src/fu-common.c +++ b/src/fu-common.c @@ -1333,6 +1333,36 @@ fu_common_bytes_compare (GBytes *bytes1, GBytes *bytes2, GError **error) return TRUE; } +/** + * fu_common_bytes_pad: + * @bytes: a #GBytes + * @sz: the desired size in bytes + * + * Pads a GBytes to a given @sz with `0xff`. + * + * Return value: (transfer full): a #GBytes + **/ +GBytes * +fu_common_bytes_pad (GBytes *bytes, gsize sz) +{ + gsize bytes_sz; + + g_return_val_if_fail (g_bytes_get_size (bytes) <= sz, NULL); + + /* pad */ + bytes_sz = g_bytes_get_size (bytes); + if (bytes_sz < sz) { + const guint8 *data = g_bytes_get_data (bytes, NULL); + guint8 *data_new = g_malloc (sz); + memcpy (data_new, data, bytes_sz); + memset (data_new + bytes_sz, 0xff, sz - bytes_sz); + return g_bytes_new_take (data_new, sz); + } + + /* exactly right */ + return g_bytes_ref (bytes); +} + /** * fu_common_realpath: * @filename: a filename @@ -1359,3 +1389,27 @@ fu_common_realpath (const gchar *filename, GError **error) } return g_strdup (full_tmp); } + +/** + * fu_common_strnsplit: + * @str: a string to split + * @sz: size of @str + * @delimiter: a string which specifies the places at which to split the string + * @max_tokens: the maximum number of pieces to split @str into + * + * Splits a string into a maximum of @max_tokens pieces, using the given + * delimiter. If @max_tokens is reached, the remainder of string is appended + * to the last token. + * + * Return value: a newly-allocated NULL-terminated array of strings + **/ +gchar ** +fu_common_strnsplit (const gchar *str, gsize sz, + const gchar *delimiter, gint max_tokens) +{ + if (str[sz - 1] != '\0') { + g_autofree gchar *str2 = g_strndup (str, sz); + return g_strsplit (str2, delimiter, max_tokens); + } + return g_strsplit (str, delimiter, max_tokens); +} diff --git a/src/fu-common.h b/src/fu-common.h index 231b9d5a5..25672ab27 100644 --- a/src/fu-common.h +++ b/src/fu-common.h @@ -133,6 +133,8 @@ gboolean fu_common_bytes_is_empty (GBytes *bytes); gboolean fu_common_bytes_compare (GBytes *bytes1, GBytes *bytes2, GError **error); +GBytes *fu_common_bytes_pad (GBytes *bytes, + gsize sz); typedef guint FuEndianType; @@ -150,5 +152,9 @@ guint32 fu_common_read_uint32 (const guint8 *buf, guint fu_common_string_replace (GString *string, const gchar *search, const gchar *replace); +gchar **fu_common_strnsplit (const gchar *str, + gsize sz, + const gchar *delimiter, + gint max_tokens); G_END_DECLS diff --git a/src/fu-device.c b/src/fu-device.c index 2248e68ab..d1e18eacb 100644 --- a/src/fu-device.c +++ b/src/fu-device.c @@ -1754,7 +1754,7 @@ fu_device_write_firmware (FuDevice *self, GError **error) { FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); - g_autoptr(GBytes) fw_new = NULL; + g_autoptr(FuFirmware) firmware = NULL; g_return_val_if_fail (FU_IS_DEVICE (self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); @@ -1769,12 +1769,12 @@ fu_device_write_firmware (FuDevice *self, } /* prepare (e.g. decompress) firmware */ - fw_new = fu_device_prepare_firmware (self, fw, flags, error); - if (fw_new == NULL) + firmware = fu_device_prepare_firmware (self, fw, flags, error); + if (firmware == NULL) return FALSE; /* call vfunc */ - return klass->write_firmware (self, fw_new, flags, error); + return klass->write_firmware (self, firmware, flags, error); } /** @@ -1796,7 +1796,7 @@ fu_device_write_firmware (FuDevice *self, * * Since: 1.1.2 **/ -GBytes * +FuFirmware * fu_device_prepare_firmware (FuDevice *self, GBytes *fw, FwupdInstallFlags flags, @@ -1804,8 +1804,8 @@ fu_device_prepare_firmware (FuDevice *self, { FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); FuDevicePrivate *priv = GET_PRIVATE (self); - guint64 fw_sz; - g_autoptr(GBytes) fw_new = NULL; + g_autoptr(FuFirmware) firmware = NULL; + g_autoptr(GBytes) fw_def = NULL; g_return_val_if_fail (FU_IS_DEVICE (self), NULL); g_return_val_if_fail (fw != NULL, NULL); @@ -1813,37 +1813,41 @@ fu_device_prepare_firmware (FuDevice *self, /* optionally subclassed */ if (klass->prepare_firmware != NULL) { - fw_new = klass->prepare_firmware (self, fw, flags, error); - if (fw_new == NULL) + firmware = klass->prepare_firmware (self, fw, flags, error); + if (firmware == NULL) return NULL; } else { - fw_new = g_bytes_ref (fw); + firmware = fu_firmware_new_from_bytes (fw); } /* check size */ - fw_sz = (guint64) g_bytes_get_size (fw_new); - if (priv->size_max > 0 && fw_sz > priv->size_max) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "firmware is %04x bytes larger than the allowed " - "maximum size of %04x bytes", - (guint) (fw_sz - priv->size_max), - (guint) priv->size_max); - return NULL; - } - if (priv->size_min > 0 && fw_sz < priv->size_min) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "firmware is %04x bytes smaller than the allowed " - "minimum size of %04x bytes", - (guint) (priv->size_min - fw_sz), - (guint) priv->size_max); - return NULL; + fw_def = fu_firmware_get_image_default_bytes (firmware, NULL); + if (fw_def != NULL) { + guint64 fw_sz = (guint64) g_bytes_get_size (fw_def); + if (priv->size_max > 0 && fw_sz > priv->size_max) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "firmware is %04x bytes larger than the allowed " + "maximum size of %04x bytes", + (guint) (fw_sz - priv->size_max), + (guint) priv->size_max); + return NULL; + } + if (priv->size_min > 0 && fw_sz < priv->size_min) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "firmware is %04x bytes smaller than the allowed " + "minimum size of %04x bytes", + (guint) (priv->size_min - fw_sz), + (guint) priv->size_max); + return NULL; + } } - return g_steal_pointer (&fw_new); + /* success */ + return g_steal_pointer (&firmware); } /** diff --git a/src/fu-device.h b/src/fu-device.h index ba9cecc4f..1e482d9d7 100644 --- a/src/fu-device.h +++ b/src/fu-device.h @@ -9,6 +9,7 @@ #include #include +#include "fu-firmware.h" #include "fu-quirks.h" #include "fu-common-version.h" @@ -23,7 +24,7 @@ struct _FuDeviceClass void (*to_string) (FuDevice *self, GString *str); gboolean (*write_firmware) (FuDevice *self, - GBytes *fw, + FuFirmware *firmware, FwupdInstallFlags flags, GError **error); GBytes *(*read_firmware) (FuDevice *self, @@ -38,7 +39,7 @@ struct _FuDeviceClass GError **error); gboolean (*probe) (FuDevice *self, GError **error); - GBytes *(*prepare_firmware) (FuDevice *self, + FuFirmware *(*prepare_firmware) (FuDevice *self, GBytes *fw, FwupdInstallFlags flags, GError **error); @@ -210,7 +211,7 @@ gboolean fu_device_write_firmware (FuDevice *self, GBytes *fw, FwupdInstallFlags flags, GError **error); -GBytes *fu_device_prepare_firmware (FuDevice *self, +FuFirmware *fu_device_prepare_firmware (FuDevice *self, GBytes *fw, FwupdInstallFlags flags, GError **error); diff --git a/src/fu-firmware-common.c b/src/fu-firmware-common.c new file mode 100644 index 000000000..79b7c2638 --- /dev/null +++ b/src/fu-firmware-common.c @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2015-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuFirmware" + +#include + +#include + +#include "fu-firmware-common.h" + +/** + * fu_firmware_strparse_uint4: + * @data: a string + * + * Parses a base 16 number from a string. + * + * The string MUST be at least 1 byte long as this function cannot check the + * length of @data. Checking the size must be done in the caller. + * + * Return value: A parsed value, or 0 for error + **/ +guint8 +fu_firmware_strparse_uint4 (const gchar *data) +{ + gchar buffer[2]; + memcpy (buffer, data, 1); + buffer[1] = '\0'; + return (guint8) g_ascii_strtoull (buffer, NULL, 16); +} + +/** + * fu_firmware_strparse_uint8: + * @data: a string + * + * Parses a base 16 number from a string. + * + * The string MUST be at least 2 bytes long as this function cannot check the + * length of @data. Checking the size must be done in the caller. + * + * Return value: A parsed value, or 0 for error + **/ +guint8 +fu_firmware_strparse_uint8 (const gchar *data) +{ + gchar buffer[3]; + memcpy (buffer, data, 2); + buffer[2] = '\0'; + return (guint8) g_ascii_strtoull (buffer, NULL, 16); +} + +/** + * fu_firmware_strparse_uint16: + * @data: a string + * + * Parses a base 16 number from a string. + * + * The string MUST be at least 4 bytes long as this function cannot check the + * length of @data. Checking the size must be done in the caller. + * + * Return value: A parsed value, or 0 for error + **/ +guint16 +fu_firmware_strparse_uint16 (const gchar *data) +{ + gchar buffer[5]; + memcpy (buffer, data, 4); + buffer[4] = '\0'; + return (guint16) g_ascii_strtoull (buffer, NULL, 16); +} + +/** + * fu_firmware_strparse_uint24: + * @data: a string + * + * Parses a base 16 number from a string. + * + * The string MUST be at least 6 bytes long as this function cannot check the + * length of @data. Checking the size must be done in the caller. + * + * Return value: A parsed value, or 0 for error + **/ +guint32 +fu_firmware_strparse_uint24 (const gchar *data) +{ + gchar buffer[7]; + memcpy (buffer, data, 6); + buffer[6] = '\0'; + return (guint32) g_ascii_strtoull (buffer, NULL, 16); +} + +/** + * fu_firmware_strparse_uint32: + * @data: a string + * + * Parses a base 16 number from a string. + * + * The string MUST be at least 8 bytes long as this function cannot check the + * length of @data. Checking the size must be done in the caller. + * + * Return value: A parsed value, or 0 for error + **/ +guint32 +fu_firmware_strparse_uint32 (const gchar *data) +{ + gchar buffer[9]; + memcpy (buffer, data, 8); + buffer[8] = '\0'; + return (guint32) g_ascii_strtoull (buffer, NULL, 16); +} diff --git a/src/fu-firmware-common.h b/src/fu-firmware-common.h new file mode 100644 index 000000000..6aa25c82d --- /dev/null +++ b/src/fu-firmware-common.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2015-2017 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +guint8 fu_firmware_strparse_uint4 (const gchar *data); +guint8 fu_firmware_strparse_uint8 (const gchar *data); +guint16 fu_firmware_strparse_uint16 (const gchar *data); +guint32 fu_firmware_strparse_uint24 (const gchar *data); +guint32 fu_firmware_strparse_uint32 (const gchar *data); + +G_END_DECLS diff --git a/src/fu-firmware-image.c b/src/fu-firmware-image.c new file mode 100644 index 000000000..708e8b351 --- /dev/null +++ b/src/fu-firmware-image.c @@ -0,0 +1,329 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuFirmware" + +#include "config.h" + +#include + +#include "fu-firmware-image.h" + +/** + * SECTION:fu-firmware_image + * @short_description: a firmware_image file + * + * An object that represents a firmware_image file. + */ + +typedef struct { + gchar *id; + GBytes *bytes; + guint64 addr; + guint64 idx; +} FuFirmwareImagePrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (FuFirmwareImage, fu_firmware_image, G_TYPE_OBJECT) +#define GET_PRIVATE(o) (fu_firmware_image_get_instance_private (o)) + +/** + * fu_firmware_image_set_id: + * @self: a #FuPlugin + * @id: image ID, e.g. "config" + * + * Since: 1.2.11 + **/ +void +fu_firmware_image_set_id (FuFirmwareImage *self, const gchar *id) +{ + FuFirmwareImagePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_FIRMWARE_IMAGE (self)); + g_return_if_fail (id != NULL); + g_free (priv->id); + priv->id = g_strdup (id); +} + +/** + * fu_firmware_image_get_id: + * @self: a #FuPlugin + * + * Gets the image ID, typically set at construction. + * + * Returns: image ID, e.g. "config" + * + * Since: 1.2.11 + **/ +const gchar * +fu_firmware_image_get_id (FuFirmwareImage *self) +{ + FuFirmwareImagePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), FALSE); + return priv->id; +} + +/** + * fu_firmware_image_set_addr: + * @self: a #FuPlugin + * @addr: integer + * + * Sets the base address of the image. + * + * Since: 1.2.11 + **/ +void +fu_firmware_image_set_addr (FuFirmwareImage *self, guint64 addr) +{ + FuFirmwareImagePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_FIRMWARE_IMAGE (self)); + priv->addr = addr; +} + +/** + * fu_firmware_image_get_addr: + * @self: a #FuPlugin + * + * Gets the base address of the image. + * + * Returns: integer + * + * Since: 1.2.11 + **/ +guint64 +fu_firmware_image_get_addr (FuFirmwareImage *self) +{ + FuFirmwareImagePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), G_MAXUINT64); + return priv->addr; +} + +/** + * fu_firmware_image_set_idx: + * @self: a #FuPlugin + * @idx: integer + * + * Sets the index of the image which is used for ordering. + * + * Since: 1.2.11 + **/ +void +fu_firmware_image_set_idx (FuFirmwareImage *self, guint64 idx) +{ + FuFirmwareImagePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_FIRMWARE_IMAGE (self)); + priv->idx = idx; +} + +/** + * fu_firmware_image_get_idx: + * @self: a #FuPlugin + * + * Gets the index of the image which is used for ordering. + * + * Returns: integer + * + * Since: 1.2.11 + **/ +guint64 +fu_firmware_image_get_idx (FuFirmwareImage *self) +{ + FuFirmwareImagePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), G_MAXUINT64); + return priv->idx; +} + +/** + * fu_firmware_image_set_bytes: + * @self: a #FuPlugin + * @bytes: A #GBytes + * + * Sets the contents of the image if not created with fu_firmware_image_new(). + * + * Since: 1.2.11 + **/ +void +fu_firmware_image_set_bytes (FuFirmwareImage *self, GBytes *bytes) +{ + FuFirmwareImagePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_FIRMWARE_IMAGE (self)); + g_return_if_fail (bytes != NULL); + g_return_if_fail (priv->bytes == NULL); + priv->bytes = g_bytes_ref (bytes); +} + +/** + * fu_firmware_image_get_bytes: + * @self: a #FuPlugin + * @error: A #GError, or %NULL + * + * Gets the contents of the bytes. + * + * Returns: (transfer full): a #GBytes of the bytes, or %NULL if the bytes is not set + * + * Since: 1.2.11 + **/ +GBytes * +fu_firmware_image_get_bytes (FuFirmwareImage *self, GError **error) +{ + FuFirmwareImagePrivate *priv = GET_PRIVATE (self); + + g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + if (priv->bytes == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no bytes found in firmware bytes %s", priv->id); + return NULL; + } + return g_bytes_ref (priv->bytes); +} + +/** + * fu_firmware_image_get_bytes_chunk: + * @self: a #FuFirmwareImage + * @address: an address greater than dfu_element_get_address() + * @chunk_sz_max: the size of the new chunk + * @error: a #GError, or %NULL + * + * Gets a block of data from the image. If the contents of the image is + * smaller than the requested chunk size then the #GBytes will be smaller + * than @chunk_sz_max. Use fu_common_bytes_pad() if padding is required. + * + * If the @address is larger than the size of the image then an error is returned. + * + * Return value: (transfer full): a #GBytes, or %NULL + * + * Since: 1.2.11 + **/ +GBytes * +fu_firmware_image_get_bytes_chunk (FuFirmwareImage *self, + guint64 address, + guint64 chunk_sz_max, + GError **error) +{ + FuFirmwareImagePrivate *priv = GET_PRIVATE (self); + gsize chunk_left; + guint64 offset; + + /* check address requested is larger than base address */ + if (address < priv->addr) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "requested address 0x%x less than base address 0x%x", + (guint) address, (guint) priv->addr); + return NULL; + } + + /* offset into data */ + offset = address - priv->addr; + if (offset > g_bytes_get_size (priv->bytes)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "offset 0x%x larger than data size 0x%x", + (guint) offset, + (guint) g_bytes_get_size (priv->bytes)); + return NULL; + } + + /* if we have less data than requested */ + chunk_left = g_bytes_get_size (priv->bytes) - offset; + if (chunk_sz_max > chunk_left) + return g_bytes_new_from_bytes (priv->bytes, offset, chunk_left); + + /* check chunk */ + return g_bytes_new_from_bytes (priv->bytes, offset, chunk_sz_max); +} + +static void +fwupd_pad_kv_str (GString *str, const gchar *key, const gchar *value) +{ + /* ignore */ + if (key == NULL || value == NULL) + return; + g_string_append_printf (str, " %s: ", key); + for (gsize i = strlen (key); i < 20; i++) + g_string_append (str, " "); + g_string_append_printf (str, "%s\n", value); +} + +/** + * fu_firmware_image_to_string: + * @self: A #FuFirmwareImage + * + * This allows us to easily print the object. + * + * Returns: a string value, or %NULL for invalid. + * + * Since: 1.2.11 + **/ +gchar * +fu_firmware_image_to_string (FuFirmwareImage *self) +{ + FuFirmwareImagePrivate *priv = GET_PRIVATE (self); + GString *str = g_string_new (" FuFirmwareImage:\n"); + if (priv->id != NULL) + fwupd_pad_kv_str (str, "ID", priv->id); + if (priv->idx != 0x0) { + g_autofree gchar *tmp = g_strdup_printf ("0x%04x", (guint) priv->idx); + fwupd_pad_kv_str (str, "Index", tmp); + } + if (priv->addr != 0x0) { + g_autofree gchar *tmp = g_strdup_printf ("0x%04x", (guint) priv->addr); + fwupd_pad_kv_str (str, "Address", tmp); + } + if (priv->bytes != NULL) { + gsize sz = g_bytes_get_size (priv->bytes); + g_autofree gchar *tmp = g_strdup_printf ("%04x", (guint) sz); + fwupd_pad_kv_str (str, "Data", tmp); + } + return g_string_free (str, FALSE); +} + +static void +fu_firmware_image_init (FuFirmwareImage *self) +{ +} + +static void +fu_firmware_image_finalize (GObject *object) +{ + FuFirmwareImage *self = FU_FIRMWARE_IMAGE (object); + FuFirmwareImagePrivate *priv = GET_PRIVATE (self); + g_free (priv->id); + if (priv->bytes != NULL) + g_bytes_unref (priv->bytes); + G_OBJECT_CLASS (fu_firmware_image_parent_class)->finalize (object); +} + +static void +fu_firmware_image_class_init (FuFirmwareImageClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_firmware_image_finalize; +} + +/** + * fu_firmware_image_new: + * @id: Optional ID + * @bytes: Optional #GBytes + * + * Creates an empty firmware_image object. + * + * Returns: a #FuFirmwareImage + * + * Since: 1.2.11 + **/ +FuFirmwareImage * +fu_firmware_image_new (GBytes *bytes) +{ + FuFirmwareImage *self = g_object_new (FU_TYPE_FIRMWARE_IMAGE, NULL); + if (bytes != NULL) + fu_firmware_image_set_bytes (self, bytes); + return self; +} diff --git a/src/fu-firmware-image.h b/src/fu-firmware-image.h new file mode 100644 index 000000000..5a20b1578 --- /dev/null +++ b/src/fu-firmware-image.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include +#include + +G_BEGIN_DECLS + +#define FU_TYPE_FIRMWARE_IMAGE (fu_firmware_image_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FuFirmwareImage, fu_firmware_image, FU, FIRMWARE_IMAGE, GObject) + +struct _FuFirmwareImageClass +{ + GObjectClass parent_class; + gboolean (*parse) (FuFirmwareImage *self, + GBytes *fw, + FwupdInstallFlags flags, + GError **error); + /*< private >*/ + gpointer padding[30]; +}; + +FuFirmwareImage *fu_firmware_image_new (GBytes *bytes); +gchar *fu_firmware_image_to_string (FuFirmwareImage *self); + +const gchar *fu_firmware_image_get_id (FuFirmwareImage *self); +void fu_firmware_image_set_id (FuFirmwareImage *self, + const gchar *id); +guint64 fu_firmware_image_get_addr (FuFirmwareImage *self); +void fu_firmware_image_set_addr (FuFirmwareImage *self, + guint64 addr); +guint64 fu_firmware_image_get_idx (FuFirmwareImage *self); +void fu_firmware_image_set_idx (FuFirmwareImage *self, + guint64 idx); +void fu_firmware_image_set_bytes (FuFirmwareImage *self, + GBytes *bytes); +GBytes *fu_firmware_image_get_bytes (FuFirmwareImage *self, + GError **error); +GBytes *fu_firmware_image_get_bytes_chunk(FuFirmwareImage *self, + guint64 address, + guint64 chunk_sz_max, + GError **error); + +G_END_DECLS diff --git a/src/fu-firmware.c b/src/fu-firmware.c new file mode 100644 index 000000000..1cb945aac --- /dev/null +++ b/src/fu-firmware.c @@ -0,0 +1,402 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuFirmware" + +#include "config.h" + +#include "fu-firmware.h" + +/** + * SECTION:fu-firmware + * @short_description: a firmware file + * + * An object that represents a firmware file. + */ + +typedef struct { + GPtrArray *images; /* FuFirmwareImage */ +} FuFirmwarePrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (FuFirmware, fu_firmware, G_TYPE_OBJECT) +#define GET_PRIVATE(o) (fu_firmware_get_instance_private (o)) + +/** + * fu_firmware_parse_full: + * @self: A #FuFirmware + * @image: A #GBytes + * @addr_start: Start address, useful for ignoring a bootloader + * @addr_end: End address, useful for ignoring config bytes + * @flags: some #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_FORCE + * @error: A #GError, or %NULL + * + * Parses a firmware, typically breaking the firmware into images. + * + * Returns: %TRUE for success + * + * Since: 1.2.11 + **/ +gboolean +fu_firmware_parse_full (FuFirmware *self, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + FuFirmwareClass *klass = FU_FIRMWARE_GET_CLASS (self); + g_autoptr(FuFirmwareImage) img = NULL; + + g_return_val_if_fail (FU_IS_FIRMWARE (self), FALSE); + g_return_val_if_fail (fw != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* subclassed */ + if (klass->parse != NULL) + return klass->parse (self, fw, addr_start, addr_end, flags, error); + + /* just add entire blob */ + img = fu_firmware_image_new (fw); + fu_firmware_add_image (self, img); + return TRUE; +} + +/** + * fu_firmware_parse: + * @self: A #FuFirmware + * @image: A #GBytes + * @flags: some #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_FORCE + * @error: A #GError, or %NULL + * + * Parses a firmware, typically breaking the firmware into images. + * + * Returns: %TRUE for success + * + * Since: 1.2.11 + **/ +gboolean +fu_firmware_parse (FuFirmware *self, GBytes *fw, FwupdInstallFlags flags, GError **error) +{ + return fu_firmware_parse_full (self, fw, 0x0, 0x0, flags, error); +} + +/** + * fu_firmware_write: + * @self: A #FuFirmware + * @error: A #GError, or %NULL + * + * Writes a firmware, typically packing the images into a binary blob. + * + * Returns: (transfer full): a #GBytes + * + * Since: 1.2.11 + **/ +GBytes * +fu_firmware_write (FuFirmware *self, GError **error) +{ + FuFirmwareClass *klass = FU_FIRMWARE_GET_CLASS (self); + + g_return_val_if_fail (FU_IS_FIRMWARE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* subclassed */ + if (klass->write != NULL) + return klass->write (self, error); + + /* just add default blob */ + return fu_firmware_get_image_default_bytes (self, error); +} + +/** + * fu_firmware_add_image: + * @self: a #FuPlugin + * @img: A #FuFirmwareImage + * + * Adds an image to the firmware. + * + * If an image with the same ID is already present it is replaced. + * + * Since: 1.2.11 + **/ +void +fu_firmware_add_image (FuFirmware *self, FuFirmwareImage *img) +{ + FuFirmwarePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_FIRMWARE (self)); + g_return_if_fail (FU_IS_FIRMWARE_IMAGE (img)); + g_ptr_array_add (priv->images, g_object_ref (img)); +} + +/** + * fu_firmware_get_images: + * @self: a #FuPlugin + * + * Returns all the images in the firmware. + * + * Returns: (transfer container) (element-type FuFirmwareImage): images + * + * Since: 1.2.11 + **/ +GPtrArray * +fu_firmware_get_images (FuFirmware *self) +{ + FuFirmwarePrivate *priv = GET_PRIVATE (self); + g_autoptr(GPtrArray) imgs = NULL; + + g_return_val_if_fail (FU_IS_FIRMWARE (self), FALSE); + + imgs = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + for (guint i = 0; i < priv->images->len; i++) { + FuFirmwareImage *img = g_ptr_array_index (priv->images, i); + g_ptr_array_add (imgs, g_object_ref (img)); + } + return g_steal_pointer (&imgs); +} + +/** + * fu_firmware_get_image_by_id: + * @self: a #FuPlugin + * @id: (nullable): image ID, e.g. "config" + * @error: A #GError, or %NULL + * + * Gets the firmware image using the image ID. + * + * Returns: (transfer full): a #FuFirmwareImage, or %NULL if the image is not found + * + * Since: 1.2.11 + **/ +FuFirmwareImage * +fu_firmware_get_image_by_id (FuFirmware *self, const gchar *id, GError **error) +{ + FuFirmwarePrivate *priv = GET_PRIVATE (self); + + g_return_val_if_fail (FU_IS_FIRMWARE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + for (guint i = 0; i < priv->images->len; i++) { + FuFirmwareImage *img = g_ptr_array_index (priv->images, i); + if (g_strcmp0 (fu_firmware_image_get_id (img), id) == 0) + return g_object_ref (img); + } + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no image id %s found in firmware", id); + return NULL; +} + +/** + * fu_firmware_get_image_by_id_bytes: + * @self: a #FuPlugin + * @id: (nullable): image ID, e.g. "config" + * @error: A #GError, or %NULL + * + * Gets the firmware image bytes using the image ID. + * + * Returns: (transfer full): a #GBytes of a #FuFirmwareImage, or %NULL if the image is not found + * + * Since: 1.2.11 + **/ +GBytes * +fu_firmware_get_image_by_id_bytes (FuFirmware *self, const gchar *id, GError **error) +{ + g_autoptr(FuFirmwareImage) img = fu_firmware_get_image_by_id (self, id, error); + if (img == NULL) + return NULL; + return fu_firmware_image_get_bytes (img, error); +} + +/** + * fu_firmware_get_image_by_idx: + * @self: a #FuPlugin + * @idx: image index + * @error: A #GError, or %NULL + * + * Gets the firmware image using the image index. + * + * Returns: (transfer full): a #FuFirmwareImage, or %NULL if the image is not found + * + * Since: 1.2.11 + **/ +FuFirmwareImage * +fu_firmware_get_image_by_idx (FuFirmware *self, guint64 idx, GError **error) +{ + FuFirmwarePrivate *priv = GET_PRIVATE (self); + + g_return_val_if_fail (FU_IS_FIRMWARE (self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + for (guint i = 0; i < priv->images->len; i++) { + FuFirmwareImage *img = g_ptr_array_index (priv->images, i); + if (fu_firmware_image_get_idx (img) == idx) + return g_object_ref (img); + } + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no image idx %" G_GUINT64_FORMAT " found in firmware", idx); + return NULL; +} + +/** + * fu_firmware_get_image_by_idx_bytes: + * @self: a #FuPlugin + * @idx: image index + * @error: A #GError, or %NULL + * + * Gets the firmware image bytes using the image index. + * + * Returns: (transfer full): a #GBytes of a #FuFirmwareImage, or %NULL if the image is not found + * + * Since: 1.2.11 + **/ +GBytes * +fu_firmware_get_image_by_idx_bytes (FuFirmware *self, guint64 idx, GError **error) +{ + g_autoptr(FuFirmwareImage) img = fu_firmware_get_image_by_idx (self, idx, error); + if (img == NULL) + return NULL; + return fu_firmware_image_get_bytes (img, error); +} + +/** + * fu_firmware_get_image_default: + * @self: a #FuPlugin + * @error: A #GError, or %NULL + * + * Gets the default firmware image. + * + * NOTE: If the firmware has multiple images included then fu_firmware_get_image_by_id() + * or fu_firmware_get_image_by_idx() must be used rather than this function. + * + * Returns: (transfer full): a #FuFirmwareImage, or %NULL if the image is not found + * + * Since: 1.2.11 + **/ +FuFirmwareImage * +fu_firmware_get_image_default (FuFirmware *self, GError **error) +{ + FuFirmwarePrivate *priv = GET_PRIVATE (self); + if (priv->images->len == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no images in firmware"); + return NULL; + } + if (priv->images->len > 1) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "multiple images present in firmware"); + return NULL; + } + return g_object_ref (FU_FIRMWARE_IMAGE (g_ptr_array_index (priv->images, 0))); +} + +/** + * fu_firmware_get_image_default_bytes: + * @self: a #FuPlugin + * @error: A #GError, or %NULL + * + * Gets the default firmware image. + * + * Returns: (transfer full): a #GBytes of the image, or %NULL if the image is not found + * + * Since: 1.2.11 + **/ +GBytes * +fu_firmware_get_image_default_bytes (FuFirmware *self, GError **error) +{ + g_autoptr(FuFirmwareImage) img = fu_firmware_get_image_default (self, error); + if (img == NULL) + return NULL; + return fu_firmware_image_get_bytes (img, error); +} + +/** + * fu_firmware_to_string: + * @self: A #FuFirmware + * + * This allows us to easily print the object. + * + * Returns: a string value, or %NULL for invalid. + * + * Since: 1.2.11 + **/ +gchar * +fu_firmware_to_string (FuFirmware *self) +{ + FuFirmwarePrivate *priv = GET_PRIVATE (self); + GString *str = g_string_new ("FuFirmware:\n"); + + for (guint i = 0; i < priv->images->len; i++) { + FuFirmwareImage *img = g_ptr_array_index (priv->images, i); + g_autofree gchar *tmp = fu_firmware_image_to_string (img); + g_string_append (str, tmp); + } + + return g_string_free (str, FALSE); +} + +static void +fu_firmware_init (FuFirmware *self) +{ + FuFirmwarePrivate *priv = GET_PRIVATE (self); + priv->images = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); +} + +static void +fu_firmware_finalize (GObject *object) +{ + FuFirmware *self = FU_FIRMWARE (object); + FuFirmwarePrivate *priv = GET_PRIVATE (self); + g_ptr_array_unref (priv->images); + G_OBJECT_CLASS (fu_firmware_parent_class)->finalize (object); +} + +static void +fu_firmware_class_init (FuFirmwareClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_firmware_finalize; +} + +/** + * fu_firmware_new: + * + * Creates an empty firmware object. + * + * Returns: a #FuFirmware + * + * Since: 1.2.11 + **/ +FuFirmware * +fu_firmware_new (void) +{ + FuFirmware *self = g_object_new (FU_TYPE_FIRMWARE, NULL); + return FU_FIRMWARE (self); +} + +/** + * fu_firmware_new_from_bytes: + * @self: A #GBytes image + * + * Creates a firmware object with the provided image set as default. + * + * Returns: a #FuFirmware + * + * Since: 1.2.11 + **/ +FuFirmware * +fu_firmware_new_from_bytes (GBytes *fw) +{ + FuFirmware *self = fu_firmware_new (); + g_autoptr(FuFirmwareImage) img = NULL; + img = fu_firmware_image_new (fw); + fu_firmware_add_image (self, img); + return self; +} diff --git a/src/fu-firmware.h b/src/fu-firmware.h new file mode 100644 index 000000000..a3eb18973 --- /dev/null +++ b/src/fu-firmware.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include +#include + +#include "fu-firmware-image.h" + +G_BEGIN_DECLS + +#define FU_TYPE_FIRMWARE (fu_firmware_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FuFirmware, fu_firmware, FU, FIRMWARE, GObject) + +struct _FuFirmwareClass +{ + GObjectClass parent_class; + gboolean (*parse) (FuFirmware *self, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error); + GBytes *(*write) (FuFirmware *self, + GError **error); + /*< private >*/ + gpointer padding[30]; +}; + +FuFirmware *fu_firmware_new (void); +FuFirmware *fu_firmware_new_from_bytes (GBytes *fw); +gchar *fu_firmware_to_string (FuFirmware *self); + +gboolean fu_firmware_parse (FuFirmware *self, + GBytes *fw, + FwupdInstallFlags flags, + GError **error); +gboolean fu_firmware_parse_full (FuFirmware *self, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error); +GBytes *fu_firmware_write (FuFirmware *self, + GError **error); + +void fu_firmware_add_image (FuFirmware *self, + FuFirmwareImage *image); +GPtrArray *fu_firmware_get_images (FuFirmware *self); +FuFirmwareImage *fu_firmware_get_image_by_id (FuFirmware *self, + const gchar *id, + GError **error); +GBytes *fu_firmware_get_image_by_id_bytes (FuFirmware *self, + const gchar *id, + GError **error); +FuFirmwareImage *fu_firmware_get_image_by_idx (FuFirmware *self, + guint64 idx, + GError **error); +GBytes *fu_firmware_get_image_by_idx_bytes (FuFirmware *self, + guint64 idx, + GError **error); +FuFirmwareImage *fu_firmware_get_image_default (FuFirmware *self, + GError **error); +GBytes *fu_firmware_get_image_default_bytes (FuFirmware *self, + GError **error); + +G_END_DECLS diff --git a/src/fu-ihex-firmware.c b/src/fu-ihex-firmware.c new file mode 100644 index 000000000..e3c600060 --- /dev/null +++ b/src/fu-ihex-firmware.c @@ -0,0 +1,377 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuFirmware" + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-firmware-common.h" +#include "fu-ihex-firmware.h" + +struct _FuIhexFirmware { + FuFirmware parent_instance; +}; + +G_DEFINE_TYPE (FuIhexFirmware, fu_ihex_firmware, FU_TYPE_FIRMWARE) + +#define DFU_INHX32_RECORD_TYPE_DATA 0x00 +#define DFU_INHX32_RECORD_TYPE_EOF 0x01 +#define DFU_INHX32_RECORD_TYPE_EXTENDED_SEGMENT 0x02 +#define DFU_INHX32_RECORD_TYPE_START_SEGMENT 0x03 +#define DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR 0x04 +#define DFU_INHX32_RECORD_TYPE_START_LINEAR 0x05 +#define DFU_INHX32_RECORD_TYPE_SIGNATURE 0xfd + +static const gchar * +fu_ihex_firmware_record_type_to_string (guint8 record_type) +{ + if (record_type == DFU_INHX32_RECORD_TYPE_DATA) + return "DATA"; + if (record_type == DFU_INHX32_RECORD_TYPE_EOF) + return "EOF"; + if (record_type == DFU_INHX32_RECORD_TYPE_EXTENDED_SEGMENT) + return "EXTENDED_SEGMENT"; + if (record_type == DFU_INHX32_RECORD_TYPE_START_SEGMENT) + return "START_SEGMENT"; + if (record_type == DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR) + return "EXTENDED_LINEAR"; + if (record_type == DFU_INHX32_RECORD_TYPE_START_LINEAR) + return "ADDR32"; + if (record_type == DFU_INHX32_RECORD_TYPE_SIGNATURE) + return "SIGNATURE"; + return NULL; +} + +static gboolean +fu_ihex_firmware_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + const gchar *data; + gboolean got_eof = FALSE; + gsize sz = 0; + guint32 abs_addr = 0x0; + guint32 addr_last = 0x0; + guint32 img_addr = G_MAXUINT32; + guint32 seg_addr = 0x0; + g_auto(GStrv) lines = NULL; + g_autoptr(FuFirmwareImage) img = fu_firmware_image_new (NULL); + g_autoptr(GBytes) img_bytes = NULL; + g_autoptr(GString) buf = g_string_new (NULL); + g_autoptr(GByteArray) buf_signature = g_byte_array_new (); + + g_return_val_if_fail (fw != NULL, FALSE); + + /* parse records */ + data = g_bytes_get_data (fw, &sz); + lines = fu_common_strnsplit (data, sz, "\n", -1); + for (guint ln = 0; lines[ln] != NULL; ln++) { + const gchar *line = lines[ln]; + gsize linesz; + guint32 addr; + guint8 byte_cnt; + guint8 record_type; + guint line_end; + + /* ignore comments */ + if (g_str_has_prefix (line, ";")) + continue; + + /* ignore blank lines */ + g_strdelimit (lines[ln], "\r\x1a", '\0'); + linesz = strlen (line); + if (linesz == 0) + continue; + + /* check starting token */ + if (line[0] != ':') { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid starting token on line %u: %s", + ln + 1, line); + return FALSE; + } + + /* check there's enough data for the smallest possible record */ + if (linesz < 11) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "line %u is incomplete, length %u", + ln + 1, (guint) linesz); + return FALSE; + } + + /* length, 16-bit address, type */ + byte_cnt = fu_firmware_strparse_uint8 (line + 1); + addr = fu_firmware_strparse_uint16 (line + 3); + record_type = fu_firmware_strparse_uint8 (line + 7); + g_debug ("%s:", fu_ihex_firmware_record_type_to_string (record_type)); + g_debug (" addr_start:\t0x%04x", addr); + g_debug (" length:\t0x%02x", byte_cnt); + addr += seg_addr; + addr += abs_addr; + g_debug (" addr:\t0x%08x", addr); + + /* position of checksum */ + line_end = 9 + byte_cnt * 2; + if (line_end > (guint) linesz) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "line %u malformed, length: %u", + ln + 1, line_end); + return FALSE; + } + + /* verify checksum */ + if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + guint8 checksum = 0; + for (guint i = 1; i < line_end + 2; i += 2) { + guint8 data_tmp = fu_firmware_strparse_uint8 (line + i); + checksum += data_tmp; + } + if (checksum != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "line %u has invalid checksum (0x%02x)", + ln + 1, checksum); + return FALSE; + } + } + + /* process different record types */ + switch (record_type) { + case DFU_INHX32_RECORD_TYPE_DATA: + /* base address for element */ + if (img_addr == G_MAXUINT32) + img_addr = addr; + + /* does not make sense */ + if (addr < addr_last) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid address 0x%x, last was 0x%x", + (guint) addr, + (guint) addr_last); + return FALSE; + } + + /* parse bytes from line */ + g_debug ("writing data 0x%08x", (guint32) addr); + for (guint i = 9; i < line_end; i += 2) { + /* any holes in the hex record */ + guint32 len_hole = addr - addr_last; + guint8 data_tmp; + if (addr_last > 0 && len_hole > 0x100000) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "hole of 0x%x bytes too large to fill", + (guint) len_hole); + return FALSE; + } + if (addr_last > 0x0 && len_hole > 1) { + g_debug ("filling address 0x%08x to 0x%08x", + addr_last + 1, addr_last + len_hole - 1); + for (guint j = 1; j < len_hole; j++) { + /* although 0xff might be clearer, + * we can't write 0xffff to pic14 */ + g_string_append_c (buf, 0x00); + } + } + /* write into buf */ + data_tmp = fu_firmware_strparse_uint8 (line + i); + g_string_append_c (buf, (gchar) data_tmp); + addr_last = addr++; + } + break; + case DFU_INHX32_RECORD_TYPE_EOF: + if (got_eof) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "duplicate EOF, perhaps " + "corrupt file"); + return FALSE; + } + got_eof = TRUE; + break; + case DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR: + abs_addr = fu_firmware_strparse_uint16 (line + 9) << 16; + g_debug (" abs_addr:\t0x%02x", abs_addr); + break; + case DFU_INHX32_RECORD_TYPE_START_LINEAR: + abs_addr = fu_firmware_strparse_uint32 (line + 9); + g_debug (" abs_addr:\t0x%08x", abs_addr); + break; + case DFU_INHX32_RECORD_TYPE_EXTENDED_SEGMENT: + /* segment base address, so ~1Mb addressable */ + seg_addr = fu_firmware_strparse_uint16 (line + 9) * 16; + g_debug (" seg_addr:\t0x%08x", seg_addr); + break; + case DFU_INHX32_RECORD_TYPE_START_SEGMENT: + /* initial content of the CS:IP registers */ + seg_addr = fu_firmware_strparse_uint32 (line + 9); + g_debug (" seg_addr:\t0x%02x", seg_addr); + break; + case DFU_INHX32_RECORD_TYPE_SIGNATURE: + for (guint i = 9; i < line_end; i += 2) { + guint8 tmp_c = fu_firmware_strparse_uint8 (line + i); + g_byte_array_append (buf_signature, &tmp_c, 1); + } + break; + default: + /* vendors sneak in nonstandard sections past the EOF */ + if (got_eof) + break; + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid ihex record type %i", + record_type); + return FALSE; + } + } + + /* no EOF */ + if (!got_eof) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no EOF, perhaps truncated file"); + return FALSE; + } + + /* add single image */ + img_bytes = g_bytes_new (buf->str, buf->len); + fu_firmware_image_set_bytes (img, img_bytes); + if (img_addr != G_MAXUINT32) + fu_firmware_image_set_addr (img, img_addr); + fu_firmware_add_image (firmware, img); + + /* add optional signature */ + if (buf_signature->len > 0) { + g_autoptr(GBytes) data_sig = g_bytes_new (buf_signature->data, buf_signature->len); + g_autoptr(FuFirmwareImage) img_sig = fu_firmware_image_new (data_sig); + fu_firmware_image_set_id (img_sig, "signature"); + fu_firmware_add_image (firmware, img_sig); + } + return TRUE; +} + +static void +fu_ihex_firmware_emit_chunk (GString *str, + guint16 address, + guint8 record_type, + const guint8 *data, + gsize sz) +{ + guint8 checksum = 0x00; + g_string_append_printf (str, ":%02X%04X%02X", + (guint) sz, + (guint) address, + (guint) record_type); + for (gsize j = 0; j < sz; j++) + g_string_append_printf (str, "%02X", data[j]); + checksum = (guint8) sz; + checksum += (guint8) ((address & 0xff00) >> 8); + checksum += (guint8) (address & 0xff); + checksum += record_type; + for (gsize j = 0; j < sz; j++) + checksum += data[j]; + g_string_append_printf (str, "%02X\n", (guint) (((~checksum) + 0x01) & 0xff)); +} + +static gboolean +dfu_firmware_to_ihex_image (FuFirmwareImage *img, GString *str, GError **error) +{ + const guint8 *data; + const guint chunk_size = 16; + gsize len; + guint32 address_offset_last = 0x0; + guint8 record_type = DFU_INHX32_RECORD_TYPE_DATA; + g_autoptr(GBytes) bytes = NULL; + + /* get data */ + bytes = fu_firmware_image_get_bytes (img, error); + if (bytes == NULL) + return FALSE; + + /* special case */ + if (g_strcmp0 (fu_firmware_image_get_id (img), "signature") == 0) + record_type = DFU_INHX32_RECORD_TYPE_SIGNATURE; + + /* get number of chunks */ + data = g_bytes_get_data (bytes, &len); + for (gsize i = 0; i < len; i += chunk_size) { + guint32 address_tmp = fu_firmware_image_get_addr (img) + i; + guint32 address_offset = (address_tmp >> 16) & 0xffff; + gsize chunk_len = MIN (len - i, 16); + + /* need to offset */ + if (address_offset != address_offset_last) { + guint8 buf[2]; + fu_common_write_uint16 (buf, address_offset, G_BIG_ENDIAN); + fu_ihex_firmware_emit_chunk (str, 0x0, + DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR, + buf, 2); + address_offset_last = address_offset; + } + address_tmp &= 0xffff; + fu_ihex_firmware_emit_chunk (str, address_tmp, + record_type, data + i, chunk_len); + } + return TRUE; +} + +static GBytes * +fu_ihex_firmware_write (FuFirmware *firmware, GError **error) +{ + g_autoptr(GPtrArray) imgs = NULL; + g_autoptr(GString) str = NULL; + + /* write all the element data */ + str = g_string_new (""); + imgs = fu_firmware_get_images (firmware); + for (guint i = 0; i < imgs->len; i++) { + FuFirmwareImage *img = g_ptr_array_index (imgs, i); + if (!dfu_firmware_to_ihex_image (img, str, error)) + return NULL; + } + + /* add EOF */ + fu_ihex_firmware_emit_chunk (str, 0x0, DFU_INHX32_RECORD_TYPE_EOF, NULL, 0); + return g_bytes_new (str->str, str->len); +} + +static void +fu_ihex_firmware_init (FuIhexFirmware *self) +{ +} + +static void +fu_ihex_firmware_class_init (FuIhexFirmwareClass *klass) +{ + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + klass_firmware->parse = fu_ihex_firmware_parse; + klass_firmware->write = fu_ihex_firmware_write; +} + +FuFirmware * +fu_ihex_firmware_new (void) +{ + return FU_FIRMWARE (g_object_new (FU_TYPE_IHEX_FIRMWARE, NULL)); +} diff --git a/src/fu-ihex-firmware.h b/src/fu-ihex-firmware.h new file mode 100644 index 000000000..ad90137ac --- /dev/null +++ b/src/fu-ihex-firmware.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware.h" + +G_BEGIN_DECLS + +#define FU_TYPE_IHEX_FIRMWARE (fu_ihex_firmware_get_type ()) +G_DECLARE_FINAL_TYPE (FuIhexFirmware, fu_ihex_firmware, FU, IHEX_FIRMWARE, FuFirmware) + +FuFirmware *fu_ihex_firmware_new (void); + +G_END_DECLS diff --git a/src/fu-self-test.c b/src/fu-self-test.c index 24b121107..7ff116025 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -23,6 +23,7 @@ #include "fu-device-list.h" #include "fu-device-private.h" #include "fu-engine.h" +#include "fu-ihex-firmware.h" #include "fu-quirks.h" #include "fu-keyring.h" #include "fu-history.h" @@ -33,6 +34,7 @@ #include "fu-hash.h" #include "fu-hwids.h" #include "fu-smbios.h" +#include "fu-srec-firmware.h" #include "fu-test.h" #ifdef ENABLE_GPG @@ -3665,6 +3667,248 @@ fu_common_vercmp_func (void) g_assert_cmpint (fu_common_vercmp (NULL, NULL), ==, G_MAXINT); } +static void +fu_firmware_ihex_func (void) +{ + const guint8 *data; + gboolean ret; + gsize len; + g_autofree gchar *filename_hex = NULL; + g_autofree gchar *filename_ref = NULL; + g_autofree gchar *str = NULL; + g_autoptr(FuFirmware) firmware = fu_ihex_firmware_new (); + g_autoptr(GBytes) data_file = NULL; + g_autoptr(GBytes) data_fw = NULL; + g_autoptr(GBytes) data_hex = NULL; + g_autoptr(GBytes) data_ref = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GFile) file_ref = NULL; + g_autoptr(GFile) file_hex = NULL; + + /* load a Intel hex32 file */ + filename_hex = fu_test_get_filename (TESTDATADIR, "firmware.hex"); + g_assert (filename_hex != NULL); + file_hex = g_file_new_for_path (filename_hex); + data_file = g_file_load_bytes (file_hex, NULL, NULL, &error); + g_assert_no_error (error); + g_assert (data_file != NULL); + ret = fu_firmware_parse (firmware, data_file, FWUPD_INSTALL_FLAG_NONE, &error); + g_assert_no_error (error); + g_assert (ret); + data_fw = fu_firmware_get_image_default_bytes (firmware, &error); + g_assert_no_error (error); + g_assert_nonnull (data_fw); + g_assert_cmpint (g_bytes_get_size (data_fw), ==, 136); + + /* did we match the reference file? */ + filename_ref = fu_test_get_filename (TESTDATADIR, "firmware.bin"); + g_assert (filename_ref != NULL); + file_ref = g_file_new_for_path (filename_ref); + data_ref = g_file_load_bytes (file_ref, NULL, NULL, &error); + g_assert_no_error (error); + g_assert (data_ref != NULL); + ret = fu_common_bytes_compare (data_fw, data_ref, &error); + g_assert_no_error (error); + g_assert_true (ret); + + /* export a ihex file (which will be slightly different due to + * non-continous regions being expanded */ + data_hex = fu_firmware_write (firmware, &error); + g_assert_no_error (error); + g_assert (data_hex != NULL); + data = g_bytes_get_data (data_hex, &len); + str = g_strndup ((const gchar *) data, len); + g_assert_cmpstr (str, ==, + ":104000003DEF20F000000000FACF01F0FBCF02F0FE\n" + ":10401000E9CF03F0EACF04F0E1CF05F0E2CF06F0FC\n" + ":10402000D9CF07F0DACF08F0F3CF09F0F4CF0AF0D8\n" + ":10403000F6CF0BF0F7CF0CF0F8CF0DF0F5CF0EF078\n" + ":104040000EC0F5FF0DC0F8FF0CC0F7FF0BC0F6FF68\n" + ":104050000AC0F4FF09C0F3FF08C0DAFF07C0D9FFA8\n" + ":1040600006C0E2FF05C0E1FF04C0EAFF03C0E9FFAC\n" + ":1040700002C0FBFF01C0FAFF11003FEF20F000017A\n" + ":0840800042EF20F03DEF20F0BB\n" + ":00000001FF\n"); +} + +static void +fu_firmware_ihex_signed_func (void) +{ + const guint8 *data; + gboolean ret; + gsize len; + g_autofree gchar *filename_shex = NULL; + g_autoptr(FuFirmware) firmware = fu_ihex_firmware_new (); + g_autoptr(GBytes) data_file = NULL; + g_autoptr(GBytes) data_fw = NULL; + g_autoptr(GBytes) data_sig = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GFile) file_hex = NULL; + + /* load a signed Intel hex32 file */ + filename_shex = fu_test_get_filename (TESTDATADIR, "firmware.shex"); + g_assert (filename_shex != NULL); + file_hex = g_file_new_for_path (filename_shex); + data_file = g_file_load_bytes (file_hex, NULL, NULL, &error); + g_assert_no_error (error); + g_assert (data_file != NULL); + ret = fu_firmware_parse (firmware, data_file, FWUPD_INSTALL_FLAG_NONE, &error); + g_assert_no_error (error); + g_assert (ret); + data_fw = fu_firmware_get_image_by_id_bytes (firmware, NULL, &error); + g_assert_no_error (error); + g_assert_nonnull (data_fw); + g_assert_cmpint (g_bytes_get_size (data_fw), ==, 136); + + /* get the signed image */ + data_sig = fu_firmware_get_image_by_id_bytes (firmware, "signature", &error); + g_assert_no_error (error); + g_assert_nonnull (data_sig); + data = g_bytes_get_data (data_sig, &len); + g_assert_cmpint (len, ==, 8); + g_assert (data != NULL); + g_assert_cmpint (memcmp (data, "deadbeef", 8), ==, 0); +} + +static void +fu_firmware_ihex_offset_func (void) +{ + const guint8 *data; + gboolean ret; + gsize len; + g_autofree gchar *str = NULL; + g_autoptr(FuFirmware) firmware = fu_ihex_firmware_new (); + g_autoptr(FuFirmware) firmware_verify = fu_ihex_firmware_new (); + g_autoptr(FuFirmwareImage) img_verify = NULL; + g_autoptr(FuFirmwareImage) img = NULL; + g_autoptr(GBytes) data_bin = NULL; + g_autoptr(GBytes) data_dummy = NULL; + g_autoptr(GBytes) data_verify = NULL; + g_autoptr(GError) error = NULL; + + /* add a 4 byte image in high memory */ + data_dummy = g_bytes_new_static ("foo", 4); + img = fu_firmware_image_new (data_dummy); + fu_firmware_image_set_addr (img, 0x80000000); + fu_firmware_add_image (firmware, img); + data_bin = fu_firmware_write (firmware, &error); + g_assert_no_error (error); + g_assert (data_bin != NULL); + data = g_bytes_get_data (data_bin, &len); + str = g_strndup ((const gchar *) data, len); + g_assert_cmpstr (str, ==, + ":0200000480007A\n" + ":04000000666F6F00B8\n" + ":00000001FF\n"); + + /* check we can load it too */ + ret = fu_firmware_parse (firmware_verify, data_bin, FWUPD_INSTALL_FLAG_NONE, &error); + g_assert_no_error (error); + g_assert (ret); + img_verify = fu_firmware_get_image_default (firmware_verify, &error); + g_assert_no_error (error); + g_assert (img_verify != NULL); + g_assert_cmpint (fu_firmware_image_get_addr (img_verify), ==, 0x80000000); + data_verify = fu_firmware_image_get_bytes (img_verify, &error); + g_assert_no_error (error); + g_assert (data_verify != NULL); + g_assert_cmpint (g_bytes_get_size (data_verify), ==, 0x4); +} + +static void +fu_firmware_srec_func (void) +{ + gboolean ret; + g_autofree gchar *filename_srec = NULL; + g_autofree gchar *filename_ref = NULL; + g_autoptr(FuFirmware) firmware = fu_srec_firmware_new (); + g_autoptr(GBytes) data_ref = NULL; + g_autoptr(GBytes) data_srec = NULL; + g_autoptr(GBytes) data_bin = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GFile) file_bin = NULL; + g_autoptr(GFile) file_srec = NULL; + + filename_srec = fu_test_get_filename (TESTDATADIR, "firmware.srec"); + g_assert (filename_srec != NULL); + file_srec = g_file_new_for_path (filename_srec); + data_srec = g_file_load_bytes (file_srec, NULL, NULL, &error); + g_assert_no_error (error); + g_assert (data_srec != NULL); + ret = fu_firmware_parse (firmware, data_srec, FWUPD_INSTALL_FLAG_NONE, &error); + g_assert_no_error (error); + g_assert (ret); + data_bin = fu_firmware_get_image_default_bytes (firmware, &error); + g_assert_no_error (error); + g_assert_nonnull (data_bin); + g_assert_cmpint (g_bytes_get_size (data_bin), ==, 136); + + /* did we match the reference file? */ + filename_ref = fu_test_get_filename (TESTDATADIR, "firmware.bin"); + g_assert (filename_ref != NULL); + file_bin = g_file_new_for_path (filename_ref); + data_ref = g_file_load_bytes (file_bin, NULL, NULL, &error); + g_assert_no_error (error); + g_assert (data_ref != NULL); + ret = fu_common_bytes_compare (data_bin, data_ref, &error); + g_assert_no_error (error); + g_assert_true (ret); +} + +static void +fu_firmware_func (void) +{ + g_autoptr(FuFirmware) firmware = fu_firmware_new (); + g_autoptr(FuFirmwareImage) img1 = fu_firmware_image_new (NULL); + g_autoptr(FuFirmwareImage) img2 = fu_firmware_image_new (NULL); + g_autoptr(FuFirmwareImage) img_id = NULL; + g_autoptr(FuFirmwareImage) img_idx = NULL; + g_autoptr(GError) error = NULL; + g_autofree gchar *str = NULL; + + fu_firmware_image_set_addr (img1, 0x200); + fu_firmware_image_set_idx (img1, 13); + fu_firmware_image_set_id (img1, "primary"); + fu_firmware_add_image (firmware, img1); + fu_firmware_image_set_addr (img2, 0x400); + fu_firmware_image_set_idx (img2, 23); + fu_firmware_image_set_id (img2, "secondary"); + fu_firmware_add_image (firmware, img2); + + img_id = fu_firmware_get_image_by_id (firmware, "NotGoingToExist", &error); + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND); + g_assert_null (img_id); + g_clear_error (&error); + img_id = fu_firmware_get_image_by_id (firmware, "primary", &error); + g_assert_no_error (error); + g_assert_nonnull (img_id); + g_assert_cmpint (fu_firmware_image_get_addr (img_id), ==, 0x200); + g_assert_cmpint (fu_firmware_image_get_idx (img_id), ==, 13); + g_assert_cmpstr (fu_firmware_image_get_id (img_id), ==, "primary"); + + img_idx = fu_firmware_get_image_by_idx (firmware, 123456, &error); + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND); + g_assert_null (img_idx); + g_clear_error (&error); + img_idx = fu_firmware_get_image_by_idx (firmware, 23, &error); + g_assert_no_error (error); + g_assert_nonnull (img_idx); + g_assert_cmpint (fu_firmware_image_get_addr (img_idx), ==, 0x400); + g_assert_cmpint (fu_firmware_image_get_idx (img_idx), ==, 23); + g_assert_cmpstr (fu_firmware_image_get_id (img_idx), ==, "secondary"); + + str = fu_firmware_to_string (firmware); + g_assert_cmpstr (str, ==, "FuFirmware:\n" + " FuFirmwareImage:\n" + " ID: primary\n" + " Index: 0x000d\n" + " Address: 0x0200\n" + " FuFirmwareImage:\n" + " ID: secondary\n" + " Index: 0x0017\n" + " Address: 0x0400\n"); +} + int main (int argc, char **argv) { @@ -3685,6 +3929,11 @@ main (int argc, char **argv) /* tests go here */ if (g_test_slow ()) g_test_add_func ("/fwupd/progressbar", fu_progressbar_func); + g_test_add_func ("/fwupd/firmware", fu_firmware_func); + g_test_add_func ("/fwupd/firmware{ihex}", fu_firmware_ihex_func); + g_test_add_func ("/fwupd/firmware{ihex-offset}", fu_firmware_ihex_offset_func); + g_test_add_func ("/fwupd/firmware{ihex-signed}", fu_firmware_ihex_signed_func); + g_test_add_func ("/fwupd/firmware{srec}", fu_firmware_srec_func); g_test_add_func ("/fwupd/archive{invalid}", fu_archive_invalid_func); g_test_add_func ("/fwupd/archive{cab}", fu_archive_cab_func); g_test_add_func ("/fwupd/engine{requirements-other-device}", fu_engine_requirements_other_device_func); diff --git a/src/fu-srec-firmware.c b/src/fu-srec-firmware.c new file mode 100644 index 000000000..3d5b4754d --- /dev/null +++ b/src/fu-srec-firmware.c @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuFirmware" + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-firmware-common.h" +#include "fu-srec-firmware.h" + +struct _FuSrecFirmware { + FuFirmware parent_instance; +}; + +G_DEFINE_TYPE (FuSrecFirmware, fu_srec_firmware, FU_TYPE_FIRMWARE) + +static gboolean +fu_srec_firmware_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + const gchar *data; + gboolean got_eof = FALSE; + gboolean got_hdr = FALSE; + gsize sz = 0; + guint16 data_cnt = 0; + guint32 addr32_last = 0; + guint32 img_address = 0; + g_auto(GStrv) lines = NULL; + g_autoptr(FuFirmwareImage) img = fu_firmware_image_new (NULL); + g_autoptr(GBytes) img_bytes = NULL; + g_autoptr(GString) outbuf = g_string_new (NULL); + + /* parse records */ + data = g_bytes_get_data (fw, &sz); + lines = fu_common_strnsplit (data, sz, "\n", -1); + for (guint ln = 0; lines[ln] != NULL; ln++) { + const gchar *line = lines[ln]; + gsize linesz; + guint32 rec_addr32; + guint8 addrsz = 0; /* bytes */ + guint8 rec_count; /* words */ + guint8 rec_kind; + + /* ignore blank lines */ + g_strdelimit (lines[ln], "\r", '\0'); + linesz = strlen (line); + if (linesz == 0) + continue; + + /* check starting token */ + if (line[0] != 'S') { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid starting token, got '%c' at line %u", + line[0], ln); + return FALSE; + } + + /* check there's enough data for the smallest possible record */ + if (linesz < 10) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "record incomplete at line %u, length %u", + ln, (guint) linesz); + return FALSE; + } + + /* kind, count, address, (data), checksum, linefeed */ + rec_kind = line[1] - '0'; + rec_count = fu_firmware_strparse_uint8 (line + 2); + if (rec_count * 2 != linesz - 4) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "count incomplete at line %u, " + "length %u, expected %u", + ln, (guint) linesz - 4, (guint) rec_count * 2); + return FALSE; + } + + /* checksum check */ + if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + guint8 rec_csum = 0; + guint8 rec_csum_expected; + for (guint8 i = 0; i < rec_count; i++) + rec_csum += fu_firmware_strparse_uint8 (line + (i * 2) + 2); + rec_csum ^= 0xff; + rec_csum_expected = fu_firmware_strparse_uint8 (line + (rec_count * 2) + 2); + if (rec_csum != rec_csum_expected) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "checksum incorrect line %u, " + "expected %02x, got %02x", + ln, rec_csum_expected, rec_csum); + return FALSE; + } + } + + /* set each command settings */ + switch (rec_kind) { + case 0: + addrsz = 2; + if (got_hdr) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "duplicate header record"); + return FALSE; + } + got_hdr = TRUE; + break; + case 1: + addrsz = 2; + break; + case 2: + addrsz = 3; + break; + case 3: + addrsz = 4; + break; + case 5: + addrsz = 2; + got_eof = TRUE; + break; + case 6: + addrsz = 3; + break; + case 7: + addrsz = 4; + got_eof = TRUE; + break; + case 8: + addrsz = 3; + got_eof = TRUE; + break; + case 9: + addrsz = 2; + got_eof = TRUE; + break; + default: + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid srec record type S%c", + line[1]); + return FALSE; + } + + /* parse address */ + switch (addrsz) { + case 2: + rec_addr32 = fu_firmware_strparse_uint16 (line + 4); + break; + case 3: + rec_addr32 = fu_firmware_strparse_uint24 (line + 4); + break; + case 4: + rec_addr32 = fu_firmware_strparse_uint32 (line + 4); + break; + default: + g_assert_not_reached (); + } + + /* header */ + if (rec_kind == 0) { + g_autoptr(GString) modname = g_string_new (NULL); + if (rec_addr32 != 0x0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid header record address, got %04x", + rec_addr32); + return FALSE; + } + + /* could be anything, lets assume text */ + for (guint8 i = 4 + (addrsz * 2); i <= rec_count * 2; i += 2) { + guint8 tmp = fu_firmware_strparse_uint8 (line + i); + if (!g_ascii_isgraph (tmp)) + break; + g_string_append_c (modname, tmp); + } + if (modname->len != 0) + fu_firmware_image_set_id (img, modname->str); + continue; + } + + /* verify we got all records */ + if (rec_kind == 5) { + if (rec_addr32 != data_cnt) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "count record was not valid, got 0x%02x expected 0x%02x", + (guint) rec_addr32, (guint) data_cnt); + return FALSE; + } + } + + /* data */ + if (rec_kind == 1 || rec_kind == 2 || rec_kind == 3) { + /* invalid */ + if (!got_hdr) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "missing header record"); + return FALSE; + } + /* does not make sense */ + if (rec_addr32 < addr32_last) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid address 0x%x, last was 0x%x", + (guint) rec_addr32, + (guint) addr32_last); + return FALSE; + } + if (rec_addr32 < addr_start) { + g_debug ("ignoring data at 0x%x as before start address 0x%x", + (guint) rec_addr32, (guint) addr_start); + } else { + guint bytecnt = 0; + guint32 len_hole = rec_addr32 - addr32_last; + + /* fill any holes, but only up to 1Mb to avoid a DoS */ + if (addr32_last > 0 && len_hole > 0x100000) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "hole of 0x%x bytes too large to fill", + (guint) len_hole); + return FALSE; + } + if (addr32_last > 0x0 && len_hole > 1) { + g_debug ("filling address 0x%08x to 0x%08x", + addr32_last + 1, addr32_last + len_hole - 1); + for (guint j = 0; j < len_hole; j++) + g_string_append_c (outbuf, 0xff); + } + + /* add data */ + for (guint8 i = 4 + (addrsz * 2); i <= rec_count * 2; i += 2) { + guint8 tmp = fu_firmware_strparse_uint8 (line + i); + g_string_append_c (outbuf, tmp); + bytecnt++; + } + if (img_address == 0x0) + img_address = rec_addr32; + addr32_last = rec_addr32 + bytecnt; + } + data_cnt++; + } + } + + /* no EOF */ + if (!got_eof) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no EOF, perhaps truncated file"); + return FALSE; + } + + /* add single image */ + img_bytes = g_bytes_new (outbuf->str, outbuf->len); + fu_firmware_image_set_bytes (img, img_bytes); + fu_firmware_image_set_addr (img, img_address); + fu_firmware_add_image (firmware, img); + return TRUE; +} + +static void +fu_srec_firmware_init (FuSrecFirmware *self) +{ +} + +static void +fu_srec_firmware_class_init (FuSrecFirmwareClass *klass) +{ + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + klass_firmware->parse = fu_srec_firmware_parse; +} + +FuFirmware * +fu_srec_firmware_new (void) +{ + return FU_FIRMWARE (g_object_new (FU_TYPE_SREC_FIRMWARE, NULL)); +} diff --git a/src/fu-srec-firmware.h b/src/fu-srec-firmware.h new file mode 100644 index 000000000..291548593 --- /dev/null +++ b/src/fu-srec-firmware.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware.h" + +G_BEGIN_DECLS + +#define FU_TYPE_SREC_FIRMWARE (fu_srec_firmware_get_type ()) +G_DECLARE_FINAL_TYPE (FuSrecFirmware, fu_srec_firmware, FU, SREC_FIRMWARE, FuFirmware) + +FuFirmware *fu_srec_firmware_new (void); + +G_END_DECLS diff --git a/src/meson.build b/src/meson.build index 922831794..35381c468 100644 --- a/src/meson.build +++ b/src/meson.build @@ -38,13 +38,18 @@ libfwupdprivate = static_library( 'fu-chunk.c', 'fu-device.c', 'fu-device-locker.c', + 'fu-firmware.c', + 'fu-firmware-common.c', + 'fu-firmware-image.c', 'fu-hwids.c', 'fu-history.c', + 'fu-ihex-firmware.c', 'fu-io-channel.c', 'fu-plugin.c', 'fu-progressbar.c', 'fu-quirks.c', 'fu-smbios.c', + 'fu-srec-firmware.c', 'fu-test.c', 'fu-udev-device.c', 'fu-usb-device.c', @@ -203,6 +208,7 @@ fwupdtool = executable( 'fu-device-locker.c', 'fu-idle.c', 'fu-install-task.c', + 'fu-ihex-firmware.c', 'fu-io-channel.c', 'fu-keyring.c', 'fu-keyring-utils.c', @@ -211,6 +217,7 @@ fwupdtool = executable( 'fu-plugin-list.c', 'fu-quirks.c', 'fu-smbios.c', + 'fu-srec-firmware.c', 'fu-udev-device.c', 'fu-usb-device.c', 'fu-util-common.c', @@ -286,7 +293,11 @@ executable( 'fu-device.c', 'fu-device-list.c', 'fu-device-locker.c', + 'fu-firmware.c', + 'fu-firmware-common.c', + 'fu-firmware-image.c', 'fu-idle.c', + 'fu-ihex-firmware.c', 'fu-io-channel.c', 'fu-install-task.c', 'fu-keyring.c', @@ -296,6 +307,7 @@ executable( 'fu-plugin-list.c', 'fu-quirks.c', 'fu-smbios.c', + 'fu-srec-firmware.c', 'fu-udev-device.c', 'fu-usb-device.c', ], @@ -353,6 +365,9 @@ if get_option('tests') 'fu-common-version.c', 'fu-config.c', 'fu-engine.c', + 'fu-firmware.c', + 'fu-firmware-common.c', + 'fu-firmware-image.c', 'fu-keyring.c', 'fu-keyring-utils.c', 'fu-hwids.c', @@ -361,6 +376,7 @@ if get_option('tests') 'fu-device-locker.c', 'fu-history.c', 'fu-idle.c', + 'fu-ihex-firmware.c', 'fu-install-task.c', 'fu-io-channel.c', 'fu-keyring.c', @@ -370,6 +386,7 @@ if get_option('tests') 'fu-progressbar.c', 'fu-quirks.c', 'fu-smbios.c', + 'fu-srec-firmware.c', 'fu-test.c', 'fu-udev-device.c', 'fu-usb-device.c', @@ -424,6 +441,12 @@ if get_option('introspection') 'fu-device.h', 'fu-device-locker.c', 'fu-device-locker.h', + 'fu-firmware.c', + 'fu-firmware.h', + 'fu-firmware-common.c', + 'fu-firmware-common.h', + 'fu-firmware-image.c', + 'fu-firmware-image.h', 'fu-io-channel.c', 'fu-plugin.c', 'fu-plugin.h',