diff options
-rw-r--r-- | cmd/gpt.c | 16 | ||||
-rw-r--r-- | common/fdt_support.c | 8 | ||||
-rw-r--r-- | disk/part_efi.c | 86 | ||||
-rw-r--r-- | include/part.h | 10 | ||||
-rw-r--r-- | test/py/tests/test_gpt.py | 10 |
5 files changed, 121 insertions, 9 deletions
diff --git a/cmd/gpt.c b/cmd/gpt.c index 1c0525fbf62..007a68eaa72 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -586,6 +586,15 @@ err: return errno; } +static int gpt_repair(struct blk_desc *blk_dev_desc) +{ + int ret = 0; + + ret = gpt_repair_headers(blk_dev_desc); + + return ret; +} + static int gpt_default(struct blk_desc *blk_dev_desc, const char *str_part) { int ret; @@ -997,7 +1006,10 @@ static int do_gpt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) return CMD_RET_FAILURE; } - if ((strcmp(argv[1], "write") == 0) && (argc == 5)) { + if (strcmp(argv[1], "repair") == 0) { + printf("Repairing GPT: "); + ret = gpt_repair(blk_dev_desc); + } else if ((strcmp(argv[1], "write") == 0) && (argc == 5)) { printf("Writing GPT: "); ret = gpt_default(blk_dev_desc, argv[4]); } else if ((strcmp(argv[1], "verify") == 0)) { @@ -1036,6 +1048,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " Restore or verify GPT information on a device connected\n" " to interface\n" " Example usage:\n" + " gpt repair mmc 0\n" + " - repair the GPT on the device\n" " gpt write mmc 0 $partitions\n" " - write the GPT to device\n" " gpt verify mmc 0 $partitions\n" diff --git a/common/fdt_support.c b/common/fdt_support.c index 8662bd27a47..7e9e6542041 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -1544,14 +1544,6 @@ int fdt_set_phandle(void *fdt, int nodeoffset, uint32_t phandle) #endif ret = fdt_setprop_cell(fdt, nodeoffset, "phandle", phandle); - if (ret < 0) - return ret; - - /* - * For now, also set the deprecated "linux,phandle" property, so that we - * don't break older kernels. - */ - ret = fdt_setprop_cell(fdt, nodeoffset, "linux,phandle", phandle); return ret; } diff --git a/disk/part_efi.c b/disk/part_efi.c index f1f3e5bceff..829ccb6bd17 100644 --- a/disk/part_efi.c +++ b/disk/part_efi.c @@ -705,6 +705,92 @@ int gpt_verify_headers(struct blk_desc *dev_desc, gpt_header *gpt_head, return 0; } +static void restore_primary_gpt_header(gpt_header *gpt_h, struct blk_desc *dev_desc) +{ + u32 calc_crc32; + u64 val; + + /* recalculate the values for the Primary GPT Header */ + val = le64_to_cpu(gpt_h->my_lba); + gpt_h->my_lba = gpt_h->alternate_lba; + gpt_h->alternate_lba = cpu_to_le64(val); + gpt_h->partition_entry_lba = cpu_to_le64(partition_entries_offset(dev_desc)); + + gpt_h->header_crc32 = 0; + + calc_crc32 = efi_crc32((const unsigned char *)gpt_h, + le32_to_cpu(gpt_h->header_size)); + gpt_h->header_crc32 = cpu_to_le32(calc_crc32); +} + +static int write_one_gpt_table(struct blk_desc *dev_desc, + gpt_header *gpt_h, gpt_entry *gpt_e) +{ + const int pte_blk_cnt = BLOCK_CNT((gpt_h->num_partition_entries + * sizeof(gpt_entry)), dev_desc); + lbaint_t start; + int ret = 0; + + start = le64_to_cpu(gpt_h->my_lba); + if (blk_dwrite(dev_desc, start, 1, gpt_h) != 1) { + ret = -1; + goto out; + } + + start = le64_to_cpu(gpt_h->partition_entry_lba); + if (blk_dwrite(dev_desc, start, pte_blk_cnt, gpt_e) != pte_blk_cnt) { + ret = -1; + goto out; + } + + out: + return ret; +} + +int gpt_repair_headers(struct blk_desc *dev_desc) +{ + ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_h1, 1, dev_desc->blksz); + ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_h2, 1, dev_desc->blksz); + gpt_entry *gpt_e1 = NULL, *gpt_e2 = NULL; + int is_gpt1_valid, is_gpt2_valid; + int ret = -1; + + is_gpt1_valid = is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA, + gpt_h1, &gpt_e1); + is_gpt2_valid = is_gpt_valid(dev_desc, dev_desc->lba - 1, + gpt_h2, &gpt_e2); + + if (is_gpt1_valid && is_gpt2_valid) { + ret = 0; + goto out; + } + + if (is_gpt1_valid && !is_gpt2_valid) { + prepare_backup_gpt_header(gpt_h1); + ret = write_one_gpt_table(dev_desc, gpt_h1, gpt_e1); + goto out; + } + + if (!is_gpt1_valid && is_gpt2_valid) { + restore_primary_gpt_header(gpt_h2, dev_desc); + ret = write_one_gpt_table(dev_desc, gpt_h2, gpt_e2); + goto out; + } + + if (!is_gpt1_valid && !is_gpt2_valid) { + ret = -1; + goto out; + } + + out: + if (is_gpt1_valid) + free(gpt_e1); + if (is_gpt2_valid) + free(gpt_e2); + + return ret; +} + int gpt_verify_partitions(struct blk_desc *dev_desc, struct disk_partition *partitions, int parts, gpt_header *gpt_head, gpt_entry **gpt_pte) diff --git a/include/part.h b/include/part.h index 3a6958dcb2a..6f604e7315a 100644 --- a/include/part.h +++ b/include/part.h @@ -467,6 +467,16 @@ int gpt_verify_headers(struct blk_desc *dev_desc, gpt_header *gpt_head, gpt_entry **gpt_pte); /** + * gpt_repair_headers() - Function to repair the GPT's header + * and partition table entries (PTE) + * + * @param dev_desc - block device descriptor + * + * Return: - '0' on success, otherwise error + */ +int gpt_repair_headers(struct blk_desc *dev_desc); + +/** * gpt_verify_partitions() - Function to check if partitions' name, start and * size correspond to '$partitions' env variable * diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 229d7eb2c21..f707d9f2534 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -101,6 +101,16 @@ def test_gpt_verify(state_disk_image, u_boot_console): @pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt') @pytest.mark.requiredtool('sgdisk') +def test_gpt_repair(state_disk_image, u_boot_console): + """Test the gpt repair command.""" + + u_boot_console.run_command('host bind 0 ' + state_disk_image.path) + output = u_boot_console.run_command('gpt repair host 0') + assert 'Repairing GPT: success!' in output + +@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('cmd_gpt') +@pytest.mark.requiredtool('sgdisk') def test_gpt_guid(state_disk_image, u_boot_console): """Test the gpt guid command.""" |