summaryrefslogtreecommitdiff
path: root/common/vboot.c
blob: 307dfac2d03a9ed3c5aad8a60b8a7276bc486886 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/* 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 "common.h"  /* for CONFIG_REBOOT_EC */
#include "console.h"
#include "host_command.h"  /* for CONFIG_REBOOT_EC */
#include "lpc_commands.h"  /* for CONFIG_REBOOT_EC */
#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);

#ifdef CONFIG_REBOOT_EC
enum lpc_status vboot_command_reboot(uint8_t *data) {
	struct lpc_params_reboot_ec *p =
		(struct lpc_params_reboot_ec *)data;

	switch (p->target) {
	case EC_LPC_IMAGE_RW_A:
		uart_puts("Rebooting to image A!\n\n\n");
		system_set_scratchpad(SCRATCHPAD_REQUEST_A);
		break;
	case EC_LPC_IMAGE_RW_B:
		uart_puts("Rebooting to image B!\n\n\n");
		system_set_scratchpad(SCRATCHPAD_REQUEST_B);
		break;
	case EC_LPC_IMAGE_RO:  /* do nothing */
		uart_puts("Rebooting to image RO!\n\n\n");
		break;
	default:
		return EC_LPC_RESULT_ERROR;
	}

	uart_flush_output();
	/* TODO - param to specify warm/cold */
	system_reset(1);
	return EC_LPC_RESULT_SUCCESS;
}
DECLARE_HOST_COMMAND(EC_LPC_COMMAND_REBOOT_EC, vboot_command_reboot);
#endif /* CONFIG_REBOOT_EC */

/*****************************************************************************/
/* Initialization */

int vboot_pre_init(void)
{
	/* FIXME(wfrichar): crosbug.com/p/7453: should protect flash */
	return EC_SUCCESS;
}


int vboot_init(void)
{
	/* FIXME(wfrichar): placeholder for full verified boot implementation.
	 * TBD exactly how, but we may want to continue in RO firmware, jump
	 * directly to one of the RW firmwares, etc. */
	jump_to_other_image();
	return EC_SUCCESS;
}