From 9ce66a98b28df3e832b822bdec24e32e69d57e08 Mon Sep 17 00:00:00 2001 From: Vincent Palatin Date: Fri, 2 Jan 2015 15:03:42 -0800 Subject: zinger: enable RO partition write-protection Check the flash protection at startup, if the RDP is still at level 0 (no read protection) or if the RO partition is not write protected : - set the write protection on the first 16KB of flash (4 LSB of WRP0) - push the RDP to level 1, so SWD/serial monitor needs to fully erase the part before re-writing the code or the write-protection. Signed-off-by: Vincent Palatin BRANCH=samus BUG=chrome-os-partner:34935 TEST=dump the content of the option bytes. Change-Id: I11af64365a6fbc34327b2e463eb8e2d369ffacd2 Reviewed-on: https://chromium-review.googlesource.com/238262 Reviewed-by: Alec Berg Commit-Queue: Vincent Palatin Trybot-Ready: Vincent Palatin Tested-by: Vincent Palatin --- board/zinger/board.c | 4 +++ board/zinger/board.h | 2 ++ board/zinger/hardware.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+) (limited to 'board/zinger') diff --git a/board/zinger/board.c b/board/zinger/board.c index 3ea9850015..e06da587da 100644 --- a/board/zinger/board.c +++ b/board/zinger/board.c @@ -83,6 +83,10 @@ int main(void) debug_printf("Power supply started ... %s\n", is_ro_mode() ? "RO" : "RW"); + /* the RO partition protection is not enabled : do it */ + if (!flash_physical_is_permanently_protected()) + flash_physical_permanent_protect(); + /* Verify RW firmware and use it if valid */ if (is_ro_mode() && check_rw_valid()) jump_to_rw(); diff --git a/board/zinger/board.h b/board/zinger/board.h index 79d60514eb..e307c6ff27 100644 --- a/board/zinger/board.h +++ b/board/zinger/board.h @@ -97,6 +97,8 @@ extern volatile uint32_t last_event; /* RW section flashing */ int flash_erase_rw(void); int flash_write_rw(int offset, int size, const char *data); +void flash_physical_permanent_protect(void); +int flash_physical_is_permanently_protected(void); uint8_t *flash_hash_rw(void); int is_ro_mode(void); diff --git a/board/zinger/hardware.c b/board/zinger/hardware.c index 1713ca342e..31f57da6a3 100644 --- a/board/zinger/hardware.c +++ b/board/zinger/hardware.c @@ -296,8 +296,11 @@ int adc_disable_watchdog(void) /* Lock bits for FLASH_CR register */ #define PG (1<<0) #define PER (1<<1) +#define OPTPG (1<<4) +#define OPTER (1<<5) #define STRT (1<<6) #define CR_LOCK (1<<7) +#define OPTWRE (1<<9) int flash_physical_write(int offset, int size, const char *data) { @@ -399,3 +402,79 @@ exit_er: return res; } + +static void unlock_erase_optb(void) +{ + int i; + + /* Clear previous error status */ + STM32_FLASH_SR = 0x34; + + /* wait to be ready */ + for (i = 0; (STM32_FLASH_SR & 1) && (i < FLASH_TIMEOUT_LOOP); i++) + ; + + /* Unlock the option bytes access */ + if (STM32_FLASH_CR & CR_LOCK) { + STM32_FLASH_KEYR = KEY1; + STM32_FLASH_KEYR = KEY2; + } + if (!(STM32_FLASH_CR & OPTWRE)) { + STM32_FLASH_OPTKEYR = KEY1; + STM32_FLASH_OPTKEYR = KEY2; + } + /* Must be set in 2 separate lines. */ + STM32_FLASH_CR |= OPTER; + STM32_FLASH_CR |= STRT; + + /* wait to be ready */ + for (i = 0; (STM32_FLASH_SR & 1) && (i < FLASH_TIMEOUT_LOOP); i++) + ; + /* reset erasing bits */ + STM32_FLASH_CR = OPTWRE; +} + + +static void write_optb(int byte, uint8_t value) +{ + volatile int16_t *hword = (uint16_t *)(STM32_OPTB_BASE + byte); + int i; + + /* Clear previous error status */ + STM32_FLASH_SR = 0x34; + + /* set OPTPG bit */ + STM32_FLASH_CR |= OPTPG; + + *hword = ((~value) << STM32_OPTB_COMPL_SHIFT) | value; + + /* reset OPTPG bit */ + STM32_FLASH_CR = OPTWRE; + + /* wait to be ready */ + for (i = 0; (STM32_FLASH_SR & 1) && (i < FLASH_TIMEOUT_LOOP); i++) + ; +} + +void flash_physical_permanent_protect(void) +{ + unlock_erase_optb(); + /* protect the 16KB RO partition against write/erase in WRP0 */ + write_optb(8, 0xF0); + /* Set RDP to level 1 to prevent disabling the protection */ + write_optb(0, 0x11); + /* Reset by using OBL_LAUNCH to take changes into account */ + asm volatile("cpsid i"); + STM32_FLASH_CR |= STM32_FLASH_CR_OBL_LAUNCH; + /* Spin and wait for reboot; should never return */ + while (1) + ; +} + +int flash_physical_is_permanently_protected(void) +{ + /* if RDP is still at level 0, the flash protection is not in place */ + return (STM32_FLASH_OBR & STM32_FLASH_OBR_RDP_MASK) && + /* the low 16KB (RO partition) are write-protected */ + !(STM32_FLASH_WRPR & 0xF); +} -- cgit v1.2.1