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>
This commit is contained in:
Vic Yang
2014-10-09 15:19:22 -07:00
committed by chrome-internal-fetch
parent 5ff320f66e
commit 82915c2502
7 changed files with 123 additions and 15 deletions

View File

@@ -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);

View File

@@ -1 +0,0 @@
flash-stm32f.c

View File

@@ -0,0 +1,44 @@
/* 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;
}

View File

@@ -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 |

View File

@@ -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

View File

@@ -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 {

View File

@@ -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);

View File

@@ -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. */