diff options
author | Vic Yang <victoryang@chromium.org> | 2014-10-09 15:19:22 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-10-15 23:55:55 +0000 |
commit | 82915c25029c0bc2c018cfc080d913255ed82aac (patch) | |
tree | 1da32cff8e9e01142b63960fd454ff2b1832278a | |
parent | 5ff320f66e990a5efe8270f6125ed7c55699d50c (diff) | |
download | chrome-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.c | 18 | ||||
-rw-r--r--[l---------] | chip/stm32/flash-stm32f0.c | 45 | ||||
-rw-r--r-- | chip/stm32/flash-stm32l.c | 7 | ||||
-rw-r--r-- | chip/stm32/registers.h | 2 | ||||
-rw-r--r-- | chip/stm32/system.c | 12 | ||||
-rw-r--r-- | common/flash.c | 48 | ||||
-rw-r--r-- | include/flash.h | 6 |
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. */ |