flash: Add ROLLBACK flash region, that can be protected separately

ROLLBACK region will be used to store rollback information, and
can be protected independently of RW (it can only be protected when
RO is protected, though).

This is only supported on stm32f0 currently.

BRANCH=none
BUG=chrome-os-partner:61671
TEST=on hammer (stm32f072)
     flashinfo => RO+RW not protected
     flashwp true; reboot => only RO protected
     flashwp all; reboot => RO+RW+RB protected
     flashwp noall; reboot => only RO protected
     flashwp rw; reboot => only RO+RW protected
     flashwp rb; reboot => RO+RW+RB protected
     flashwp norb; reboot => RO+RW protected
     flashwp all; reboot => RO+RW+RB protected
     flashwp norw; reboot => RO+RB protected
TEST=on reef, rb/norb commands not available

Change-Id: I45ffc66d91cf3699ecff025e5114c59a73dc8274
Reviewed-on: https://chromium-review.googlesource.com/430519
Commit-Ready: Nicolas Boichat <drinkcat@chromium.org>
Tested-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
This commit is contained in:
Nicolas Boichat
2017-02-14 11:13:52 +08:00
committed by chrome-bot
parent f4174ddaa4
commit 2dcfd2446c
7 changed files with 121 additions and 9 deletions

View File

@@ -356,6 +356,11 @@ int flash_physical_protect_at_boot(uint32_t new_flags)
if (block >= WP_BANK_OFFSET &&
block < WP_BANK_OFFSET + WP_BANK_COUNT)
protect |= new_flags & EC_FLASH_PROTECT_RO_AT_BOOT;
#ifdef CONFIG_ROLLBACK
else if (block >= ROLLBACK_BANK_OFFSET &&
block < ROLLBACK_BANK_OFFSET + ROLLBACK_BANK_COUNT)
protect |= new_flags & EC_FLASH_PROTECT_ROLLBACK_AT_BOOT;
#endif
#ifdef CONFIG_FLASH_PROTECT_RW
else
protect |= new_flags & EC_FLASH_PROTECT_RW_AT_BOOT;
@@ -489,6 +494,15 @@ int flash_pre_init(void)
}
#endif
#ifdef CONFIG_ROLLBACK
if ((flash_physical_get_valid_flags() & EC_FLASH_PROTECT_ROLLBACK_AT_BOOT) &&
(!!(prot_flags & EC_FLASH_PROTECT_ROLLBACK_AT_BOOT) !=
!!(prot_flags & EC_FLASH_PROTECT_ROLLBACK_NOW))) {
/* ROLLBACK_AT_BOOT and ROLLBACK_NOW do not match. */
need_reset = 1;
}
#endif
if (need_reset)
system_reset(SYSTEM_RESET_HARD | SYSTEM_RESET_PRESERVE_FLAGS);

View File

