summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Boichat <drinkcat@google.com>2017-03-22 16:41:34 +0800
committerchrome-bot <chrome-bot@chromium.org>2017-04-26 04:28:07 -0700
commit7f6176dc5502dc4d6b166ab2c7c90209220e82ff (patch)
tree8d9e82ff5971b11f5ed5d102fa4ce72c5faa1736
parentacb397063002fec38979c56ae6d7219dd04c1412 (diff)
downloadchrome-ec-7f6176dc5502dc4d6b166ab2c7c90209220e82ff.tar.gz
common/usb_update: add support for extra commands
Add support for 4 extra commands that are required to update hammer: - UPDATE_EXTRA_CMD_IMMEDIATE_RESET - UPDATE_EXTRA_CMD_JUMP_TO_RW: Tells the RWSIG task to jump to RW as soon as possible (assuming the image verifies) - UPDATE_EXTRA_CMD_STAY_IN_RO: Tells the RWSIG task to not jump to RW, and stay in RO, to leave enough time for AP to update RW. - UPDATE_EXTRA_CMD_UNLOCK_RW: Tells EC to unlock the RW section so that it can be updated (on next reboot). BRANCH=none BUG=b:35587171 TEST=Test RO+RW update cd extra/usb_updater; make # Jump to RW sudo ./usb_updater2 -j sleep 0.5 # Update RO, then reboot sudo ./usb_updater2 ../../build/hammer/ec.bin sleep 0.5 # Update RW (first tell RO to not jump to RW) sudo ./usb_updater2 -s sudo ./usb_updater2 ../../build/hammer/ec.bin TEST=Test RW update only, with RO protected On EC console: flashwp true; reboot cd extra/usb_updater; make # Tell RW to unprotect RW and jump back to RO sudo ./usb_updater2 -w sudo ./usb_updater2 -r sleep 0.5 # Update RW, then reboot sudo ./usb_updater2 -s sudo ./usb_updater2 ../../build/hammer/ec.bin Change-Id: I5e8df7bdb4f06f2ac7b47de53dcde69c5002f578 Reviewed-on: https://chromium-review.googlesource.com/458470 Commit-Ready: Nicolas Boichat <drinkcat@chromium.org> Tested-by: Nicolas Boichat <drinkcat@chromium.org> Reviewed-by: Nicolas Boichat <drinkcat@chromium.org>
-rw-r--r--common/usb_update.c97
-rw-r--r--include/update_fw.h8
2 files changed, 103 insertions, 2 deletions
diff --git a/common/usb_update.c b/common/usb_update.c
index cf1f205763..cf5850e53d 100644
--- a/common/usb_update.c
+++ b/common/usb_update.c
@@ -8,7 +8,10 @@
#include "console.h"
#include "consumer.h"
#include "extension.h"
+#include "flash.h"
#include "queue_policies.h"
+#include "host_command.h"
+#include "rwsig.h"
#include "system.h"
#include "update_fw.h"
#include "usb-stream.h"
@@ -109,8 +112,98 @@ static int fetch_transfer_start(struct consumer const *consumer, size_t count,
static int try_vendor_command(struct consumer const *consumer, size_t count)
{
- /* TODO(b/35587171): Vendor commands not implemented (yet). */
- return 0;
+ char buffer[USB_MAX_PACKET_SIZE];
+ struct update_frame_header *cmd_buffer = (void *)buffer;
+ int rv = 0;
+
+ /* Validate count (too short, or too long). */
+ if (count < sizeof(*cmd_buffer) || count > sizeof(buffer))
+ return 0;
+
+ /*
+ * Let's copy off the queue the update frame header, to see if this
+ * is a channeled vendor command.
+ */
+ queue_peek_units(consumer->queue, cmd_buffer, 0, sizeof(*cmd_buffer));
+ if (be32toh(cmd_buffer->cmd.block_base) != UPDATE_EXTRA_CMD)
+ return 0;
+
+ if (be32toh(cmd_buffer->block_size) != count) {
+ CPRINTS("%s: problem: block size and count mismatch (%d != %d)",
+ __func__, be32toh(cmd_buffer->block_size), count);
+ return 0;
+ }
+
+ /* Get the entire command, don't remove it from the queue just yet. */
+ queue_peek_units(consumer->queue, cmd_buffer, 0, count);
+
+ /* Looks like this is a vendor command, let's verify it. */
+ if (update_pdu_valid(&cmd_buffer->cmd,
+ count - offsetof(struct update_frame_header, cmd))) {
+ enum update_extra_command subcommand;
+ uint16_t response;
+ size_t response_size = sizeof(response);
+
+ /* looks good, let's process it. */
+ rv = 1;
+
+ /* Now remove it from the queue. */
+ queue_advance_head(consumer->queue, count);
+
+ subcommand = be16toh(*((uint16_t *)(cmd_buffer + 1)));
+
+ switch (subcommand) {
+ case UPDATE_EXTRA_CMD_IMMEDIATE_RESET:
+ CPRINTS("Rebooting!\n\n\n");
+ cflush();
+ system_reset(SYSTEM_RESET_MANUALLY_TRIGGERED);
+ /* Unreachable, unless something bad happens. */
+ response = EC_RES_ERROR;
+ break;
+ case UPDATE_EXTRA_CMD_JUMP_TO_RW:
+#ifdef CONFIG_RWSIG
+ /*
+ * Tell rwsig task to jump to RW. This does nothing if
+ * verification failed, and will only jump later on if
+ * verification is still in progress.
+ */
+ rwsig_continue();
+
+ switch (rwsig_get_status()) {
+ case RWSIG_VALID:
+ response = EC_RES_SUCCESS;
+ break;
+ case RWSIG_INVALID:
+ response = EC_RES_INVALID_CHECKSUM;
+ break;
+ case RWSIG_IN_PROGRESS:
+ response = EC_RES_IN_PROGRESS;
+ break;
+ default:
+ response = EC_RES_ERROR;
+ }
+#else
+ system_run_image_copy(SYSTEM_IMAGE_RW);
+#endif
+ break;
+#ifdef CONFIG_RWSIG
+ case UPDATE_EXTRA_CMD_STAY_IN_RO:
+ rwsig_abort();
+ response = EC_RES_SUCCESS;
+ break;
+ case UPDATE_EXTRA_CMD_UNLOCK_RW:
+ flash_set_protect(EC_FLASH_PROTECT_RW_AT_BOOT, 0);
+ response = EC_RES_SUCCESS;
+ break;
+#endif
+ default:
+ response = EC_RES_INVALID_COMMAND;
+ }
+
+ QUEUE_ADD_UNITS(&update_to_usb, &response, response_size);
+ }
+
+ return rv;
}
/*
diff --git a/include/update_fw.h b/include/update_fw.h
index 115b34d35c..e575500b19 100644
--- a/include/update_fw.h
+++ b/include/update_fw.h
@@ -154,6 +154,14 @@ enum first_response_pdu_header_type {
/* TODO: Handle this in update_fw.c, not usb_update.c */
#define UPDATE_DONE 0xB007AB1E
+#define UPDATE_EXTRA_CMD 0xB007AB1F
+
+enum update_extra_command {
+ UPDATE_EXTRA_CMD_IMMEDIATE_RESET = 0,
+ UPDATE_EXTRA_CMD_JUMP_TO_RW = 1,
+ UPDATE_EXTRA_CMD_STAY_IN_RO = 2,
+ UPDATE_EXTRA_CMD_UNLOCK_RW = 3,
+};
void fw_update_command_handler(void *body,
size_t cmd_size,