Message ID | 20201222140914.9933-7-m.szyprowski@samsung.com |
---|---|
State | Superseded |
Headers | show |
Series | Add MBR partition table creation and verify command | expand |
On 12/22/20 3:09 PM, Marek Szyprowski wrote: > Add a 'mbr' command to let user create or verify MBR partition layout > based on the provided text description. The partition layout is > altearnatively read from 'mbr_parts' environment variable. This can be > used in scripts to help system image flashing tools to ensure proper > partition layout. > > The syntax of the text description of the partition list is similar to > the one used by the 'gpt' command. Supported parameters are: name > (currently ignored), start (partition start offset in bytes), size (in > bytes or '-' to expand it to the whole free area), bootable (boolean > flag) and id (MBR partition system ID). If one wants to create more than > 4 partitions, an 'Extended' primary partition (with 0x05 ID) has to be > explicitely provided as a one of the first 4 entries. > > Here is the example how to create a 6 partitions (3 on the 'extended > volume'), some of the predefined sizes: > >> setenv mbr_parts 'name=boot,start=4M,size=128M,bootable,id=0x0e; > name=rootfs,size=3072M,id=0x83; > name=system-data,size=512M,id=0x83; > name=[ext],size=-,id=0x05; > name=user,size=-,id=0x83; > name=modules,size=100M,id=0x83; > name=ramdisk,size=8M,id=0x83' >> mbr write mmc 0 > > Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> > --- > cmd/Kconfig | 8 ++ > cmd/Makefile | 1 + > cmd/mbr.c | 314 ++++++++++++++++++++++++++++++++++++++++++++ > doc/usage/index.rst | 1 + > doc/usage/mbr.rst | 93 +++++++++++++ > 5 files changed, 417 insertions(+) > create mode 100644 cmd/mbr.c > create mode 100644 doc/usage/mbr.rst > > diff --git a/cmd/Kconfig b/cmd/Kconfig > index 1595de999b..2c3358e359 100644 > --- a/cmd/Kconfig > +++ b/cmd/Kconfig > @@ -1025,6 +1025,14 @@ config CMD_LSBLK > Print list of available block device drivers, and for each, the list > of known block devices. > > +config CMD_MBR > + bool "MBR (Master Boot Record) command" > + select DOS_PARTITION > + select HAVE_BLOCK_DEVICE > + help > + Enable the 'mbr' command to ready and write MBR (Master Boot Record) > + style partition tables. > + > config CMD_MISC > bool "misc" > depends on MISC > diff --git a/cmd/Makefile b/cmd/Makefile > index dd86675bf2..41379d9a0e 100644 > --- a/cmd/Makefile > +++ b/cmd/Makefile > @@ -178,6 +178,7 @@ obj-$(CONFIG_CMD_ZFS) += zfs.o > > obj-$(CONFIG_CMD_DFU) += dfu.o > obj-$(CONFIG_CMD_GPT) += gpt.o > +obj-$(CONFIG_CMD_MBR) += mbr.o > obj-$(CONFIG_CMD_ETHSW) += ethsw.o > obj-$(CONFIG_CMD_AXI) += axi.o > obj-$(CONFIG_CMD_PVBLOCK) += pvblock.o > diff --git a/cmd/mbr.c b/cmd/mbr.c > new file mode 100644 > index 0000000000..da2e3a4722 > --- /dev/null > +++ b/cmd/mbr.c > @@ -0,0 +1,314 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * cmd_mbr.c -- MBR (Master Boot Record) handling command > + * > + * Copyright (C) 2020 Samsung Electronics > + * author: Marek Szyprowski <m.szyprowski@samsung.com> > + * > + * based on the gpt command. > + */ > + > +#include <common.h> > +#include <blk.h> > +#include <command.h> > +#include <malloc.h> > +#include <part.h> > + > +/** > + * extract_val() - Extract a value from the key=value pair list > + * @str: pointer to string with key=values pairs > + * @key: pointer to the key to search for > + * > + * The list of parameters is come separated, only a value for > + * the given key is returend. > + * > + * Function allocates memory for the value, remember to free! > + * > + * Return: Pointer to allocated string with the value. > + */ > +static char *extract_val(const char *str, const char *key) > +{ > + char *v, *k; > + char *s, *strcopy; > + char *new = NULL; > + > + strcopy = strdup(str); > + if (strcopy == NULL) > + return NULL; > + > + s = strcopy; > + while (s) { > + v = strsep(&s, ","); > + if (!v) > + break; > + k = strsep(&v, "="); > + if (!k) > + break; > + if (strcmp(k, key) == 0) { > + new = strdup(v); > + break; > + } > + } > + > + free(strcopy); > + > + return new; > +} > + > +/** > + * found_key() - Search for a key without a value in the parameter list > + * @str: pointer to string with key > + * @key: pointer to the key to search for > + * > + * The list of parameters is come separated. > + * > + * Return: True if key has been found. > + */ > +static bool found_key(const char *str, const char *key) > +{ > + char *k; > + char *s, *strcopy; > + bool result = false; > + > + strcopy = strdup(str); > + if (!strcopy) > + return NULL; > + > + s = strcopy; > + while (s) { > + k = strsep(&s, ","); > + if (!k) > + break; > + if (strcmp(k, key) == 0) { > + result = true; > + break; > + } > + } > + > + free(strcopy); > + > + return result; > +} > + > +static int str_to_partitions(const char *str_part, int blksz, > + unsigned long *disk_uuid, struct disk_partition **partitions, > + int *parts_count) > +{ > + char *tok, *str, *s; > + int i; > + char *val, *p; > + int p_count; > + struct disk_partition *parts; > + int errno = 0; > + uint64_t size_ll, start_ll; > + > + if (str_part == NULL) > + return -1; > + > + str = strdup(str_part); > + if (str == NULL) > + return -ENOMEM; > + > + /* extract disk guid */ > + s = str; > + val = extract_val(str, "uuid_disk"); > + if (val) { > + val = strsep(&val, ";"); > + p = val; > + *disk_uuid = ustrtoull(p, &p, 0); > + free(val); > + /* Move s to first partition */ > + strsep(&s, ";"); > + } > + if (s == NULL) { > + printf("Error: is the partitions string NULL-terminated?\n"); > + return -EINVAL; > + } > + > + /* remove the optional semicolon at the end of the string */ > + i = strlen(s) - 1; > + if (s[i] == ';') > + s[i] = '\0'; > + > + /* calculate expected number of partitions */ > + p_count = 1; > + p = s; > + while (*p) { > + if (*p++ == ';') > + p_count++; > + } > + > + /* allocate memory for partitions */ > + parts = calloc(sizeof(struct disk_partition), p_count); > + if (parts == NULL) > + return -ENOMEM; > + > + /* retrieve partitions data from string */ > + for (i = 0; i < p_count; i++) { > + tok = strsep(&s, ";"); > + > + if (tok == NULL) > + break; > + > + /* size */ > + val = extract_val(tok, "size"); > + if (!val) { /* 'size' is mandatory */ > + errno = -4; > + goto err; > + } > + p = val; > + if ((strcmp(p, "-") == 0)) { > + /* auto extend the size */ > + parts[i].size = 0; > + } else { > + size_ll = ustrtoull(p, &p, 0); > + parts[i].size = size_ll / blksz; > + } > + free(val); > + > + /* start address */ > + val = extract_val(tok, "start"); > + if (val) { /* start address is optional */ > + p = val; > + start_ll = ustrtoull(p, &p, 0); > + parts[i].start = start_ll / blksz; > + free(val); > + } > + > + /* system id */ > + val = extract_val(tok, "id"); > + if (!val) { /* '' is mandatory */ > + errno = -4; > + goto err; > + } > + p = val; > + parts[i].sys_ind = ustrtoul(p, &p, 0); > + free(val); > + > + /* bootable */ > + if (found_key(tok, "bootable")) > + parts[i].bootable = PART_BOOTABLE; > + } > + > + *parts_count = p_count; > + *partitions = parts; > + free(str); > + > + return 0; > +err: > + free(str); > + free(parts); > + > + return errno; > +} > + > +static int do_write_mbr(struct blk_desc *dev, const char *str) > +{ > + unsigned long disk_uuid = 0; > + struct disk_partition *partitions; > + int blksz = dev->blksz; > + int count; > + > + if (str_to_partitions(str, blksz, &disk_uuid, &partitions, &count)) { > + printf("MBR: failed to setup partitions from \"%s\"\n", str); > + return -1; > + } > + > + if (layout_mbr_partitions(partitions, count, dev->lba)) { > + printf("MBR: failed to layout partitions on the device\n"); > + free(partitions); > + return -1; > + } > + > + if (write_mbr_partitions(dev, partitions, count, disk_uuid)) { > + printf("MBR: failed to write partitions to the device\n"); > + free(partitions); > + return -1; > + } > + > + return 0; > +} > + > +static int do_verify_mbr(struct blk_desc *dev, const char *str) > +{ > + unsigned long disk_uuid = 0; > + struct disk_partition *partitions; > + int blksz = dev->blksz; > + int count, i, ret = 1; > + > + if (str_to_partitions(str, blksz, &disk_uuid, &partitions, &count)) { > + printf("MBR: failed to setup partitions from \"%s\"\n", str); > + return -1; > + } > + > + for (i = 0; i < count; i++) { > + struct disk_partition p; > + > + if (part_get_info(dev, i+1, &p)) > + goto fail; > + > + if ((partitions[i].size && p.size < partitions[i].size) || > + (partitions[i].start && p.start < partitions[i].start) || > + (p.sys_ind != partitions[i].sys_ind)) > + goto fail; > + } > + ret = 0; > +fail: > + free(partitions); > + return ret; > +} > + > +static int do_mbr(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) > +{ > + const char *parts = NULL; > + int ret = CMD_RET_SUCCESS; > + int dev = 0; > + char *ep; > + struct blk_desc *blk_dev_desc = NULL; > + > + if (argc != 4 && argc != 5) > + return CMD_RET_USAGE; > + > + dev = (int)simple_strtoul(argv[3], &ep, 10); > + if (!ep || ep[0] != '\0') { > + printf("'%s' is not a number\n", argv[3]); > + return CMD_RET_USAGE; > + } > + blk_dev_desc = blk_get_dev(argv[2], dev); > + if (!blk_dev_desc) { > + printf("%s: %s dev %d NOT available\n", > + __func__, argv[2], dev); > + return CMD_RET_FAILURE; > + } > + > + if ((strcmp(argv[1], "write") == 0)) { > + parts = (argc == 5) ? argv[4] : env_get("mbr_parts"); > + printf("MBR: write "); > + ret = do_write_mbr(blk_dev_desc, parts); > + } else if ((strcmp(argv[1], "verify") == 0)) { > + printf("MBR: verify "); > + parts = (argc == 5) ? argv[4] : env_get("mbr_parts"); > + ret = do_verify_mbr(blk_dev_desc, parts); > + } else { > + return CMD_RET_USAGE; > + } > + > + if (ret) { > + printf("error!\n"); > + return CMD_RET_FAILURE; > + } > + > + printf("success!\n"); > + return CMD_RET_SUCCESS; > +} > + > +U_BOOT_CMD(mbr, CONFIG_SYS_MAXARGS, 1, do_mbr, > + "MBR (Master Boot Record)", > + "<command> <interface> <dev> <partitions_list>\n" > + " - MBR partition table restoration utility\n" > + " Restore or check partition information on a device connected\n" > + " to the given block interface\n" > + " Example usage:\n" > + " mbr write mmc 0 [\"${mbr_parts}\"]\n" > + " mbr verify mmc 0 [\"${partitions}\"]\n" > +); > diff --git a/doc/usage/index.rst b/doc/usage/index.rst > index fbb2c0481c..5869fba189 100644 > --- a/doc/usage/index.rst > +++ b/doc/usage/index.rst > @@ -14,4 +14,5 @@ Shell commands > bootefi > bootmenu > button > + mbr > pstore > diff --git a/doc/usage/mbr.rst b/doc/usage/mbr.rst > new file mode 100644 > index 0000000000..ee27b00c75 > --- /dev/null > +++ b/doc/usage/mbr.rst > @@ -0,0 +1,93 @@ > +.. SPDX-License-Identifier: GPL-2.0+ > + > +mbr command > +=========== > + > +Synopsis > +-------- > + > +:: > + > + mbr verify [interface] [device no] [partition list] > + mbr write [interface] [device no] [partition list] > + > +Description > +----------- > + > +The mbr command lets user to create or verify MBR partition layout allows the user to create or lets users create create or verify the MBR > +based on the provided text description. The partition layout is > +altearnatively read from 'mbr_parts' environment variable. This can be alternatively read from the > +used in scripts to help system image flashing tools to ensure proper > +partition layout. > + > +The syntax of the text description of the partition list is similar to > +the one used by the 'gpt' command. > + > +Supported partition parameters are: > + > +* name (currently ignored) > +* start (partition start offset in bytes) > +* size (in bytes or '-' to expand it to the whole free area) > +* bootable (boolean flag) > +* id (MBR partition system ID) fdisk calls this 'partition type'. The word ID does not make sense because all four partitions may have the same value. > + > +If one wants to create more than 4 partitions, an 'Extended' primary > +partition (with 0x05 ID) has to be explicitely provided as a one of the explicitly > +first 4 entries. > + > +Here is the example how to create a 6 partitions (3 on the 'extended an example > +volume'), some of the predefined sizes: > + > +:: > + > + => setenv mbr_parts 'name=boot,start=4M,size=128M,bootable,id=0x0e; > + name=rootfs,size=3072M,id=0x83; > + name=system-data,size=512M,id=0x83; > + name=[ext],size=-,id=0x05; > + name=user,size=-,id=0x83; > + name=modules,size=100M,id=0x83; > + name=ramdisk,size=8M,id=0x83' > + => mbr write mmc 0 > + > +To check if the layout on the MMC #0 storage device matches the provided > +text description one has to issue following command (assuming that > +mbr_parts environment variable is set): > + > +:: > + > + => mbr verify mmc 0 > + > +The verify sub-command is especially useful in the system update scripts: > + > +:: > + => if mbr verify mmc 0; then > + echo MBR layout needs to be updated > + ... > + fi > + > +The 'mbr write' command returns 0 on success write or -1 on failure. > + > +The 'mbr verify' returns 0 if the layout matches the one on the storage > +device or -1 if not. CMD_RET_FAILURE has value 1 not -1. See you table below. Best regards Heinrich > + > +Configuration > +------------- > + > +To use the mbr command you must specify CONFIG_CMD_MBR=y. > + > +Return value > +------------ > + > +The variable *$?* takes the following values > + > ++---+------------------------------+ > +| 0 | mbr write was succesful | > ++---+------------------------------+ > +| 1 | mbr write failed | > ++---+------------------------------+ > +| 0 | mbr verify was succesful | > ++---+------------------------------+ > +| 1 | mbr verify was not succesful | > ++---+------------------------------+ > +|-1 | invalid arguments | > ++---+------------------------------+ >
Hi Marek, On Tue, 22 Dec 2020 at 07:09, Marek Szyprowski <m.szyprowski@samsung.com> wrote: > > Add a 'mbr' command to let user create or verify MBR partition layout > based on the provided text description. The partition layout is > altearnatively read from 'mbr_parts' environment variable. This can be > used in scripts to help system image flashing tools to ensure proper > partition layout. > > The syntax of the text description of the partition list is similar to > the one used by the 'gpt' command. Supported parameters are: name > (currently ignored), start (partition start offset in bytes), size (in > bytes or '-' to expand it to the whole free area), bootable (boolean > flag) and id (MBR partition system ID). If one wants to create more than > 4 partitions, an 'Extended' primary partition (with 0x05 ID) has to be > explicitely provided as a one of the first 4 entries. > > Here is the example how to create a 6 partitions (3 on the 'extended > volume'), some of the predefined sizes: > > > setenv mbr_parts 'name=boot,start=4M,size=128M,bootable,id=0x0e; > name=rootfs,size=3072M,id=0x83; > name=system-data,size=512M,id=0x83; > name=[ext],size=-,id=0x05; > name=user,size=-,id=0x83; > name=modules,size=100M,id=0x83; > name=ramdisk,size=8M,id=0x83' > > mbr write mmc 0 > > Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> > --- > cmd/Kconfig | 8 ++ > cmd/Makefile | 1 + > cmd/mbr.c | 314 ++++++++++++++++++++++++++++++++++++++++++++ > doc/usage/index.rst | 1 + > doc/usage/mbr.rst | 93 +++++++++++++ > 5 files changed, 417 insertions(+) > create mode 100644 cmd/mbr.c > create mode 100644 doc/usage/mbr.rst This looks good - is it possible to write a test for it? Perhaps a test for str_to_partitions() and the other functions there would be a good start? Regards, Simon
diff --git a/cmd/Kconfig b/cmd/Kconfig index 1595de999b..2c3358e359 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1025,6 +1025,14 @@ config CMD_LSBLK Print list of available block device drivers, and for each, the list of known block devices. +config CMD_MBR + bool "MBR (Master Boot Record) command" + select DOS_PARTITION + select HAVE_BLOCK_DEVICE + help + Enable the 'mbr' command to ready and write MBR (Master Boot Record) + style partition tables. + config CMD_MISC bool "misc" depends on MISC diff --git a/cmd/Makefile b/cmd/Makefile index dd86675bf2..41379d9a0e 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -178,6 +178,7 @@ obj-$(CONFIG_CMD_ZFS) += zfs.o obj-$(CONFIG_CMD_DFU) += dfu.o obj-$(CONFIG_CMD_GPT) += gpt.o +obj-$(CONFIG_CMD_MBR) += mbr.o obj-$(CONFIG_CMD_ETHSW) += ethsw.o obj-$(CONFIG_CMD_AXI) += axi.o obj-$(CONFIG_CMD_PVBLOCK) += pvblock.o diff --git a/cmd/mbr.c b/cmd/mbr.c new file mode 100644 index 0000000000..da2e3a4722 --- /dev/null +++ b/cmd/mbr.c @@ -0,0 +1,314 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * cmd_mbr.c -- MBR (Master Boot Record) handling command + * + * Copyright (C) 2020 Samsung Electronics + * author: Marek Szyprowski <m.szyprowski@samsung.com> + * + * based on the gpt command. + */ + +#include <common.h> +#include <blk.h> +#include <command.h> +#include <malloc.h> +#include <part.h> + +/** + * extract_val() - Extract a value from the key=value pair list + * @str: pointer to string with key=values pairs + * @key: pointer to the key to search for + * + * The list of parameters is come separated, only a value for + * the given key is returend. + * + * Function allocates memory for the value, remember to free! + * + * Return: Pointer to allocated string with the value. + */ +static char *extract_val(const char *str, const char *key) +{ + char *v, *k; + char *s, *strcopy; + char *new = NULL; + + strcopy = strdup(str); + if (strcopy == NULL) + return NULL; + + s = strcopy; + while (s) { + v = strsep(&s, ","); + if (!v) + break; + k = strsep(&v, "="); + if (!k) + break; + if (strcmp(k, key) == 0) { + new = strdup(v); + break; + } + } + + free(strcopy); + + return new; +} + +/** + * found_key() - Search for a key without a value in the parameter list + * @str: pointer to string with key + * @key: pointer to the key to search for + * + * The list of parameters is come separated. + * + * Return: True if key has been found. + */ +static bool found_key(const char *str, const char *key) +{ + char *k; + char *s, *strcopy; + bool result = false; + + strcopy = strdup(str); + if (!strcopy) + return NULL; + + s = strcopy; + while (s) { + k = strsep(&s, ","); + if (!k) + break; + if (strcmp(k, key) == 0) { + result = true; + break; + } + } + + free(strcopy); + + return result; +} + +static int str_to_partitions(const char *str_part, int blksz, + unsigned long *disk_uuid, struct disk_partition **partitions, + int *parts_count) +{ + char *tok, *str, *s; + int i; + char *val, *p; + int p_count; + struct disk_partition *parts; + int errno = 0; + uint64_t size_ll, start_ll; + + if (str_part == NULL) + return -1; + + str = strdup(str_part); + if (str == NULL) + return -ENOMEM; + + /* extract disk guid */ + s = str; + val = extract_val(str, "uuid_disk"); + if (val) { + val = strsep(&val, ";"); + p = val; + *disk_uuid = ustrtoull(p, &p, 0); + free(val); + /* Move s to first partition */ + strsep(&s, ";"); + } + if (s == NULL) { + printf("Error: is the partitions string NULL-terminated?\n"); + return -EINVAL; + } + + /* remove the optional semicolon at the end of the string */ + i = strlen(s) - 1; + if (s[i] == ';') + s[i] = '\0'; + + /* calculate expected number of partitions */ + p_count = 1; + p = s; + while (*p) { + if (*p++ == ';') + p_count++; + } + + /* allocate memory for partitions */ + parts = calloc(sizeof(struct disk_partition), p_count); + if (parts == NULL) + return -ENOMEM; + + /* retrieve partitions data from string */ + for (i = 0; i < p_count; i++) { + tok = strsep(&s, ";"); + + if (tok == NULL) + break; + + /* size */ + val = extract_val(tok, "size"); + if (!val) { /* 'size' is mandatory */ + errno = -4; + goto err; + } + p = val; + if ((strcmp(p, "-") == 0)) { + /* auto extend the size */ + parts[i].size = 0; + } else { + size_ll = ustrtoull(p, &p, 0); + parts[i].size = size_ll / blksz; + } + free(val); + + /* start address */ + val = extract_val(tok, "start"); + if (val) { /* start address is optional */ + p = val; + start_ll = ustrtoull(p, &p, 0); + parts[i].start = start_ll / blksz; + free(val); + } + + /* system id */ + val = extract_val(tok, "id"); + if (!val) { /* '' is mandatory */ + errno = -4; + goto err; + } + p = val; + parts[i].sys_ind = ustrtoul(p, &p, 0); + free(val); + + /* bootable */ + if (found_key(tok, "bootable")) + parts[i].bootable = PART_BOOTABLE; + } + + *parts_count = p_count; + *partitions = parts; + free(str); + + return 0; +err: + free(str); + free(parts); + + return errno; +} + +static int do_write_mbr(struct blk_desc *dev, const char *str) +{ + unsigned long disk_uuid = 0; + struct disk_partition *partitions; + int blksz = dev->blksz; + int count; + + if (str_to_partitions(str, blksz, &disk_uuid, &partitions, &count)) { + printf("MBR: failed to setup partitions from \"%s\"\n", str); + return -1; + } + + if (layout_mbr_partitions(partitions, count, dev->lba)) { + printf("MBR: failed to layout partitions on the device\n"); + free(partitions); + return -1; + } + + if (write_mbr_partitions(dev, partitions, count, disk_uuid)) { + printf("MBR: failed to write partitions to the device\n"); + free(partitions); + return -1; + } + + return 0; +} + +static int do_verify_mbr(struct blk_desc *dev, const char *str) +{ + unsigned long disk_uuid = 0; + struct disk_partition *partitions; + int blksz = dev->blksz; + int count, i, ret = 1; + + if (str_to_partitions(str, blksz, &disk_uuid, &partitions, &count)) { + printf("MBR: failed to setup partitions from \"%s\"\n", str); + return -1; + } + + for (i = 0; i < count; i++) { + struct disk_partition p; + + if (part_get_info(dev, i+1, &p)) + goto fail; + + if ((partitions[i].size && p.size < partitions[i].size) || + (partitions[i].start && p.start < partitions[i].start) || + (p.sys_ind != partitions[i].sys_ind)) + goto fail; + } + ret = 0; +fail: + free(partitions); + return ret; +} + +static int do_mbr(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + const char *parts = NULL; + int ret = CMD_RET_SUCCESS; + int dev = 0; + char *ep; + struct blk_desc *blk_dev_desc = NULL; + + if (argc != 4 && argc != 5) + return CMD_RET_USAGE; + + dev = (int)simple_strtoul(argv[3], &ep, 10); + if (!ep || ep[0] != '\0') { + printf("'%s' is not a number\n", argv[3]); + return CMD_RET_USAGE; + } + blk_dev_desc = blk_get_dev(argv[2], dev); + if (!blk_dev_desc) { + printf("%s: %s dev %d NOT available\n", + __func__, argv[2], dev); + return CMD_RET_FAILURE; + } + + if ((strcmp(argv[1], "write") == 0)) { + parts = (argc == 5) ? argv[4] : env_get("mbr_parts"); + printf("MBR: write "); + ret = do_write_mbr(blk_dev_desc, parts); + } else if ((strcmp(argv[1], "verify") == 0)) { + printf("MBR: verify "); + parts = (argc == 5) ? argv[4] : env_get("mbr_parts"); + ret = do_verify_mbr(blk_dev_desc, parts); + } else { + return CMD_RET_USAGE; + } + + if (ret) { + printf("error!\n"); + return CMD_RET_FAILURE; + } + + printf("success!\n"); + return CMD_RET_SUCCESS; +} + +U_BOOT_CMD(mbr, CONFIG_SYS_MAXARGS, 1, do_mbr, + "MBR (Master Boot Record)", + "<command> <interface> <dev> <partitions_list>\n" + " - MBR partition table restoration utility\n" + " Restore or check partition information on a device connected\n" + " to the given block interface\n" + " Example usage:\n" + " mbr write mmc 0 [\"${mbr_parts}\"]\n" + " mbr verify mmc 0 [\"${partitions}\"]\n" +); diff --git a/doc/usage/index.rst b/doc/usage/index.rst index fbb2c0481c..5869fba189 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -14,4 +14,5 @@ Shell commands bootefi bootmenu button + mbr pstore diff --git a/doc/usage/mbr.rst b/doc/usage/mbr.rst new file mode 100644 index 0000000000..ee27b00c75 --- /dev/null +++ b/doc/usage/mbr.rst @@ -0,0 +1,93 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +mbr command +=========== + +Synopsis +-------- + +:: + + mbr verify [interface] [device no] [partition list] + mbr write [interface] [device no] [partition list] + +Description +----------- + +The mbr command lets user to create or verify MBR partition layout +based on the provided text description. The partition layout is +altearnatively read from 'mbr_parts' environment variable. This can be +used in scripts to help system image flashing tools to ensure proper +partition layout. + +The syntax of the text description of the partition list is similar to +the one used by the 'gpt' command. + +Supported partition parameters are: + +* name (currently ignored) +* start (partition start offset in bytes) +* size (in bytes or '-' to expand it to the whole free area) +* bootable (boolean flag) +* id (MBR partition system ID) + +If one wants to create more than 4 partitions, an 'Extended' primary +partition (with 0x05 ID) has to be explicitely provided as a one of the +first 4 entries. + +Here is the example how to create a 6 partitions (3 on the 'extended +volume'), some of the predefined sizes: + +:: + + => setenv mbr_parts 'name=boot,start=4M,size=128M,bootable,id=0x0e; + name=rootfs,size=3072M,id=0x83; + name=system-data,size=512M,id=0x83; + name=[ext],size=-,id=0x05; + name=user,size=-,id=0x83; + name=modules,size=100M,id=0x83; + name=ramdisk,size=8M,id=0x83' + => mbr write mmc 0 + +To check if the layout on the MMC #0 storage device matches the provided +text description one has to issue following command (assuming that +mbr_parts environment variable is set): + +:: + + => mbr verify mmc 0 + +The verify sub-command is especially useful in the system update scripts: + +:: + => if mbr verify mmc 0; then + echo MBR layout needs to be updated + ... + fi + +The 'mbr write' command returns 0 on success write or -1 on failure. + +The 'mbr verify' returns 0 if the layout matches the one on the storage +device or -1 if not. + +Configuration +------------- + +To use the mbr command you must specify CONFIG_CMD_MBR=y. + +Return value +------------ + +The variable *$?* takes the following values + ++---+------------------------------+ +| 0 | mbr write was succesful | ++---+------------------------------+ +| 1 | mbr write failed | ++---+------------------------------+ +| 0 | mbr verify was succesful | ++---+------------------------------+ +| 1 | mbr verify was not succesful | ++---+------------------------------+ +|-1 | invalid arguments | ++---+------------------------------+