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 23static inline void VALGRIND_MAKE_MEM_UNDEFINED(void *p, size_t len) 24{ 25} 26 27static 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 42int verbose_test = 1; 43char *test_name; 44 45void __attribute__((weak)) cleanup(void) 46{ 47} 48 49static 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 57void 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 77void 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 92void 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 134const 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 153const 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 177const 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 235int 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 249void 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 297void *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 312void *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 319void 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 337void *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