diff options
author | Nick Sanders <nsanders@chromium.org> | 2016-04-06 14:25:45 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2016-05-26 16:17:26 -0700 |
commit | 56ee8aefc33505a7df4e4148001a11ac461907a3 (patch) | |
tree | 9aa84b4f26d7396878757bb7ed79bebaa18f59a2 /common | |
parent | 5cc3cac589d3e869266c18ed7e538a769496478f (diff) | |
download | chrome-ec-56ee8aefc33505a7df4e4148001a11ac461907a3.tar.gz |
servo_micro: add programmable serial number
This change provides a console command for setting,
and loading a usb serial number from flash. This
feature adds CONFIG_USB_SERIALNO, and currently only
has a useful implementation when PSTATE is present.
BUG=chromium:571477
TEST=serialno set abcdef; serialno load; reboot
BRANCH=none
Change-Id: I3b24cfa2d52d54118bc3fd54b276e3d95412d245
Signed-off-by: Nick Sanders <nsanders@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/337359
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Diffstat (limited to 'common')
-rw-r--r-- | common/flash.c | 170 |
1 files changed, 146 insertions, 24 deletions
diff --git a/common/flash.c b/common/flash.c index 7cd977d9e0..2bb1679197 100644 --- a/common/flash.c +++ b/common/flash.c @@ -35,17 +35,24 @@ #ifdef CONFIG_FLASH_PSTATE_BANK /* 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 */ +/* NOTE: It's not expected that RO and RW will support + * differing PSTATE versions. */ +#define PERSIST_STATE_VERSION 3 /* Expected persist_state.version */ +#define SERIALNO_MAX 30 /* Flags for persist_state.flags */ /* Protect persist state and RO firmware at boot */ #define PERSIST_FLAG_PROTECT_RO 0x02 +#define PSTATE_VALID_FLAGS (1 << 0) +#define PSTATE_VALID_SERIALNO (1 << 1) + +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 */ + uint8_t serialno[SERIALNO_MAX]; /* Serial number. */ +}; #else /* !CONFIG_FLASH_PSTATE_BANK */ @@ -142,6 +149,7 @@ static uint32_t flash_read_pstate(void) 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; @@ -155,23 +163,33 @@ static uint32_t flash_read_pstate(void) } /** - * Write persistent state from pstate, erasing if necessary. + * Read and return persistent serial number. + */ +static const char *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 0; +} + +/** + * Write persistent state after erasing. * - * @param flags New flash write protect flags to set in pstate. + * @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(uint32_t flags) +static int flash_write_pstate_data(struct persist_state *newpstate) { - struct persist_state pstate; int rv; - /* 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; - /* Erase pstate */ rv = flash_physical_erase(CONFIG_FW_PSTATE_OFF, CONFIG_FW_PSTATE_SIZE); @@ -184,15 +202,101 @@ static int flash_write_pstate(uint32_t flags) * it's protected. */ - /* Write a new pstate */ - memset(&pstate, 0, sizeof(pstate)); - pstate.version = PERSIST_STATE_VERSION; + /* Write the updated pstate */ + return 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; + pstate->valid_fields = 0; + } + + 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) - pstate.flags |= PERSIST_FLAG_PROTECT_RO; - return flash_physical_write(CONFIG_FW_PSTATE_OFF, sizeof(pstate), - (const char *)&pstate); + 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); } +/** + * Write persistent serial number to pstate, erasing if necessary. + * + * @param serialno New iascii serial number to set in pstate. + * @return EC_SUCCESS, or nonzero if error. + */ +static int flash_write_pstate_serial(const char *serialno) +{ + int i; + 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; + + /* Cache the old copy for read/modify/write. */ + memcpy(&newpstate, pstate, sizeof(newpstate)); + validate_pstate_struct(&newpstate); + + /* Copy in serialno. */ + for (i = 0; i < SERIALNO_MAX - 1; i++) { + newpstate.serialno[i] = serialno[i]; + if (serialno[i] == 0) + break; + } + for (; i < SERIALNO_MAX; i++) + newpstate.serialno[i] = 0; + newpstate.valid_fields |= PSTATE_VALID_SERIALNO; + + return flash_write_pstate_data(&newpstate); +} + + + + #else /* !CONFIG_FLASH_PSTATE_BANK */ /** @@ -349,6 +453,24 @@ int flash_erase(int offset, int size) return flash_physical_erase(offset, size); } +const char *flash_read_serial(void) +{ +#if defined(CONFIG_FLASH_PSTATE) && defined(CONFIG_FLASH_PSTATE_BANK) + return flash_read_pstate_serial(); +#else + return 0; +#endif +} + +int flash_write_serial(const char *serialno) +{ +#if defined(CONFIG_FLASH_PSTATE) && defined(CONFIG_FLASH_PSTATE_BANK) + return flash_write_pstate_serial(serialno); +#else + return EC_ERROR_UNIMPLEMENTED; +#endif +} + int flash_protect_at_boot(enum flash_wp_range range) { #ifdef CONFIG_FLASH_PSTATE |