summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2012-06-19 16:22:26 -0700
committerGerrit <chrome-bot@google.com>2012-06-20 23:30:02 -0700
commit80fa2da908d4f03b6f1bdf4da5876aff20af88cb (patch)
tree37404f6d52e6070d28b1101b20b2d4e294fc5ae5
parent50ea753bbbd537fd38062899651027c185937be4 (diff)
downloadchrome-ec-80fa2da908d4f03b6f1bdf4da5876aff20af88cb.tar.gz
Add reboot-at-shutdown flag
Also removes unused recovery request, since AP handles that internally now. BUG=chrome-os-partner:10685 TEST=manual. From root shell, ectool reboot_ec RO -> EC reboots to RO, AP stays up ectool reboot_ec A -> EC reboots to A, AP stays up ectool reboot_ec cold -> EC reboots, AP shuts down ectool reboot_ec cold at-shutdown -> (EC stores request, but doesn't reboot) shutdown -P now -> EC reboots when AP shuts down ectool reboot_ec cold at-shutdown -> (EC stores request, but doesn't reboot) ectool reboot_ec cancel -> (EC stores cancel-request) shutdown -P now -> AP shuts down, but EC doesn't reboot Signed-off-by: Randall Spangler <rspangler@chromium.org> Change-Id: I51bbf997f6b7f94fe61f06a8a1804c3cc5c319b8 Reviewed-on: https://gerrit.chromium.org/gerrit/25791 Reviewed-by: Hung-Te Lin <hungte@chromium.org> Reviewed-by: Simon Glass <sjg@chromium.org>
-rw-r--r--common/system_common.c116
-rw-r--r--common/vboot.c4
-rw-r--r--include/ec_commands.h35
-rw-r--r--include/system.h6
-rw-r--r--util/burn_my_ec.c4
-rw-r--r--util/ectool.c59
6 files changed, 132 insertions, 92 deletions
diff --git a/common/system_common.c b/common/system_common.c
index 1ffef0175a..8952a455ff 100644
--- a/common/system_common.c
+++ b/common/system_common.c
@@ -8,12 +8,12 @@
#include "board.h"
#include "clock.h"
#include "console.h"
+#include "ec_commands.h"
#include "flash.h"
#include "gpio.h"
#include "hooks.h"
#include "host_command.h"
#include "lpc.h"
-#include "ec_commands.h"
#include "system.h"
#include "task.h"
#include "uart.h"
@@ -42,8 +42,8 @@ struct jump_data {
* be the last word in RAM regardless of how many fields are added. */
/* Fields from version 3 */
- uint8_t recovery_required; /* Signal recovery mode to BIOS */
- int struct_size; /* Size of struct jump_data */
+ uint8_t reserved0; /* (used in proto1 to signal recovery mode) */
+ int struct_size; /* Size of struct jump_data */
/* Fields from version 2 */
int jump_tag_total; /* Total size of all jump tags */
@@ -65,7 +65,7 @@ static const char * const image_names[] = {"unknown", "RO", "A", "B"};
static enum system_reset_cause_t reset_cause = SYSTEM_RESET_UNKNOWN;
static int jumped_to_image;
static int disable_jump;
-
+static enum ec_reboot_cmd reboot_at_shutdown;
int system_is_locked(void)
{
@@ -109,12 +109,6 @@ enum system_reset_cause_t system_get_reset_cause(void)
}
-int system_get_recovery_required(void)
-{
- return jdata->recovery_required;
-}
-
-
int system_jumped_to_this_image(void)
{
return jumped_to_image;
@@ -256,8 +250,7 @@ const char *system_get_image_copy_string(void)
/* Jump to what we hope is the init address of an image. This function does
* not return. */
-static void jump_to_image(uint32_t init_addr,
- int recovery_required)
+static void jump_to_image(uint32_t init_addr)
{
void (*resetvec)(void) = (void(*)(void))init_addr;
@@ -278,7 +271,7 @@ static void jump_to_image(uint32_t init_addr,
interrupt_disable();
/* Fill in preserved data between jumps */
- jdata->recovery_required = recovery_required != 0;
+ jdata->reserved0 = 0;
jdata->magic = JUMP_DATA_MAGIC;
jdata->version = JUMP_DATA_VERSION;
jdata->reset_cause = reset_cause;
@@ -328,8 +321,7 @@ static uint32_t get_size(enum system_image_copy_t copy)
}
-int system_run_image_copy(enum system_image_copy_t copy,
- int recovery_required)
+int system_run_image_copy(enum system_image_copy_t copy)
{
uint32_t base;
uint32_t init_addr;
@@ -367,7 +359,7 @@ int system_run_image_copy(enum system_image_copy_t copy,
CPRINTF("[%T Jumping to image %s]\n", image_names[copy]);
- jump_to_image(init_addr, recovery_required);
+ jump_to_image(init_addr);
/* Should never get here */
return EC_ERROR_UNKNOWN;
@@ -480,7 +472,7 @@ int system_common_pre_init(void)
/* Initialize fields added after version 2 */
if (jdata->version < 3)
- jdata->recovery_required = 0;
+ jdata->reserved0 = 0;
/* Struct size is now the current struct size */
jdata->struct_size = sizeof(struct jump_data);
@@ -497,6 +489,36 @@ int system_common_pre_init(void)
return EC_SUCCESS;
}
+/* Handle a pending reboot command */
+static int handle_pending_reboot(enum ec_reboot_cmd cmd)
+{
+ switch (cmd) {
+ case EC_REBOOT_CANCEL:
+ return EC_SUCCESS;
+ case EC_REBOOT_JUMP_RO:
+ return system_run_image_copy(SYSTEM_IMAGE_RO);
+ case EC_REBOOT_JUMP_RW_A:
+ return system_run_image_copy(SYSTEM_IMAGE_RW_A);
+ case EC_REBOOT_JUMP_RW_B:
+ return system_run_image_copy(SYSTEM_IMAGE_RW_B);
+ case EC_REBOOT_COLD:
+ system_reset(1);
+ /* That shouldn't return... */
+ return EC_ERROR_UNKNOWN;
+ default:
+ return EC_ERROR_INVAL;
+ }
+}
+
+/*****************************************************************************/
+/* Hooks */
+
+static int system_common_shutdown(void)
+{
+ return handle_pending_reboot(reboot_at_shutdown);
+}
+DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, system_common_shutdown, HOOK_PRIO_DEFAULT);
+
/*****************************************************************************/
/* Console commands */
@@ -596,11 +618,11 @@ static int command_sysjump(int argc, char **argv)
/* Handle named images */
if (!strcasecmp(argv[1], "RO"))
- return system_run_image_copy(SYSTEM_IMAGE_RO, 0);
+ return system_run_image_copy(SYSTEM_IMAGE_RO);
else if (!strcasecmp(argv[1], "A"))
- return system_run_image_copy(SYSTEM_IMAGE_RW_A, 0);
+ return system_run_image_copy(SYSTEM_IMAGE_RW_A);
else if (!strcasecmp(argv[1], "B"))
- return system_run_image_copy(SYSTEM_IMAGE_RW_B, 0);
+ return system_run_image_copy(SYSTEM_IMAGE_RW_B);
/* Check for arbitrary address */
addr = strtoi(argv[1], &e, 0);
@@ -609,7 +631,7 @@ static int command_sysjump(int argc, char **argv)
ccprintf("Jumping to 0x%08x\n", addr);
cflush();
- jump_to_image(addr, 0);
+ jump_to_image(addr);
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(sysjump, command_sysjump,
@@ -717,29 +739,20 @@ DECLARE_HOST_COMMAND(EC_CMD_GET_BOARD_VERSION, host_command_get_board_version);
int host_command_reboot(uint8_t *data, int *resp_size)
{
- enum system_image_copy_t copy;
- struct ec_params_reboot_ec *p = (struct ec_params_reboot_ec *)data;
- int recovery_request = p->reboot_flags & EC_CMD_REBOOT_BIT_RECOVERY;
-
- /* This command is only allowed on unlocked systems, because jumping
- * directly to another image bypasses verified boot. */
- if (system_is_locked())
- return EC_RES_ACCESS_DENIED;
-
- switch (p->target) {
- case EC_IMAGE_RO:
- copy = SYSTEM_IMAGE_RO;
- break;
- case EC_IMAGE_RW_A:
- copy = SYSTEM_IMAGE_RW_A;
- break;
- case EC_IMAGE_RW_B:
- copy = SYSTEM_IMAGE_RW_B;
- break;
- default:
- return EC_RES_ERROR;
+ struct ec_params_reboot_ec *p = (struct ec_params_reboot_ec *)data;
+
+ if (p->cmd == EC_REBOOT_CANCEL) {
+ /* Cancel pending reboot */
+ reboot_at_shutdown = EC_REBOOT_CANCEL;
+ return EC_RES_SUCCESS;
+ } else if (p->flags & EC_REBOOT_FLAG_ON_AP_SHUTDOWN) {
+ /* Store request for processing at chipset shutdown */
+ reboot_at_shutdown = p->cmd;
+ return EC_RES_SUCCESS;
}
+ /* TODO: (crosbug.com/p/9040) handle EC_REBOOT_FLAG_POWER_ON */
+
#ifdef CONFIG_TASK_HOSTCMD
#ifdef CONFIG_LPC
/* Clean busy bits on host */
@@ -751,14 +764,15 @@ int host_command_reboot(uint8_t *data, int *resp_size)
#endif
CPUTS("[Executing host reboot command]\n");
- system_run_image_copy(copy, recovery_request);
-
- /* We normally never get down here, because we'll have jumped to
- * another image. To confirm this command worked, the host will need
- * to check what image is current using GET_VERSION.
- *
- * If we DO get down here, something went wrong in the reboot, so
- * return error. */
- return EC_RES_ERROR;
+ switch (handle_pending_reboot(p->cmd)) {
+ case EC_SUCCESS:
+ return EC_RES_SUCCESS;
+ case EC_ERROR_INVAL:
+ return EC_RES_INVALID_PARAM;
+ case EC_ERROR_ACCESS_DENIED:
+ return EC_RES_ACCESS_DENIED;
+ default:
+ return EC_RES_ERROR;
+ }
}
DECLARE_HOST_COMMAND(EC_CMD_REBOOT_EC, host_command_reboot);
diff --git a/common/vboot.c b/common/vboot.c
index efd5651880..c5c0243f6b 100644
--- a/common/vboot.c
+++ b/common/vboot.c
@@ -154,7 +154,7 @@ int vboot_init(void)
switch (r) {
case IMAGE_IS_GOOD:
CPRINTF("[Image A verified]\n");
- system_run_image_copy(SYSTEM_IMAGE_RW_A, 0);
+ system_run_image_copy(SYSTEM_IMAGE_RW_A);
CPRINTF("[ERROR: Unable to jump to image A]\n");
goto bad;
case IMAGE_IS_GOOD_BUT_USE_RO_ANYWAY:
@@ -182,7 +182,7 @@ int vboot_init(void)
switch (r) {
case IMAGE_IS_GOOD:
CPRINTF("[Image B verified]\n");
- system_run_image_copy(SYSTEM_IMAGE_RW_B, 0);
+ system_run_image_copy(SYSTEM_IMAGE_RW_B);
CPRINTF("[ERROR: Unable to jump to image B]\n");
goto bad;
case IMAGE_IS_GOOD_BUT_USE_RO_ANYWAY:
diff --git a/include/ec_commands.h b/include/ec_commands.h
index 6690522e88..02ad07eb20 100644
--- a/include/ec_commands.h
+++ b/include/ec_commands.h
@@ -600,6 +600,33 @@ struct ec_params_switch_enable_wireless {
} __attribute__ ((packed));
/*****************************************************************************/
+/* System commands */
+
+/* TODO: this is a confusing name, since it doesn't necessarily reboot the EC.
+ * Rename to "set image" or something similar. */
+#define EC_CMD_REBOOT_EC 0xd2
+
+/* Command */
+enum ec_reboot_cmd {
+ EC_REBOOT_CANCEL = 0, /* Cancel a pending reboot */
+ EC_REBOOT_JUMP_RO, /* Jump to RO without rebooting */
+ EC_REBOOT_JUMP_RW_A, /* Jump to RW-A without rebooting */
+ EC_REBOOT_JUMP_RW_B, /* Jump to RW-B without rebooting */
+ EC_REBOOT_COLD, /* Cold-reboot */
+};
+
+/* Flags for ec_params_reboot_ec.reboot_flags */
+#define EC_REBOOT_FLAG_RESERVED0 (1 << 0) /* Was recovery request */
+#define EC_REBOOT_FLAG_ON_AP_SHUTDOWN (1 << 1)
+#define EC_REBOOT_FLAG_POWER_ON (1 << 2)
+
+struct ec_params_reboot_ec {
+ uint8_t cmd; /* enum ec_reboot_cmd */
+ uint8_t flags; /* See EC_REBOOT_FLAG_* */
+} __attribute__ ((packed));
+
+
+/*****************************************************************************/
/* Special commands
*
* These do not follow the normal rules for commands. See each command for
@@ -620,14 +647,6 @@ struct ec_params_switch_enable_wireless {
* command. */
#define EC_CMD_REBOOT 0xd1 /* Think "die" */
-#define EC_CMD_REBOOT_EC 0xd2
-#define EC_CMD_REBOOT_BIT_RECOVERY (1 << 0)
-
-struct ec_params_reboot_ec {
- uint8_t target; /* enum ec_current_image */
- uint8_t reboot_flags;
-} __attribute__ ((packed));
-
#endif /* !__ACPI__ */
#endif /* __CROS_EC_COMMANDS_H */
diff --git a/include/system.h b/include/system.h
index fb9c802b8f..25d8232f1f 100644
--- a/include/system.h
+++ b/include/system.h
@@ -45,9 +45,6 @@ int system_common_pre_init(void);
* the cause is not known. */
enum system_reset_cause_t system_get_reset_cause(void);
-/* Return a Boolean indicating if BIOS should come up in recovery mode */
-int system_get_recovery_required(void);
-
/* Record the cause of the last reset. */
void system_set_reset_cause(enum system_reset_cause_t cause);
@@ -97,8 +94,7 @@ int system_unsafe_to_overwrite(uint32_t offset, uint32_t size);
const char *system_get_image_copy_string(void);
/* Jump to the specified image copy. */
-int system_run_image_copy(enum system_image_copy_t copy,
- int recovery_request);
+int system_run_image_copy(enum system_image_copy_t copy);
/* Return the version string for an image copy, or an empty string if
* error. If copy==SYSTEM_IMAGE_UNKNOWN, returns the version for the
diff --git a/util/burn_my_ec.c b/util/burn_my_ec.c
index cb8ead87ac..522f461e62 100644
--- a/util/burn_my_ec.c
+++ b/util/burn_my_ec.c
@@ -66,8 +66,8 @@ int flash_partition(enum ec_current_image part, const uint8_t *payload,
current = get_version();
if (current == part) {
- rst_req.target = part == EC_IMAGE_RO ?
- EC_IMAGE_RW_A : EC_IMAGE_RO;
+ rst_req.cmd = part == EC_IMAGE_RO ?
+ EC_REBOOT_JUMP_RW_A : EC_REBOOT_JUMP_RO;
ec_command(EC_CMD_REBOOT_EC, &rst_req, sizeof(rst_req),
NULL, 0);
/* wait EC reboot */
diff --git a/util/ectool.c b/util/ectool.c
index 6942f9f9ab..cd1b3a293f 100644
--- a/util/ectool.c
+++ b/util/ectool.c
@@ -83,7 +83,7 @@ const char help_str[] =
" Does an ACPI Query Embedded Controller command\n"
" readtest <patternoffset> <size>\n"
" Reads a pattern from the EC via LPC\n"
- " reboot_ec <RO|A|B>\n"
+ " reboot_ec <RO|A|B> [at-shutdown]\n"
" Reboot EC to RO or RW A/B\n"
" sertest\n"
" Serial output test for COM2\n"
@@ -327,38 +327,49 @@ int cmd_read_test(int argc, char *argv[])
return 0;
}
+
int cmd_reboot_ec(int argc, char *argv[])
{
struct ec_params_reboot_ec p;
- int rv;
+ int i;
if (argc < 2) {
- rv = ec_command(EC_CMD_REBOOT, NULL, 0, NULL, 0);
- } else if (argc == 2) {
- if (!strcmp(argv[1], "RO")) {
- p.target = EC_IMAGE_RO;
- } else if (!strcmp(argv[1], "A")) {
- p.target = EC_IMAGE_RW_A;
- } else if (!strcmp(argv[1], "B")) {
- p.target = EC_IMAGE_RW_B;
- } else {
- fprintf(stderr,
- "Not supported firmware copy: %s\n", argv[1]);
+ /*
+ * No params specified so tell the EC to reboot immediately.
+ * That reboots the AP as well, so unlikely we'll be around
+ * to see a return code from this...
+ */
+ return ec_command(EC_CMD_REBOOT, NULL, 0, NULL, 0);
+ }
+
+ /* Parse command */
+ if (!strcmp(argv[1], "cancel"))
+ p.cmd = EC_REBOOT_CANCEL;
+ else if (!strcmp(argv[1], "RO"))
+ p.cmd = EC_REBOOT_JUMP_RO;
+ else if (!strcmp(argv[1], "A"))
+ p.cmd = EC_REBOOT_JUMP_RW_A;
+ else if (!strcmp(argv[1], "B"))
+ p.cmd = EC_REBOOT_JUMP_RW_B;
+ else if (!strcmp(argv[1], "cold"))
+ p.cmd = EC_REBOOT_COLD;
+ else {
+ fprintf(stderr, "Unknown command: %s\n", argv[1]);
+ return -1;
+ }
+
+ /* Parse flags, if any */
+ p.flags = 0;
+ for (i = 2; i < argc; i++) {
+ if (!strcmp(argv[i], "at-shutdown"))
+ p.flags |= EC_REBOOT_FLAG_ON_AP_SHUTDOWN;
+ else {
+ fprintf(stderr, "Unknown flag: %s\n", argv[i]);
return -1;
}
-
- rv = ec_command(EC_CMD_REBOOT_EC,
- &p, sizeof(p), NULL, 0);
- } else {
- fprintf(stderr, "Wrong argument count: %d\n", argc);
- return -1;
}
- if (rv)
- return rv;
-
- printf("done.\n");
- return 0;
+ return ec_command(EC_CMD_REBOOT_EC, &p, sizeof(p), NULL, 0);
}