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