From a7d7297577d5450610ddc1a76544fe3300873042 Mon Sep 17 00:00:00 2001 From: Vic Yang Date: Sun, 5 Aug 2012 22:26:09 +0800 Subject: stm32f: Use FLASH_KEYR to lock entire flash Writing wrong key to FLASH_KEYR locks entire flash and effectively performs RW_NOW. Therefore we can use this and remove RW_AT_BOOT to prevent having to reboot for RW to be protected. BUG=chrome-os-partner:12043 TEST=1. fakewp 1 -> wp_gpio_asserted 2. flashwp now -> nothing happens 2. flashwp enable -> wp_gpio_asserted ro_at_boot 3. reboot -> wp_gpio_asserted ro_at_boot ro_now 4. flasherase 0x10000 0x1000 -> success 5. flashwp now -> wp_gpio_asserted ro_at_boot ro_now rw_now 6. flasherase 0x10000 0x1000 -> error 7. reboot -> wp_gpio_asserted ro_at_boot ro_now 8. flasherase 0x10000 0x1000 -> success Change-Id: I22df188e31404c190c5830c6d94c9646224eb9ab Reviewed-on: https://gerrit.chromium.org/gerrit/29255 Reviewed-by: Randall Spangler Reviewed-by: Vincent Palatin Commit-Ready: Vic Yang Tested-by: Vic Yang --- chip/stm32/flash-stm32f100.c | 133 ++++++++++++++++++++++++++++--------------- chip/stm32/system.c | 13 ----- core/cortex-m/panic.c | 17 ++++++ include/panic.h | 7 +++ 4 files changed, 110 insertions(+), 60 deletions(-) diff --git a/chip/stm32/flash-stm32f100.c b/chip/stm32/flash-stm32f100.c index 68f2268198..fe8af24d54 100644 --- a/chip/stm32/flash-stm32f100.c +++ b/chip/stm32/flash-stm32f100.c @@ -8,6 +8,7 @@ #include "console.h" #include "flash.h" #include "registers.h" +#include "panic.h" #include "power_button.h" #include "system.h" #include "task.h" @@ -70,13 +71,14 @@ struct persist_state { /* Protect persist state and RO firmware at boot */ #define PERSIST_FLAG_PROTECT_RO 0x02 +/* Flag indicating whether we have locked down entire flash */ +static int entire_flash_locked; + /* Functions defined in system.c to access backup registers */ -int system_set_flash_rw_at_boot(int val); -int system_get_flash_rw_at_boot(void); int system_set_fake_wp(int val); int system_get_fake_wp(void); -static void write_optb(int byte, uint8_t value); +static int write_optb(int byte, uint8_t value); static int wait_busy(void) { @@ -89,6 +91,12 @@ static int wait_busy(void) static int unlock(int locks) { + /* + * We may have already locked the flash module and get a bus fault + * in the attempt to unlock. Need to disable bus fault handler now. + */ + ignore_bus_fault(1); + /* unlock CR if needed */ if (STM32_FLASH_CR & CR_LOCK) { STM32_FLASH_KEYR = KEY1; @@ -100,6 +108,9 @@ static int unlock(int locks) STM32_FLASH_OPTKEYR = KEY2; } + /* Re-enable bus fault handler */ + ignore_bus_fault(0); + return ((STM32_FLASH_CR ^ OPT_LOCK) & (locks | CR_LOCK)) ? EC_ERROR_UNKNOWN : EC_SUCCESS; } @@ -129,19 +140,28 @@ static uint8_t read_optb(int byte) return *(uint8_t *)(STM32_OPTB_BASE + byte); } -static void erase_optb(void) +static int erase_optb(void) { - wait_busy(); + int rv; - if (unlock(OPT_LOCK) != EC_SUCCESS) - return; + rv = wait_busy(); + if (rv) + return rv; + + rv = unlock(OPT_LOCK); + if (rv) + return rv; /* Must be set in 2 separate lines. */ STM32_FLASH_CR |= OPTER; STM32_FLASH_CR |= STRT; - wait_busy(); + rv = wait_busy(); + if (rv) + return rv; lock(); + + return EC_SUCCESS; } /* @@ -149,44 +169,57 @@ static void erase_optb(void) * rest of bytes, but make this byte 0xff. * Note that this could make a recursive call to write_optb(). */ -static void preserve_optb(int byte) +static int preserve_optb(int byte) { - int i; + int i, rv; uint8_t optb[8]; /* The byte has been reset, no need to run preserve. */ if (*(uint16_t *)(STM32_OPTB_BASE + byte) == 0xffff) - return; + return EC_SUCCESS;; for (i = 0; i < ARRAY_SIZE(optb); ++i) optb[i] = read_optb(i * 2); optb[byte / 2] = 0xff; - erase_optb(); - for (i = 0; i < ARRAY_SIZE(optb); ++i) - write_optb(i * 2, optb[i]); + rv = erase_optb(); + if (rv) + return rv; + for (i = 0; i < ARRAY_SIZE(optb); ++i) { + rv = write_optb(i * 2, optb[i]); + if (rv) + return rv; + } + + return EC_SUCCESS; } -static void write_optb(int byte, uint8_t value) +static int write_optb(int byte, uint8_t value) { volatile int16_t *hword = (uint16_t *)(STM32_OPTB_BASE + byte); + int rv; - wait_busy(); + rv = wait_busy(); + if (rv) + return rv; /* The target byte is the value we want to write. */ if (*(uint8_t *)hword == value) - return; + return EC_SUCCESS; /* Try to erase that byte back to 0xff. */ - preserve_optb(byte); + rv = preserve_optb(byte); + if (rv) + return rv; /* The value is 0xff after erase. No need to write 0xff again. */ if (value == 0xff) - return; + return EC_SUCCESS; - if (unlock(OPT_LOCK) != EC_SUCCESS) - return; + rv = unlock(OPT_LOCK); + if (rv) + return rv; /* set OPTPG bit */ STM32_FLASH_CR |= OPTPG; @@ -196,8 +229,12 @@ static void write_optb(int byte, uint8_t value) /* reset OPTPG bit */ STM32_FLASH_CR &= ~OPTPG; - wait_busy(); + rv = wait_busy(); + if (rv) + return rv; lock(); + + return EC_SUCCESS; } /** @@ -371,7 +408,7 @@ exit_er: int flash_physical_get_protect(int block) { - return !(STM32_FLASH_WRPR & (1 << block)); + return entire_flash_locked || !(STM32_FLASH_WRPR & (1 << block)); } static int flash_physical_get_protect_at_boot(int block) @@ -440,18 +477,17 @@ static int protect_ro_at_boot(int enable, int force) return EC_SUCCESS; } -static int protect_rw_at_boot(int enable, int force) +static int protect_entire_flash_until_reboot(void) { - int old_flag = system_get_flash_rw_at_boot() ? 1 : 0; - int new_flag = enable ? 1 : 0; + /* + * Lock by writing a wrong key to FLASH_KEYR. This triggers a bus + * fault, so we need to disable bus fault handler while doing this. + */ + ignore_bus_fault(1); + STM32_FLASH_KEYR = 0xffffffff; + ignore_bus_fault(0); - /* Update state if necessary */ - if (old_flag != new_flag || force) { - system_set_flash_rw_at_boot(new_flag); - flash_physical_set_protect_at_boot(RW_BANK_OFFSET, - RW_BANK_COUNT, - new_flag); - } + entire_flash_locked = 1; return EC_SUCCESS; } @@ -465,7 +501,6 @@ static int register_need_reset(void) uint32_t flags = flash_get_protect(); int i; int ro_at_boot = (flags & EC_FLASH_PROTECT_RO_AT_BOOT) ? 1 : 0; - int rw_at_boot = (flags & EC_FLASH_PROTECT_RW_AT_BOOT) ? 1 : 0; int ro_wp_region_start = RO_BANK_OFFSET; int ro_wp_region_end = RO_BANK_OFFSET + RO_BANK_COUNT + PSTATE_BANK_COUNT; @@ -473,9 +508,6 @@ static int register_need_reset(void) for (i = ro_wp_region_start; i < ro_wp_region_end; i++) if (flash_physical_get_protect_at_boot(i) != ro_at_boot) return 1; - for (i = RW_BANK_OFFSET; i < RW_BANK_OFFSET + RW_BANK_COUNT; i++) - if (flash_physical_get_protect_at_boot(i) != rw_at_boot) - return 1; return 0; } @@ -520,15 +552,11 @@ int flash_pre_init(void) */ protect_ro_at_boot( prot_flags & EC_FLASH_PROTECT_RO_AT_BOOT, 1); - /* And reset RW protect register */ - protect_rw_at_boot( - prot_flags & EC_FLASH_PROTECT_RW_AT_BOOT, 1); need_reset = 1; } } else { - if ((prot_flags & EC_FLASH_PROTECT_RO_NOW) || - (prot_flags & EC_FLASH_PROTECT_RW_NOW)) { + if (prot_flags & EC_FLASH_PROTECT_RO_NOW) { /* * Write protect pin unasserted but some section is * protected. Drop it and reboot. @@ -559,9 +587,8 @@ uint32_t flash_get_protect(void) if (pstate.flags & PERSIST_FLAG_PROTECT_RO) flags |= EC_FLASH_PROTECT_RO_AT_BOOT; - /* Read the current persist state from flash */ - if (system_get_flash_rw_at_boot()) - flags |= EC_FLASH_PROTECT_RW_AT_BOOT; + if (entire_flash_locked) + flags |= EC_FLASH_PROTECT_RW_NOW; /* Scan flash protection */ for (i = 0; i < PHYSICAL_BANKS; i++) { @@ -603,8 +630,20 @@ int flash_set_protect(uint32_t mask, uint32_t flags) retval = rv; } - if (mask & EC_FLASH_PROTECT_RW_AT_BOOT) { - rv = protect_rw_at_boot(flags & EC_FLASH_PROTECT_RW_AT_BOOT, 0); + /* + * All subsequent flags only work if write protect is enabled (that is, + * hardware WP flag) *and* RO is protected at boot (software WP flag). + */ + if ((~flash_get_protect()) & (EC_FLASH_PROTECT_GPIO_ASSERTED | + EC_FLASH_PROTECT_RO_AT_BOOT)) + return retval; + + if (mask & EC_FLASH_PROTECT_RW_NOW) { + /* + * Since RO is already protected, protecting entire flash + * is effectively protecting RW. + */ + rv = protect_entire_flash_until_reboot(); if (rv) retval = rv; } diff --git a/chip/stm32/system.c b/chip/stm32/system.c index 4bfecf0812..5a8f7bfc5e 100644 --- a/chip/stm32/system.c +++ b/chip/stm32/system.c @@ -16,7 +16,6 @@ enum bkpdata_index { BKPDATA_INDEX_SCRATCHPAD, /* General-purpose scratchpad */ BKPDATA_INDEX_WAKE, /* Wake reasons for hibernate */ BKPDATA_INDEX_SAVED_RESET_FLAGS,/* Saved reset flags */ - BKPDATA_INDEX_FLASH_RW_AT_BOOT, /* Flash protect RW at boot flag */ BKPDATA_INDEX_FAKE_WP, /* Fake write-protect pin */ /* TODO: Remove this when we have real * write protect pin. @@ -299,15 +298,3 @@ int system_get_fake_wp(void) { return bkpdata_read(BKPDATA_INDEX_FAKE_WP); } - - -int system_set_flash_rw_at_boot(int val) -{ - return bkpdata_write(BKPDATA_INDEX_FLASH_RW_AT_BOOT, (uint16_t)val); -} - - -int system_get_flash_rw_at_boot(void) -{ - return bkpdata_read(BKPDATA_INDEX_FLASH_RW_AT_BOOT); -} diff --git a/core/cortex-m/panic.c b/core/cortex-m/panic.c index 1663d8fd93..26d537ce85 100644 --- a/core/cortex-m/panic.c +++ b/core/cortex-m/panic.c @@ -19,6 +19,9 @@ /* This is the size of our private panic stack, if we have one */ #define STACK_SIZE_WORDS 64 +/* Whether bus fault is ignored */ +static int bus_fault_ignored; + /* We save registers here for display by report_panic() */ static struct save_area { @@ -361,6 +364,20 @@ void exception_panic(void) } +void bus_fault_handler(void) __attribute__((naked)); +void bus_fault_handler(void) +{ + if (!bus_fault_ignored) + exception_panic(); +} + + +void ignore_bus_fault(int ignored) +{ + bus_fault_ignored = ignored; +} + + #ifdef CONFIG_ASSERT_HELP void panic_assert_fail(const char *msg, const char *func, const char *fname, int linenum) diff --git a/include/panic.h b/include/panic.h index f42a399efa..d22a0e11be 100644 --- a/include/panic.h +++ b/include/panic.h @@ -85,4 +85,11 @@ void panic(const char *msg); */ void report_panic(const char *msg, uint32_t *lregs); +/** + * Enable/disable bus fault handler + * + * @param ignored Non-zero if ignoring bus fault + */ +void ignore_bus_fault(int ignored); + #endif -- cgit v1.2.1