diff options
author | Randall Spangler <rspangler@chromium.org> | 2012-04-19 16:10:11 -0700 |
---|---|---|
committer | Randall Spangler <rspangler@chromium.org> | 2012-04-19 18:15:18 -0700 |
commit | 13ad1c007bef3922e0aae8c7e2ef067a05eb0c06 (patch) | |
tree | ccba49c2460301a85e0abe050a27c734fde1acdb | |
parent | 24dafefb3a63c9e2111ff87c4595ceaff7182d20 (diff) | |
download | chrome-ec-13ad1c007bef3922e0aae8c7e2ef067a05eb0c06.tar.gz |
Implement HOOK_SYSJUMP and use it to preserve LPC host event mask
This also changes shared_mem to use all the remaining RAM, instead of
reserving a fixed-size buffer.
Signed-off-by: Randall Spangler <rspangler@chromium.org>
BUG=chrome-os-partner:9161
TEST=manual
hostevent --> all masks should be 0
hostevent smi 0x12300000
hostevent --> should confirm SMI mask was set
sysjump b
hostevent --> should confirm SMI mask is still set
reboot
hostevent --> should confirm SMI mask is back to 0
Change-Id: Iccb6da6ccc93ee5036a3f478d24b717a462d9150
-rw-r--r-- | chip/lm4/lpc.c | 230 | ||||
-rw-r--r-- | common/hooks.c | 31 | ||||
-rw-r--r-- | common/shared_mem.c | 27 | ||||
-rw-r--r-- | common/system_common.c | 113 | ||||
-rw-r--r-- | core/cortex-m/ec.lds.S | 9 | ||||
-rw-r--r-- | core/cortex-m/link_defs.h | 4 | ||||
-rw-r--r-- | include/hooks.h | 8 | ||||
-rw-r--r-- | include/system.h | 17 |
8 files changed, 297 insertions, 142 deletions
diff --git a/chip/lm4/lpc.c b/chip/lm4/lpc.c index c8b45df798..a5dfedefc8 100644 --- a/chip/lm4/lpc.c +++ b/chip/lm4/lpc.c @@ -14,10 +14,13 @@ #include "lpc_commands.h" #include "port80.h" #include "registers.h" +#include "system.h" #include "task.h" #include "timer.h" #include "uart.h" +#include "util.h" +#define LPC_SYSJUMP_TAG 0x4c50 /* "LP" */ static uint32_t host_events; /* Currently pending SCI/SMI events */ static uint32_t event_mask[3]; /* Event masks for each type */ @@ -106,104 +109,6 @@ static void lpc_generate_sci(void) } -static int lpc_init(void) -{ - volatile uint32_t scratch __attribute__((unused)); - - /* Enable RGCGLPC then delay a few clocks. */ - LM4_SYSTEM_RCGCLPC = 1; - scratch = LM4_SYSTEM_RCGCLPC; - - LM4_LPC_LPCIM = 0; - LM4_LPC_LPCCTL = 0; - LM4_LPC_LPCIRQCTL = 0; - - /* Configure GPIOs */ - configure_gpio(); - - /* Set LPC channel 0 to I/O address 0x62 (data) / 0x66 (command), - * single endpoint, offset 0 for host command/writes and 1 for EC - * data writes, pool bytes 0(data)/1(cmd) */ - LM4_LPC_ADR(LPC_CH_KERNEL) = EC_LPC_ADDR_KERNEL_DATA; - LM4_LPC_CTL(LPC_CH_KERNEL) = (LPC_POOL_OFFS_KERNEL << (5 - 1)); - /* Unmask interrupt for host command writes */ - LM4_LPC_LPCIM |= LM4_LPC_INT_MASK(LPC_CH_KERNEL, 4); - - /* Set LPC channel 1 to I/O address 0x80 (data), single endpoint, - * pool bytes 4(data)/5(cmd). */ - LM4_LPC_ADR(LPC_CH_PORT80) = 0x80; - LM4_LPC_CTL(LPC_CH_PORT80) = (LPC_POOL_OFFS_PORT80 << (5 - 1)); - /* Unmask interrupt for host data writes */ - LM4_LPC_LPCIM |= LM4_LPC_INT_MASK(LPC_CH_PORT80, 2); - - - /* Set LPC channel 2 to I/O address 0x800, range endpoint, - * arbitration disabled, pool bytes 512-1023. To access this from - * x86, use the following commands to set GEN_LPC2 and GEN_LPC3: - * - * pci_write32 0 0x1f 0 0x88 0x007c0801 - * pci_write32 0 0x1f 0 0x8c 0x007c0901 - */ - LM4_LPC_ADR(LPC_CH_CMD_DATA) = EC_LPC_ADDR_KERNEL_PARAM; - LM4_LPC_CTL(LPC_CH_CMD_DATA) = 0x801D | - (LPC_POOL_OFFS_CMD_DATA << (5 - 1)); - - /* Set LPC channel 3 to I/O address 0x60 (data) / 0x64 (command), - * single endpoint, offset 0 for host command/writes and 1 for EC - * data writes, pool bytes 0(data)/1(cmd) */ - LM4_LPC_ADR(LPC_CH_KEYBOARD) = 0x60; - LM4_LPC_CTL(LPC_CH_KEYBOARD) = (1 << 24/* IRQSEL1 */) | - (0 << 18/* IRQEN1 */) | (LPC_POOL_OFFS_KEYBOARD << (5 - 1)); - LM4_LPC_ST(LPC_CH_KEYBOARD) = 0; - /* Unmask interrupt for host command/data writes and data reads */ - LM4_LPC_LPCIM |= LM4_LPC_INT_MASK(LPC_CH_KEYBOARD, 7); - - /* Set LPC channel 4 to I/O address 0x200 (data) / 0x204 (command), - * single endpoint, offset 0 for host command/writes and 1 for EC - * data writes, pool bytes 0(data)/1(cmd) */ - LM4_LPC_ADR(LPC_CH_USER) = EC_LPC_ADDR_USER_DATA; - LM4_LPC_CTL(LPC_CH_USER) = (LPC_POOL_OFFS_USER << (5 - 1)); - /* Unmask interrupt for host command writes */ - LM4_LPC_LPCIM |= LM4_LPC_INT_MASK(LPC_CH_USER, 4); - - /* Set LPC channel 7 to COM port I/O address. Note that channel 7 - * ignores the TYPE bit and is always an 8-byte range. */ - LM4_LPC_ADR(LPC_CH_COMX) = LPC_COMX_ADDR; - /* TODO: could configure IRQSELs and set IRQEN2/CX, and then the host - * can enable IRQs on its own. */ - LM4_LPC_CTL(LPC_CH_COMX) = 0x0004 | (LPC_POOL_OFFS_COMX << (5 - 1)); - /* Enable COMx emulation for reads and writes. */ - LM4_LPC_LPCDMACX = 0x00310000; - /* Unmask interrupt for host data writes. We don't need interrupts for - * reads, because there's no flow control in that direction; LPC is - * much faster than the UART, and the UART doesn't have anywhere - * sensible to buffer input anyway. */ - LM4_LPC_LPCIM |= LM4_LPC_INT_MASK(LPC_CH_COMX, 2); - - /* Unmaksk LPC bus reset interrupt. This lets us monitor the PCH - * PLTRST# signal for debugging. */ - LM4_LPC_LPCIM |= (1 << 31); - - /* Enable LPC channels */ - LM4_LPC_LPCCTL = LM4_LPC_SCI_CLK_1 | - (1 << LPC_CH_KERNEL) | - (1 << LPC_CH_PORT80) | - (1 << LPC_CH_CMD_DATA) | - (1 << LPC_CH_KEYBOARD) | - (1 << LPC_CH_USER) | - (1 << LPC_CH_COMX); - - /* Enable LPC interrupt */ - task_enable_irq(LM4_IRQ_LPC); - - /* Enable COMx UART */ - uart_comx_enable(); - - return EC_SUCCESS; -} -DECLARE_HOOK(HOOK_INIT, lpc_init, HOOK_PRIO_DEFAULT); - - uint8_t *lpc_get_host_range(int slot) { return (uint8_t *)LPC_POOL_CMD_DATA + EC_LPC_PARAM_SIZE * slot; @@ -438,9 +343,136 @@ static void lpc_interrupt(void) /* Debugging: print changes to LPC0RESET */ if (mis & (1 << 31)) { - uart_printf("[%T LPC PLTRST# %sasserted]\n", + uart_printf("[%T LPC RESET# %sasserted]\n", (LM4_LPC_LPCSTS & (1<<10)) ? "" : "de"); } } DECLARE_IRQ(LM4_IRQ_LPC, lpc_interrupt, 2); + +/* Preserve event masks across a sysjump */ +static int lpc_sysjump(void) +{ + system_add_jump_tag(LPC_SYSJUMP_TAG, 1, + sizeof(event_mask), event_mask); + + return EC_SUCCESS; +} +DECLARE_HOOK(HOOK_SYSJUMP, lpc_sysjump, HOOK_PRIO_DEFAULT); + + +/* Restore event masks after a sysjump */ +static void lpc_post_sysjump(void) +{ + const uint32_t *prev_mask; + int size, version; + + prev_mask = (const uint32_t *)system_get_jump_tag(LPC_SYSJUMP_TAG, + &version, &size); + if (!prev_mask || version != 1 || size != sizeof(event_mask)) + return; + + memcpy(event_mask, prev_mask, sizeof(event_mask)); + update_host_event_status(); +} + + +static int lpc_init(void) +{ + volatile uint32_t scratch __attribute__((unused)); + + /* Enable RGCGLPC then delay a few clocks. */ + LM4_SYSTEM_RCGCLPC = 1; + scratch = LM4_SYSTEM_RCGCLPC; + + LM4_LPC_LPCIM = 0; + LM4_LPC_LPCCTL = 0; + LM4_LPC_LPCIRQCTL = 0; + + /* Configure GPIOs */ + configure_gpio(); + + /* Set LPC channel 0 to I/O address 0x62 (data) / 0x66 (command), + * single endpoint, offset 0 for host command/writes and 1 for EC + * data writes, pool bytes 0(data)/1(cmd) */ + LM4_LPC_ADR(LPC_CH_KERNEL) = EC_LPC_ADDR_KERNEL_DATA; + LM4_LPC_CTL(LPC_CH_KERNEL) = (LPC_POOL_OFFS_KERNEL << (5 - 1)); + /* Unmask interrupt for host command writes */ + LM4_LPC_LPCIM |= LM4_LPC_INT_MASK(LPC_CH_KERNEL, 4); + + /* Set LPC channel 1 to I/O address 0x80 (data), single endpoint, + * pool bytes 4(data)/5(cmd). */ + LM4_LPC_ADR(LPC_CH_PORT80) = 0x80; + LM4_LPC_CTL(LPC_CH_PORT80) = (LPC_POOL_OFFS_PORT80 << (5 - 1)); + /* Unmask interrupt for host data writes */ + LM4_LPC_LPCIM |= LM4_LPC_INT_MASK(LPC_CH_PORT80, 2); + + + /* Set LPC channel 2 to I/O address 0x800, range endpoint, + * arbitration disabled, pool bytes 512-1023. To access this from + * x86, use the following commands to set GEN_LPC2 and GEN_LPC3: + * + * pci_write32 0 0x1f 0 0x88 0x007c0801 + * pci_write32 0 0x1f 0 0x8c 0x007c0901 + */ + LM4_LPC_ADR(LPC_CH_CMD_DATA) = EC_LPC_ADDR_KERNEL_PARAM; + LM4_LPC_CTL(LPC_CH_CMD_DATA) = 0x801D | + (LPC_POOL_OFFS_CMD_DATA << (5 - 1)); + + /* Set LPC channel 3 to I/O address 0x60 (data) / 0x64 (command), + * single endpoint, offset 0 for host command/writes and 1 for EC + * data writes, pool bytes 0(data)/1(cmd) */ + LM4_LPC_ADR(LPC_CH_KEYBOARD) = 0x60; + LM4_LPC_CTL(LPC_CH_KEYBOARD) = (1 << 24/* IRQSEL1 */) | + (0 << 18/* IRQEN1 */) | (LPC_POOL_OFFS_KEYBOARD << (5 - 1)); + LM4_LPC_ST(LPC_CH_KEYBOARD) = 0; + /* Unmask interrupt for host command/data writes and data reads */ + LM4_LPC_LPCIM |= LM4_LPC_INT_MASK(LPC_CH_KEYBOARD, 7); + + /* Set LPC channel 4 to I/O address 0x200 (data) / 0x204 (command), + * single endpoint, offset 0 for host command/writes and 1 for EC + * data writes, pool bytes 0(data)/1(cmd) */ + LM4_LPC_ADR(LPC_CH_USER) = EC_LPC_ADDR_USER_DATA; + LM4_LPC_CTL(LPC_CH_USER) = (LPC_POOL_OFFS_USER << (5 - 1)); + /* Unmask interrupt for host command writes */ + LM4_LPC_LPCIM |= LM4_LPC_INT_MASK(LPC_CH_USER, 4); + + /* Set LPC channel 7 to COM port I/O address. Note that channel 7 + * ignores the TYPE bit and is always an 8-byte range. */ + LM4_LPC_ADR(LPC_CH_COMX) = LPC_COMX_ADDR; + /* TODO: could configure IRQSELs and set IRQEN2/CX, and then the host + * can enable IRQs on its own. */ + LM4_LPC_CTL(LPC_CH_COMX) = 0x0004 | (LPC_POOL_OFFS_COMX << (5 - 1)); + /* Enable COMx emulation for reads and writes. */ + LM4_LPC_LPCDMACX = 0x00310000; + /* Unmask interrupt for host data writes. We don't need interrupts for + * reads, because there's no flow control in that direction; LPC is + * much faster than the UART, and the UART doesn't have anywhere + * sensible to buffer input anyway. */ + LM4_LPC_LPCIM |= LM4_LPC_INT_MASK(LPC_CH_COMX, 2); + + /* Unmaksk LPC bus reset interrupt. This lets us monitor the PCH + * PLTRST# signal for debugging. */ + LM4_LPC_LPCIM |= (1 << 31); + + /* Enable LPC channels */ + LM4_LPC_LPCCTL = LM4_LPC_SCI_CLK_1 | + (1 << LPC_CH_KERNEL) | + (1 << LPC_CH_PORT80) | + (1 << LPC_CH_CMD_DATA) | + (1 << LPC_CH_KEYBOARD) | + (1 << LPC_CH_USER) | + (1 << LPC_CH_COMX); + + /* Enable LPC interrupt */ + task_enable_irq(LM4_IRQ_LPC); + + /* Enable COMx UART */ + uart_comx_enable(); + + /* Restore event masks if needed */ + lpc_post_sysjump(); + + return EC_SUCCESS; +} +DECLARE_HOOK(HOOK_INIT, lpc_init, HOOK_PRIO_DEFAULT); diff --git a/common/hooks.c b/common/hooks.c index 81bc2ac212..e8a64ebeb7 100644 --- a/common/hooks.c +++ b/common/hooks.c @@ -10,6 +10,20 @@ #include "uart.h" #include "util.h" +struct hook_ptrs { + const struct hook_data *start; + const struct hook_data *end; +}; + +/* Hook data start and end pointers for each type of hook. Must be in same + * order as enum hook_type. */ +static const struct hook_ptrs hook_list[] = { + {__hooks_init, __hooks_init_end}, + {__hooks_freq_change, __hooks_freq_change_end}, + {__hooks_sysjump, __hooks_sysjump_end}, +}; + + int hook_notify(enum hook_type type, int stop_on_error) { const struct hook_data *start, *end, *p; @@ -17,21 +31,8 @@ int hook_notify(enum hook_type type, int stop_on_error) int last_prio = HOOK_PRIO_FIRST - 1, prio; int rv_error = EC_SUCCESS, rv; - /* Get the start and end pointers for the hook type */ - switch (type) { - case HOOK_INIT: - start = __hooks_init; - end = __hooks_init_end; - break; - case HOOK_FREQ_CHANGE: - start = __hooks_freq_change; - end = __hooks_freq_change_end; - break; - default: - /* Unhandled hook type */ - return EC_ERROR_UNKNOWN; - } - + start = hook_list[type].start; + end = hook_list[type].end; count = ((uint32_t)end - (uint32_t)start) / sizeof(struct hook_data); /* Call all the hooks in priority order */ diff --git a/common/shared_mem.c b/common/shared_mem.c index bff3ec6da3..63edd7e755 100644 --- a/common/shared_mem.c +++ b/common/shared_mem.c @@ -1,35 +1,30 @@ -/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. +/* Copyright (c) 2012 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. */ /* Shared memory module for Chrome EC */ +#include "config.h" +#include "link_defs.h" #include "shared_mem.h" -#include "uart.h" +#include "system.h" -/* Size of shared memory buffer */ -#define SHARED_MEM_SIZE 4096 - -static char shared_buf[SHARED_MEM_SIZE]; -static int buf_in_use = 0; - - -int shared_mem_init(void) -{ - return EC_SUCCESS; -} +static int buf_in_use; int shared_mem_size(void) { - return SHARED_MEM_SIZE; + /* Use all the RAM we can. The shared memory buffer is the + * last thing allocated from the start of RAM, so we can use + * everything up to the jump data at the end of RAM. */ + return system_usable_ram_end() - (uint32_t)__shared_mem_buf; } int shared_mem_acquire(int size, int wait, char **dest_ptr) { - if (size > SHARED_MEM_SIZE || size <= 0) + if (size > shared_mem_size() || size <= 0) return EC_ERROR_INVAL; /* TODO: if task_start() hasn't been called, fail immediately @@ -42,7 +37,7 @@ int shared_mem_acquire(int size, int wait, char **dest_ptr) /* TODO: atomically acquire buf_in_use. */ buf_in_use = 1; - *dest_ptr = shared_buf; + *dest_ptr = __shared_mem_buf; return EC_SUCCESS; } diff --git a/common/system_common.c b/common/system_common.c index 7d6ed1e1e7..0d1805b2ca 100644 --- a/common/system_common.c +++ b/common/system_common.c @@ -6,6 +6,7 @@ /* System module for Chrome EC : common functions */ #include "console.h" +#include "hooks.h" #include "host_command.h" #include "lpc.h" #include "lpc_commands.h" @@ -16,24 +17,55 @@ #include "version.h" +struct jump_tag { + uint16_t tag; + uint8_t data_size; + uint8_t data_version; +}; + + /* Data passed between the current image and the next one when jumping between * images. */ #define JUMP_DATA_MAGIC 0x706d754a /* "Jump" */ -#define JUMP_DATA_VERSION 1 +#define JUMP_DATA_VERSION 2 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. */ - int reset_cause; /* Reset cause for the previous boot */ - int version; /* Version (JUMP_DATA_VERSION) */ - int magic; /* Magic number (JUMP_DATA_MAGIC) */ + + /* Fields from version 2 */ + int jump_tag_total; /* Total size of all jump tags */ + + /* Fields from version 1 */ + int reset_cause; /* Reset cause for the previous boot */ + int version; /* Version (JUMP_DATA_VERSION) */ + int magic; /* Magic number (JUMP_DATA_MAGIC). If this + * doesn't match at pre-init time, assume no valid + * data from the previous image. */ }; +/* Jump data goes at the end of RAM */ +static struct jump_data * const jdata = + (struct jump_data *)(CONFIG_RAM_BASE + CONFIG_RAM_SIZE + - sizeof(struct jump_data)); static enum system_reset_cause_t reset_cause = SYSTEM_RESET_UNKNOWN; static int jumped_to_image; +int system_usable_ram_end(void) +{ + /* Leave space at the end of RAM for jump data. + * + * Note that jump_tag_total is 0 on a reboot, so we have the maximum + * amount of RAM available on a reboot; we only lose space for stored + * tags after a sysjump. When verified boot runs after a reboot, it'll + * have as much RAM as we can give it; after verified boot jumps to + * another image there'll be less RAM, but we'll care less too. */ + return (uint32_t)jdata - jdata->jump_tag_total; +} + + enum system_reset_cause_t system_get_reset_cause(void) { return reset_cause; @@ -46,6 +78,56 @@ int system_jumped_to_this_image(void) } +int system_add_jump_tag(uint16_t tag, int version, int size, const void *data) +{ + struct jump_tag *t; + + /* Only allowed during a sysjump */ + if (jdata->magic != JUMP_DATA_MAGIC) + return EC_ERROR_UNKNOWN; + + /* Make room for the new tag */ + if (size > 255 || (size & 3)) + return EC_ERROR_INVAL; + jdata->jump_tag_total += size + sizeof(struct jump_tag); + + t = (struct jump_tag *)system_usable_ram_end(); + t->tag = tag; + t->data_size = size; + t->data_version = version; + if (size) + memcpy(t + 1, data, size); + + return EC_SUCCESS; +} + +const uint8_t *system_get_jump_tag(uint16_t tag, int *version, int *size) +{ + const struct jump_tag *t; + int used = 0; + + /* Search through tag data for a match */ + while (used < jdata->jump_tag_total) { + /* Check the next tag */ + t = (const struct jump_tag *)(system_usable_ram_end() + used); + used += sizeof(struct jump_tag) + t->data_size; + if (t->tag != tag) + continue; + + /* Found a match */ + if (size) + *size = t->data_size; + if (version) + *version = t->data_version; + + return (const uint8_t *)(t + 1); + } + + /* If we're still here, no match */ + return NULL; +} + + void system_set_reset_cause(enum system_reset_cause_t cause) { reset_cause = cause; @@ -112,8 +194,6 @@ const char *system_get_image_copy_string(void) static void jump_to_image(uint32_t init_addr) { void (*resetvec)(void) = (void(*)(void))init_addr; - struct jump_data *jdata = (struct jump_data *) - (CONFIG_RAM_BASE + CONFIG_RAM_SIZE - sizeof(struct jump_data)); /* Flush UART output unless the UART hasn't been initialized yet */ if (uart_init_done()) @@ -126,6 +206,10 @@ static void jump_to_image(uint32_t init_addr) jdata->magic = JUMP_DATA_MAGIC; jdata->version = JUMP_DATA_VERSION; jdata->reset_cause = reset_cause; + jdata->jump_tag_total = 0; /* Reset tags */ + + /* Call other hooks; these may add tags */ + hook_notify(HOOK_SYSJUMP, 0); /* Jump to the reset vector */ resetvec(); @@ -216,19 +300,26 @@ const char *system_get_build_info(void) int system_common_pre_init(void) { - struct jump_data *jdata = (struct jump_data *) - (CONFIG_RAM_BASE + CONFIG_RAM_SIZE - sizeof(struct jump_data)); - /* Check jump data if this is a jump between images */ if (jdata->magic == JUMP_DATA_MAGIC && - jdata->version == JUMP_DATA_VERSION && + jdata->version >= 1 && reset_cause == SYSTEM_RESET_SOFT_WARM) { /* Yes, we jumped to this image */ jumped_to_image = 1; /* Overwrite the reset cause with the real one */ reset_cause = jdata->reset_cause; - /* Clear the jump struct's magic number */ + + /* Initialize fields added after version 1 */ + if (jdata->version < 2) + jdata->jump_tag_total = 0; + + /* 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(). */ jdata->magic = 0; + } else { + /* Clear the whole jump_data struct */ + memset(jdata, 0, sizeof(struct jump_data)); } return EC_SUCCESS; diff --git a/core/cortex-m/ec.lds.S b/core/cortex-m/ec.lds.S index 3b80f28093..32114b59da 100644 --- a/core/cortex-m/ec.lds.S +++ b/core/cortex-m/ec.lds.S @@ -50,10 +50,15 @@ SECTIONS __hooks_init = .; *(.rodata.HOOK_INIT) __hooks_init_end = .; + __hooks_freq_change = .; *(.rodata.HOOK_FREQ_CHANGE) __hooks_freq_change_end = .; + __hooks_sysjump = .; + *(.rodata.HOOK_SYSJUMP) + __hooks_sysjump_end = .; + . = ALIGN(4); *(.rodata*) . = ALIGN(4); @@ -79,6 +84,10 @@ SECTIONS *(.bss) . = ALIGN(4); __bss_end = .; + + /* Shared memory buffer must be at the end of preallocated RAM, so it + * can expand to use all the remaining RAM. */ + __shared_mem_buf = .; } > IRAM /DISCARD/ : { *(.ARM.*) } } diff --git a/core/cortex-m/link_defs.h b/core/cortex-m/link_defs.h index 9279f42804..af809ad7e0 100644 --- a/core/cortex-m/link_defs.h +++ b/core/cortex-m/link_defs.h @@ -20,6 +20,8 @@ extern const struct hook_data __hooks_init[]; extern const struct hook_data __hooks_init_end[]; extern const struct hook_data __hooks_freq_change[]; extern const struct hook_data __hooks_freq_change_end[]; +extern const struct hook_data __hooks_sysjump[]; +extern const struct hook_data __hooks_sysjump_end[]; extern const struct host_command __hcmds[]; extern const struct host_command __hcmds_end[]; @@ -27,4 +29,6 @@ extern const struct host_command __hcmds_end[]; extern const struct irq_priority __irqprio[]; extern const struct irq_priority __irqprio_end[]; +extern uint8_t __shared_mem_buf[]; + #endif /* __CROS_EC_LINK_DEFS_H */ diff --git a/include/hooks.h b/include/hooks.h index 889cf553bc..a0e12e708b 100644 --- a/include/hooks.h +++ b/include/hooks.h @@ -18,8 +18,14 @@ enum hook_priority { enum hook_type { - HOOK_INIT, /* System init */ + HOOK_INIT = 0, /* System init */ HOOK_FREQ_CHANGE, /* System clock changed frequency */ + HOOK_SYSJUMP, /* About to jump to another image. Modules which + * need to preserve data across such a jump should + * save it here and restore it in HOOK_INIT. + * + * NOTE: This hook is called with interrupts + * disabled! */ }; diff --git a/include/system.h b/include/system.h index 36a8998b35..c84830bec4 100644 --- a/include/system.h +++ b/include/system.h @@ -70,6 +70,23 @@ enum system_image_copy_t system_get_image_copy(void); * once since the last real boot. */ int system_jumped_to_this_image(void); +/* Preserve data across a jump between images. <tag> identifies the data + * type. <size> must be a multiple of 4 bytes, and less than 255 bytes. + * <version> is the data version, so that tag data can evolve as firmware + * is updated. <data> points to the data to save. + * + * This may ONLY be called from within a HOOK_SYSJUMP handler. */ +int system_add_jump_tag(uint16_t tag, int version, int size, const void *data); + +/* Retrieve data stored by a previous image's call to + * system_add_jump_tag(). If a matching tag is found, retrieves + * <size> and <version>, and returns a pointer to the data. Returns + * NULL if no matching tag is found. */ +const uint8_t *system_get_jump_tag(uint16_t tag, int *version, int *size); + +/* Returns the address just past the last usable byte in RAM. */ +int system_usable_ram_end(void); + /* Returns true if the given range is overlapped with the active image. */ int system_unsafe_to_overwrite(uint32_t offset, uint32_t size); |