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