summaryrefslogtreecommitdiff
path: root/common/vboot.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/vboot.c')
-rw-r--r--common/vboot.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/common/vboot.c b/common/vboot.c
new file mode 100644
index 0000000000..4f8934bcec
--- /dev/null
+++ b/common/vboot.c
@@ -0,0 +1,98 @@
+/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Verified boot module for Chrome EC */
+
+#include "console.h"
+#include "system.h"
+#include "uart.h"
+#include "util.h"
+#include "vboot.h"
+
+
+#define SCRATCHPAD_EMPTY 0
+#define SCRATCHPAD_REQUEST_A 0xb00daaaa
+#define SCRATCHPAD_REQUEST_B 0xb00dbbbb
+#define SCRATCHPAD_SELECTED_A 0x0000d1da
+#define SCRATCHPAD_SELECTED_B 0x0000d1db
+#define SCRATCHPAD_SELECTED_RO 0x0000d1d0
+#define SCRATCHPAD_FAILED_A 0x0000eeea
+#define SCRATCHPAD_FAILED_B 0x0000eeeb
+
+
+/* Jumps to one of the RW images if necessary. */
+static void jump_to_other_image(void)
+{
+ int s;
+
+ if (system_get_image_copy() != SYSTEM_IMAGE_RO)
+ return; /* Not in RO firmware, so ignore scratchpad */
+
+ if (system_get_reset_cause() != SYSTEM_RESET_SOFT_COLD) {
+ /* In RO firmware, but not because of a warm boot.
+ * Stay in RO regardless of scratchpad, and clear it
+ * so we don't use it on the next boot. */
+ system_set_scratchpad(SCRATCHPAD_EMPTY);
+ return;
+ }
+
+ /* TODO: check recovery button; if it's pressed, stay in RO */
+
+ /* Check for a scratchpad value we recognize. Clear the
+ * scratchpad before jumping, so we only do this once. */
+ s = system_get_scratchpad();
+ if (s == SCRATCHPAD_REQUEST_A) {
+ system_set_scratchpad(SCRATCHPAD_SELECTED_A);
+ system_run_image_copy(SYSTEM_IMAGE_RW_A);
+ /* Shouldn't normally return; if we did, flag error */
+ system_set_scratchpad(SCRATCHPAD_FAILED_A);
+ } else if (s == SCRATCHPAD_REQUEST_B) {
+ system_set_scratchpad(SCRATCHPAD_SELECTED_B);
+ system_run_image_copy(SYSTEM_IMAGE_RW_B);
+ /* Shouldn't normally return; if we did, flag error */
+ system_set_scratchpad(SCRATCHPAD_FAILED_B);
+ } else {
+ system_set_scratchpad(SCRATCHPAD_EMPTY);
+ }
+}
+
+
+/*****************************************************************************/
+/* Console commands */
+
+static int command_reboot(int argc, char **argv)
+{
+ /* Handle request to boot to a specific image */
+ if (argc >= 2) {
+ if (!strcasecmp(argv[1], "a")) {
+ uart_puts("Rebooting to image A!\n\n\n");
+ system_set_scratchpad(SCRATCHPAD_REQUEST_A);
+ } else if (!strcasecmp(argv[1], "b")) {
+ uart_puts("Rebooting to image B!\n\n\n");
+ system_set_scratchpad(SCRATCHPAD_REQUEST_B);
+ } else {
+ uart_puts("Usage: reboot [ A | B ]\n");
+ return EC_ERROR_UNKNOWN;
+ }
+ } else {
+ uart_puts("Rebooting to RO!\n\n\n");
+ }
+
+ uart_flush_output();
+ /* TODO - param to specify warm/cold */
+ system_reset(1);
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(reboot, command_reboot);
+
+/*****************************************************************************/
+/* Initialization */
+
+int vboot_pre_init(void)
+{
+ /* Jump to a different image if necessary; this may not return */
+ jump_to_other_image();
+ return EC_SUCCESS;
+}