unifying: fix signature writing and parsing for texas bootloader

Signed-off-by: Ogier Bouvier <obouvier@logitech.com>
This commit is contained in:
Ogier Bouvier 2017-12-15 14:15:32 +01:00 committed by Richard Hughes
parent 5c535a53ce
commit 620d973fc2
4 changed files with 73 additions and 19 deletions

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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,