summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLouis Yung-Chieh Lo <yjlou@chromium.org>2012-05-03 21:30:18 +0800
committerLouis Yung-Chieh Lo <yjlou@chromium.org>2012-05-03 21:30:18 +0800
commit7cac1d3b52b34fbf57c4bab4df05db67e746b02f (patch)
tree8b1efa14cc422a49520fef8e649ce5bf4f608e42
parent702674438870732bbe3ddec4308d8f39f8a40370 (diff)
downloadchrome-ec-7cac1d3b52b34fbf57c4bab4df05db67e746b02f.tar.gz
Add header_size in struct jump_data.
The position of jump_tags was shifted every time a new field was added to struct jump_data. This broke the sysjump hook badly. To make this more scalable, add a header_size field in struct jump_data. Then the new code can always prepend (or reduce if jump_data becomes smaller) some spaces between jump_data and jump_tags. BUG=chrome-os-partner:9447 TEST=EC upgrade from EC 517 (2231) to this version, and keyboard keeps working. Note that EC 526 (2235) to this version is not working because we have no way to identify that header version change. Change-Id: If1b506c6f7d22e5affaaf8ada15990f60d2f957a
-rw-r--r--common/system_common.c39
1 files changed, 38 insertions, 1 deletions
diff --git a/common/system_common.c b/common/system_common.c
index 6394a434de..793bdaf263 100644
--- a/common/system_common.c
+++ b/common/system_common.c
@@ -30,13 +30,15 @@ struct jump_tag {
/* Data passed between the current image and the next one when jumping between
* images. */
#define JUMP_DATA_MAGIC 0x706d754a /* "Jump" */
-#define JUMP_DATA_VERSION 2
+#define JUMP_DATA_VERSION 3
struct jump_data {
/* Add new fields to the _start_ of the struct, since we copy it to the
* _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. */
+ /* Fields from version 3 */
uint8_t recovery_required; /* signal recovery mode to BIOS */
+ int header_size; /* Header size to correctly point to jump tags. */
/* Fields from version 2 */
int jump_tag_total; /* Total size of all jump tags */
@@ -220,6 +222,7 @@ static void jump_to_image(uint32_t init_addr,
jdata->version = JUMP_DATA_VERSION;
jdata->reset_cause = reset_cause;
jdata->jump_tag_total = 0; /* Reset tags */
+ jdata->header_size = sizeof(struct jump_data);
/* Call other hooks; these may add tags */
hook_notify(HOOK_SYSJUMP, 0);
@@ -327,15 +330,49 @@ int system_common_pre_init(void)
if (jdata->magic == JUMP_DATA_MAGIC &&
jdata->version >= 1 &&
reset_cause == SYSTEM_RESET_SOFT_WARM) {
+ int jtag_total; /* #byte of jump tags */
+ int delta; /* delta of header size */
+ uint8_t *jtag; /* point to _real_ start of jump tags */
+
/* Yes, we jumped to this image */
jumped_to_image = 1;
/* Overwrite the reset cause with the real one */
reset_cause = jdata->reset_cause;
+ /* Header version 3 introduces the header_size field.
+ * Thus we can estimate the real offset of jump tags
+ * between different header versions.
+ */
+ if (jdata->version == 1) {
+ jtag_total = 0;
+ delta = sizeof(struct jump_data) - 12;
+ } else if (jdata->version == 2) {
+ jtag_total = jdata->jump_tag_total;
+ delta = sizeof(struct jump_data) - 16;
+ } else {
+ jtag_total = jdata->jump_tag_total;
+ delta = sizeof(struct jump_data) - jdata->header_size;
+ }
+ jtag = ((uint8_t*)jdata) + delta - jtag_total;
+ /* TODO: re-write with memmove(). */
+ if (delta > 0) {
+ memcpy(jtag - delta, jtag, jtag_total);
+ } else {
+ int i;
+ for (i = jtag_total - 1; i >= 0; i--)
+ jtag[i - delta] = jtag[i];
+ }
+
/* Initialize fields added after version 1 */
if (jdata->version < 2)
jdata->jump_tag_total = 0;
+ /* Initialize fields added after version 2 */
+ if (jdata->version < 3) {
+ jdata->recovery_required = 0;
+ jdata->header_size = 16;
+ }
+
/* Clear the jump struct's magic number. This prevents
* accidentally detecting a jump when there wasn't one, and
* disallows use of system_add_jump_tag(). */