Am 17. Dezember 2020 12:27:39 MEZ schrieb Marek Szyprowski <m.szyprow...@samsung.com>: >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
It is good to have this information in the commit message. But we cannot expect a user to look at commit messages. Please, provide a man-page in doc/usage/. You can use this patch as template: https://lists.denx.de/pipermail/u-boot/2020-December/435144.html Use 'make htmldocs' to build and check the documentation. Once your patch is merged the documentation will be published at https://u-boot.readthedocs.io/ Best regards Heinrich > >Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> >--- > cmd/Kconfig | 8 ++ > cmd/Makefile | 1 + > cmd/mbr.c | 308 +++++++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 317 insertions(+) > create mode 100644 cmd/mbr.c > >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..25a3f694d3 >--- /dev/null >+++ b/cmd/mbr.c >@@ -0,0 +1,308 @@ >+// SPDX-License-Identifier: GPL-2.0+ >+/* >+ * cmd_mbr.c -- MBR (Master Boot Record) handling command >+ * >+ * Copyright (C) 2020 Samsung Electronics >+ * author: Marek Szyprowski <m.szyprow...@samsung.com> >+ * >+ * based on the gpt command. >+ */ >+ >+#include <common.h> >+#include <blk.h> >+#include <malloc.h> >+#include <command.h> >+#include <part.h> >+ >+/** >+ * extract_val(): Extract value from a key=value pair list (comma >separated). >+ * Only value for the given key is returend. >+ * Function allocates memory for the value, remember to >free! >+ * >+ * @param str - pointer to string with key=values pairs >+ * @param key - pointer to the key to search for >+ * >+ * @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(): Found key without value in parameter list (comma >separated). >+ * >+ * @param str - pointer to string with key >+ * @param key - pointer to the key to search for >+ * >+ * @return - true on found key >+ */ >+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_partition_info(const char *str_part, 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 / 512; >+ } >+ 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 / 512; >+ 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 count; >+ >+ if (str_to_partition_info(str, &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 count, i, ret = 1; >+ >+ if (str_to_partition_info(str, &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" >+);