summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2012-07-17 13:51:44 -0700
committerRandall Spangler <rspangler@chromium.org>2012-07-18 13:48:46 -0700
commitad2268e7396abc6ff094376eedec2402b06f3b21 (patch)
tree4ddfbb8b0bafbefc4e709173a4c743f52086ae94
parent2bee304abda0f51bbc3d673daae26e583fb7ca55 (diff)
downloadchrome-ec-ad2268e7396abc6ff094376eedec2402b06f3b21.tar.gz
Simplify flash protection, part 1
1. If the flash protection state is locked, RO firmware is explicitly locked. 2. Protecting flash now locks the entire flash. BUG=chrome-os-partner:11150 TEST=manual flashinfo -> nothing protected flashwp now flashinfo -> unlocked,applied; everything protected reboot flashinfo -> nothing protected flashwp lock -> flashinfo -> locked,applied; now has 40 Y's at start and 1 at end reboot flashinfo -> locked,applied; now has 40 Y's at start and 1 at end remove WP screw reboot flashinfo -> locked, not applied; nothing protected flashwp unlock flashinfo -> nothing protected Change-Id: I2cf0e8bfe82ab7a5bf88b9161b7a05b889cae71a Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/27717
-rw-r--r--chip/lm4/config.h2
-rw-r--r--chip/lm4/flash.c10
-rw-r--r--chip/stm32/config-stm32f100.h15
-rw-r--r--chip/stm32/config-stm32l15x.h16
-rw-r--r--chip/stm32/flash-stm32f100.c13
-rw-r--r--chip/stm32/flash-stm32l15x.c13
-rw-r--r--common/flash_commands.c29
-rw-r--r--common/flash_common.c146
-rw-r--r--include/flash.h34
9 files changed, 101 insertions, 177 deletions
diff --git a/chip/lm4/config.h b/chip/lm4/config.h
index 063132b74a..712b8d8f87 100644
--- a/chip/lm4/config.h
+++ b/chip/lm4/config.h
@@ -46,7 +46,7 @@
*/
#define CONFIG_SECTION_FLASH_PSTATE_SIZE (1 * CONFIG_FLASH_BANK_SIZE)
#define CONFIG_SECTION_FLASH_PSTATE_OFF (CONFIG_FLASH_SIZE \
- - CONFIG_FLASH_FLASH_PSTATE_SIZE)
+ - CONFIG_SECTION_FLASH_PSTATE_SIZE)
/* Then there are the two major sections. */
/* TODO: Increase to 128KB, or shrink to 64KB? */
diff --git a/chip/lm4/flash.c b/chip/lm4/flash.c
index 20c90793bd..c69538d5bc 100644
--- a/chip/lm4/flash.c
+++ b/chip/lm4/flash.c
@@ -171,15 +171,17 @@ int flash_physical_erase(int offset, int size)
}
-int flash_physical_get_protect(int block)
+int flash_physical_get_protect(int bank)
{
- return (LM4_FLASH_FMPPE[F_BANK(block)] & F_BIT(block)) ? 0 : 1;
+ return (LM4_FLASH_FMPPE[F_BANK(bank)] & F_BIT(bank)) ? 0 : 1;
}
-void flash_physical_set_protect(int block)
+void flash_physical_set_protect(int start_bank, int bank_count)
{
- LM4_FLASH_FMPPE[F_BANK(block)] &= ~F_BIT(block);
+ int bank;
+ for (bank = start_bank; bank < start_bank + bank_count; bank++)
+ LM4_FLASH_FMPPE[F_BANK(bank)] &= ~F_BIT(bank);
}
int flash_physical_pre_init(void)
diff --git a/chip/stm32/config-stm32f100.h b/chip/stm32/config-stm32f100.h
index 2a591e7b1d..831daa62d7 100644
--- a/chip/stm32/config-stm32f100.h
+++ b/chip/stm32/config-stm32f100.h
@@ -5,7 +5,8 @@
/* Memory mapping */
#define CONFIG_FLASH_BASE 0x08000000
-#define CONFIG_FLASH_SIZE 0x00020000
+#define CONFIG_FLASH_PHYSICAL_SIZE 0x00020000
+#define CONFIG_FLASH_SIZE CONFIG_FLASH_PHYSICAL_SIZE
#define CONFIG_FLASH_BANK_SIZE 0x1000
#define CONFIG_RAM_BASE 0x20000000
#define CONFIG_RAM_SIZE 0x00002000
@@ -23,11 +24,13 @@
#define CONFIG_SECTION_RW_OFF CONFIG_FW_RW_OFF
#define CONFIG_SECTION_RW_SIZE CONFIG_FW_RW_SIZE
-/* no keys for now */
-#define CONFIG_VBOOT_ROOTKEY_OFF (CONFIG_FW_RO_OFF + CONFIG_FW_RO_SIZE)
-#define CONFIG_VBLOCK_RW_OFF (CONFIG_FW_RW_OFF + CONFIG_FW_RW_SIZE)
-#define CONFIG_VBOOT_ROOTKEY_SIZE 0
-#define CONFIG_VBLOCK_SIZE 0
+/*
+ * The EC uses the top bank of flash to emulate a SPI-like write protect
+ * register with persistent state. Put that up at the top.
+ */
+#define CONFIG_SECTION_FLASH_PSTATE_SIZE (1 * CONFIG_FLASH_BANK_SIZE)
+#define CONFIG_SECTION_FLASH_PSTATE_OFF (CONFIG_FLASH_SIZE \
+ - CONFIG_SECTION_FLASH_PSTATE_SIZE)
/* Number of IRQ vectors on the NVIC */
#define CONFIG_IRQ_COUNT 61
diff --git a/chip/stm32/config-stm32l15x.h b/chip/stm32/config-stm32l15x.h
index 15b37eb956..63d9b0d323 100644
--- a/chip/stm32/config-stm32l15x.h
+++ b/chip/stm32/config-stm32l15x.h
@@ -5,7 +5,8 @@
/* Memory mapping */
#define CONFIG_FLASH_BASE 0x08000000
-#define CONFIG_FLASH_SIZE 0x00020000
+#define CONFIG_FLASH_PHYSICAL_SIZE 0x00020000
+#define CONFIG_FLASH_SIZE CONFIG_FLASH_PHYSICAL_SIZE
#define CONFIG_FLASH_BANK_SIZE 0x1000
#define CONFIG_RAM_BASE 0x20000000
#define CONFIG_RAM_SIZE 0x00004000
@@ -23,12 +24,13 @@
#define CONFIG_SECTION_RW_OFF CONFIG_FW_RW_OFF
#define CONFIG_SECTION_RW_SIZE CONFIG_FW_RW_SIZE
-/* no keys for now */
-#define CONFIG_VBOOT_ROOTKEY_OFF (CONFIG_FW_RO_OFF + CONFIG_FW_RO_SIZE)
-#define CONFIG_VBLOCK_RW_OFF (CONFIG_FW_RW_OFF + CONFIG_FW_RW_SIZE)
-#define CONFIG_VBOOT_ROOTKEY_SIZE 0
-#define CONFIG_VBLOCK_SIZE 0
-
+/*
+ * The EC uses the top bank of flash to emulate a SPI-like write protect
+ * register with persistent state. Put that up at the top.
+ */
+#define CONFIG_SECTION_FLASH_PSTATE_SIZE (1 * CONFIG_FLASH_BANK_SIZE)
+#define CONFIG_SECTION_FLASH_PSTATE_OFF (CONFIG_FLASH_SIZE \
+ - CONFIG_SECTION_FLASH_PSTATE_SIZE)
/* Number of IRQ vectors on the NVIC */
#define CONFIG_IRQ_COUNT 45
diff --git a/chip/stm32/flash-stm32f100.c b/chip/stm32/flash-stm32f100.c
index 46dc8336be..2e88f3b511 100644
--- a/chip/stm32/flash-stm32f100.c
+++ b/chip/stm32/flash-stm32f100.c
@@ -326,12 +326,15 @@ int flash_physical_get_protect(int block)
return !(val & (1 << (block % 8)));
}
-
-void flash_physical_set_protect(int block)
+void flash_physical_set_protect(int start_bank, int bank_count)
{
- int byte_off = STM32_OPTB_WRP_OFF(block/8);
- uint8_t val = read_optb(byte_off) & ~(1 << (block % 8));
- write_optb(byte_off, val);
+ int block;
+
+ for (block = start_bank; block < start_bank + bank_count; block++) {
+ int byte_off = STM32_OPTB_WRP_OFF(block/8);
+ uint8_t val = read_optb(byte_off) | (1 << (block % 8));
+ write_optb(byte_off, val);
+ }
}
int flash_physical_pre_init(void)
diff --git a/chip/stm32/flash-stm32l15x.c b/chip/stm32/flash-stm32l15x.c
index d3e3db5033..2ac9227c2e 100644
--- a/chip/stm32/flash-stm32l15x.c
+++ b/chip/stm32/flash-stm32l15x.c
@@ -308,13 +308,16 @@ int flash_physical_get_protect(int block)
return val & (1 << (block % 8));
}
-
-void flash_physical_set_protect(int block)
+void flash_physical_set_protect(int start_bank, int bank_count)
{
if (0) { /* TODO: crosbug.com/p/9849 verify WP */
- int byte_off = STM32_OPTB_WRP_OFF(block/8);
- uint8_t val = read_optb(byte_off) | (1 << (block % 8));
- write_optb(byte_off, val);
+ int block;
+
+ for (block = start_bank; block < start_bank + bank_count; block++) {
+ int byte_off = STM32_OPTB_WRP_OFF(block/8);
+ uint8_t val = read_optb(byte_off) | (1 << (block % 8));
+ write_optb(byte_off, val);
+ }
}
}
diff --git a/common/flash_commands.c b/common/flash_commands.c
index c52f308325..322409cbaf 100644
--- a/common/flash_commands.c
+++ b/common/flash_commands.c
@@ -74,12 +74,6 @@ static int command_flash_info(int argc, char **argv)
ccputs(" ");
ccputs(wp[i] & FLASH_PROTECT_UNTIL_REBOOT ? "Y" : ".");
}
- ccputs("\n Persistent: ");
- for (i = 0; i < banks; i++) {
- if (!(i & 7))
- ccputs(" ");
- ccputs(wp[i] & FLASH_PROTECT_PERSISTENT ? "Y" : ".");
- }
ccputs("\n");
return EC_SUCCESS;
@@ -151,36 +145,21 @@ DECLARE_CONSOLE_COMMAND(flashwrite, command_flash_write,
static int command_flash_wp(int argc, char **argv)
{
- int offset = -1;
- int size = flash_get_protect_block_size();
- int rv;
-
if (argc < 2)
return EC_ERROR_PARAM_COUNT;
- /* Commands that don't need offset and size */
if (!strcasecmp(argv[1], "lock"))
return flash_lock_protect(1);
else if (!strcasecmp(argv[1], "unlock"))
return flash_lock_protect(0);
-
- /* All remaining commands need offset and size */
- rv = parse_offset_size(argc, argv, 2, &offset, &size);
- if (rv)
- return rv;
-
- if (!strcasecmp(argv[1], "now"))
- return flash_protect_until_reboot(offset, size);
- else if (!strcasecmp(argv[1], "set"))
- return flash_set_protect(offset, size, 1);
- else if (!strcasecmp(argv[1], "clear"))
- return flash_set_protect(offset, size, 0);
+ else if (!strcasecmp(argv[1], "now"))
+ return flash_protect_until_reboot();
else
return EC_ERROR_PARAM1;
}
DECLARE_CONSOLE_COMMAND(flashwp, command_flash_wp,
- "<lock | unlock | now | set | clear> offset [size]",
- "Print or modify flash write protect",
+ "<lock | unlock | now>",
+ "Modify flash write protect",
NULL);
/*****************************************************************************/
diff --git a/common/flash_common.c b/common/flash_common.c
index e7467954f4..c0a769d0c9 100644
--- a/common/flash_common.c
+++ b/common/flash_common.c
@@ -14,6 +14,16 @@
#define PERSIST_STATE_VERSION 1
#define MAX_BANKS (CONFIG_FLASH_SIZE / CONFIG_FLASH_BANK_SIZE)
+/* Persistent protection state flash offset / size / bank */
+#define PSTATE_OFFSET (CONFIG_SECTION_FLASH_PSTATE_OFF - CONFIG_FLASH_BASE)
+#define PSTATE_SIZE CONFIG_SECTION_FLASH_PSTATE_SIZE
+#define PSTATE_BANK (PSTATE_OFFSET / CONFIG_FLASH_BANK_SIZE)
+
+/* Read-only firmware offset and size in units of flash banks */
+#define RO_BANK_OFFSET ((CONFIG_SECTION_RO_OFF - CONFIG_FLASH_BASE) \
+ / CONFIG_FLASH_BANK_SIZE)
+#define RO_BANK_COUNT (CONFIG_SECTION_RO_SIZE / CONFIG_FLASH_BANK_SIZE)
+
/* Persistent protection state - emulates a SPI status register for flashrom */
struct persist_state {
uint8_t version; /* Version of this struct */
@@ -22,7 +32,6 @@ struct persist_state {
uint8_t blocks[MAX_BANKS]; /* Per-block flags */
};
-static int usable_flash_size; /* Usable flash size, not counting pstate */
static struct persist_state pstate; /* RAM copy of pstate data */
@@ -41,12 +50,15 @@ static int wp_pin_asserted(void)
#endif
}
-
/* Read persistent state into pstate. */
static int read_pstate(void)
{
+#ifdef CHIP_stm32
+ memset(&pstate, 0, sizeof(pstate));
+ pstate.version = PERSIST_STATE_VERSION;
+#else
int i;
- int rv = flash_physical_read(usable_flash_size, sizeof(pstate),
+ int rv = flash_physical_read(PSTATE_OFFSET, sizeof(pstate),
(char *)&pstate);
if (rv)
return rv;
@@ -60,42 +72,40 @@ static int read_pstate(void)
/* Mask off currently-valid flags */
pstate.lock &= FLASH_PROTECT_LOCK_SET;
for (i = 0; i < MAX_BANKS; i++)
- pstate.blocks[i] &= FLASH_PROTECT_PERSISTENT;
+ pstate.blocks[i] = 0;
+#endif /* CHIP_stm32 */
return EC_SUCCESS;
}
-
/* Write persistent state from pstate, erasing if necessary. */
static int write_pstate(void)
{
int rv;
- /* Erase top protection block. Assumes pstate size is less than
- * erase/protect block size, and protect block size is less than erase
- * block size. */
- /* TODO: optimize based on current physical flash contents; we can
- * avoid the erase if we're only changing 1's into 0's. */
- rv = flash_physical_erase(usable_flash_size,
- flash_get_protect_block_size());
+ /* Erase pstate */
+ /*
+ * TODO: optimize based on current physical flash contents; we can
+ * avoid the erase if we're only changing 1's into 0's.
+ */
+ rv = flash_physical_erase(PSTATE_OFFSET, PSTATE_SIZE);
if (rv)
return rv;
- /* Note that if we lose power in here, we'll lose the pstate contents.
+ /*
+ * Note that if we lose power in here, we'll lose the pstate contents.
* That's ok, because it's only possible to write the pstate before
- * it's protected. */
+ * it's protected.
+ */
/* Rewrite the data */
- return flash_physical_write(usable_flash_size, sizeof(pstate),
+ return flash_physical_write(PSTATE_OFFSET, sizeof(pstate),
(const char *)&pstate);
}
-
/* Apply write protect based on persistent state. */
static int apply_pstate(void)
{
- int pbsize = flash_get_protect_block_size();
- int banks = usable_flash_size / pbsize;
- int rv, i;
+ int rv;
/* If write protect is disabled, nothing to do */
if (!wp_pin_asserted())
@@ -111,47 +121,38 @@ static int apply_pstate(void)
return EC_SUCCESS;
/* Lock the protection data first */
- flash_physical_set_protect(banks);
+ flash_physical_set_protect(PSTATE_BANK, 1);
- /* Then lock any banks necessary */
- for (i = 0; i < banks; i++) {
- if (pstate.blocks[i] & FLASH_PROTECT_PERSISTENT)
- flash_physical_set_protect(i);
- }
+ /* Lock the read-only section whenever pstate is locked */
+ flash_physical_set_protect(RO_BANK_OFFSET, RO_BANK_COUNT);
return EC_SUCCESS;
}
-
/* Return non-zero if pstate block is already write-protected. */
static int is_pstate_lock_applied(void)
{
- int pstate_block = usable_flash_size / flash_get_protect_block_size();
-
/* Fail if write protect block is already locked */
- return flash_physical_get_protect(pstate_block);
+ return flash_physical_get_protect(PSTATE_BANK);
}
-
int flash_get_size(void)
{
- return usable_flash_size;
+ return CONFIG_FLASH_SIZE;
}
-
int flash_dataptr(int offset, int size_req, int align, char **ptrp)
{
if (offset < 0 || size_req < 0 ||
- offset + size_req > usable_flash_size ||
+ offset + size_req > CONFIG_FLASH_SIZE ||
(offset | size_req) & (align - 1))
return -1; /* Invalid range */
if (ptrp)
*ptrp = flash_physical_dataptr(offset);
- return usable_flash_size - offset;
+ return CONFIG_FLASH_SIZE - offset;
}
-
int flash_read(int offset, int size, char *data)
{
if (flash_dataptr(offset, size, 1, NULL) < 0)
@@ -160,84 +161,33 @@ int flash_read(int offset, int size, char *data)
return flash_physical_read(offset, size, data);
}
-
int flash_write(int offset, int size, const char *data)
{
if (flash_dataptr(offset, size, flash_get_write_block_size(),
NULL) < 0)
return EC_ERROR_INVAL; /* Invalid range */
- /* TODO (crosbug.com/p/7478) - safety check - don't allow writing to
- * the image we're running from */
-
return flash_physical_write(offset, size, data);
}
-
int flash_erase(int offset, int size)
{
if (flash_dataptr(offset, size, flash_get_erase_block_size(),
NULL) < 0)
return EC_ERROR_INVAL; /* Invalid range */
- /* TODO (crosbug.com/p/7478) - safety check - don't allow erasing the
- * image we're running from */
-
return flash_physical_erase(offset, size);
}
-
-int flash_protect_until_reboot(int offset, int size)
+int flash_protect_until_reboot(void)
{
- int pbsize = flash_get_protect_block_size();
- int i;
-
- if (flash_dataptr(offset, size, pbsize, NULL) < 0)
- return EC_ERROR_INVAL; /* Invalid range */
-
- /* Convert offset and size to blocks */
- offset /= pbsize;
- size /= pbsize;
+ /* Protect the entire flash */
+ flash_physical_set_protect(0, CONFIG_FLASH_PHYSICAL_SIZE /
+ CONFIG_FLASH_BANK_SIZE);
- for (i = 0; i < size; i++)
- flash_physical_set_protect(offset + i);
return EC_SUCCESS;
}
-
-int flash_set_protect(int offset, int size, int enable)
-{
- uint8_t newflag = enable ? FLASH_PROTECT_PERSISTENT : 0;
- int pbsize = flash_get_protect_block_size();
- int rv, i;
-
- if (flash_dataptr(offset, size, pbsize, NULL) < 0)
- return EC_ERROR_INVAL; /* Invalid range */
-
- /* Fail if write protect block is already locked */
- if (is_pstate_lock_applied())
- return EC_ERROR_UNKNOWN;
-
- /* Read the current persist state from flash */
- rv = read_pstate();
- if (rv)
- return rv;
-
- /* Convert offset and size to blocks */
- offset /= pbsize;
- size /= pbsize;
-
- /* Set the new state */
- for (i = 0; i < size; i++) {
- pstate.blocks[offset + i] &= ~FLASH_PROTECT_PERSISTENT;
- pstate.blocks[offset + i] |= newflag;
- }
-
- /* Write the state back to flash */
- return write_pstate();
-}
-
-
int flash_lock_protect(int lock)
{
int rv;
@@ -267,7 +217,6 @@ int flash_lock_protect(int lock)
return apply_pstate();
}
-
const uint8_t *flash_get_protect_array(void)
{
/*
@@ -275,15 +224,13 @@ const uint8_t *flash_get_protect_array(void)
* of per-protect-block flags. (This is NOT the actual array, so
* attempting to change it will have no effect.)
*/
- int pbsize = flash_get_protect_block_size();
- int banks = usable_flash_size / pbsize;
int i;
/* Read the current persist state from flash */
read_pstate();
/* Combine with current block protection state */
- for (i = 0; i < banks; i++) {
+ for (i = 0; i < MAX_BANKS; i++) {
if (flash_physical_get_protect(i))
pstate.blocks[i] |= FLASH_PROTECT_UNTIL_REBOOT;
}
@@ -292,7 +239,6 @@ const uint8_t *flash_get_protect_array(void)
return pstate.blocks;
}
-
int flash_get_protect(int offset, int size)
{
int pbsize = flash_get_protect_block_size();
@@ -320,7 +266,6 @@ int flash_get_protect(int offset, int size)
return minflags;
}
-
int flash_get_protect_lock(void)
{
int flags;
@@ -352,13 +297,6 @@ int flash_pre_init(void)
*/
flash_physical_pre_init();
- /*
- * Calculate usable flash size. Reserve one protection block
- * at the top to hold the "pretend SPI" write protect data.
- */
- usable_flash_size = flash_physical_size() -
- flash_get_protect_block_size();
-
- /* Apply write protect to blocks if needed */
+ /* Read pstate and apply write protect to blocks if needed */
return apply_pstate();
}
diff --git a/include/flash.h b/include/flash.h
index 2ad8581440..bd89448c57 100644
--- a/include/flash.h
+++ b/include/flash.h
@@ -55,11 +55,16 @@ int flash_physical_write(int offset, int size, const char *data);
/* Erase <size> bytes of flash at byte offset <offset>. */
int flash_physical_erase(int offset, int size);
-/* Return non-zero if block is protected until reboot. */
-int flash_physical_get_protect(int block);
+/* Return non-zero if bank is protected until reboot. */
+int flash_physical_get_protect(int bank);
-/* Protects the block until reboot. */
-void flash_physical_set_protect(int block);
+/**
+ * Protect the flash banks until reboot.
+ *
+ * @param start_bank Start bank to protect
+ * @param bank_count Number of banks to protect
+ */
+void flash_physical_set_protect(int start_bank, int bank_count);
/*****************************************************************************/
/* High-level interface for use by other modules. */
@@ -131,18 +136,13 @@ int flash_erase(int offset, int size);
* the system is rebooted with the write protect pin asserted - at which point,
* protection is re-applied. */
-/* Write-protect <size> bytes of flash at byte offset <offset> until next
- * reboot. */
-int flash_protect_until_reboot(int offset, int size);
+/**
+ * Protect the entire flash until reboot.
+ */
+int flash_protect_until_reboot(void);
/* Higher-level APIs to emulate SPI write protect */
-/* Set (enable=1) or clear (enable=0) the persistent write protect setting for
- * the specified range. This will only succeed if write protect is unlocked.
- * This will take effect on the next boot, or when flash_lock_protect(1) is
- * called. */
-int flash_set_protect(int offset, int size, int enable);
-
/* Lock or unlock the persistent write protect settings. Once the write
* protect settings are locked, they will STAY locked until the system is
* cold-booted with the hardware write protect pin disabled.
@@ -152,16 +152,10 @@ int flash_set_protect(int offset, int size, int enable);
int flash_lock_protect(int lock);
/* Flags for flash_get_protect() and flash_get_protect_array(). */
-/* Protected persistently. Note that if the write protect pin was deasserted
- * at boot time, a block may have the FLASH_PROTECT_PERSISTENT flag indicating
- * the block would be protected on a normal boot, but may not have the
- * FLASH_PROTECT_UNTIL_REBOOT flag indicating it's actually protected right
- * now. */
-#define FLASH_PROTECT_PERSISTENT 0x01
/* Protected until reboot. This will be set for persistently-protected blocks
* as soon as the flash module protects them, and for non-persistent protection
* after flash_protect_until_reboot() is called on a block. */
-#define FLASH_PROTECT_UNTIL_REBOOT 0x02
+#define FLASH_PROTECT_UNTIL_REBOOT 0x01
/* Return a copy of the current write protect state. This is an array of
* per-protect-block flags. The data is valid until the next call to a flash