All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/6] Add MBR partition table creation and verify command
       [not found] <CGME20201223125533eucas1p26a3a9fdce43c0902e8ee3c033cb510b0@eucas1p2.samsung.com>
@ 2020-12-23 12:55 ` Marek Szyprowski
       [not found]   ` <CGME20201223125533eucas1p24c90762deb359fc4c73ddb717892c932@eucas1p2.samsung.com>
                     ` (5 more replies)
  0 siblings, 6 replies; 13+ messages in thread
From: Marek Szyprowski @ 2020-12-23 12:55 UTC (permalink / raw)
  To: u-boot

Hi All,

This patchset adds 'mbr' command to let one to create or verify MBR
(Master Boot Record) partition layout based on the provided text
description. This can be used in scripts to help system flashing
tools/scripts to ensure proper partition layout. It has been inspired by
the 'gpt' command already present in u-boot.

Best regards
Marek Szyprowski
Samsung R&D Institute Poland


Changelog:

v3:
- fixed minor issues in the docs

v2: https://lists.denx.de/pipermail/u-boot/2020-December/435689.html
- added docs and minor fixes in the code style

v1: https://lists.denx.de/pipermail/u-boot/2020-December/435208.html
- initial version


Patch summary:

Marek Szyprowski (6):
  disk: dos: rename write_mbr_partition to write_mbr_sector
  disk: dos: add some defines for the hardcoded numbers
  disk: dos: use generic macro for unaligned le32 access
  disk: dos: make some functions static
  disk: dos: add code for creating MBR partition layout
  cmd: Add MBR partition layout control utility

 cmd/Kconfig               |   8 +
 cmd/Makefile              |   1 +
 cmd/mbr.c                 | 314 ++++++++++++++++++++++++++++++++++++++
 disk/part_dos.c           | 207 ++++++++++++++++++++++---
 disk/part_dos.h           |   5 +
 doc/usage/index.rst       |   1 +
 doc/usage/mbr.rst         |  93 +++++++++++
 drivers/fastboot/fb_mmc.c |   2 +-
 include/part.h            |   9 +-
 9 files changed, 612 insertions(+), 28 deletions(-)
 create mode 100644 cmd/mbr.c
 create mode 100644 doc/usage/mbr.rst

-- 
2.17.1

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v3 1/6] disk: dos: rename write_mbr_partition to write_mbr_sector
       [not found]   ` <CGME20201223125533eucas1p24c90762deb359fc4c73ddb717892c932@eucas1p2.samsung.com>
@ 2020-12-23 12:55     ` Marek Szyprowski
  2021-01-16 16:25       ` Tom Rini
  0 siblings, 1 reply; 13+ messages in thread
From: Marek Szyprowski @ 2020-12-23 12:55 UTC (permalink / raw)
  To: u-boot

write_mbr_partition() function name is a bit misleading, so rename it to
write_mbr_sector(). This is a preparation for adding code for writing a
complete MBR partition layout.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 disk/part_dos.c           | 2 +-
 drivers/fastboot/fb_mmc.c | 2 +-
 include/part.h            | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/disk/part_dos.c b/disk/part_dos.c
index 04f53106f7..ef706fb59c 100644
--- a/disk/part_dos.c
+++ b/disk/part_dos.c
@@ -329,7 +329,7 @@ int is_valid_dos_buf(void *buf)
 	return test_block_type(buf) == DOS_MBR ? 0 : -1;
 }
 
-int write_mbr_partition(struct blk_desc *dev_desc, void *buf)
+int write_mbr_sector(struct blk_desc *dev_desc, void *buf)
 {
 	if (is_valid_dos_buf(buf))
 		return -1;
diff --git a/drivers/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c
index ae8e8e512f..4e26cef941 100644
--- a/drivers/fastboot/fb_mmc.c
+++ b/drivers/fastboot/fb_mmc.c
@@ -508,7 +508,7 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer,
 			fastboot_fail("invalid MBR partition", response);
 			return;
 		}
