mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-05 22:41:44 +00:00
Merge "Implement persistent flash write protect settings"
This commit is contained in:
@@ -21,6 +21,10 @@
|
||||
#define CONFIG_TMP006
|
||||
#define CONFIG_USB_CHARGE
|
||||
|
||||
/* Temporarily use RECOVERYn signal for the write protect signal instead of
|
||||
* WRITE_PROTECTn. This way we can test via servo. crosbug.com/p/8580. */
|
||||
#define CONFIG_WP_USES_RECOVERY_GPIO
|
||||
|
||||
/* 66.667 Mhz clock frequency */
|
||||
#define CPU_CLOCK 66666667
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
/* Memory mapping */
|
||||
#define CONFIG_FLASH_BASE 0x00000000
|
||||
#define CONFIG_FLASH_SIZE 0x00040000
|
||||
#define CONFIG_FLASH_BANK_SIZE 0x2000
|
||||
#define CONFIG_FLASH_BANK_SIZE 0x00000800 /* Protect bank size */
|
||||
#define CONFIG_RAM_BASE 0x20000000
|
||||
#define CONFIG_RAM_SIZE 0x00008000
|
||||
|
||||
|
||||
208
chip/lm4/flash.c
208
chip/lm4/flash.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
|
||||
/* 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.
|
||||
*/
|
||||
@@ -6,24 +6,21 @@
|
||||
/* Flash memory module for Chrome EC */
|
||||
|
||||
#include "flash.h"
|
||||
#include "gpio.h"
|
||||
#include "uart.h"
|
||||
#include "registers.h"
|
||||
#include "util.h"
|
||||
|
||||
#define FLASH_WRITE_BYTES 4
|
||||
#define FLASH_FWB_WORDS 32
|
||||
#define FLASH_FWB_BYTES (FLASH_FWB_WORDS * 4)
|
||||
#define FLASH_ERASE_BYTES 1024
|
||||
#define FLASH_PROTECT_BYTES 2048
|
||||
|
||||
#define BANK_SHIFT 5 /* bank registers have 32bits each, 2^32 */
|
||||
#define BANK_MASK ((1 << BANK_SHIFT) - 1) /* 5 bits */
|
||||
#define F_BANK(b) ((b) >> BANK_SHIFT)
|
||||
#define F_BIT(b) (1 << ((b) & BANK_MASK))
|
||||
|
||||
static int usable_flash_size;
|
||||
|
||||
|
||||
int flash_get_size(void)
|
||||
{
|
||||
return usable_flash_size;
|
||||
}
|
||||
|
||||
|
||||
int flash_get_write_block_size(void)
|
||||
{
|
||||
@@ -39,16 +36,19 @@ int flash_get_erase_block_size(void)
|
||||
|
||||
int flash_get_protect_block_size(void)
|
||||
{
|
||||
BUILD_ASSERT(FLASH_PROTECT_BYTES == CONFIG_FLASH_BANK_SIZE);
|
||||
return FLASH_PROTECT_BYTES;
|
||||
}
|
||||
|
||||
|
||||
int flash_read(int offset, int size, char *data)
|
||||
int flash_physical_size(void)
|
||||
{
|
||||
if (size < 0 || offset > usable_flash_size ||
|
||||
offset + size > usable_flash_size)
|
||||
return EC_ERROR_UNKNOWN; /* Invalid range */
|
||||
return (LM4_FLASH_FSIZE + 1) * FLASH_PROTECT_BYTES;
|
||||
}
|
||||
|
||||
|
||||
int flash_physical_read(int offset, int size, char *data)
|
||||
{
|
||||
/* Just read the flash from its memory window. */
|
||||
/* TODO: (crosbug.com/p/7473) is this affected by data cache?
|
||||
* That is, if we read a block, then alter it, then read it
|
||||
@@ -58,8 +58,8 @@ int flash_read(int offset, int size, char *data)
|
||||
}
|
||||
|
||||
|
||||
/* Performs a write-buffer operation. Buffer (FWB) and address (FMA)
|
||||
* must be pre-loaded. */
|
||||
/* Perform a write-buffer operation. Buffer (FWB) and address (FMA) must be
|
||||
* pre-loaded. */
|
||||
static int write_buffer(void)
|
||||
{
|
||||
if (!LM4_FLASH_FWBVAL)
|
||||
@@ -72,32 +72,25 @@ static int write_buffer(void)
|
||||
LM4_FLASH_FMC2 = 0xa4420001;
|
||||
|
||||
/* Wait for write to complete */
|
||||
/* TODO: timeout */
|
||||
while (LM4_FLASH_FMC2 & 0x01) {}
|
||||
|
||||
/* Check for error conditions - program failed, erase needed,
|
||||
* voltage error. */
|
||||
if (LM4_FLASH_FCRIS & 0x2600)
|
||||
if (LM4_FLASH_FCRIS & 0x2e01)
|
||||
return EC_ERROR_UNKNOWN;
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int flash_write(int offset, int size, const char *data)
|
||||
int flash_physical_write(int offset, int size, const char *data)
|
||||
{
|
||||
const uint32_t *data32 = (const uint32_t *)data;
|
||||
int rv;
|
||||
int i;
|
||||
|
||||
if (size < 0 || offset > usable_flash_size ||
|
||||
offset + size > usable_flash_size ||
|
||||
(offset | size) & (FLASH_WRITE_BYTES - 1))
|
||||
return EC_ERROR_UNKNOWN; /* Invalid range */
|
||||
|
||||
/* TODO (crosbug.com/p/7478) - safety check - don't allow writing to
|
||||
* the image we're running from */
|
||||
|
||||
/* Get initial page and write buffer index */
|
||||
/* Get initial write buffer index and page */
|
||||
LM4_FLASH_FMA = offset & ~(FLASH_FWB_BYTES - 1);
|
||||
i = (offset >> 2) & (FLASH_FWB_WORDS - 1);
|
||||
|
||||
@@ -125,16 +118,8 @@ int flash_write(int offset, int size, const char *data)
|
||||
}
|
||||
|
||||
|
||||
int flash_erase(int offset, int size)
|
||||
int flash_physical_erase(int offset, int size)
|
||||
{
|
||||
if (size < 0 || offset > usable_flash_size ||
|
||||
offset + size > usable_flash_size ||
|
||||
(offset | size) & (FLASH_ERASE_BYTES - 1))
|
||||
return EC_ERROR_UNKNOWN; /* Invalid range */
|
||||
|
||||
/* TODO (crosbug.com/p/7478) - safety check - don't allow erasing the
|
||||
* image we're running from */
|
||||
|
||||
LM4_FLASH_FCMISC = LM4_FLASH_FCRIS; /* Clear previous error status */
|
||||
LM4_FLASH_FMA = offset;
|
||||
|
||||
@@ -143,10 +128,12 @@ int flash_erase(int offset, int size)
|
||||
LM4_FLASH_FMC = 0xa4420002;
|
||||
|
||||
/* Wait for erase to complete */
|
||||
/* TODO: timeout */
|
||||
while (LM4_FLASH_FMC & 0x02) {}
|
||||
|
||||
/* Check for error conditions - erase failed, voltage error */
|
||||
if (LM4_FLASH_FCRIS & 0x0a00)
|
||||
/* Check for error conditions - erase failed, voltage error,
|
||||
* protection error */
|
||||
if (LM4_FLASH_FCRIS & 0x0a01)
|
||||
return EC_ERROR_UNKNOWN;
|
||||
|
||||
LM4_FLASH_FMA += FLASH_ERASE_BYTES;
|
||||
@@ -155,149 +142,14 @@ int flash_erase(int offset, int size)
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
/* Get write protect status of single flash block
|
||||
* return value:
|
||||
* 0 - WP
|
||||
* non-zero - writable
|
||||
*/
|
||||
static uint32_t get_block_wp(int block)
|
||||
|
||||
int flash_physical_get_protect(int block)
|
||||
{
|
||||
return LM4_FLASH_FMPPE[F_BANK(block)] & F_BIT(block);
|
||||
return (LM4_FLASH_FMPPE[F_BANK(block)] & F_BIT(block)) ? 0 : 1;
|
||||
}
|
||||
|
||||
static void set_block_wp(int block)
|
||||
|
||||
void flash_physical_set_protect(int block)
|
||||
{
|
||||
LM4_FLASH_FMPPE[F_BANK(block)] &= ~F_BIT(block);
|
||||
}
|
||||
|
||||
static int find_first_wp_block(void)
|
||||
{
|
||||
int block;
|
||||
for (block = 0; block < LM4_FLASH_FSIZE; block++)
|
||||
if (get_block_wp(block) == 0)
|
||||
return block;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int find_last_wp_block(void)
|
||||
{
|
||||
int block;
|
||||
for (block = LM4_FLASH_FSIZE - 1; block >= 0; block--)
|
||||
if (get_block_wp(block) == 0)
|
||||
return block;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int get_wp_range(uint32_t *start, uint32_t *nblock)
|
||||
{
|
||||
int start_blk, end_blk;
|
||||
|
||||
start_blk = find_first_wp_block();
|
||||
|
||||
if (start_blk < 0) {
|
||||
/* Flash is not write protected */
|
||||
*start = 0;
|
||||
*nblock = 0;
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
/* TODO: Sanity check the shadow value? */
|
||||
|
||||
end_blk = find_last_wp_block();
|
||||
*nblock = (uint32_t)(end_blk - start_blk + 1);
|
||||
*start = (uint32_t)start_blk;
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int set_wp_range(int start, int nblock)
|
||||
{
|
||||
int end_blk, block;
|
||||
|
||||
if (nblock == 0)
|
||||
return EC_SUCCESS;
|
||||
|
||||
end_blk = (start + nblock - 1);
|
||||
|
||||
for (block = start; block <= end_blk; block++)
|
||||
set_block_wp(block);
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
int flash_get_write_protect_range(uint32_t *offset, uint32_t *size)
|
||||
{
|
||||
uint32_t start, nblock;
|
||||
int rv;
|
||||
|
||||
rv = get_wp_range(&start, &nblock);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
*size = nblock * FLASH_PROTECT_BYTES;
|
||||
*offset = start * FLASH_PROTECT_BYTES;
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
int flash_set_write_protect_range(uint32_t offset, uint32_t size)
|
||||
{
|
||||
int start, nblock;
|
||||
int rv;
|
||||
|
||||
if ((offset + size) > (LM4_FLASH_FSIZE * FLASH_PROTECT_BYTES))
|
||||
return EC_ERROR_UNKNOWN; /* Invalid range */
|
||||
|
||||
rv = flash_get_write_protect_status();
|
||||
|
||||
if (rv & EC_FLASH_WP_RANGE_LOCKED) {
|
||||
if (size == 0) {
|
||||
/* TODO: Clear shadow if system WP is asserted */
|
||||
/* TODO: Reboot EC */
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
return EC_ERROR_UNKNOWN; /* Range locked */
|
||||
}
|
||||
|
||||
start = offset / FLASH_PROTECT_BYTES;
|
||||
nblock = ((offset + size - 1) / FLASH_PROTECT_BYTES) - start + 1;
|
||||
rv = set_wp_range(start, nblock);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int flash_get_write_protect_status(void)
|
||||
{
|
||||
uint32_t start, nblock;
|
||||
int rv;
|
||||
|
||||
rv = get_wp_range(&start, &nblock);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
rv = 0;
|
||||
if (nblock)
|
||||
rv |= EC_FLASH_WP_RANGE_LOCKED;
|
||||
/* TODO: get WP gpio*/
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
int flash_pre_init(void)
|
||||
{
|
||||
/* Calculate usable flash size. Reserve one protection block
|
||||
* at the top to hold the write protect range. FSIZE already
|
||||
* returns one less than the number of protection pages. */
|
||||
usable_flash_size = LM4_FLASH_FSIZE * FLASH_PROTECT_BYTES;
|
||||
|
||||
/* TODO (crosbug.com/p/7453) - check WP# GPIO. If it's set and the
|
||||
* flash protect range is set, write the flash protection registers.
|
||||
* Probably cleaner to do this in vboot, since we're going to need to
|
||||
* use the same last block of flash to hold the firmware rollback
|
||||
* counters. */
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ common-y+=memory_commands.o shared_mem.o system_common.o
|
||||
common-y+=gpio_commands.o version.o
|
||||
common-$(CONFIG_BATTERY_ATL706486)+=battery_atl706486.o
|
||||
common-$(CONFIG_CHARGER_BQ24725)+=charger_bq24725.o
|
||||
common-$(CONFIG_FLASH)+=flash_commands.o
|
||||
common-$(CONFIG_FLASH)+=flash_common.o flash_commands.o
|
||||
common-$(CONFIG_LIGHTBAR)+=lightbar.o
|
||||
common-$(CONFIG_LPC)+=port80.o host_event_commands.o
|
||||
common-$(CONFIG_POWER_LED)+=power_led.o
|
||||
|
||||
@@ -14,13 +14,81 @@
|
||||
#include "uart.h"
|
||||
#include "util.h"
|
||||
|
||||
/* Parse offset and size from command line argv[0] and argv[1].
|
||||
*
|
||||
* Default values: If argc<1, leaves offset unchanged, returning error if
|
||||
* *offset<0. If argc<2, leaves size unchanged, returning error if *size<0. */
|
||||
static int parse_offset_size(int argc, char **argv, int *offset, int *size)
|
||||
{
|
||||
char *e;
|
||||
int i;
|
||||
|
||||
if (argc >= 1) {
|
||||
i = (uint32_t)strtoi(argv[0], &e, 0);
|
||||
if (e && *e) {
|
||||
uart_printf("Invalid offset \"%s\"\n", argv[0]);
|
||||
return EC_ERROR_INVAL;
|
||||
}
|
||||
*offset = i;
|
||||
} else if (*offset < 0) {
|
||||
uart_puts("Must specify offset.\n");
|
||||
return EC_ERROR_INVAL;
|
||||
}
|
||||
|
||||
if (argc >= 2) {
|
||||
i = (uint32_t)strtoi(argv[1], &e, 1);
|
||||
if (e && *e) {
|
||||
uart_printf("Invalid size \"%s\"\n", argv[1]);
|
||||
return EC_ERROR_INVAL;
|
||||
}
|
||||
*size = i;
|
||||
} else if (*size < 0) {
|
||||
uart_puts("Must specify offset and size.\n");
|
||||
return EC_ERROR_INVAL;
|
||||
}
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Console commands */
|
||||
|
||||
static int command_flash_info(int argc, char **argv)
|
||||
{
|
||||
uart_printf("Usable flash size: %d B\n", flash_get_size());
|
||||
const uint8_t *wp;
|
||||
int banks = flash_get_size() / flash_get_protect_block_size();
|
||||
int i;
|
||||
|
||||
uart_printf("Physical size: %4d KB\n", flash_physical_size() / 1024);
|
||||
uart_printf("Usable size: %4d KB\n", flash_get_size() / 1024);
|
||||
uart_printf("Write block: %4d B\n", flash_get_write_block_size());
|
||||
uart_printf("Erase block: %4d B\n", flash_get_erase_block_size());
|
||||
uart_printf("Protect block: %4d B\n", flash_get_protect_block_size());
|
||||
|
||||
i = flash_get_protect_lock();
|
||||
uart_printf("Protect lock: %s%s\n",
|
||||
(i & FLASH_PROTECT_LOCK_SET) ? "LOCKED" : "unlocked",
|
||||
(i & FLASH_PROTECT_LOCK_APPLIED) ? " AND APPLIED" : "");
|
||||
uart_printf("WP pin: %s\n", (i & FLASH_PROTECT_PIN_ASSERTED) ?
|
||||
"ASSERTED" : "deasserted");
|
||||
|
||||
wp = flash_get_protect_array();
|
||||
|
||||
uart_puts("Protected now:");
|
||||
for (i = 0; i < banks; i++) {
|
||||
if (!(i & 7))
|
||||
uart_puts(" ");
|
||||
uart_puts(wp[i] & FLASH_PROTECT_UNTIL_REBOOT ? "Y" : ".");
|
||||
}
|
||||
uart_puts("\n Persistent: ");
|
||||
for (i = 0; i < banks; i++) {
|
||||
if (!(i & 7))
|
||||
uart_puts(" ");
|
||||
uart_puts(wp[i] & FLASH_PROTECT_PERSISTENT ? "Y" : ".");
|
||||
}
|
||||
uart_puts("\n");
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
DECLARE_CONSOLE_COMMAND(flashinfo, command_flash_info);
|
||||
@@ -28,73 +96,37 @@ DECLARE_CONSOLE_COMMAND(flashinfo, command_flash_info);
|
||||
|
||||
static int command_flash_erase(int argc, char **argv)
|
||||
{
|
||||
int offset = 0;
|
||||
int size = FLASH_ERASE_BYTES;
|
||||
char *endptr;
|
||||
int offset = -1;
|
||||
int size = flash_get_erase_block_size();
|
||||
int rv;
|
||||
|
||||
if (argc < 2) {
|
||||
uart_puts("Usage: flasherase <offset> [size]\n");
|
||||
return EC_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
offset = strtoi(argv[1], &endptr, 0);
|
||||
if (*endptr) {
|
||||
uart_puts("Invalid offset\n");
|
||||
return EC_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
if (argc > 2) {
|
||||
size = strtoi(argv[2], &endptr, 0);
|
||||
if (*endptr) {
|
||||
uart_puts("Invalid size\n");
|
||||
return EC_ERROR_UNKNOWN;
|
||||
}
|
||||
}
|
||||
rv = parse_offset_size(argc - 1, argv + 1, &offset, &size);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
uart_printf("Erasing %d bytes at offset 0x%x (%d)...\n",
|
||||
size, offset, offset);
|
||||
rv = flash_erase(offset, size);
|
||||
if (rv == EC_SUCCESS)
|
||||
uart_puts("done.\n");
|
||||
else
|
||||
uart_printf("failed. (error %d)\n", rv);
|
||||
|
||||
return rv;
|
||||
return flash_erase(offset, size);
|
||||
}
|
||||
DECLARE_CONSOLE_COMMAND(flasherase, command_flash_erase);
|
||||
|
||||
|
||||
static int command_flash_write(int argc, char **argv)
|
||||
{
|
||||
char *data;
|
||||
int offset = 0;
|
||||
int size = 1024; /* Default size */
|
||||
char *endptr;
|
||||
int offset = -1;
|
||||
int size = flash_get_erase_block_size();
|
||||
int rv;
|
||||
char *data;
|
||||
int i;
|
||||
|
||||
if (argc < 2) {
|
||||
uart_puts("Usage: flashwrite <offset> <size>\n");
|
||||
return EC_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
offset = strtoi(argv[1], &endptr, 0);
|
||||
if (*endptr) {
|
||||
uart_puts("Invalid offset\n");
|
||||
return EC_ERROR_UNKNOWN;
|
||||
}
|
||||
rv = parse_offset_size(argc - 1, argv + 1, &offset, &size);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
if (argc > 2) {
|
||||
size = strtoi(argv[2], &endptr, 0);
|
||||
if (*endptr) {
|
||||
uart_puts("Invalid size\n");
|
||||
return EC_ERROR_UNKNOWN;
|
||||
}
|
||||
if (size > shared_mem_size()) {
|
||||
uart_puts("Truncating size\n");
|
||||
size = sizeof(data);
|
||||
}
|
||||
if (size > shared_mem_size()) {
|
||||
uart_puts("Truncating size\n");
|
||||
size = shared_mem_size();
|
||||
}
|
||||
|
||||
/* Acquire the shared memory buffer */
|
||||
@@ -124,70 +156,46 @@ static int command_flash_write(int argc, char **argv)
|
||||
DECLARE_CONSOLE_COMMAND(flashwrite, command_flash_write);
|
||||
|
||||
|
||||
static const char flash_wp_help[] =
|
||||
"Usage: flashwp <now | set | clear> <offset> [size]\n"
|
||||
" or: flashwp <lock | unlock>\n";
|
||||
|
||||
|
||||
static int command_flash_wp(int argc, char **argv)
|
||||
{
|
||||
int b = 0;
|
||||
char *endptr;
|
||||
|
||||
if (argc < 2) {
|
||||
uart_puts("Usage: flashwp [bitmask]\n");
|
||||
uart_printf("(current value of FMPPE1: 0x%08x)\n",
|
||||
LM4_FLASH_FMPPE1);
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
b = strtoi(argv[1], &endptr, 0);
|
||||
if (*endptr) {
|
||||
uart_puts("Invalid bitmask\n");
|
||||
return EC_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
uart_printf("FMPPE1 before: 0x%08x\n", LM4_FLASH_FMPPE1);
|
||||
LM4_FLASH_FMPPE1 = b;
|
||||
uart_printf("FMPPE1 after: 0x%08x\n", LM4_FLASH_FMPPE1);
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
DECLARE_CONSOLE_COMMAND(flashwp, command_flash_wp);
|
||||
|
||||
static int command_flash_wp_range(int argc, char **argv)
|
||||
{
|
||||
uint32_t offset, size;
|
||||
char *endptr;
|
||||
int offset = -1;
|
||||
int size = flash_get_protect_block_size();
|
||||
int rv;
|
||||
|
||||
if (argc < 3) {
|
||||
uart_puts("Usage: flashwprange [offset size]\n");
|
||||
rv = flash_get_write_protect_range(&offset, &size);
|
||||
if (rv)
|
||||
uart_puts("flash_get_write_protect_range failed\n");
|
||||
else
|
||||
uart_printf("Current range : offset(%d) size(%d)\n",
|
||||
offset, size);
|
||||
uart_printf("FMPPEs : %08x %08x %08x %08x\n",
|
||||
LM4_FLASH_FMPPE0, LM4_FLASH_FMPPE1,
|
||||
LM4_FLASH_FMPPE2, LM4_FLASH_FMPPE3);
|
||||
} else {
|
||||
offset = (uint32_t)strtoi(argv[1], &endptr, 0);
|
||||
if (*endptr) {
|
||||
uart_printf("Invalid offset \"%s\"\n", argv[1]);
|
||||
return EC_ERROR_UNKNOWN;
|
||||
}
|
||||
size = (uint32_t)strtoi(argv[2], &endptr, 0);
|
||||
if (*endptr) {
|
||||
uart_printf("Invalid size \"%s\"\n", argv[2]);
|
||||
return EC_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
rv = flash_set_write_protect_range(offset, size);
|
||||
if (rv) {
|
||||
uart_puts("flash_set_write_protect_range failed\n");
|
||||
return rv;
|
||||
}
|
||||
if (argc < 2) {
|
||||
uart_puts(flash_wp_help);
|
||||
return EC_ERROR_INVAL;
|
||||
}
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
DECLARE_CONSOLE_COMMAND(flashwprange, command_flash_wp_range);
|
||||
|
||||
/* 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 - 2, 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 {
|
||||
uart_puts(flash_wp_help);
|
||||
return EC_ERROR_INVAL;
|
||||
}
|
||||
|
||||
}
|
||||
DECLARE_CONSOLE_COMMAND(flashwp, command_flash_wp);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Host commands */
|
||||
@@ -198,9 +206,9 @@ enum lpc_status flash_command_get_info(uint8_t *data)
|
||||
(struct lpc_response_flash_info *)data;
|
||||
|
||||
r->flash_size = flash_get_size();
|
||||
r->write_block_size = FLASH_WRITE_BYTES;
|
||||
r->erase_block_size = FLASH_ERASE_BYTES;
|
||||
r->protect_block_size = FLASH_PROTECT_BYTES;
|
||||
r->write_block_size = flash_get_write_block_size();
|
||||
r->erase_block_size = flash_get_erase_block_size();
|
||||
r->protect_block_size = flash_get_protect_block_size();
|
||||
return EC_LPC_RESULT_SUCCESS;
|
||||
}
|
||||
DECLARE_HOST_COMMAND(EC_LPC_COMMAND_FLASH_INFO, flash_command_get_info);
|
||||
@@ -286,7 +294,13 @@ enum lpc_status flash_command_erase(uint8_t *data)
|
||||
DECLARE_HOST_COMMAND(EC_LPC_COMMAND_FLASH_ERASE, flash_command_erase);
|
||||
|
||||
|
||||
/* TODO: use shadow range in EEPROM */
|
||||
#ifdef REWORK_THESE_TO_USE_NEW_WP_MECHANISM
|
||||
/* TODO: (crosbug.com/p/8448) rework these to use the new WP mechanism. Note
|
||||
* that the concept of a single range oversimplifies how WP works; there are
|
||||
* multiple protected regions, including the persistent WP state (last bank)
|
||||
* and rollback information (bank before that; will be implemented by
|
||||
* vboot). */
|
||||
|
||||
static int shadow_wp_offset;
|
||||
static int shadow_wp_size;
|
||||
|
||||
@@ -354,3 +368,5 @@ enum lpc_status flash_command_wp_get_range(uint8_t *data)
|
||||
}
|
||||
DECLARE_HOST_COMMAND(EC_LPC_COMMAND_FLASH_WP_GET_RANGE,
|
||||
flash_command_wp_get_range);
|
||||
|
||||
#endif /* REWORK_THESE_TO_USE_NEW_WP_MECHANISM */
|
||||
|
||||
349
common/flash_common.c
Normal file
349
common/flash_common.c
Normal file
@@ -0,0 +1,349 @@
|
||||
/* 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 "uart.h"
|
||||
#include "util.h"
|
||||
|
||||
#define PERSIST_STATE_VERSION 1
|
||||
#define MAX_BANKS (CONFIG_FLASH_SIZE / CONFIG_FLASH_BANK_SIZE)
|
||||
|
||||
/* Persistent protection state */
|
||||
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 CONFIG_WP_USES_RECOVERY_GPIO
|
||||
/* Bypass all WP if the recovery GPIO is asserted. This is a temporary
|
||||
* workaround to allow servo-based testing of WP. See
|
||||
* crosbug.com/p/8580. */
|
||||
return gpio_get_level(GPIO_RECOVERYn) == 0 ? 0 : 1;
|
||||
#else
|
||||
return gpio_get_level(GPIO_WRITE_PROTECTn) == 0 ? 1 : 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Read persistent state into pstate. */
|
||||
static int read_pstate(void)
|
||||
{
|
||||
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;
|
||||
|
||||
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());
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/* 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_read(int offset, int size, char *data)
|
||||
{
|
||||
if (size < 0 || offset > usable_flash_size ||
|
||||
offset + size > usable_flash_size)
|
||||
return EC_ERROR_UNKNOWN; /* Invalid range */
|
||||
|
||||
return flash_physical_read(offset, size, data);
|
||||
}
|
||||
|
||||
|
||||
int flash_write(int offset, int size, const char *data)
|
||||
{
|
||||
if (size < 0 || offset > usable_flash_size ||
|
||||
offset + size > usable_flash_size ||
|
||||
(offset | size) & (flash_get_write_block_size() - 1))
|
||||
return EC_ERROR_UNKNOWN; /* 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 (size < 0 || offset > usable_flash_size ||
|
||||
offset + size > usable_flash_size ||
|
||||
(offset | size) & (flash_get_erase_block_size() - 1))
|
||||
return EC_ERROR_UNKNOWN; /* 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 (size < 0 || offset > usable_flash_size ||
|
||||
offset + size > usable_flash_size ||
|
||||
(offset | size) & (pbsize - 1))
|
||||
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 (size < 0 || offset > usable_flash_size ||
|
||||
offset + size > usable_flash_size ||
|
||||
(offset | size) & (pbsize - 1))
|
||||
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 (size < 0 || offset > usable_flash_size ||
|
||||
offset + size > usable_flash_size ||
|
||||
(offset | size) & (pbsize - 1))
|
||||
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)
|
||||
{
|
||||
/* Calculate usable flash size. Reserve one protection block
|
||||
* at the top to hold the write protect data. */
|
||||
usable_flash_size = flash_physical_size() -
|
||||
flash_get_protect_block_size();
|
||||
|
||||
/* Apply write protect to blocks if needed */
|
||||
return apply_pstate();
|
||||
}
|
||||
155
include/flash.h
155
include/flash.h
@@ -11,12 +11,37 @@
|
||||
#include "common.h"
|
||||
|
||||
|
||||
#define FLASH_WRITE_BYTES 4
|
||||
#define FLASH_FWB_WORDS 32
|
||||
#define FLASH_FWB_BYTES (FLASH_FWB_WORDS * 4)
|
||||
#define FLASH_ERASE_BYTES 1024
|
||||
#define FLASH_PROTECT_BYTES 2048
|
||||
/*****************************************************************************/
|
||||
/* Low-level methods, for use by flash_common. */
|
||||
|
||||
/* 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. */
|
||||
int flash_get_write_block_size(void);
|
||||
int flash_get_erase_block_size(void);
|
||||
int flash_get_protect_block_size(void);
|
||||
|
||||
/* Return the physical size of flash in bytes */
|
||||
int flash_physical_size(void);
|
||||
|
||||
/* Read <size> bytes of data from offset <offset> into <data>. */
|
||||
int flash_physical_read(int offset, int size, char *data);
|
||||
|
||||
/* Write <size> bytes of data to flash at byte offset <offset>.
|
||||
* <data> must be 32-bit aligned. */
|
||||
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);
|
||||
|
||||
/* Protects the block until reboot. */
|
||||
void flash_physical_set_protect(int block);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* High-level interface for use by other modules. */
|
||||
|
||||
/* Initializes the module. */
|
||||
int flash_pre_init(void);
|
||||
@@ -25,14 +50,6 @@ int flash_pre_init(void);
|
||||
* smaller than the actual flash size, */
|
||||
int flash_get_size(void);
|
||||
|
||||
/* Returns 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. */
|
||||
int flash_get_write_block_size(void);
|
||||
int flash_get_erase_block_size(void);
|
||||
int flash_get_protect_block_size(void);
|
||||
|
||||
/* Reads <size> bytes of data from offset <offset> into <data>. */
|
||||
int flash_read(int offset, int size, char *data);
|
||||
|
||||
@@ -43,46 +60,90 @@ int flash_write(int offset, int size, const char *data);
|
||||
/* Erases <size> bytes of flash at byte offset <offset>. */
|
||||
int flash_erase(int offset, int size);
|
||||
|
||||
/* TODO: not super happy about the following APIs yet.
|
||||
/* Flash protection APIs
|
||||
*
|
||||
* The theory of operation is that we'll use the last page of flash to
|
||||
* hold the write protect range, and the flag for whether the last
|
||||
* page itself should be protected. Then when flash_init() is called,
|
||||
* it checks if the write protect pin is asserted, and if so, it
|
||||
* writes (but does not commit) the flash protection registers.
|
||||
* Flash can be protected on a per-block basis at any point by calling
|
||||
* flash_protect_until_reboot(). Once a block is protected, it will stay
|
||||
* protected until reboot. This function may be called at any time, regardless
|
||||
* of the persistent flash protection state, and protection will be applied
|
||||
* immediately.
|
||||
*
|
||||
* This simulates what a SPI flash does, where the status register
|
||||
* holds the write protect range, and a bit which protects the status
|
||||
* register itself. The bit is only obeyed if the write protect pin
|
||||
* is enabled.
|
||||
* Flash may also be protected in a persistent fashion by calling
|
||||
* flash_set_protect(). This sets a persistent flag for each block which is
|
||||
* checked at boot time and applied if the hardware write protect pin is
|
||||
* enabled.
|
||||
*
|
||||
* It's an imperfect simulation, because in a SPI flash, as soon as
|
||||
* you deassert the pin you can alter the status register, where here
|
||||
* it'll take a cold boot to clear protection. Also, here protection
|
||||
* gets written to the registers as soon as you set the write protect
|
||||
* lock, which is different than SPI, where it's effective as soon as
|
||||
* you set the write protect range. */
|
||||
* The flash persistent protection settings are themselves protected by a lock,
|
||||
* which can be set via flash_lock_protect(). Once the protection settings are
|
||||
* locked:
|
||||
*
|
||||
* (1) They will be immediately applied (as if flash_protect_until_reboot()
|
||||
* had been called).
|
||||
*
|
||||
* (2) The persistent settings cannot be changed. That is, subsequent calls
|
||||
* to flash_set_protect() and flash_lock_protect() will fail.
|
||||
*
|
||||
* The lock can be bypassed by cold-booting the system with the hardware write
|
||||
* protect pin deasserted. In this case, the persistent settings and lock
|
||||
* state may be changed until flash_lock_protect(non-zero) is called, or until
|
||||
* the system is rebooted with the write protect pin asserted - at which point,
|
||||
* protection is re-applied. */
|
||||
|
||||
/* Gets or sets the write protect range in bytes. This setting is
|
||||
* stored in flash, and persists across reboots. If size is non-zero,
|
||||
* the write protect range is also locked, and may not be subsequently
|
||||
* altered until after a cold boot with the write protect pin
|
||||
* deasserted. */
|
||||
int flash_get_write_protect_range(uint32_t *offset, uint32_t *size);
|
||||
int flash_set_write_protect_range(uint32_t offset, uint32_t size);
|
||||
/* Write-protect <size> bytes of flash at byte offset <offset> until next
|
||||
* reboot. */
|
||||
int flash_protect_until_reboot(int offset, int size);
|
||||
|
||||
/* The write protect range has been stored into the chip registers
|
||||
* this boot. The flash is write protected and the range cannot be
|
||||
* changed without rebooting. */
|
||||
#define EC_FLASH_WP_RANGE_LOCKED 0x01
|
||||
/* The write protect pin was asserted at init time. */
|
||||
#define EC_FLASH_WP_PIN_ASSERTED_AT_INIT 0x02
|
||||
/* The write protect pin is asserted now. */
|
||||
#define EC_FLASH_WP_PIN_ASSERTED_NOW 0x04
|
||||
/* Higher-level APIs to emulate SPI write protect */
|
||||
|
||||
/* Returns the current write protect status; see EC_FLASH_WP_*
|
||||
* for valid flags. */
|
||||
int flash_get_write_protect_status(void);
|
||||
/* 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.
|
||||
*
|
||||
* If called with lock!=0, this will also immediately protect all
|
||||
* persistently-protected blocks. */
|
||||
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
|
||||
|
||||
/* 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
|
||||
* function. */
|
||||
const uint8_t *flash_get_protect_array(void);
|
||||
|
||||
/* Return the lowest amount of protection for any flash block in the specified
|
||||
* range. That is, if any byte in the range is not protected until reboot,
|
||||
* FLASH_PROTECT_UNTIL_REBOOT will not be set. */
|
||||
int flash_get_protect(int offset, int size);
|
||||
|
||||
/* Flags for flash_get_protect_lock() */
|
||||
/* Flash protection lock has been set. Note that if the write protect pin was
|
||||
* deasserted at boot time, this simply indicates the state of the lock
|
||||
* setting, and not whether blocks are actually protected. */
|
||||
#define FLASH_PROTECT_LOCK_SET 0x01
|
||||
/* Flash protection lock has actually been applied. All blocks with
|
||||
FLASH_PROTECT_PERSISTENT have been protected, and flash protection cannot be
|
||||
unlocked. */
|
||||
#define FLASH_PROTECT_LOCK_APPLIED 0x02
|
||||
/* Write protect pin is currently asserted */
|
||||
#define FLASH_PROTECT_PIN_ASSERTED 0x04
|
||||
|
||||
/* Return the flash protect lock status. */
|
||||
int flash_get_protect_lock(void);
|
||||
|
||||
#endif /* __CROS_EC_FLASH_H */
|
||||
|
||||
Reference in New Issue
Block a user