mirror of
https://git.proxmox.com/git/fwupd
synced 2025-05-30 16:45:56 +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;
|
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
|
static gboolean
|
||||||
fu_altos_device_write_firmware (FuDevice *device,
|
fu_altos_device_write_firmware (FuDevice *device,
|
||||||
GBytes *fw,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
FuAltosDevice *self = FU_ALTOS_DEVICE (device);
|
FuAltosDevice *self = FU_ALTOS_DEVICE (device);
|
||||||
GBytes *fw_blob;
|
|
||||||
const gchar *data;
|
const gchar *data;
|
||||||
const gsize data_len;
|
const gsize data_len;
|
||||||
guint flash_len;
|
guint flash_len;
|
||||||
g_autoptr(FuAltosFirmware) altos_firmware = NULL;
|
|
||||||
g_autoptr(FuDeviceLocker) locker = NULL;
|
g_autoptr(FuDeviceLocker) locker = NULL;
|
||||||
|
g_autoptr(FuFirmwareImage) img = NULL;
|
||||||
|
g_autoptr(GBytes) fw = NULL;
|
||||||
g_autoptr(GString) buf = g_string_new (NULL);
|
g_autoptr(GString) buf = g_string_new (NULL);
|
||||||
|
|
||||||
/* check kind */
|
/* check kind */
|
||||||
@ -312,25 +324,27 @@ fu_altos_device_write_firmware (FuDevice *device,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* load ihex blob */
|
/* load ihex blob */
|
||||||
altos_firmware = fu_altos_firmware_new ();
|
img = fu_firmware_get_image_default (firmware, error);
|
||||||
if (!fu_altos_firmware_parse (altos_firmware, fw, error))
|
if (img == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* check the start address */
|
/* 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,
|
g_set_error (error,
|
||||||
FWUPD_ERROR,
|
FWUPD_ERROR,
|
||||||
FWUPD_ERROR_INVALID_FILE,
|
FWUPD_ERROR_INVALID_FILE,
|
||||||
"start address not correct %" G_GUINT64_FORMAT ":"
|
"start address not correct %" G_GUINT64_FORMAT ":"
|
||||||
"%" G_GUINT64_FORMAT,
|
"%" G_GUINT64_FORMAT,
|
||||||
fu_altos_firmware_get_address (altos_firmware),
|
fu_firmware_image_get_addr (img),
|
||||||
self->addr_base);
|
self->addr_base);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check firmware will fit */
|
/* check firmware will fit */
|
||||||
fw_blob = fu_altos_firmware_get_data (altos_firmware);
|
fw = fu_firmware_image_get_bytes (img, error);
|
||||||
data = g_bytes_get_data (fw_blob, (gsize *) &data_len);
|
if (fw == NULL)
|
||||||
|
return FALSE;
|
||||||
|
data = g_bytes_get_data (fw, (gsize *) &data_len);
|
||||||
if (data_len > flash_len) {
|
if (data_len > flash_len) {
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
FWUPD_ERROR,
|
FWUPD_ERROR,
|
||||||
@ -628,6 +642,7 @@ fu_altos_device_class_init (FuAltosDeviceClass *klass)
|
|||||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
|
FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
|
||||||
klass_device->probe = fu_altos_device_probe;
|
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->write_firmware = fu_altos_device_write_firmware;
|
||||||
klass_device->read_firmware = fu_altos_device_read_firmware;
|
klass_device->read_firmware = fu_altos_device_read_firmware;
|
||||||
object_class->finalize = fu_altos_device_finalize;
|
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+
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <gio/gio.h>
|
|
||||||
#include <gelf.h>
|
#include <gelf.h>
|
||||||
#include <libelf.h>
|
#include <libelf.h>
|
||||||
|
|
||||||
#include "fu-altos-firmware.h"
|
#include "fu-altos-firmware.h"
|
||||||
#include "fwupd-error.h"
|
|
||||||
|
|
||||||
struct _FuAltosFirmware {
|
struct _FuAltosFirmware {
|
||||||
GObject parent_instance;
|
FuFirmware parent_instance;
|
||||||
GBytes *data;
|
|
||||||
guint64 address;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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 push
|
||||||
#pragma clang diagnostic ignored "-Wunused-function"
|
#pragma clang diagnostic ignored "-Wunused-function"
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(Elf, elf_end);
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(Elf, elf_end);
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
|
|
||||||
GBytes *
|
static gboolean
|
||||||
fu_altos_firmware_get_data (FuAltosFirmware *self)
|
fu_altos_firmware_parse (FuFirmware *firmware,
|
||||||
{
|
GBytes *blob,
|
||||||
return self->data;
|
guint64 addr_start,
|
||||||
}
|
guint64 addr_end,
|
||||||
|
FwupdInstallFlags flags,
|
||||||
guint64
|
GError **error)
|
||||||
fu_altos_firmware_get_address (FuAltosFirmware *self)
|
|
||||||
{
|
|
||||||
return self->address;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
fu_altos_firmware_parse (FuAltosFirmware *self, GBytes *blob, GError **error)
|
|
||||||
{
|
{
|
||||||
const gchar *name;
|
const gchar *name;
|
||||||
Elf_Scn *scn = NULL;
|
Elf_Scn *scn = NULL;
|
||||||
@ -99,8 +88,12 @@ fu_altos_firmware_parse (FuAltosFirmware *self, GBytes *blob, GError **error)
|
|||||||
if (g_strcmp0 (name, ".text") == 0) {
|
if (g_strcmp0 (name, ".text") == 0) {
|
||||||
Elf_Data *data = elf_getdata (scn, NULL);
|
Elf_Data *data = elf_getdata (scn, NULL);
|
||||||
if (data != NULL && data->d_buf != NULL) {
|
if (data != NULL && data->d_buf != NULL) {
|
||||||
self->data = g_bytes_new (data->d_buf, data->d_size);
|
g_autoptr(FuFirmwareImage) img = NULL;
|
||||||
self->address = shdr.sh_addr;
|
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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@ -112,22 +105,11 @@ fu_altos_firmware_parse (FuAltosFirmware *self, GBytes *blob, GError **error)
|
|||||||
return FALSE;
|
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
|
static void
|
||||||
fu_altos_firmware_class_init (FuAltosFirmwareClass *klass)
|
fu_altos_firmware_class_init (FuAltosFirmwareClass *klass)
|
||||||
{
|
{
|
||||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass);
|
||||||
object_class->finalize = fu_altos_firmware_finalize;
|
klass_firmware->parse = fu_altos_firmware_parse;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -135,10 +117,8 @@ fu_altos_firmware_init (FuAltosFirmware *self)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
FuAltosFirmware *
|
FuFirmware *
|
||||||
fu_altos_firmware_new (void)
|
fu_altos_firmware_new (void)
|
||||||
{
|
{
|
||||||
FuAltosFirmware *self;
|
return FU_FIRMWARE (g_object_new (FU_TYPE_ALTOS_FIRMWARE, NULL));
|
||||||
self = g_object_new (FU_TYPE_ALTOS_FIRMWARE, NULL);
|
|
||||||
return FU_ALTOS_FIRMWARE (self);
|
|
||||||
}
|
}
|
||||||
|
@ -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+
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "fu-firmware.h"
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
#define FU_TYPE_ALTOS_FIRMWARE (fu_altos_firmware_get_type ())
|
#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);
|
FuFirmware *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);
|
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
@ -578,15 +578,21 @@ fu_ata_device_fw_download (FuAtaDevice *self,
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fu_ata_device_write_firmware (FuDevice *device,
|
fu_ata_device_write_firmware (FuDevice *device,
|
||||||
GBytes *fw,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
FuAtaDevice *self = FU_ATA_DEVICE (device);
|
FuAtaDevice *self = FU_ATA_DEVICE (device);
|
||||||
guint32 chunksz = (guint32) self->transfer_blocks * FU_ATA_BLOCK_SIZE;
|
guint32 chunksz = (guint32) self->transfer_blocks * FU_ATA_BLOCK_SIZE;
|
||||||
guint max_size = 0xffff * FU_ATA_BLOCK_SIZE;
|
guint max_size = 0xffff * FU_ATA_BLOCK_SIZE;
|
||||||
|
g_autoptr(GBytes) fw = NULL;
|
||||||
g_autoptr(GPtrArray) chunks = 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 */
|
/* only one block allowed */
|
||||||
if (self->transfer_mode == ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNK)
|
if (self->transfer_mode == ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNK)
|
||||||
max_size = 0xffff;
|
max_size = 0xffff;
|
||||||
|
@ -328,13 +328,19 @@ ch_colorhug_device_calculate_checksum (const guint8 *data, guint32 len)
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fu_colorhug_device_write_firmware (FuDevice *device,
|
fu_colorhug_device_write_firmware (FuDevice *device,
|
||||||
GBytes *fw,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
FuColorhugDevice *self = FU_COLORHUG_DEVICE (device);
|
FuColorhugDevice *self = FU_COLORHUG_DEVICE (device);
|
||||||
|
g_autoptr(GBytes) fw = NULL;
|
||||||
g_autoptr(GPtrArray) chunks = 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 */
|
/* build packets */
|
||||||
chunks = fu_chunk_array_new_from_bytes (fw,
|
chunks = fu_chunk_array_new_from_bytes (fw,
|
||||||
self->start_addr,
|
self->start_addr,
|
||||||
|
@ -10,9 +10,9 @@
|
|||||||
|
|
||||||
#include "fu-chunk.h"
|
#include "fu-chunk.h"
|
||||||
#include "fu-csr-device.h"
|
#include "fu-csr-device.h"
|
||||||
|
#include "fu-ihex-firmware.h"
|
||||||
|
|
||||||
#include "dfu-common.h"
|
#include "dfu-common.h"
|
||||||
#include "dfu-firmware.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FU_CSR_DEVICE_QUIRK_FLAG_REQUIRE_DELAY:
|
* 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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GBytes *
|
static FuFirmware *
|
||||||
_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 *
|
|
||||||
fu_csr_device_prepare_firmware (FuDevice *device,
|
fu_csr_device_prepare_firmware (FuDevice *device,
|
||||||
GBytes *fw,
|
GBytes *fw,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
GBytes *blob_noftr;
|
g_autoptr(FuFirmware) firmware = fu_ihex_firmware_new ();
|
||||||
g_autoptr(DfuFirmware) dfu_firmware = dfu_firmware_new ();
|
|
||||||
|
|
||||||
/* parse the file */
|
/* parse the file */
|
||||||
if (!dfu_firmware_parse_data (dfu_firmware, fw,
|
if (!fu_firmware_parse (firmware, fw, flags, error))
|
||||||
DFU_FIRMWARE_PARSE_FLAG_NONE, error))
|
|
||||||
return NULL;
|
return NULL;
|
||||||
if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL) {
|
if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL) {
|
||||||
g_autofree gchar *fw_str = 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);
|
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 */
|
/* success */
|
||||||
return g_bytes_ref (blob_noftr);
|
return g_steal_pointer (&firmware);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fu_csr_device_download (FuDevice *device,
|
fu_csr_device_download (FuDevice *device,
|
||||||
GBytes *blob,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
FuCsrDevice *self = FU_CSR_DEVICE (device);
|
FuCsrDevice *self = FU_CSR_DEVICE (device);
|
||||||
guint16 idx;
|
guint16 idx;
|
||||||
g_autoptr(GBytes) blob_empty = NULL;
|
g_autoptr(GBytes) blob_empty = NULL;
|
||||||
|
g_autoptr(GBytes) blob = NULL;
|
||||||
g_autoptr(GPtrArray) chunks = 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 */
|
/* notify UI */
|
||||||
fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE);
|
fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE);
|
||||||
|
|
||||||
|
@ -46,22 +46,29 @@ fu_dell_dock_hub_probe (FuDevice *device, GError **error)
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fu_dell_dock_hub_write_fw (FuDevice *device,
|
fu_dell_dock_hub_write_fw (FuDevice *device,
|
||||||
GBytes *blob_fw,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
FuDellDockHub *self = FU_DELL_DOCK_HUB (device);
|
FuDellDockHub *self = FU_DELL_DOCK_HUB (device);
|
||||||
gsize fw_size = 0;
|
gsize fw_size = 0;
|
||||||
const guint8 *data = g_bytes_get_data (blob_fw, &fw_size);
|
const guint8 *data;
|
||||||
gsize write_size =
|
gsize write_size =
|
||||||
(fw_size / HIDI2C_MAX_WRITE) >= 1 ? HIDI2C_MAX_WRITE : fw_size;
|
(fw_size / HIDI2C_MAX_WRITE) >= 1 ? HIDI2C_MAX_WRITE : fw_size;
|
||||||
gsize nwritten = 0;
|
gsize nwritten = 0;
|
||||||
guint32 address = 0;
|
guint32 address = 0;
|
||||||
gboolean result = FALSE;
|
gboolean result = FALSE;
|
||||||
g_autofree gchar *dynamic_version = NULL;
|
g_autofree gchar *dynamic_version = NULL;
|
||||||
|
g_autoptr(GBytes) fw = NULL;
|
||||||
|
|
||||||
g_return_val_if_fail (device != NULL, FALSE);
|
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",
|
dynamic_version = g_strdup_printf ("%02x.%02x",
|
||||||
data[self->blob_major_offset],
|
data[self->blob_major_offset],
|
||||||
|
@ -745,7 +745,7 @@ fu_dell_dock_ec_commit_package (FuDevice *device, GBytes *blob_fw,
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fu_dell_dock_ec_write_fw (FuDevice *device,
|
fu_dell_dock_ec_write_fw (FuDevice *device,
|
||||||
GBytes *blob_fw,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
@ -753,15 +753,22 @@ fu_dell_dock_ec_write_fw (FuDevice *device,
|
|||||||
FuDellDockECFWUpdateStatus status = FW_UPDATE_IN_PROGRESS;
|
FuDellDockECFWUpdateStatus status = FW_UPDATE_IN_PROGRESS;
|
||||||
guint8 progress1 = 0, progress0 = 0;
|
guint8 progress1 = 0, progress0 = 0;
|
||||||
gsize fw_size = 0;
|
gsize fw_size = 0;
|
||||||
const guint8 *data = g_bytes_get_data (blob_fw, &fw_size);
|
const guint8 *data;
|
||||||
gsize write_size =
|
gsize write_size =
|
||||||
(fw_size / HIDI2C_MAX_WRITE) >= 1 ? HIDI2C_MAX_WRITE : fw_size;
|
(fw_size / HIDI2C_MAX_WRITE) >= 1 ? HIDI2C_MAX_WRITE : fw_size;
|
||||||
gsize nwritten = 0;
|
gsize nwritten = 0;
|
||||||
guint32 address = 0 | 0xff << 24;
|
guint32 address = 0 | 0xff << 24;
|
||||||
g_autofree gchar *dynamic_version = NULL;
|
g_autofree gchar *dynamic_version = NULL;
|
||||||
|
g_autoptr(GBytes) fw = NULL;
|
||||||
|
|
||||||
g_return_val_if_fail (device != NULL, FALSE);
|
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);
|
dynamic_version = g_strndup ((gchar *) data + self->blob_version_offset, 11);
|
||||||
g_debug ("writing EC firmware version %s", dynamic_version);
|
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
|
static gboolean
|
||||||
fu_dell_dock_mst_write_fw (FuDevice *device,
|
fu_dell_dock_mst_write_fw (FuDevice *device,
|
||||||
GBytes *blob_fw,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
@ -745,13 +745,20 @@ fu_dell_dock_mst_write_fw (FuDevice *device,
|
|||||||
gboolean checksum = FALSE;
|
gboolean checksum = FALSE;
|
||||||
guint8 order[2] = {ESM, Bank0};
|
guint8 order[2] = {ESM, Bank0};
|
||||||
guint16 chip_id;
|
guint16 chip_id;
|
||||||
const guint8* data = g_bytes_get_data (blob_fw, NULL);
|
const guint8 *data;
|
||||||
g_autofree gchar *dynamic_version = NULL;
|
g_autofree gchar *dynamic_version = NULL;
|
||||||
|
g_autoptr(GBytes) fw = NULL;
|
||||||
|
|
||||||
g_return_val_if_fail (device != NULL, FALSE);
|
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);
|
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",
|
dynamic_version = g_strdup_printf ("%02x.%02x.%02x",
|
||||||
data[self->blob_major_offset],
|
data[self->blob_major_offset],
|
||||||
data[self->blob_minor_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++) {
|
for (guint phase = 0; phase < 2; phase++) {
|
||||||
g_debug ("MST: Checking bank %u", order[phase]);
|
g_debug ("MST: Checking bank %u", order[phase]);
|
||||||
if (!fu_dell_dock_mst_checksum_bank (self->symbiote,
|
if (!fu_dell_dock_mst_checksum_bank (self->symbiote,
|
||||||
blob_fw,
|
fw,
|
||||||
order[phase],
|
order[phase],
|
||||||
&checksum, error))
|
&checksum, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -804,11 +811,11 @@ fu_dell_dock_mst_write_fw (FuDevice *device,
|
|||||||
error))
|
error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE);
|
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))
|
order[phase], error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
if (!fu_dell_dock_mst_checksum_bank (self->symbiote,
|
if (!fu_dell_dock_mst_checksum_bank (self->symbiote,
|
||||||
blob_fw,
|
fw,
|
||||||
order[phase],
|
order[phase],
|
||||||
&checksum,
|
&checksum,
|
||||||
error))
|
error))
|
||||||
|
@ -53,20 +53,27 @@ G_DEFINE_TYPE (FuDellDockTbt, fu_dell_dock_tbt, FU_TYPE_DEVICE)
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fu_dell_dock_tbt_write_fw (FuDevice *device,
|
fu_dell_dock_tbt_write_fw (FuDevice *device,
|
||||||
GBytes *blob_fw,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
FuDellDockTbt *self = FU_DELL_DOCK_TBT (device);
|
FuDellDockTbt *self = FU_DELL_DOCK_TBT (device);
|
||||||
guint32 start_offset = 0;
|
guint32 start_offset = 0;
|
||||||
gsize image_size;
|
gsize image_size = 0;
|
||||||
const guint8 *buffer = g_bytes_get_data (blob_fw, &image_size);
|
const guint8 *buffer;
|
||||||
guint16 target_system = 0;
|
guint16 target_system = 0;
|
||||||
g_autoptr(GTimer) timer = g_timer_new ();
|
g_autoptr(GTimer) timer = g_timer_new ();
|
||||||
g_autofree gchar *dynamic_version = NULL;
|
g_autofree gchar *dynamic_version = NULL;
|
||||||
|
g_autoptr(GBytes) fw = NULL;
|
||||||
|
|
||||||
g_return_val_if_fail (device != NULL, FALSE);
|
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",
|
dynamic_version = g_strdup_printf ("%02x.%02x",
|
||||||
buffer[self->blob_major_offset],
|
buffer[self->blob_major_offset],
|
||||||
|
@ -58,7 +58,7 @@ fu_dell_dock_status_setup (FuDevice *device, GError **error)
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fu_dell_dock_status_write (FuDevice *device,
|
fu_dell_dock_status_write (FuDevice *device,
|
||||||
GBytes *blob_fw,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
@ -66,18 +66,25 @@ fu_dell_dock_status_write (FuDevice *device,
|
|||||||
FuDevice *parent;
|
FuDevice *parent;
|
||||||
gsize length = 0;
|
gsize length = 0;
|
||||||
guint32 status_version = 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_autofree gchar *dynamic_version = NULL;
|
||||||
|
g_autoptr(GBytes) fw = NULL;
|
||||||
|
|
||||||
g_return_val_if_fail (device != NULL, FALSE);
|
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));
|
memcpy (&status_version, data + self->blob_version_offset, sizeof (guint32));
|
||||||
dynamic_version = fu_dell_dock_status_ver_string (status_version);
|
dynamic_version = fu_dell_dock_status_ver_string (status_version);
|
||||||
g_debug ("writing status firmware version %s", dynamic_version);
|
g_debug ("writing status firmware version %s", dynamic_version);
|
||||||
|
|
||||||
parent = fu_device_get_parent (device);
|
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;
|
return FALSE;
|
||||||
|
|
||||||
/* dock will reboot to re-read; this is to appease the daemon */
|
/* 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);
|
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 */
|
/* helpers */
|
||||||
GBytes *dfu_utils_bytes_join_array (GPtrArray *chunks);
|
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
|
G_END_DECLS
|
||||||
|
@ -86,6 +86,7 @@
|
|||||||
#include "dfu-target-stm.h"
|
#include "dfu-target-stm.h"
|
||||||
|
|
||||||
#include "fu-device-locker.h"
|
#include "fu-device-locker.h"
|
||||||
|
#include "fu-firmware-common.h"
|
||||||
|
|
||||||
#include "fwupd-error.h"
|
#include "fwupd-error.h"
|
||||||
|
|
||||||
@ -1120,8 +1121,8 @@ dfu_device_detach (DfuDevice *device, GError **error)
|
|||||||
g_autoptr(GError) error_jabra = NULL;
|
g_autoptr(GError) error_jabra = NULL;
|
||||||
|
|
||||||
/* parse string and create magic packet */
|
/* parse string and create magic packet */
|
||||||
rep = dfu_utils_buffer_parse_uint8 (priv->jabra_detach + 0);
|
rep = fu_firmware_strparse_uint8 (priv->jabra_detach + 0);
|
||||||
adr = dfu_utils_buffer_parse_uint8 (priv->jabra_detach + 2);
|
adr = fu_firmware_strparse_uint8 (priv->jabra_detach + 2);
|
||||||
buf[0] = rep;
|
buf[0] = rep;
|
||||||
buf[1] = adr;
|
buf[1] = adr;
|
||||||
buf[2] = 0x00;
|
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 (g_strcmp0 (key, FU_QUIRKS_DFU_FORCE_VERSION) == 0) {
|
||||||
if (value != NULL && strlen (value) == 4) {
|
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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
g_set_error_literal (error,
|
g_set_error_literal (error,
|
||||||
|
@ -239,60 +239,3 @@ dfu_element_set_target_size (DfuElement *element, guint32 target_size)
|
|||||||
g_bytes_unref (priv->contents);
|
g_bytes_unref (priv->contents);
|
||||||
priv->contents = g_bytes_new_take (buf, target_size);
|
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);
|
GBytes *dfu_element_get_contents (DfuElement *element);
|
||||||
guint32 dfu_element_get_address (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,
|
void dfu_element_set_contents (DfuElement *element,
|
||||||
GBytes *contents);
|
GBytes *contents);
|
||||||
void dfu_element_set_address (DfuElement *element,
|
void dfu_element_set_address (DfuElement *element,
|
||||||
|
@ -15,6 +15,9 @@
|
|||||||
#include "dfu-format-ihex.h"
|
#include "dfu-format-ihex.h"
|
||||||
#include "dfu-image.h"
|
#include "dfu-image.h"
|
||||||
|
|
||||||
|
#include "fu-firmware-common.h"
|
||||||
|
#include "fu-ihex-firmware.h"
|
||||||
|
|
||||||
#include "fwupd-error.h"
|
#include "fwupd-error.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,34 +49,6 @@ dfu_firmware_detect_ihex (GBytes *bytes)
|
|||||||
return DFU_FIRMWARE_FORMAT_UNKNOWN;
|
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)
|
* dfu_firmware_from_ihex: (skip)
|
||||||
* @firmware: a #DfuFirmware
|
* @firmware: a #DfuFirmware
|
||||||
@ -91,315 +66,28 @@ dfu_firmware_from_ihex (DfuFirmware *firmware,
|
|||||||
DfuFirmwareParseFlags flags,
|
DfuFirmwareParseFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
const gchar *data;
|
g_autoptr(FuFirmware) firmware_new = fu_ihex_firmware_new ();
|
||||||
gboolean got_eof = FALSE;
|
g_autoptr(GPtrArray) imgs = NULL;
|
||||||
gsize sz = 0;
|
FwupdInstallFlags flags_new = FWUPD_INSTALL_FLAG_NONE;
|
||||||
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_return_val_if_fail (bytes != NULL, FALSE);
|
/* make a native objects from the abstract firmware */
|
||||||
|
if (flags & DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST)
|
||||||
/* create element */
|
flags_new |= FWUPD_INSTALL_FLAG_FORCE;
|
||||||
image = dfu_image_new ();
|
if (!fu_firmware_parse (firmware_new, bytes, flags_new, error))
|
||||||
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");
|
|
||||||
return FALSE;
|
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);
|
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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,18 +104,21 @@ GBytes *
|
|||||||
dfu_firmware_to_ihex (DfuFirmware *firmware, GError **error)
|
dfu_firmware_to_ihex (DfuFirmware *firmware, GError **error)
|
||||||
{
|
{
|
||||||
GPtrArray *images;
|
GPtrArray *images;
|
||||||
g_autoptr(GString) str = NULL;
|
g_autoptr(FuFirmware) firmware_new = fu_ihex_firmware_new ();
|
||||||
|
|
||||||
/* write all the element data */
|
/* make a new object from the native firmware */
|
||||||
str = g_string_new ("");
|
|
||||||
images = dfu_firmware_get_images (firmware);
|
images = dfu_firmware_get_images (firmware);
|
||||||
for (guint i = 0; i < images->len; i++) {
|
for (guint i = 0; i < images->len; i++) {
|
||||||
DfuImage *image = g_ptr_array_index (images, i);
|
DfuImage *image = g_ptr_array_index (images, i);
|
||||||
if (!dfu_firmware_to_ihex_image (image, str, error))
|
GPtrArray *elements = dfu_image_get_elements (image);
|
||||||
return NULL;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return fu_firmware_write (firmware_new, error);
|
||||||
/* add EOF */
|
|
||||||
dfu_firmware_ihex_emit_chunk (str, 0x0, DFU_INHX32_RECORD_TYPE_EOF, NULL, 0);
|
|
||||||
return g_bytes_new (str->str, str->len);
|
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,13 @@
|
|||||||
|
|
||||||
#include "fu-common.h"
|
#include "fu-common.h"
|
||||||
|
|
||||||
#include "dfu-element.h"
|
|
||||||
#include "dfu-firmware.h"
|
#include "dfu-firmware.h"
|
||||||
#include "dfu-format-srec.h"
|
#include "dfu-format-srec.h"
|
||||||
#include "dfu-image.h"
|
#include "dfu-image.h"
|
||||||
|
|
||||||
|
#include "fu-firmware-common.h"
|
||||||
|
#include "fu-srec-firmware.h"
|
||||||
|
|
||||||
#include "fwupd-error.h"
|
#include "fwupd-error.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,282 +40,6 @@ dfu_firmware_detect_srec (GBytes *bytes)
|
|||||||
return DFU_FIRMWARE_FORMAT_SREC;
|
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)
|
* dfu_firmware_from_srec: (skip)
|
||||||
* @firmware: a #DfuFirmware
|
* @firmware: a #DfuFirmware
|
||||||
@ -331,15 +57,26 @@ dfu_firmware_from_srec (DfuFirmware *firmware,
|
|||||||
DfuFirmwareParseFlags flags,
|
DfuFirmwareParseFlags flags,
|
||||||
GError **error)
|
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);
|
/* make a native objects from the abstract firmware */
|
||||||
|
if (flags & DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST)
|
||||||
/* add single image */
|
flags_new |= FWUPD_INSTALL_FLAG_FORCE;
|
||||||
image = dfu_image_new ();
|
if (!fu_firmware_parse (firmware_new, bytes, flags_new, error))
|
||||||
if (!dfu_image_from_srec (image, bytes, 0x0, flags, error))
|
|
||||||
return FALSE;
|
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);
|
dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_SREC);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -20,10 +20,5 @@ gboolean dfu_firmware_from_srec (DfuFirmware *firmware,
|
|||||||
GBytes *bytes,
|
GBytes *bytes,
|
||||||
DfuFirmwareParseFlags flags,
|
DfuFirmwareParseFlags flags,
|
||||||
GError **error);
|
GError **error);
|
||||||
gboolean dfu_image_from_srec (DfuImage *image,
|
|
||||||
GBytes *bytes,
|
|
||||||
guint32 start_addr,
|
|
||||||
DfuFirmwareParseFlags flags,
|
|
||||||
GError **error);
|
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
@ -320,209 +320,6 @@ dfu_firmware_metadata_func (void)
|
|||||||
g_assert_true (ret);
|
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 *
|
static gchar *
|
||||||
dfu_target_sectors_to_string (DfuTarget *target)
|
dfu_target_sectors_to_string (DfuTarget *target)
|
||||||
{
|
{
|
||||||
@ -794,7 +591,6 @@ main (int argc, char **argv)
|
|||||||
g_setenv ("G_MESSAGES_DEBUG", "all", FALSE);
|
g_setenv ("G_MESSAGES_DEBUG", "all", FALSE);
|
||||||
|
|
||||||
/* tests go here */
|
/* 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", dfu_patch_func);
|
||||||
g_test_add_func ("/dfu/patch{merges}", dfu_patch_merges_func);
|
g_test_add_func ("/dfu/patch{merges}", dfu_patch_merges_func);
|
||||||
g_test_add_func ("/dfu/patch{apply}", dfu_patch_apply_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{dfuse}", dfu_firmware_dfuse_func);
|
||||||
g_test_add_func ("/dfu/firmware{xdfu}", dfu_firmware_xdfu_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{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 ();
|
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
|
static gboolean
|
||||||
fu_ebitdo_device_write_firmware (FuDevice *device,
|
fu_ebitdo_device_write_firmware (FuDevice *device,
|
||||||
GBytes *fw,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
@ -358,6 +358,7 @@ fu_ebitdo_device_write_firmware (FuDevice *device,
|
|||||||
const guint chunk_sz = 32;
|
const guint chunk_sz = 32;
|
||||||
guint32 payload_len;
|
guint32 payload_len;
|
||||||
guint32 serial_new[3];
|
guint32 serial_new[3];
|
||||||
|
g_autoptr(GBytes) fw = NULL;
|
||||||
g_autoptr(GError) error_local = NULL;
|
g_autoptr(GError) error_local = NULL;
|
||||||
const guint32 app_key_index[16] = {
|
const guint32 app_key_index[16] = {
|
||||||
0x186976e5, 0xcac67acd, 0x38f27fee, 0x0a4948f1,
|
0x186976e5, 0xcac67acd, 0x38f27fee, 0x0a4948f1,
|
||||||
@ -408,6 +409,11 @@ fu_ebitdo_device_write_firmware (FuDevice *device,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* get default image */
|
||||||
|
fw = fu_firmware_get_image_default_bytes (firmware, error);
|
||||||
|
if (fw == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
/* corrupt */
|
/* corrupt */
|
||||||
if (g_bytes_get_size (fw) < sizeof (FuEbitdoFirmwareHeader)) {
|
if (g_bytes_get_size (fw) < sizeof (FuEbitdoFirmwareHeader)) {
|
||||||
g_set_error_literal (error,
|
g_set_error_literal (error,
|
||||||
|
@ -595,11 +595,17 @@ fu_fastboot_device_write_qfil (FuDevice *device, FuArchive* archive, GError **er
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fu_fastboot_device_write_firmware (FuDevice *device,
|
fu_fastboot_device_write_firmware (FuDevice *device,
|
||||||
GBytes *fw,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
g_autoptr(FuArchive) archive = NULL;
|
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 */
|
/* decompress entire archive ahead of time */
|
||||||
archive = fu_archive_new (fw, FU_ARCHIVE_FLAG_IGNORE_PATH, error);
|
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
|
static gboolean
|
||||||
fu_mm_device_write_firmware (FuDevice *device,
|
fu_mm_device_write_firmware (FuDevice *device,
|
||||||
GBytes *fw,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
FuMmDevice *self = FU_MM_DEVICE (device);
|
FuMmDevice *self = FU_MM_DEVICE (device);
|
||||||
g_autoptr(FuDeviceLocker) locker = NULL;
|
g_autoptr(FuDeviceLocker) locker = NULL;
|
||||||
g_autoptr(FuArchive) archive = NULL;
|
g_autoptr(FuArchive) archive = NULL;
|
||||||
|
g_autoptr(GBytes) fw = NULL;
|
||||||
g_autoptr(GPtrArray) array = 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 */
|
/* lock device */
|
||||||
locker = fu_device_locker_new (device, error);
|
locker = fu_device_locker_new (device, error);
|
||||||
if (locker == NULL)
|
if (locker == NULL)
|
||||||
|
@ -395,16 +395,22 @@ fu_nvme_device_close (FuDevice *device, GError **error)
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fu_nvme_device_write_firmware (FuDevice *device,
|
fu_nvme_device_write_firmware (FuDevice *device,
|
||||||
GBytes *fw,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
FuNvmeDevice *self = FU_NVME_DEVICE (device);
|
FuNvmeDevice *self = FU_NVME_DEVICE (device);
|
||||||
g_autoptr(GBytes) fw2 = NULL;
|
g_autoptr(GBytes) fw2 = NULL;
|
||||||
|
g_autoptr(GBytes) fw = NULL;
|
||||||
g_autoptr(GPtrArray) chunks = NULL;
|
g_autoptr(GPtrArray) chunks = NULL;
|
||||||
guint64 block_size = self->write_block_size > 0 ?
|
guint64 block_size = self->write_block_size > 0 ?
|
||||||
self->write_block_size : 0x1000;
|
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
|
/* some vendors provide firmware files whose sizes are not multiples
|
||||||
* of blksz *and* the device won't accept blocks of different sizes */
|
* of blksz *and* the device won't accept blocks of different sizes */
|
||||||
if (fu_device_has_custom_flag (device, "force-align")) {
|
if (fu_device_has_custom_flag (device, "force-align")) {
|
||||||
|
@ -315,13 +315,19 @@ fu_rts54hid_device_close (FuUsbDevice *device, GError **error)
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fu_rts54hid_device_write_firmware (FuDevice *device,
|
fu_rts54hid_device_write_firmware (FuDevice *device,
|
||||||
GBytes *fw,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
FuRts54HidDevice *self = FU_RTS54HID_DEVICE (device);
|
FuRts54HidDevice *self = FU_RTS54HID_DEVICE (device);
|
||||||
|
g_autoptr(GBytes) fw = NULL;
|
||||||
g_autoptr(GPtrArray) chunks = 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 */
|
/* set MCU to high clock rate for better ISP performance */
|
||||||
if (!fu_rts54hid_device_set_clock_mode (self, TRUE, error))
|
if (!fu_rts54hid_device_set_clock_mode (self, TRUE, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -212,13 +212,19 @@ fu_rts54hid_module_close (FuDevice *device, GError **error)
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fu_rts54hid_module_write_firmware (FuDevice *module,
|
fu_rts54hid_module_write_firmware (FuDevice *module,
|
||||||
GBytes *fw,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
FuRts54HidModule *self = FU_RTS54HID_MODULE (module);
|
FuRts54HidModule *self = FU_RTS54HID_MODULE (module);
|
||||||
|
g_autoptr(GBytes) fw = NULL;
|
||||||
g_autoptr(GPtrArray) chunks = 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 */
|
/* build packets */
|
||||||
chunks = fu_chunk_array_new_from_bytes (fw,
|
chunks = fu_chunk_array_new_from_bytes (fw,
|
||||||
0x00, /* start addr */
|
0x00, /* start addr */
|
||||||
|
@ -309,13 +309,19 @@ fu_rts54hub_device_close (FuUsbDevice *device, GError **error)
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fu_rts54hub_device_write_firmware (FuDevice *device,
|
fu_rts54hub_device_write_firmware (FuDevice *device,
|
||||||
GBytes *fw,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
FuRts54HubDevice *self = FU_RTS54HUB_DEVICE (device);
|
FuRts54HubDevice *self = FU_RTS54HUB_DEVICE (device);
|
||||||
|
g_autoptr(GBytes) fw = NULL;
|
||||||
g_autoptr(GPtrArray) chunks = 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 */
|
/* enable vendor commands */
|
||||||
if (!fu_rts54hub_device_vendor_cmd (self,
|
if (!fu_rts54hub_device_vendor_cmd (self,
|
||||||
FU_RTS54HUB_VENDOR_CMD_STATUS |
|
FU_RTS54HUB_VENDOR_CMD_STATUS |
|
||||||
@ -383,7 +389,7 @@ fu_rts54hub_device_write_firmware (FuDevice *device,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GBytes *
|
static FuFirmware *
|
||||||
fu_rts54hub_device_prepare_firmware (FuDevice *device,
|
fu_rts54hub_device_prepare_firmware (FuDevice *device,
|
||||||
GBytes *fw,
|
GBytes *fw,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
@ -405,7 +411,7 @@ fu_rts54hub_device_prepare_firmware (FuDevice *device,
|
|||||||
"firmware needs to be dual bank");
|
"firmware needs to be dual bank");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return g_bytes_ref (fw);
|
return fu_firmware_new_from_bytes (fw);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -7,11 +7,10 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <json-glib/json-glib.h>
|
|
||||||
|
|
||||||
#include "dfu-firmware.h"
|
|
||||||
#include "fu-chunk.h"
|
#include "fu-chunk.h"
|
||||||
#include "fu-solokey-device.h"
|
#include "fu-solokey-device.h"
|
||||||
|
#include "fu-solokey-firmware.h"
|
||||||
|
|
||||||
struct _FuSolokeyDevice {
|
struct _FuSolokeyDevice {
|
||||||
FuUsbDevice parent_instance;
|
FuUsbDevice parent_instance;
|
||||||
@ -396,30 +395,15 @@ fu_solokey_device_setup (FuDevice *device, GError **error)
|
|||||||
return TRUE;
|
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
|
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) req = g_byte_array_new ();
|
||||||
g_autoptr(GByteArray) res = NULL;
|
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);
|
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);
|
fu_solokey_device_exchange (req, SOLO_BOOTLOADER_DONE, 0x00, sig);
|
||||||
res = fu_solokey_device_packet (self, SOLO_BOOTLOADER_HID_CMD_BOOT, req, error);
|
res = fu_solokey_device_packet (self, SOLO_BOOTLOADER_HID_CMD_BOOT, req, error);
|
||||||
if (res == NULL)
|
if (res == NULL)
|
||||||
@ -427,75 +411,42 @@ fu_solokey_device_verify (FuSolokeyDevice *self, const gchar *base64, GError **e
|
|||||||
return TRUE;
|
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
|
static gboolean
|
||||||
fu_solokey_device_write_firmware (FuDevice *device,
|
fu_solokey_device_write_firmware (FuDevice *device,
|
||||||
GBytes *fw,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
FuSolokeyDevice *self = FU_SOLOKEY_DEVICE (device);
|
FuSolokeyDevice *self = FU_SOLOKEY_DEVICE (device);
|
||||||
DfuElement *element;
|
g_autoptr(FuFirmwareImage) img = NULL;
|
||||||
DfuImage *image;
|
g_autoptr(GBytes) fw = NULL;
|
||||||
JsonNode *json_root;
|
g_autoptr(GBytes) fw_sig = NULL;
|
||||||
JsonObject *json_obj;
|
|
||||||
const gchar *base64;
|
|
||||||
g_autoptr(DfuFirmware) firmware = dfu_firmware_new ();
|
|
||||||
g_autoptr(GBytes) fw_ihex = NULL;
|
|
||||||
g_autoptr(GPtrArray) chunks = NULL;
|
g_autoptr(GPtrArray) chunks = NULL;
|
||||||
g_autoptr(GString) base64_websafe = NULL;
|
|
||||||
g_autoptr(JsonParser) parser = json_parser_new ();
|
|
||||||
|
|
||||||
/* parse JSON */
|
/* get main image */
|
||||||
fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING);
|
img = fu_firmware_get_image_by_id (firmware, NULL, error);
|
||||||
if (!json_parser_load_from_data (parser,
|
if (img == NULL)
|
||||||
(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;
|
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 */
|
/* build packets */
|
||||||
chunks = fu_chunk_array_new_from_bytes (dfu_element_get_contents (element),
|
fw = fu_firmware_image_get_bytes (img, error);
|
||||||
dfu_element_get_address (element),
|
if (fw == NULL)
|
||||||
|
return FALSE;
|
||||||
|
chunks = fu_chunk_array_new_from_bytes (fw,
|
||||||
|
fu_firmware_image_get_addr (img),
|
||||||
0x00, /* page_sz */
|
0x00, /* page_sz */
|
||||||
2048);
|
2048);
|
||||||
|
|
||||||
@ -525,11 +476,10 @@ fu_solokey_device_write_firmware (FuDevice *device,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* verify the signature and reboot back to runtime */
|
/* verify the signature and reboot back to runtime */
|
||||||
base64_websafe = g_string_new (json_object_get_string_member (json_obj, "signature"));
|
fw_sig = fu_firmware_get_image_by_id_bytes (firmware, "signature", error);
|
||||||
fu_common_string_replace (base64_websafe, "-", "+");
|
if (fw_sig == NULL)
|
||||||
fu_common_string_replace (base64_websafe, "_", "/");
|
return FALSE;
|
||||||
g_string_append (base64_websafe, "==");
|
return fu_solokey_device_verify (self, fw_sig, error);
|
||||||
return fu_solokey_device_verify (self, base64_websafe->str, error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -549,6 +499,7 @@ fu_solokey_device_class_init (FuSolokeyDeviceClass *klass)
|
|||||||
FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
|
FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
|
||||||
FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass);
|
FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass);
|
||||||
klass_device->write_firmware = fu_solokey_device_write_firmware;
|
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_device->setup = fu_solokey_device_setup;
|
||||||
klass_usb_device->open = fu_solokey_device_open;
|
klass_usb_device->open = fu_solokey_device_open;
|
||||||
klass_usb_device->close = fu_solokey_device_close;
|
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,
|
fu_hash,
|
||||||
sources : [
|
sources : [
|
||||||
'fu-solokey-device.c',
|
'fu-solokey-device.c',
|
||||||
|
'fu-solokey-firmware.c',
|
||||||
'fu-plugin-solokey.c',
|
'fu-plugin-solokey.c',
|
||||||
],
|
],
|
||||||
include_directories : [
|
include_directories : [
|
||||||
include_directories('../..'),
|
include_directories('../..'),
|
||||||
include_directories('../dfu'),
|
|
||||||
include_directories('../../src'),
|
include_directories('../../src'),
|
||||||
include_directories('../../libfwupd'),
|
include_directories('../../libfwupd'),
|
||||||
],
|
],
|
||||||
@ -22,7 +22,6 @@ shared_module('fu_plugin_solokey',
|
|||||||
install_dir: plugin_dir,
|
install_dir: plugin_dir,
|
||||||
link_with : [
|
link_with : [
|
||||||
libfwupdprivate,
|
libfwupdprivate,
|
||||||
dfu,
|
|
||||||
],
|
],
|
||||||
c_args : cargs,
|
c_args : cargs,
|
||||||
dependencies : [
|
dependencies : [
|
||||||
|
@ -362,7 +362,7 @@ fu_superio_device_setup (FuDevice *device, GError **error)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GBytes *
|
static FuFirmware *
|
||||||
fu_superio_device_prepare_firmware (FuDevice *device,
|
fu_superio_device_prepare_firmware (FuDevice *device,
|
||||||
GBytes *fw,
|
GBytes *fw,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
@ -378,7 +378,7 @@ fu_superio_device_prepare_firmware (FuDevice *device,
|
|||||||
if (memcmp (&buf[off], sig1, sizeof(sig1)) == 0 &&
|
if (memcmp (&buf[off], sig1, sizeof(sig1)) == 0 &&
|
||||||
memcmp (&buf[off + 8], sig2, sizeof(sig2)) == 0) {
|
memcmp (&buf[off + 8], sig2, sizeof(sig2)) == 0) {
|
||||||
g_debug ("found signature at 0x%04x", (guint) off);
|
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,
|
g_set_error_literal (error,
|
||||||
|
@ -591,13 +591,14 @@ fu_superio_it89_device_get_jedec_id (FuSuperioDevice *self, guint8 *id, GError *
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fu_superio_it89_device_write_firmware (FuDevice *device,
|
fu_superio_it89_device_write_firmware (FuDevice *device,
|
||||||
GBytes *fw,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
FuSuperioDevice *self = FU_SUPERIO_DEVICE (device);
|
FuSuperioDevice *self = FU_SUPERIO_DEVICE (device);
|
||||||
guint8 id[4] = { 0x0 };
|
guint8 id[4] = { 0x0 };
|
||||||
g_autoptr(GBytes) fw_fixed = NULL;
|
g_autoptr(GBytes) fw_fixed = NULL;
|
||||||
|
g_autoptr(GBytes) fw = NULL;
|
||||||
g_autoptr(GPtrArray) chunks = NULL;
|
g_autoptr(GPtrArray) chunks = NULL;
|
||||||
|
|
||||||
/* check JEDEC ID */
|
/* check JEDEC ID */
|
||||||
@ -618,6 +619,11 @@ fu_superio_it89_device_write_firmware (FuDevice *device,
|
|||||||
if (!fu_superio_it89_device_check_eflash (self, error))
|
if (!fu_superio_it89_device_check_eflash (self, error))
|
||||||
return FALSE;
|
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 */
|
/* disable the mirroring of e-flash */
|
||||||
if (g_getenv ("FWUPD_SUPERIO_DISABLE_MIRROR") != NULL) {
|
if (g_getenv ("FWUPD_SUPERIO_DISABLE_MIRROR") != NULL) {
|
||||||
fw_fixed = fu_plugin_superio_fix_signature (self, fw, error);
|
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;
|
gchar *data = NULL;
|
||||||
gsize len = 0;
|
gsize len = 0;
|
||||||
g_autoptr(GBytes) blob = NULL;
|
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))
|
if (!g_file_get_contents (filename, &data, &len, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
blob = g_bytes_new_take (data, len);
|
blob = g_bytes_new_take (data, len);
|
||||||
array = fu_synaprom_firmware_new (blob, error);
|
return fu_firmware_parse (firmware, blob, 0, error);
|
||||||
return array != NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -28,7 +27,10 @@ fu_dump_generate (const gchar *filename, GError **error)
|
|||||||
const gchar *data;
|
const gchar *data;
|
||||||
gsize len = 0;
|
gsize len = 0;
|
||||||
g_autoptr(GBytes) blob = NULL;
|
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);
|
data = g_bytes_get_data (blob, &len);
|
||||||
return g_file_set_contents (filename, data, len, error);
|
return g_file_set_contents (filename, data, len, error);
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ static void
|
|||||||
fu_test_synaprom_firmware_func (void)
|
fu_test_synaprom_firmware_func (void)
|
||||||
{
|
{
|
||||||
const guint8 *buf;
|
const guint8 *buf;
|
||||||
|
gboolean ret;
|
||||||
gsize sz = 0;
|
gsize sz = 0;
|
||||||
g_autofree gchar *filename = NULL;
|
g_autofree gchar *filename = NULL;
|
||||||
g_autoptr(FuSynapromDevice) device = fu_synaprom_device_new (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) blob2 = NULL;
|
||||||
g_autoptr(GBytes) fw = NULL;
|
g_autoptr(GBytes) fw = NULL;
|
||||||
g_autoptr(GError) error = 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");
|
filename = fu_test_get_filename (TESTDATADIR, "test.pkg");
|
||||||
g_assert_nonnull (filename);
|
g_assert_nonnull (filename);
|
||||||
@ -36,22 +38,18 @@ fu_test_synaprom_firmware_func (void)
|
|||||||
g_assert_cmpint (sz, ==, 294);
|
g_assert_cmpint (sz, ==, 294);
|
||||||
g_assert_cmpint (buf[0], ==, 0x01);
|
g_assert_cmpint (buf[0], ==, 0x01);
|
||||||
g_assert_cmpint (buf[1], ==, 0x00);
|
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_no_error (error);
|
||||||
g_assert_nonnull (firmware);
|
g_assert_true (ret);
|
||||||
|
|
||||||
/* does not exist */
|
/* 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);
|
g_assert_null (blob1);
|
||||||
blob1 = fu_synaprom_firmware_get_bytes_by_tag (firmware,
|
blob1 = fu_firmware_get_image_by_id_bytes (firmware, "cfg-update-header", NULL);
|
||||||
FU_SYNAPROM_FIRMWARE_TAG_CFG_HEADER,
|
|
||||||
NULL);
|
|
||||||
g_assert_null (blob1);
|
g_assert_null (blob1);
|
||||||
|
|
||||||
/* header needs to exist */
|
/* header needs to exist */
|
||||||
blob1 = fu_synaprom_firmware_get_bytes_by_tag (firmware,
|
blob1 = fu_firmware_get_image_by_id_bytes (firmware, "mfw-update-header", &error);
|
||||||
FU_SYNAPROM_FIRMWARE_TAG_MFW_HEADER,
|
|
||||||
&error);
|
|
||||||
g_assert_no_error (error);
|
g_assert_no_error (error);
|
||||||
g_assert_nonnull (blob1);
|
g_assert_nonnull (blob1);
|
||||||
buf = g_bytes_get_data (blob1, &sz);
|
buf = g_bytes_get_data (blob1, &sz);
|
||||||
@ -64,8 +62,11 @@ fu_test_synaprom_firmware_func (void)
|
|||||||
|
|
||||||
/* payload needs to exist */
|
/* payload needs to exist */
|
||||||
fu_synaprom_device_set_version (device, 10, 1, 1234);
|
fu_synaprom_device_set_version (device, 10, 1, 1234);
|
||||||
blob2 = fu_synaprom_device_prepare_fw (FU_DEVICE (device), fw,
|
firmware2 = fu_synaprom_device_prepare_fw (FU_DEVICE (device), fw,
|
||||||
FWUPD_INSTALL_FLAG_NONE, &error);
|
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_no_error (error);
|
||||||
g_assert_nonnull (blob2);
|
g_assert_nonnull (blob2);
|
||||||
buf = g_bytes_get_data (blob2, &sz);
|
buf = g_bytes_get_data (blob2, &sz);
|
||||||
|
@ -112,7 +112,7 @@ fu_synaprom_config_setup (FuDevice *device, GError **error)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GBytes *
|
static FuFirmware *
|
||||||
fu_synaprom_config_prepare_firmware (FuDevice *device,
|
fu_synaprom_config_prepare_firmware (FuDevice *device,
|
||||||
GBytes *fw,
|
GBytes *fw,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
@ -121,20 +121,17 @@ fu_synaprom_config_prepare_firmware (FuDevice *device,
|
|||||||
FuSynapromConfig *self = FU_SYNAPROM_CONFIG (device);
|
FuSynapromConfig *self = FU_SYNAPROM_CONFIG (device);
|
||||||
FuSynapromFirmwareCfgHeader hdr;
|
FuSynapromFirmwareCfgHeader hdr;
|
||||||
g_autoptr(GBytes) blob = NULL;
|
g_autoptr(GBytes) blob = NULL;
|
||||||
g_autoptr(GPtrArray) firmware = NULL;
|
g_autoptr(FuFirmware) firmware = fu_synaprom_firmware_new ();
|
||||||
guint32 product;
|
guint32 product;
|
||||||
guint32 id1;
|
guint32 id1;
|
||||||
|
|
||||||
/* parse the firmware */
|
/* parse the firmware */
|
||||||
fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING);
|
fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING);
|
||||||
firmware = fu_synaprom_firmware_new (fw, error);
|
if (!fu_firmware_parse (firmware, fw, flags, error))
|
||||||
if (firmware == NULL)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* check the update header product and version */
|
/* check the update header product and version */
|
||||||
blob = fu_synaprom_firmware_get_bytes_by_tag (firmware,
|
blob = fu_firmware_get_image_by_id_bytes (firmware, "cfg-update-header", error);
|
||||||
FU_SYNAPROM_FIRMWARE_TAG_CFG_HEADER,
|
|
||||||
error);
|
|
||||||
if (blob == NULL)
|
if (blob == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (g_bytes_get_size (blob) != sizeof(hdr)) {
|
if (g_bytes_get_size (blob) != sizeof(hdr)) {
|
||||||
@ -178,19 +175,24 @@ fu_synaprom_config_prepare_firmware (FuDevice *device,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get payload */
|
/* success */
|
||||||
return fu_synaprom_firmware_get_bytes_by_tag (firmware,
|
return g_steal_pointer (&firmware);
|
||||||
FU_SYNAPROM_FIRMWARE_TAG_CFG_PAYLOAD,
|
|
||||||
error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fu_synaprom_config_write_firmware (FuDevice *device,
|
fu_synaprom_config_write_firmware (FuDevice *device,
|
||||||
GBytes *fw,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
FuSynapromConfig *self = FU_SYNAPROM_CONFIG (device);
|
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...*/
|
/* I assume the CFG/MFW difference is detected in the device...*/
|
||||||
return fu_synaprom_device_write_fw (self->device, fw, error);
|
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);
|
return fu_synaprom_device_cmd_send (device, request, reply, 20000, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
GBytes *
|
FuFirmware *
|
||||||
fu_synaprom_device_prepare_fw (FuDevice *device,
|
fu_synaprom_device_prepare_fw (FuDevice *device,
|
||||||
GBytes *fw,
|
GBytes *fw,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
@ -240,18 +240,15 @@ fu_synaprom_device_prepare_fw (FuDevice *device,
|
|||||||
FuSynapromFirmwareMfwHeader hdr;
|
FuSynapromFirmwareMfwHeader hdr;
|
||||||
guint32 product;
|
guint32 product;
|
||||||
g_autoptr(GBytes) blob = NULL;
|
g_autoptr(GBytes) blob = NULL;
|
||||||
g_autoptr(GPtrArray) firmware = NULL;
|
g_autoptr(FuFirmware) firmware = fu_synaprom_firmware_new ();
|
||||||
|
|
||||||
/* parse the firmware */
|
/* parse the firmware */
|
||||||
fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING);
|
fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING);
|
||||||
firmware = fu_synaprom_firmware_new (fw, error);
|
if (!fu_firmware_parse (firmware, fw, flags, error))
|
||||||
if (firmware == NULL)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* check the update header product and version */
|
/* check the update header product and version */
|
||||||
blob = fu_synaprom_firmware_get_bytes_by_tag (firmware,
|
blob = fu_firmware_get_image_by_id_bytes (firmware, "mfw-update-header", error);
|
||||||
FU_SYNAPROM_FIRMWARE_TAG_MFW_HEADER,
|
|
||||||
error);
|
|
||||||
if (blob == NULL)
|
if (blob == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (g_bytes_get_size (blob) != sizeof(hdr)) {
|
if (g_bytes_get_size (blob) != sizeof(hdr)) {
|
||||||
@ -296,10 +293,8 @@ fu_synaprom_device_prepare_fw (FuDevice *device,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get payload */
|
/* success */
|
||||||
return fu_synaprom_firmware_get_bytes_by_tag (firmware,
|
return g_steal_pointer (&firmware);
|
||||||
FU_SYNAPROM_FIRMWARE_TAG_MFW_PAYLOAD,
|
|
||||||
error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
@ -352,11 +347,18 @@ fu_synaprom_device_write_fw (FuSynapromDevice *self, GBytes *fw, GError **error)
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fu_synaprom_device_write_firmware (FuDevice *device,
|
fu_synaprom_device_write_firmware (FuDevice *device,
|
||||||
GBytes *fw,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
FuSynapromDevice *self = FU_SYNAPROM_DEVICE (device);
|
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);
|
return fu_synaprom_device_write_fw (self, fw, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ void fu_synaprom_device_set_version (FuSynapromDevice *self,
|
|||||||
guint8 vmajor,
|
guint8 vmajor,
|
||||||
guint8 vminor,
|
guint8 vminor,
|
||||||
guint32 buildnum);
|
guint32 buildnum);
|
||||||
GBytes *fu_synaprom_device_prepare_fw (FuDevice *device,
|
FuFirmware *fu_synaprom_device_prepare_fw (FuDevice *device,
|
||||||
GBytes *fw,
|
GBytes *fw,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
@ -11,27 +11,21 @@
|
|||||||
|
|
||||||
#include "fu-synaprom-firmware.h"
|
#include "fu-synaprom-firmware.h"
|
||||||
|
|
||||||
|
struct _FuSynapromFirmware {
|
||||||
|
FuFirmware parent_instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (FuSynapromFirmware, fu_synaprom_firmware, FU_TYPE_FIRMWARE)
|
||||||
|
|
||||||
typedef struct __attribute__((packed)) {
|
typedef struct __attribute__((packed)) {
|
||||||
guint16 tag;
|
guint16 tag;
|
||||||
guint32 bufsz;
|
guint32 bufsz;
|
||||||
} FuSynapromFirmwareHdr;
|
} FuSynapromFirmwareHdr;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
guint16 tag;
|
|
||||||
GBytes *bytes;
|
|
||||||
} FuSynapromFirmwareItem;
|
|
||||||
|
|
||||||
/* use only first 12 bit of 16 bits as tag value */
|
/* use only first 12 bit of 16 bits as tag value */
|
||||||
#define FU_SYNAPROM_FIRMWARE_TAG_MAX 0xfff0
|
#define FU_SYNAPROM_FIRMWARE_TAG_MAX 0xfff0
|
||||||
#define FU_SYNAPROM_FIRMWARE_SIGSIZE 0x0100
|
#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 *
|
static const gchar *
|
||||||
fu_synaprom_firmware_tag_to_string (guint16 tag)
|
fu_synaprom_firmware_tag_to_string (guint16 tag)
|
||||||
{
|
{
|
||||||
@ -46,18 +40,21 @@ fu_synaprom_firmware_tag_to_string (guint16 tag)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
GPtrArray *
|
static gboolean
|
||||||
fu_synaprom_firmware_new (GBytes *blob, GError **error)
|
fu_synaprom_firmware_parse (FuFirmware *firmware,
|
||||||
|
GBytes *fw,
|
||||||
|
guint64 addr_start,
|
||||||
|
guint64 addr_end,
|
||||||
|
FwupdInstallFlags flags,
|
||||||
|
GError **error)
|
||||||
{
|
{
|
||||||
const guint8 *buf;
|
const guint8 *buf;
|
||||||
gsize bufsz = 0;
|
gsize bufsz = 0;
|
||||||
gsize offset = 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 (fw, &bufsz);
|
||||||
buf = g_bytes_get_data (blob, &bufsz);
|
|
||||||
|
|
||||||
/* 256 byte signature as footer */
|
/* 256 byte signature as footer */
|
||||||
if (bufsz < FU_SYNAPROM_FIRMWARE_SIGSIZE + sizeof(FuSynapromFirmwareHdr)) {
|
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,
|
||||||
G_IO_ERROR_INVALID_DATA,
|
G_IO_ERROR_INVALID_DATA,
|
||||||
"blob is too small to be firmware");
|
"blob is too small to be firmware");
|
||||||
return NULL;
|
return FALSE;
|
||||||
}
|
}
|
||||||
bufsz -= FU_SYNAPROM_FIRMWARE_SIGSIZE;
|
bufsz -= FU_SYNAPROM_FIRMWARE_SIGSIZE;
|
||||||
|
|
||||||
@ -73,19 +70,20 @@ fu_synaprom_firmware_new (GBytes *blob, GError **error)
|
|||||||
while (offset != bufsz) {
|
while (offset != bufsz) {
|
||||||
FuSynapromFirmwareHdr header;
|
FuSynapromFirmwareHdr header;
|
||||||
guint32 hdrsz;
|
guint32 hdrsz;
|
||||||
g_autofree FuSynapromFirmwareItem *item = NULL;
|
guint32 tag;
|
||||||
|
g_autoptr(GBytes) bytes = NULL;
|
||||||
|
g_autoptr(FuFirmwareImage) img = NULL;
|
||||||
|
|
||||||
/* verify item header */
|
/* verify item header */
|
||||||
memcpy (&header, buf, sizeof(header));
|
memcpy (&header, buf, sizeof(header));
|
||||||
item = g_new0 (FuSynapromFirmwareItem, 1);
|
tag = GUINT16_FROM_LE(header.tag);
|
||||||
item->tag = GUINT16_FROM_LE(header.tag);
|
if (tag >= FU_SYNAPROM_FIRMWARE_TAG_MAX) {
|
||||||
if (item->tag >= FU_SYNAPROM_FIRMWARE_TAG_MAX) {
|
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
G_IO_ERROR,
|
G_IO_ERROR,
|
||||||
G_IO_ERROR_INVALID_DATA,
|
G_IO_ERROR_INVALID_DATA,
|
||||||
"tag 0x%04x is too large",
|
"tag 0x%04x is too large",
|
||||||
item->tag);
|
tag);
|
||||||
return NULL;
|
return FALSE;
|
||||||
}
|
}
|
||||||
hdrsz = GUINT32_FROM_LE(header.bufsz);
|
hdrsz = GUINT32_FROM_LE(header.bufsz);
|
||||||
offset += sizeof(header) + hdrsz;
|
offset += sizeof(header) + hdrsz;
|
||||||
@ -95,41 +93,29 @@ fu_synaprom_firmware_new (GBytes *blob, GError **error)
|
|||||||
G_IO_ERROR_INVALID_DATA,
|
G_IO_ERROR_INVALID_DATA,
|
||||||
"data is corrupted 0x%04x > 0x%04x",
|
"data is corrupted 0x%04x > 0x%04x",
|
||||||
(guint) offset, (guint) bufsz);
|
(guint) offset, (guint) bufsz);
|
||||||
return NULL;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* move pointer to data */
|
/* move pointer to data */
|
||||||
buf += sizeof(header);
|
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",
|
g_debug ("adding 0x%04x (%s) with size 0x%04x",
|
||||||
item->tag,
|
tag,
|
||||||
fu_synaprom_firmware_tag_to_string (item->tag),
|
fu_synaprom_firmware_tag_to_string (tag),
|
||||||
hdrsz);
|
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 */
|
/* next item */
|
||||||
buf += hdrsz;
|
buf += hdrsz;
|
||||||
}
|
}
|
||||||
return g_steal_pointer (&firmware);
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
GBytes *
|
static GBytes *
|
||||||
fu_synaprom_firmware_get_bytes_by_tag (GPtrArray *firmware, guint16 tag, GError **error)
|
fu_synaprom_firmware_write (FuFirmware *self, 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)
|
|
||||||
{
|
{
|
||||||
GByteArray *blob = g_byte_array_new ();
|
GByteArray *blob = g_byte_array_new ();
|
||||||
const guint8 data[] = { 'R', 'H' };
|
const guint8 data[] = { 'R', 'H' };
|
||||||
@ -163,3 +149,22 @@ fu_synaprom_firmware_generate (void)
|
|||||||
}
|
}
|
||||||
return g_byte_array_free_to_bytes (blob);
|
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
|
#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_HEADER 0x0001
|
||||||
#define FU_SYNAPROM_FIRMWARE_TAG_MFW_PAYLOAD 0x0002
|
#define FU_SYNAPROM_FIRMWARE_TAG_MFW_PAYLOAD 0x0002
|
||||||
@ -34,9 +39,6 @@ typedef struct __attribute__((packed)) {
|
|||||||
guint8 unused[2];
|
guint8 unused[2];
|
||||||
} FuSynapromFirmwareCfgHeader;
|
} FuSynapromFirmwareCfgHeader;
|
||||||
|
|
||||||
GPtrArray *fu_synaprom_firmware_new (GBytes *blob,
|
FuFirmware *fu_synaprom_firmware_new (void);
|
||||||
GError **error);
|
|
||||||
GBytes *fu_synaprom_firmware_get_bytes_by_tag (GPtrArray *firmware,
|
G_END_DECLS
|
||||||
guint16 tag,
|
|
||||||
GError **error);
|
|
||||||
GBytes *fu_synaprom_firmware_generate (void);
|
|
||||||
|
@ -66,10 +66,15 @@ if get_option('tests')
|
|||||||
],
|
],
|
||||||
include_directories : [
|
include_directories : [
|
||||||
include_directories('../..'),
|
include_directories('../..'),
|
||||||
|
include_directories('../../src'),
|
||||||
|
include_directories('../../libfwupd'),
|
||||||
],
|
],
|
||||||
dependencies : [
|
dependencies : [
|
||||||
gio,
|
gio,
|
||||||
],
|
],
|
||||||
|
link_with : [
|
||||||
|
libfwupdprivate,
|
||||||
|
],
|
||||||
c_args : cargs
|
c_args : cargs
|
||||||
)
|
)
|
||||||
endif
|
endif
|
||||||
|
@ -401,7 +401,7 @@ fu_uefi_device_write_update_info (FuUefiDevice *self,
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fu_uefi_device_write_firmware (FuDevice *device,
|
fu_uefi_device_write_firmware (FuDevice *device,
|
||||||
GBytes *fw,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags install_flags,
|
FwupdInstallFlags install_flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
@ -411,6 +411,7 @@ fu_uefi_device_write_firmware (FuDevice *device,
|
|||||||
const gchar *esp_path = fu_device_get_metadata (device, "EspPath");
|
const gchar *esp_path = fu_device_get_metadata (device, "EspPath");
|
||||||
efi_guid_t guid;
|
efi_guid_t guid;
|
||||||
g_autoptr(GBytes) fixed_fw = NULL;
|
g_autoptr(GBytes) fixed_fw = NULL;
|
||||||
|
g_autoptr(GBytes) fw = NULL;
|
||||||
g_autofree gchar *basename = NULL;
|
g_autofree gchar *basename = NULL;
|
||||||
g_autofree gchar *directory = NULL;
|
g_autofree gchar *directory = NULL;
|
||||||
g_autofree gchar *fn = NULL;
|
g_autofree gchar *fn = NULL;
|
||||||
@ -425,6 +426,11 @@ fu_uefi_device_write_firmware (FuDevice *device,
|
|||||||
return FALSE;
|
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 */
|
/* save the blob to the ESP */
|
||||||
directory = fu_uefi_get_esp_path_for_os (esp_path);
|
directory = fu_uefi_get_esp_path_for_os (esp_path);
|
||||||
basename = g_strdup_printf ("fwupd-%s.cap", self->fw_class);
|
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
|
static gboolean
|
||||||
fu_unifying_bootloader_nordic_write_firmware (FuDevice *device,
|
fu_unifying_bootloader_nordic_write_firmware (FuDevice *device,
|
||||||
GBytes *fw,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
FuUnifyingBootloader *self = FU_UNIFYING_BOOTLOADER (device);
|
FuUnifyingBootloader *self = FU_UNIFYING_BOOTLOADER (device);
|
||||||
const FuUnifyingBootloaderRequest *payload;
|
const FuUnifyingBootloaderRequest *payload;
|
||||||
guint16 addr;
|
guint16 addr;
|
||||||
|
g_autoptr(GBytes) fw = NULL;
|
||||||
g_autoptr(GPtrArray) reqs = 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 */
|
/* erase firmware pages up to the bootloader */
|
||||||
fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE);
|
fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE);
|
||||||
for (addr = fu_unifying_bootloader_get_addr_lo (self);
|
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
|
static gboolean
|
||||||
fu_unifying_bootloader_texas_write_firmware (FuDevice *device,
|
fu_unifying_bootloader_texas_write_firmware (FuDevice *device,
|
||||||
GBytes *fw,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
FuUnifyingBootloader *self = FU_UNIFYING_BOOTLOADER (device);
|
FuUnifyingBootloader *self = FU_UNIFYING_BOOTLOADER (device);
|
||||||
const FuUnifyingBootloaderRequest *payload;
|
const FuUnifyingBootloaderRequest *payload;
|
||||||
|
g_autoptr(GBytes) fw = NULL;
|
||||||
g_autoptr(GPtrArray) reqs = NULL;
|
g_autoptr(GPtrArray) reqs = NULL;
|
||||||
g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new ();
|
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 */
|
/* transfer payload */
|
||||||
reqs = fu_unifying_bootloader_parse_requests (self, fw, error);
|
reqs = fu_unifying_bootloader_parse_requests (self, fw, error);
|
||||||
if (reqs == NULL)
|
if (reqs == NULL)
|
||||||
|
@ -882,7 +882,7 @@ fu_unifying_peripheral_write_firmware_pkt (FuUnifyingPeripheral *self,
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fu_unifying_peripheral_write_firmware (FuDevice *device,
|
fu_unifying_peripheral_write_firmware (FuDevice *device,
|
||||||
GBytes *fw,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
@ -891,6 +891,7 @@ fu_unifying_peripheral_write_firmware (FuDevice *device,
|
|||||||
const guint8 *data;
|
const guint8 *data;
|
||||||
guint8 cmd = 0x04;
|
guint8 cmd = 0x04;
|
||||||
guint8 idx;
|
guint8 idx;
|
||||||
|
g_autoptr(GBytes) fw = NULL;
|
||||||
|
|
||||||
/* if we're in bootloader mode, we should be able to get this feature */
|
/* 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);
|
idx = fu_unifying_peripheral_feature_get_idx (self, HIDPP_FEATURE_DFU);
|
||||||
@ -902,6 +903,11 @@ fu_unifying_peripheral_write_firmware (FuDevice *device,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* get default image */
|
||||||
|
fw = fu_firmware_get_image_default_bytes (firmware, error);
|
||||||
|
if (fw == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
/* flash hardware */
|
/* flash hardware */
|
||||||
data = g_bytes_get_data (fw, &sz);
|
data = g_bytes_get_data (fw, &sz);
|
||||||
fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE);
|
fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE);
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
#include <glib/gstdio.h>
|
#include <glib/gstdio.h>
|
||||||
|
|
||||||
#include "fu-chunk.h"
|
#include "fu-chunk.h"
|
||||||
|
#include "fu-ihex-firmware.h"
|
||||||
#include "fu-wacom-common.h"
|
#include "fu-wacom-common.h"
|
||||||
#include "fu-wacom-device.h"
|
#include "fu-wacom-device.h"
|
||||||
#include "dfu-firmware.h"
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@ -216,69 +216,56 @@ fu_wacom_device_set_version_bootloader (FuWacomDevice *self, GError **error)
|
|||||||
return TRUE;
|
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
|
static gboolean
|
||||||
fu_wacom_device_write_firmware (FuDevice *device,
|
fu_wacom_device_write_firmware (FuDevice *device,
|
||||||
GBytes *fw,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
FuWacomDevice *self = FU_WACOM_DEVICE (device);
|
FuWacomDevice *self = FU_WACOM_DEVICE (device);
|
||||||
FuWacomDevicePrivate *priv = GET_PRIVATE (self);
|
FuWacomDevicePrivate *priv = GET_PRIVATE (self);
|
||||||
FuWacomDeviceClass *klass = FU_WACOM_DEVICE_GET_CLASS (device);
|
FuWacomDeviceClass *klass = FU_WACOM_DEVICE_GET_CLASS (device);
|
||||||
DfuElement *element;
|
g_autoptr(FuFirmwareImage) img = NULL;
|
||||||
DfuImage *image;
|
g_autoptr(GBytes) fw = NULL;
|
||||||
GBytes *fw_new;
|
|
||||||
g_autoptr(DfuFirmware) firmware = dfu_firmware_new ();
|
|
||||||
g_autoptr(GPtrArray) chunks = 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 */
|
/* use the correct image from the firmware */
|
||||||
image = dfu_firmware_get_image_default (firmware);
|
img = fu_firmware_get_image_default (firmware, error);
|
||||||
if (image == NULL) {
|
if (img == NULL)
|
||||||
g_set_error_literal (error,
|
|
||||||
FWUPD_ERROR,
|
|
||||||
FWUPD_ERROR_INTERNAL,
|
|
||||||
"no firmware image");
|
|
||||||
return FALSE;
|
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",
|
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 */
|
/* 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_set_error (error,
|
||||||
G_IO_ERROR,
|
G_IO_ERROR,
|
||||||
G_IO_ERROR_FAILED,
|
G_IO_ERROR_FAILED,
|
||||||
"base addr invalid: 0x%05x",
|
"base addr invalid: 0x%05x",
|
||||||
(guint) dfu_element_get_address (element));
|
(guint) fu_firmware_image_get_addr (img));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
fw_new = dfu_element_get_contents (element);
|
fw = fu_firmware_image_get_bytes (img, error);
|
||||||
if (g_bytes_get_size (fw_new) > priv->flash_size) {
|
if (fw == NULL)
|
||||||
|
return FALSE;
|
||||||
|
if (g_bytes_get_size (fw) > priv->flash_size) {
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
G_IO_ERROR,
|
G_IO_ERROR,
|
||||||
G_IO_ERROR_FAILED,
|
G_IO_ERROR_FAILED,
|
||||||
"size is invalid: 0x%05x",
|
"size is invalid: 0x%05x",
|
||||||
(guint) g_bytes_get_size (fw_new));
|
(guint) g_bytes_get_size (fw));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,7 +276,7 @@ fu_wacom_device_write_firmware (FuDevice *device,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* flash chunks */
|
/* 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 */
|
0x00, /* page_sz */
|
||||||
priv->flash_block_size);
|
priv->flash_block_size);
|
||||||
return klass->write_firmware (device, chunks, error);
|
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->to_string = fu_wacom_device_to_string;
|
||||||
klass_device->open = fu_wacom_device_open;
|
klass_device->open = fu_wacom_device_open;
|
||||||
klass_device->close = fu_wacom_device_close;
|
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->write_firmware = fu_wacom_device_write_firmware;
|
||||||
klass_device->attach = fu_wacom_device_attach;
|
klass_device->attach = fu_wacom_device_attach;
|
||||||
klass_device->detach = fu_wacom_device_detach;
|
klass_device->detach = fu_wacom_device_detach;
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#include "fu-wacom-common.h"
|
#include "fu-wacom-common.h"
|
||||||
#include "fu-udev-device.h"
|
#include "fu-udev-device.h"
|
||||||
#include "dfu-element.h"
|
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@ shared_module('fu_plugin_wacom_raw',
|
|||||||
],
|
],
|
||||||
include_directories : [
|
include_directories : [
|
||||||
include_directories('../..'),
|
include_directories('../..'),
|
||||||
include_directories('../dfu'),
|
|
||||||
include_directories('../../src'),
|
include_directories('../../src'),
|
||||||
include_directories('../../libfwupd'),
|
include_directories('../../libfwupd'),
|
||||||
],
|
],
|
||||||
@ -26,6 +25,6 @@ shared_module('fu_plugin_wacom_raw',
|
|||||||
plugin_deps,
|
plugin_deps,
|
||||||
],
|
],
|
||||||
link_with : [
|
link_with : [
|
||||||
dfu,
|
libfwupdprivate,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -19,11 +19,10 @@
|
|||||||
static void
|
static void
|
||||||
fu_wac_firmware_parse_func (void)
|
fu_wac_firmware_parse_func (void)
|
||||||
{
|
{
|
||||||
DfuElement *element;
|
|
||||||
DfuImage *image;
|
|
||||||
gboolean ret;
|
gboolean ret;
|
||||||
g_autofree gchar *fn = NULL;
|
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) blob_block = NULL;
|
||||||
g_autoptr(GBytes) bytes = NULL;
|
g_autoptr(GBytes) bytes = NULL;
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
@ -37,20 +36,17 @@ fu_wac_firmware_parse_func (void)
|
|||||||
bytes = fu_common_get_contents_bytes (fn, &error);
|
bytes = fu_common_get_contents_bytes (fn, &error);
|
||||||
g_assert_no_error (error);
|
g_assert_no_error (error);
|
||||||
g_assert_nonnull (bytes);
|
g_assert_nonnull (bytes);
|
||||||
ret = fu_wac_firmware_parse_data (firmware, bytes,
|
ret = fu_firmware_parse (firmware, bytes, FWUPD_INSTALL_FLAG_NONE, &error);
|
||||||
DFU_FIRMWARE_PARSE_FLAG_NONE, &error);
|
|
||||||
g_assert_no_error (error);
|
g_assert_no_error (error);
|
||||||
g_assert_true (ret);
|
g_assert_true (ret);
|
||||||
|
|
||||||
/* get image data */
|
/* get image data */
|
||||||
image = dfu_firmware_get_image (firmware, 0);
|
img = fu_firmware_get_image_default (firmware, &error);
|
||||||
g_assert_nonnull (image);
|
g_assert_no_error (error);
|
||||||
element = dfu_image_get_element_default (image);
|
g_assert_nonnull (img);
|
||||||
g_assert_nonnull (element);
|
|
||||||
|
|
||||||
/* get block */
|
/* get block */
|
||||||
blob_block = dfu_element_get_contents_chunk (element, 0x8008000,
|
blob_block = fu_firmware_image_get_bytes_chunk (img, 0x8008000, 1024, &error);
|
||||||
1024, &error);
|
|
||||||
g_assert_no_error (error);
|
g_assert_no_error (error);
|
||||||
g_assert_nonnull (blob_block);
|
g_assert_nonnull (blob_block);
|
||||||
fu_wac_buffer_dump ("IMG", FU_WAC_REPORT_ID_MODULE,
|
fu_wac_buffer_dump ("IMG", FU_WAC_REPORT_ID_MODULE,
|
||||||
|
@ -15,9 +15,6 @@
|
|||||||
#include "fu-wac-module-bluetooth.h"
|
#include "fu-wac-module-bluetooth.h"
|
||||||
#include "fu-wac-module-touch.h"
|
#include "fu-wac-module-touch.h"
|
||||||
|
|
||||||
#include "dfu-common.h"
|
|
||||||
#include "dfu-firmware.h"
|
|
||||||
|
|
||||||
typedef struct __attribute__((packed)) {
|
typedef struct __attribute__((packed)) {
|
||||||
guint32 start_addr;
|
guint32 start_addr;
|
||||||
guint32 block_sz;
|
guint32 block_sz;
|
||||||
@ -481,34 +478,37 @@ fu_wac_device_switch_to_flash_loader (FuWacDevice *self, GError **error)
|
|||||||
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
|
static gboolean
|
||||||
fu_wac_device_write_firmware (FuDevice *device,
|
fu_wac_device_write_firmware (FuDevice *device,
|
||||||
GBytes *blob,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
DfuElement *element;
|
|
||||||
DfuImage *image;
|
|
||||||
FuWacDevice *self = FU_WAC_DEVICE (device);
|
FuWacDevice *self = FU_WAC_DEVICE (device);
|
||||||
gsize blocks_done = 0;
|
gsize blocks_done = 0;
|
||||||
gsize blocks_total = 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_autofree guint32 *csum_local = NULL;
|
||||||
|
g_autoptr(FuFirmwareImage) img = NULL;
|
||||||
|
g_autoptr(GHashTable) fd_blobs = NULL;
|
||||||
|
|
||||||
/* load .wac file, including metadata */
|
/* use the correct image from the firmware */
|
||||||
if (!fu_wac_firmware_parse_data (firmware, blob,
|
img = fu_firmware_get_image_by_idx (firmware, self->firmware_index == 1 ? 1 : 0, error);
|
||||||
DFU_FIRMWARE_PARSE_FLAG_NONE,
|
if (img == NULL)
|
||||||
error))
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
if (dfu_firmware_get_format (firmware) != DFU_FIRMWARE_FORMAT_SREC) {
|
g_debug ("using image at addr 0x%0x", (guint) fu_firmware_image_get_addr (img));
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* enter flash mode */
|
/* enter flash mode */
|
||||||
if (!fu_wac_device_switch_to_flash_loader (self, error))
|
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))
|
if (!fu_wac_device_ensure_firmware_index (self, error))
|
||||||
return FALSE;
|
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) */
|
/* get firmware parameters (page sz and transfer sz) */
|
||||||
if (!fu_wac_device_ensure_parameters (self, error))
|
if (!fu_wac_device_ensure_parameters (self, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -572,13 +550,13 @@ fu_wac_device_write_firmware (FuDevice *device,
|
|||||||
|
|
||||||
if (fu_wav_device_flash_descriptor_is_wp (fd))
|
if (fu_wav_device_flash_descriptor_is_wp (fd))
|
||||||
continue;
|
continue;
|
||||||
blob_tmp = dfu_element_get_contents_chunk (element,
|
blob_tmp = fu_firmware_image_get_bytes_chunk (img,
|
||||||
fd->start_addr,
|
fd->start_addr,
|
||||||
fd->block_sz,
|
fd->block_sz,
|
||||||
NULL);
|
NULL);
|
||||||
if (blob_tmp == NULL)
|
if (blob_tmp == NULL)
|
||||||
break;
|
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);
|
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);
|
FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
|
||||||
FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass);
|
FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass);
|
||||||
object_class->finalize = fu_wac_device_finalize;
|
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->write_firmware = fu_wac_device_write_firmware;
|
||||||
klass_device->to_string = fu_wac_device_to_string;
|
klass_device->to_string = fu_wac_device_to_string;
|
||||||
klass_device->setup = fu_wac_device_setup;
|
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+
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
*/
|
*/
|
||||||
@ -8,47 +8,42 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "dfu-element.h"
|
#include "fu-common.h"
|
||||||
#include "dfu-format-srec.h"
|
#include "fu-srec-firmware.h"
|
||||||
#include "dfu-image.h"
|
#include "fu-firmware-common.h"
|
||||||
|
|
||||||
#include "fu-wac-firmware.h"
|
#include "fu-wac-firmware.h"
|
||||||
|
|
||||||
#include "fwupd-error.h"
|
#include "fwupd-error.h"
|
||||||
|
|
||||||
|
struct _FuWacFirmware {
|
||||||
|
FuFirmware parent_instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (FuWacFirmware, fu_wac_firmware, FU_TYPE_FIRMWARE)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
guint32 addr;
|
guint32 addr;
|
||||||
guint32 sz;
|
guint32 sz;
|
||||||
guint32 prog_start_addr;
|
guint32 prog_start_addr;
|
||||||
} DfuFirmwareWacHeaderRecord;
|
} FuFirmwareWacHeaderRecord;
|
||||||
|
|
||||||
/**
|
static gboolean
|
||||||
* fu_wac_firmware_parse_data:
|
fu_wac_firmware_parse (FuFirmware *firmware,
|
||||||
* @firmware: a #DfuFirmware
|
GBytes *fw,
|
||||||
* @bytes: data to parse
|
guint64 addr_start,
|
||||||
* @flags: some #DfuFirmwareParseFlags
|
guint64 addr_end,
|
||||||
* @error: a #GError, or %NULL
|
FwupdInstallFlags flags,
|
||||||
*
|
GError **error)
|
||||||
* 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)
|
|
||||||
{
|
{
|
||||||
gsize len;
|
gsize len;
|
||||||
guint8 *data;
|
guint8 *data;
|
||||||
g_auto(GStrv) lines = NULL;
|
|
||||||
g_autoptr(GString) image_buffer = NULL;
|
|
||||||
g_autofree gchar *data_str = NULL;
|
|
||||||
guint8 images_cnt = 0;
|
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(GPtrArray) header_infos = g_ptr_array_new_with_free_func (g_free);
|
||||||
|
g_autoptr(GString) image_buffer = NULL;
|
||||||
|
|
||||||
/* check the prefix (BE) */
|
/* 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) {
|
if (memcmp (data, "WACOM", 5) != 0) {
|
||||||
g_set_error_literal (error,
|
g_set_error_literal (error,
|
||||||
FWUPD_ERROR,
|
FWUPD_ERROR,
|
||||||
@ -58,8 +53,7 @@ fu_wac_firmware_parse_data (DfuFirmware *firmware,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* parse each line */
|
/* parse each line */
|
||||||
data_str = g_strndup ((const gchar *) data, len);
|
lines = fu_common_strnsplit ((const gchar *) data, len, "\n", -1);
|
||||||
lines = g_strsplit (data_str, "\n", -1);
|
|
||||||
for (guint i = 0; lines[i] != NULL; i++) {
|
for (guint i = 0; lines[i] != NULL; i++) {
|
||||||
g_autofree gchar *cmd = g_strndup (lines[i], 2);
|
g_autofree gchar *cmd = g_strndup (lines[i], 2);
|
||||||
|
|
||||||
@ -81,11 +75,11 @@ fu_wac_firmware_parse_data (DfuFirmware *firmware,
|
|||||||
cmdlen);
|
cmdlen);
|
||||||
return FALSE;
|
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++) {
|
for (guint j = 0; j < header_image_cnt; j++) {
|
||||||
DfuFirmwareWacHeaderRecord *hdr = g_new0 (DfuFirmwareWacHeaderRecord, 1);
|
FuFirmwareWacHeaderRecord *hdr = g_new0 (FuFirmwareWacHeaderRecord, 1);
|
||||||
hdr->addr = dfu_utils_buffer_parse_uint32 (lines[i] + (j * 16) + 6);
|
hdr->addr = fu_firmware_strparse_uint32 (lines[i] + (j * 16) + 6);
|
||||||
hdr->sz = dfu_utils_buffer_parse_uint32 (lines[i] + (j * 16) + 14);
|
hdr->sz = fu_firmware_strparse_uint32 (lines[i] + (j * 16) + 14);
|
||||||
g_ptr_array_add (header_infos, hdr);
|
g_ptr_array_add (header_infos, hdr);
|
||||||
g_debug ("header_fw%u_addr: 0x%x", j, hdr->addr);
|
g_debug ("header_fw%u_addr: 0x%x", j, hdr->addr);
|
||||||
g_debug ("header_fw%u_sz: 0x%x", j, hdr->sz);
|
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 */
|
/* firmware headline record */
|
||||||
if (cmdlen == 13) {
|
if (cmdlen == 13) {
|
||||||
DfuFirmwareWacHeaderRecord *hdr;
|
FuFirmwareWacHeaderRecord *hdr;
|
||||||
guint8 idx = dfu_utils_buffer_parse_uint4 (lines[i] + 2);
|
guint8 idx = fu_firmware_strparse_uint4 (lines[i] + 2);
|
||||||
if (idx == 0) {
|
if (idx == 0) {
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
FWUPD_ERROR,
|
FWUPD_ERROR,
|
||||||
@ -114,7 +108,7 @@ fu_wac_firmware_parse_data (DfuFirmware *firmware,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
hdr = g_ptr_array_index (header_infos, idx - 1);
|
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) {
|
if (hdr->prog_start_addr != hdr->addr) {
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
FWUPD_ERROR,
|
FWUPD_ERROR,
|
||||||
@ -168,8 +162,9 @@ fu_wac_firmware_parse_data (DfuFirmware *firmware,
|
|||||||
/* end */
|
/* end */
|
||||||
if (g_strcmp0 (cmd, "S7") == 0) {
|
if (g_strcmp0 (cmd, "S7") == 0) {
|
||||||
g_autoptr(GBytes) blob = NULL;
|
g_autoptr(GBytes) blob = NULL;
|
||||||
g_autoptr(DfuImage) image = dfu_image_new ();
|
g_autoptr(FuFirmware) firmware_srec = fu_srec_firmware_new ();
|
||||||
DfuFirmwareWacHeaderRecord *hdr;
|
g_autoptr(FuFirmwareImage) img = NULL;
|
||||||
|
FuFirmwareWacHeaderRecord *hdr;
|
||||||
|
|
||||||
/* get the correct relocated start address */
|
/* get the correct relocated start address */
|
||||||
if (images_cnt >= header_infos->len) {
|
if (images_cnt >= header_infos->len) {
|
||||||
@ -191,12 +186,13 @@ fu_wac_firmware_parse_data (DfuFirmware *firmware,
|
|||||||
|
|
||||||
/* parse SREC file and add as image */
|
/* parse SREC file and add as image */
|
||||||
blob = g_bytes_new (image_buffer->str, image_buffer->len);
|
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;
|
return FALSE;
|
||||||
|
img = fu_firmware_get_image_default (firmware_srec, error);
|
||||||
/* the alt-setting is used for the firmware index */
|
if (img == NULL)
|
||||||
dfu_image_set_alt_setting (image, images_cnt);
|
return FALSE;
|
||||||
dfu_firmware_add_image (firmware, image);
|
fu_firmware_image_set_idx (img, images_cnt);
|
||||||
|
fu_firmware_add_image (firmware, img);
|
||||||
images_cnt++;
|
images_cnt++;
|
||||||
|
|
||||||
/* clear the image buffer */
|
/* clear the image buffer */
|
||||||
@ -226,6 +222,23 @@ fu_wac_firmware_parse_data (DfuFirmware *firmware,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* success */
|
/* success */
|
||||||
dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_SREC);
|
|
||||||
return TRUE;
|
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+
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <gio/gio.h>
|
#include "fu-firmware.h"
|
||||||
|
|
||||||
#include "dfu-firmware.h"
|
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
gboolean fu_wac_firmware_parse_data (DfuFirmware *firmware,
|
#define FU_TYPE_WAC_FIRMWARE (fu_wac_firmware_get_type ())
|
||||||
GBytes *bytes,
|
G_DECLARE_FINAL_TYPE (FuWacFirmware, fu_wac_firmware, FU, WAC_FIRMWARE, FuFirmware)
|
||||||
DfuFirmwareParseFlags flags,
|
|
||||||
GError **error);
|
FuFirmware *fu_wac_firmware_new (void);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
@ -106,7 +106,7 @@ fu_wac_module_bluetooth_parse_blocks (const guint8 *data, gsize sz, gboolean ski
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fu_wac_module_bluetooth_write_firmware (FuDevice *device,
|
fu_wac_module_bluetooth_write_firmware (FuDevice *device,
|
||||||
GBytes *blob,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
@ -117,9 +117,15 @@ fu_wac_module_bluetooth_write_firmware (FuDevice *device,
|
|||||||
const guint8 buf_start[] = { 0x00 };
|
const guint8 buf_start[] = { 0x00 };
|
||||||
g_autoptr(GPtrArray) blocks = NULL;
|
g_autoptr(GPtrArray) blocks = NULL;
|
||||||
g_autoptr(GBytes) blob_start = g_bytes_new_static (buf_start, 1);
|
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 */
|
/* 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 = fu_wac_module_bluetooth_parse_blocks (data, len, TRUE);
|
||||||
blocks_total = blocks->len + 2;
|
blocks_total = blocks->len + 2;
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
#include "fu-wac-module-touch.h"
|
#include "fu-wac-module-touch.h"
|
||||||
|
|
||||||
#include "fu-chunk.h"
|
#include "fu-chunk.h"
|
||||||
#include "dfu-firmware.h"
|
#include "fu-ihex-firmware.h"
|
||||||
|
|
||||||
struct _FuWacModuleTouch
|
struct _FuWacModuleTouch
|
||||||
{
|
{
|
||||||
@ -21,57 +21,43 @@ struct _FuWacModuleTouch
|
|||||||
|
|
||||||
G_DEFINE_TYPE (FuWacModuleTouch, fu_wac_module_touch, FU_TYPE_WAC_MODULE)
|
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
|
static gboolean
|
||||||
fu_wac_module_touch_write_firmware (FuDevice *device,
|
fu_wac_module_touch_write_firmware (FuDevice *device,
|
||||||
GBytes *blob,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
DfuElement *element;
|
|
||||||
DfuImage *image;
|
|
||||||
FuWacModule *self = FU_WAC_MODULE (device);
|
FuWacModule *self = FU_WAC_MODULE (device);
|
||||||
gsize blocks_total = 0;
|
gsize blocks_total = 0;
|
||||||
|
g_autoptr(FuFirmwareImage) img = NULL;
|
||||||
|
g_autoptr(GBytes) fw = NULL;
|
||||||
g_autoptr(GPtrArray) chunks = 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 */
|
/* use the correct image from the firmware */
|
||||||
image = dfu_firmware_get_image (firmware, 0);
|
img = fu_firmware_get_image_default (firmware, error);
|
||||||
if (image == NULL) {
|
if (img == NULL)
|
||||||
g_set_error_literal (error,
|
|
||||||
FWUPD_ERROR,
|
|
||||||
FWUPD_ERROR_INTERNAL,
|
|
||||||
"no firmware image");
|
|
||||||
return FALSE;
|
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",
|
g_debug ("using element at addr 0x%0x",
|
||||||
(guint) dfu_element_get_address (element));
|
(guint) fu_firmware_image_get_addr (img));
|
||||||
blob = dfu_element_get_contents (element);
|
fw = fu_firmware_image_get_bytes (img, error);
|
||||||
|
if (fw == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
/* build each data packet */
|
/* build each data packet */
|
||||||
chunks = fu_chunk_array_new_from_bytes (blob,
|
chunks = fu_chunk_array_new_from_bytes (fw,
|
||||||
dfu_element_get_address (element),
|
fu_firmware_image_get_addr (img),
|
||||||
0x0, /* page_sz */
|
0x0, /* page_sz */
|
||||||
128); /* packet_sz */
|
128); /* packet_sz */
|
||||||
blocks_total = chunks->len + 2;
|
blocks_total = chunks->len + 2;
|
||||||
@ -129,6 +115,7 @@ static void
|
|||||||
fu_wac_module_touch_class_init (FuWacModuleTouchClass *klass)
|
fu_wac_module_touch_class_init (FuWacModuleTouchClass *klass)
|
||||||
{
|
{
|
||||||
FuDeviceClass *klass_device = FU_DEVICE_CLASS (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;
|
klass_device->write_firmware = fu_wac_module_touch_write_firmware;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,9 +12,6 @@
|
|||||||
#include "fu-wac-common.h"
|
#include "fu-wac-common.h"
|
||||||
#include "fu-wac-device.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_OK 0
|
||||||
#define FU_WAC_MODULE_STATUS_BUSY 1
|
#define FU_WAC_MODULE_STATUS_BUSY 1
|
||||||
#define FU_WAC_MODULE_STATUS_ERR_CRC 2
|
#define FU_WAC_MODULE_STATUS_ERR_CRC 2
|
||||||
|
@ -17,7 +17,6 @@ shared_module('fu_plugin_wacom_usb',
|
|||||||
],
|
],
|
||||||
include_directories : [
|
include_directories : [
|
||||||
include_directories('../..'),
|
include_directories('../..'),
|
||||||
include_directories('../dfu'),
|
|
||||||
include_directories('../../src'),
|
include_directories('../../src'),
|
||||||
include_directories('../../libfwupd'),
|
include_directories('../../libfwupd'),
|
||||||
],
|
],
|
||||||
@ -29,7 +28,6 @@ shared_module('fu_plugin_wacom_usb',
|
|||||||
],
|
],
|
||||||
link_with : [
|
link_with : [
|
||||||
libfwupdprivate,
|
libfwupdprivate,
|
||||||
dfu,
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -46,7 +44,6 @@ if get_option('tests')
|
|||||||
],
|
],
|
||||||
include_directories : [
|
include_directories : [
|
||||||
include_directories('..'),
|
include_directories('..'),
|
||||||
include_directories('../dfu'),
|
|
||||||
include_directories('../..'),
|
include_directories('../..'),
|
||||||
include_directories('../../libfwupd'),
|
include_directories('../../libfwupd'),
|
||||||
include_directories('../../src'),
|
include_directories('../../src'),
|
||||||
@ -59,7 +56,6 @@ if get_option('tests')
|
|||||||
libm,
|
libm,
|
||||||
],
|
],
|
||||||
link_with : [
|
link_with : [
|
||||||
dfu,
|
|
||||||
libfwupdprivate,
|
libfwupdprivate,
|
||||||
],
|
],
|
||||||
c_args : cargs
|
c_args : cargs
|
||||||
|
@ -1333,6 +1333,36 @@ fu_common_bytes_compare (GBytes *bytes1, GBytes *bytes2, GError **error)
|
|||||||
return TRUE;
|
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:
|
* fu_common_realpath:
|
||||||
* @filename: a filename
|
* @filename: a filename
|
||||||
@ -1359,3 +1389,27 @@ fu_common_realpath (const gchar *filename, GError **error)
|
|||||||
}
|
}
|
||||||
return g_strdup (full_tmp);
|
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,
|
gboolean fu_common_bytes_compare (GBytes *bytes1,
|
||||||
GBytes *bytes2,
|
GBytes *bytes2,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
GBytes *fu_common_bytes_pad (GBytes *bytes,
|
||||||
|
gsize sz);
|
||||||
|
|
||||||
typedef guint FuEndianType;
|
typedef guint FuEndianType;
|
||||||
|
|
||||||
@ -150,5 +152,9 @@ guint32 fu_common_read_uint32 (const guint8 *buf,
|
|||||||
guint fu_common_string_replace (GString *string,
|
guint fu_common_string_replace (GString *string,
|
||||||
const gchar *search,
|
const gchar *search,
|
||||||
const gchar *replace);
|
const gchar *replace);
|
||||||
|
gchar **fu_common_strnsplit (const gchar *str,
|
||||||
|
gsize sz,
|
||||||
|
const gchar *delimiter,
|
||||||
|
gint max_tokens);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
@ -1754,7 +1754,7 @@ fu_device_write_firmware (FuDevice *self,
|
|||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self);
|
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 (FU_IS_DEVICE (self), FALSE);
|
||||||
g_return_val_if_fail (error == NULL || *error == NULL, 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 */
|
/* prepare (e.g. decompress) firmware */
|
||||||
fw_new = fu_device_prepare_firmware (self, fw, flags, error);
|
firmware = fu_device_prepare_firmware (self, fw, flags, error);
|
||||||
if (fw_new == NULL)
|
if (firmware == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* call vfunc */
|
/* 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
|
* Since: 1.1.2
|
||||||
**/
|
**/
|
||||||
GBytes *
|
FuFirmware *
|
||||||
fu_device_prepare_firmware (FuDevice *self,
|
fu_device_prepare_firmware (FuDevice *self,
|
||||||
GBytes *fw,
|
GBytes *fw,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
@ -1804,8 +1804,8 @@ fu_device_prepare_firmware (FuDevice *self,
|
|||||||
{
|
{
|
||||||
FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self);
|
FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self);
|
||||||
FuDevicePrivate *priv = GET_PRIVATE (self);
|
FuDevicePrivate *priv = GET_PRIVATE (self);
|
||||||
guint64 fw_sz;
|
g_autoptr(FuFirmware) firmware = NULL;
|
||||||
g_autoptr(GBytes) fw_new = NULL;
|
g_autoptr(GBytes) fw_def = NULL;
|
||||||
|
|
||||||
g_return_val_if_fail (FU_IS_DEVICE (self), NULL);
|
g_return_val_if_fail (FU_IS_DEVICE (self), NULL);
|
||||||
g_return_val_if_fail (fw != NULL, NULL);
|
g_return_val_if_fail (fw != NULL, NULL);
|
||||||
@ -1813,37 +1813,41 @@ fu_device_prepare_firmware (FuDevice *self,
|
|||||||
|
|
||||||
/* optionally subclassed */
|
/* optionally subclassed */
|
||||||
if (klass->prepare_firmware != NULL) {
|
if (klass->prepare_firmware != NULL) {
|
||||||
fw_new = klass->prepare_firmware (self, fw, flags, error);
|
firmware = klass->prepare_firmware (self, fw, flags, error);
|
||||||
if (fw_new == NULL)
|
if (firmware == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
fw_new = g_bytes_ref (fw);
|
firmware = fu_firmware_new_from_bytes (fw);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check size */
|
/* check size */
|
||||||
fw_sz = (guint64) g_bytes_get_size (fw_new);
|
fw_def = fu_firmware_get_image_default_bytes (firmware, NULL);
|
||||||
if (priv->size_max > 0 && fw_sz > priv->size_max) {
|
if (fw_def != NULL) {
|
||||||
g_set_error (error,
|
guint64 fw_sz = (guint64) g_bytes_get_size (fw_def);
|
||||||
FWUPD_ERROR,
|
if (priv->size_max > 0 && fw_sz > priv->size_max) {
|
||||||
FWUPD_ERROR_INVALID_FILE,
|
g_set_error (error,
|
||||||
"firmware is %04x bytes larger than the allowed "
|
FWUPD_ERROR,
|
||||||
"maximum size of %04x bytes",
|
FWUPD_ERROR_INVALID_FILE,
|
||||||
(guint) (fw_sz - priv->size_max),
|
"firmware is %04x bytes larger than the allowed "
|
||||||
(guint) priv->size_max);
|
"maximum size of %04x bytes",
|
||||||
return NULL;
|
(guint) (fw_sz - priv->size_max),
|
||||||
}
|
(guint) priv->size_max);
|
||||||
if (priv->size_min > 0 && fw_sz < priv->size_min) {
|
return NULL;
|
||||||
g_set_error (error,
|
}
|
||||||
FWUPD_ERROR,
|
if (priv->size_min > 0 && fw_sz < priv->size_min) {
|
||||||
FWUPD_ERROR_INVALID_FILE,
|
g_set_error (error,
|
||||||
"firmware is %04x bytes smaller than the allowed "
|
FWUPD_ERROR,
|
||||||
"minimum size of %04x bytes",
|
FWUPD_ERROR_INVALID_FILE,
|
||||||
(guint) (priv->size_min - fw_sz),
|
"firmware is %04x bytes smaller than the allowed "
|
||||||
(guint) priv->size_max);
|
"minimum size of %04x bytes",
|
||||||
return NULL;
|
(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 <glib-object.h>
|
||||||
#include <fwupd.h>
|
#include <fwupd.h>
|
||||||
|
|
||||||
|
#include "fu-firmware.h"
|
||||||
#include "fu-quirks.h"
|
#include "fu-quirks.h"
|
||||||
#include "fu-common-version.h"
|
#include "fu-common-version.h"
|
||||||
|
|
||||||
@ -23,7 +24,7 @@ struct _FuDeviceClass
|
|||||||
void (*to_string) (FuDevice *self,
|
void (*to_string) (FuDevice *self,
|
||||||
GString *str);
|
GString *str);
|
||||||
gboolean (*write_firmware) (FuDevice *self,
|
gboolean (*write_firmware) (FuDevice *self,
|
||||||
GBytes *fw,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error);
|
GError **error);
|
||||||
GBytes *(*read_firmware) (FuDevice *self,
|
GBytes *(*read_firmware) (FuDevice *self,
|
||||||
@ -38,7 +39,7 @@ struct _FuDeviceClass
|
|||||||
GError **error);
|
GError **error);
|
||||||
gboolean (*probe) (FuDevice *self,
|
gboolean (*probe) (FuDevice *self,
|
||||||
GError **error);
|
GError **error);
|
||||||
GBytes *(*prepare_firmware) (FuDevice *self,
|
FuFirmware *(*prepare_firmware) (FuDevice *self,
|
||||||
GBytes *fw,
|
GBytes *fw,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error);
|
GError **error);
|
||||||
@ -210,7 +211,7 @@ gboolean fu_device_write_firmware (FuDevice *self,
|
|||||||
GBytes *fw,
|
GBytes *fw,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error);
|
GError **error);
|
||||||
GBytes *fu_device_prepare_firmware (FuDevice *self,
|
FuFirmware *fu_device_prepare_firmware (FuDevice *self,
|
||||||
GBytes *fw,
|
GBytes *fw,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error);
|
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-list.h"
|
||||||
#include "fu-device-private.h"
|
#include "fu-device-private.h"
|
||||||
#include "fu-engine.h"
|
#include "fu-engine.h"
|
||||||
|
#include "fu-ihex-firmware.h"
|
||||||
#include "fu-quirks.h"
|
#include "fu-quirks.h"
|
||||||
#include "fu-keyring.h"
|
#include "fu-keyring.h"
|
||||||
#include "fu-history.h"
|
#include "fu-history.h"
|
||||||
@ -33,6 +34,7 @@
|
|||||||
#include "fu-hash.h"
|
#include "fu-hash.h"
|
||||||
#include "fu-hwids.h"
|
#include "fu-hwids.h"
|
||||||
#include "fu-smbios.h"
|
#include "fu-smbios.h"
|
||||||
|
#include "fu-srec-firmware.h"
|
||||||
#include "fu-test.h"
|
#include "fu-test.h"
|
||||||
|
|
||||||
#ifdef ENABLE_GPG
|
#ifdef ENABLE_GPG
|
||||||
@ -3665,6 +3667,248 @@ fu_common_vercmp_func (void)
|
|||||||
g_assert_cmpint (fu_common_vercmp (NULL, NULL), ==, G_MAXINT);
|
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
|
int
|
||||||
main (int argc, char **argv)
|
main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -3685,6 +3929,11 @@ main (int argc, char **argv)
|
|||||||
/* tests go here */
|
/* tests go here */
|
||||||
if (g_test_slow ())
|
if (g_test_slow ())
|
||||||
g_test_add_func ("/fwupd/progressbar", fu_progressbar_func);
|
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{invalid}", fu_archive_invalid_func);
|
||||||
g_test_add_func ("/fwupd/archive{cab}", fu_archive_cab_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);
|
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-chunk.c',
|
||||||
'fu-device.c',
|
'fu-device.c',
|
||||||
'fu-device-locker.c',
|
'fu-device-locker.c',
|
||||||
|
'fu-firmware.c',
|
||||||
|
'fu-firmware-common.c',
|
||||||
|
'fu-firmware-image.c',
|
||||||
'fu-hwids.c',
|
'fu-hwids.c',
|
||||||
'fu-history.c',
|
'fu-history.c',
|
||||||
|
'fu-ihex-firmware.c',
|
||||||
'fu-io-channel.c',
|
'fu-io-channel.c',
|
||||||
'fu-plugin.c',
|
'fu-plugin.c',
|
||||||
'fu-progressbar.c',
|
'fu-progressbar.c',
|
||||||
'fu-quirks.c',
|
'fu-quirks.c',
|
||||||
'fu-smbios.c',
|
'fu-smbios.c',
|
||||||
|
'fu-srec-firmware.c',
|
||||||
'fu-test.c',
|
'fu-test.c',
|
||||||
'fu-udev-device.c',
|
'fu-udev-device.c',
|
||||||
'fu-usb-device.c',
|
'fu-usb-device.c',
|
||||||
@ -203,6 +208,7 @@ fwupdtool = executable(
|
|||||||
'fu-device-locker.c',
|
'fu-device-locker.c',
|
||||||
'fu-idle.c',
|
'fu-idle.c',
|
||||||
'fu-install-task.c',
|
'fu-install-task.c',
|
||||||
|
'fu-ihex-firmware.c',
|
||||||
'fu-io-channel.c',
|
'fu-io-channel.c',
|
||||||
'fu-keyring.c',
|
'fu-keyring.c',
|
||||||
'fu-keyring-utils.c',
|
'fu-keyring-utils.c',
|
||||||
@ -211,6 +217,7 @@ fwupdtool = executable(
|
|||||||
'fu-plugin-list.c',
|
'fu-plugin-list.c',
|
||||||
'fu-quirks.c',
|
'fu-quirks.c',
|
||||||
'fu-smbios.c',
|
'fu-smbios.c',
|
||||||
|
'fu-srec-firmware.c',
|
||||||
'fu-udev-device.c',
|
'fu-udev-device.c',
|
||||||
'fu-usb-device.c',
|
'fu-usb-device.c',
|
||||||
'fu-util-common.c',
|
'fu-util-common.c',
|
||||||
@ -286,7 +293,11 @@ executable(
|
|||||||
'fu-device.c',
|
'fu-device.c',
|
||||||
'fu-device-list.c',
|
'fu-device-list.c',
|
||||||
'fu-device-locker.c',
|
'fu-device-locker.c',
|
||||||
|
'fu-firmware.c',
|
||||||
|
'fu-firmware-common.c',
|
||||||
|
'fu-firmware-image.c',
|
||||||
'fu-idle.c',
|
'fu-idle.c',
|
||||||
|
'fu-ihex-firmware.c',
|
||||||
'fu-io-channel.c',
|
'fu-io-channel.c',
|
||||||
'fu-install-task.c',
|
'fu-install-task.c',
|
||||||
'fu-keyring.c',
|
'fu-keyring.c',
|
||||||
@ -296,6 +307,7 @@ executable(
|
|||||||
'fu-plugin-list.c',
|
'fu-plugin-list.c',
|
||||||
'fu-quirks.c',
|
'fu-quirks.c',
|
||||||
'fu-smbios.c',
|
'fu-smbios.c',
|
||||||
|
'fu-srec-firmware.c',
|
||||||
'fu-udev-device.c',
|
'fu-udev-device.c',
|
||||||
'fu-usb-device.c',
|
'fu-usb-device.c',
|
||||||
],
|
],
|
||||||
@ -353,6 +365,9 @@ if get_option('tests')
|
|||||||
'fu-common-version.c',
|
'fu-common-version.c',
|
||||||
'fu-config.c',
|
'fu-config.c',
|
||||||
'fu-engine.c',
|
'fu-engine.c',
|
||||||
|
'fu-firmware.c',
|
||||||
|
'fu-firmware-common.c',
|
||||||
|
'fu-firmware-image.c',
|
||||||
'fu-keyring.c',
|
'fu-keyring.c',
|
||||||
'fu-keyring-utils.c',
|
'fu-keyring-utils.c',
|
||||||
'fu-hwids.c',
|
'fu-hwids.c',
|
||||||
@ -361,6 +376,7 @@ if get_option('tests')
|
|||||||
'fu-device-locker.c',
|
'fu-device-locker.c',
|
||||||
'fu-history.c',
|
'fu-history.c',
|
||||||
'fu-idle.c',
|
'fu-idle.c',
|
||||||
|
'fu-ihex-firmware.c',
|
||||||
'fu-install-task.c',
|
'fu-install-task.c',
|
||||||
'fu-io-channel.c',
|
'fu-io-channel.c',
|
||||||
'fu-keyring.c',
|
'fu-keyring.c',
|
||||||
@ -370,6 +386,7 @@ if get_option('tests')
|
|||||||
'fu-progressbar.c',
|
'fu-progressbar.c',
|
||||||
'fu-quirks.c',
|
'fu-quirks.c',
|
||||||
'fu-smbios.c',
|
'fu-smbios.c',
|
||||||
|
'fu-srec-firmware.c',
|
||||||
'fu-test.c',
|
'fu-test.c',
|
||||||
'fu-udev-device.c',
|
'fu-udev-device.c',
|
||||||
'fu-usb-device.c',
|
'fu-usb-device.c',
|
||||||
@ -424,6 +441,12 @@ if get_option('introspection')
|
|||||||
'fu-device.h',
|
'fu-device.h',
|
||||||
'fu-device-locker.c',
|
'fu-device-locker.c',
|
||||||
'fu-device-locker.h',
|
'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-io-channel.c',
|
||||||
'fu-plugin.c',
|
'fu-plugin.c',
|
||||||
'fu-plugin.h',
|
'fu-plugin.h',
|
||||||
|
Loading…
Reference in New Issue
Block a user