diff options
author | Randall Spangler <rspangler@chromium.org> | 2012-07-18 13:15:40 -0700 |
---|---|---|
committer | Randall Spangler <rspangler@chromium.org> | 2012-07-18 18:15:29 -0700 |
commit | 8137b29125dec793c84273b522d8adfa7c1748dc (patch) | |
tree | 763ea30bc74eb93b205aac543be708fe6d99d583 | |
parent | 3dfc336b440979c1eb58102df0f15a7cc0f305e8 (diff) | |
download | chrome-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.c | 87 | ||||
-rw-r--r-- | common/system_common.c | 2 | ||||
-rw-r--r-- | include/ec_commands.h | 54 | ||||
-rw-r--r-- | include/flash.h | 25 | ||||
-rw-r--r-- | util/ectool.c | 75 |
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}, |