diff --git a/common/flash_commands.c b/common/flash_commands.c index 117979d725..b5cf854f7e 100644 --- a/common/flash_commands.c +++ b/common/flash_commands.c @@ -10,6 +10,7 @@ #include "host_command.h" #include "registers.h" /* TODO: remove; only for temp debugging */ #include "shared_mem.h" +#include "system.h" #include "uart.h" #include "util.h" @@ -258,6 +259,9 @@ enum lpc_status flash_command_write(uint8_t *data) if (p->size > sizeof(p->data)) return EC_LPC_RESULT_ERROR; + if (system_unsafe_to_overwrite(p->offset, p->size)) + return EC_LPC_RESULT_ACCESS_DENIED; + if (flash_write(p->offset, p->size, p->data)) return EC_LPC_RESULT_ERROR; @@ -271,6 +275,9 @@ enum lpc_status flash_command_erase(uint8_t *data) struct lpc_params_flash_erase *p = (struct lpc_params_flash_erase *)data; + if (system_unsafe_to_overwrite(p->offset, p->size)) + return EC_LPC_RESULT_ACCESS_DENIED; + if (flash_erase(p->offset, p->size)) return EC_LPC_RESULT_ERROR; diff --git a/common/system_common.c b/common/system_common.c index bf78622115..085e81f41e 100644 --- a/common/system_common.c +++ b/common/system_common.c @@ -7,6 +7,7 @@ #include "console.h" #include "host_command.h" +#include "lpc.h" #include "lpc_commands.h" #include "system.h" #include "task.h" @@ -57,6 +58,26 @@ enum system_image_copy_t system_get_image_copy(void) } +/* Returns true if the given range is overlapped with the active image. + * + * We only care the runtime code since the EC is running over it. + * We don't care about the vector table, FMAP, and init code. + * Read core/$CORE/ec.lds.S about the below extern symbols. + */ +int system_unsafe_to_overwrite(uint32_t offset, uint32_t size) { + int copy = ((uint32_t)system_unsafe_to_overwrite - CONFIG_FLASH_BASE) / + CONFIG_FW_IMAGE_SIZE; + uint32_t r_offset = copy * CONFIG_FW_IMAGE_SIZE; + uint32_t r_size = CONFIG_FW_IMAGE_SIZE; + + if ((offset >= r_offset && offset < (r_offset + r_size)) || + (r_offset >= offset && r_offset < (offset + size))) + return 1; + else + return 0; +} + + const char *system_get_image_copy_string(void) { static const char * const copy_descs[] = {"unknown", "RO", "A", "B"}; @@ -335,6 +356,13 @@ DECLARE_HOST_COMMAND(EC_LPC_COMMAND_GET_BUILD_INFO, host_command_build_info); #ifdef CONFIG_REBOOT_EC +static void clean_busy_bits(void) { +#ifdef CONFIG_LPC + lpc_send_host_response(0, EC_LPC_RESULT_SUCCESS); + lpc_send_host_response(1, EC_LPC_RESULT_SUCCESS); +#endif +} + enum lpc_status host_command_reboot(uint8_t *data) { struct lpc_params_reboot_ec *p = @@ -346,14 +374,17 @@ enum lpc_status host_command_reboot(uint8_t *data) switch (p->target) { case EC_LPC_IMAGE_RO: uart_puts("[Rebooting to image RO!\n]"); + clean_busy_bits(); system_run_image_copy(SYSTEM_IMAGE_RO); break; case EC_LPC_IMAGE_RW_A: uart_puts("[Rebooting to image A!]\n"); + clean_busy_bits(); system_run_image_copy(SYSTEM_IMAGE_RW_A); break; case EC_LPC_IMAGE_RW_B: uart_puts("[Rebooting to image B!]\n"); + clean_busy_bits(); system_run_image_copy(SYSTEM_IMAGE_RW_B); break; default: diff --git a/include/lpc_commands.h b/include/lpc_commands.h index 9aa22c8603..4ca2f44b6a 100644 --- a/include/lpc_commands.h +++ b/include/lpc_commands.h @@ -102,6 +102,7 @@ enum lpc_status { EC_LPC_RESULT_INVALID_COMMAND = 1, EC_LPC_RESULT_ERROR = 2, EC_LPC_RESULT_INVALID_PARAM = 3, + EC_LPC_RESULT_ACCESS_DENIED = 4, }; diff --git a/include/system.h b/include/system.h index 0259f357c9..6981694fde 100644 --- a/include/system.h +++ b/include/system.h @@ -65,6 +65,9 @@ const char *system_get_reset_cause_string(void); /* Returns the image copy which is currently running. */ enum system_image_copy_t system_get_image_copy(void); +/* Returns true if the given range is overlapped with the active image. */ +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);