@@ -35,12 +35,16 @@ uint32_t flash_physical_get_protect_flags(void)
* ROLLBACK independently (EC_FLASH_PROTECT_RO_AT_BOOT should be set
* by pstate logic).
*/
#if defined(CONFIG_FLASH_PROTECT_RW)
#if defined(CONFIG_FLASH_PROTECT_RW) || defined(CONFIG_ROLLBACK)
/* Flags that must be set for each region. */
const int mask_flags[] = {
[FLASH_REGION_RW] = EC_FLASH_PROTECT_RW_AT_BOOT,
[FLASH_REGION_RO] = EC_FLASH_PROTECT_RO_AT_BOOT,
#ifdef CONFIG_ROLLBACK
[FLASH_REGION_ROLLBACK] = EC_FLASH_PROTECT_ROLLBACK_AT_BOOT,
#endif
};
/*
* Sets up required mask for wrp01/23 registers: for protection to be
* set, values set in the mask must be zeros, values in the mask << 8
@@ -64,6 +68,11 @@ uint32_t flash_physical_get_protect_flags(void)
if (i >= WP_BANK_OFFSET &&
i < WP_BANK_OFFSET + WP_BANK_COUNT)
region = FLASH_REGION_RO;
#ifdef CONFIG_ROLLBACK
if (i >= ROLLBACK_BANK_OFFSET &&
i < ROLLBACK_BANK_OFFSET + ROLLBACK_BANK_COUNT)
region = FLASH_REGION_ROLLBACK;
#endif
switch (i) {
case 8:
@@ -94,7 +103,7 @@ uint32_t flash_physical_get_protect_flags(void)
#endif
flags |= mask_flags[i];
}
#endif /* CONFIG_FLASH_PROTECT_RW */
#endif /* CONFIG_FLASH_PROTECT_RW || CONFIG_ROLLBACK */
if (wrp01 == 0xff00ff00)
#if CONFIG_FLASH_SIZE > 64 * 1024
@@ -123,6 +132,10 @@ uint32_t flash_physical_get_valid_flags(void)
#ifdef CONFIG_FLASH_PROTECT_RW
EC_FLASH_PROTECT_RW_AT_BOOT |
EC_FLASH_PROTECT_RW_NOW |
#endif
#ifdef CONFIG_ROLLBACK
EC_FLASH_PROTECT_ROLLBACK_AT_BOOT |
EC_FLASH_PROTECT_ROLLBACK_NOW |
#endif
EC_FLASH_PROTECT_ALL_AT_BOOT |
EC_FLASH_PROTECT_ALL_NOW;
@@ -150,5 +163,11 @@ uint32_t flash_physical_get_writable_flags(uint32_t cur_flags)
ret |= EC_FLASH_PROTECT_RW_AT_BOOT;
#endif
#ifdef CONFIG_ROLLBACK
if (cur_flags & (EC_FLASH_PROTECT_ROLLBACK_AT_BOOT |
EC_FLASH_PROTECT_GPIO_ASSERTED))
ret |= EC_FLASH_PROTECT_ROLLBACK_AT_BOOT;
#endif
return ret;
}

View File

