1 // SPDX-License-Identifier: GPL-2.0+
3 * cmd_mbr.c -- MBR (Master Boot Record) handling command
5 * Copyright (C) 2020 Samsung Electronics
6 * author: Marek Szyprowski <m.szyprowski@samsung.com>
8 * based on the gpt command.
18 * extract_val() - Extract a value from the key=value pair list
19 * @str: pointer to string with key=values pairs
20 * @key: pointer to the key to search for
22 * The list of parameters is come separated, only a value for
23 * the given key is returend.
25 * Function allocates memory for the value, remember to free!
27 * Return: Pointer to allocated string with the value.
29 static char *extract_val(const char *str
, const char *key
)
35 strcopy
= strdup(str
);
47 if (strcmp(k
, key
) == 0) {
59 * found_key() - Search for a key without a value in the parameter list
60 * @str: pointer to string with key
61 * @key: pointer to the key to search for
63 * The list of parameters is come separated.
65 * Return: True if key has been found.
67 static bool found_key(const char *str
, const char *key
)
73 strcopy
= strdup(str
);
82 if (strcmp(k
, key
) == 0) {
93 static int str_to_partitions(const char *str_part
, int blksz
,
94 unsigned long *disk_uuid
, struct disk_partition
**partitions
,
101 struct disk_partition
*parts
;
103 uint64_t size_ll
, start_ll
;
105 if (str_part
== NULL
)
108 str
= strdup(str_part
);
112 /* extract disk guid */
114 val
= extract_val(str
, "uuid_disk");
116 val
= strsep(&val
, ";");
118 *disk_uuid
= ustrtoull(p
, &p
, 0);
120 /* Move s to first partition */
124 printf("Error: is the partitions string NULL-terminated?\n");
128 /* remove the optional semicolon at the end of the string */
133 /* calculate expected number of partitions */
141 /* allocate memory for partitions */
142 parts
= calloc(sizeof(struct disk_partition
), p_count
);
146 /* retrieve partitions data from string */
147 for (i
= 0; i
< p_count
; i
++) {
148 tok
= strsep(&s
, ";");
154 val
= extract_val(tok
, "size");
155 if (!val
) { /* 'size' is mandatory */
160 if ((strcmp(p
, "-") == 0)) {
161 /* auto extend the size */
164 size_ll
= ustrtoull(p
, &p
, 0);
165 parts
[i
].size
= size_ll
/ blksz
;
170 val
= extract_val(tok
, "start");
171 if (val
) { /* start address is optional */
173 start_ll
= ustrtoull(p
, &p
, 0);
174 parts
[i
].start
= start_ll
/ blksz
;
179 val
= extract_val(tok
, "id");
180 if (!val
) { /* '' is mandatory */
185 parts
[i
].sys_ind
= ustrtoul(p
, &p
, 0);
189 if (found_key(tok
, "bootable"))
190 parts
[i
].bootable
= PART_BOOTABLE
;
193 *parts_count
= p_count
;
205 static int do_write_mbr(struct blk_desc
*dev
, const char *str
)
207 unsigned long disk_uuid
= 0;
208 struct disk_partition
*partitions
;
209 int blksz
= dev
->blksz
;
212 if (str_to_partitions(str
, blksz
, &disk_uuid
, &partitions
, &count
)) {
213 printf("MBR: failed to setup partitions from \"%s\"\n", str
);
217 if (layout_mbr_partitions(partitions
, count
, dev
->lba
)) {
218 printf("MBR: failed to layout partitions on the device\n");
223 if (write_mbr_partitions(dev
, partitions
, count
, disk_uuid
)) {
224 printf("MBR: failed to write partitions to the device\n");
232 static int do_verify_mbr(struct blk_desc
*dev
, const char *str
)
234 unsigned long disk_uuid
= 0;
235 struct disk_partition
*partitions
;
236 int blksz
= dev
->blksz
;
237 int count
, i
, ret
= 1;
239 if (str_to_partitions(str
, blksz
, &disk_uuid
, &partitions
, &count
)) {
240 printf("MBR: failed to setup partitions from \"%s\"\n", str
);
244 for (i
= 0; i
< count
; i
++) {
245 struct disk_partition p
;
247 if (part_get_info_by_type(dev
, i
+ 1, PART_TYPE_DOS
, &p
))
250 if ((partitions
[i
].size
&& p
.size
!= partitions
[i
].size
) ||
251 (partitions
[i
].start
&& p
.start
!= partitions
[i
].start
) ||
252 p
.sys_ind
!= partitions
[i
].sys_ind
)
261 static int do_mbr(struct cmd_tbl
*cmdtp
, int flag
, int argc
, char *const argv
[])
263 const char *parts
= NULL
;
264 int ret
= CMD_RET_SUCCESS
;
267 struct blk_desc
*blk_dev_desc
= NULL
;
269 if (argc
!= 4 && argc
!= 5)
270 return CMD_RET_USAGE
;
272 dev
= (int)dectoul(argv
[3], &ep
);
273 if (!ep
|| ep
[0] != '\0') {
274 printf("'%s' is not a number\n", argv
[3]);
275 return CMD_RET_USAGE
;
277 blk_dev_desc
= blk_get_dev(argv
[2], dev
);
279 printf("%s: %s dev %d NOT available\n",
280 __func__
, argv
[2], dev
);
281 return CMD_RET_FAILURE
;
284 if ((strcmp(argv
[1], "write") == 0)) {
285 parts
= (argc
== 5) ? argv
[4] : env_get("mbr_parts");
286 printf("MBR: write ");
287 ret
= do_write_mbr(blk_dev_desc
, parts
);
288 } else if ((strcmp(argv
[1], "verify") == 0)) {
289 printf("MBR: verify ");
290 parts
= (argc
== 5) ? argv
[4] : env_get("mbr_parts");
291 ret
= do_verify_mbr(blk_dev_desc
, parts
);
293 return CMD_RET_USAGE
;
298 return CMD_RET_FAILURE
;
301 printf("success!\n");
302 return CMD_RET_SUCCESS
;
305 U_BOOT_CMD(mbr
, CONFIG_SYS_MAXARGS
, 1, do_mbr
,
306 "MBR (Master Boot Record)",
307 "<command> <interface> <dev> <partitions_list>\n"
308 " - MBR partition table restoration utility\n"
309 " Restore or check partition information on a device connected\n"
310 " to the given block interface\n"
312 " mbr write mmc 0 [\"${mbr_parts}\"]\n"
313 " mbr verify mmc 0 [\"${partitions}\"]\n"