mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-28 02:35:28 +00:00
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:
committed by
chrome-internal-fetch
parent
5ff320f66e
commit
82915c2502
@@ -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);
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
flash-stm32f.c
|
||||
44
chip/stm32/flash-stm32f0.c
Normal file
44
chip/stm32/flash-stm32f0.c
Normal 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;
|
||||
}
|
||||
@@ -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 |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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. */
|
||||
|
||||
Reference in New Issue
Block a user