From 8d365e84def16eecce07ee36abf4def716f351b0 Mon Sep 17 00:00:00 2001 From: Vincent Huang Date: Tue, 10 Jan 2023 14:17:07 +0800 Subject: [PATCH] synaptics-rmi: add support to write signature --- .../synaptics-rmi/fu-synaptics-rmi-firmware.c | 118 +++++++++++------ .../fu-synaptics-rmi-v7-device.c | 124 ++++++++++++++++-- 2 files changed, 190 insertions(+), 52 deletions(-) diff --git a/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.c b/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.c index 890b2150e..ddf7e1143 100644 --- a/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.c +++ b/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.c @@ -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,58 +335,64 @@ 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, - "ui", - fw, - content_addr, - length, - error)) + 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, - "flash-config", - fw, - content_addr, - length, - error)) + 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, - "config", - fw, - content_addr, - length, - error)) + 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, - "fixed-location-data", - fw, - content_addr, - length, - error)) + 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, - "afe-config", - fw, - content_addr, - length, - error)) + 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, - "display-config", - fw, - content_addr, - length, - error)) + if (!fu_synaptics_rmi_firmware_add_image_v10(firmware, + "display-config", + fw, + content_addr, + length, + signature_size, + error)) return FALSE; break; case RMI_FIRMWARE_CONTAINER_ID_GENERAL_INFORMATION: @@ -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; diff --git a/plugins/synaptics-rmi/fu-synaptics-rmi-v7-device.c b/plugins/synaptics-rmi/fu-synaptics-rmi-v7-device.c index d8f41b4f4..3a7fb5a69 100644 --- a/plugins/synaptics-rmi/fu-synaptics-rmi-v7-device.c +++ b/plugins/synaptics-rmi/fu-synaptics-rmi-v7-device.c @@ -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),