/* $NetBSD: dtbs_equal_unordered.c,v 1.1.1.3 2019/12/22 12:34:06 skrll Exp $ */ // SPDX-License-Identifier: LGPL-2.1-or-later /* * libfdt - Flat Device Tree manipulation * Tests if two given dtbs are structurally equal (including order) * Copyright (C) 2007 David Gibson, IBM Corporation. */ #include #include #include #include #include #include #include "tests.h" #include "testdata.h" static int notequal; /* = 0 */ static int ignore_memrsv; /* = 0 */ #define MISMATCH(fmt, ...) \ do { \ if (notequal) \ PASS(); \ else \ FAIL(fmt, ##__VA_ARGS__); \ } while (0) #define MATCH() \ do { \ if (!notequal) \ PASS(); \ else \ FAIL("Trees match which shouldn't"); \ } while (0) #define CHECK(code) \ { \ err = (code); \ if (err) \ FAIL(#code ": %s", fdt_strerror(err)); \ } static int mem_rsv_cmp(const void *p1, const void *p2) { const struct fdt_reserve_entry *re1 = p1; const struct fdt_reserve_entry *re2 = p2; if (fdt64_to_cpu(re1->address) < fdt64_to_cpu(re2->address)) return -1; else if (fdt64_to_cpu(re1->address) > fdt64_to_cpu(re2->address)) return 1; if (fdt64_to_cpu(re1->size) < fdt64_to_cpu(re2->size)) return -1; else if (fdt64_to_cpu(re1->size) > fdt64_to_cpu(re2->size)) return 1; return 0; } static void compare_mem_rsv(void *fdt1, void *fdt2) { int i; uint64_t addr1, size1, addr2, size2; int err; if (fdt_num_mem_rsv(fdt1) != fdt_num_mem_rsv(fdt2)) MISMATCH("Trees have different number of reserve entries"); qsort((char *)fdt1 + fdt_off_mem_rsvmap(fdt1), fdt_num_mem_rsv(fdt1), sizeof(struct fdt_reserve_entry), mem_rsv_cmp); qsort((char *)fdt2 + fdt_off_mem_rsvmap(fdt2), fdt_num_mem_rsv(fdt2), sizeof(struct fdt_reserve_entry), mem_rsv_cmp); for (i = 0; i < fdt_num_mem_rsv(fdt1); i++) { CHECK(fdt_get_mem_rsv(fdt1, i, &addr1, &size1)); CHECK(fdt_get_mem_rsv(fdt2, i, &addr2, &size2)); if ((addr1 != addr2) || (size1 != size2)) MISMATCH("Mismatch in reserve entry %d: " "(0x%llx, 0x%llx) != (0x%llx, 0x%llx)", i, (unsigned long long)addr1, (unsigned long long)size1, (unsigned long long)addr2, (unsigned long long)size2); } } static void compare_properties(const void *fdt1, int offset1, const void *fdt2, int offset2) { int offset = offset1; /* Check the properties */ for (offset = fdt_first_property_offset(fdt1, offset1); offset >= 0; offset = fdt_next_property_offset(fdt1, offset)) { const char *name; int len1, len2; const void *data1, *data2; int i; data1 = fdt_getprop_by_offset(fdt1, offset, &name, &len1); if (!data1) FAIL("fdt_getprop_by_offset(): %s\n", fdt_strerror(len1)); verbose_printf("Property '%s'\n", name); data2 = fdt_getprop(fdt2, offset2, name, &len2); if (!data2) { if (len2 == -FDT_ERR_NOTFOUND) MISMATCH("Property '%s' missing\n", name); else FAIL("fdt_get_property(): %s\n", fdt_strerror(len2)); } verbose_printf("len1=%d data1=", len1); for (i = 0; i < len1; i++) verbose_printf(" %02x", ((const char *)data1)[i]); verbose_printf("\nlen2=%d data2=", len2); for (i = 0; i < len1; i++) verbose_printf(" %02x", ((const char *)data2)[i]); verbose_printf("\n"); if (len1 != len2) MISMATCH("Property '%s' mismatched length %d vs. %d\n", name, len1, len2); else if (memcmp(data1, data2, len1) != 0) MISMATCH("Property '%s' mismatched value\n", name); } } static void compare_node(const void *fdt1, int offset1, const void *fdt2, int offset2); static void compare_subnodes(const void *fdt1, int offset1, const void *fdt2, int offset2, int recurse) { int coffset1, coffset2, depth; for (depth = 0, coffset1 = offset1; (coffset1 >= 0) && (depth >= 0); coffset1 = fdt_next_node(fdt1, coffset1, &depth)) if (depth == 1) { const char *name = fdt_get_name(fdt1, coffset1, NULL); verbose_printf("Subnode %s\n", name); coffset2 = fdt_subnode_offset(fdt2, offset2, name); if (coffset2 == -FDT_ERR_NOTFOUND) MISMATCH("Subnode %s missing\n", name); else if (coffset2 < 0) FAIL("fdt_subnode_offset(): %s\n", fdt_strerror(coffset2)); if (recurse) compare_node(fdt1, coffset1, fdt2, coffset2); } } static void compare_node(const void *fdt1, int offset1, const void *fdt2, int offset2) { int err; char path1[PATH_MAX], path2[PATH_MAX]; CHECK(fdt_get_path(fdt1, offset1, path1, sizeof(path1))); CHECK(fdt_get_path(fdt2, offset2, path2, sizeof(path2))); if (!streq(path1, path2)) TEST_BUG("Path mismatch %s vs. %s\n", path1, path2); verbose_printf("Checking %s\n", path1); compare_properties(fdt1, offset1, fdt2, offset2); compare_properties(fdt2, offset2, fdt1, offset1); compare_subnodes(fdt1, offset1, fdt2, offset2, 1); compare_subnodes(fdt2, offset2, fdt1, offset1, 0); } static void badargs(char **argv) { CONFIG("Usage: %s [-n] [-m] ", argv[0]); } int main(int argc, char *argv[]) { void *fdt1, *fdt2; uint32_t cpuid1, cpuid2; char **args; int argsleft; test_init(argc, argv); args = &argv[1]; argsleft = argc - 1; while (argsleft > 2) { if (streq(args[0], "-n")) notequal = 1; else if (streq(args[0], "-m")) ignore_memrsv = 1; else badargs(argv); args++; argsleft--; } if (argsleft != 2) badargs(argv); fdt1 = load_blob(args[0]); fdt2 = load_blob(args[1]); if (!ignore_memrsv) compare_mem_rsv(fdt1, fdt2); compare_node(fdt1, 0, fdt2, 0); cpuid1 = fdt_boot_cpuid_phys(fdt1); cpuid2 = fdt_boot_cpuid_phys(fdt2); if (cpuid1 != cpuid2) MISMATCH("boot_cpuid_phys mismatch 0x%x != 0x%x", cpuid1, cpuid2); MATCH(); }