From 5c783b54d605aa21c8e3e0e188ab99d58135addd Mon Sep 17 00:00:00 2001 From: Philippe Reynes Date: Fri, 22 Apr 2022 17:46:48 +0200 Subject: [PATCH 1/4] disk: part_efi: add support to repair gpt table If a gpt table is corrupted (after a power cut for example), then the gpt table should repaired. The function gpt_repair_headers check if at least one gpt table is valid, and then only write the corrupted gpt table. Signed-off-by: Philippe Reynes --- disk/part_efi.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++ include/part.h | 10 ++++++ 2 files changed, 96 insertions(+) diff --git a/disk/part_efi.c b/disk/part_efi.c index f1f3e5bcef..829ccb6bd1 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 3a6958dcb2..6f604e7315 100644 --- a/include/part.h +++ b/include/part.h @@ -466,6 +466,16 @@ int write_mbr_and_gpt_partitions(struct blk_desc *dev_desc, void *buf); 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 From 26f404c7665265946305f2883cfad1b785d35bb2 Mon Sep 17 00:00:00 2001 From: Philippe Reynes Date: Fri, 22 Apr 2022 17:46:49 +0200 Subject: [PATCH 2/4] cmd: gpt: add subcommand repair Adds a sub-command repair to the command gpt that allow to repair a corrupted gpt table. If the both gpt table (primary and backup) are valid, then the command does nothing. Signed-off-by: Philippe Reynes --- cmd/gpt.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/cmd/gpt.c b/cmd/gpt.c index 1c0525fbf6..007a68eaa7 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" From b6b6a906469ab11f460b493a5ecca8160393bfad Mon Sep 17 00:00:00 2001 From: Philippe Reynes Date: Fri, 22 Apr 2022 17:46:50 +0200 Subject: [PATCH 3/4] test: py: tests: test_gpt.py: add a simple test for the command gpt repair Adds a simple test for the command gpt repair. Signed-off-by: Philippe Reynes --- test/py/tests/test_gpt.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 229d7eb2c2..f707d9f253 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -98,6 +98,16 @@ def test_gpt_verify(state_disk_image, u_boot_console): output = u_boot_console.run_command('gpt verify host 0') assert 'Verify GPT: success!' in output +@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') From 9ac4c2bfe9f502549362c6d394c7024236146a5b Mon Sep 17 00:00:00 2001 From: John Keeping Date: Wed, 20 Apr 2022 11:31:11 +0100 Subject: [PATCH 4/4] fdt: don't set linux,phandle This has been deprecated for over 10 years and everything now uses the plain "phandle" property in preference. There's no need to set linux,phandle when creating phandles for nodes that do not have one. dtc changed the default to creating just phandle in version 1.4.5 released in September 2017 with the justification that the new style had already been supported for 7 years by that point (see dtc commit 0016f8c ("dtc: change default phandles to ePAPR style instead of both")). Signed-off-by: John Keeping --- common/fdt_support.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/common/fdt_support.c b/common/fdt_support.c index 8662bd27a4..7e9e654204 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; }