mirror of
https://git.proxmox.com/git/fwupd
synced 2025-05-29 21:51:16 +00:00
Use FuFirmware as a container for firmware images
In many plugins we've wanted to use ->prepare_firmware() to parse the firmware ahead of ->detach() and ->write_firmware() but this has the limitation that it can only return a single blob of data. For many devices, multiple binary blobs are required from one parsed image, for instance providing signatures, config and data blobs that have to be pushed to the device in different way. This also means we parse the firmware *before* we ask the user to detach. Break the internal FuDevice API to support these firmware types as they become more popular. This also allows us to move the Intel HEX and SREC parsing out of the dfu plugin as they are used by a few plugins now, and resolving symbols between plugins isn't exactly awesome.
This commit is contained in:
parent
747f570310
commit
7afd7cba0d
11
data/tests/firmware.shex
Normal file
11
data/tests/firmware.shex
Normal file
@ -0,0 +1,11 @@
|
||||
:100000003DEF20F000000000FACF01F0FBCF02F03E
|
||||
:10001000E9CF03F0EACF04F0E1CF05F0E2CF06F03C
|
||||
:10002000D9CF07F0DACF08F0F3CF09F0F4CF0AF018
|
||||
:10003000F6CF0BF0F7CF0CF0F8CF0DF0F5CF0EF0B8
|
||||
:100040000EC0F5FF0DC0F8FF0CC0F7FF0BC0F6FFA8
|
||||
:100050000AC0F4FF09C0F3FF08C0DAFF07C0D9FFE8
|
||||
:1000600006C0E2FF05C0E1FF04C0EAFF03C0E9FFEC
|
||||
:1000700002C0FBFF01C0FAFF11003FEF20F00001BA
|
||||
:0800800042EF20F03DEF20F0FB
|
||||
:080000FD6465616462656566DB
|
||||
:00000001FF
|
@ -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;
|
||||
|
@ -1,45 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
|
||||
* Copyright (C) 2017-2019 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gelf.h>
|
||||
#include <libelf.h>
|
||||
|
||||
#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));
|
||||
}
|
||||
|
@ -1,22 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
|
||||
* Copyright (C) 2017-2019 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* 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
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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],
|
||||
|
@ -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);
|
||||
|
@ -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))
|
||||
|
@ -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],
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 ();
|
||||
}
|
||||
|
||||
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
deadbeef
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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")) {
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -7,11 +7,10 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <json-glib/json-glib.h>
|
||||
|
||||
#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;
|
||||
|
112
plugins/solokey/fu-solokey-firmware.c
Normal file
112
plugins/solokey/fu-solokey-firmware.c
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <json-glib/json-glib.h>
|
||||
|
||||
#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));
|
||||
}
|
18
plugins/solokey/fu-solokey-firmware.h
Normal file
18
plugins/solokey/fu-solokey-firmware.h
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* 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
|
@ -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 : [
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -7,7 +7,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib.h>
|
||||
#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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -14,9 +14,9 @@
|
||||
#include <glib/gstdio.h>
|
||||
|
||||
#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;
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
#include "fu-wacom-common.h"
|
||||
#include "fu-udev-device.h"
|
||||
#include "dfu-element.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
@ -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,
|
||||
],
|
||||
)
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Richard Hughes <richard@hughsie.com>
|
||||
* Copyright (C) 2018-2019 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
@ -8,47 +8,42 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#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));
|
||||
}
|
||||
|
@ -1,20 +1,18 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Richard Hughes <richard@hughsie.com>
|
||||
* Copyright (C) 2018-2019 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <glib-object.h>
|
||||
#include <fwupd.h>
|
||||
|
||||
#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);
|
||||
|
113
src/fu-firmware-common.c
Normal file
113
src/fu-firmware-common.c
Normal file
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2019 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "FuFirmware"
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#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);
|
||||
}
|
19
src/fu-firmware-common.h
Normal file
19
src/fu-firmware-common.h
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2017 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
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
|
329
src/fu-firmware-image.c
Normal file
329
src/fu-firmware-image.c
Normal file
@ -0,0 +1,329 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "FuFirmware"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
49
src/fu-firmware-image.h
Normal file
49
src/fu-firmware-image.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <fwupd.h>
|
||||
|
||||
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
|
402
src/fu-firmware.c
Normal file
402
src/fu-firmware.c
Normal file
@ -0,0 +1,402 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* 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;
|
||||
}
|
71
src/fu-firmware.h
Normal file
71
src/fu-firmware.h
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <fwupd.h>
|
||||
|
||||
#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
|
377
src/fu-ihex-firmware.c
Normal file
377
src/fu-ihex-firmware.c
Normal file
@ -0,0 +1,377 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "FuFirmware"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#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));
|
||||
}
|
18
src/fu-ihex-firmware.h
Normal file
18
src/fu-ihex-firmware.h
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* 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
|
@ -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);
|
||||
|
303
src/fu-srec-firmware.c
Normal file
303
src/fu-srec-firmware.c
Normal file
@ -0,0 +1,303 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "FuFirmware"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#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));
|
||||
}
|
18
src/fu-srec-firmware.h
Normal file
18
src/fu-srec-firmware.h
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* 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
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user