synaptics-rmi: add support to write signature

This commit is contained in:
Vincent Huang 2023-01-10 14:17:07 +08:00 committed by Richard Hughes
parent b1ea3fab8c
commit 8d365e84de
2 changed files with 190 additions and 52 deletions

View File

@ -57,10 +57,7 @@ typedef struct __attribute__((packed)) {
guint16 container_id;
guint8 minor_version;
guint8 major_version;
guint8 reserved_08;
guint8 reserved_09;
guint8 reserved_0a;
guint8 reserved_0b;
guint32 signature_size;
guint32 container_option_flags;
guint32 content_options_length;
guint32 content_options_address;
@ -172,6 +169,33 @@ fu_synaptics_rmi_firmware_add_image(FuFirmware *firmware,
return TRUE;
}
static gboolean
fu_synaptics_rmi_firmware_add_image_v10(FuFirmware *firmware,
const gchar *id,
GBytes *fw,
gsize offset,
gsize sz,
gsize sig_sz,
GError **error)
{
g_autoptr(GBytes) bytes = NULL;
g_autoptr(FuFirmware) img = NULL;
g_autofree gchar *sig_id = NULL;
if (!fu_synaptics_rmi_firmware_add_image(firmware, id, fw, offset, sz, error))
return FALSE;
if (sig_sz != 0) {
bytes = fu_bytes_new_offset(fw, offset + sz, sig_sz, error);
if (bytes == NULL)
return FALSE;
img = fu_firmware_new_from_bytes(bytes);
sig_id = g_strdup_printf("%s-signature", id);
fu_firmware_set_id(img, sig_id);
fu_firmware_add_image(firmware, img);
}
return TRUE;
}
static void
fu_synaptics_rmi_firmware_export(FuFirmware *firmware,
FuFirmwareExportFlags flags,
@ -203,6 +227,7 @@ fu_synaptics_rmi_firmware_parse_v10(FuFirmware *firmware, GBytes *fw, GError **e
guint8 product_id[RMI_PRODUCT_ID_LENGTH] = {0x0};
gsize sz = 0;
const guint8 *data = g_bytes_get_data(fw, &sz);
guint32 signature_size;
if (!fu_memread_uint32_safe(data,
sz,
@ -274,10 +299,12 @@ fu_synaptics_rmi_firmware_parse_v10(FuFirmware *firmware, GBytes *fw, GError **e
container_id = GUINT16_FROM_LE(desc.container_id);
content_addr = GUINT32_FROM_LE(desc.content_address);
length = GUINT32_FROM_LE(desc.content_length);
g_debug("RmiFirmwareContainerDescriptor 0x%02x @ 0x%x (len 0x%x)",
signature_size = GUINT32_FROM_LE(desc.signature_size);
g_debug("RmiFirmwareContainerDescriptor 0x%02x @ 0x%x (len 0x%x) sig_size 0x%x",
container_id,
content_addr,
length);
length,
signature_size);
if (length == 0 || length > sz) {
g_set_error(error,
FWUPD_ERROR,
@ -308,57 +335,63 @@ fu_synaptics_rmi_firmware_parse_v10(FuFirmware *firmware, GBytes *fw, GError **e
break;
case RMI_FIRMWARE_CONTAINER_ID_UI:
case RMI_FIRMWARE_CONTAINER_ID_CORE_CODE:
if (!fu_synaptics_rmi_firmware_add_image(firmware,
if (!fu_synaptics_rmi_firmware_add_image_v10(firmware,
"ui",
fw,
content_addr,
length,
signature_size,
error))
return FALSE;
break;
case RMI_FIRMWARE_CONTAINER_ID_FLASH_CONFIG:
if (!fu_synaptics_rmi_firmware_add_image(firmware,
if (!fu_synaptics_rmi_firmware_add_image_v10(firmware,
"flash-config",
fw,
content_addr,
length,
signature_size,
error))
return FALSE;
break;
case RMI_FIRMWARE_CONTAINER_ID_UI_CONFIG:
case RMI_FIRMWARE_CONTAINER_ID_CORE_CONFIG:
if (!fu_synaptics_rmi_firmware_add_image(firmware,
if (!fu_synaptics_rmi_firmware_add_image_v10(firmware,
"config",
fw,
content_addr,
length,
signature_size,
error))
return FALSE;
break;
case RMI_FIRMWARE_CONTAINER_ID_FIXED_LOCATION_DATA:
if (!fu_synaptics_rmi_firmware_add_image(firmware,
if (!fu_synaptics_rmi_firmware_add_image_v10(firmware,
"fixed-location-data",
fw,
content_addr,
length,
signature_size,
error))
return FALSE;
break;
case RMI_FIRMWARE_CONTAINER_ID_EXTERNAL_TOUCH_AFE_CONFIG:
if (!fu_synaptics_rmi_firmware_add_image(firmware,
if (!fu_synaptics_rmi_firmware_add_image_v10(firmware,
"afe-config",
fw,
content_addr,
length,
signature_size,
error))
return FALSE;
break;
case RMI_FIRMWARE_CONTAINER_ID_DISPLAY_CONFIG:
if (!fu_synaptics_rmi_firmware_add_image(firmware,
if (!fu_synaptics_rmi_firmware_add_image_v10(firmware,
"display-config",
fw,
content_addr,
length,
signature_size,
error))
return FALSE;
break;
@ -581,6 +614,7 @@ fu_synaptics_rmi_firmware_parse(FuFirmware *firmware,
self->kind = RMI_FIRMWARE_KIND_0X;
break;
case 16:
case 17:
if (!fu_synaptics_rmi_firmware_parse_v10(firmware, fw, error))
return FALSE;
self->kind = RMI_FIRMWARE_KIND_10;

View File

@ -22,6 +22,7 @@ typedef enum {
RMI_FLASH_CMD_ERASE,
RMI_FLASH_CMD_ERASE_AP,
RMI_FLASH_CMD_SENSOR_ID,
RMI_FLASH_CMD_SIGNATURE,
} RmiFlashCommand;
typedef enum {
@ -252,8 +253,88 @@ fu_synaptics_rmi_v7_device_write_blocks(FuSynapticsRmiDevice *self,
return TRUE;
}
static gboolean
fu_synaptics_rmi_v7_device_write_partition_signature(FuSynapticsRmiDevice *self,
FuFirmware *firmware,
const gchar *id,
RmiPartitionId partition_id,
GError **error)
{
FuSynapticsRmiFunction *f34;
FuSynapticsRmiFlash *flash = fu_synaptics_rmi_device_get_flash(self);
g_autoptr(GByteArray) req_offset = g_byte_array_new();
g_autoptr(GPtrArray) chunks = NULL;
g_autoptr(GBytes) bytes = NULL;
/* f34 */
f34 = fu_synaptics_rmi_device_get_function(self, 0x34, error);
if (f34 == NULL)
return FALSE;
/*check if signature exists */
bytes =
fu_firmware_get_image_by_id_bytes(firmware, g_strdup_printf("%s-signature", id), NULL);
if (bytes == NULL) {
return TRUE;
}
/* write partition signature */
g_debug("writing partition signature %s…",
rmi_firmware_partition_id_to_string(partition_id));
fu_byte_array_append_uint16(req_offset, 0x0, G_LITTLE_ENDIAN);
if (!fu_synaptics_rmi_device_write(self,
f34->data_base + 0x2,
req_offset,
FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE,
error)) {
g_prefix_error(error, "failed to write offset: ");
return FALSE;
}
chunks =
fu_chunk_array_new_from_bytes(bytes,
0x00, /* start addr */
0x00, /* page_sz */
(gsize)flash->payload_length * (gsize)flash->block_size);
for (guint i = 0; i < chunks->len; i++) {
FuChunk *chk = g_ptr_array_index(chunks, i);
g_autoptr(GByteArray) req_trans_sz = g_byte_array_new();
g_autoptr(GByteArray) req_cmd = g_byte_array_new();
fu_byte_array_append_uint16(req_trans_sz,
fu_chunk_get_data_sz(chk) / flash->block_size,
G_LITTLE_ENDIAN);
if (!fu_synaptics_rmi_device_write(self,
f34->data_base + 0x3,
req_trans_sz,
FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE,
error)) {
g_prefix_error(error, "failed to write transfer length: ");
return FALSE;
}
fu_byte_array_append_uint8(req_cmd, RMI_FLASH_CMD_SIGNATURE);
if (!fu_synaptics_rmi_device_write(self,
f34->data_base + 0x4,
req_cmd,
FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE,
error)) {
g_prefix_error(error, "failed to write signature command: ");
return FALSE;
}
if (!fu_synaptics_rmi_v7_device_write_blocks(self,
f34->data_base + 0x5,
fu_chunk_get_data(chk),
fu_chunk_get_data_sz(chk),
error))
return FALSE;
}
return TRUE;
}
static gboolean
fu_synaptics_rmi_v7_device_write_partition(FuSynapticsRmiDevice *self,
FuFirmware *firmware,
const gchar *id,
RmiPartitionId partition_id,
GBytes *bytes,
FuProgress *progress,
@ -298,7 +379,7 @@ fu_synaptics_rmi_v7_device_write_partition(FuSynapticsRmiDevice *self,
0x00, /* page_sz */
(gsize)flash->payload_length * (gsize)flash->block_size);
fu_progress_set_id(progress, G_STRLOC);
fu_progress_set_steps(progress, chunks->len);
fu_progress_set_steps(progress, chunks->len + 1);
for (guint i = 0; i < chunks->len; i++) {
FuChunk *chk = g_ptr_array_index(chunks, i);
g_autoptr(GByteArray) req_trans_sz = g_byte_array_new();
@ -331,6 +412,13 @@ fu_synaptics_rmi_v7_device_write_partition(FuSynapticsRmiDevice *self,
return FALSE;
fu_progress_step_done(progress);
}
if (!fu_synaptics_rmi_v7_device_write_partition_signature(self,
firmware,
id,
partition_id,
error))
return FALSE;
fu_progress_step_done(progress);
return TRUE;
}
@ -354,14 +442,14 @@ fu_synaptics_rmi_v7_device_write_firmware(FuDevice *device,
/* progress */
fu_progress_set_id(progress, G_STRLOC);
fu_progress_add_flag(progress, FU_PROGRESS_FLAG_GUESSED);
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_BUSY, 1, "disable-sleep");
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 1, "fixed-location-data");
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_ERASE, 10, NULL);
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 20, "flash-config");
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 20, "core-code");
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 20, "core-config");
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 1, "external-touch-afe-config");
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 1, "display-config");
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_BUSY, 0, "disable-sleep");
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 2, "fixed-location-data");
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_ERASE, 3, NULL);
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 0, "flash-config");
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 89, "core-code");
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 2, "core-config");
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 2, "external-touch-afe-config");
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 2, "display-config");
/* we should be in bootloader mode now, but check anyway */
if (!fu_device_has_flag(device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) {
@ -402,6 +490,8 @@ fu_synaptics_rmi_v7_device_write_firmware(FuDevice *device,
if (bytes_fld != NULL) {
if (!fu_synaptics_rmi_v7_device_write_partition(
self,
firmware,
"fixed-location-data",
RMI_PARTITION_ID_FIXED_LOCATION_DATA,
bytes_fld,
fu_progress_get_child(progress),
@ -420,6 +510,8 @@ fu_synaptics_rmi_v7_device_write_firmware(FuDevice *device,
/* write flash config for v8 */
if (bytes_flashcfg != NULL) {
if (!fu_synaptics_rmi_v7_device_write_partition(self,
firmware,
"flash-config",
RMI_PARTITION_ID_FLASH_CONFIG,
bytes_flashcfg,
fu_progress_get_child(progress),
@ -430,6 +522,8 @@ fu_synaptics_rmi_v7_device_write_firmware(FuDevice *device,
/* write core code */
if (!fu_synaptics_rmi_v7_device_write_partition(self,
firmware,
"ui",
RMI_PARTITION_ID_CORE_CODE,
bytes_bin,
fu_progress_get_child(progress),
@ -439,6 +533,8 @@ fu_synaptics_rmi_v7_device_write_firmware(FuDevice *device,
/* write core config */
if (!fu_synaptics_rmi_v7_device_write_partition(self,
firmware,
"config",
RMI_PARTITION_ID_CORE_CONFIG,
bytes_cfg,
fu_progress_get_child(progress),
@ -450,6 +546,8 @@ fu_synaptics_rmi_v7_device_write_firmware(FuDevice *device,
if (bytes_afe != NULL) {
if (!fu_synaptics_rmi_v7_device_write_partition(
self,
firmware,
"afe-config",
RMI_PARTITION_ID_EXTERNAL_TOUCH_AFE_CONFIG,
bytes_afe,
fu_progress_get_child(progress),
@ -461,6 +559,8 @@ fu_synaptics_rmi_v7_device_write_firmware(FuDevice *device,
/* write display config if exists */
if (bytes_displayconfig != NULL) {
if (!fu_synaptics_rmi_v7_device_write_partition(self,
firmware,
"display-config",
RMI_PARTITION_ID_DISPLAY_CONFIG,
bytes_displayconfig,
fu_progress_get_child(progress),
@ -492,6 +592,7 @@ fu_synaptics_rmi_device_read_flash_config_v7(FuSynapticsRmiDevice *self, GError
g_autoptr(GByteArray) req_partition_id = g_byte_array_new();
g_autoptr(GByteArray) req_transfer_length = g_byte_array_new();
g_autoptr(GByteArray) res = NULL;
gsize partition_size = sizeof(RmiPartitionTbl);
/* f34 */
f34 = fu_synaptics_rmi_device_get_function(self, 0x34, error);
@ -565,8 +666,11 @@ fu_synaptics_rmi_device_read_flash_config_v7(FuSynapticsRmiDevice *self, GError
FU_DUMP_FLAGS_NONE);
}
if ((res->data[0] & 0x0f) == 1)
partition_size = sizeof(RmiPartitionTbl) + 2;
/* parse the config length */
for (guint i = 0x2; i < res->len; i += sizeof(RmiPartitionTbl)) {
for (guint i = 0x2; i < res->len; i += partition_size) {
RmiPartitionTbl tbl;
if (!fu_memcpy_safe((guint8 *)&tbl,
sizeof(tbl),