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>
This commit is contained in:
Randall Spangler
2012-06-19 16:22:26 -07:00
committed by Gerrit
parent 50ea753bbb
commit 80fa2da908
6 changed files with 130 additions and 90 deletions

View File

@@ -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);

View File

@@ -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:

View File

@@ -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 */

View File

@@ -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

View File

@@ -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 */

View File

@@ -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]);
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);
}