mmc-utils: Expand 'writeprotect boot'
This patch updates 'mmc writeprotect boot set' with a few more optional
parameters, so that it can be used to enable permanent write-protection
and so that the two boot partitions can be protected independently. It
also splits protection information output by 'mmc writeprotect boot get'
by partition.
BUG=b:151202634
TEST=Enabled different kinds of protection on my Trogdor.
Signed-off-by: Julius Werner <jwerner@chromium.org>
Change-Id: I327fff23675b267a9f75d754ccc47db3f84c294c
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/mmc-utils/+/2103512
Reviewed-by: Gwendal Grignou <gwendal@chromium.org>
diff --git a/mmc.c b/mmc.c
index fe3f479..85e0dbd 100644
--- a/mmc.c
+++ b/mmc.c
@@ -69,8 +69,12 @@
NULL
},
{ do_writeprotect_boot_set, -1,
- "writeprotect boot set", "<device>\n"
- "Set the boot partitions write protect status for <device>.\nThis sets the eMMC boot partitions to be write-protected until\nthe next boot.",
+ "writeprotect boot set", "[-p] " "<device> [<number>]\n"
+ "Set the boot partition write protect status for <device>.\n"
+ "If <number> is passed (0 or 1), only protect that particular\n"
+ "eMMC boot partition, otherwise protect both. It will be\n"
+ "write-protected until the next boot.\n"
+ " -p Protect partition permanently instead. WARNING: THIS IS IRREVERSIBLE!\n",
NULL
},
{ do_writeprotect_user_set, -4,
diff --git a/mmc.h b/mmc.h
index 53f5b10..d82e182 100644
--- a/mmc.h
+++ b/mmc.h
@@ -77,6 +77,7 @@
#define EXT_CSD_PART_CONFIG 179
#define EXT_CSD_BOOT_BUS_CONDITIONS 177
#define EXT_CSD_ERASE_GROUP_DEF 175
+#define EXT_CSD_BOOT_WP_STATUS 174
#define EXT_CSD_BOOT_WP 173
#define EXT_CSD_USER_WP 171
#define EXT_CSD_FW_CONFIG 169 /* R/W */
@@ -147,9 +148,16 @@
#define EXT_CSD_HPI_SUPP (1<<0)
#define EXT_CSD_HPI_IMPL (1<<1)
#define EXT_CSD_CMD_SET_NORMAL (1<<0)
+#define EXT_CSD_BOOT_WP_S_AREA_2_PERM (0x08)
+#define EXT_CSD_BOOT_WP_S_AREA_2_PWR (0x04)
+#define EXT_CSD_BOOT_WP_S_AREA_1_PERM (0x02)
+#define EXT_CSD_BOOT_WP_S_AREA_1_PWR (0x01)
+#define EXT_CSD_BOOT_WP_B_SEC_WP_SEL (0x80)
#define EXT_CSD_BOOT_WP_B_PWR_WP_DIS (0x40)
#define EXT_CSD_BOOT_WP_B_PERM_WP_DIS (0x10)
+#define EXT_CSD_BOOT_WP_B_PERM_WP_SEC_SEL (0x08)
#define EXT_CSD_BOOT_WP_B_PERM_WP_EN (0x04)
+#define EXT_CSD_BOOT_WP_B_PWR_WP_SEC_SEL (0x02)
#define EXT_CSD_BOOT_WP_B_PWR_WP_EN (0x01)
#define EXT_CSD_BOOT_INFO_HS_MODE (1<<2)
#define EXT_CSD_BOOT_INFO_DDR_DDR (1<<1)
diff --git a/mmc_cmds.c b/mmc_cmds.c
index 6229292..04ffeab 100644
--- a/mmc_cmds.c
+++ b/mmc_cmds.c
@@ -213,11 +213,21 @@
else
printf("possible\n");
- printf(" ro lock status: ");
- if (reg & EXT_CSD_BOOT_WP_B_PWR_WP_EN)
- printf("locked until next power on\n");
- else if (reg & EXT_CSD_BOOT_WP_B_PERM_WP_EN)
+ /* Note: We call the partitions 0 and 1 (like Linux does), but
+ * the eMMC spec calls them AREA 1 and AREA 2. */
+ reg = ext_csd[EXT_CSD_BOOT_WP_STATUS];
+ printf(" partition 0 ro lock status: ");
+ if (reg & EXT_CSD_BOOT_WP_S_AREA_1_PERM)
printf("locked permanently\n");
+ else if (reg & EXT_CSD_BOOT_WP_S_AREA_1_PWR)
+ printf("locked until next power on\n");
+ else
+ printf("not locked\n");
+ printf(" partition 1 ro lock status: ");
+ if (reg & EXT_CSD_BOOT_WP_S_AREA_2_PERM)
+ printf("locked permanently\n");
+ else if (reg & EXT_CSD_BOOT_WP_S_AREA_2_PWR)
+ printf("locked until next power on\n");
else
printf("not locked\n");
}
@@ -271,13 +281,22 @@
__u8 ext_csd[EXT_CSD_SIZE], value;
int fd, ret;
char *device;
+ char *end;
+ int argi = 1;
+ int permanent = 0;
+ int partition = -1;
- if (nargs != 2) {
- fprintf(stderr, "Usage: mmc writeprotect boot set </path/to/mmcblkX>\n");
+ if (!strcmp(argv[argi], "-p")){
+ permanent = 1;
+ argi++;
+ }
+
+ if (nargs < 1 + argi || nargs > 2 + argi) {
+ fprintf(stderr, "Usage: mmc writeprotect boot set [-p] </path/to/mmcblkX> [0|1]\n");
exit(1);
}
- device = argv[1];
+ device = argv[argi++];
fd = open(device, O_RDWR);
if (fd < 0) {
@@ -285,14 +304,49 @@
exit(1);
}
+ if (nargs == 1 + argi) {
+ partition = strtoul(argv[argi], &end, 0);
+ if (*end != '\0' || !(partition == 0 || partition == 1)) {
+ fprintf(stderr, "Invalid partition number (must be 0 or 1): %s\n",
+ argv[argi]);
+ exit(1);
+ }
+ }
+
ret = read_extcsd(fd, ext_csd);
if (ret) {
fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
exit(1);
}
- value = ext_csd[EXT_CSD_BOOT_WP] |
- EXT_CSD_BOOT_WP_B_PWR_WP_EN;
+ value = ext_csd[EXT_CSD_BOOT_WP];
+ /*
+ * If permanent protection is already on for one partition and we're
+ * trying to enable power-reset protection for the other we need to make
+ * sure the selection bit for permanent protection still points to the
+ * former or we'll accidentally permanently protect the latter.
+ */
+ if ((value & EXT_CSD_BOOT_WP_B_PERM_WP_EN) && !permanent) {
+ if (ext_csd[EXT_CSD_BOOT_WP_STATUS] &
+ EXT_CSD_BOOT_WP_S_AREA_2_PERM) {
+ value |= EXT_CSD_BOOT_WP_B_PERM_WP_SEC_SEL;
+ if (partition != 1)
+ partition = 0;
+ } else {
+ /* PERM_WP_SEC_SEL cleared -> pointing to partition 0 */
+ if (partition != 0)
+ partition = 1;
+ }
+ }
+ if (partition != -1) {
+ value |= EXT_CSD_BOOT_WP_B_SEC_WP_SEL;
+ if (partition == 1)
+ value |= permanent ? EXT_CSD_BOOT_WP_B_PERM_WP_SEC_SEL
+ : EXT_CSD_BOOT_WP_B_PWR_WP_SEC_SEL;
+ }
+ value |= permanent ? EXT_CSD_BOOT_WP_B_PERM_WP_EN
+ : EXT_CSD_BOOT_WP_B_PWR_WP_EN;
+
ret = write_extcsd_value(fd, EXT_CSD_BOOT_WP, value);
if (ret) {
fprintf(stderr, "Could not write 0x%02x to "