Commit be4cac34 authored by Julius Werner's avatar Julius Werner Committed by Ulf Hansson
Browse files

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.

(Note: eMMC boot partitions are named "Area 1" and "Area 2" by the eMMC
spec, but mmcblk0boot0 and mmcblk0boot1 by Linux. To avoid confusion
between the two numbering schemes, this patch uses 0 and 1 throughout,
even when defining EXT_CSD register bits.)
Signed-off-by: default avatarJulius Werner <jwerner@chromium.org>
Link: https://lore.kernel.org/r/20200316202221.107714-1-jwerner@chromium.org

Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
parent 5b3e56f7
......@@ -64,9 +64,20 @@ static struct Command commands[] = {
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.",
NULL
"writeprotect boot set",
#ifdef DANGEROUS_COMMANDS_ENABLED
"[-p] "
#endif /* DANGEROUS_COMMANDS_ENABLED */
"<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"
#ifdef DANGEROUS_COMMANDS_ENABLED
" -p Protect partition permanently instead.\n"
" NOTE! -p is a one-time programmable (unreversible) change.\n"
#endif /* DANGEROUS_COMMANDS_ENABLED */
, NULL
},
{ do_writeprotect_user_set, -4,
"writeprotect user set", "<type>" "<start block>" "<blocks>" "<device>\n"
......
......@@ -75,6 +75,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 */
......@@ -144,9 +145,19 @@
#define EXT_CSD_HPI_SUPP (1<<0)
#define EXT_CSD_HPI_IMPL (1<<1)
#define EXT_CSD_CMD_SET_NORMAL (1<<0)
/* NOTE: The eMMC spec calls the partitions "Area 1" and "Area 2", but Linux
* calls them mmcblk0boot0 and mmcblk0boot1. To avoid confustion between the two
* numbering schemes, this tool uses 0 and 1 throughout. */
#define EXT_CSD_BOOT_WP_S_AREA_1_PERM (0x08)
#define EXT_CSD_BOOT_WP_S_AREA_1_PWR (0x04)
#define EXT_CSD_BOOT_WP_S_AREA_0_PERM (0x02)
#define EXT_CSD_BOOT_WP_S_AREA_0_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)
......
......@@ -202,11 +202,19 @@ static void print_writeprotect_boot_status(__u8 *ext_csd)
else
printf("possible\n");
printf(" ro lock status: ");
if (reg & EXT_CSD_BOOT_WP_B_PWR_WP_EN)
reg = ext_csd[EXT_CSD_BOOT_WP_STATUS];
printf(" partition 0 ro lock status: ");
if (reg & EXT_CSD_BOOT_WP_S_AREA_0_PERM)
printf("locked permanently\n");
else if (reg & EXT_CSD_BOOT_WP_S_AREA_0_PWR)
printf("locked until next power on\n");
else if (reg & EXT_CSD_BOOT_WP_B_PERM_WP_EN)
else
printf("not locked\n");
printf(" partition 1 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");
}
......@@ -260,13 +268,28 @@ int do_writeprotect_boot_set(int nargs, char **argv)
__u8 ext_csd[512], 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");
#ifdef DANGEROUS_COMMANDS_ENABLED
if (!strcmp(argv[argi], "-p")){
permanent = 1;
argi++;
}
#endif
if (nargs < 1 + argi || nargs > 2 + argi) {
fprintf(stderr, "Usage: mmc writeprotect boot set "
#ifdef DANGEROUS_COMMANDS_ENABLED
"[-p] "
#endif
"</path/to/mmcblkX> [0|1]\n");
exit(1);
}
device = argv[1];
device = argv[argi++];
fd = open(device, O_RDWR);
if (fd < 0) {
......@@ -274,14 +297,49 @@ int do_writeprotect_boot_set(int nargs, char **argv)
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_1_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 "
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment