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