diff --git a/board/zinger/usb_pd_policy.c b/board/zinger/usb_pd_policy.c index 6c4110a289..c15e79169e 100644 --- a/board/zinger/usb_pd_policy.c +++ b/board/zinger/usb_pd_policy.c @@ -418,10 +418,16 @@ int pd_custom_vdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload) (const char *)(payload+1)); flash_offset += 4*(cnt - 1); break; - case VDO_CMD_FLASH_HASH: + case VDO_CMD_ERASE_SIG: /* this is not touching the code area */ - flash_write_rw(CONFIG_FW_RW_SIZE - 32, 4*cnt, - (const char *)(payload+1)); + { + uint32_t zero = 0; + int offset; + /* zeroes the area containing the RSA signature */ + for (offset = CONFIG_FW_RW_SIZE - 256; + offset < CONFIG_FW_RW_SIZE; offset += 4) + flash_write_rw(offset, 4, (const char *)&zero); + } break; case VDO_CMD_PING_ENABLE: pd_ping_enable(0, payload[1]); diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index 97d42475e9..90716edaf0 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -1586,15 +1586,9 @@ static int remote_flashing(int argc, char **argv) } else if (!strcasecmp(argv[3], "reboot")) { cmd = VDO_CMD_REBOOT; ccprintf("REBOOT ..."); - } else if (!strcasecmp(argv[3], "hash")) { - int i; - argc -= 4; - for (i = 0; i < argc; i++) - if (hex8tou32(argv[i+4], data + i)) - return EC_ERROR_INVAL; - cmd = VDO_CMD_FLASH_HASH; - cnt = argc; - ccprintf("HASH ..."); + } else if (!strcasecmp(argv[3], "signature")) { + cmd = VDO_CMD_ERASE_SIG; + ccprintf("ERASE SIG ..."); } else if (!strcasecmp(argv[3], "info")) { cmd = VDO_CMD_READ_INFO; ccprintf("INFO..."); @@ -1936,16 +1930,9 @@ static int hc_remote_flash(struct host_cmd_handler_args *args) task_wait_event(100*MSEC); break; - case USB_PD_FW_FLASH_HASH: - /* Can only write 20 bytes */ - if (p->size != 20) - return EC_RES_INVALID_PARAM; - - ccprintf("PD Update - Write RW flash hash "); - for (i = 0; i < 5; i++) - ccprintf("%08x ", *(data + i)); - ccprintf("\n"); - pd_send_vdm(port, USB_VID_GOOGLE, VDO_CMD_FLASH_HASH, data, 5); + case USB_PD_FW_ERASE_SIG: + ccprintf("PD Update - Erase RW RSA signature\n"); + pd_send_vdm(port, USB_VID_GOOGLE, VDO_CMD_ERASE_SIG, NULL, 0); /* Wait until VDM is done */ while (pd[port].vdm_state > 0) diff --git a/include/ec_commands.h b/include/ec_commands.h index 36c61ac4a1..c0d1300160 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -2650,7 +2650,7 @@ enum usb_pd_fw_update_cmds { USB_PD_FW_REBOOT, USB_PD_FW_FLASH_ERASE, USB_PD_FW_FLASH_WRITE, - USB_PD_FW_FLASH_HASH, + USB_PD_FW_ERASE_SIG, }; struct ec_params_usb_pd_fw_update { diff --git a/include/usb_pd.h b/include/usb_pd.h index 011c7244e5..7dfb2a73e5 100644 --- a/include/usb_pd.h +++ b/include/usb_pd.h @@ -126,7 +126,7 @@ enum pd_errors { #define VDO_CMD_REBOOT VDO_CMD_VENDOR(5) #define VDO_CMD_FLASH_ERASE VDO_CMD_VENDOR(6) #define VDO_CMD_FLASH_WRITE VDO_CMD_VENDOR(7) -#define VDO_CMD_FLASH_HASH VDO_CMD_VENDOR(8) +#define VDO_CMD_ERASE_SIG VDO_CMD_VENDOR(8) #define VDO_CMD_PING_ENABLE VDO_CMD_VENDOR(10) #define VDO_CMD_CURRENT VDO_CMD_VENDOR(11) diff --git a/util/ectool.c b/util/ectool.c index 04003b072c..4f79a11ece 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -856,16 +856,15 @@ int cmd_pd_device_info(int argc, char *argv[]) /* PD image size is 16k minus 32 bits for the RW hash */ -#define PD_RW_IMAGE_SIZE (16 * 1024 - 32) -static struct sha1_ctx ctx; +#define PD_RW_IMAGE_SIZE (16 * 1024) int cmd_flash_pd(int argc, char *argv[]) { struct ec_params_usb_pd_fw_update *p = (struct ec_params_usb_pd_fw_update *)ec_outbuf; int i; - int rv, fsize, step = 96, padding_size; + int rv, fsize, step = 96; char *e; - char *buf, *fw_padding; + char *buf; uint32_t *data = &(p->size) + 1; if (argc < 4) { @@ -892,21 +891,13 @@ int cmd_flash_pd(int argc, char *argv[]) return -1; /* Verify size of file */ - if (fsize > PD_RW_IMAGE_SIZE) + if (fsize != PD_RW_IMAGE_SIZE) goto pd_flash_error; - /* Add padding to image */ - padding_size = PD_RW_IMAGE_SIZE - fsize; - fw_padding = (char *)malloc(padding_size); - memset(fw_padding, 0xff, padding_size); - fprintf(stderr, "File size %d, Padding size %d\n", fsize, padding_size); - - /* Write expected flash hash to all 0s */ + /* Erase the current RW RSA signature */ fprintf(stderr, "Erasing expected RW hash\n"); - p->cmd = USB_PD_FW_FLASH_HASH; - p->size = 20; - for (i = 0; i < 5; i++) - *(data + i) = 0; + p->cmd = USB_PD_FW_ERASE_SIG; + p->size = 0; rv = ec_command(EC_CMD_USB_PD_FW_UPDATE, 0, p, p->size + sizeof(*p), NULL, 0); @@ -947,30 +938,6 @@ int cmd_flash_pd(int argc, char *argv[]) goto pd_flash_error; } - /* - * TODO(crosbug.com/p/31552): Would be better to have sha1 in the RW - * binary and we won't have to calculate it here and send it down. - */ - /* Calculate sha1 of new RW flash */ - sha1_init(&ctx); - sha1_update(&ctx, buf, fsize); - sha1_update(&ctx, fw_padding, padding_size); - sha1_final(&ctx); - - /* Write expected flash hash */ - fprintf(stderr, "Setting expected RW hash\n"); - p->cmd = USB_PD_FW_FLASH_HASH; - p->size = 20; - memcpy(data, ctx.buf.b, p->size); - for (i = 0; i < 5; i++) - fprintf(stderr, "%08x ", *(data + i)); - fprintf(stderr, "\n"); - rv = ec_command(EC_CMD_USB_PD_FW_UPDATE, 0, - p, p->size + sizeof(*p), NULL, 0); - - if (rv < 0) - goto pd_flash_error; - free(buf); fprintf(stderr, "Complete\n"); return 0; diff --git a/util/flash_pd.py b/util/flash_pd.py index 4190caa02e..f3e9aaeca9 100755 --- a/util/flash_pd.py +++ b/util/flash_pd.py @@ -5,12 +5,11 @@ """Flash PD PSU RW firmware over the USBPD comm channel using console. Example: - util/flash_pd.py ./build/zinger/ec.RW.flat + util/flash_pd.py ./build/zinger/ec.RW.bin """ import array import errno -import hashlib import logging import optparse import os @@ -24,13 +23,12 @@ import serial from servo import client from servo import multiservo -VERSION = '0.0.1' - -# RW area is half of the 32-kB flash minus the hash storage area -MAX_FW_SIZE = 16 * 1024 - 32 -# Hash of RW when erased (set to all F's) -ERASED_RW_HASH = 'd582e94d 0d12a61c 1199927e 5610c036 2e2870a9' +VERSION = '0.0.2' +# RW area is half of the 32-kB +MAX_FW_SIZE = 16 * 1024 +# 20 first bytes of SHA-256 of RW when erased (set to all F's) +ERASED_RW_HASH = 'd86670be 559860c7 2b2149e8 d2ae1104 9550e093' class FlashPDError(Exception): """Exception class for flash_pd utility.""" @@ -200,14 +198,10 @@ def flash_pd(options): with open(options.firmware) as fd: fw = fd.read() fw_size = len(fw) - # Compute SHA-1 hash for the full (padded) RW firmware - padded_fw = fw + '\xff' * (MAX_FW_SIZE - fw_size) - sha = hashlib.sha1(padded_fw).digest() - sha_str = ' '.join(['%08x' % (w) for w in array.array('I', sha)]) + # The RW firmware should be already padded and signed + if fw_size != MAX_FW_SIZE: + raise FlashPDError('Bad RW firmware size %d/%d' % (fw_size, MAX_FW_SIZE)) - # pad the firmware to a multiple of 6 U32 - if fw_size % 24: - fw += '\xff'*(24 - fw_size % 24) words = array.array('I', fw) logging.info('Current PD FW version is %s', ec.get_version()) @@ -216,31 +210,23 @@ def flash_pd(options): logging.info('Flashing %d bytes', fw_size) - # reset flashed hash to reboot in RO - ec.flash_command('hash' + ' 00000000' * 5) + # reset flashed signature to reboot in RO + ec.flash_command('signature') # reboot in RO ec.reboot() # erase all RW partition ec.flash_command('erase') - # TODO(tbroch) deprecate rw_hash if/when command is completely deprecated in - # favor of 'info' - # verify that erase was successful by reading hash empty RW - (done, _) = ec.flash_command('rw_hash', expect=ERASED_RW_HASH, retries=0, - ignore_fail=True) - if done: - done = ec.expect('DONE') - else: - # try info command and guarantee we're in RO - (done, line) = ec.flash_command('info', expect=r'INFO') - m = re.match(r'INFO.*(18d1\S{4})', line) - if done and m: - done = ec.expect('DONE 0') - in_rw = int(m.group(1), 16) & 0x1 - if in_rw: - raise FlashPDError('Not in RO after erase') - # Google UFP devices share their hash to DFP after info command so check it - (done, _) = ec.pd_command('hash', expect=ERASED_RW_HASH) + # try info command and guarantee we're in RO + (done, line) = ec.flash_command('info', expect=r'INFO') + m = re.match(r'INFO.*(18d1\S{4})', line) + if done and m: + done = ec.expect('DONE 0') + in_rw = int(m.group(1), 16) & 0x1 + if in_rw: + raise FlashPDError('Not in RO after erase') + # Google UFP devices share their hash to DFP after info command so check it + (done, _) = ec.pd_command('hash', expect=ERASED_RW_HASH) if not done: raise FlashPDError('Erase failed') @@ -259,14 +245,15 @@ def flash_pd(options): ec.flash_command(cmd) if not i % 0x10: logging.info('Chunk %d of %d done.', i, len(words) / 6) + # write the remaining words + chunk = words[len(words) / 6 * 6:] + cmd = ' '.join(['%08x' % (w) for w in chunk]) + ec.flash_command(cmd) - # write new firmware hash - ec.flash_command('hash ' + sha_str) # reboot in RW ec.reboot() logging.info('Flashing DONE.') - logging.info('SHA-1: %s', sha_str) logging.info('New PD FW version is %s', ec.get_version())