mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-27 18:25:05 +00:00
This renames constants used in compiler conditionals to uppercase.
BOARD_foo
CHIP_foo
CHIP_FAMILY_foo
CHIP_VARIANT_foo
CORE_foo
Mixed-case constants are still defined by the makefile, but are now no
longer used. I will make one more pass in a week or so to catch any
that are part of someone else's CL, since otherwise this change might
silently merge correctly but result in incorrect compilation. Then I
will remove defining the mixed-case constants.
BUG=chromium:322144
BRANCH=none
TEST=Build all boards. Also, "git grep 'BOARD_[a-z]'" should return no
results (similarly for CHIP, CORE, etc.)
Change-Id: I6418412e9f7ec604a35c2d426d12475dd83e7076
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/179206
Reviewed-by: Vic Yang <victoryang@chromium.org>
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
690 lines
18 KiB
C
690 lines
18 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 "common.h"
|
|
#include "console.h"
|
|
#include "flash.h"
|
|
#include "gpio.h"
|
|
#include "host_command.h"
|
|
#include "shared_mem.h"
|
|
#include "system.h"
|
|
#include "util.h"
|
|
#include "vboot_hash.h"
|
|
|
|
/*
|
|
* Contents of erased flash, as a 32-bit value. Most platforms erase flash
|
|
* bits to 1.
|
|
*/
|
|
#ifndef CONFIG_FLASH_ERASED_VALUE32
|
|
#define CONFIG_FLASH_ERASED_VALUE32 (-1U)
|
|
#endif
|
|
|
|
/* Persistent protection state - emulates a SPI status register for flashrom */
|
|
struct persist_state {
|
|
uint8_t version; /* Version of this struct */
|
|
uint8_t flags; /* Lock flags (PERSIST_FLAG_*) */
|
|
uint8_t reserved[2]; /* Reserved; set 0 */
|
|
};
|
|
|
|
#define PERSIST_STATE_VERSION 2 /* Expected persist_state.version */
|
|
|
|
/* Flags for persist_state.flags */
|
|
/* Protect persist state and RO firmware at boot */
|
|
#define PERSIST_FLAG_PROTECT_RO 0x02
|
|
|
|
/**
|
|
* Get the physical memory address of a flash offset
|
|
*
|
|
* This is used for direct flash access. We assume that the flash is
|
|
* contiguous from this start address through to the end of the usable
|
|
* flash.
|
|
*
|
|
* @param offset Flash offset to get address of
|
|
* @param dataptrp Returns pointer to memory address of flash offset
|
|
* @return pointer to flash memory offset, if ok, else NULL
|
|
*/
|
|
static const char *flash_physical_dataptr(int offset)
|
|
{
|
|
return (char *)((uintptr_t)CONFIG_FLASH_BASE + offset);
|
|
}
|
|
|
|
/**
|
|
* Read persistent state into pstate.
|
|
*
|
|
* @param pstate Destination for persistent state
|
|
*/
|
|
static void flash_read_pstate(struct persist_state *pstate)
|
|
{
|
|
memcpy(pstate, flash_physical_dataptr(PSTATE_OFFSET), sizeof(*pstate));
|
|
|
|
/* Sanity-check data and initialize if necessary */
|
|
if (pstate->version != PERSIST_STATE_VERSION) {
|
|
memset(pstate, 0, sizeof(*pstate));
|
|
pstate->version = PERSIST_STATE_VERSION;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Write persistent state from pstate, erasing if necessary.
|
|
*
|
|
* @param pstate Source persistent state
|
|
* @return EC_SUCCESS, or nonzero if error.
|
|
*/
|
|
static int flash_write_pstate(const struct persist_state *pstate)
|
|
{
|
|
struct persist_state current_pstate;
|
|
int rv;
|
|
|
|
/* Check if pstate has actually changed */
|
|
flash_read_pstate(¤t_pstate);
|
|
if (!memcmp(¤t_pstate, pstate, sizeof(*pstate)))
|
|
return EC_SUCCESS;
|
|
|
|
/* Erase pstate */
|
|
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.
|
|
* That's ok, because it's only possible to write the pstate before
|
|
* it's protected.
|
|
*/
|
|
|
|
/* Rewrite the data */
|
|
return flash_physical_write(PSTATE_OFFSET, sizeof(*pstate),
|
|
(const char *)pstate);
|
|
}
|
|
|
|
int flash_dataptr(int offset, int size_req, int align, const char **ptrp)
|
|
{
|
|
if (offset < 0 || size_req < 0 ||
|
|
offset + size_req > CONFIG_FLASH_SIZE ||
|
|
(offset | size_req) & (align - 1))
|
|
return -1; /* Invalid range */
|
|
if (ptrp)
|
|
*ptrp = flash_physical_dataptr(offset);
|
|
|
|
return CONFIG_FLASH_SIZE - offset;
|
|
}
|
|
|
|
int flash_is_erased(uint32_t offset, int size)
|
|
{
|
|
const uint32_t *ptr;
|
|
|
|
if (flash_dataptr(offset, size, sizeof(uint32_t),
|
|
(const char **)&ptr) < 0)
|
|
return 0;
|
|
|
|
for (size /= sizeof(uint32_t); size > 0; size -= 4, ptr++)
|
|
if (*ptr != CONFIG_FLASH_ERASED_VALUE32)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int flash_write(int offset, int size, const char *data)
|
|
{
|
|
if (flash_dataptr(offset, size, CONFIG_FLASH_WRITE_SIZE, NULL) < 0)
|
|
return EC_ERROR_INVAL; /* Invalid range */
|
|
|
|
#ifdef HAS_TASK_VBOOTHASH
|
|
vboot_hash_invalidate(offset, size);
|
|
#endif
|
|
|
|
return flash_physical_write(offset, size, data);
|
|
}
|
|
|
|
int flash_erase(int offset, int size)
|
|
{
|
|
if (flash_dataptr(offset, size, CONFIG_FLASH_ERASE_SIZE, NULL) < 0)
|
|
return EC_ERROR_INVAL; /* Invalid range */
|
|
|
|
#ifdef HAS_TASK_VBOOTHASH
|
|
vboot_hash_invalidate(offset, size);
|
|
#endif
|
|
|
|
return flash_physical_erase(offset, size);
|
|
}
|
|
|
|
int flash_protect_ro_at_boot(int enable)
|
|
{
|
|
struct persist_state pstate;
|
|
int new_flags = enable ? PERSIST_FLAG_PROTECT_RO : 0;
|
|
|
|
/* Read the current persist state from flash */
|
|
flash_read_pstate(&pstate);
|
|
|
|
if (pstate.flags != new_flags) {
|
|
/* Need to update pstate */
|
|
int rv;
|
|
|
|
/* Fail if write protect block is already locked */
|
|
if (flash_physical_get_protect(PSTATE_BANK))
|
|
return EC_ERROR_ACCESS_DENIED;
|
|
|
|
/* Set the new flag */
|
|
pstate.flags = new_flags;
|
|
|
|
/* Write the state back to flash */
|
|
rv = flash_write_pstate(&pstate);
|
|
if (rv)
|
|
return rv;
|
|
}
|
|
|
|
#ifdef CONFIG_FLASH_PROTECT_NEXT_BOOT
|
|
/*
|
|
* Try updating at-boot protection state, if on a platform where write
|
|
* protection only changes after a reboot. Otherwise we wouldn't
|
|
* update it until after the next reboot, and we'd need to reboot
|
|
* again. Ignore errors, because the protection registers might
|
|
* already be locked this boot, and we'll still apply the correct state
|
|
* again on the next boot.
|
|
*
|
|
* This assumes PSTATE immediately follows RO, which it does on
|
|
* all STM32 platforms (which are the only ones with this config).
|
|
*/
|
|
flash_physical_protect_ro_at_boot(new_flags);
|
|
#endif
|
|
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
uint32_t flash_get_protect(void)
|
|
{
|
|
struct persist_state pstate;
|
|
uint32_t flags = 0;
|
|
int not_protected[2] = {0};
|
|
int i;
|
|
|
|
/* Read write protect GPIO */
|
|
#ifdef CONFIG_WP_ACTIVE_HIGH
|
|
if (gpio_get_level(GPIO_WP))
|
|
flags |= EC_FLASH_PROTECT_GPIO_ASSERTED;
|
|
#else
|
|
if (!gpio_get_level(GPIO_WP_L))
|
|
flags |= EC_FLASH_PROTECT_GPIO_ASSERTED;
|
|
#endif
|
|
|
|
/* Read persistent state of RO-at-boot flag */
|
|
flash_read_pstate(&pstate);
|
|
if (pstate.flags & PERSIST_FLAG_PROTECT_RO)
|
|
flags |= EC_FLASH_PROTECT_RO_AT_BOOT;
|
|
|
|
/* Scan flash protection */
|
|
for (i = 0; i < PHYSICAL_BANKS; i++) {
|
|
/*
|
|
* Is this bank part of RO? Needs to handle PSTATE not
|
|
* immediately following RO code, since it doesn't on link.
|
|
*/
|
|
int is_ro = ((i >= RO_BANK_OFFSET &&
|
|
i < RO_BANK_OFFSET + RO_BANK_COUNT) ||
|
|
(i >= PSTATE_BANK &&
|
|
i < PSTATE_BANK + PSTATE_BANK_COUNT)) ? 1 : 0;
|
|
int bank_flag = (is_ro ? EC_FLASH_PROTECT_RO_NOW :
|
|
EC_FLASH_PROTECT_ALL_NOW);
|
|
|
|
if (flash_physical_get_protect(i)) {
|
|
/* At least one bank in the region is protected */
|
|
flags |= bank_flag;
|
|
if (not_protected[is_ro])
|
|
flags |= EC_FLASH_PROTECT_ERROR_INCONSISTENT;
|
|
} else {
|
|
/* At least one bank in the region is NOT protected */
|
|
not_protected[is_ro] = 1;
|
|
if (flags & bank_flag)
|
|
flags |= EC_FLASH_PROTECT_ERROR_INCONSISTENT;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If the RW banks are protected but the RO banks aren't, that's
|
|
* inconsistent.
|
|
*
|
|
* Note that we check this before adding in the physical flags below,
|
|
* since some chips can also protect ALL_NOW for the current boot by
|
|
* locking up the flash program-erase registers.
|
|
*/
|
|
if ((flags & EC_FLASH_PROTECT_ALL_NOW) &&
|
|
!(flags & EC_FLASH_PROTECT_RO_NOW))
|
|
flags |= EC_FLASH_PROTECT_ERROR_INCONSISTENT;
|
|
|
|
/* Add in flags from physical layer */
|
|
return flags | flash_physical_get_protect_flags();
|
|
}
|
|
|
|
int flash_set_protect(uint32_t mask, uint32_t flags)
|
|
{
|
|
int retval = EC_SUCCESS;
|
|
int rv;
|
|
|
|
/*
|
|
* Process flags we can set. Track the most recent error, but process
|
|
* all flags before returning.
|
|
*/
|
|
if (mask & EC_FLASH_PROTECT_RO_AT_BOOT) {
|
|
rv = flash_protect_ro_at_boot(
|
|
flags & EC_FLASH_PROTECT_RO_AT_BOOT);
|
|
if (rv)
|
|
retval = rv;
|
|
}
|
|
|
|
/*
|
|
* All subsequent flags only work if write protect is enabled (that is,
|
|
* hardware WP flag) *and* RO is protected at boot (software WP flag).
|
|
*/
|
|
if ((~flash_get_protect()) & (EC_FLASH_PROTECT_GPIO_ASSERTED |
|
|
EC_FLASH_PROTECT_RO_AT_BOOT))
|
|
return retval;
|
|
|
|
if ((mask & EC_FLASH_PROTECT_RO_NOW) &&
|
|
(flags & EC_FLASH_PROTECT_RO_NOW)) {
|
|
rv = flash_physical_protect_now(0);
|
|
if (rv)
|
|
retval = rv;
|
|
}
|
|
|
|
if ((mask & EC_FLASH_PROTECT_ALL_NOW) &&
|
|
(flags & EC_FLASH_PROTECT_ALL_NOW)) {
|
|
rv = flash_physical_protect_now(1);
|
|
if (rv)
|
|
retval = rv;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* Console commands */
|
|
|
|
/**
|
|
* Parse offset and size from command line argv[shift] and argv[shift+1]
|
|
*
|
|
* Default values: If argc<=shift, leaves offset unchanged, returning error if
|
|
* *offset<0. If argc<shift+1, leaves size unchanged, returning error if
|
|
* *size<0.
|
|
*/
|
|
static int parse_offset_size(int argc, char **argv, int shift,
|
|
int *offset, int *size)
|
|
{
|
|
char *e;
|
|
int i;
|
|
|
|
if (argc > shift) {
|
|
i = (uint32_t)strtoi(argv[shift], &e, 0);
|
|
if (*e)
|
|
return EC_ERROR_PARAM1;
|
|
*offset = i;
|
|
} else if (*offset < 0)
|
|
return EC_ERROR_PARAM_COUNT;
|
|
|
|
if (argc > shift + 1) {
|
|
i = (uint32_t)strtoi(argv[shift + 1], &e, 0);
|
|
if (*e)
|
|
return EC_ERROR_PARAM2;
|
|
*size = i;
|
|
} else if (*size < 0)
|
|
return EC_ERROR_PARAM_COUNT;
|
|
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
static int command_flash_info(int argc, char **argv)
|
|
{
|
|
int i;
|
|
|
|
ccprintf("Physical:%4d KB\n", CONFIG_FLASH_PHYSICAL_SIZE / 1024);
|
|
ccprintf("Usable: %4d KB\n", CONFIG_FLASH_SIZE / 1024);
|
|
ccprintf("Write: %4d B (ideal %d B)\n", CONFIG_FLASH_WRITE_SIZE,
|
|
CONFIG_FLASH_WRITE_IDEAL_SIZE);
|
|
ccprintf("Erase: %4d B (to %d-bits)\n", CONFIG_FLASH_ERASE_SIZE,
|
|
CONFIG_FLASH_ERASED_VALUE32 ? 1 : 0);
|
|
ccprintf("Protect: %4d B\n", CONFIG_FLASH_BANK_SIZE);
|
|
|
|
i = flash_get_protect();
|
|
ccprintf("Flags: ");
|
|
if (i & EC_FLASH_PROTECT_GPIO_ASSERTED)
|
|
ccputs(" wp_gpio_asserted");
|
|
if (i & EC_FLASH_PROTECT_RO_AT_BOOT)
|
|
ccputs(" ro_at_boot");
|
|
if (i & EC_FLASH_PROTECT_ALL_AT_BOOT)
|
|
ccputs(" all_at_boot");
|
|
if (i & EC_FLASH_PROTECT_RO_NOW)
|
|
ccputs(" ro_now");
|
|
if (i & EC_FLASH_PROTECT_ALL_NOW)
|
|
ccputs(" all_now");
|
|
if (i & EC_FLASH_PROTECT_ERROR_STUCK)
|
|
ccputs(" STUCK");
|
|
if (i & EC_FLASH_PROTECT_ERROR_INCONSISTENT)
|
|
ccputs(" INCONSISTENT");
|
|
ccputs("\n");
|
|
|
|
ccputs("Protected now:");
|
|
for (i = 0; i < CONFIG_FLASH_PHYSICAL_SIZE / CONFIG_FLASH_BANK_SIZE;
|
|
i++) {
|
|
if (!(i & 31))
|
|
ccputs("\n ");
|
|
else if (!(i & 7))
|
|
ccputs(" ");
|
|
ccputs(flash_physical_get_protect(i) ? "Y" : ".");
|
|
}
|
|
ccputs("\n");
|
|
|
|
return EC_SUCCESS;
|
|
}
|
|
DECLARE_CONSOLE_COMMAND(flashinfo, command_flash_info,
|
|
NULL,
|
|
"Print flash info",
|
|
NULL);
|
|
|
|
static int command_flash_erase(int argc, char **argv)
|
|
{
|
|
int offset = -1;
|
|
int size = CONFIG_FLASH_ERASE_SIZE;
|
|
int rv;
|
|
|
|
if (flash_get_protect() & EC_FLASH_PROTECT_ALL_NOW)
|
|
return EC_ERROR_ACCESS_DENIED;
|
|
|
|
rv = parse_offset_size(argc, argv, 1, &offset, &size);
|
|
if (rv)
|
|
return rv;
|
|
|
|
ccprintf("Erasing %d bytes at 0x%x...\n", size, offset, offset);
|
|
return flash_erase(offset, size);
|
|
}
|
|
DECLARE_CONSOLE_COMMAND(flasherase, command_flash_erase,
|
|
"offset [size]",
|
|
"Erase flash",
|
|
NULL);
|
|
|
|
static int command_flash_write(int argc, char **argv)
|
|
{
|
|
int offset = -1;
|
|
int size = CONFIG_FLASH_ERASE_SIZE;
|
|
int rv;
|
|
char *data;
|
|
int i;
|
|
|
|
if (flash_get_protect() & EC_FLASH_PROTECT_ALL_NOW)
|
|
return EC_ERROR_ACCESS_DENIED;
|
|
|
|
rv = parse_offset_size(argc, argv, 1, &offset, &size);
|
|
if (rv)
|
|
return rv;
|
|
|
|
if (size > shared_mem_size())
|
|
size = shared_mem_size();
|
|
|
|
/* Acquire the shared memory buffer */
|
|
rv = shared_mem_acquire(size, &data);
|
|
if (rv) {
|
|
ccputs("Can't get shared mem\n");
|
|
return rv;
|
|
}
|
|
|
|
/* Fill the data buffer with a pattern */
|
|
for (i = 0; i < size; i++)
|
|
data[i] = i;
|
|
|
|
ccprintf("Writing %d bytes to 0x%x...\n",
|
|
size, offset, offset);
|
|
rv = flash_write(offset, size, data);
|
|
|
|
/* Free the buffer */
|
|
shared_mem_release(data);
|
|
|
|
return rv;
|
|
}
|
|
DECLARE_CONSOLE_COMMAND(flashwrite, command_flash_write,
|
|
"offset [size]",
|
|
"Write pattern to flash",
|
|
NULL);
|
|
|
|
static int command_flash_wp(int argc, char **argv)
|
|
{
|
|
if (argc < 2)
|
|
return EC_ERROR_PARAM_COUNT;
|
|
|
|
if (!strcasecmp(argv[1], "enable"))
|
|
return flash_set_protect(EC_FLASH_PROTECT_RO_AT_BOOT, -1);
|
|
else if (!strcasecmp(argv[1], "disable"))
|
|
return flash_set_protect(EC_FLASH_PROTECT_RO_AT_BOOT, 0);
|
|
else if (!strcasecmp(argv[1], "now"))
|
|
return flash_set_protect(EC_FLASH_PROTECT_ALL_NOW, -1);
|
|
else if (!strcasecmp(argv[1], "rw"))
|
|
return flash_set_protect(EC_FLASH_PROTECT_ALL_AT_BOOT, -1);
|
|
else if (!strcasecmp(argv[1], "norw"))
|
|
return flash_set_protect(EC_FLASH_PROTECT_ALL_AT_BOOT, 0);
|
|
else
|
|
return EC_ERROR_PARAM1;
|
|
}
|
|
DECLARE_CONSOLE_COMMAND(flashwp, command_flash_wp,
|
|
"<enable | disable | now | rw | norw>",
|
|
"Modify flash write protect",
|
|
NULL);
|
|
|
|
/*****************************************************************************/
|
|
/* Host commands */
|
|
|
|
static int flash_command_get_info(struct host_cmd_handler_args *args)
|
|
{
|
|
struct ec_response_flash_info_1 *r = args->response;
|
|
|
|
r->flash_size = CONFIG_FLASH_SIZE;
|
|
r->write_block_size = CONFIG_FLASH_WRITE_SIZE;
|
|
r->erase_block_size = CONFIG_FLASH_ERASE_SIZE;
|
|
r->protect_block_size = CONFIG_FLASH_BANK_SIZE;
|
|
|
|
if (args->version == 0) {
|
|
/* Only version 0 fields returned */
|
|
args->response_size = sizeof(struct ec_response_flash_info);
|
|
} else {
|
|
/* Fill in full version 1 struct */
|
|
|
|
/*
|
|
* Compute the ideal amount of data for the host to send us,
|
|
* based on the maximum response size and the ideal write size.
|
|
*/
|
|
r->write_ideal_size =
|
|
(args->response_max -
|
|
sizeof(struct ec_params_flash_write)) &
|
|
~(CONFIG_FLASH_WRITE_IDEAL_SIZE - 1);
|
|
/*
|
|
* If we can't get at least one ideal block, then just want
|
|
* as high a multiple of the minimum write size as possible.
|
|
*/
|
|
if (!r->write_ideal_size)
|
|
r->write_ideal_size =
|
|
(args->response_max -
|
|
sizeof(struct ec_params_flash_write)) &
|
|
~(CONFIG_FLASH_WRITE_SIZE - 1);
|
|
|
|
r->flags = 0;
|
|
|
|
#if (CONFIG_FLASH_ERASED_VALUE32 == 0)
|
|
r->flags |= EC_FLASH_INFO_ERASE_TO_0;
|
|
#endif
|
|
|
|
args->response_size = sizeof(*r);
|
|
}
|
|
return EC_RES_SUCCESS;
|
|
}
|
|
DECLARE_HOST_COMMAND(EC_CMD_FLASH_INFO,
|
|
flash_command_get_info,
|
|
EC_VER_MASK(0) | EC_VER_MASK(1));
|
|
|
|
static int flash_command_read(struct host_cmd_handler_args *args)
|
|
{
|
|
const struct ec_params_flash_read *p = args->params;
|
|
const char *src;
|
|
|
|
if (flash_dataptr(p->offset, p->size, 1, &src) < 0)
|
|
return EC_RES_ERROR;
|
|
|
|
if (p->size > args->response_max)
|
|
return EC_RES_OVERFLOW;
|
|
|
|
memcpy(args->response, src, p->size);
|
|
args->response_size = p->size;
|
|
|
|
return EC_RES_SUCCESS;
|
|
}
|
|
DECLARE_HOST_COMMAND(EC_CMD_FLASH_READ,
|
|
flash_command_read,
|
|
EC_VER_MASK(0));
|
|
|
|
/**
|
|
* Flash write command
|
|
*
|
|
* Version 0 and 1 are equivalent from the EC-side; the only difference is
|
|
* that the host can only send 64 bytes of data at a time in version 0.
|
|
*/
|
|
static int flash_command_write(struct host_cmd_handler_args *args)
|
|
{
|
|
const struct ec_params_flash_write *p = args->params;
|
|
|
|
if (flash_get_protect() & EC_FLASH_PROTECT_ALL_NOW)
|
|
return EC_RES_ACCESS_DENIED;
|
|
|
|
if (p->size + sizeof(*p) > args->params_size)
|
|
return EC_RES_INVALID_PARAM;
|
|
|
|
if (system_unsafe_to_overwrite(p->offset, p->size))
|
|
return EC_RES_ACCESS_DENIED;
|
|
|
|
if (flash_write(p->offset, p->size, (const uint8_t *)(p + 1)))
|
|
return EC_RES_ERROR;
|
|
|
|
return EC_RES_SUCCESS;
|
|
}
|
|
DECLARE_HOST_COMMAND(EC_CMD_FLASH_WRITE,
|
|
flash_command_write,
|
|
EC_VER_MASK(0) | EC_VER_MASK(EC_VER_FLASH_WRITE));
|
|
|
|
static int flash_command_erase(struct host_cmd_handler_args *args)
|
|
{
|
|
const struct ec_params_flash_erase *p = args->params;
|
|
|
|
if (flash_get_protect() & EC_FLASH_PROTECT_ALL_NOW)
|
|
return EC_RES_ACCESS_DENIED;
|
|
|
|
if (system_unsafe_to_overwrite(p->offset, p->size))
|
|
return EC_RES_ACCESS_DENIED;
|
|
|
|
/* Indicate that we might be a while */
|
|
#if defined(HAS_TASK_HOSTCMD) && defined(CONFIG_HOST_COMMAND_STATUS)
|
|
args->result = EC_RES_IN_PROGRESS;
|
|
host_send_response(args);
|
|
#endif
|
|
if (flash_erase(p->offset, p->size))
|
|
return EC_RES_ERROR;
|
|
|
|
return EC_RES_SUCCESS;
|
|
}
|
|
DECLARE_HOST_COMMAND(EC_CMD_FLASH_ERASE,
|
|
flash_command_erase,
|
|
EC_VER_MASK(0));
|
|
|
|
static int flash_command_protect(struct host_cmd_handler_args *args)
|
|
{
|
|
const struct ec_params_flash_protect *p = args->params;
|
|
struct ec_response_flash_protect *r = args->response;
|
|
|
|
/*
|
|
* Handle requesting new flags. Note that we ignore the return code
|
|
* from flash_set_protect(), since errors will be visible to the caller
|
|
* via the flags in the response. (If we returned error, the caller
|
|
* wouldn't get the response.)
|
|
*/
|
|
if (p->mask)
|
|
flash_set_protect(p->mask, p->flags);
|
|
|
|
/*
|
|
* Retrieve the current flags. The caller can use this to determine
|
|
* which of the requested flags could be set. This is cleaner than
|
|
* simply returning error, because it provides information to the
|
|
* caller about the actual result.
|
|
*/
|
|
r->flags = flash_get_protect();
|
|
|
|
/* Indicate which flags are valid on this platform */
|
|
r->valid_flags =
|
|
EC_FLASH_PROTECT_GPIO_ASSERTED |
|
|
EC_FLASH_PROTECT_ERROR_STUCK |
|
|
EC_FLASH_PROTECT_RO_AT_BOOT |
|
|
EC_FLASH_PROTECT_RO_NOW |
|
|
EC_FLASH_PROTECT_ALL_NOW |
|
|
EC_FLASH_PROTECT_ERROR_INCONSISTENT;
|
|
r->writable_flags = 0;
|
|
|
|
/* If RO protection isn't enabled, its at-boot state can be changed. */
|
|
if (!(r->flags & EC_FLASH_PROTECT_RO_NOW))
|
|
r->writable_flags |= EC_FLASH_PROTECT_RO_AT_BOOT;
|
|
|
|
#ifdef CHIP_FAMILY_STM32F
|
|
/*
|
|
* TODO(crosbug.com/p/23762): Should ignore all-now on STM32F if WP
|
|
* isn't asserted. We don't do this due to limitations in early snow
|
|
* boards (lack of WP GPIO?) - in which case, this can either be
|
|
* restricted to BOARD_SNOW, or removed entirely.
|
|
*/
|
|
r->valid_flags |= EC_FLASH_PROTECT_ALL_NOW;
|
|
r->writable_flags |= EC_FLASH_PROTECT_ALL_NOW;
|
|
#else
|
|
/*
|
|
* If entire flash isn't protected at this boot, it can be enabled if
|
|
* the WP GPIO is asserted.
|
|
*/
|
|
if (!(r->flags & EC_FLASH_PROTECT_ALL_NOW) &&
|
|
(r->flags & EC_FLASH_PROTECT_GPIO_ASSERTED))
|
|
r->writable_flags |= EC_FLASH_PROTECT_ALL_NOW;
|
|
#endif
|
|
|
|
args->response_size = sizeof(*r);
|
|
|
|
return EC_RES_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* TODO(crbug.com/239197) : Adding both versions to the version mask is a
|
|
* temporary workaround for a problem in the cros_ec driver. Drop
|
|
* EC_VER_MASK(0) once cros_ec driver can send the correct version.
|
|
*/
|
|
DECLARE_HOST_COMMAND(EC_CMD_FLASH_PROTECT,
|
|
flash_command_protect,
|
|
EC_VER_MASK(0) | EC_VER_MASK(1));
|
|
|
|
static int flash_command_region_info(struct host_cmd_handler_args *args)
|
|
{
|
|
const struct ec_params_flash_region_info *p = args->params;
|
|
struct ec_response_flash_region_info *r = args->response;
|
|
|
|
switch (p->region) {
|
|
case EC_FLASH_REGION_RO:
|
|
r->offset = CONFIG_FW_RO_OFF;
|
|
r->size = CONFIG_FW_RO_SIZE;
|
|
break;
|
|
case EC_FLASH_REGION_RW:
|
|
r->offset = CONFIG_FW_RW_OFF;
|
|
r->size = CONFIG_FW_RW_SIZE;
|
|
break;
|
|
case EC_FLASH_REGION_WP_RO:
|
|
r->offset = CONFIG_FW_WP_RO_OFF;
|
|
r->size = CONFIG_FW_WP_RO_SIZE;
|
|
break;
|
|
default:
|
|
return EC_RES_INVALID_PARAM;
|
|
}
|
|
|
|
args->response_size = sizeof(*r);
|
|
return EC_RES_SUCCESS;
|
|
}
|
|
DECLARE_HOST_COMMAND(EC_CMD_FLASH_REGION_INFO,
|
|
flash_command_region_info,
|
|
EC_VER_MASK(EC_VER_FLASH_REGION_INFO));
|