Flash pre-init reboots if it needs to clear protection registers

BUG=chrome-os-partner:11171
TEST=manual

1. Clear some of the writable-bits in the flash registers
> ww 0x400fe40c 0xffff1234
write 0x400fe40c = 0xffff1234
> rw 0x400fe40c
read 0x400fe40c = 0xffff1234
2. Reset using power+refresh
3. Register should be clear again
> rw 0x400fe40c
read 0x400fe40c = 0xffffffff
4. Sysinfo should indicate reset-pin reason AND hard-reset reason
> sysinfo
Reset flags: 0x0000000a (reset-pin power-on)
5. Reset using power+refresh
6. Sysinfo should indicate reset-pin reason only
> sysinfo
Reset flags: 0x00000002 (reset-pin)
7. Clear writable-bits again
> ww 0x400fe40c 0xffff1234
write 0x400fe40c = 0xffff1234
8. Jump to another image.  This should NOT trigger a hard reset.
> sysjump A
> sysinfo
Reset flags: 0x00000402 (reset-pin sysjump)

Change-Id: Ie1d6af2acc68217bb82faae464798ee85d63d1ea
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/27540
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
This commit is contained in:
Randall Spangler
2012-07-16 14:19:59 -07:00
committed by Gerrit
parent a42edb86c5
commit acf6f963a1
8 changed files with 81 additions and 26 deletions

View File

@@ -7,6 +7,7 @@
#include "flash.h"
#include "registers.h"
#include "system.h"
#include "timer.h"
#include "util.h"
#include "watchdog.h"
@@ -180,3 +181,43 @@ void flash_physical_set_protect(int block)
{
LM4_FLASH_FMPPE[F_BANK(block)] &= ~F_BIT(block);
}
int flash_physical_pre_init(void)
{
int reset_flags = system_get_reset_flags();
int any_wp = 0;
int i;
/*
* If we have already jumped between images, an earlier image could
* have applied write protection. Nothing additional needs to be done.
*/
if (reset_flags & RESET_FLAG_SYSJUMP)
return EC_SUCCESS;
/* Check if any blocks are currently physically write-protected */
for (i = 0; i < (LM4_FLASH_FSIZE + 1) / 32; i++) {
if (LM4_FLASH_FMPPE[i] != 0xffffffff) {
any_wp = 1;
break;
}
}
/* If nothing is write-protected, done. */
if (!any_wp)
return EC_SUCCESS;
/*
* If the last reboot was a power-on reset, it should have cleared
* write-protect. If it didn't, then the flash write protect registers
* have been permanently committed and we can't fix that.
*/
if (reset_flags & RESET_FLAG_POWER_ON)
return EC_ERROR_ACCESS_DENIED;
/* Otherwise, do a hard boot to clear the flash protection registers */
system_reset(SYSTEM_RESET_HARD | SYSTEM_RESET_PRESERVE_FLAGS);
/* That doesn't return, so if we're still here that's an error */
return EC_ERROR_UNKNOWN;
}

View File

@@ -257,3 +257,8 @@ void flash_physical_set_protect(int block)
write_optb(byte_off, val);
}
}
int flash_physical_pre_init(void)
{
return EC_SUCCESS;
}

View File

@@ -317,3 +317,8 @@ void flash_physical_set_protect(int block)
write_optb(byte_off, val);
}
}
int flash_physical_pre_init(void)
{
return EC_SUCCESS;
}

View File

@@ -272,9 +272,11 @@ int flash_lock_protect(int lock)
const uint8_t *flash_get_protect_array(void)
{
/* Return a copy of the current write protect state. This is an array
/*
* Return a copy of the current write protect state. This is an array
* of per-protect-block flags. (This is NOT the actual array, so
* attempting to change it will have no effect.) */
* attempting to change it will have no effect.)
*/
int pbsize = flash_get_protect_block_size();
int banks = usable_flash_size / pbsize;
int i;
@@ -345,15 +347,25 @@ int flash_get_protect_lock(void)
int flash_pre_init(void)
{
/* Initialize the physical flash interface */
/*
* TODO: track pre-init error so we can report it later. Do at the
* same time as new flash commands to get/set write protect status.
*/
flash_physical_pre_init();
#ifdef CHIP_stm32
usable_flash_size = flash_physical_size();
#else
/* Calculate usable flash size. Reserve one protection block
* at the top to hold the "pretend SPI" write protect data. */
/*
* 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();
#endif
/* Apply write protect to blocks if needed */
return apply_pstate();
}

View File

@@ -6,8 +6,8 @@
*/
#include "clock.h"
#include "common.h"
#include "cpu.h"
#include "config.h"
#include "eeprom.h"
#include "eoption.h"
#include "flash.h"
@@ -44,18 +44,6 @@ int main(void)
*/
task_pre_init();
#ifdef CONFIG_FLASH
flash_pre_init();
#endif
#ifdef CONFIG_VBOOT
/*
* Verified boot pre-init. This write-protects flash if necessary.
* Flash and GPIOs must be initialized first.
*/
vboot_pre_init();
#endif
/*
* Initialize the system module. This enables the hibernate clock
* source we need to calibrate the internal oscillator.
@@ -63,6 +51,14 @@ int main(void)
system_pre_init();
system_common_pre_init();
#ifdef CONFIG_FLASH
/*
* Initialize flash and apply write protecte if necessary. Requires
* the reset flags calculated by system initialization.
*/
flash_pre_init();
#endif
/* Set the CPU clocks / PLLs. System is now running at full speed. */
clock_init();

View File

@@ -15,12 +15,6 @@
#define CPUTS(outstr) cputs(CC_VBOOT, outstr)
#define CPRINTF(format, args...) cprintf(CC_VBOOT, format, ## args)
int vboot_pre_init(void)
{
/* FIXME(wfrichar): crosbug.com/p/7453: should protect flash */
return EC_SUCCESS;
}
/****************************************************************************/
/* Host commands */

View File

@@ -14,6 +14,11 @@
/*****************************************************************************/
/* Low-level methods, for use by flash_common. */
/**
* Initialize the physical flash interface.
*/
int flash_physical_pre_init(void);
/* Return the write / erase / protect block size, in bytes. Operations must be
* aligned to and multiples of the granularity. For example, erase operations
* must have offset and size which are multiples of the erase block size. */

View File

@@ -10,9 +10,6 @@
#include "common.h"
/* Pre-initialize the module. This occurs before clocks or tasks are set up. */
int vboot_pre_init(void);
/*
* Check verified boot signatures, and jump to one of the RW images if
* necessary.