@@ -526,9 +526,15 @@ uint32_t flash_get_protect(void)
int i;
/* Region protection status */
int not_protected[FLASH_REGION_COUNT] = {0};
#ifdef CONFIG_ROLLBACK
/* Flags that must be set to set ALL_NOW flag. */
const uint32_t all_flags = EC_FLASH_PROTECT_RO_NOW |
EC_FLASH_PROTECT_RW_NOW |
EC_FLASH_PROTECT_ROLLBACK_NOW;
#else
const uint32_t all_flags = EC_FLASH_PROTECT_RO_NOW |
EC_FLASH_PROTECT_RW_NOW;
#endif
/* Read write protect GPIO */
#ifdef CONFIG_WP_ALWAYS
@@ -555,6 +561,14 @@ uint32_t flash_get_protect(void)
int bank_flag = is_ro ? EC_FLASH_PROTECT_RO_NOW :
EC_FLASH_PROTECT_RW_NOW;
#ifdef CONFIG_ROLLBACK
if (i >= ROLLBACK_BANK_OFFSET &&
i < ROLLBACK_BANK_OFFSET + ROLLBACK_BANK_COUNT) {
region = FLASH_REGION_ROLLBACK;
bank_flag = EC_FLASH_PROTECT_ROLLBACK_NOW;
}
#endif
if (flash_physical_get_protect(i)) {
/* At least one bank in the region is protected */
flags |= bank_flag;
@@ -572,8 +586,8 @@ uint32_t flash_get_protect(void)
flags |= EC_FLASH_PROTECT_ALL_NOW;
/*
* If the RW banks are protected but the RO banks aren't, that's
* inconsistent.
* If the RW or ROLLBACK banks are protected but the RO banks aren't,
* that's inconsistent.
*
* Note that we check this before adding in the physical flags below,
* since some chips can also protect ALL_NOW for the current boot by
@@ -597,6 +611,7 @@ int flash_set_protect(uint32_t mask, uint32_t flags)
int rv;
int old_flags_at_boot = flash_get_protect() &
(EC_FLASH_PROTECT_RO_AT_BOOT | EC_FLASH_PROTECT_RW_AT_BOOT |
EC_FLASH_PROTECT_ROLLBACK_AT_BOOT |
EC_FLASH_PROTECT_ALL_AT_BOOT);
int new_flags_at_boot = old_flags_at_boot;
@@ -630,12 +645,15 @@ int flash_set_protect(uint32_t mask, uint32_t flags)
new_flags_at_boot &= ~(mask & EC_FLASH_PROTECT_RO_AT_BOOT);
new_flags_at_boot |= flags & EC_FLASH_PROTECT_RO_AT_BOOT;
/* Removing ALL must also remove RW */
/* Removing ALL must also remove RW/ROLLBACK */
if ((mask & EC_FLASH_PROTECT_ALL_AT_BOOT) &&
!(flags & EC_FLASH_PROTECT_ALL_AT_BOOT)) {
new_flags_at_boot &= ~EC_FLASH_PROTECT_ALL_AT_BOOT;
#ifdef CONFIG_FLASH_PROTECT_RW
new_flags_at_boot &= ~EC_FLASH_PROTECT_RW_AT_BOOT;
#endif
#ifdef CONFIG_ROLLBACK
new_flags_at_boot &= ~EC_FLASH_PROTECT_ROLLBACK_AT_BOOT;
#endif
}
@@ -643,8 +661,16 @@ int flash_set_protect(uint32_t mask, uint32_t flags)
/* Removing RW must also remove ALL (otherwise nothing will happen). */
if ((mask & EC_FLASH_PROTECT_RW_AT_BOOT) &&
!(flags & EC_FLASH_PROTECT_RW_AT_BOOT)) {
new_flags_at_boot &= ~EC_FLASH_PROTECT_ALL_AT_BOOT;
new_flags_at_boot &= ~EC_FLASH_PROTECT_RW_AT_BOOT;
new_flags_at_boot &= ~EC_FLASH_PROTECT_ALL_AT_BOOT;
}
#endif
#ifdef CONFIG_ROLLBACK
if ((mask & EC_FLASH_PROTECT_ROLLBACK_AT_BOOT) &&
!(flags & EC_FLASH_PROTECT_ROLLBACK_AT_BOOT)) {
new_flags_at_boot &= ~EC_FLASH_PROTECT_ROLLBACK_AT_BOOT;
new_flags_at_boot &= ~EC_FLASH_PROTECT_ALL_AT_BOOT;
}
#endif
@@ -664,8 +690,8 @@ int flash_set_protect(uint32_t mask, uint32_t flags)
return retval;
/*
* The case where ALL/RW_AT_BOOT is unset is already covered above,
* so we do not need to mask it out.
* The case where ALL/RW/ROLLBACK_AT_BOOT is unset is already covered
* above, so we do not need to mask it out.
*/
new_flags_at_boot |= flags & EC_FLASH_PROTECT_ALL_AT_BOOT;
@@ -673,6 +699,10 @@ int flash_set_protect(uint32_t mask, uint32_t flags)
new_flags_at_boot |= flags & EC_FLASH_PROTECT_RW_AT_BOOT;
#endif
#ifdef CONFIG_ROLLBACK
new_flags_at_boot |= flags & EC_FLASH_PROTECT_ROLLBACK_AT_BOOT;
#endif
if (new_flags_at_boot != old_flags_at_boot) {
rv = flash_protect_at_boot(new_flags_at_boot);
if (rv)
@@ -729,6 +759,12 @@ static int command_flash_info(int argc, char **argv)
ccputs(" STUCK");
if (i & EC_FLASH_PROTECT_ERROR_INCONSISTENT)
ccputs(" INCONSISTENT");
#ifdef CONFIG_ROLLBACK
if (i & EC_FLASH_PROTECT_ROLLBACK_AT_BOOT)
ccputs(" rollback_at_boot");
if (i & EC_FLASH_PROTECT_ROLLBACK_NOW)
ccputs(" rollback_now");
#endif
ccputs("\n");
ccputs("Protected now:");
@@ -882,6 +918,14 @@ static int command_flash_wp(int argc, char **argv)
return flash_set_protect(EC_FLASH_PROTECT_RW_AT_BOOT, 0);
#endif
#ifdef CONFIG_ROLLBACK
if (!strcasecmp(argv[1], "rb"))
return flash_set_protect(EC_FLASH_PROTECT_ROLLBACK_AT_BOOT, -1);
if (!strcasecmp(argv[1], "norb"))
return flash_set_protect(EC_FLASH_PROTECT_ROLLBACK_AT_BOOT, 0);
#endif
/* Do this last, since anything starting with 'n' means "no" */
if (parse_bool(argv[1], &val))
return flash_set_protect(EC_FLASH_PROTECT_RO_AT_BOOT,
@@ -893,6 +937,9 @@ DECLARE_CONSOLE_COMMAND(flashwp, command_flash_wp,
"<BOOLEAN> | now | all | noall"
#ifdef CONFIG_FLASH_PROTECT_RW
" | rw | norw"
#endif
#ifdef CONFIG_ROLLBACK
" | rb | norb"
#endif
, "Modify flash write protect");

View File

@@ -1112,6 +1112,15 @@
#undef CONFIG_WP_STORAGE_OFF
#undef CONFIG_WP_STORAGE_SIZE
/*
* Rollback protect region. If CONFIG_ROLLBACK is defined to enable the rollback
* protect region, CONFIG_ROLLBACK_OFF and CONFIG_ROLLBACK_SIZE must be defined
* too.
*/
#undef CONFIG_ROLLBACK
#undef CONFIG_ROLLBACK_OFF
#undef CONFIG_ROLLBACK_SIZE
/*
* Board Image ec.bin contains a RO firmware. If not defined, the image will
* only contain the RW firmware. The RO firmware comes from another board.

View File

@@ -1213,6 +1213,10 @@ struct __ec_align4 ec_params_flash_erase {
#define EC_FLASH_PROTECT_RW_AT_BOOT (1 << 7)
/* RW flash code protected now. */
#define EC_FLASH_PROTECT_RW_NOW (1 << 8)
/* Rollback information flash region protected when the EC boots */
#define EC_FLASH_PROTECT_ROLLBACK_AT_BOOT (1 << 9)
/* Rollback information flash region protected now */
#define EC_FLASH_PROTECT_ROLLBACK_NOW (1 << 10)
struct __ec_align4 ec_params_flash_protect {
uint32_t mask; /* Bits in flags to apply */

View File

@@ -12,9 +12,13 @@
#include "ec_commands.h" /* For EC_FLASH_PROTECT_* flags */
/* Number of physical flash banks */
/*
* TODO(crosbug.com/p/62372): This assumes flash protection blocks are all of
* identical sizes, which is incorrect, for example, on STM32F091VC.
*/
#define PHYSICAL_BANKS (CONFIG_FLASH_SIZE / CONFIG_FLASH_BANK_SIZE)
/*WP region offset and size in units of flash banks */
/* WP region offset and size in units of flash banks */
#define WP_BANK_OFFSET (CONFIG_WP_STORAGE_OFF / CONFIG_FLASH_BANK_SIZE)
#define WP_BANK_COUNT (CONFIG_WP_STORAGE_SIZE / CONFIG_FLASH_BANK_SIZE)
@@ -26,10 +30,21 @@
#define PSTATE_BANK_COUNT 0
#endif
#ifdef CONFIG_ROLLBACK
/*
* ROLLBACK region offset and size in units of flash banks.
*/
#define ROLLBACK_BANK_OFFSET (CONFIG_ROLLBACK_OFF / CONFIG_FLASH_BANK_SIZE)
#define ROLLBACK_BANK_COUNT (CONFIG_ROLLBACK_SIZE / CONFIG_FLASH_BANK_SIZE)
#endif
/* This enum is useful to identify different regions during verification. */
enum flash_region {
FLASH_REGION_RW = 0,
FLASH_REGION_RO,
#ifdef CONFIG_ROLLBACK
FLASH_REGION_ROLLBACK,
#endif
FLASH_REGION_COUNT
};

View File

@@ -909,12 +909,16 @@ static void print_flash_protect_flags(const char *desc, uint32_t flags)
printf(" ro_at_boot");
if (flags & EC_FLASH_PROTECT_RW_AT_BOOT)
printf(" rw_at_boot");
if (flags & EC_FLASH_PROTECT_ROLLBACK_AT_BOOT)
printf(" rollback_at_boot");
if (flags & EC_FLASH_PROTECT_ALL_AT_BOOT)
printf(" all_at_boot");
if (flags & EC_FLASH_PROTECT_RO_NOW)
printf(" ro_now");
if (flags & EC_FLASH_PROTECT_RW_NOW)
printf(" rw_now");
if (flags & EC_FLASH_PROTECT_ROLLBACK_NOW)
printf(" rollback_now");
if (flags & EC_FLASH_PROTECT_ALL_NOW)
printf(" all_now");
if (flags & EC_FLASH_PROTECT_ERROR_STUCK)