Files
OpenCellular/common/flash_common.c
Rong Chang 63368620c5 CHERRY-PICK: stm32: de-activate all flash accesses for pstate
Cherry-picked from factory-2475.B.

This feature is not implemented and accessing random flash
addresses.

Signed-off-by: Vincent Palatin <vpalatin@chromium.org>

BUG=chrome-os-partner:10237
TEST=on Snow, run flashrom -p internal:bus=lpc --wp-status

Reviewed-on: https://gerrit.chromium.org/gerrit/25979
Reviewed-by: Katie Roberts-Hoffman <katierh@chromium.org>
Tested-by: David Hendricks <dhendrix@chromium.org>

Change-Id: Idce19f4e2af37faa5fde9d6561779d981772c9ac
Reviewed-on: https://gerrit.chromium.org/gerrit/26666
Reviewed-by: David Hendricks <dhendrix@chromium.org>
Commit-Ready: Rong Chang <rongchang@chromium.org>
Tested-by: Rong Chang <rongchang@chromium.org>
2012-07-03 23:51:19 -07:00

360 lines
8.5 KiB
C

/* Copyright (c) 2012 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 - common functions */
#include "config.h"
#include "flash.h"
#include "gpio.h"
#include "registers.h"
#include "util.h"
#define PERSIST_STATE_VERSION 1
#define MAX_BANKS (CONFIG_FLASH_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 */
uint8_t lock; /* Lock flags */
uint8_t reserved[2]; /* Reserved; set 0 */
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 */
/* Return non-zero if the write protect pin is asserted */
static int wp_pin_asserted(void)
{
#ifdef CHIP_stm32
/* TODO (vpalatin) : write protect scheme for stm32 */
return 0; /* always disable write protect */
#else
return gpio_get_level(GPIO_WRITE_PROTECT);
#endif
}
/* Read persistent state into pstate. */
static int read_pstate(void)
{
#ifndef CHIP_stm32
int i;
int rv = flash_physical_read(usable_flash_size, sizeof(pstate),
(char *)&pstate);
if (rv)
return rv;
/* Sanity-check data and initialize if necessary */
if (pstate.version != PERSIST_STATE_VERSION) {
memset(&pstate, 0, sizeof(pstate));
pstate.version = PERSIST_STATE_VERSION;
}
/* Mask off currently-valid flags */
pstate.lock &= FLASH_PROTECT_LOCK_SET;
for (i = 0; i < MAX_BANKS; i++)
pstate.blocks[i] &= FLASH_PROTECT_PERSISTENT;
#endif /* CHIP_stm32 */
return EC_SUCCESS;
}
/* Write persistent state from pstate, erasing if necessary. */
static int write_pstate(void)
{
#ifndef CHIP_stm32
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());
if (rv)
return rv;
/* 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. */
/* Rewrite the data */
return flash_physical_write(usable_flash_size, sizeof(pstate),
(const char *)&pstate);
#else
return EC_SUCCESS;
#endif /* CHIP_stm32 */
}
/* 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;
/* If write protect is disabled, nothing to do */
if (!wp_pin_asserted())
return EC_SUCCESS;
/* Read the current persist state from flash */
rv = read_pstate();
if (rv)
return rv;
/* If flash isn't locked, nothing to do */
if (!(pstate.lock & FLASH_PROTECT_LOCK_SET))
return EC_SUCCESS;
/* Lock the protection data first */
flash_physical_set_protect(banks);
/* Then lock any banks necessary */
for (i = 0; i < banks; i++) {
if (pstate.blocks[i] & FLASH_PROTECT_PERSISTENT)
flash_physical_set_protect(i);
}
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);
}
int flash_get_size(void)
{
return usable_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) & (align - 1))
return -1; /* Invalid range */
if (ptrp)
*ptrp = flash_physical_dataptr(offset);
return usable_flash_size - offset;
}
int flash_read(int offset, int size, char *data)
{
if (flash_dataptr(offset, size, 1, NULL) < 0)
return EC_ERROR_INVAL; /* Invalid range */
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 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;
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;
/* 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;
/* Set the new flag */
pstate.lock = lock ? FLASH_PROTECT_LOCK_SET : 0;
/* Write the state back to flash */
rv = write_pstate();
if (rv)
return rv;
/* If unlocking, done now */
if (!lock)
return EC_SUCCESS;
/* Otherwise, we need to apply all locks NOW */
return apply_pstate();
}
const uint8_t *flash_get_protect_array(void)
{
/* 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.) */
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++) {
if (flash_physical_get_protect(i))
pstate.blocks[i] |= FLASH_PROTECT_UNTIL_REBOOT;
}
/* Return the block array */
return pstate.blocks;
}
int flash_get_protect(int offset, int size)
{
int pbsize = flash_get_protect_block_size();
uint8_t minflags = 0xff;
int i;
if (flash_dataptr(offset, size, pbsize, NULL) < 0)
return 0; /* Invalid range; assume nothing protected */
/* Convert offset and size to blocks */
offset /= pbsize;
size /= pbsize;
/* Read the current persist state from flash */
read_pstate();
/* Combine with current block protection state */
for (i = 0; i < size; i++) {
int f = pstate.blocks[offset + i];
if (flash_physical_get_protect(offset + i))
f |= FLASH_PROTECT_UNTIL_REBOOT;
minflags &= f;
}
return minflags;
}
int flash_get_protect_lock(void)
{
int flags;
/* Read the current persist state from flash */
read_pstate();
flags = pstate.lock;
/* Check if lock has been applied */
if (is_pstate_lock_applied())
flags |= FLASH_PROTECT_LOCK_APPLIED;
/* Check if write protect pin is asserted now */
if (wp_pin_asserted())
flags |= FLASH_PROTECT_PIN_ASSERTED;
return flags;
}
/*****************************************************************************/
/* Initialization */
int flash_pre_init(void)
{
#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. */
usable_flash_size = flash_physical_size() -
flash_get_protect_block_size();
#endif
/* Apply write protect to blocks if needed */
return apply_pstate();
}