diff --git a/plugins/unifying/lu-device-bootloader-nordic.c b/plugins/unifying/lu-device-bootloader-nordic.c index 9d65d72a7..2e1a0b847 100644 --- a/plugins/unifying/lu-device-bootloader-nordic.c +++ b/plugins/unifying/lu-device-bootloader-nordic.c @@ -93,6 +93,31 @@ lu_device_bootloader_nordic_probe (LuDevice *device, GError **error) return TRUE; } +static gboolean +lu_device_bootloader_nordic_write_signature (LuDevice *device, + guint16 addr, guint8 len, const guint8 *data, + GError **error) +{ + g_autoptr(LuDeviceBootloaderRequest) req = lu_device_bootloader_request_new(); + req->cmd = 0xC0; + req->addr = addr; + req->len = len; + memcpy (req->data, data, req->len); + if (!lu_device_bootloader_request (device, req, error)) { + g_prefix_error (error, "failed to write sig @0x%02x: ", addr); + return FALSE; + } + if (req->cmd == LU_DEVICE_BOOTLOADER_CMD_WRITE_RAM_BUFFER_INVALID_ADDR) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to write @%04x: signature is too big", + addr); + return FALSE; + } + return TRUE; +} + static gboolean lu_device_bootloader_nordic_write (LuDevice *device, guint16 addr, guint8 len, const guint8 *data, @@ -132,18 +157,12 @@ lu_device_bootloader_nordic_write (LuDevice *device, return FALSE; } if (req->cmd == LU_DEVICE_BOOTLOADER_CMD_WRITE_NONZERO_START) { - if (addr == 0x0000) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to write @%04x: only 1 byte write supported", - addr); - return FALSE; - } + g_debug ("wrote %d bytes at address %04x, value %02x", req->len, + req->addr, req->data[0]); g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "failed to write @%04x: byte 0x00 is not 0xff", + "failed to write @%04x: only 1 byte write of 0xff supported", addr); return FALSE; } @@ -209,12 +228,24 @@ lu_device_bootloader_nordic_write_firmware (LuDevice *device, GBytes *fw, GError return FALSE; for (guint i = 1; i < reqs->len; i++) { + gboolean res; payload = g_ptr_array_index (reqs, i); - if (!lu_device_bootloader_nordic_write (device, - payload->addr, - payload->len, - payload->data, - error)) + + if (payload->cmd == LU_DEVICE_BOOTLOADER_CMD_WRITE_SIGNATURE) { + res = lu_device_bootloader_nordic_write_signature(device, + payload->addr, + payload->len, + payload->data, + error); + } else { + res = lu_device_bootloader_nordic_write (device, + payload->addr, + payload->len, + payload->data, + error); + } + + if (!res) return FALSE; fu_device_set_progress_full (FU_DEVICE (device), i * 32, reqs->len * 32); } @@ -228,7 +259,6 @@ lu_device_bootloader_nordic_write_firmware (LuDevice *device, GBytes *fw, GError error)) return FALSE; - /* set the reset vector */ if (!lu_device_bootloader_nordic_write (device, 0x0000, 0x01, diff --git a/plugins/unifying/lu-device-bootloader-texas.c b/plugins/unifying/lu-device-bootloader-texas.c index 3c8e8ba92..d53884acd 100644 --- a/plugins/unifying/lu-device-bootloader-texas.c +++ b/plugins/unifying/lu-device-bootloader-texas.c @@ -157,8 +157,14 @@ lu_device_bootloader_texas_write_firmware (LuDevice *device, GBytes *fw, GError } /* build packet */ - req->cmd = LU_DEVICE_BOOTLOADER_CMD_WRITE_RAM_BUFFER; - req->addr = payload->addr % 0x80; + req->cmd = payload->cmd; + + /* signature addresses do not need to fit inside 128 bytes */ + if (req->cmd == LU_DEVICE_BOOTLOADER_CMD_WRITE_SIGNATURE) + req->addr = payload->addr; + else + req->addr = payload->addr % 0x80; + req->len = payload->len; memcpy (req->data, payload->data, payload->len); if (!lu_device_bootloader_request (device, req, error)) { @@ -185,7 +191,8 @@ lu_device_bootloader_texas_write_firmware (LuDevice *device, GBytes *fw, GError } /* flush RAM buffer to EEPROM */ - if ((payload->addr + 0x10) % 0x80 == 0) { + if ((payload->addr + 0x10) % 0x80 == 0 && + req->cmd != LU_DEVICE_BOOTLOADER_CMD_WRITE_SIGNATURE) { guint16 addr_start = payload->addr - (7 * 0x10); g_debug ("addr flush @ 0x%04x for 0x%04x", payload->addr, addr_start); diff --git a/plugins/unifying/lu-device-bootloader.c b/plugins/unifying/lu-device-bootloader.c index ce1b8c673..1ffd6e403 100644 --- a/plugins/unifying/lu-device-bootloader.c +++ b/plugins/unifying/lu-device-bootloader.c @@ -58,6 +58,7 @@ lu_device_bootloader_parse_requests (LuDevice *device, GBytes *fw, GError **erro lines = g_strsplit_set (tmp, "\n\r", -1); for (guint i = 0; lines[i] != NULL; i++) { g_autoptr(LuDeviceBootloaderRequest) payload = NULL; + guint8 rec_type = 0x00; /* skip empty lines */ tmp = lines[i]; @@ -77,6 +78,15 @@ lu_device_bootloader_parse_requests (LuDevice *device, GBytes *fw, GError **erro payload->addr = ((guint16) lu_buffer_read_uint8 (tmp + 0x03)) << 8; payload->addr |= lu_buffer_read_uint8 (tmp + 0x05); + rec_type = lu_buffer_read_uint8 (tmp + 0x07); + + /* record type of 0xFD indicates signature data */ + if (rec_type == 0xFD) { + payload->cmd = LU_DEVICE_BOOTLOADER_CMD_WRITE_SIGNATURE; + } else { + payload->cmd = LU_DEVICE_BOOTLOADER_CMD_WRITE_RAM_BUFFER; + } + /* read the data, but skip the checksum byte */ for (guint j = 0; j < payload->len; j++) { const gchar *ptr = tmp + 0x09 + (j * 2); @@ -91,6 +101,12 @@ lu_device_bootloader_parse_requests (LuDevice *device, GBytes *fw, GError **erro payload->data[j] = lu_buffer_read_uint8 (ptr); } + /* no need to bound check signature addresses */ + if (payload->cmd == LU_DEVICE_BOOTLOADER_CMD_WRITE_SIGNATURE) { + g_ptr_array_add (reqs, g_steal_pointer (&payload)); + continue; + } + /* skip the bootloader */ if (payload->addr > lu_device_bootloader_get_addr_hi (device)) { g_debug ("skipping write @ %04x", payload->addr); diff --git a/plugins/unifying/lu-device.h b/plugins/unifying/lu-device.h index bde8462db..d0f539313 100644 --- a/plugins/unifying/lu-device.h +++ b/plugins/unifying/lu-device.h @@ -64,7 +64,8 @@ struct _LuDeviceClass #define LU_DEVICE_EP1 0x81 #define LU_DEVICE_EP3 0x83 -#define LU_DEVICE_TIMEOUT_MS 2500 +/* Signed firmware are very long to verify on the device */ +#define LU_DEVICE_TIMEOUT_MS 20000 typedef enum { LU_DEVICE_KIND_UNKNOWN,