mirror of
https://git.proxmox.com/git/fwupd
synced 2025-07-27 07:32:12 +00:00
ccgx: Parse the metadata block in the firmware image
This commit is contained in:
parent
b258e514c5
commit
48d9fb8f74
24
plugins/ccgx/fu-ccgx-common.h
Normal file
24
plugins/ccgx/fu-ccgx-common.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Cypress Semiconductor Corporation.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
|
/* metadata valid signature "CY" */
|
||||||
|
#define CCGX_METADATA_VALID_SIG 0x4359
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed)) {
|
||||||
|
guint8 fw_checksum; /* firmware checksum */
|
||||||
|
guint32 fw_entry; /* firmware entry address */
|
||||||
|
guint16 last_boot_row; /* last flash row of bootloader or previous firmware */
|
||||||
|
guint8 reserved1[2]; /* reserved */
|
||||||
|
guint32 fw_size; /* firmware size */
|
||||||
|
guint8 reserved2[9]; /* reserved */
|
||||||
|
guint16 metadata_valid; /* meta data valid "CY" */
|
||||||
|
guint8 reserved3[4]; /* reserved */
|
||||||
|
guint32 boot_seq; /* boot sequence number */
|
||||||
|
} CCGxMetaData;
|
@ -8,10 +8,15 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "fu-common.h"
|
#include "fu-common.h"
|
||||||
|
#include "fu-common-version.h"
|
||||||
#include "fu-firmware-common.h"
|
#include "fu-firmware-common.h"
|
||||||
|
|
||||||
|
#include "fu-ccgx-common.h"
|
||||||
#include "fu-ccgx-cyacd-firmware-image.h"
|
#include "fu-ccgx-cyacd-firmware-image.h"
|
||||||
|
|
||||||
|
/* offset stored appication version for CCGx */
|
||||||
|
#define CCGX_APP_VERSION_OFFSET 228 /* 128+64+32+4 */
|
||||||
|
|
||||||
struct _FuCcgxCyacdFirmwareImage {
|
struct _FuCcgxCyacdFirmwareImage {
|
||||||
FuFirmwareImageClass parent_instance;
|
FuFirmwareImageClass parent_instance;
|
||||||
GPtrArray *records;
|
GPtrArray *records;
|
||||||
@ -36,6 +41,102 @@ fu_ccgx_cyacd_firmware_image_record_free (FuCcgxCyacdFirmwareImageRecord *rcd)
|
|||||||
|
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuCcgxCyacdFirmwareImageRecord, fu_ccgx_cyacd_firmware_image_record_free)
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuCcgxCyacdFirmwareImageRecord, fu_ccgx_cyacd_firmware_image_record_free)
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
fu_ccgx_cyacd_firmware_image_parse_md_block (FuCcgxCyacdFirmwareImage *self, GError **error)
|
||||||
|
{
|
||||||
|
FuCcgxCyacdFirmwareImageRecord *rcd;
|
||||||
|
CCGxMetaData metadata;
|
||||||
|
const guint8 *buf;
|
||||||
|
gsize bufsz = 0;
|
||||||
|
gsize md_offset = 0;
|
||||||
|
guint32 fw_size = 0;
|
||||||
|
guint32 rcd_version_idx = 0;
|
||||||
|
guint32 version = 0;
|
||||||
|
guint8 checksum_calc = 0;
|
||||||
|
g_autofree gchar *version_str = NULL;
|
||||||
|
|
||||||
|
/* sanity check */
|
||||||
|
if (self->records->len == 0) {
|
||||||
|
g_set_error_literal (error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_NOT_SUPPORTED,
|
||||||
|
"no records added to image");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read metadata from correct ofsset */
|
||||||
|
rcd = g_ptr_array_index (self->records, self->records->len - 1);
|
||||||
|
buf = g_bytes_get_data (rcd->data, &bufsz);
|
||||||
|
switch (bufsz) {
|
||||||
|
case 0x80:
|
||||||
|
md_offset = 0x40;
|
||||||
|
break;
|
||||||
|
case 0x100:
|
||||||
|
md_offset = 0xC0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!fu_memcpy_safe ((guint8 *) &metadata, sizeof(metadata), 0x0, /* dst */
|
||||||
|
buf, bufsz, md_offset, sizeof(metadata), error)) /* src */
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* sanity check */
|
||||||
|
if (metadata.metadata_valid != CCGX_METADATA_VALID_SIG) {
|
||||||
|
g_set_error (error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_NOT_SUPPORTED,
|
||||||
|
"invalid metadata 0x@%x, expected 0x%04x, got 0x%04x",
|
||||||
|
(guint) md_offset,
|
||||||
|
(guint) CCGX_METADATA_VALID_SIG,
|
||||||
|
(guint) metadata.metadata_valid);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
for (guint i = 0; i < self->records->len - 1; i++) {
|
||||||
|
rcd = g_ptr_array_index (self->records, i);
|
||||||
|
buf = g_bytes_get_data (rcd->data, &bufsz);
|
||||||
|
fw_size += bufsz;
|
||||||
|
for (gsize j = 0; j < bufsz; j++)
|
||||||
|
checksum_calc += buf[j];
|
||||||
|
}
|
||||||
|
if (fw_size != metadata.fw_size) {
|
||||||
|
g_set_error (error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_INVALID_FILE,
|
||||||
|
"firmware size invalid, got %02x, expected %02x",
|
||||||
|
fw_size, metadata.fw_size);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
checksum_calc = 1 + ~checksum_calc;
|
||||||
|
if (metadata.fw_checksum != checksum_calc) {
|
||||||
|
g_set_error (error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_INVALID_FILE,
|
||||||
|
"checksum invalid, got %02x, expected %02x",
|
||||||
|
checksum_calc, metadata.fw_checksum);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get version */
|
||||||
|
rcd_version_idx = CCGX_APP_VERSION_OFFSET / bufsz;
|
||||||
|
if (rcd_version_idx >= self->records->len) {
|
||||||
|
g_set_error (error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_INVALID_FILE,
|
||||||
|
"invalid version index of %02x",
|
||||||
|
rcd_version_idx);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
rcd = g_ptr_array_index (self->records, rcd_version_idx);
|
||||||
|
buf = g_bytes_get_data (rcd->data, &bufsz);
|
||||||
|
if (!fu_common_read_uint32_safe (buf, bufsz, CCGX_APP_VERSION_OFFSET % bufsz,
|
||||||
|
&version, G_LITTLE_ENDIAN, error))
|
||||||
|
return FALSE;
|
||||||
|
version_str = fu_common_version_from_uint32 (version, FWUPD_VERSION_FORMAT_QUAD);
|
||||||
|
fu_firmware_image_set_version (FU_FIRMWARE_IMAGE (self), version_str);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
fu_ccgx_cyacd_firmware_image_parse_header (FuCcgxCyacdFirmwareImage *self,
|
fu_ccgx_cyacd_firmware_image_parse_header (FuCcgxCyacdFirmwareImage *self,
|
||||||
const gchar *line,
|
const gchar *line,
|
||||||
|
@ -22,6 +22,8 @@ FuFirmwareImage *fu_ccgx_cyacd_firmware_image_new (void);
|
|||||||
gboolean fu_ccgx_cyacd_firmware_image_parse_header (FuCcgxCyacdFirmwareImage *self,
|
gboolean fu_ccgx_cyacd_firmware_image_parse_header (FuCcgxCyacdFirmwareImage *self,
|
||||||
const gchar *line,
|
const gchar *line,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
gboolean fu_ccgx_cyacd_firmware_image_parse_md_block (FuCcgxCyacdFirmwareImage *self,
|
||||||
|
GError **error);
|
||||||
gboolean fu_ccgx_cyacd_firmware_image_add_record (FuCcgxCyacdFirmwareImage *self,
|
gboolean fu_ccgx_cyacd_firmware_image_add_record (FuCcgxCyacdFirmwareImage *self,
|
||||||
const gchar *line,
|
const gchar *line,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
@ -74,6 +74,8 @@ fu_ccgx_cyacd_firmware_parse (FuFirmware *firmware,
|
|||||||
}
|
}
|
||||||
for (guint i = 0; i < images->len; i++) {
|
for (guint i = 0; i < images->len; i++) {
|
||||||
FuFirmwareImage *img = g_ptr_array_index (images, i);
|
FuFirmwareImage *img = g_ptr_array_index (images, i);
|
||||||
|
if (!fu_ccgx_cyacd_firmware_image_parse_md_block (FU_CCGX_CYACD_FIRMWARE_IMAGE (img), error))
|
||||||
|
return FALSE;
|
||||||
fu_firmware_add_image (firmware, img);
|
fu_firmware_add_image (firmware, img);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user