From b71837716d1c049df622077de397ea77bfa85147 Mon Sep 17 00:00:00 2001 From: Louis Yung-Chieh Lo Date: Wed, 21 Mar 2012 22:18:39 +0800 Subject: [PATCH] flash write and erase commands protect the active image. Comapre the range to be write (erase) with the range of active image. If overlap, return error to indicate the access denied. Note that we actually protect only runtime code and ro data. FMAP is intentional unprotected so that flashrom can update to new map before jumping. Since the vector table and init code are in the same erase page, they are unprotected as well. BUG=chrome-os-partner:7478 TEST= Change-Id: Icb5cc89836432a11cef80e18eb66bb39a6c9b1d9 --- common/flash_commands.c | 7 +++++++ common/system_common.c | 31 +++++++++++++++++++++++++++++++ include/lpc_commands.h | 1 + include/system.h | 3 +++ 4 files changed, 42 insertions(+) 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);