summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Bendebury <vbendeb@chromium.org>2012-04-26 17:37:38 -0700
committerVadim Bendebury <vbendeb@chromium.org>2012-04-30 15:36:41 -0700
commit0467763f5a75125d734e7ed20e2a18c41aae26bf (patch)
tree6f39c7a13d2023c5ed0012186d4f416322dbd103
parenta5027ece4cb02a736db3db1e971bffd699422dec (diff)
downloadchrome-ec-0467763f5a75125d734e7ed20e2a18c41aae26bf.tar.gz
Enhance LPC EC REBOOT reset command to allow to request recovery
When the host reboots the EC it should be able to request the EC to force recovery mode after reset. This is achieved by extending the REBOOT EC command with a bitmask byte, with bit 0 dedicated to recovery request. So, when BIOS on the way up determines that recovery is requested, but the EC is not running from the RO space, the BIOS would reset the EC forcing it to run from RO and to request recovery mode through the LPC bitmask. Then BIOS will restart itself ensuring that the system comes up in consistent state. Some refactoring was also done to make the code a bit more compact. BUG=chrome-os-partner:9040 TEST=manual . tested along with coreboot changes (test described in the coerboot CL). Change-Id: I29801b6aec80da0901ba0e8db8e92e615cc778bd Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
-rw-r--r--chip/lm4/power_button.c4
-rw-r--r--common/system_common.c60
-rw-r--r--common/vboot.c2
-rw-r--r--include/lpc_commands.h3
-rw-r--r--include/system.h8
5 files changed, 55 insertions, 22 deletions
diff --git a/chip/lm4/power_button.c b/chip/lm4/power_button.c
index f037cb2139..f6597d30d5 100644
--- a/chip/lm4/power_button.c
+++ b/chip/lm4/power_button.c
@@ -92,6 +92,10 @@ static void update_other_switches(void)
else
*memmap_switches &= ~EC_LPC_SWITCH_DEDICATED_RECOVERY;
+ /* Was this a reboot requesting recovery? */
+ if (system_get_recovery_required())
+ *memmap_switches |= EC_LPC_SWITCH_DEDICATED_RECOVERY;
+
#ifdef CONFIG_FAKE_DEV_SWITCH
if (eoption_get_bool(EOPTION_BOOL_FAKE_DEV))
*memmap_switches |= EC_LPC_SWITCH_FAKE_DEVELOPER;
diff --git a/common/system_common.c b/common/system_common.c
index f1b5473eb7..6394a434de 100644
--- a/common/system_common.c
+++ b/common/system_common.c
@@ -36,6 +36,8 @@ struct jump_data {
* _end_ of RAM between images. This way, the magic number will always
* be the last word in RAM regardless of how many fields are added. */
+ uint8_t recovery_required; /* signal recovery mode to BIOS */
+
/* Fields from version 2 */
int jump_tag_total; /* Total size of all jump tags */
@@ -75,6 +77,12 @@ 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;
@@ -194,7 +202,8 @@ 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)
+static void jump_to_image(uint32_t init_addr,
+ int recovery_required)
{
void (*resetvec)(void) = (void(*)(void))init_addr;
@@ -206,6 +215,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->magic = JUMP_DATA_MAGIC;
jdata->version = JUMP_DATA_VERSION;
jdata->reset_cause = reset_cause;
@@ -237,7 +247,15 @@ static uint32_t get_base(enum system_image_copy_t copy)
}
-int system_run_image_copy(enum system_image_copy_t copy)
+static const char * const image_names[] = {
+ "Unknown",
+ "RO",
+ "A",
+ "B"
+};
+
+int system_run_image_copy(enum system_image_copy_t copy,
+ int recovery_required)
{
uint32_t base;
uint32_t init_addr;
@@ -260,7 +278,9 @@ int system_run_image_copy(enum system_image_copy_t copy)
if (init_addr < base || init_addr >= base + CONFIG_FW_IMAGE_SIZE)
return EC_ERROR_UNKNOWN;
- jump_to_image(init_addr);
+ CPRINTF("Rebooting to image %s\n", image_names[copy]);
+
+ jump_to_image(init_addr, recovery_required);
/* Should never get here */
return EC_ERROR_UNIMPLEMENTED;
@@ -426,16 +446,15 @@ static int command_sysjump(int argc, char **argv)
return EC_ERROR_INVAL;
}
+ ccputs("Processing sysjump command\n");
+
/* Handle named images */
if (!strcasecmp(argv[1], "RO")) {
- ccputs("Jumping directly to RO image...\n");
- return system_run_image_copy(SYSTEM_IMAGE_RO);
+ return system_run_image_copy(SYSTEM_IMAGE_RO, 0);
} else if (!strcasecmp(argv[1], "A")) {
- ccputs("Jumping directly to image A...\n");
- return system_run_image_copy(SYSTEM_IMAGE_RW_A);
+ return system_run_image_copy(SYSTEM_IMAGE_RW_A, 0);
} else if (!strcasecmp(argv[1], "B")) {
- ccputs("Jumping directly to image B...\n");
- return system_run_image_copy(SYSTEM_IMAGE_RW_B);
+ return system_run_image_copy(SYSTEM_IMAGE_RW_B, 0);
}
/* Check for arbitrary address */
@@ -446,7 +465,7 @@ static int command_sysjump(int argc, char **argv)
}
ccprintf("Jumping directly to 0x%08x...\n", addr);
cflush();
- jump_to_image(addr);
+ jump_to_image(addr, 0);
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(sysjump, command_sysjump);
@@ -533,32 +552,35 @@ static void clean_busy_bits(void) {
enum lpc_status host_command_reboot(uint8_t *data)
{
+ enum system_image_copy_t copy;
+
struct lpc_params_reboot_ec *p =
(struct lpc_params_reboot_ec *)data;
+ int recovery_request = p->reboot_flags &
+ EC_LPC_COMMAND_REBOOT_BIT_RECOVERY;
+
/* TODO: (crosbug.com/p/7468) For this command to be allowed, WP must
* be disabled. */
switch (p->target) {
case EC_LPC_IMAGE_RO:
- CPUTS("[Rebooting to image RO!\n]");
- clean_busy_bits();
- system_run_image_copy(SYSTEM_IMAGE_RO);
+ copy = SYSTEM_IMAGE_RO;
break;
case EC_LPC_IMAGE_RW_A:
- CPUTS("[Rebooting to image A!]\n");
- clean_busy_bits();
- system_run_image_copy(SYSTEM_IMAGE_RW_A);
+ copy = SYSTEM_IMAGE_RW_A;
break;
case EC_LPC_IMAGE_RW_B:
- CPUTS("[Rebooting to image B!]\n");
- clean_busy_bits();
- system_run_image_copy(SYSTEM_IMAGE_RW_B);
+ copy = SYSTEM_IMAGE_RW_B;
break;
default:
return EC_LPC_RESULT_ERROR;
}
+ clean_busy_bits();
+ 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.
diff --git a/common/vboot.c b/common/vboot.c
index b96765b97b..fa6c2c27aa 100644
--- a/common/vboot.c
+++ b/common/vboot.c
@@ -52,7 +52,7 @@ static void jump_to_other_image(void)
* image, enable this there too. */
/* TODO: real verified boot (including recovery reason); for now, just
* jump to image A. */
- system_run_image_copy(SYSTEM_IMAGE_RW_A);
+ system_run_image_copy(SYSTEM_IMAGE_RW_A, 0);
#endif
}
diff --git a/include/lpc_commands.h b/include/lpc_commands.h
index a3386c7280..354c059b1f 100644
--- a/include/lpc_commands.h
+++ b/include/lpc_commands.h
@@ -499,8 +499,11 @@ struct lpc_response_host_event_mask {
#define EC_LPC_COMMAND_REBOOT 0xd1 /* Think "die" */
#define EC_LPC_COMMAND_REBOOT_EC 0xd2
+#define EC_LPC_COMMAND_REBOOT_BIT_RECOVERY (1 << 0)
+
struct lpc_params_reboot_ec {
uint8_t target; /* enum lpc_current_image */
+ uint8_t reboot_flags;
} __attribute__ ((packed));
#endif /* !__ACPI__ */
diff --git a/include/system.h b/include/system.h
index c84830bec4..3246242971 100644
--- a/include/system.h
+++ b/include/system.h
@@ -57,6 +57,9 @@ int system_common_pre_init(void);
* the cause is not known. */
enum system_reset_cause_t system_get_reset_cause(void);
+/* returns 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);
@@ -93,8 +96,9 @@ int system_unsafe_to_overwrite(uint32_t offset, uint32_t size);
/* Returns a text description of the image copy which is currently running. */
const char *system_get_image_copy_string(void);
-/* Jumps to the specified image copy. Only works from RO firmware. */
-int system_run_image_copy(enum system_image_copy_t copy);
+/* Jumps to the specified image copy. */
+int system_run_image_copy(enum system_image_copy_t copy,
+ int recovery_request);
/* Returns the version string for an image copy, or an empty string if
* error. If copy==SYSTEM_IMAGE_UNKNOWN, returns the version for the