summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVic Yang <victoryang@chromium.org>2014-10-09 15:19:22 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-10-15 23:55:55 +0000
commit82915c25029c0bc2c018cfc080d913255ed82aac (patch)
tree1da32cff8e9e01142b63960fd454ff2b1832278a
parent5ff320f66e990a5efe8270f6125ed7c55699d50c (diff)
downloadchrome-ec-82915c25029c0bc2c018cfc080d913255ed82aac.tar.gz
Write protect support for STM32F0
On STM32F0, we cannot work around the hard fault triggered when trying to protect the whole flash. Therefore, we need to go with the ALL_AT_BOOT approach. When write protect is enabled, instead of setting ALL_NOW flag to immediately lock down the entire flash, we need to set ALL_AT_BOOT and then reboot to have the protection take effect. BUG=chrome-os-partner:32745 TEST=Along with the next CL. On Ryu: 1. Enable HW WP. Check the output of 'ectool flashprotect' and see correct flags. 2. 'flashrom -p ec --wp-range 0 0x10000'. Check RO_AT_BOOT is set. 3. Reboot EC and check RO_NOW is enabled. 4. Boot the system and check ALL_NOW is set. 5. Update BIOS and reboot. Check software sync updates EC-RW. 6. 'flashrom -p ec --wp-disable' and check it fails. 7. Disable HW WP and reboot EC. Check RO_NOW and ALL_NOW are cleared. 8. 'flashrom -p ec --wp-disable' and check RO_AT_BOOT is cleared. TEST=Enable/disable WP on Spring. Check RO_AT_BOOT/ALL_NOW can be set properly. BRANCH=samus Change-Id: I1c7c4f98f2535f1c8a1c7daaa88d47412d015977 Signed-off-by: Vic Yang <victoryang@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/222622 Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--chip/stm32/flash-f.c18
-rw-r--r--[l---------]chip/stm32/flash-stm32f0.c45
-rw-r--r--chip/stm32/flash-stm32l.c7
-rw-r--r--chip/stm32/registers.h2
-rw-r--r--chip/stm32/system.c12
-rw-r--r--common/flash.c48
-rw-r--r--include/flash.h6
7 files changed, 123 insertions, 15 deletions
diff --git a/chip/stm32/flash-f.c b/chip/stm32/flash-f.c
index 29e2c062d7..e457aea8ce 100644
--- a/chip/stm32/flash-f.c
+++ b/chip/stm32/flash-f.c
@@ -426,8 +426,9 @@ int flash_pre_init(void)
* to the check above. One of them should be able to
* go away.
*/
- flash_protect_ro_at_boot(
- prot_flags & EC_FLASH_PROTECT_RO_AT_BOOT);
+ flash_protect_at_boot(
+ (prot_flags & EC_FLASH_PROTECT_RO_AT_BOOT) ?
+ FLASH_WP_RO : FLASH_WP_NONE);
need_reset = 1;
}
} else {
@@ -441,6 +442,19 @@ int flash_pre_init(void)
}
}
+ if (!!(prot_flags & EC_FLASH_PROTECT_ALL_AT_BOOT) !=
+ !!(prot_flags & EC_FLASH_PROTECT_ALL_NOW)) {
+ /*
+ * ALL_AT_BOOT and ALL_NOW should be both set or both unset
+ * at boot. If they are not, it must be that the chip requires
+ * OBL_LAUNCH to be set to reload option bytes. Let's reset
+ * the system with OBL_LAUNCH set.
+ * This assumes OBL_LAUNCH is used for hard reset in
+ * chip/stm32/system.c.
+ */
+ need_reset = 1;
+ }
+
if (need_reset)
system_reset(SYSTEM_RESET_HARD | SYSTEM_RESET_PRESERVE_FLAGS);
diff --git a/chip/stm32/flash-stm32f0.c b/chip/stm32/flash-stm32f0.c
index 13dc8d8e47..bbf3574c21 120000..100644
--- a/chip/stm32/flash-stm32f0.c
+++ b/chip/stm32/flash-stm32f0.c
@@ -1 +1,44 @@
-flash-stm32f.c \ No newline at end of file
+/* Copyright 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Flash memory module for Chrome EC */
+
+#include "common.h"
+#include "flash.h"
+#include "registers.h"
+
+/*****************************************************************************/
+/* Physical layer APIs */
+
+int flash_physical_get_protect(int block)
+{
+ return !(STM32_FLASH_WRPR & (1 << block));
+}
+
+uint32_t flash_physical_get_protect_flags(void)
+{
+ uint32_t flags = 0;
+ uint32_t wrp01 = REG32(STM32_OPTB_BASE + STM32_OPTB_WRP01);
+ uint32_t wrp23 = REG32(STM32_OPTB_BASE + STM32_OPTB_WRP23);
+
+ if (STM32_FLASH_WRPR == 0)
+ flags |= EC_FLASH_PROTECT_ALL_NOW;
+
+ if (wrp01 == 0xff00ff00 && wrp23 == 0xff00ff00)
+ flags |= EC_FLASH_PROTECT_ALL_AT_BOOT;
+
+ return flags;
+}
+
+int flash_physical_protect_now(int all)
+{
+ return EC_ERROR_INVAL;
+}
+
+int flash_physical_restore_state(void)
+{
+ /* Nothing to restore */
+ return 0;
+}
diff --git a/chip/stm32/flash-stm32l.c b/chip/stm32/flash-stm32l.c
index 90ed1a9d55..98f46565a3 100644
--- a/chip/stm32/flash-stm32l.c
+++ b/chip/stm32/flash-stm32l.c
@@ -422,7 +422,7 @@ int flash_pre_init(void)
* update to the write protect register and reboot so
* it takes effect.
*/
- flash_protect_ro_at_boot(1);
+ flash_protect_at_boot(FLASH_WP_RO);
need_reset = 1;
}
@@ -431,8 +431,9 @@ int flash_pre_init(void)
* Write protect register was in an inconsistent state.
* Set it back to a good state and reboot.
*/
- flash_protect_ro_at_boot(
- prot_flags & EC_FLASH_PROTECT_RO_AT_BOOT);
+ flash_protect_at_boot(
+ (prot_flags & EC_FLASH_PROTECT_RO_AT_BOOT) ?
+ FLASH_WP_RO : FLASH_WP_NONE);
need_reset = 1;
}
} else if (prot_flags & (EC_FLASH_PROTECT_RO_NOW |
diff --git a/chip/stm32/registers.h b/chip/stm32/registers.h
index b721bc9915..c5ac5a9852 100644
--- a/chip/stm32/registers.h
+++ b/chip/stm32/registers.h
@@ -861,6 +861,7 @@ typedef volatile struct stm32_spi_regs stm32_spi_regs_t;
#define STM32_FLASH_OPTKEYR REG32(STM32_FLASH_REGS_BASE + 0x08)
#define STM32_FLASH_SR REG32(STM32_FLASH_REGS_BASE + 0x0c)
#define STM32_FLASH_CR REG32(STM32_FLASH_REGS_BASE + 0x10)
+#define STM32_FLASH_CR_OBL_LAUNCH (1 << 13)
#define STM32_FLASH_AR REG32(STM32_FLASH_REGS_BASE + 0x14)
#define STM32_FLASH_OBR REG32(STM32_FLASH_REGS_BASE + 0x1c)
#define STM32_FLASH_WRPR REG32(STM32_FLASH_REGS_BASE + 0x20)
@@ -870,6 +871,7 @@ typedef volatile struct stm32_spi_regs stm32_spi_regs_t;
#define STM32_OPTB_RDP_OFF 0x00
#define STM32_OPTB_USER_OFF 0x02
#define STM32_OPTB_WRP_OFF(n) (0x08 + (n&3) * 2)
+#define STM32_OPTB_WRP01 0x08
#define STM32_OPTB_WRP23 0x0c
#define STM32_OPTB_COMPL_SHIFT 8
diff --git a/chip/stm32/system.c b/chip/stm32/system.c
index fa7b199325..52b200ea11 100644
--- a/chip/stm32/system.c
+++ b/chip/stm32/system.c
@@ -231,11 +231,21 @@ void system_reset(int flags)
/* Fall through to watchdog if that fails */
#endif
+#if defined(CHIP_FAMILY_STM32F0) || defined(CHIP_FAMILY_STM32F3)
+ /*
+ * On some chips, a reboot doesn't always reload the option
+ * bytes, and we need to explicitly request for a reload.
+ * The reload request triggers a chip reset, so let's just
+ * use this for hard reset.
+ */
+ STM32_FLASH_CR |= STM32_FLASH_CR_OBL_LAUNCH;
+#else
/* Ask the watchdog to trigger a hard reboot */
STM32_IWDG_KR = 0x5555;
STM32_IWDG_RLR = 0x1;
STM32_IWDG_KR = 0xcccc;
- /* wait for the watchdog */
+#endif
+ /* wait for the chip to reboot */
while (1)
;
} else {
diff --git a/common/flash.c b/common/flash.c
index bd2c191ee7..15af5cd1e8 100644
--- a/common/flash.c
+++ b/common/flash.c
@@ -151,10 +151,10 @@ int flash_erase(int offset, int size)
return flash_physical_erase(offset, size);
}
-int flash_protect_ro_at_boot(int enable)
+int flash_protect_at_boot(enum flash_wp_range range)
{
struct persist_state pstate;
- int new_flags = enable ? PERSIST_FLAG_PROTECT_RO : 0;
+ int new_flags = (range != FLASH_WP_NONE) ? PERSIST_FLAG_PROTECT_RO : 0;
/* Read the current persist state from flash */
flash_read_pstate(&pstate);
@@ -188,7 +188,7 @@ int flash_protect_ro_at_boot(int enable)
* This assumes PSTATE immediately follows RO, which it does on
* all STM32 platforms (which are the only ones with this config).
*/
- flash_physical_protect_at_boot(new_flags ? FLASH_WP_RO : FLASH_WP_NONE);
+ flash_physical_protect_at_boot(range);
#endif
return EC_SUCCESS;
@@ -261,14 +261,45 @@ int flash_set_protect(uint32_t mask, uint32_t flags)
{
int retval = EC_SUCCESS;
int rv;
+ enum flash_wp_range range = FLASH_WP_NONE;
+ int need_set_protect = 0;
/*
* Process flags we can set. Track the most recent error, but process
* all flags before returning.
*/
+
+ /*
+ * AT_BOOT flags are trickier than NOW flags, as they can be set
+ * when HW write protection is disabled and can be unset without
+ * a reboot.
+ *
+ * If we are only setting/clearing RO_AT_BOOT, things are simple.
+ * Setting ALL_AT_BOOT is processed only if HW write protection is
+ * enabled and RO_AT_BOOT is set, so it's also simple.
+ *
+ * The most tricky one is when we want to clear ALL_AT_BOOT. We need
+ * to determine whether to clear protection for the entire flash or
+ * leave RO protected. There are two cases that we want to keep RO
+ * protected:
+ * 1. RO_AT_BOOT was already set before flash_set_protect() is
+ * called.
+ * 2. RO_AT_BOOT was not set, but it's requested to be set by
+ * the caller of flash_set_protect().
+ */
if (mask & EC_FLASH_PROTECT_RO_AT_BOOT) {
- rv = flash_protect_ro_at_boot(
- flags & EC_FLASH_PROTECT_RO_AT_BOOT);
+ range = (flags & EC_FLASH_PROTECT_RO_AT_BOOT) ?
+ FLASH_WP_RO : FLASH_WP_NONE;
+ need_set_protect = 1;
+ }
+ if ((mask & EC_FLASH_PROTECT_ALL_AT_BOOT) &&
+ !(flags & EC_FLASH_PROTECT_ALL_AT_BOOT)) {
+ if (flash_get_protect() & EC_FLASH_PROTECT_RO_AT_BOOT)
+ range = FLASH_WP_RO;
+ need_set_protect = 1;
+ }
+ if (need_set_protect) {
+ rv = flash_protect_at_boot(range);
if (rv)
retval = rv;
}
@@ -281,6 +312,13 @@ int flash_set_protect(uint32_t mask, uint32_t flags)
EC_FLASH_PROTECT_RO_AT_BOOT))
return retval;
+ if ((mask & EC_FLASH_PROTECT_ALL_AT_BOOT) &&
+ (flags & EC_FLASH_PROTECT_ALL_AT_BOOT)) {
+ rv = flash_protect_at_boot(FLASH_WP_ALL);
+ if (rv)
+ retval = rv;
+ }
+
if ((mask & EC_FLASH_PROTECT_RO_NOW) &&
(flags & EC_FLASH_PROTECT_RO_NOW)) {
rv = flash_physical_protect_now(0);
diff --git a/include/flash.h b/include/flash.h
index dff1be7948..0c6e11c429 100644
--- a/include/flash.h
+++ b/include/flash.h
@@ -125,17 +125,17 @@ int flash_physical_restore_state(void);
int flash_is_erased(uint32_t offset, int size);
/**
- * Enable write protect for the read-only code.
+ * Enable write protect for the specified range.
*
* Once write protect is enabled, it will STAY enabled until the system is
* hard-rebooted with the hardware write protect pin deasserted. If the write
* protect pin is deasserted, the protect setting is ignored, and the entire
* flash will be writable.
*
- * @param enable Enable write protection
+ * @param range The range to protect.
* @return EC_SUCCESS, or nonzero if error.
*/
-int flash_protect_ro_at_boot(int enable);
+int flash_protect_at_boot(enum flash_wp_range range);
/*****************************************************************************/
/* High-level interface for use by other modules. */