| // SPDX-License-Identifier: GPL-2.0-or-later | |
| /* | |
| * Tests for zip/unzip/gzwrite commands | |
| * | |
| * Copyright 2026, Marek Vasut <marek.vasut+renesas@mailbox.org> | |
| */ | |
| #include <command.h> | |
| #include <env.h> | |
| #include <dm.h> | |
| #include <dm/lists.h> | |
| #include <dm/test.h> | |
| #include <linux/sizes.h> | |
| #include <mapmem.h> | |
| #include <part.h> | |
| #include <test/cmd.h> | |
| #include <test/test.h> | |
| #include <test/ut.h> | |
| #include <u-boot/crc.h> | |
| /* sys/random.h is not accessible */ | |
| extern ssize_t getrandom(void *buf, size_t size, unsigned int flags); | |
| static const ssize_t sizes[] = { 32, SZ_1K, SZ_4K, SZ_1M, SZ_16M, SZ_1M - 1, SZ_1M + 1, 6758401 }; | |
| static int do_test_cmd_zip_unzip(struct unit_test_state *uts, ssize_t size, | |
| const bool gzwrite) | |
| { | |
| unsigned long loadaddr = env_get_ulong("loadaddr", 16, 0); | |
| unsigned long encaddr = loadaddr + size + 0x10000; | |
| unsigned long decaddr = encaddr + size + 0x10000; | |
| unsigned char *loadmap = map_sysmem(loadaddr, size); | |
| unsigned char *decmap = map_sysmem(decaddr, size); | |
| unsigned char *encmap = map_sysmem(encaddr, size); | |
| /* | |
| * Prepare three buffers, $loadadd, $encaddr, $decaddr, and | |
| * fill them all with random data. Add slight space between | |
| * the compressed buffer 'encaddr' and uncompressed buffer | |
| * 'decaddr', because the compressed data with gzip header | |
| * might be longer than uncompressed source data 'loadaddr', | |
| * and if the uncompressed data buffer 'decaddr' followed | |
| * 'encaddr', the decompression could corrupt end of 'encaddr' | |
| * buffer. | |
| */ | |
| ut_assert(getrandom(loadmap, size, 0) == size); | |
| ut_assert(getrandom(decmap, size, 0) == size); | |
| ut_assert(getrandom(encmap, size, 0) == size); | |
| /* Compress data in $loadaddr into $encaddr */ | |
| ut_assertok(run_commandf("zip $loadaddr %zx %zx", size, encaddr)); | |
| console_record_readline(uts->actual_str, sizeof(uts->actual_str)); | |
| ut_assert(strstr(uts->actual_str, "Compressed size: ")); | |
| if (gzwrite) { | |
| unsigned int sectsize = DIV_ROUND_UP(size, 512); | |
| u32 crc = crc32(0, loadmap, size); | |
| struct blk_desc *mmc_dev_desc; | |
| ut_assertok(run_commandf("gzwrite mmc 9 %zx $filesize", encaddr)); | |
| ut_assert_skip_to_line("\t%zu bytes, crc 0x%08x", size, crc); | |
| ut_asserteq(9, blk_get_device_by_str("mmc", "9", &mmc_dev_desc)); | |
| ut_assertok(run_commandf("mmc dev 9")); | |
| ut_assert_nextline("switch to partitions #0, OK"); | |
| ut_assert_nextline("mmc9 is current device"); | |
| ut_assertok(run_commandf("mmc read %zx 0 %x", decaddr, sectsize)); | |
| ut_assert_nextline("MMC read: dev # 9, block # 0, count %u ... %u blocks read: OK", | |
| sectsize, sectsize); | |
| } else { | |
| /* Decompress data in $encaddr into $decaddr */ | |
| ut_assertok(run_commandf("unzip %zx %zx $filesize", encaddr, decaddr)); | |
| ut_assert_nextline("Uncompressed size: %zu = 0x%zX", size, size); | |
| } | |
| /* Input data and compressed-decompressed data */ | |
| ut_asserteq_mem(loadmap, decmap, size); | |
| ut_assert_console_end(); | |
| unmap_sysmem(loadmap); | |
| unmap_sysmem(decmap); | |
| unmap_sysmem(encmap); | |
| return 0; | |
| } | |
| static int dm_test_cmd_zip_unzip(struct unit_test_state *uts) | |
| { | |
| int i, ret; | |
| for (i = 0; i < ARRAY_SIZE(sizes); i++) { | |
| ret = do_test_cmd_zip_unzip(uts, sizes[i], false); | |
| if (ret) | |
| return ret; | |
| } | |
| return 0; | |
| } | |
| DM_TEST(dm_test_cmd_zip_unzip, UTF_CONSOLE); | |
| static int dm_test_cmd_zip_gzwrite(struct unit_test_state *uts) | |
| { | |
| struct udevice *dev; | |
| ofnode root, node; | |
| int i, j, ret; | |
| /* Enable the mmc9 node for this test */ | |
| root = oftree_root(oftree_default()); | |
| node = ofnode_find_subnode(root, "mmc9"); | |
| ut_assert(ofnode_valid(node)); | |
| ut_assertok(lists_bind_fdt(gd->dm_root, node, &dev, NULL, false)); | |
| for (i = 0; i < ARRAY_SIZE(sizes); i++) { | |
| ret = do_test_cmd_zip_unzip(uts, sizes[i], true); | |
| if (ret) | |
| return ret; | |
| } | |
| /* Test various sizes of decompression chunk sizes */ | |
| for (j = 0; j < ARRAY_SIZE(sizes); j++) { | |
| env_set_ulong("gzwrite_chunk", sizes[j]); | |
| for (i = 0; i < ARRAY_SIZE(sizes); i++) { | |
| ret = do_test_cmd_zip_unzip(uts, sizes[i], true); | |
| if (ret) | |
| return ret; | |
| } | |
| } | |
| return 0; | |
| } | |
| DM_TEST(dm_test_cmd_zip_gzwrite, UTF_CONSOLE); |