Home | History | Annotate | Line # | Download | only in tests
      1 /*	$NetBSD: testutils.c,v 1.1.1.3 2019/12/22 12:34:07 skrll Exp $	*/
      2 
      3 // SPDX-License-Identifier: LGPL-2.1-or-later
      4 /*
      5  * libfdt - Flat Device Tree manipulation
      6  *	Testcase common utility functions
      7  * Copyright (C) 2006 David Gibson, IBM Corporation.
      8  */
      9 
     10 #define _GNU_SOURCE /* for strsignal() in glibc.  FreeBSD has it either way */
     11 
     12 #include <stdio.h>
     13 #include <stdlib.h>
     14 #include <stdint.h>
     15 #include <limits.h>
     16 #include <string.h>
     17 #include <errno.h>
     18 #include <signal.h>
     19 #include <unistd.h>
     20 #include <fcntl.h>
     21 
     22 #if NO_VALGRIND
     23 static inline void VALGRIND_MAKE_MEM_UNDEFINED(void *p, size_t len)
     24 {
     25 }
     26 
     27 static inline void VALGRIND_MAKE_MEM_DEFINED(void *p, size_t len)
     28 {
     29 }
     30 #else
     31 #include <valgrind/memcheck.h>
     32 #endif
     33 
     34 #include <libfdt.h>
     35 
     36 #include "tests.h"
     37 #include "testdata.h"
     38 
     39 /* For FDT_SW_MAGIC */
     40 #include "libfdt_internal.h"
     41 
     42 int verbose_test = 1;
     43 char *test_name;
     44 
     45 void  __attribute__((weak)) cleanup(void)
     46 {
     47 }
     48 
     49 static void sigint_handler(int signum, siginfo_t *si, void *uc)
     50 {
     51 	cleanup();
     52 	fprintf(stderr, "%s: %s (pid=%d)\n", test_name,
     53 		strsignal(signum), getpid());
     54 	exit(RC_BUG);
     55 }
     56 
     57 void test_init(int argc, char *argv[])
     58 {
     59 	int err;
     60 	struct sigaction sa_int = {
     61 		.sa_sigaction = sigint_handler,
     62 	};
     63 
     64 	test_name = argv[0];
     65 
     66 	err = sigaction(SIGINT, &sa_int, NULL);
     67 	if (err)
     68 		FAIL("Can't install SIGINT handler");
     69 
     70 	if (getenv("QUIET_TEST"))
     71 		verbose_test = 0;
     72 
     73 	verbose_printf("Starting testcase \"%s\", pid %d\n",
     74 		       test_name, getpid());
     75 }
     76 
     77 void check_mem_rsv(void *fdt, int n, uint64_t addr, uint64_t size)
     78 {
     79 	int err;
     80 	uint64_t addr_v, size_v;
     81 
     82 	err = fdt_get_mem_rsv(fdt, n, &addr_v, &size_v);
     83 	if (err < 0)
     84 		FAIL("fdt_get_mem_rsv(%d): %s", n, fdt_strerror(err));
     85 	if ((addr_v != addr) || (size_v != size))
     86 		FAIL("fdt_get_mem_rsv() returned (0x%llx,0x%llx) "
     87 		     "instead of (0x%llx,0x%llx)",
     88 		     (unsigned long long)addr_v, (unsigned long long)size_v,
     89 		     (unsigned long long)addr, (unsigned long long)size);
     90 }
     91 
     92 void check_property(void *fdt, int nodeoffset, const char *name,
     93 		    int len, const void *val)
     94 {
     95 	const struct fdt_property *prop;
     96 	int retlen, namelen;
     97 	uint32_t tag, nameoff, proplen;
     98 	const char *propname;
     99 
    100 	verbose_printf("Checking property \"%s\"...", name);
    101 	prop = fdt_get_property(fdt, nodeoffset, name, &retlen);
    102 	verbose_printf("pointer %p\n", prop);
    103 	if (! prop)
    104 		FAIL("Error retrieving \"%s\" pointer: %s", name,
    105 		     fdt_strerror(retlen));
    106 
    107 	tag = fdt32_to_cpu(prop->tag);
    108 	nameoff = fdt32_to_cpu(prop->nameoff);
    109 	proplen = fdt32_to_cpu(prop->len);
    110 
    111 	if (tag != FDT_PROP)
    112 		FAIL("Incorrect tag 0x%08x on property \"%s\"", tag, name);
    113 
    114 	propname = fdt_get_string(fdt, nameoff, &namelen);
    115 	if (!propname)
    116 		FAIL("Couldn't get property name: %s", fdt_strerror(namelen));
    117 	if (namelen != strlen(propname))
    118 		FAIL("Incorrect prop name length: %d instead of %zd",
    119 		     namelen, strlen(propname));
    120 	if (!streq(propname, name))
    121 		FAIL("Property name mismatch \"%s\" instead of \"%s\"",
    122 		     propname, name);
    123 	if (proplen != retlen)
    124 		FAIL("Length retrieved for \"%s\" by fdt_get_property()"
    125 		     " differs from stored length (%d != %d)",
    126 		     name, retlen, proplen);
    127 	if (proplen != len)
    128 		FAIL("Size mismatch on property \"%s\": %d insead of %d",
    129 		     name, proplen, len);
    130 	if (len && memcmp(val, prop->data, len) != 0)
    131 		FAIL("Data mismatch on property \"%s\"", name);
    132 }
    133 
    134 const void *check_getprop(void *fdt, int nodeoffset, const char *name,
    135 			  int len, const void *val)
    136 {
    137 	const void *propval;
    138 	int proplen;
    139 
    140 	propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
    141 	if (! propval)
    142 		FAIL("fdt_getprop(\"%s\"): %s", name, fdt_strerror(proplen));
    143 
    144 	if (proplen != len)
    145 		FAIL("Size mismatch on property \"%s\": %d insead of %d",
    146 		     name, proplen, len);
    147 	if (len && memcmp(val, propval, len) != 0)
    148 		FAIL("Data mismatch on property \"%s\"", name);
    149 
    150 	return propval;
    151 }
    152 
    153 const void *check_get_prop_offset(void *fdt, int poffset, const char *exp_name,
    154 				  int exp_len, const void *exp_val)
    155 {
    156 	const void *propval;
    157 	const char *name;
    158 	int proplen;
    159 
    160 	propval = fdt_getprop_by_offset(fdt, poffset, &name, &proplen);
    161 	if (!propval)
    162 		FAIL("fdt_getprop(\"%s\"): %s", name, fdt_strerror(proplen));
    163 
    164 	/* Not testing for this field, so ignore */
    165 	if (strcmp(name, exp_name))
    166 		return NULL;
    167 
    168 	if (proplen != exp_len)
    169 		FAIL("Size mismatch on property \"%s\": %d insead of %d",
    170 		     name, proplen, exp_len);
    171 	if (exp_len && memcmp(exp_val, propval, exp_len))
    172 		FAIL("Data mismatch on property \"%s\"", name);
    173 
    174 	return propval;
    175 }
    176 
    177 const void *check_getprop_addrrange(void *fdt, int parent, int nodeoffset,
    178 				    const char *name, int num)
    179 {
    180 	const void *propval;
    181 	int xac, xsc, buf_size, cells, i;
    182 	char *buf, *p;
    183 	uint64_t addr, size;
    184 	fdt32_t val;
    185 
    186 	xac = fdt_address_cells(fdt, parent);
    187 	xsc = fdt_size_cells(fdt, parent);
    188 
    189 	if (xac <= 0)
    190 		FAIL("Couldn't identify #address-cells: %s",
    191 		     fdt_strerror(xac));
    192 	if (xsc <= 0)
    193 		FAIL("Couldn't identify #size-cells: %s",
    194 		     fdt_strerror(xsc));
    195 
    196 	buf_size = (xac + xsc) * sizeof(fdt32_t) * num;
    197 	buf = malloc(buf_size);
    198 	if (!buf)
    199 		FAIL("Couldn't allocate temporary buffer");
    200 
    201 	/* expected value */
    202 	addr = TEST_MEMREGION_ADDR;
    203 	if (xac > 1)
    204 		addr += TEST_MEMREGION_ADDR_HI;
    205 	size = TEST_MEMREGION_SIZE;
    206 	if (xsc > 1)
    207 		size += TEST_MEMREGION_SIZE_HI;
    208 	for (p = buf, i = 0; i < num; i++) {
    209 		cells = xac;
    210 		while (cells) {
    211 			val = cpu_to_fdt32(addr >> (32 * (--cells)));
    212 			memcpy(p, &val, sizeof(val));
    213 			p += sizeof(val);
    214 		}
    215 		cells = xsc;
    216 		while (cells) {
    217 			val = cpu_to_fdt32(size >> (32 * (--cells)));
    218 			memcpy(p, &val, sizeof(val));
    219 			p += sizeof(val);
    220 		}
    221 
    222 		addr += size;
    223 		size += TEST_MEMREGION_SIZE_INC;
    224 	}
    225 
    226 	/* check */
    227 	propval = check_getprop(fdt, nodeoffset, name, buf_size,
    228 				(const void *)buf);
    229 
    230 	free(buf);
    231 
    232 	return propval;
    233 }
    234 
    235 int nodename_eq(const char *s1, const char *s2)
    236 {
    237 	int len = strlen(s2);
    238 
    239 	if (strncmp(s1, s2, len) != 0)
    240 		return 0;
    241 	if (s1[len] == '\0')
    242 		return 1;
    243 	else if (!memchr(s2, '@', len) && (s1[len] == '@'))
    244 		return 1;
    245 	else
    246 		return 0;
    247 }
    248 
    249 void vg_prepare_blob(void *fdt, size_t bufsize)
    250 {
    251 	char *blob = fdt;
    252 	int off_memrsv, off_strings, off_struct;
    253 	int num_memrsv;
    254 	size_t size_memrsv, size_strings, size_struct;
    255 
    256 	off_memrsv = fdt_off_mem_rsvmap(fdt);
    257 	num_memrsv = fdt_num_mem_rsv(fdt);
    258 	if (num_memrsv < 0)
    259 		size_memrsv = fdt_totalsize(fdt) - off_memrsv;
    260 	else
    261 		size_memrsv = (num_memrsv + 1)
    262 			* sizeof(struct fdt_reserve_entry);
    263 
    264 	VALGRIND_MAKE_MEM_UNDEFINED(blob, bufsize);
    265 	VALGRIND_MAKE_MEM_DEFINED(blob, FDT_V1_SIZE);
    266 	VALGRIND_MAKE_MEM_DEFINED(blob, fdt_header_size(fdt));
    267 
    268 	if (fdt_magic(fdt) == FDT_MAGIC) {
    269 		off_strings = fdt_off_dt_strings(fdt);
    270 		if (fdt_version(fdt) >= 3)
    271 			size_strings = fdt_size_dt_strings(fdt);
    272 		else
    273 			size_strings = fdt_totalsize(fdt) - off_strings;
    274 
    275 		off_struct = fdt_off_dt_struct(fdt);
    276 		if (fdt_version(fdt) >= 17)
    277 			size_struct = fdt_size_dt_struct(fdt);
    278 		else
    279 			size_struct = fdt_totalsize(fdt) - off_struct;
    280 	} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
    281 		size_strings = fdt_size_dt_strings(fdt);
    282 		off_strings = fdt_off_dt_strings(fdt) - size_strings;
    283 
    284 		off_struct = fdt_off_dt_struct(fdt);
    285 		size_struct = fdt_size_dt_struct(fdt);
    286 		size_struct = fdt_totalsize(fdt) - off_struct;
    287 
    288 	} else {
    289 		CONFIG("Bad magic on vg_prepare_blob()");
    290 	}
    291 
    292 	VALGRIND_MAKE_MEM_DEFINED(blob + off_memrsv, size_memrsv);
    293 	VALGRIND_MAKE_MEM_DEFINED(blob + off_strings, size_strings);
    294 	VALGRIND_MAKE_MEM_DEFINED(blob + off_struct, size_struct);
    295 }
    296 
    297 void *load_blob(const char *filename)
    298 {
    299 	char *blob;
    300 	size_t len;
    301 	int ret = utilfdt_read_err(filename, &blob, &len);
    302 
    303 	if (ret)
    304 		CONFIG("Couldn't open blob from \"%s\": %s", filename,
    305 		       strerror(ret));
    306 
    307 	vg_prepare_blob(blob, len);
    308 
    309 	return blob;
    310 }
    311 
    312 void *load_blob_arg(int argc, char *argv[])
    313 {
    314 	if (argc != 2)
    315 		CONFIG("Usage: %s <dtb file>", argv[0]);
    316 	return load_blob(argv[1]);
    317 }
    318 
    319 void save_blob(const char *filename, void *fdt)
    320 {
    321 	size_t size = fdt_totalsize(fdt);
    322 	void *tmp;
    323 	int ret;
    324 
    325 	/* Make a temp copy of the blob so that valgrind won't check
    326 	 * about uninitialized bits in the pieces between blocks */
    327 	tmp = xmalloc(size);
    328 	fdt_move(fdt, tmp, size);
    329 	VALGRIND_MAKE_MEM_DEFINED(tmp, size);
    330 	ret = utilfdt_write_err(filename, tmp);
    331 	if (ret)
    332 		CONFIG("Couldn't write blob to \"%s\": %s", filename,
    333 		       strerror(ret));
    334 	free(tmp);
    335 }
    336 
    337 void *open_blob_rw(void *blob)
    338 {
    339 	int err;
    340 	void *buf = blob;
    341 
    342 	err = fdt_open_into(blob, buf, fdt_totalsize(blob));
    343 	if (err == -FDT_ERR_NOSPACE) {
    344 		/* Ran out of space converting to v17 */
    345 		int newsize = fdt_totalsize(blob) + 8;
    346 
    347 		buf = xmalloc(newsize);
    348 		err = fdt_open_into(blob, buf, newsize);
    349 	}
    350 	if (err)
    351 		FAIL("fdt_open_into(): %s", fdt_strerror(err));
    352 	return buf;
    353 }
    354