diff options
Diffstat (limited to 'common/flash_common.c')
-rw-r--r-- | common/flash_common.c | 292 |
1 files changed, 31 insertions, 261 deletions
diff --git a/common/flash_common.c b/common/flash_common.c index c496560ca1..f09868431b 100644 --- a/common/flash_common.c +++ b/common/flash_common.c @@ -9,142 +9,11 @@ #include "console.h" #include "flash.h" #include "host_command.h" -#include "power_button.h" #include "registers.h" #include "shared_mem.h" #include "system.h" #include "util.h" -#define PERSIST_STATE_VERSION 2 -#define MAX_BANKS (CONFIG_FLASH_SIZE / CONFIG_FLASH_BANK_SIZE) -#define PHYSICAL_BANKS (CONFIG_FLASH_PHYSICAL_SIZE / CONFIG_FLASH_BANK_SIZE) - -/* Persistent protection state flash offset / size / bank */ -#define PSTATE_OFFSET CONFIG_SECTION_FLASH_PSTATE_OFF -#define PSTATE_SIZE CONFIG_SECTION_FLASH_PSTATE_SIZE -#define PSTATE_BANK (PSTATE_OFFSET / CONFIG_FLASH_BANK_SIZE) - -/* Read-only firmware offset and size in units of flash banks */ -#define RO_BANK_OFFSET (CONFIG_SECTION_RO_OFF / CONFIG_FLASH_BANK_SIZE) -#define RO_BANK_COUNT (CONFIG_SECTION_RO_SIZE / CONFIG_FLASH_BANK_SIZE) - - -/* Flags for persist_state.flags */ -/* Protect persist state and RO firmware at boot */ -#define PERSIST_FLAG_PROTECT_RO 0x02 - -/* Persistent protection state - emulates a SPI status register for flashrom */ -struct persist_state { - uint8_t version; /* Version of this struct */ - uint8_t flags; /* Lock flags (PERSIST_FLAG_*) */ - uint8_t reserved[2]; /* Reserved; set 0 */ -}; - -int stuck_locked; /* Is physical flash stuck protected? */ - -static struct persist_state pstate; /* RAM copy of pstate data */ - -/* Return non-zero if the write protect pin is asserted */ -static int wp_pin_asserted(void) -{ -#if defined(BOARD_link) && defined(CONFIG_TASK_POWERBTN) - return write_protect_asserted(); -#elif defined(CHIP_VARIANT_stm32f100) - /* Fake write protect pin */ - return write_protect_asserted(); -#elif defined(CHIP_STM32) - /* TODO (vpalatin) : write protect scheme for stm32 */ - /* - * Always enable write protect until we have WP pin. For developer to - * unlock WP, please use stm32mon -u and immediately re-program the - * pstate sector (so that apply_pstate() has no chance to run). - */ - return 1; -#else - /* Other boards don't have a WP pin */ - return 0; -#endif -} - -/* Read persistent state into pstate. */ -static int read_pstate(void) -{ -#ifdef CHIP_stm32 - memset(&pstate, 0, sizeof(pstate)); - pstate.version = PERSIST_STATE_VERSION; - return EC_SUCCESS; -#else - const char *flash_pstate = flash_physical_dataptr(PSTATE_OFFSET); - - if (flash_pstate) - memcpy(&pstate, flash_pstate, sizeof(pstate)); - - /* Sanity-check data and initialize if necessary */ - if (pstate.version != PERSIST_STATE_VERSION || !flash_pstate) { - memset(&pstate, 0, sizeof(pstate)); - pstate.version = PERSIST_STATE_VERSION; - } - - return flash_pstate ? EC_SUCCESS : EC_ERROR_UNKNOWN; -#endif /* CHIP_stm32 */ -} - -/* Write persistent state from pstate, erasing if necessary. */ -static int write_pstate(void) -{ -#ifdef CHIP_stm32 - return EC_SUCCESS; -#else - int rv; - - /* Erase pstate */ - /* - * TODO: optimize based on current physical flash contents; we can - * avoid the erase if we're only changing 1's into 0's. - */ - rv = flash_physical_erase(PSTATE_OFFSET, PSTATE_SIZE); - if (rv) - return rv; - - /* - * Note that if we lose power in here, we'll lose the pstate contents. - * That's ok, because it's only possible to write the pstate before - * it's protected. - */ - - /* Rewrite the data */ - return flash_physical_write(PSTATE_OFFSET, sizeof(pstate), - (const char *)&pstate); -#endif -} - -/* Apply write protect based on persistent state. */ -static int apply_pstate(void) -{ - int rv; - - /* If write protect is disabled, nothing to do */ - if (!wp_pin_asserted()) - return EC_SUCCESS; - - /* Read the current persist state from flash */ - rv = read_pstate(); - if (rv) - return rv; - - /* If flash isn't locked, nothing to do */ - if (!(pstate.flags & PERSIST_FLAG_PROTECT_RO)) - return EC_SUCCESS; - - /* Lock the protection data first */ - flash_physical_set_protect(PSTATE_BANK, 1); - - /* Lock the read-only section whenever pstate is locked */ - flash_physical_set_protect(RO_BANK_OFFSET, RO_BANK_COUNT); - - return EC_SUCCESS; -} - int flash_dataptr(int offset, int size_req, int align, char **ptrp) { if (offset < 0 || size_req < 0 || @@ -173,105 +42,6 @@ int flash_erase(int offset, int size) return flash_physical_erase(offset, size); } -int flash_protect_until_reboot(void) -{ - /* Ignore if write protect is disabled */ - if (!wp_pin_asserted()) - return EC_SUCCESS; - - /* Protect the entire flash */ - flash_physical_set_protect(0, CONFIG_FLASH_PHYSICAL_SIZE / - CONFIG_FLASH_BANK_SIZE); - - return EC_SUCCESS; -} - -int flash_enable_protect(int enable) -{ - int new_flags = enable ? PERSIST_FLAG_PROTECT_RO : 0; - int rv; - - /* Read the current persist state from flash */ - rv = read_pstate(); - if (rv) - return rv; - - /* Update state if necessary */ - if (pstate.flags != new_flags) { - - /* Fail if write protect block is already locked */ - if (flash_physical_get_protect(PSTATE_BANK)) - return EC_ERROR_ACCESS_DENIED; - - /* Set the new flag */ - pstate.flags = new_flags; - - /* Write the state back to flash */ - rv = write_pstate(); - if (rv) - return rv; - } - - /* If unlocking, done now */ - if (!enable) - return EC_SUCCESS; - - /* Otherwise, we need to protect RO code NOW */ - return apply_pstate(); -} - -int flash_get_protect(void) -{ - int flags = 0; - int i; - - /* Read the current persist state from flash */ - read_pstate(); - if (pstate.flags & PERSIST_FLAG_PROTECT_RO) - flags |= EC_FLASH_PROTECT_RO_AT_BOOT; - - /* Check if write protect pin is asserted now */ - if (wp_pin_asserted()) - flags |= EC_FLASH_PROTECT_GPIO_ASSERTED; - - /* Scan flash protection */ - for (i = 0; i < PHYSICAL_BANKS; i++) { - /* Is this bank part of RO? */ - int is_ro = ((i >= RO_BANK_OFFSET && - i < RO_BANK_OFFSET + RO_BANK_COUNT) || - i == PSTATE_BANK); - int bank_flag = (is_ro ? EC_FLASH_PROTECT_RO_NOW : - EC_FLASH_PROTECT_RW_NOW); - - if (flash_physical_get_protect(i)) { - /* At least one bank in the region is protected */ - flags |= bank_flag; - } else if (flags & bank_flag) { - /* But not all banks in the region! */ - flags |= EC_FLASH_PROTECT_ERROR_INCONSISTENT; - } - } - - /* Check if any banks were stuck locked at boot */ - if (stuck_locked) - flags |= EC_FLASH_PROTECT_ERROR_STUCK; - - return flags; -} - -/*****************************************************************************/ -/* Initialization */ - -int flash_pre_init(void) -{ - /* Initialize the physical flash interface */ - if (flash_physical_pre_init() == EC_ERROR_ACCESS_DENIED) - stuck_locked = 1; - - /* Apply write protect to blocks if needed */ - return apply_pstate(); -} - /*****************************************************************************/ /* Console commands */ @@ -312,10 +82,6 @@ static int command_flash_info(int argc, char **argv) int i; ccprintf("Physical:%4d KB\n", CONFIG_FLASH_PHYSICAL_SIZE / 1024); - if (flash_physical_size() != CONFIG_FLASH_PHYSICAL_SIZE) - ccprintf("But chip claims %d KB!\n", - flash_physical_size() / 1024); - ccprintf("Usable: %4d KB\n", CONFIG_FLASH_SIZE / 1024); ccprintf("Write: %4d B\n", CONFIG_FLASH_WRITE_SIZE); ccprintf("Erase: %4d B\n", CONFIG_FLASH_ERASE_SIZE); @@ -338,7 +104,8 @@ static int command_flash_info(int argc, char **argv) ccputs("\n"); ccputs("Protected now:"); - for (i = 0; i < PHYSICAL_BANKS; i++) { + for (i = 0; i < CONFIG_FLASH_PHYSICAL_SIZE / CONFIG_FLASH_BANK_SIZE; + i++) { if (!(i & 31)) ccputs("\n "); else if (!(i & 7)) @@ -419,11 +186,12 @@ static int command_flash_wp(int argc, char **argv) return EC_ERROR_PARAM_COUNT; if (!strcasecmp(argv[1], "enable")) - return flash_enable_protect(1); + return flash_set_protect(EC_FLASH_PROTECT_RO_AT_BOOT, -1); else if (!strcasecmp(argv[1], "disable")) - return flash_enable_protect(0); + return flash_set_protect(EC_FLASH_PROTECT_RO_AT_BOOT, 0); else if (!strcasecmp(argv[1], "now")) - return flash_protect_until_reboot(); + return flash_set_protect(EC_FLASH_PROTECT_RW_NOW | + EC_FLASH_PROTECT_RO_NOW, -1); else return EC_ERROR_PARAM1; } @@ -511,15 +279,14 @@ static int flash_command_protect(struct host_cmd_handler_args *args) struct ec_response_flash_protect *r = (struct ec_response_flash_protect *)args->response; - /* Handle requesting new flags */ - if (p->mask & EC_FLASH_PROTECT_RO_AT_BOOT) - flash_enable_protect(p->flags & EC_FLASH_PROTECT_RO_AT_BOOT); - - if ((p->mask & EC_FLASH_PROTECT_RW_NOW) && - (p->flags & EC_FLASH_PROTECT_RW_NOW)) - flash_protect_until_reboot(); - - /* Ignore all other requested flags */ + /* + * Handle requesting new flags. Note that we ignore the return code + * from flash_set_protect(), since errors will be visible to the caller + * via the flags in the response. (If we returned error, the caller + * wouldn't get the response.) + */ + if (p->mask) + flash_set_protect(p->mask, p->flags); /* * Retrieve the current flags. The caller can use this to determine @@ -530,16 +297,20 @@ static int flash_command_protect(struct host_cmd_handler_args *args) r->flags = flash_get_protect(); /* Indicate which flags are valid on this platform */ - r->valid_flags = (EC_FLASH_PROTECT_RO_AT_BOOT | - EC_FLASH_PROTECT_RO_NOW | - EC_FLASH_PROTECT_RW_NOW | - EC_FLASH_PROTECT_GPIO_ASSERTED | - EC_FLASH_PROTECT_ERROR_STUCK | - EC_FLASH_PROTECT_ERROR_INCONSISTENT); - - /* Indicate which flags can be changed this boot */ + r->valid_flags = + EC_FLASH_PROTECT_GPIO_ASSERTED | + EC_FLASH_PROTECT_ERROR_STUCK | + EC_FLASH_PROTECT_RO_AT_BOOT | + EC_FLASH_PROTECT_RO_NOW | + EC_FLASH_PROTECT_RW_NOW | + EC_FLASH_PROTECT_ERROR_INCONSISTENT; r->writable_flags = 0; + /* If RO protection isn't enabled, its at-boot state can be changed. */ + if (!(r->flags & EC_FLASH_PROTECT_RO_NOW)) + r->writable_flags |= EC_FLASH_PROTECT_RO_AT_BOOT; + +#ifdef CHIP_lm4 /* * If RW protection isn't enabled this boot, it can be enabled if the * * WP GPIO is asserted. @@ -548,12 +319,11 @@ static int flash_command_protect(struct host_cmd_handler_args *args) (r->flags & EC_FLASH_PROTECT_GPIO_ASSERTED)) r->writable_flags |= EC_FLASH_PROTECT_RW_NOW; - /* If RO protection isn't enabled, its at-boot state can be changed. */ - if (!(r->flags & EC_FLASH_PROTECT_RO_NOW)) - r->writable_flags |= EC_FLASH_PROTECT_RO_AT_BOOT; - - /* Other flags can't be written */ - +#elif defined(CHIP_stm32) + /* RW protection can only be changed at boot */ + r->valid_flags |= EC_FLASH_PROTECT_RW_AT_BOOT; + r->writable_flags |= EC_FLASH_PROTECT_RW_AT_BOOT; +#endif args->response_size = sizeof(*r); |