1/* $NetBSD: dtbs_equal_unordered.c,v 1.1.1.3 2019/12/22 12:34:06 skrll Exp $ */ 2 3// SPDX-License-Identifier: LGPL-2.1-or-later 4/* 5 * libfdt - Flat Device Tree manipulation 6 * Tests if two given dtbs are structurally equal (including order) 7 * Copyright (C) 2007 David Gibson, IBM Corporation. 8 */ 9 10#include <stdlib.h> 11#include <stdio.h> 12#include <string.h> 13#include <stdint.h> 14#include <limits.h> 15 16#include <libfdt.h> 17 18#include "tests.h" 19#include "testdata.h" 20 21static int notequal; /* = 0 */ 22static int ignore_memrsv; /* = 0 */ 23 24#define MISMATCH(fmt, ...) \ 25 do { \ 26 if (notequal) \ 27 PASS(); \ 28 else \ 29 FAIL(fmt, ##__VA_ARGS__); \ 30 } while (0) 31 32#define MATCH() \ 33 do { \ 34 if (!notequal) \ 35 PASS(); \ 36 else \ 37 FAIL("Trees match which shouldn't"); \ 38 } while (0) 39 40#define CHECK(code) \ 41 { \ 42 err = (code); \ 43 if (err) \ 44 FAIL(#code ": %s", fdt_strerror(err)); \ 45 } 46 47static int mem_rsv_cmp(const void *p1, const void *p2) 48{ 49 const struct fdt_reserve_entry *re1 = p1; 50 const struct fdt_reserve_entry *re2 = p2; 51 52 if (fdt64_to_cpu(re1->address) < fdt64_to_cpu(re2->address)) 53 return -1; 54 else if (fdt64_to_cpu(re1->address) > fdt64_to_cpu(re2->address)) 55 return 1; 56 57 if (fdt64_to_cpu(re1->size) < fdt64_to_cpu(re2->size)) 58 return -1; 59 else if (fdt64_to_cpu(re1->size) > fdt64_to_cpu(re2->size)) 60 return 1; 61 62 return 0; 63} 64 65static void compare_mem_rsv(void *fdt1, void *fdt2) 66{ 67 int i; 68 uint64_t addr1, size1, addr2, size2; 69 int err; 70 71 if (fdt_num_mem_rsv(fdt1) != fdt_num_mem_rsv(fdt2)) 72 MISMATCH("Trees have different number of reserve entries"); 73 74 qsort((char *)fdt1 + fdt_off_mem_rsvmap(fdt1), fdt_num_mem_rsv(fdt1), 75 sizeof(struct fdt_reserve_entry), mem_rsv_cmp); 76 qsort((char *)fdt2 + fdt_off_mem_rsvmap(fdt2), fdt_num_mem_rsv(fdt2), 77 sizeof(struct fdt_reserve_entry), mem_rsv_cmp); 78 79 for (i = 0; i < fdt_num_mem_rsv(fdt1); i++) { 80 CHECK(fdt_get_mem_rsv(fdt1, i, &addr1, &size1)); 81 CHECK(fdt_get_mem_rsv(fdt2, i, &addr2, &size2)); 82 83 if ((addr1 != addr2) || (size1 != size2)) 84 MISMATCH("Mismatch in reserve entry %d: " 85 "(0x%llx, 0x%llx) != (0x%llx, 0x%llx)", i, 86 (unsigned long long)addr1, 87 (unsigned long long)size1, 88 (unsigned long long)addr2, 89 (unsigned long long)size2); 90 } 91} 92 93static void compare_properties(const void *fdt1, int offset1, 94 const void *fdt2, int offset2) 95{ 96 int offset = offset1; 97 98 /* Check the properties */ 99 for (offset = fdt_first_property_offset(fdt1, offset1); 100 offset >= 0; 101 offset = fdt_next_property_offset(fdt1, offset)) { 102 const char *name; 103 int len1, len2; 104 const void *data1, *data2; 105 int i; 106 107 data1 = fdt_getprop_by_offset(fdt1, offset, &name, &len1); 108 if (!data1) 109 FAIL("fdt_getprop_by_offset(): %s\n", 110 fdt_strerror(len1)); 111 112 verbose_printf("Property '%s'\n", name); 113 114 data2 = fdt_getprop(fdt2, offset2, name, &len2); 115 if (!data2) { 116 if (len2 == -FDT_ERR_NOTFOUND) 117 MISMATCH("Property '%s' missing\n", name); 118 else 119 FAIL("fdt_get_property(): %s\n", 120 fdt_strerror(len2)); 121 } 122 123 verbose_printf("len1=%d data1=", len1); 124 for (i = 0; i < len1; i++) 125 verbose_printf(" %02x", ((const char *)data1)[i]); 126 verbose_printf("\nlen2=%d data2=", len2); 127 for (i = 0; i < len1; i++) 128 verbose_printf(" %02x", ((const char *)data2)[i]); 129 verbose_printf("\n"); 130 131 if (len1 != len2) 132 MISMATCH("Property '%s' mismatched length %d vs. %d\n", 133 name, len1, len2); 134 else if (memcmp(data1, data2, len1) != 0) 135 MISMATCH("Property '%s' mismatched value\n", name); 136 } 137} 138 139static void compare_node(const void *fdt1, int offset1, 140 const void *fdt2, int offset2); 141 142static void compare_subnodes(const void *fdt1, int offset1, 143 const void *fdt2, int offset2, 144 int recurse) 145{ 146 int coffset1, coffset2, depth; 147 148 for (depth = 0, coffset1 = offset1; 149 (coffset1 >= 0) && (depth >= 0); 150 coffset1 = fdt_next_node(fdt1, coffset1, &depth)) 151 if (depth == 1) { 152 const char *name = fdt_get_name(fdt1, coffset1, NULL); 153 154 verbose_printf("Subnode %s\n", name); 155 coffset2 = fdt_subnode_offset(fdt2, offset2, name); 156 if (coffset2 == -FDT_ERR_NOTFOUND) 157 MISMATCH("Subnode %s missing\n", name); 158 else if (coffset2 < 0) 159 FAIL("fdt_subnode_offset(): %s\n", 160 fdt_strerror(coffset2)); 161 162 if (recurse) 163 compare_node(fdt1, coffset1, fdt2, coffset2); 164 } 165} 166 167static void compare_node(const void *fdt1, int offset1, 168 const void *fdt2, int offset2) 169{ 170 int err; 171 char path1[PATH_MAX], path2[PATH_MAX]; 172 173 CHECK(fdt_get_path(fdt1, offset1, path1, sizeof(path1))); 174 CHECK(fdt_get_path(fdt2, offset2, path2, sizeof(path2))); 175 176 if (!streq(path1, path2)) 177 TEST_BUG("Path mismatch %s vs. %s\n", path1, path2); 178 179 verbose_printf("Checking %s\n", path1); 180 181 compare_properties(fdt1, offset1, fdt2, offset2); 182 compare_properties(fdt2, offset2, fdt1, offset1); 183 184 compare_subnodes(fdt1, offset1, fdt2, offset2, 1); 185 compare_subnodes(fdt2, offset2, fdt1, offset1, 0); 186} 187 188static void badargs(char **argv) 189{ 190 CONFIG("Usage: %s [-n] [-m] <dtb file> <dtb file>", argv[0]); 191} 192 193int main(int argc, char *argv[]) 194{ 195 void *fdt1, *fdt2; 196 uint32_t cpuid1, cpuid2; 197 char **args; 198 int argsleft; 199 200 test_init(argc, argv); 201 202 args = &argv[1]; 203 argsleft = argc - 1; 204 205 while (argsleft > 2) { 206 if (streq(args[0], "-n")) 207 notequal = 1; 208 else if (streq(args[0], "-m")) 209 ignore_memrsv = 1; 210 else 211 badargs(argv); 212 args++; 213 argsleft--; 214 } 215 if (argsleft != 2) 216 badargs(argv); 217 218 fdt1 = load_blob(args[0]); 219 fdt2 = load_blob(args[1]); 220 221 if (!ignore_memrsv) 222 compare_mem_rsv(fdt1, fdt2); 223 compare_node(fdt1, 0, fdt2, 0); 224 225 cpuid1 = fdt_boot_cpuid_phys(fdt1); 226 cpuid2 = fdt_boot_cpuid_phys(fdt2); 227 if (cpuid1 != cpuid2) 228 MISMATCH("boot_cpuid_phys mismatch 0x%x != 0x%x", 229 cpuid1, cpuid2); 230 231 MATCH(); 232} 233