summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2012-07-18 13:15:40 -0700
committerRandall Spangler <rspangler@chromium.org>2012-07-18 18:15:29 -0700
commit8137b29125dec793c84273b522d8adfa7c1748dc (patch)
tree763ea30bc74eb93b205aac543be708fe6d99d583
parent3dfc336b440979c1eb58102df0f15a7cc0f305e8 (diff)
downloadchrome-ec-8137b29125dec793c84273b522d8adfa7c1748dc.tar.gz
Add EC flash protect command to ectool
BUG=chrome-os-partner:11150 TEST=manual Enable WP GPIO. Then from a root shell localhost ~ # ectool flashprotect Flash protect flags: 0x00000008 wp_gpio_asserted Writable flags: 0x00000005 ro_at_boot rw_now localhost ~ # ectool flashprotect enable Flash protect flags: 0x0000000b wp_gpio_asserted ro_at_boot ro_now Writable flags: 0x00000004 rw_now localhost ~ # ectool flashprotect enable Flash protect flags: 0x0000000b wp_gpio_asserted ro_at_boot ro_now Writable flags: 0x00000004 rw_now localhost ~ # ectool flashprotect now Flash protect flags: 0x0000000f wp_gpio_asserted ro_at_boot ro_now rw_now Writable flags: 0x00000000 localhost ~ # ectool flashprotect now Flash protect flags: 0x0000000f wp_gpio_asserted ro_at_boot ro_now rw_now Writable flags: 0x00000000 localhost ~ # ectool flashprotect disable Flash protect flags: 0x0000000f wp_gpio_asserted ro_at_boot ro_now rw_now Writable flags: 0x00000000 Unable to set requested flags (wanted mask 0x00000001 flags 0x00000000) Which is expected, because writable mask is 0x00000000. Then disable WP GPIO and reboot localhost ~ # ectool flashprotect Flash protect flags: 0x00000001 ro_at_boot Writable flags: 0x00000001 ro_at_boot localhost ~ # ectool flashprotect disable Flash protect flags: 0x00000000 Writable flags: 0x00000001 ro_at_boot Change-Id: Idc5de3b3033521467aca8fb0ba9b7c378d0ad2a1 Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/27799
-rw-r--r--common/flash_common.c87
-rw-r--r--common/system_common.c2
-rw-r--r--include/ec_commands.h54
-rw-r--r--include/flash.h25
-rw-r--r--util/ectool.c75
5 files changed, 206 insertions, 37 deletions
diff --git a/common/flash_common.c b/common/flash_common.c
index 8203aa774a..c914d52672 100644
--- a/common/flash_common.c
+++ b/common/flash_common.c
@@ -226,11 +226,11 @@ int flash_get_protect(void)
/* Read the current persist state from flash */
read_pstate();
if (pstate.flags & PERSIST_FLAG_PROTECT_RO)
- flags |= FLASH_PROTECT_RO_AT_BOOT;
+ flags |= EC_FLASH_PROTECT_RO_AT_BOOT;
/* Check if write protect pin is asserted now */
if (wp_pin_asserted())
- flags |= FLASH_PROTECT_PIN_ASSERTED;
+ flags |= EC_FLASH_PROTECT_GPIO_ASSERTED;
/* Scan flash protection */
for (i = 0; i < PHYSICAL_BANKS; i++) {
@@ -238,21 +238,21 @@ int flash_get_protect(void)
int is_ro = ((i >= RO_BANK_OFFSET &&
i < RO_BANK_OFFSET + RO_BANK_COUNT) ||
i == PSTATE_BANK);
- int bank_flag = (is_ro ? FLASH_PROTECT_RO_NOW :
- FLASH_PROTECT_RW_NOW);
+ int bank_flag = (is_ro ? EC_FLASH_PROTECT_RO_NOW :
+ EC_FLASH_PROTECT_RW_NOW);
if (flash_physical_get_protect(i)) {
/* At least one bank in the region is protected */
flags |= bank_flag;
} else if (flags & bank_flag) {
/* But not all banks in the region! */
- flags |= FLASH_PROTECT_PARTIAL;
+ flags |= EC_FLASH_PROTECT_ERROR_INCONSISTENT;
}
}
/* Check if any banks were stuck locked at boot */
if (stuck_locked)
- flags |= FLASH_PROTECT_STUCK_LOCKED;
+ flags |= EC_FLASH_PROTECT_ERROR_STUCK;
return flags;
}
@@ -321,18 +321,18 @@ static int command_flash_info(int argc, char **argv)
i = flash_get_protect();
ccprintf("Flags: ");
- if (i & FLASH_PROTECT_PIN_ASSERTED)
- ccputs(" wp_asserted");
- if (i & FLASH_PROTECT_RO_AT_BOOT)
+ 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 & FLASH_PROTECT_RO_NOW)
+ if (i & EC_FLASH_PROTECT_RO_NOW)
ccputs(" ro_now");
- if (i & FLASH_PROTECT_RW_NOW)
+ if (i & EC_FLASH_PROTECT_RW_NOW)
ccputs(" rw_now");
- if (i & FLASH_PROTECT_STUCK_LOCKED)
+ if (i & EC_FLASH_PROTECT_ERROR_STUCK)
ccputs(" STUCK");
- if (i & FLASH_PROTECT_PARTIAL)
- ccputs(" PARTIAL");
+ if (i & EC_FLASH_PROTECT_ERROR_INCONSISTENT)
+ ccputs(" INCONSISTENT");
ccputs("\n");
ccputs("Protected now:");
@@ -501,3 +501,62 @@ static int flash_command_erase(struct host_cmd_handler_args *args)
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 =
+ (const struct ec_params_flash_protect *)args->params;
+ struct ec_response_flash_protect *r =
+ (struct ec_response_flash_protect *)args->response;
+
+ /* Handle requesting new flags */
+ if (p->mask & EC_FLASH_PROTECT_RO_AT_BOOT)
+ flash_enable_protect(p->flags & EC_FLASH_PROTECT_RO_AT_BOOT);
+
+ if ((p->mask & EC_FLASH_PROTECT_RW_NOW) &&
+ (p->flags & EC_FLASH_PROTECT_RW_NOW))
+ flash_protect_until_reboot();
+
+ /* Ignore all other requested 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_RO_AT_BOOT |
+ EC_FLASH_PROTECT_RO_NOW |
+ EC_FLASH_PROTECT_RW_NOW |
+ EC_FLASH_PROTECT_GPIO_ASSERTED |
+ EC_FLASH_PROTECT_ERROR_STUCK |
+ EC_FLASH_PROTECT_ERROR_INCONSISTENT);
+
+ /* Indicate which flags can be changed this boot */
+ r->writable_flags = 0;
+
+ /*
+ * If RW protection isn't enabled this boot, it can be enabled if the *
+ * WP GPIO is asserted.
+ */
+ if (!(r->flags & EC_FLASH_PROTECT_RW_NOW) &&
+ (r->flags & EC_FLASH_PROTECT_GPIO_ASSERTED))
+ r->writable_flags |= EC_FLASH_PROTECT_RW_NOW;
+
+ /* 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;
+
+ /* Other flags can't be written */
+
+
+ args->response_size = sizeof(*r);
+
+ return EC_RES_SUCCESS;
+}
+DECLARE_HOST_COMMAND(EC_CMD_FLASH_PROTECT,
+ flash_command_protect,
+ EC_VER_MASK(1));
diff --git a/common/system_common.c b/common/system_common.c
index 83b156743c..3251a79a56 100644
--- a/common/system_common.c
+++ b/common/system_common.c
@@ -96,7 +96,7 @@ int system_is_locked(void)
* On link, unlocked if write protect pin deasserted or read-only
* firmware is not protected.
*/
- if ((FLASH_PROTECT_PIN_ASSERTED | FLASH_PROTECT_RO_NOW) &
+ if ((EC_FLASH_PROTECT_GPIO_ASSERTED | EC_FLASH_PROTECT_RO_NOW) &
~flash_get_protect())
return 0;
diff --git a/include/ec_commands.h b/include/ec_commands.h
index b63035aaff..819151aa14 100644
--- a/include/ec_commands.h
+++ b/include/ec_commands.h
@@ -427,6 +427,60 @@ struct ec_params_flash_erase {
} __packed;
/*
+ * Get/set flash protection.
+ *
+ * If mask!=0, sets/clear the requested bits of flags. Depending on the
+ * firmware write protect GPIO, not all flags will take effect immediately;
+ * some flags require a subsequent hard reset to take effect. Check the
+ * returned flags bits to see what actually happened.
+ *
+ * If mask=0, simply returns the current flags state.
+ */
+#define EC_CMD_FLASH_PROTECT 0x15
+#define EC_VER_FLASH_PROTECT 1 /* Command version 1 */
+
+/* Flags for flash protection */
+/* RO flash code protected when the EC boots */
+#define EC_FLASH_PROTECT_RO_AT_BOOT (1 << 0)
+/*
+ * RO flash code protected now. If this bit is set, at-boot status cannot
+ * be changed.
+ */
+#define EC_FLASH_PROTECT_RO_NOW (1 << 1)
+/* RW flash code protected now, until reboot. */
+#define EC_FLASH_PROTECT_RW_NOW (1 << 2)
+/* Flash write protect GPIO is asserted now */
+#define EC_FLASH_PROTECT_GPIO_ASSERTED (1 << 3)
+/* Error - at least one bank of flash is stuck locked, and cannot be unlocked */
+#define EC_FLASH_PROTECT_ERROR_STUCK (1 << 4)
+/*
+ * Error - flash protection is in inconsistent state. At least one bank of
+ * flash which should be protected is not protected. Usually fixed by
+ * re-requesting the desired flags, or by a hard reset if that fails.
+ */
+#define EC_FLASH_PROTECT_ERROR_INCONSISTENT (1 << 5)
+/* RW flash code protected when the EC boots */
+#define EC_FLASH_PROTECT_RW_AT_BOOT (1 << 6)
+
+struct ec_params_flash_protect {
+ uint32_t mask; /* Bits in flags to apply */
+ uint32_t flags; /* New flags to apply */
+} __packed;
+
+struct ec_response_flash_protect {
+ /* Current value of flash protect flags */
+ uint32_t flags;
+ /*
+ * Flags which are valid on this platform. This allows the caller
+ * to distinguish between flags which aren't set vs. flags which can't
+ * be set on this platform.
+ */
+ uint32_t valid_flags;
+ /* Flags which can be changed given the current protection state */
+ uint32_t writable_flags;
+} __packed;
+
+/*
* Note: commands 0x14 - 0x19 version 0 were old commands to get/set flash
* write protect. These commands may be reused with version > 0.
*/
diff --git a/include/flash.h b/include/flash.h
index e78119868b..617259f0c9 100644
--- a/include/flash.h
+++ b/include/flash.h
@@ -9,7 +9,7 @@
#define __CROS_EC_FLASH_H
#include "common.h"
-
+#include "ec_commands.h" /* For EC_FLASH_PROTECT_* flags */
/*****************************************************************************/
/* Low-level methods, for use by flash_common. */
@@ -158,29 +158,10 @@ int flash_protect_until_reboot(void);
*/
int flash_enable_protect(int enable);
-/* Flags for flash_get_protect() */
-/*
- * 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_RO_AT_BOOT (1 << 0)
-/*
- * Flash protection lock has actually been applied. Read-only firmware is
- * protected, and flash protection cannot be unlocked.
- */
-#define FLASH_PROTECT_RO_NOW (1 << 1)
-/* Write protect pin is currently asserted */
-#define FLASH_PROTECT_PIN_ASSERTED (1 << 2)
-/* Entire flash is protected until reboot */
-#define FLASH_PROTECT_RW_NOW (1 << 3)
-/* At least one bank of flash is stuck locked, and cannot be unlocked */
-#define FLASH_PROTECT_STUCK_LOCKED (1 << 4)
-/* At least one bank of flash which should be protected is not protected */
-#define FLASH_PROTECT_PARTIAL (1 << 5)
-
/**
* Return the flash protect lock status.
+ *
+ * Uses the EC_FLASH_PROTECT_* flags from ec_commands.h
*/
int flash_get_protect(void);
diff --git a/util/ectool.c b/util/ectool.c
index 3fddb992f1..0cb9825c06 100644
--- a/util/ectool.c
+++ b/util/ectool.c
@@ -65,6 +65,8 @@ const char help_str[] =
" Erases EC flash\n"
" flashinfo\n"
" Prints information on the EC flash\n"
+ " flashprotect [now] [enable | disable]\n"
+ " Prints or sets EC flash protection state\n"
" flashread <offset> <size> <outfile>\n"
" Reads from EC flash to a file\n"
" flashwrite <offset> <infile>\n"
@@ -574,6 +576,78 @@ int cmd_flash_erase(int argc, char *argv[])
}
+static void print_flash_protect_flags(const char *desc, uint32_t flags)
+{
+ printf("%s 0x%08x", desc, flags);
+ if (flags & EC_FLASH_PROTECT_GPIO_ASSERTED)
+ printf(" wp_gpio_asserted");
+ if (flags & EC_FLASH_PROTECT_RO_AT_BOOT)
+ printf(" ro_at_boot");
+ if (flags & EC_FLASH_PROTECT_RW_AT_BOOT)
+ printf(" rw_at_boot");
+ if (flags & EC_FLASH_PROTECT_RO_NOW)
+ printf(" ro_now");
+ if (flags & EC_FLASH_PROTECT_RW_NOW)
+ printf(" rw_now");
+ if (flags & EC_FLASH_PROTECT_ERROR_STUCK)
+ printf(" STUCK");
+ if (flags & EC_FLASH_PROTECT_ERROR_INCONSISTENT)
+ printf(" INCONSISTENT");
+ printf("\n");
+}
+
+
+int cmd_flash_protect(int argc, char *argv[])
+{
+ struct ec_params_flash_protect p;
+ struct ec_response_flash_protect r;
+ int rv, i;
+
+ /*
+ * Set up requested flags. If no flags were specified, p.mask will
+ * be 0 and nothing will change.
+ */
+ p.mask = p.flags = 0;
+ for (i = 1; i < argc; i++) {
+ if (!strcasecmp(argv[i], "now")) {
+ p.mask |= EC_FLASH_PROTECT_RW_NOW;
+ p.flags |= EC_FLASH_PROTECT_RW_NOW;
+ } else if (!strcasecmp(argv[i], "enable")) {
+ p.mask |= EC_FLASH_PROTECT_RO_AT_BOOT;
+ p.flags |= EC_FLASH_PROTECT_RO_AT_BOOT;
+ } else if (!strcasecmp(argv[i], "disable"))
+ p.mask |= EC_FLASH_PROTECT_RO_AT_BOOT;
+ }
+
+ rv = ec_command(EC_CMD_FLASH_PROTECT, EC_VER_FLASH_PROTECT,
+ &p, sizeof(p), &r, sizeof(r));
+ if (rv < 0)
+ return rv;
+ if (rv < sizeof(r)) {
+ fprintf(stderr, "Too little data returned.\n");
+ return -1;
+ }
+
+ /* Print returned flags */
+ print_flash_protect_flags("Flash protect flags:", r.flags);
+ print_flash_protect_flags("Writable flags: ", r.writable_flags);
+
+ /* Check if we got all the flags we asked for */
+ if ((r.flags & p.mask) != (p.flags & p.mask)) {
+ fprintf(stderr, "Unable to set requested flags "
+ "(wanted mask 0x%08x flags 0x%08x)\n",
+ p.mask, p.flags);
+ if (p.mask & ~r.writable_flags)
+ fprintf(stderr, "Which is expected, because writable "
+ "mask is 0x%08x.\n", r.writable_flags);
+
+ return -1;
+ }
+
+ return 0;
+}
+
+
int cmd_serial_test(int argc, char *argv[])
{
const char *c = "COM2 sample serial output from host!\r\n";
@@ -1964,6 +2038,7 @@ const struct command commands[] = {
{"eventsetwakemask", cmd_host_event_set_wake_mask},
{"fanduty", cmd_fanduty},
{"flasherase", cmd_flash_erase},
+ {"flashprotect", cmd_flash_protect},
{"flashread", cmd_flash_read},
{"flashwrite", cmd_flash_write},
{"flashinfo", cmd_flash_info},