summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVic Yang <victoryang@chromium.org>2012-08-05 22:26:09 +0800
committerGerrit <chrome-bot@google.com>2012-08-08 11:39:48 -0700
commita7d7297577d5450610ddc1a76544fe3300873042 (patch)
treeb49d4b5150dcb543ddc3955a15354c31c9753070
parent99a770b14cfd4f1e713623088e0311fc95c2927f (diff)
downloadchrome-ec-a7d7297577d5450610ddc1a76544fe3300873042.tar.gz
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 <rspangler@chromium.org> Reviewed-by: Vincent Palatin <vpalatin@chromium.org> Commit-Ready: Vic Yang <victoryang@chromium.org> Tested-by: Vic Yang <victoryang@chromium.org>
-rw-r--r--chip/stm32/flash-stm32f100.c133
-rw-r--r--chip/stm32/system.c13
-rw-r--r--core/cortex-m/panic.c17
-rw-r--r--include/panic.h7
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