-		if (write_mbr_partition(dev_desc, download_buffer)) {
+		if (write_mbr_sector(dev_desc, download_buffer)) {
 			printf("%s: writing MBR partition failed\n", __func__);
 			fastboot_fail("writing MBR partition failed",
 				      response);
diff --git a/include/part.h b/include/part.h
index 55be724d20..67b8b2a5cc 100644
--- a/include/part.h
+++ b/include/part.h
@@ -465,14 +465,14 @@ int get_disk_guid(struct blk_desc *dev_desc, char *guid);
 int is_valid_dos_buf(void *buf);
 
 /**
- * write_mbr_partition() - write DOS MBR
+ * write_mbr_sector() - write DOS MBR
  *
  * @param dev_desc - block device descriptor
  * @param buf - buffer which contains the MBR
  *
  * @return - '0' on success, otherwise error
  */
-int write_mbr_partition(struct blk_desc *dev_desc, void *buf);
+int write_mbr_sector(struct blk_desc *dev_desc, void *buf);
 
 #endif
 
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 2/6] disk: dos: add some defines for the hardcoded numbers
       [not found]   ` <CGME20201223125534eucas1p2388f9e307ba4fdb85ba1dfea6184e60f@eucas1p2.samsung.com>
@ 2020-12-23 12:55     ` Marek Szyprowski
  2021-01-16 16:25       ` Tom Rini
  0 siblings, 1 reply; 13+ messages in thread
From: Marek Szyprowski @ 2020-12-23 12:55 UTC (permalink / raw)
  To: u-boot

Add some handy defines for some hardcoded magic numbers related to
extended partition handling.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 disk/part_dos.c | 6 +++---
 disk/part_dos.h | 3 +++
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/disk/part_dos.c b/disk/part_dos.c
index ef706fb59c..20d35dc9cd 100644
--- a/disk/part_dos.c
+++ b/disk/part_dos.c
@@ -42,9 +42,9 @@ static inline unsigned int le32_to_int(unsigned char *le32)
 
 static inline int is_extended(int part_type)
 {
-    return (part_type == 0x5 ||
-	    part_type == 0xf ||
-	    part_type == 0x85);
+    return (part_type == DOS_PART_TYPE_EXTENDED ||
+	    part_type == DOS_PART_TYPE_EXTENDED_LBA ||
+	    part_type == DOS_PART_TYPE_EXTENDED_LINUX);
 }
 
 static int get_bootable(dos_partition_t *p)
diff --git a/disk/part_dos.h b/disk/part_dos.h
index 434b021ae8..dd909a9317 100644
--- a/disk/part_dos.h
+++ b/disk/part_dos.h
@@ -15,6 +15,9 @@
 #define DOS_PBR_MEDIA_TYPE_OFFSET	0x15
 #define DOS_MBR	0
 #define DOS_PBR	1
+#define DOS_PART_TYPE_EXTENDED		0x05
+#define DOS_PART_TYPE_EXTENDED_LBA	0x0F
+#define DOS_PART_TYPE_EXTENDED_LINUX	0x85
 
 typedef struct dos_partition {
 	unsigned char boot_ind;		/* 0x80 - active			*/
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 3/6] disk: dos: use generic macro for unaligned le32 access
       [not found]   ` <CGME20201223125534eucas1p12cb4b6a480be29f0101e5cd953d1ce02@eucas1p1.samsung.com>
@ 2020-12-23 12:55     ` Marek Szyprowski
  2021-01-16 16:25       ` Tom Rini
  0 siblings, 1 reply; 13+ messages in thread
From: Marek Szyprowski @ 2020-12-23 12:55 UTC (permalink / raw)
  To: u-boot

Use a generic helper for reading LE32 integers.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 disk/part_dos.c | 28 +++++++++-------------------
 1 file changed, 9 insertions(+), 19 deletions(-)

diff --git a/disk/part_dos.c b/disk/part_dos.c
index 20d35dc9cd..3b79b9b1b8 100644
--- a/disk/part_dos.c
+++ b/disk/part_dos.c
@@ -18,6 +18,7 @@
 #include <command.h>
 #include <ide.h>
 #include <memalign.h>
+#include <asm/unaligned.h>
 #include "part_dos.h"
 #include <part.h>
 
@@ -29,17 +30,6 @@
  * to use large numbers of partitions */
 #define MAX_EXT_PARTS 256
 
-/* Convert char[4] in little endian format to the host format integer
- */
-static inline unsigned int le32_to_int(unsigned char *le32)
-{
-    return ((le32[3] << 24) +
-	    (le32[2] << 16) +
-	    (le32[1] << 8) +
-	     le32[0]
-	   );
-}
-
 static inline int is_extended(int part_type)
 {
     return (part_type == DOS_PART_TYPE_EXTENDED ||
@@ -61,8 +51,8 @@ static int get_bootable(dos_partition_t *p)
 static void print_one_part(dos_partition_t *p, lbaint_t ext_part_sector,
 			   int part_num, unsigned int disksig)
 {
-	lbaint_t lba_start = ext_part_sector + le32_to_int (p->start4);
-	lbaint_t lba_size  = le32_to_int (p->size4);
+	lbaint_t lba_start = ext_part_sector + get_unaligned_le32(p->start4);
+	lbaint_t lba_size  = get_unaligned_le32(p->size4);
 
 	printf("%3d\t%-10" LBAFlength "u\t%-10" LBAFlength
 		"u\t%08x-%02x\t%02x%s%s\n",
@@ -171,7 +161,7 @@ static void print_partition_extended(struct blk_desc *dev_desc,
 	}
 
 	if (!ext_part_sector)
-		disksig = le32_to_int(&buffer[DOS_PART_DISKSIG_OFFSET]);
+		disksig = get_unaligned_le32(&buffer[DOS_PART_DISKSIG_OFFSET]);
 
 	/* Print all primary/logical partitions */
 	pt = (dos_partition_t *) (buffer + DOS_PART_TBL_OFFSET);
@@ -198,7 +188,7 @@ static void print_partition_extended(struct blk_desc *dev_desc,
 	for (i = 0; i < 4; i++, pt++) {
 		if (is_extended (pt->sys_ind)) {
 			lbaint_t lba_start
-				= le32_to_int (pt->start4) + relative;
+				= get_unaligned_le32 (pt->start4) + relative;
 
 			print_partition_extended(dev_desc, lba_start,
 				ext_part_sector == 0  ? lba_start : relative,
@@ -244,7 +234,7 @@ static int part_get_info_extended(struct blk_desc *dev_desc,
 
 #if CONFIG_IS_ENABLED(PARTITION_UUIDS)
 	if (!ext_part_sector)
-		disksig = le32_to_int(&buffer[DOS_PART_DISKSIG_OFFSET]);
+		disksig = get_unaligned_le32(&buffer[DOS_PART_DISKSIG_OFFSET]);
 #endif
 
 	/* Print all primary/logical partitions */
@@ -260,8 +250,8 @@ static int part_get_info_extended(struct blk_desc *dev_desc,
 		    (ext_part_sector == 0 || is_extended(pt->sys_ind) == 0)) {
 			info->blksz = DOS_PART_DEFAULT_SECTOR;
 			info->start = (lbaint_t)(ext_part_sector +
-					le32_to_int(pt->start4));
-			info->size  = (lbaint_t)le32_to_int(pt->size4);
+					get_unaligned_le32(pt->start4));
+			info->size  = (lbaint_t)get_unaligned_le32(pt->size4);
 			part_set_generic_name(dev_desc, part_num,
 					      (char *)info->name);
 			/* sprintf(info->type, "%d, pt->sys_ind); */
@@ -286,7 +276,7 @@ static int part_get_info_extended(struct blk_desc *dev_desc,
 	for (i = 0; i < 4; i++, pt++) {
 		if (is_extended (pt->sys_ind)) {
 			lbaint_t lba_start
-				= le32_to_int (pt->start4) + relative;
+				= get_unaligned_le32 (pt->start4) + relative;
 
 			return part_get_info_extended(dev_desc, lba_start,
 				 ext_part_sector == 0 ? lba_start : relative,
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 4/6] disk: dos: make some functions static
       [not found]   ` <CGME20201223125534eucas1p17107d79af8457f52a5536084f9b903b9@eucas1p1.samsung.com>
@ 2020-12-23 12:55     ` Marek Szyprowski
  2021-01-16 16:25       ` Tom Rini
  0 siblings, 1 reply; 13+ messages in thread
From: Marek Szyprowski @ 2020-12-23 12:55 UTC (permalink / raw)
  To: u-boot

Make functions not used outside this file static.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 disk/part_dos.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/disk/part_dos.c b/disk/part_dos.c
index 3b79b9b1b8..2c4ad0b6ba 100644
--- a/disk/part_dos.c
+++ b/disk/part_dos.c
@@ -302,13 +302,13 @@ static int part_get_info_extended(struct blk_desc *dev_desc,
 	return -1;
 }
 
-void part_print_dos(struct blk_desc *dev_desc)
+static void part_print_dos(struct blk_desc *dev_desc)
 {
 	printf("Part\tStart Sector\tNum Sectors\tUUID\t\tType\n");
 	print_partition_extended(dev_desc, 0, 0, 1, 0);
 }
 
-int part_get_info_dos(struct blk_desc *dev_desc, int part,
+static int part_get_info_dos(struct blk_desc *dev_desc, int part,
 		      struct disk_partition *info)
 {
 	return part_get_info_extended(dev_desc, 0, 0, 1, part, info, 0);
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 5/6] disk: dos: add code for creating MBR partition layout
       [not found]   ` <CGME20201223125535eucas1p2358eef28313de969c15405450a5b9acf@eucas1p2.samsung.com>
@ 2020-12-23 12:55     ` Marek Szyprowski
  2021-01-16 16:25       ` Tom Rini
  0 siblings, 1 reply; 13+ messages in thread
From: Marek Szyprowski @ 2020-12-23 12:55 UTC (permalink / raw)
  To: u-boot

Add a code for creating and writing MBR partition layout. The code generates
similar layout of EBRs (Exteneded Block Records) and logical volumes as
Linux's fdisk utility.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 disk/part_dos.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++
 disk/part_dos.h |   2 +
 include/part.h  |   5 ++
 3 files changed, 174 insertions(+)

diff --git a/disk/part_dos.c b/disk/part_dos.c
index 2c4ad0b6ba..f77f927995 100644
--- a/disk/part_dos.c
+++ b/disk/part_dos.c
@@ -319,6 +319,173 @@ int is_valid_dos_buf(void *buf)
 	return test_block_type(buf) == DOS_MBR ? 0 : -1;
 }
 
+#if CONFIG_IS_ENABLED(CMD_MBR)
+static void lba_to_chs(lbaint_t lba, unsigned char *rc, unsigned char *rh,
+		       unsigned char *rs)
+{
+	unsigned int c, h, s;
+	/* use fixed CHS geometry */
+	unsigned int sectpertrack = 63;
+	unsigned int heads = 255;
+
+	c = (lba + 1) / sectpertrack / heads;
+	h = (lba + 1) / sectpertrack - c * heads;
+	s = (lba + 1) - (c * heads + h) * sectpertrack;
+
+	if (c > 1023) {
+		c = 1023;
+		h = 254;
+		s = 63;
+	}
+
+	*rc = c & 0xff;
+	*rh = h;
+	*rs = s + ((c & 0x300) >> 2);
+}
+
+static void mbr_fill_pt_entry(dos_partition_t *pt, lbaint_t start,
+		lbaint_t relative, lbaint_t size, uchar sys_ind, bool bootable)
+{
+	pt->boot_ind = bootable ? 0x80 : 0x00;
+	pt->sys_ind = sys_ind;
+	lba_to_chs(start, &pt->cyl, &pt->head, &pt->sector);
+	lba_to_chs(start + size - 1, &pt->end_cyl, &pt->end_head, &pt->end_sector);
+	put_unaligned_le32(relative, &pt->start4);
+	put_unaligned_le32(size, &pt->size4);
+}
+
+int write_mbr_partitions(struct blk_desc *dev,
+		struct disk_partition *p, int count, unsigned int disksig)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, dev->blksz);
+	lbaint_t ext_part_start = 0, ext_part_size = 0, ext_part_sect = 0;
+	dos_partition_t *pt;
+	int i;
+
+	memset(buffer, 0, dev->blksz);
+	buffer[DOS_PART_MAGIC_OFFSET] = 0x55;
+	buffer[DOS_PART_MAGIC_OFFSET + 1] = 0xaa;
+	put_unaligned_le32(disksig, &buffer[DOS_PART_DISKSIG_OFFSET]);
+	pt = (dos_partition_t *) (buffer + DOS_PART_TBL_OFFSET);
+
+	/* create all primary partitions */
+	for (i = 0; i < 4 && i < count; i++, pt++) {
+		mbr_fill_pt_entry(pt, p[i].start, p[i].start, p[i].size,
+				  p[i].sys_ind, p[i].bootable);
+		if (is_extended(p[i].sys_ind)) {
+			ext_part_start = p[i].start;
+			ext_part_size = p[i].size;
+			ext_part_sect = p[i].start;
+		}
+	}
+
+	if (i < count && !ext_part_start) {
+		printf("%s: extended partition is needed for more than 4 partitions\n",
+		        __func__);
+		return -1;
+	}
+
+	/* write MBR */
+	if (blk_dwrite(dev, 0, 1, buffer) != 1) {
+		printf("%s: failed writing 'MBR' (1 blks@0x0)\n",
+		       __func__);
+		return -1;
+	}
+
+	/* create extended volumes */
+	for (; i < count; i++) {
+		lbaint_t next_ebr = 0;
+
+		memset(buffer, 0, dev->blksz);
+		buffer[DOS_PART_MAGIC_OFFSET] = 0x55;
+		buffer[DOS_PART_MAGIC_OFFSET + 1] = 0xaa;
+		pt = (dos_partition_t *) (buffer + DOS_PART_TBL_OFFSET);
+
+		mbr_fill_pt_entry(pt, p[i].start, p[i].start - ext_part_sect,
+				  p[i].size, p[i].sys_ind, p[i].bootable);
+
+		if (i + 1 < count) {
+			pt++;
+			next_ebr = p[i].start + p[i].size;
+			mbr_fill_pt_entry(pt, next_ebr,
+					  next_ebr - ext_part_start,
+					  p[i+1].start + p[i+1].size - next_ebr,
+					  DOS_PART_TYPE_EXTENDED, 0);
+		}
+
+		/* write EBR */
+		if (blk_dwrite(dev, ext_part_sect, 1, buffer) != 1) {
+			printf("%s: failed writing 'EBR' (1 blks@0x%lx)\n",
+			       __func__, ext_part_sect);
+			return -1;
+		}
+		ext_part_sect = next_ebr;
+	}
+
+	return 0;
+}
+
+int layout_mbr_partitions(struct disk_partition *p, int count,
+			  lbaint_t total_sectors)
+{
+	struct disk_partition *ext = NULL;
+	int i, j;
+	lbaint_t ext_vol_start;
+
+	/* calculate primary partitions start and size if needed */
+	if (!p[0].start)
+		p[0].start = DOS_PART_DEFAULT_GAP;
+	for (i = 0; i < 4 && i < count; i++) {
+		if (!p[i].start)
+			p[i].start = p[i - 1].start + p[i - 1].size;
+		if (!p[i].size) {
+			lbaint_t end = total_sectors;
+			lbaint_t allocated = 0;
+
+			for (j = i + 1; j < 4 && j < count; j++) {
+				if (p[j].start) {
+					end = p[j].start;
+					break;
+				}
+				allocated += p[j].size;
+			}
+			p[i].size = end - allocated - p[i].start;
+		}
+		if (p[i].sys_ind == 0x05)
+			ext = &p[i];
+	}
+
+	if (i >= 4 && !ext) {
+		printf("%s: extended partition is needed for more than 4 partitions\n",
+		        __func__);
+		return -1;
+	}
+
+	/* calculate extended volumes start and size if needed */
+	ext_vol_start = ext->start;
+	for (i = 4; i < count; i++) {
+		if (!p[i].start)
+			p[i].start = ext_vol_start + DOS_PART_DEFAULT_GAP;
+		if (!p[i].size) {
+			lbaint_t end = ext->start + ext->size;
+			lbaint_t allocated = 0;
+
+			for (j = i + 1; j < count; j++) {
+				if (p[j].start) {
+					end = p[j].start - DOS_PART_DEFAULT_GAP;
+					break;
+				}
+				allocated += p[j].size + DOS_PART_DEFAULT_GAP;
+			}
+			p[i].size = end - allocated - p[i].start;
+		}
+		ext_vol_start = p[i].start + p[i].size;
+	}
+
+	return 0;
+}
+#endif
+
 int write_mbr_sector(struct blk_desc *dev_desc, void *buf)
 {
 	if (is_valid_dos_buf(buf))
diff --git a/disk/part_dos.h b/disk/part_dos.h
index dd909a9317..5055822422 100644
--- a/disk/part_dos.h
+++ b/disk/part_dos.h
@@ -19,6 +19,8 @@
 #define DOS_PART_TYPE_EXTENDED_LBA	0x0F
 #define DOS_PART_TYPE_EXTENDED_LINUX	0x85
 
+#define DOS_PART_DEFAULT_GAP		2048
+
 typedef struct dos_partition {
 	unsigned char boot_ind;		/* 0x80 - active			*/
 	unsigned char head;		/* starting head			*/
diff --git a/include/part.h b/include/part.h
index 67b8b2a5cc..fac36364bd 100644
--- a/include/part.h
+++ b/include/part.h
@@ -474,6 +474,11 @@ int is_valid_dos_buf(void *buf);
  */
 int write_mbr_sector(struct blk_desc *dev_desc, void *buf);
 
+int write_mbr_partitions(struct blk_desc *dev,
+		struct disk_partition *p, int count, unsigned int disksig);
+int layout_mbr_partitions(struct disk_partition *p, int count,
+			  lbaint_t total_sectors);
+
 #endif
 
 
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 6/6] cmd: Add MBR partition layout control utility
       [not found]   ` <CGME20201223125535eucas1p12eefba574c1dad89834fa4e12ee35e56@eucas1p1.samsung.com>
@ 2020-12-23 12:55     ` Marek Szyprowski
  2021-01-16 16:25       ` Tom Rini
  0 siblings, 1 reply; 13+ messages in thread
From: Marek Szyprowski @ 2020-12-23 12:55 UTC (permalink / raw)
  To: u-boot

Add a 'mbr' command to let users create or verify MBR partition layout
based on the provided text description. The partition layout is
alternatively read from the '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 type). 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 an 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..2339162098
--- /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 users create or verify the MBR (Master Boot Record)
+partition layout based on the provided text description. The partition
+layout is alternatively read from the '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 type)
+
+If one wants to create more than 4 partitions, an 'Extended' primary
+partition (with 0x05 ID) has to be explicitly provided as a one of the
+first 4 entries.
+
+Here is an 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            |
++---+------------------------------+
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 1/6] disk: dos: rename write_mbr_partition to write_mbr_sector
  2020-12-23 12:55     ` [PATCH v3 1/6] disk: dos: rename write_mbr_partition to write_mbr_sector Marek Szyprowski
@ 2021-01-16 16:25       ` Tom Rini
  0 siblings, 0 replies; 13+ messages in thread
From: Tom Rini @ 2021-01-16 16:25 UTC (permalink / raw)
  To: u-boot

On Wed, Dec 23, 2020 at 01:55:10PM +0100, Marek Szyprowski wrote:

> write_mbr_partition() function name is a bit misleading, so rename it to
> write_mbr_sector(). This is a preparation for adding code for writing a
> complete MBR partition layout.
> 
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>

Applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 659 bytes
Desc: not available
URL: <https://lists.denx.de/pipermail/u-boot/attachments/20210116/dc693b9d/attachment.sig>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v3 2/6] disk: dos: add some defines for the hardcoded numbers
  2020-12-23 12:55     ` [PATCH v3 2/6] disk: dos: add some defines for the hardcoded numbers Marek Szyprowski
@ 2021-01-16 16:25       ` Tom Rini
  0 siblings, 0 replies; 13+ messages in thread
From: Tom Rini @ 2021-01-16 16:25 UTC (permalink / raw)
  To: u-boot

On Wed, Dec 23, 2020 at 01:55:11PM +0100, Marek Szyprowski wrote:

> Add some handy defines for some hardcoded magic numbers related to
> extended partition handling.
> 
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>

Applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 659 bytes
Desc: not available
URL: <https://lists.denx.de/pipermail/u-boot/attachments/20210116/cf43e9d5/attachment.sig>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v3 3/6] disk: dos: use generic macro for unaligned le32 access
  2020-12-23 12:55     ` [PATCH v3 3/6] disk: dos: use generic macro for unaligned le32 access Marek Szyprowski
@ 2021-01-16 16:25       ` Tom Rini
  0 siblings, 0 replies; 13+ messages in thread
From: Tom Rini @ 2021-01-16 16:25 UTC (permalink / raw)
  To: u-boot

On Wed, Dec 23, 2020 at 01:55:12PM +0100, Marek Szyprowski wrote:

> Use a generic helper for reading LE32 integers.
> 
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>

Applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 659 bytes
Desc: not available
URL: <https://lists.denx.de/pipermail/u-boot/attachments/20210116/3cd4e9cc/attachment.sig>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v3 4/6] disk: dos: make some functions static
  2020-12-23 12:55     ` [PATCH v3 4/6] disk: dos: make some functions static Marek Szyprowski
@ 2021-01-16 16:25       ` Tom Rini
  0 siblings, 0 replies; 13+ messages in thread
From: Tom Rini @ 2021-01-16 16:25 UTC (permalink / raw)
  To: u-boot

On Wed, Dec 23, 2020 at 01:55:13PM +0100, Marek Szyprowski wrote:

> Make functions not used outside this file static.
> 
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>

Applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 659 bytes
Desc: not available
URL: <https://lists.denx.de/pipermail/u-boot/attachments/20210116/9625564d/attachment-0001.sig>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v3 5/6] disk: dos: add code for creating MBR partition layout
  2020-12-23 12:55     ` [PATCH v3 5/6] disk: dos: add code for creating MBR partition layout Marek Szyprowski
@ 2021-01-16 16:25       ` Tom Rini
  0 siblings, 0 replies; 13+ messages in thread
From: Tom Rini @ 2021-01-16 16:25 UTC (permalink / raw)
  To: u-boot

On Wed, Dec 23, 2020 at 01:55:14PM +0100, Marek Szyprowski wrote:

> Add a code for creating and writing MBR partition layout. The code generates
> similar layout of EBRs (Exteneded Block Records) and logical volumes as
> Linux's fdisk utility.
> 
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>

Applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 659 bytes
Desc: not available
URL: <https://lists.denx.de/pipermail/u-boot/attachments/20210116/a81b61ee/attachment.sig>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v3 6/6] cmd: Add MBR partition layout control utility
  2020-12-23 12:55     ` [PATCH v3 6/6] cmd: Add MBR partition layout control utility Marek Szyprowski
@ 2021-01-16 16:25       ` Tom Rini
  0 siblings, 0 replies; 13+ messages in thread
From: Tom Rini @ 2021-01-16 16:25 UTC (permalink / raw)
  To: u-boot

On Wed, Dec 23, 2020 at 01:55:15PM +0100, Marek Szyprowski wrote:

> Add a 'mbr' command to let users create or verify MBR partition layout
> based on the provided text description. The partition layout is
> alternatively read from the '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 type). 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 an 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>

Applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 659 bytes
Desc: not available
URL: <https://lists.denx.de/pipermail/u-boot/attachments/20210116/9009d632/attachment.sig>

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2021-01-16 16:25 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CGME20201223125533eucas1p26a3a9fdce43c0902e8ee3c033cb510b0@eucas1p2.samsung.com>
2020-12-23 12:55 ` [PATCH v3 0/6] Add MBR partition table creation and verify command Marek Szyprowski
     [not found]   ` <CGME20201223125533eucas1p24c90762deb359fc4c73ddb717892c932@eucas1p2.samsung.com>
2020-12-23 12:55     ` [PATCH v3 1/6] disk: dos: rename write_mbr_partition to write_mbr_sector Marek Szyprowski
2021-01-16 16:25       ` Tom Rini
     [not found]   ` <CGME20201223125534eucas1p2388f9e307ba4fdb85ba1dfea6184e60f@eucas1p2.samsung.com>
2020-12-23 12:55     ` [PATCH v3 2/6] disk: dos: add some defines for the hardcoded numbers Marek Szyprowski
2021-01-16 16:25       ` Tom Rini
     [not found]   ` <CGME20201223125534eucas1p12cb4b6a480be29f0101e5cd953d1ce02@eucas1p1.samsung.com>
2020-12-23 12:55     ` [PATCH v3 3/6] disk: dos: use generic macro for unaligned le32 access Marek Szyprowski
2021-01-16 16:25       ` Tom Rini
     [not found]   ` <CGME20201223125534eucas1p17107d79af8457f52a5536084f9b903b9@eucas1p1.samsung.com>
2020-12-23 12:55     ` [PATCH v3 4/6] disk: dos: make some functions static Marek Szyprowski
2021-01-16 16:25       ` Tom Rini
     [not found]   ` <CGME20201223125535eucas1p2358eef28313de969c15405450a5b9acf@eucas1p2.samsung.com>
2020-12-23 12:55     ` [PATCH v3 5/6] disk: dos: add code for creating MBR partition layout Marek Szyprowski
2021-01-16 16:25       ` Tom Rini
     [not found]   ` <CGME20201223125535eucas1p12eefba574c1dad89834fa4e12ee35e56@eucas1p1.samsung.com>
2020-12-23 12:55     ` [PATCH v3 6/6] cmd: Add MBR partition layout control utility Marek Szyprowski
2021-01-16 16:25       ` Tom Rini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.