summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Bendebury <vbendeb@chromium.org>2017-03-21 10:30:02 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2017-09-08 22:17:03 +0000
commit6b55b822906b12e06738cb375a899885094e4519 (patch)
treecd36c274cf93f98618a7d92d3b191f24db30153c
parenta4833434c9c2ed8d4a030e5f303bc785a7c40025 (diff)
downloadchrome-ec-6b55b822906b12e06738cb375a899885094e4519.tar.gz
usb_updater: separate image updates and resets, add restore image option
With the upcoming availability of the downloaded header corruption, there needs to be a mechanism for usb_updater to restore the corrupted header, so that the downloaded code can run right away. This patch separates image download and reset functionality. Download happens as before, and the UPGRADE_DONE PDU is sent immediately once image transfer completes. This puts the receive state machine into the idle state and allows to send other commands. The reset function is different for the target supporting protocol versions 5 and above. The only command version 5 recognizes is the indirect reboot command (the UPGRADE_DONE PDU sent the second time in a row). For protocol version 6 and above the reset could be immediate or posted, and for targets running RW version 19 or above the command to restore the corrupted header is required. When running on the target the command to restore the corrupted header would be generated by the AP firmware on the reboot. BRANCH=cr50 BUG=b:35580805 TEST=with the next patch of the series applied observed the corrupted header properly restored and the device rebooted. Change-Id: If87c12fe8578cd6f1b4beed6d113471356f6b6c2 Signed-off-by: Vadim Bendebury <vbendeb@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/457677 Reviewed-by: Aaron Durbin <adurbin@chromium.org> (cherry picked from commit 218f65dda650e775b9e28e5dee9704f6511e8a28) Reviewed-on: https://chromium-review.googlesource.com/658341 Commit-Queue: Philip Chen <philipchen@chromium.org> Tested-by: Philip Chen <philipchen@chromium.org>
-rw-r--r--extra/usb_updater/usb_updater.c126
1 files changed, 64 insertions, 62 deletions
diff --git a/extra/usb_updater/usb_updater.c b/extra/usb_updater/usb_updater.c
index f4e98978ea..b69ce22567 100644
--- a/extra/usb_updater/usb_updater.c
+++ b/extra/usb_updater/usb_updater.c
@@ -1003,8 +1003,6 @@ static void invalidate_inactive_rw(struct transfer_descriptor *td)
uint16_t subcommand = VENDOR_CC_INVALIDATE_INACTIVE_RW;
if (td->ep_type == usb_xfer) {
- send_done(&td->uep);
-
if (protocol_version > 5) {
ext_cmd_over_usb(&td->uep, subcommand,
NULL, 0,
@@ -1015,13 +1013,11 @@ static void invalidate_inactive_rw(struct transfer_descriptor *td)
}
/* Returns number of successfully transmitted image sections. */
-static int transfer_and_reboot(struct transfer_descriptor *td,
+static int transfer_image(struct transfer_descriptor *td,
uint8_t *data, size_t data_len)
{
size_t i;
- int num_txed_secitons = 0;
- /* By default target is reset immediately after update. */
- uint16_t subcommand = VENDOR_CC_IMMEDIATE_RESET;
+ int num_txed_sections = 0;
for (i = 0; i < ARRAY_SIZE(sections); i++)
if (sections[i].ustatus == needed) {
@@ -1029,69 +1025,77 @@ static int transfer_and_reboot(struct transfer_descriptor *td,
data + sections[i].offset,
sections[i].offset,
sections[i].size);
- num_txed_secitons++;
+ num_txed_sections++;
}
- if (!num_txed_secitons) {
- if (td->ep_type == usb_xfer)
- send_done(&td->uep);
-
- printf("nothing to do\n");
- return 0;
- }
-
- printf("-------\nupdate complete\n");
-
/*
- * In upstart mode, or in case the user explicitly wants it, request
- * post reset instead of immediate reset. In this case the h1 will
- * reset next time the target reboots, and will consider running the
- * uploaded code.
+ * Move USB receiver sate machine to idle state so that vendor
+ * commands can be processed later, if any.
*/
- if (td->upstart_mode || td->post_reset)
- subcommand = EXTENSION_POST_RESET;
-
- if (td->ep_type == usb_xfer) {
- uint32_t out;
-
+ if (td->ep_type == usb_xfer)
send_done(&td->uep);
- if (protocol_version > 5) {
- uint8_t response;
- size_t response_size;
- void *presponse;
+ if (!num_txed_sections)
+ printf("nothing to do\n");
+ else
+ printf("-------\nupdate complete\n");
+ return num_txed_sections;
+}
- /*
- * Protocol versions 6 and above use vendor command to
- * communicate reset mode (immediate or posted) to the
- * target.
- *
- * No response is expected in case of immediate reset.
- */
- if (subcommand == VENDOR_CC_IMMEDIATE_RESET) {
- presponse = NULL;
- response_size = 0;
- } else {
- presponse = &response;
- response_size = sizeof(response);
- }
+static void generate_reset_request(struct transfer_descriptor *td)
+{
+ size_t response_size;
+ uint8_t response;
+ uint16_t subcommand;
+ uint8_t command_body[2]; /* Max command body size. */
+ size_t command_body_size;
- ext_cmd_over_usb(&td->uep, subcommand,
- NULL, 0,
- presponse, &response_size);
- } else {
+ if (protocol_version < 6) {
+ if (td->ep_type == usb_xfer) {
/*
* Send a second stop request, which should reboot
* without replying.
*/
- xfer(&td->uep, &out, sizeof(out), 0, 0);
+ send_done(&td->uep);
}
+ /* Nothing we can do over /dev/tpm0 running versions below 6. */
+ return;
+ }
+
+ /*
+ * If the user explicitly wants it, request post reset instead of
+ * immediate reset. In this case next time the target reboots, the h1
+ * will reboot as well, and will consider running the uploaded code.
+ *
+ * In case target RW version is 19 or above, to reset the target the
+ * host is supposed to send the command to enable the uploaded image
+ * disabled by default.
+ *
+ * Otherwise the immediate reset command would suffice.
+ */
+ /* Most common case. */
+ command_body_size = 0;
+ response_size = 1;
+ if (td->post_reset) {
+ subcommand = EXTENSION_POST_RESET;
+ } else if (targ.shv[1].minor >= 19) {
+ subcommand = VENDOR_CC_TURN_UPDATE_ON;
+ command_body_size = sizeof(command_body);
+ command_body[0] = 0;
+ command_body[1] = 100; /* Reset in 100 ms. */
+ } else {
+ response_size = 0;
+ subcommand = VENDOR_CC_IMMEDIATE_RESET;
+ }
+ if (td->ep_type == usb_xfer) {
+ ext_cmd_over_usb(&td->uep, subcommand,
+ command_body, command_body_size,
+ &response, &response_size);
} else {
- uint8_t response;
- size_t response_size;
- /* Need to send extended command for posted reboot. */
- if (tpm_send_pkt(td->tpm_fd, 0, 0, NULL, 0,
+ /* Need to send extended command for reboot. */
+ if (tpm_send_pkt(td->tpm_fd, 0, 0,
+ command_body, command_body_size,
&response, &response_size, subcommand) < 0) {
fprintf(stderr, "Failed to request posted reboot\n");
exit(update_error);
@@ -1101,8 +1105,6 @@ static int transfer_and_reboot(struct transfer_descriptor *td,
printf("reboot %s\n", subcommand == EXTENSION_POST_RESET ?
"request posted" : "triggered");
-
- return num_txed_secitons;
}
static int show_headers_versions(const void *image)
@@ -1254,17 +1256,17 @@ int main(int argc, char *argv[])
targ.shv[1].minor);
}
- if (corrupt_inactive_rw)
- invalidate_inactive_rw(&td);
-
if (data) {
- transferred_sections = transfer_and_reboot(&td, data, data_len);
+ transferred_sections = transfer_image(&td, data, data_len);
free(data);
+
+ if (transferred_sections && !td.upstart_mode)
+ generate_reset_request(&td);
+ } else if (corrupt_inactive_rw) {
+ invalidate_inactive_rw(&td);
}
if (td.ep_type == usb_xfer) {
- if (!data && !corrupt_inactive_rw)
- send_done(&td.uep);
libusb_close(td.uep.devh);
libusb_exit(NULL);
}