From 80fa2da908d4f03b6f1bdf4da5876aff20af88cb Mon Sep 17 00:00:00 2001 From: Randall Spangler Date: Tue, 19 Jun 2012 16:22:26 -0700 Subject: [PATCH] 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 Change-Id: I51bbf997f6b7f94fe61f06a8a1804c3cc5c319b8 Reviewed-on: https://gerrit.chromium.org/gerrit/25791 Reviewed-by: Hung-Te Lin Reviewed-by: Simon Glass --- common/system_common.c | 114 +++++++++++++++++++++++------------------ common/vboot.c | 4 +- include/ec_commands.h | 35 ++++++++++--- include/system.h | 6 +-- util/burn_my_ec.c | 4 +- util/ectool.c | 57 ++++++++++++--------- 6 files changed, 130 insertions(+), 90 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; + struct ec_params_reboot_ec *p = (struct ec_params_reboot_ec *)data; - /* 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; + 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 @@ -599,6 +599,33 @@ struct ec_params_switch_enable_wireless { uint8_t enabled; } __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 * @@ -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 \n" " Reads a pattern from the EC via LPC\n" - " reboot_ec \n" + " reboot_ec [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]); - return -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); + } - rv = ec_command(EC_CMD_REBOOT_EC, - &p, sizeof(p), NULL, 0); - } else { - fprintf(stderr, "Wrong argument count: %d\n", argc); + /* 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; } - if (rv) - return rv; + /* 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; + } + } - printf("done.\n"); - return 0; + return ec_command(EC_CMD_REBOOT_EC, &p, sizeof(p), NULL, 0); }