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(dev, i + 1, &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"