lib_test_gpt_blksz() drives gpt_fill_header() and gpt_fill_pte() with a synthetic struct blk_desc. That is what lets it sweep block sizes no real device here can provide, but it also means it cannot reach anything that touches the medium, so the protective MBR, the header CRCs and every conversion behind them go unchecked.
Add a companion test that backs a blkmap device with plain memory, writes a table with gpt_restore(), reads it back with gpt_verify_partitions() and parses it with part_get_info(), then checks that the backup header really did land in the last block. That covers set_protective_mbr(), is_pmbr_valid(), gpt_verify_headers(), is_gpt_valid() and part_get_info_efi(). The two tests are complementary rather than alternatives: gpt_blksz covers the block size arithmetic across sizes a device cannot easily offer, gpt_blkmap covers the read and write paths a synthetic descriptor cannot reach. Neither replaces the sandbox tests in test/py/tests/test_gpt.py, which exercise the gpt command against images built by sgdisk. A blkmap needs no host filesystem, so unlike 'host bind' this runs on QEMU and on real hardware, which is what makes big-endian coverage possible. Every blkmap is DEFAULT_BLKSZ today, so the block size stays a parameter of the case table with a single entry, ready for a second one should blkmap ever learn to be created with a block size. Signed-off-by: Alexey Charkov <[email protected]> --- test/lib/part_efi.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) diff --git a/test/lib/part_efi.c b/test/lib/part_efi.c index 75de002278f3..d913ca701825 100644 --- a/test/lib/part_efi.c +++ b/test/lib/part_efi.c @@ -4,6 +4,9 @@ * Tests for the GPT layout helpers in disk/part_efi.c */ +#include <blk.h> +#include <blkmap.h> +#include <dm.h> #include <malloc.h> #include <memalign.h> #include <part.h> @@ -111,3 +114,144 @@ static int lib_test_gpt_blksz(struct unit_test_state *uts) return 0; } LIB_TEST(lib_test_gpt_blksz, 0); + +#if CONFIG_IS_ENABLED(BLKMAP) + +#define GPT_TEST_LABEL "gpttest" + +/** + * gpt_blkmap_create() - back a blkmap device with freshly allocated memory + * + * @uts: test state + * @blksz: requested block size + * @lba: size of the device in blocks + * @bufp: returns the backing buffer, to be freed by the caller + * @devp: returns the blkmap device + * Return: 0 if OK, other value on error + */ +static int gpt_blkmap_create(struct unit_test_state *uts, unsigned long blksz, + lbaint_t lba, void **bufp, struct udevice **devp) +{ + struct udevice *dev; + void *buf; + + /* + * blkmap devices are fixed at DEFAULT_BLKSZ, so this is the only size + * that can be asked for today. Once blkmap can be created with a block + * size, pass it through here and the cases below cover 4096 as well. + */ + ut_asserteq(DEFAULT_BLKSZ, blksz); + + buf = memalign(ARCH_DMA_MINALIGN, lba * blksz); + ut_assertnonnull(buf); + memset(buf, '\0', lba * blksz); + + ut_assertok(blkmap_create(GPT_TEST_LABEL, &dev)); + ut_assertok(blkmap_map_mem(dev, 0, lba, buf)); + + *bufp = buf; + *devp = dev; + + return 0; +} + +/* + * Write a GPT to a real block device, then read it back the way the rest of + * U-Boot does. gpt_verify_partitions() and part_get_info() both start by + * reading blocks, so neither is reachable from lib_test_gpt_blksz(), which has + * only a synthetic descriptor. Backing the device with memory through blkmap + * keeps this runnable anywhere rather than on sandbox alone. + */ +static int lib_test_gpt_blkmap(struct unit_test_state *uts) +{ + static const struct { + unsigned long blksz; + lbaint_t lba; + } cases[] = { + /* + * Keep the disk small: the backing memory comes out of the + * malloc pool, which is only a few MB on boards like malta. + * Add a 4096-byte case here once blkmap can be created with a + * block size. + */ + { 512, 0x400 }, + }; + + char str_disk_guid[UUID_STR_LEN + 1] = + "8d60b397-1bb6-4d33-80ee-b1587d24c2f8"; + struct disk_partition parts[2], info; + struct udevice *dev, *blk; + struct blk_desc *desc; + gpt_header *gpt_head; + gpt_entry *gpt_pte; + void *buf; + int i; + + for (i = 0; i < ARRAY_SIZE(cases); i++) { + ut_assertok(gpt_blkmap_create(uts, cases[i].blksz, + cases[i].lba, &buf, &dev)); + ut_assertok(blk_get_from_parent(dev, &blk)); + desc = dev_get_uclass_plat(blk); + + ut_asserteq(cases[i].blksz, desc->blksz); + ut_asserteq_64(cases[i].lba, desc->lba); + + gpt_head = malloc_cache_aligned(PAD_TO_BLOCKSIZE + (sizeof(gpt_header), desc)); + ut_assertnonnull(gpt_head); + + /* two partitions, the second one running to the end */ + memset(parts, '\0', sizeof(parts)); + strcpy((char *)parts[0].name, "first"); + strcpy((char *)parts[1].name, "second"); + parts[0].size = 0x100; + parts[1].size = 0x100; + disk_partition_set_uuid(&parts[0], + "a2a0d0eb-e5b9-3344-87c0-68b6b72699c7"); + disk_partition_set_uuid(&parts[1], + "a2a0d0eb-e5b9-3344-87c0-68b6b72699c8"); + + ut_assertok(gpt_restore(desc, str_disk_guid, parts, 2)); + + /* + * Read the table back and compare it against the layout it was + * asked for. This walks gpt_verify_headers() and is_gpt_valid() + * on the way, so it covers the header fields those two convert. + */ + gpt_pte = NULL; + ut_assertok(gpt_verify_partitions(desc, parts, 2, gpt_head, + &gpt_pte)); + free(gpt_pte); + + /* + * And parse it the way every other user of a disk does. Clear + * the existing partition type to force part_init() to guess it + * anew, otherwise whatever stale state remains sticks across + * the part_init() call + */ + desc->part_type = PART_TYPE_UNKNOWN; + part_init(desc); + ut_asserteq(PART_TYPE_EFI, desc->part_type); + ut_assertok(part_get_info(desc, 1, &info)); + ut_asserteq_64(parts[0].size, info.size); + ut_assertok(part_get_info(desc, 2, &info)); + ut_asserteq_64(parts[1].size, info.size); + + /* the backup header has to be in the very last block */ + ut_asserteq(1, blk_dread(desc, cases[i].lba - 1, 1, gpt_head)); + ut_asserteq_64(GPT_HEADER_SIGNATURE_UBOOT, + le64_to_cpu(gpt_head->signature)); + ut_asserteq_64(cases[i].lba - 1, + le64_to_cpu(gpt_head->my_lba)); + ut_asserteq_64(1, le64_to_cpu(gpt_head->alternate_lba)); + + free(gpt_head); + ut_assertok(blkmap_destroy(dev)); + free(buf); + } + + return 0; +} +LIB_TEST(lib_test_gpt_blkmap, 0); + +#endif /* BLKMAP */ -- 2.55.0
