summaryrefslogtreecommitdiff
path: root/common/flash.c
diff options
context:
space:
mode:
authorNick Sanders <nsanders@chromium.org>2016-04-06 14:25:45 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-05-26 16:17:26 -0700
commit56ee8aefc33505a7df4e4148001a11ac461907a3 (patch)
tree9aa84b4f26d7396878757bb7ed79bebaa18f59a2 /common/flash.c
parent5cc3cac589d3e869266c18ed7e538a769496478f (diff)
downloadchrome-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/flash.c')
-rw-r--r--common/flash.c170
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