summaryrefslogtreecommitdiff
path: root/common/flash.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/flash.c')
-rw-r--r--common/flash.c1562
1 files changed, 0 insertions, 1562 deletions
diff --git a/common/flash.c b/common/flash.c
deleted file mode 100644
index c8f58a82af..0000000000
--- a/common/flash.c
+++ /dev/null
@@ -1,1562 +0,0 @@
-/* Copyright 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 "cros_board_info.h"
-#include "flash.h"
-#include "gpio.h"
-#include "hooks.h"
-#include "host_command.h"
-#include "otp.h"
-#include "rwsig.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
-
-#ifdef CONFIG_FLASH_PSTATE
-
-/*
- * If flash isn't mapped to the EC's address space, it's probably SPI, and
- * should be using SPI write protect, not PSTATE.
- */
-#if !defined(CONFIG_INTERNAL_STORAGE) || !defined(CONFIG_MAPPED_STORAGE)
-#error "PSTATE should only be used with internal mem-mapped flash."
-#endif
-
-#ifdef CONFIG_FLASH_PSTATE_BANK
-/* Persistent protection state - emulates a SPI status register for flashrom */
-/* NOTE: It's not expected that RO and RW will support
- * differing PSTATE versions. */
-#define PERSIST_STATE_VERSION 3 /* Expected persist_state.version */
-
-/* Flags for persist_state.flags */
-/* Protect persist state and RO firmware at boot */
-#define PERSIST_FLAG_PROTECT_RO 0x02
-#define PSTATE_VALID_FLAGS BIT(0)
-#define PSTATE_VALID_SERIALNO BIT(1)
-#define PSTATE_VALID_MAC_ADDR BIT(2)
-
-struct persist_state {
- uint8_t version; /* Version of this struct */
- uint8_t flags; /* Lock flags (PERSIST_FLAG_*) */
- uint8_t valid_fields; /* Flags for valid data. */
- uint8_t reserved; /* Reserved; set 0 */
-#ifdef CONFIG_SERIALNO_LEN
- uint8_t serialno[CONFIG_SERIALNO_LEN]; /* Serial number. */
-#endif /* CONFIG_SERIALNO_LEN */
-#ifdef CONFIG_MAC_ADDR_LEN
- uint8_t mac_addr[CONFIG_MAC_ADDR_LEN];
-#endif /* CONFIG_MAC_ADDR_LEN */
-#if !defined(CONFIG_SERIALNO_LEN) && !defined(CONFIG_MAC_ADDR_LEN)
- uint8_t padding[4 % CONFIG_FLASH_WRITE_SIZE];
-#endif
-};
-
-/* written with flash_physical_write, need to respect alignment constraints */
-#ifndef CHIP_FAMILY_STM32L /* STM32L1xx is somewhat lying to us */
-BUILD_ASSERT(sizeof(struct persist_state) % CONFIG_FLASH_WRITE_SIZE == 0);
-#endif
-
-BUILD_ASSERT(sizeof(struct persist_state) <= CONFIG_FW_PSTATE_SIZE);
-
-#else /* !CONFIG_FLASH_PSTATE_BANK */
-
-/*
- * Flags for write protect state depend on the erased value of flash. The
- * locked value must be the same as the unlocked value with one or more bits
- * transitioned away from the erased state. That way, it is possible to
- * rewrite the data in-place to set the lock.
- *
- * STM32F0x can only write 0x0000 to a non-erased half-word, which means
- * PSTATE_MAGIC_LOCKED isn't quite as pretty. That's ok; the only thing
- * we actually need to detect is PSTATE_MAGIC_UNLOCKED, since that's the
- * only value we'll ever alter, and the only value which causes us not to
- * lock the flash at boot.
- */
-#if (CONFIG_FLASH_ERASED_VALUE32 == -1U)
-#define PSTATE_MAGIC_UNLOCKED 0x4f4e5057 /* "WPNO" */
-#define PSTATE_MAGIC_LOCKED 0x00000000 /* "" */
-#elif (CONFIG_FLASH_ERASED_VALUE32 == 0)
-#define PSTATE_MAGIC_UNLOCKED 0x4f4e5057 /* "WPNO" */
-#define PSTATE_MAGIC_LOCKED 0x5f5f5057 /* "WP__" */
-#else
-/* What kind of wacky flash doesn't erase all bits to 1 or 0? */
-#error "PSTATE needs magic values for this flash architecture."
-#endif
-
-/*
- * Rewriting the write protect flag in place currently requires a minimum write
- * size <= the size of the flag value.
- *
- * We could work around this on chips with larger minimum write size by reading
- * the write block containing the flag into RAM, changing it to the locked
- * value, and then rewriting that block. But we should only pay for that
- * complexity when we run across another chip which needs it.
- */
-#if (CONFIG_FLASH_WRITE_SIZE > 4)
-#error "Non-bank-based PSTATE requires flash write size <= 32 bits."
-#endif
-
-const uint32_t pstate_data __attribute__((section(".rodata.pstate"))) =
-#ifdef CONFIG_FLASH_PSTATE_LOCKED
- PSTATE_MAGIC_LOCKED;
-#else
- PSTATE_MAGIC_UNLOCKED;
-#endif
-
-#endif /* !CONFIG_FLASH_PSTATE_BANK */
-#endif /* CONFIG_FLASH_PSTATE */
-
-#ifdef CONFIG_FLASH_MULTIPLE_REGION
-const struct ec_flash_bank *flash_bank_info(int bank)
-{
- int i;
- for (i = 0; i < ARRAY_SIZE(flash_bank_array); i++) {
- if (bank < flash_bank_array[i].count)
- return &flash_bank_array[i];
- bank -= flash_bank_array[i].count;
- }
-
- return NULL;
-}
-
-int crec_flash_bank_size(int bank)
-{
- int rv;
- const struct ec_flash_bank *info = flash_bank_info(bank);
-
- if (!info)
- return -1;
-
- rv = BIT(info->size_exp);
- ASSERT(rv > 0);
- return rv;
-}
-
-int crec_flash_bank_erase_size(int bank)
-{
- int rv;
- const struct ec_flash_bank *info = flash_bank_info(bank);
-
- if (!info)
- return -1;
-
- rv = BIT(info->erase_size_exp);
- ASSERT(rv > 0);
- return rv;
-}
-
-int crec_flash_bank_index(int offset)
-{
- int bank_offset = 0, i;
-
- if (offset == 0)
- return bank_offset;
-
- for (i = 0; i < ARRAY_SIZE(flash_bank_array); i++) {
- int all_sector_size = flash_bank_array[i].count <<
- flash_bank_array[i].size_exp;
- if (offset >= all_sector_size) {
- offset -= all_sector_size;
- bank_offset += flash_bank_array[i].count;
- continue;
- }
- if (offset & ((1 << flash_bank_array[i].size_exp) - 1))
- return -1;
- return bank_offset + (offset >> flash_bank_array[i].size_exp);
- }
- if (offset != 0)
- return -1;
- return bank_offset;
-}
-
-int crec_flash_bank_count(int offset, int size)
-{
- int begin = crec_flash_bank_index(offset);
- int end = crec_flash_bank_index(offset + size);
-
- if (begin == -1 || end == -1)
- return -1;
- return end - begin;
-}
-
-int crec_flash_bank_start_offset(int bank)
-{
- int i;
- int offset;
- int bank_size;
-
- if (bank < 0)
- return -1;
-
- offset = 0;
- for (i = 0; i < bank; i++) {
- bank_size = crec_flash_bank_size(i);
- if (bank_size < 0)
- return -1;
- offset += bank_size;
- }
-
- return offset;
-}
-
-#endif /* CONFIG_FLASH_MULTIPLE_REGION */
-
-static int flash_range_ok(int offset, int size_req, int align)
-{
- if (offset < 0 || size_req < 0 ||
- offset > CONFIG_FLASH_SIZE_BYTES ||
- size_req > CONFIG_FLASH_SIZE_BYTES ||
- offset + size_req > CONFIG_FLASH_SIZE_BYTES ||
- (offset | size_req) & (align - 1))
- return 0; /* Invalid range */
-
- return 1;
-}
-
-#ifdef CONFIG_MAPPED_STORAGE
-/**
- * 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_MAPPED_STORAGE_BASE + offset);
-}
-
-int crec_flash_dataptr(int offset, int size_req, int align, const char **ptrp)
-{
- if (!flash_range_ok(offset, size_req, align))
- return -1; /* Invalid range */
- if (ptrp)
- *ptrp = flash_physical_dataptr(offset);
-
- return CONFIG_FLASH_SIZE_BYTES - offset;
-}
-#endif
-
-#ifdef CONFIG_FLASH_PSTATE
-#ifdef CONFIG_FLASH_PSTATE_BANK
-
-/**
- * Read and return persistent state flags (EC_FLASH_PROTECT_*)
- */
-static uint32_t flash_read_pstate(void)
-{
- const struct persist_state *pstate =
- (const struct persist_state *)
- flash_physical_dataptr(CONFIG_FW_PSTATE_OFF);
-
- if ((pstate->version == PERSIST_STATE_VERSION) &&
- (pstate->valid_fields & PSTATE_VALID_FLAGS) &&
- (pstate->flags & PERSIST_FLAG_PROTECT_RO)) {
- /* Lock flag is known to be set */
- return EC_FLASH_PROTECT_RO_AT_BOOT;
- } else {
-#ifdef CONFIG_WP_ALWAYS
- return PERSIST_FLAG_PROTECT_RO;
-#else
- return 0;
-#endif
- }
-}
-
-/**
- * Write persistent state after erasing.
- *
- * @param pstate New data to set in pstate. NOT memory mapped
- * old pstate as it will be erased.
- * @return EC_SUCCESS, or nonzero if error.
- */
-static int flash_write_pstate_data(struct persist_state *newpstate)
-{
- int rv;
-
- /* Erase pstate */
- rv = crec_flash_physical_erase(CONFIG_FW_PSTATE_OFF,
- CONFIG_FW_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.
- */
-
- /* Write the updated pstate */
- return crec_flash_physical_write(CONFIG_FW_PSTATE_OFF,
- sizeof(*newpstate),
- (const char *)newpstate);
-}
-
-
-
-/**
- * Validate and Init persistent state datastructure.
- *
- * @param pstate A pstate data structure. Will be valid at complete.
- * @return EC_SUCCESS, or nonzero if error.
- */
-static int validate_pstate_struct(struct persist_state *pstate)
-{
- if (pstate->version != PERSIST_STATE_VERSION) {
- memset(pstate, 0, sizeof(*pstate));
- pstate->version = PERSIST_STATE_VERSION;
- }
-
- return EC_SUCCESS;
-}
-
-/**
- * Write persistent state from pstate, erasing if necessary.
- *
- * @param flags New flash write protect flags to set in pstate.
- * @return EC_SUCCESS, or nonzero if error.
- */
-static int flash_write_pstate(uint32_t flags)
-{
- struct persist_state newpstate;
- const struct persist_state *pstate =
- (const struct persist_state *)
- flash_physical_dataptr(CONFIG_FW_PSTATE_OFF);
-
- /* Only check the flags we write to pstate */
- flags &= EC_FLASH_PROTECT_RO_AT_BOOT;
-
- /* Check if pstate has actually changed */
- if (flags == flash_read_pstate())
- return EC_SUCCESS;
-
- /* Cache the old copy for read/modify/write. */
- memcpy(&newpstate, pstate, sizeof(newpstate));
- validate_pstate_struct(&newpstate);
-
- if (flags & EC_FLASH_PROTECT_RO_AT_BOOT)
- newpstate.flags |= PERSIST_FLAG_PROTECT_RO;
- else
- newpstate.flags &= ~PERSIST_FLAG_PROTECT_RO;
- newpstate.valid_fields |= PSTATE_VALID_FLAGS;
-
- return flash_write_pstate_data(&newpstate);
-}
-
-#ifdef CONFIG_SERIALNO_LEN
-/**
- * Read and return persistent serial number.
- */
-const char *crec_flash_read_pstate_serial(void)
-{
- const struct persist_state *pstate =
- (const struct persist_state *)
- flash_physical_dataptr(CONFIG_FW_PSTATE_OFF);
-
- if ((pstate->version == PERSIST_STATE_VERSION) &&
- (pstate->valid_fields & PSTATE_VALID_SERIALNO)) {
- return (const char *)(pstate->serialno);
- }
-
- return NULL;
-}
-
-/**
- * Write persistent serial number to pstate, erasing if necessary.
- *
- * @param serialno New ascii serial number to set in pstate.
- * @return EC_SUCCESS, or nonzero if error.
- */
-int crec_flash_write_pstate_serial(const char *serialno)
-{
- int length;
- struct persist_state newpstate;
- const struct persist_state *pstate =
- (const struct persist_state *)
- flash_physical_dataptr(CONFIG_FW_PSTATE_OFF);
-
- /* Check that this is OK */
- if (!serialno)
- return EC_ERROR_INVAL;
-
- length = strnlen(serialno, sizeof(newpstate.serialno));
- if (length >= sizeof(newpstate.serialno)) {
- return EC_ERROR_INVAL;
- }
-
- /* Cache the old copy for read/modify/write. */
- memcpy(&newpstate, pstate, sizeof(newpstate));
- validate_pstate_struct(&newpstate);
-
- /*
- * Erase any prior data and copy the string. The length was verified to
- * be shorter than the buffer so a null terminator always remains.
- */
- memset(newpstate.serialno, '\0', sizeof(newpstate.serialno));
- memcpy(newpstate.serialno, serialno, length);
-
- newpstate.valid_fields |= PSTATE_VALID_SERIALNO;
-
- return flash_write_pstate_data(&newpstate);
-}
-
-#endif /* CONFIG_SERIALNO_LEN */
-
-#ifdef CONFIG_MAC_ADDR_LEN
-
-/**
- * Read and return persistent MAC address.
- */
-const char *crec_flash_read_pstate_mac_addr(void)
-{
- const struct persist_state *pstate =
- (const struct persist_state *)
- flash_physical_dataptr(CONFIG_FW_PSTATE_OFF);
-
- if ((pstate->version == PERSIST_STATE_VERSION) &&
- (pstate->valid_fields & PSTATE_VALID_MAC_ADDR)) {
- return (const char *)(pstate->mac_addr);
- }
-
- return NULL;
-}
-
-/**
- * Write persistent MAC Addr to pstate, erasing if necessary.
- *
- * @param mac_addr New ascii MAC address to set in pstate.
- * @return EC_SUCCESS, or nonzero if error.
- */
-int crec_flash_write_pstate_mac_addr(const char *mac_addr)
-{
- int length;
- struct persist_state newpstate;
- const struct persist_state *pstate =
- (const struct persist_state *)
- flash_physical_dataptr(CONFIG_FW_PSTATE_OFF);
-
- /* Check that this is OK, data is valid and fits in the region. */
- if (!mac_addr) {
- return EC_ERROR_INVAL;
- }
-
- /*
- * This will perform validation of the mac address before storing it.
- * The MAC address format is '12:34:56:78:90:AB', a 17 character long
- * string containing pairs of hex digits, each pair delimited by a ':'.
- */
- length = strnlen(mac_addr, sizeof(newpstate.mac_addr));
- if (length != 17) {
- return EC_ERROR_INVAL;
- }
- for (int i = 0; i < 17; i++) {
- if (i % 3 != 2) {
- /* Verify the remaining characters are hex digits. */
- if ((mac_addr[i] < '0' || '9' < mac_addr[i]) &&
- (mac_addr[i] < 'A' || 'F' < mac_addr[i]) &&
- (mac_addr[i] < 'a' || 'f' < mac_addr[i])) {
- return EC_ERROR_INVAL;
- }
- } else {
- /* Every 3rd character is a ':' */
- if (mac_addr[i] != ':') {
- return EC_ERROR_INVAL;
- }
- }
- }
-
- /* Cache the old copy for read/modify/write. */
- memcpy(&newpstate, pstate, sizeof(newpstate));
- validate_pstate_struct(&newpstate);
-
- /*
- * Erase any prior data and copy the string. The length was verified to
- * be shorter than the buffer so a null terminator always remains.
- */
- memset(newpstate.mac_addr, '\0', sizeof(newpstate.mac_addr));
- memcpy(newpstate.mac_addr, mac_addr, length);
-
- newpstate.valid_fields |= PSTATE_VALID_MAC_ADDR;
-
- return flash_write_pstate_data(&newpstate);
-}
-
-#endif /* CONFIG_MAC_ADDR_LEN */
-
-#else /* !CONFIG_FLASH_PSTATE_BANK */
-
-/**
- * Return the address of the pstate data in EC-RO.
- */
-static const uintptr_t get_pstate_addr(void)
-{
- uintptr_t addr = (uintptr_t)&pstate_data;
-
- /* Always use the pstate data in RO, even if we're RW */
- if (system_is_in_rw())
- addr += CONFIG_RO_MEM_OFF - CONFIG_RW_MEM_OFF;
-
- return addr;
-}
-
-/**
- * Read and return persistent state flags (EC_FLASH_PROTECT_*)
- */
-static uint32_t flash_read_pstate(void)
-{
- /* Check for the unlocked magic value */
- if (*(const uint32_t *)get_pstate_addr() == PSTATE_MAGIC_UNLOCKED)
- return 0;
-
- /* Anything else is locked */
- return EC_FLASH_PROTECT_RO_AT_BOOT;
-}
-
-/**
- * Write persistent state from pstate, erasing if necessary.
- *
- * @param flags New flash write protect flags to set in pstate.
- * @return EC_SUCCESS, or nonzero if error.
- */
-static int flash_write_pstate(uint32_t flags)
-{
- const uint32_t new_pstate = PSTATE_MAGIC_LOCKED;
-
- /* Only check the flags we write to pstate */
- flags &= EC_FLASH_PROTECT_RO_AT_BOOT;
-
- /* Check if pstate has actually changed */
- if (flags == flash_read_pstate())
- return EC_SUCCESS;
-
- /* We can only set the protect flag, not clear it */
- if (!(flags & EC_FLASH_PROTECT_RO_AT_BOOT))
- return EC_ERROR_ACCESS_DENIED;
-
- /*
- * Write a new pstate. We can overwrite the existing value, because
- * we're only moving bits from the erased state to the unerased state.
- */
- return crec_flash_physical_write(get_pstate_addr() -
- CONFIG_PROGRAM_MEMORY_BASE,
- sizeof(new_pstate),
- (const char *)&new_pstate);
-}
-
-#endif /* !CONFIG_FLASH_PSTATE_BANK */
-#endif /* CONFIG_FLASH_PSTATE */
-
-int crec_flash_is_erased(uint32_t offset, int size)
-{
- const uint32_t *ptr;
-
-#ifdef CONFIG_MAPPED_STORAGE
- /* Use pointer directly to flash */
- if (crec_flash_dataptr(offset, size, sizeof(uint32_t),
- (const char **)&ptr) < 0)
- return 0;
-
- crec_flash_lock_mapped_storage(1);
- for (size /= sizeof(uint32_t); size > 0; size--, ptr++)
- if (*ptr != CONFIG_FLASH_ERASED_VALUE32) {
- crec_flash_lock_mapped_storage(0);
- return 0;
- }
-
- crec_flash_lock_mapped_storage(0);
-#else
- /* Read flash a chunk at a time */
- uint32_t buf[8];
- int bsize;
-
- while (size) {
- bsize = MIN(size, sizeof(buf));
-
- if (crec_flash_read(offset, bsize, (char *)buf))
- return 0;
-
- size -= bsize;
- offset += bsize;
-
- ptr = buf;
- for (bsize /= sizeof(uint32_t); bsize > 0; bsize--, ptr++)
- if (*ptr != CONFIG_FLASH_ERASED_VALUE32)
- return 0;
-
- }
-#endif
-
- return 1;
-}
-
-int crec_flash_read(int offset, int size, char *data)
-{
-#ifdef CONFIG_MAPPED_STORAGE
- const char *src;
-
- if (crec_flash_dataptr(offset, size, 1, &src) < 0)
- return EC_ERROR_INVAL;
-
- crec_flash_lock_mapped_storage(1);
- memcpy(data, src, size);
- crec_flash_lock_mapped_storage(0);
- return EC_SUCCESS;
-#else
- return crec_flash_physical_read(offset, size, data);
-#endif
-}
-
-static void flash_abort_or_invalidate_hash(int offset, int size)
-{
-#ifdef CONFIG_VBOOT_HASH
- if (vboot_hash_in_progress()) {
- /* Abort hash calculation when flash update is in progress. */
- vboot_hash_abort();
- return;
- }
-
-#ifdef CONFIG_EXTERNAL_STORAGE
- /*
- * If EC executes in RAM and is currently in RW, we keep the current
- * hash. On the next hash check, AP will catch hash mismatch between the
- * flash copy and the RAM copy, then take necessary actions.
- */
- if (system_is_in_rw())
- return;
-#endif
-
- /* If EC executes in place, we need to invalidate the cached hash. */
- vboot_hash_invalidate(offset, size);
-#endif
-
-#ifdef HAS_TASK_RWSIG
- /*
- * If RW flash has been written to, make sure we do not automatically
- * jump to RW after the timeout.
- */
- if ((offset >= CONFIG_RW_MEM_OFF &&
- offset < (CONFIG_RW_MEM_OFF + CONFIG_RW_SIZE)) ||
- ((offset + size) > CONFIG_RW_MEM_OFF &&
- (offset + size) <= (CONFIG_RW_MEM_OFF + CONFIG_RW_SIZE)) ||
- (offset < CONFIG_RW_MEM_OFF &&
- (offset + size) > (CONFIG_RW_MEM_OFF + CONFIG_RW_SIZE)))
- rwsig_abort();
-#endif
-}
-
-int crec_flash_write(int offset, int size, const char *data)
-{
- if (!flash_range_ok(offset, size, CONFIG_FLASH_WRITE_SIZE))
- return EC_ERROR_INVAL; /* Invalid range */
-
- flash_abort_or_invalidate_hash(offset, size);
-
- return crec_flash_physical_write(offset, size, data);
-}
-
-int crec_flash_erase(int offset, int size)
-{
-#ifndef CONFIG_FLASH_MULTIPLE_REGION
- if (!flash_range_ok(offset, size, CONFIG_FLASH_ERASE_SIZE))
- return EC_ERROR_INVAL; /* Invalid range */
-#endif
-
- flash_abort_or_invalidate_hash(offset, size);
-
- return crec_flash_physical_erase(offset, size);
-}
-
-int crec_flash_protect_at_boot(uint32_t new_flags)
-{
-#ifdef CONFIG_FLASH_PSTATE
- uint32_t new_pstate_flags = new_flags & EC_FLASH_PROTECT_RO_AT_BOOT;
-
- /* Read the current persist state from flash */
- if (flash_read_pstate() != new_pstate_flags) {
- /* Need to update pstate */
- int rv;
-
-#ifdef CONFIG_FLASH_PSTATE_BANK
- /* Fail if write protect block is already locked */
- if (crec_flash_physical_get_protect(PSTATE_BANK))
- return EC_ERROR_ACCESS_DENIED;
-#endif
-
- /* Write the desired flags */
- rv = flash_write_pstate(new_pstate_flags);
- 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).
- */
- crec_flash_physical_protect_at_boot(new_flags);
-#endif
-
- return EC_SUCCESS;
-#else
- return crec_flash_physical_protect_at_boot(new_flags);
-#endif
-}
-
-uint32_t crec_flash_get_protect(void)
-{
- uint32_t flags = 0;
- int i;
- /* Region protection status */
- int not_protected[FLASH_REGION_COUNT] = {0};
-#ifdef CONFIG_ROLLBACK
- /* Flags that must be set to set ALL_NOW flag. */
- const uint32_t all_flags = EC_FLASH_PROTECT_RO_NOW |
- EC_FLASH_PROTECT_RW_NOW |
- EC_FLASH_PROTECT_ROLLBACK_NOW;
-#else
- const uint32_t all_flags = EC_FLASH_PROTECT_RO_NOW |
- EC_FLASH_PROTECT_RW_NOW;
-#endif
-
- /* Read write protect GPIO */
-#ifdef CONFIG_WP_ALWAYS
- flags |= EC_FLASH_PROTECT_GPIO_ASSERTED;
-#elif defined(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
-
-#ifdef CONFIG_FLASH_PSTATE
- /* Read persistent state of RO-at-boot flag */
- flags |= flash_read_pstate();
-#endif
-
- /* Scan flash protection */
- for (i = 0; i < PHYSICAL_BANKS; i++) {
- int is_ro = (i >= WP_BANK_OFFSET &&
- i < WP_BANK_OFFSET + WP_BANK_COUNT);
- enum flash_region region = is_ro ? FLASH_REGION_RO :
- FLASH_REGION_RW;
- int bank_flag = is_ro ? EC_FLASH_PROTECT_RO_NOW :
- EC_FLASH_PROTECT_RW_NOW;
-
-#ifdef CONFIG_ROLLBACK
- if (i >= ROLLBACK_BANK_OFFSET &&
- i < ROLLBACK_BANK_OFFSET + ROLLBACK_BANK_COUNT) {
- region = FLASH_REGION_ROLLBACK;
- bank_flag = EC_FLASH_PROTECT_ROLLBACK_NOW;
- }
-#endif
-
- if (crec_flash_physical_get_protect(i)) {
- /* At least one bank in the region is protected */
- flags |= bank_flag;
- if (not_protected[region])
- flags |= EC_FLASH_PROTECT_ERROR_INCONSISTENT;
- } else {
- /* At least one bank in the region is NOT protected */
- not_protected[region] = 1;
- if (flags & bank_flag)
- flags |= EC_FLASH_PROTECT_ERROR_INCONSISTENT;
- }
- }
-
- if ((flags & all_flags) == all_flags)
- flags |= EC_FLASH_PROTECT_ALL_NOW;
-
- /*
- * If the RW or ROLLBACK 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 & all_flags) && !(flags & EC_FLASH_PROTECT_RO_NOW))
- flags |= EC_FLASH_PROTECT_ERROR_INCONSISTENT;
-
-#ifndef CONFIG_FLASH_PROTECT_RW
- /* RW flag was used for intermediate computations, clear it now. */
- flags &= ~EC_FLASH_PROTECT_RW_NOW;
-#endif
-
- /* Add in flags from physical layer */
- return flags | crec_flash_physical_get_protect_flags();
-}
-
-/*
- * Request a flash protection flags change for |mask| flash protect flags
- * to |flags| state.
- *
- * Order of flag processing:
- * 1. Clear/Set RO_AT_BOOT + Clear *_AT_BOOT flags + Commit *_AT_BOOT flags.
- * 2. Return if RO_AT_BOOT and HW-WP are not asserted.
- * 3. Set remaining *_AT_BOOT flags + Commit *_AT_BOOT flags.
- * 4. Commit RO_NOW.
- * 5. Commit ALL_NOW.
- */
-int crec_flash_set_protect(uint32_t mask, uint32_t flags)
-{
- int retval = EC_SUCCESS;
- int rv;
- int old_flags_at_boot = crec_flash_get_protect() &
- (EC_FLASH_PROTECT_RO_AT_BOOT | EC_FLASH_PROTECT_RW_AT_BOOT |
- EC_FLASH_PROTECT_ROLLBACK_AT_BOOT |
- EC_FLASH_PROTECT_ALL_AT_BOOT);
- int new_flags_at_boot = old_flags_at_boot;
-
- /* Sanitize input flags */
- flags = flags & mask;
-
- /*
- * Process flags we can set. Track the most recent error, but process
- * all flags before returning.
- */
-
- /*
- * AT_BOOT flags are trickier than NOW flags, as they can be set
- * when HW write protection is disabled and can be unset without
- * a reboot.
- *
- * If we are only setting/clearing RO_AT_BOOT, things are simple.
- * Setting ALL_AT_BOOT is processed only if HW write protection is
- * enabled and RO_AT_BOOT is set, so it's also simple.
- *
- * The most tricky one is when we want to clear ALL_AT_BOOT. We need
- * to determine whether to clear protection for the entire flash or
- * leave RO protected. There are two cases that we want to keep RO
- * protected:
- * A. RO_AT_BOOT was already set before flash_set_protect() is
- * called.
- * B. RO_AT_BOOT was not set, but it's requested to be set by
- * the caller of flash_set_protect().
- */
-
- /* 1.a - Clear RO_AT_BOOT. */
- new_flags_at_boot &= ~(mask & EC_FLASH_PROTECT_RO_AT_BOOT);
- /* 1.b - Set RO_AT_BOOT. */
- new_flags_at_boot |= flags & EC_FLASH_PROTECT_RO_AT_BOOT;
-
- /* 1.c - Clear ALL_AT_BOOT. */
- if ((mask & EC_FLASH_PROTECT_ALL_AT_BOOT) &&
- !(flags & EC_FLASH_PROTECT_ALL_AT_BOOT)) {
- new_flags_at_boot &= ~EC_FLASH_PROTECT_ALL_AT_BOOT;
- /* Must also clear RW/ROLLBACK. */
-#ifdef CONFIG_FLASH_PROTECT_RW
- new_flags_at_boot &= ~EC_FLASH_PROTECT_RW_AT_BOOT;
-#endif
-#ifdef CONFIG_ROLLBACK
- new_flags_at_boot &= ~EC_FLASH_PROTECT_ROLLBACK_AT_BOOT;
-#endif
- }
-
- /* 1.d - Clear RW_AT_BOOT. */
-#ifdef CONFIG_FLASH_PROTECT_RW
- if ((mask & EC_FLASH_PROTECT_RW_AT_BOOT) &&
- !(flags & EC_FLASH_PROTECT_RW_AT_BOOT)) {
- new_flags_at_boot &= ~EC_FLASH_PROTECT_RW_AT_BOOT;
- /* Must also clear ALL (otherwise nothing will happen). */
- new_flags_at_boot &= ~EC_FLASH_PROTECT_ALL_AT_BOOT;
- }
-#endif
-
- /* 1.e - Clear ROLLBACK_AT_BOOT. */
-#ifdef CONFIG_ROLLBACK
- if ((mask & EC_FLASH_PROTECT_ROLLBACK_AT_BOOT) &&
- !(flags & EC_FLASH_PROTECT_ROLLBACK_AT_BOOT)) {
- new_flags_at_boot &= ~EC_FLASH_PROTECT_ROLLBACK_AT_BOOT;
- /* Must also remove ALL (otherwise nothing will happen). */
- new_flags_at_boot &= ~EC_FLASH_PROTECT_ALL_AT_BOOT;
- }
-#endif
-
- /* 1.f - Commit *_AT_BOOT "clears" (and RO "set" 1.b). */
- if (new_flags_at_boot != old_flags_at_boot) {
- rv = crec_flash_protect_at_boot(new_flags_at_boot);
- if (rv)
- retval = rv;
- old_flags_at_boot = new_flags_at_boot;
- }
-
- /* 2 - Return if RO_AT_BOOT and HW-WP are not asserted.
- *
- * 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 ((~crec_flash_get_protect()) & (EC_FLASH_PROTECT_GPIO_ASSERTED |
- EC_FLASH_PROTECT_RO_AT_BOOT))
- return retval;
-
- /*
- * 3.a - Set ALL_AT_BOOT.
- *
- * The case where ALL/RW/ROLLBACK_AT_BOOT is cleared is already covered
- * above, so we do not need to mask it out.
- */
- new_flags_at_boot |= flags & EC_FLASH_PROTECT_ALL_AT_BOOT;
-
- /* 3.b - Set RW_AT_BOOT. */
-#ifdef CONFIG_FLASH_PROTECT_RW
- new_flags_at_boot |= flags & EC_FLASH_PROTECT_RW_AT_BOOT;
-#endif
-
- /* 3.c - Set ROLLBACK_AT_BOOT. */
-#ifdef CONFIG_ROLLBACK
- new_flags_at_boot |= flags & EC_FLASH_PROTECT_ROLLBACK_AT_BOOT;
-#endif
-
- /* 3.d - Commit *_AT_BOOT "sets". */
- if (new_flags_at_boot != old_flags_at_boot) {
- rv = crec_flash_protect_at_boot(new_flags_at_boot);
- if (rv)
- retval = rv;
- }
-
- /* 4 - Commit RO_NOW. */
- if (flags & EC_FLASH_PROTECT_RO_NOW) {
- rv = crec_flash_physical_protect_now(0);
- if (rv)
- retval = rv;
-
- /*
- * Latch the CBI EEPROM WP immediately if HW WP is asserted and
- * we're now protecting the RO region with SW WP.
- */
- if (IS_ENABLED(CONFIG_EEPROM_CBI_WP) &&
- (EC_FLASH_PROTECT_GPIO_ASSERTED &
- crec_flash_get_protect()))
- cbi_latch_eeprom_wp();
- }
-
- /* 5 - Commit ALL_NOW. */
- if (flags & EC_FLASH_PROTECT_ALL_NOW) {
- rv = crec_flash_physical_protect_now(1);
- if (rv)
- retval = rv;
- }
-
- return retval;
-}
-
-#ifdef CONFIG_FLASH_DEFERRED_ERASE
-static volatile enum ec_status erase_rc = EC_RES_SUCCESS;
-static struct ec_params_flash_erase_v1 erase_info;
-
-static void flash_erase_deferred(void)
-{
- erase_rc = EC_RES_BUSY;
- if (crec_flash_erase(erase_info.params.offset, erase_info.params.size))
- erase_rc = EC_RES_ERROR;
- else
- erase_rc = EC_RES_SUCCESS;
-}
-DECLARE_DEFERRED(flash_erase_deferred);
-#endif
-
-/*****************************************************************************/
-/* Console commands */
-
-#ifdef CONFIG_CMD_FLASHINFO
-static int command_flash_info(int argc, char **argv)
-{
- int i, flags;
-
- ccprintf("Usable: %4d KB\n", CONFIG_FLASH_SIZE_BYTES / 1024);
- ccprintf("Write: %4d B (ideal %d B)\n", CONFIG_FLASH_WRITE_SIZE,
- CONFIG_FLASH_WRITE_IDEAL_SIZE);
-#ifdef CONFIG_FLASH_MULTIPLE_REGION
- ccprintf("Regions:\n");
- for (i = 0; i < ARRAY_SIZE(flash_bank_array); i++) {
- ccprintf(" %d region%s:\n",
- flash_bank_array[i].count,
- (flash_bank_array[i].count == 1 ? "" : "s"));
- ccprintf(" Erase: %4d B (to %d-bits)\n",
- 1 << flash_bank_array[i].erase_size_exp,
- CONFIG_FLASH_ERASED_VALUE32 ? 1 : 0);
- ccprintf(" Size/Protect: %4d B\n",
- 1 << flash_bank_array[i].size_exp);
- }
-#else
- 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);
-#endif
- flags = crec_flash_get_protect();
- ccprintf("Flags: ");
- if (flags & EC_FLASH_PROTECT_GPIO_ASSERTED)
- ccputs(" wp_gpio_asserted");
- if (flags & EC_FLASH_PROTECT_RO_AT_BOOT)
- ccputs(" ro_at_boot");
- if (flags & EC_FLASH_PROTECT_ALL_AT_BOOT)
- ccputs(" all_at_boot");
- if (flags & EC_FLASH_PROTECT_RO_NOW)
- ccputs(" ro_now");
- if (flags & EC_FLASH_PROTECT_ALL_NOW)
- ccputs(" all_now");
-#ifdef CONFIG_FLASH_PROTECT_RW
- if (flags & EC_FLASH_PROTECT_RW_AT_BOOT)
- ccputs(" rw_at_boot");
- if (flags & EC_FLASH_PROTECT_RW_NOW)
- ccputs(" rw_now");
-#endif
- if (flags & EC_FLASH_PROTECT_ERROR_STUCK)
- ccputs(" STUCK");
- if (flags & EC_FLASH_PROTECT_ERROR_INCONSISTENT)
- ccputs(" INCONSISTENT");
-#ifdef CONFIG_ROLLBACK
- if (flags & EC_FLASH_PROTECT_ROLLBACK_AT_BOOT)
- ccputs(" rollback_at_boot");
- if (flags & EC_FLASH_PROTECT_ROLLBACK_NOW)
- ccputs(" rollback_now");
-#endif
- ccputs("\n");
-
- ccputs("Protected now:");
- for (i = 0; i < PHYSICAL_BANKS; i++) {
- if (!(i & 31))
- ccputs("\n ");
- else if (!(i & 7))
- ccputs(" ");
- ccputs(crec_flash_physical_get_protect(i) ? "Y" : ".");
- }
- ccputs("\n");
- return EC_SUCCESS;
-}
-DECLARE_SAFE_CONSOLE_COMMAND(flashinfo, command_flash_info,
- NULL,
- "Print flash info");
-#endif /* CONFIG_CMD_FLASHINFO */
-
-#ifdef CONFIG_CMD_FLASH
-static int command_flash_erase(int argc, char **argv)
-{
- int offset = -1;
- int size = -1;
- int rv;
-
- if (crec_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);
- return crec_flash_erase(offset, size);
-}
-DECLARE_CONSOLE_COMMAND(flasherase, command_flash_erase,
- "offset size",
- "Erase flash");
-
-static int command_flash_write(int argc, char **argv)
-{
- int offset = -1;
- int size = -1;
- int rv;
- char *data;
- int i;
-
- if (crec_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);
- rv = crec_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");
-
-static int command_flash_read(int argc, char **argv)
-{
- int offset = -1;
- int size = 256;
- int rv;
- char *data;
- int i;
-
- 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;
- }
-
- /* Read the data */
- if (crec_flash_read(offset, size, data)) {
- shared_mem_release(data);
- return EC_ERROR_INVAL;
- }
-
- /* Dump it */
- for (i = 0; i < size; i++) {
- if ((offset + i) % 16) {
- ccprintf(" %02x", data[i]);
- } else {
- ccprintf("\n%08x: %02x", offset + i, data[i]);
- cflush();
- }
- }
- ccprintf("\n");
-
- /* Free the buffer */
- shared_mem_release(data);
-
- return EC_SUCCESS;
-}
-DECLARE_CONSOLE_COMMAND(flashread, command_flash_read,
- "offset [size]",
- "Read flash");
-#endif
-
-#ifdef CONFIG_CMD_FLASH_WP
-static int command_flash_wp(int argc, char **argv)
-{
- int val;
-
- if (argc < 2)
- return EC_ERROR_PARAM_COUNT;
-
- if (!strcasecmp(argv[1], "now"))
- return crec_flash_set_protect(EC_FLASH_PROTECT_ALL_NOW, -1);
-
- if (!strcasecmp(argv[1], "all"))
- return crec_flash_set_protect(EC_FLASH_PROTECT_ALL_AT_BOOT, -1);
-
- if (!strcasecmp(argv[1], "noall"))
- return crec_flash_set_protect(EC_FLASH_PROTECT_ALL_AT_BOOT, 0);
-
-#ifdef CONFIG_FLASH_PROTECT_RW
- if (!strcasecmp(argv[1], "rw"))
- return crec_flash_set_protect(EC_FLASH_PROTECT_RW_AT_BOOT, -1);
-
- if (!strcasecmp(argv[1], "norw"))
- return crec_flash_set_protect(EC_FLASH_PROTECT_RW_AT_BOOT, 0);
-#endif
-
-#ifdef CONFIG_ROLLBACK
- if (!strcasecmp(argv[1], "rb"))
- return crec_flash_set_protect(EC_FLASH_PROTECT_ROLLBACK_AT_BOOT,
- -1);
-
- if (!strcasecmp(argv[1], "norb"))
- return crec_flash_set_protect(EC_FLASH_PROTECT_ROLLBACK_AT_BOOT,
- 0);
-#endif
-
- /* Do this last, since anything starting with 'n' means "no" */
- if (parse_bool(argv[1], &val))
- return crec_flash_set_protect(EC_FLASH_PROTECT_RO_AT_BOOT,
- val ? -1 : 0);
-
- return EC_ERROR_PARAM1;
-}
-DECLARE_CONSOLE_COMMAND(flashwp, command_flash_wp,
- "<BOOLEAN> | now | all | noall"
-#ifdef CONFIG_FLASH_PROTECT_RW
- " | rw | norw"
-#endif
-#ifdef CONFIG_ROLLBACK
- " | rb | norb"
-#endif
- , "Modify flash write protect");
-#endif /* CONFIG_CMD_FLASH_WP */
-
-/*****************************************************************************/
-/* Host commands */
-
-/*
- * All internal EC code assumes that offsets are provided relative to
- * physical address zero of storage. In some cases, the region of storage
- * belonging to the EC is not physical address zero - a non-zero fmap_base
- * indicates so. Since fmap_base is not yet handled correctly by external
- * code, we must perform the adjustment in our host command handlers -
- * adjust all offsets so they are relative to the beginning of the storage
- * region belonging to the EC. TODO(crbug.com/529365): Handle fmap_base
- * correctly in flashrom, dump_fmap, etc. and remove EC_FLASH_REGION_START.
- */
-#define EC_FLASH_REGION_START MIN(CONFIG_EC_PROTECTED_STORAGE_OFF, \
- CONFIG_EC_WRITABLE_STORAGE_OFF)
-
-static enum ec_status flash_command_get_info(struct host_cmd_handler_args *args)
-{
- const struct ec_params_flash_info_2 *p_2 = args->params;
- struct ec_response_flash_info_2 *r_2 = args->response;
-#ifdef CONFIG_FLASH_MULTIPLE_REGION
- int banks_size = ARRAY_SIZE(flash_bank_array);
- const struct ec_flash_bank *banks = flash_bank_array;
-#else
- struct ec_response_flash_info_1 *r_1 = args->response;
-#if CONFIG_FLASH_BANK_SIZE < CONFIG_FLASH_ERASE_SIZE
-#error "Flash: Bank size expected bigger or equal to erase size."
-#endif
- struct ec_flash_bank single_bank = {
- .count = CONFIG_FLASH_SIZE_BYTES / CONFIG_FLASH_BANK_SIZE,
- .size_exp = __fls(CONFIG_FLASH_BANK_SIZE),
- .write_size_exp = __fls(CONFIG_FLASH_WRITE_SIZE),
- .erase_size_exp = __fls(CONFIG_FLASH_ERASE_SIZE),
- .protect_size_exp = __fls(CONFIG_FLASH_BANK_SIZE),
- };
- int banks_size = 1;
- const struct ec_flash_bank *banks = &single_bank;
-#endif
- int banks_len;
- int ideal_size;
-
- /*
- * Compute the ideal amount of data for the host to send us,
- * based on the maximum response size and the ideal write size.
- */
- 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 (!ideal_size)
- ideal_size = (args->response_max -
- sizeof(struct ec_params_flash_write)) &
- ~(CONFIG_FLASH_WRITE_SIZE - 1);
-
-
- if (args->version >= 2) {
- args->response_size = sizeof(struct ec_response_flash_info_2);
- r_2->flash_size =
- CONFIG_FLASH_SIZE_BYTES - EC_FLASH_REGION_START;
-#if (CONFIG_FLASH_ERASED_VALUE32 == 0)
- r_2->flags = EC_FLASH_INFO_ERASE_TO_0;
-#else
- r_2->flags = 0;
-#endif
-#ifdef CONFIG_FLASH_SELECT_REQUIRED
- r_2->flags |= EC_FLASH_INFO_SELECT_REQUIRED;
-#endif
- r_2->write_ideal_size = ideal_size;
- r_2->num_banks_total = banks_size;
- r_2->num_banks_desc = MIN(banks_size, p_2->num_banks_desc);
- banks_len = r_2->num_banks_desc * sizeof(struct ec_flash_bank);
- memcpy(r_2->banks, banks, banks_len);
- args->response_size += banks_len;
- return EC_RES_SUCCESS;
- }
-#ifdef CONFIG_FLASH_MULTIPLE_REGION
- return EC_RES_INVALID_PARAM;
-#else
- r_1->flash_size = CONFIG_FLASH_SIZE_BYTES - EC_FLASH_REGION_START;
- r_1->flags = 0;
- r_1->write_block_size = CONFIG_FLASH_WRITE_SIZE;
- r_1->erase_block_size = CONFIG_FLASH_ERASE_SIZE;
- r_1->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 {
- args->response_size = sizeof(struct ec_response_flash_info_1);
- /* Fill in full version 1 struct */
- r_1->write_ideal_size = ideal_size;
-#if (CONFIG_FLASH_ERASED_VALUE32 == 0)
- r_1->flags |= EC_FLASH_INFO_ERASE_TO_0;
-#endif
-#ifdef CONFIG_FLASH_SELECT_REQUIRED
- r_1->flags |= EC_FLASH_INFO_SELECT_REQUIRED;
-#endif
- }
- return EC_RES_SUCCESS;
-#endif /* CONFIG_FLASH_MULTIPLE_REGION */
-}
-#ifdef CONFIG_FLASH_MULTIPLE_REGION
-#define FLASH_INFO_VER EC_VER_MASK(2)
-#else
-#define FLASH_INFO_VER (EC_VER_MASK(0) | EC_VER_MASK(1) | EC_VER_MASK(2))
-#endif
-DECLARE_HOST_COMMAND(EC_CMD_FLASH_INFO,
- flash_command_get_info, FLASH_INFO_VER);
-
-
-static enum ec_status flash_command_read(struct host_cmd_handler_args *args)
-{
- const struct ec_params_flash_read *p = args->params;
- uint32_t offset = p->offset + EC_FLASH_REGION_START;
-
- if (p->size > args->response_max)
- return EC_RES_OVERFLOW;
-
- if (crec_flash_read(offset, p->size, args->response))
- return EC_RES_ERROR;
-
- 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 enum ec_status flash_command_write(struct host_cmd_handler_args *args)
-{
- const struct ec_params_flash_write *p = args->params;
- uint32_t offset = p->offset + EC_FLASH_REGION_START;
-
- if (crec_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;
-
-#ifdef CONFIG_INTERNAL_STORAGE
- if (system_unsafe_to_overwrite(offset, p->size))
- return EC_RES_ACCESS_DENIED;
-#endif
-
- if (crec_flash_write(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));
-
-#ifndef CONFIG_FLASH_MULTIPLE_REGION
-/*
- * Make sure our image sizes are a multiple of flash block erase size so that
- * the host can erase the entire image.
- * Note that host (flashrom/depthcharge) does not erase/program the
- * EC_FLASH_REGION_RO region, it only queries this region.
- */
-BUILD_ASSERT(CONFIG_WP_STORAGE_SIZE % CONFIG_FLASH_ERASE_SIZE == 0);
-BUILD_ASSERT(CONFIG_EC_WRITABLE_STORAGE_SIZE % CONFIG_FLASH_ERASE_SIZE == 0);
-
-#endif
-
-static enum ec_status flash_command_erase(struct host_cmd_handler_args *args)
-{
- const struct ec_params_flash_erase *p = args->params;
- int rc = EC_RES_SUCCESS, cmd = FLASH_ERASE_SECTOR;
- uint32_t offset;
-#ifdef CONFIG_FLASH_DEFERRED_ERASE
- const struct ec_params_flash_erase_v1 *p_1 = args->params;
-
- if (args->version > 0) {
- cmd = p_1->cmd;
- p = &p_1->params;
- }
-#endif
- offset = p->offset + EC_FLASH_REGION_START;
-
- if (crec_flash_get_protect() & EC_FLASH_PROTECT_ALL_NOW)
- return EC_RES_ACCESS_DENIED;
-
-#ifdef CONFIG_INTERNAL_STORAGE
- if (system_unsafe_to_overwrite(offset, p->size))
- return EC_RES_ACCESS_DENIED;
-#endif
-
- switch (cmd) {
- case FLASH_ERASE_SECTOR:
-#if defined(HAS_TASK_HOSTCMD) && defined(CONFIG_HOST_COMMAND_STATUS)
- args->result = EC_RES_IN_PROGRESS;
- host_send_response(args);
-#endif
- if (crec_flash_erase(offset, p->size))
- return EC_RES_ERROR;
-
- break;
-#ifdef CONFIG_FLASH_DEFERRED_ERASE
- case FLASH_ERASE_SECTOR_ASYNC:
- rc = erase_rc;
- if (rc == EC_RES_SUCCESS) {
- memcpy(&erase_info, p_1, sizeof(*p_1));
- hook_call_deferred(&flash_erase_deferred_data,
- 100 * MSEC);
- } else {
- /*
- * Not our job to return the result of
- * the previous command.
- */
- rc = EC_RES_BUSY;
- }
- break;
- case FLASH_ERASE_GET_RESULT:
- rc = erase_rc;
- if (rc != EC_RES_BUSY)
- /* Ready for another command */
- erase_rc = EC_RES_SUCCESS;
- break;
-#endif
- default:
- rc = EC_RES_INVALID_PARAM;
- }
- return rc;
-}
-
-
-DECLARE_HOST_COMMAND(EC_CMD_FLASH_ERASE, flash_command_erase,
- EC_VER_MASK(0)
-#ifdef CONFIG_FLASH_DEFERRED_ERASE
- | EC_VER_MASK(1)
-#endif
- );
-
-static enum ec_status 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)
- crec_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 = crec_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_ERROR_INCONSISTENT |
- crec_flash_physical_get_valid_flags();
- r->writable_flags = crec_flash_physical_get_writable_flags(r->flags);
-
- 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 enum ec_status
-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_EC_PROTECTED_STORAGE_OFF +
- CONFIG_RO_STORAGE_OFF -
- EC_FLASH_REGION_START;
- r->size = EC_FLASH_REGION_RO_SIZE;
- break;
- case EC_FLASH_REGION_ACTIVE:
- r->offset = flash_get_rw_offset(system_get_active_copy()) -
- EC_FLASH_REGION_START;
- r->size = CONFIG_EC_WRITABLE_STORAGE_SIZE;
- break;
- case EC_FLASH_REGION_WP_RO:
- r->offset = CONFIG_WP_STORAGE_OFF -
- EC_FLASH_REGION_START;
- r->size = CONFIG_WP_STORAGE_SIZE;
- break;
- case EC_FLASH_REGION_UPDATE:
- r->offset = flash_get_rw_offset(system_get_update_copy()) -
- EC_FLASH_REGION_START;
- r->size = CONFIG_EC_WRITABLE_STORAGE_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));
-
-
-#ifdef CONFIG_FLASH_SELECT_REQUIRED
-
-static enum ec_status flash_command_select(struct host_cmd_handler_args *args)
-{
- const struct ec_params_flash_select *p = args->params;
-
- return crec_board_flash_select(p->select);
-}
-DECLARE_HOST_COMMAND(EC_CMD_FLASH_SELECT,
- flash_command_select,
- EC_VER_MASK(0));
-
-#endif /* CONFIG_FLASH_SELECT_REQUIRED */