From dac87b8b52dae2882b9d00d7de8f57e91c10d556 Mon Sep 17 00:00:00 2001 From: Daisuke Nojiri Date: Thu, 11 Mar 2021 13:17:35 -0800 Subject: PCHG: Flash multiple binaries in one update session CTN730 firmware consists of separate binaries and currently each binary is flashed in a separate session. This does not work if two binaries need to be updated at the same time because each session writes a new version (after closing the session) and CTN730 refuses to open a session if the version number is the same. This patch makes ectool write multiple binaries in one update session. Example session: localhost ~ # ectool pchg 0 update 0x1041 0x201200 /tmp/user_ee.bin \ 0x207000 /tmp/WLC_Host_UserApp_CRC.bin Opened update session (port=0 ver=0x1041 bsize=128): Writing /tmp/user_ee.bin (3072 bytes). ******************************************************************** Writing /tmp/WLC_Host_UserApp_CRC.bin (90624 bytes). ******************************************************************** Firmware is updated successfully (CRC32=0x5ef03e4d). localhost ~ # ectool pchg 0 reset Reset port 0 complete. localhost ~ # ectool pchg 0 State: ENABLED (2) Battery: 0% Errors: 0x0 FW Version: 0x1041 Dropped events: 0 BUG=b:182600604, b:173235954 BRANCH=trogdor TEST=See the description above. Change-Id: I554ae560947e896ae73979c85d637f32d3e114af Signed-off-by: Daisuke Nojiri Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2952836 Reviewed-by: Vincent Palatin (cherry picked from commit 417c1411ed94cdbc27e99a3ca829b786b9a4ec4e) Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2970901 --- util/ectool.c | 142 ++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 103 insertions(+), 39 deletions(-) diff --git a/util/ectool.c b/util/ectool.c index 7a03764508..3613098ee8 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -9393,7 +9393,7 @@ static void cmd_pchg_help(char *cmd) " Usage3: %s reset\n" " Reset .\n" "\n" - " Usage4: %s update
\n" + " Usage4: %s update ...\n" " Update firmware of .\n", cmd, cmd, cmd, cmd); } @@ -9438,30 +9438,15 @@ static int cmd_pchg_wait_event(int port, uint32_t expected) return -1; } -static int cmd_pchg_update(int port, uint32_t address, uint32_t version, - const char *filename) +static int cmd_pchg_update_open(int port, uint32_t version, + uint32_t *block_size, uint32_t *crc) { struct ec_params_pchg_update *p = (struct ec_params_pchg_update *)(ec_outbuf); struct ec_response_pchg_update *r = (struct ec_response_pchg_update *)(ec_inbuf); - FILE *fp; - size_t len, total; - int progress = 0; int rv; - fp = fopen(filename, "rb"); - if (!fp) { - fprintf(stderr, "\nCan't open %s: %s\n", - filename, strerror(errno)); - return -1; - } - - fseek(fp, 0L, SEEK_END); - total = ftell(fp); - rewind(fp); - printf("Update file %s (%zu bytes) is opened.\n", filename, total); - /* Open session. */ p->port = port; p->cmd = EC_PCHG_UPDATE_CMD_OPEN; @@ -9469,14 +9454,12 @@ static int cmd_pchg_update(int port, uint32_t address, uint32_t version, rv = ec_command(EC_CMD_PCHG_UPDATE, 0, p, sizeof(*p), r, sizeof(*r)); if (rv < 0) { fprintf(stderr, "\nFailed to open update session: %d\n", rv); - fclose(fp); return rv; } if (r->block_size + sizeof(*p) > ec_max_outsize) { fprintf(stderr, "\nBlock size (%d) is too large.\n", r->block_size); - fclose(fp); return -1; } @@ -9484,20 +9467,48 @@ static int cmd_pchg_update(int port, uint32_t address, uint32_t version, if (rv) return rv; - printf("Writing firmware (port=%d ver=0x%x addr=0x%x bsize=%d):\n", - port, version, address, r->block_size); + printf("Opened update session (port=%d ver=0x%x bsize=%d):\n", + port, version, r->block_size); + + *block_size = r->block_size; + crc32_ctx_init(crc); + + return 0; +} + +static int cmd_pchg_update_write(int port, uint32_t address, + const char *filename, uint32_t block_size, + uint32_t *crc) +{ + struct ec_params_pchg_update *p = + (struct ec_params_pchg_update *)(ec_outbuf); + FILE *fp; + size_t len, total; + int progress = 0; + int rv; + + fp = fopen(filename, "rb"); + if (!fp) { + fprintf(stderr, "\nCan't open %s: %s\n", + filename, strerror(errno)); + return -1; + } + + fseek(fp, 0L, SEEK_END); + total = ftell(fp); + rewind(fp); + printf("Writing %s (%zu bytes).\n", filename, total); p->cmd = EC_PCHG_UPDATE_CMD_WRITE; p->addr = address; - crc32_init(); /* Write firmware in blocks. */ - len = fread(p->data, 1, r->block_size, fp); + len = fread(p->data, 1, block_size, fp); while (len > 0) { int previous_progress = progress; int i; - crc32_hash(p->data, len); + crc32_ctx_hash(crc, p->data, len); p->size = len; rv = ec_command(EC_CMD_PCHG_UPDATE, 0, p, sizeof(*p) + len, NULL, 0); @@ -9518,15 +9529,23 @@ static int cmd_pchg_update(int port, uint32_t address, uint32_t version, fflush(stdout); } - len = fread(p->data, 1, r->block_size, fp); + len = fread(p->data, 1, block_size, fp); } printf("\n"); fclose(fp); - /* Close session. */ + return 0; +} + +static int cmd_pchg_update_close(int port, uint32_t *crc) +{ + struct ec_params_pchg_update *p = + (struct ec_params_pchg_update *)(ec_outbuf); + int rv; + p->cmd = EC_PCHG_UPDATE_CMD_CLOSE; - p->crc32 = crc32_result(); + p->crc32 = crc32_ctx_result(crc); rv = ec_command(EC_CMD_PCHG_UPDATE, 0, p, sizeof(*p), NULL, 0); if (rv < 0) { @@ -9538,18 +9557,18 @@ static int cmd_pchg_update(int port, uint32_t address, uint32_t version, if (rv) return rv; - printf("FW update session closed (CRC32=0x%x).\n", p->crc32); + printf("Firmware was updated successfully (CRC32=0x%x).\n", p->crc32); return 0; } static int cmd_pchg(int argc, char *argv[]) { + const size_t max_input_files = 8; int port, port_count; struct ec_response_pchg_count rcnt; struct ec_params_pchg p; struct ec_response_pchg r; - uint32_t address, version; char *e; int rv; @@ -9598,21 +9617,66 @@ static int cmd_pchg(int argc, char *argv[]) } printf("Reset port %d complete.\n", port); return 0; - } else if (argc == 6 && !strcmp(argv[2], "update")) { - /* Usage.4 */ - address = strtol(argv[3], &e, 0); - if (e && *e) { - fprintf(stderr, "\nBad address: %s.\n", argv[3]); - cmd_pchg_help(argv[0]); + } else if (argc >= 6 && !strcmp(argv[2], "update")) { + /* + * Usage.4: + * argv[3]: + * argv[4]: + * argv[5]: + * argv[6]: + * argv[7]: + * ... + */ + uint32_t address, version; + uint32_t block_size; + uint32_t crc; + int i; + + if (argc > 4 + max_input_files * 2) { + fprintf(stderr, "\nToo many input files.\n"); return -1; } - version = strtol(argv[4], &e, 0); + + version = strtol(argv[3], &e, 0); if (e && *e) { - fprintf(stderr, "\nBad version: %s.\n", argv[4]); + fprintf(stderr, "\nBad version: %s.\n", argv[3]); cmd_pchg_help(argv[0]); return -1; } - return cmd_pchg_update(port, address, version, argv[5]); + + rv = cmd_pchg_update_open(port, version, &block_size, &crc); + if (rv < 0) { + fprintf(stderr, "\nFailed to open update session: %d\n", + rv); + return -1; + } + + /* Write files one by one. */ + for (i = 4; i + 1 < argc; i += 2) { + address = strtol(argv[i], &e, 0); + if (e && *e) { + fprintf(stderr, "\nBad address: %s\n", argv[i]); + cmd_pchg_help(argv[0]); + return -1; + } + rv = cmd_pchg_update_write(port, address, argv[i+1], + block_size, &crc); + if (rv < 0) { + fprintf(stderr, + "\nFailed to write file '%s': %d", + argv[i+i], rv); + return -1; + } + } + + rv = cmd_pchg_update_close(port, &crc); + if (rv < 0) { + fprintf(stderr, "\nFailed to close update session: %d", + rv); + return -1; + } + + return 0; } fprintf(stderr, "Invalid parameter\n\n"); -- cgit v1.2.1