diff options
-rw-r--r-- | extra/usb_updater/usb_updater.c | 126 |
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); } |