13da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson/*
23da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson * libfdt - Flat Device Tree manipulation
33da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson *	Testcase common utility functions
43da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson * Copyright (C) 2006 David Gibson, IBM Corporation.
53da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson *
63da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson * This library is free software; you can redistribute it and/or
73da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson * modify it under the terms of the GNU Lesser General Public License
83da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson * as published by the Free Software Foundation; either version 2.1 of
93da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson * the License, or (at your option) any later version.
103da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson *
113da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson * This library is distributed in the hope that it will be useful, but
123da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson * WITHOUT ANY WARRANTY; without even the implied warranty of
133da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
143da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson * Lesser General Public License for more details.
153da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson *
163da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson * You should have received a copy of the GNU Lesser General Public
173da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson * License along with this library; if not, write to the Free Software
183da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
193da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson */
203da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson
21cdcb415851dc6c3e9550f27139c933fcaeb2d6a7David Gibson#define _GNU_SOURCE /* for strsignal() in glibc.  FreeBSD has it either way */
223da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson
233da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson#include <stdio.h>
243da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson#include <stdlib.h>
25857f54e79f74429af20c2b5ecc00ee98af6a3b8bDavid Gibson#include <stdint.h>
263da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson#include <limits.h>
273da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson#include <string.h>
283da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson#include <errno.h>
293da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson#include <signal.h>
303da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson#include <unistd.h>
314e6221c171377324cc3e80a9c2260b9788335d87David Gibson#include <fcntl.h>
323da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson
333da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson#include <libfdt.h>
343da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson
353da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson#include "tests.h"
363da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson
373da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibsonint verbose_test = 1;
383da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibsonchar *test_name;
393da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson
403da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibsonvoid  __attribute__((weak)) cleanup(void)
413da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson{
423da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson}
433da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson
443da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibsonstatic void sigint_handler(int signum, siginfo_t *si, void *uc)
453da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson{
463da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	cleanup();
473da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	fprintf(stderr, "%s: %s (pid=%d)\n", test_name,
483da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson		strsignal(signum), getpid());
493da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	exit(RC_BUG);
503da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson}
513da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson
523da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibsonvoid test_init(int argc, char *argv[])
533da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson{
543da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	int err;
553da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	struct sigaction sa_int = {
563da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson		.sa_sigaction = sigint_handler,
573da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	};
583da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson
593da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	test_name = argv[0];
603da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson
613da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	err = sigaction(SIGINT, &sa_int, NULL);
623da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	if (err)
633da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson		FAIL("Can't install SIGINT handler");
643da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson
653da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	if (getenv("QUIET_TEST"))
663da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson		verbose_test = 0;
673da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson
683da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	verbose_printf("Starting testcase \"%s\", pid %d\n",
693da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson		       test_name, getpid());
703da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson}
713da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson
72fd1bf3a5ae46962528ef89a824261a88830758a2David Gibsonvoid check_mem_rsv(void *fdt, int n, uint64_t addr, uint64_t size)
73fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson{
74fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson	int err;
75fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson	uint64_t addr_v, size_v;
76fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson
77fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson	err = fdt_get_mem_rsv(fdt, n, &addr_v, &size_v);
78fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson	if (err < 0)
79fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson		FAIL("fdt_get_mem_rsv(%d): %s", n, fdt_strerror(err));
80fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson	if ((addr_v != addr) || (size_v != size))
81fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson		FAIL("fdt_get_mem_rsv() returned (0x%llx,0x%llx) "
82fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson		     "instead of (0x%llx,0x%llx)",
83fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson		     (unsigned long long)addr_v, (unsigned long long)size_v,
84fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson		     (unsigned long long)addr, (unsigned long long)size);
85fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson}
86fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson
8773d60926a05814b8864c86c435e272b386513b0eDavid Gibsonvoid check_property(void *fdt, int nodeoffset, const char *name,
883da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson		    int len, const void *val)
893da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson{
903da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	const struct fdt_property *prop;
915434fcc7e05e86b61530999d48548e6f18036cf7David Gibson	int retlen;
923da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	uint32_t tag, nameoff, proplen;
933da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	const char *propname;
943da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson
953da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	verbose_printf("Checking property \"%s\"...", name);
965434fcc7e05e86b61530999d48548e6f18036cf7David Gibson	prop = fdt_get_property(fdt, nodeoffset, name, &retlen);
973da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	verbose_printf("pointer %p\n", prop);
983da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	if (! prop)
995434fcc7e05e86b61530999d48548e6f18036cf7David Gibson		FAIL("Error retreiving \"%s\" pointer: %s", name,
1005434fcc7e05e86b61530999d48548e6f18036cf7David Gibson		     fdt_strerror(retlen));
1013da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson
1023da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	tag = fdt32_to_cpu(prop->tag);
1033da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	nameoff = fdt32_to_cpu(prop->nameoff);
1043da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	proplen = fdt32_to_cpu(prop->len);
1053da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson
1063da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	if (tag != FDT_PROP)
1073da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson		FAIL("Incorrect tag 0x%08x on property \"%s\"", tag, name);
1083da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson
1093da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	propname = fdt_string(fdt, nameoff);
1103da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	if (!propname || !streq(propname, name))
1113da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson		FAIL("Property name mismatch \"%s\" instead of \"%s\"",
1123da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson		     propname, name);
1135434fcc7e05e86b61530999d48548e6f18036cf7David Gibson	if (proplen != retlen)
1145434fcc7e05e86b61530999d48548e6f18036cf7David Gibson		FAIL("Length retrieved for \"%s\" by fdt_get_property()"
1155434fcc7e05e86b61530999d48548e6f18036cf7David Gibson		     " differs from stored length (%d != %d)",
1165434fcc7e05e86b61530999d48548e6f18036cf7David Gibson		     name, retlen, proplen);
1173da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	if (proplen != len)
1183da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson		FAIL("Size mismatch on property \"%s\": %d insead of %d",
1193da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson		     name, proplen, len);
1203da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	if (memcmp(val, prop->data, len) != 0)
1213da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson		FAIL("Data mismatch on property \"%s\"", name);
1223da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson}
1233da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson
124a6c76f923dcc42102fac58375eaca28057811c20David Gibsonconst void *check_getprop(void *fdt, int nodeoffset, const char *name,
125a6c76f923dcc42102fac58375eaca28057811c20David Gibson			  int len, const void *val)
1263da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson{
127a6c76f923dcc42102fac58375eaca28057811c20David Gibson	const void *propval;
1283da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	int proplen;
1293da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson
1303da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
131a7ee95ded6a0d64c1c259b9c6fea090e19ca81f8David Gibson	if (! propval)
1325434fcc7e05e86b61530999d48548e6f18036cf7David Gibson		FAIL("fdt_getprop(\"%s\"): %s", name, fdt_strerror(proplen));
1333da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson
1343da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	if (proplen != len)
1353da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson		FAIL("Size mismatch on property \"%s\": %d insead of %d",
1363da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson		     name, proplen, len);
1373da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	if (memcmp(val, propval, len) != 0)
1383da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson		FAIL("Data mismatch on property \"%s\"", name);
1393da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson
1403da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson	return propval;
1413da0f9a10dfa9b615d06c350c7b9fe29f360a6eDavid Gibson}
1424e6221c171377324cc3e80a9c2260b9788335d87David Gibson
143d2a9da045897c37071597d9aa473964717b14735David Gibsonint nodename_eq(const char *s1, const char *s2)
144d2a9da045897c37071597d9aa473964717b14735David Gibson{
145d2a9da045897c37071597d9aa473964717b14735David Gibson	int len = strlen(s2);
146d2a9da045897c37071597d9aa473964717b14735David Gibson
147d2a9da045897c37071597d9aa473964717b14735David Gibson	if (strncmp(s1, s2, len) != 0)
148d2a9da045897c37071597d9aa473964717b14735David Gibson		return 0;
149d2a9da045897c37071597d9aa473964717b14735David Gibson	if (s1[len] == '\0')
150d2a9da045897c37071597d9aa473964717b14735David Gibson		return 1;
151d2a9da045897c37071597d9aa473964717b14735David Gibson	else if (!memchr(s2, '@', len) && (s1[len] == '@'))
152d2a9da045897c37071597d9aa473964717b14735David Gibson		return 1;
153d2a9da045897c37071597d9aa473964717b14735David Gibson	else
154d2a9da045897c37071597d9aa473964717b14735David Gibson		return 0;
155d2a9da045897c37071597d9aa473964717b14735David Gibson}
156d2a9da045897c37071597d9aa473964717b14735David Gibson
1574e6221c171377324cc3e80a9c2260b9788335d87David Gibson#define CHUNKSIZE	128
1584e6221c171377324cc3e80a9c2260b9788335d87David Gibson
1594e6221c171377324cc3e80a9c2260b9788335d87David Gibsonvoid *load_blob(const char *filename)
1604e6221c171377324cc3e80a9c2260b9788335d87David Gibson{
1611c25c0d520dee58bfd86626a07036fe9febfebe6Simon Glass	char *blob;
1625543b88d5e3047b781552eb431bc2e3bdd9ade06Jon Loeliger	int ret = utilfdt_read_err(filename, &blob);
1634e6221c171377324cc3e80a9c2260b9788335d87David Gibson
1641c25c0d520dee58bfd86626a07036fe9febfebe6Simon Glass	if (ret)
1651c25c0d520dee58bfd86626a07036fe9febfebe6Simon Glass		CONFIG("Couldn't open blob from \"%s\": %s", filename,
1661c25c0d520dee58bfd86626a07036fe9febfebe6Simon Glass		       strerror(ret));
1671c25c0d520dee58bfd86626a07036fe9febfebe6Simon Glass	return blob;
1684e6221c171377324cc3e80a9c2260b9788335d87David Gibson}
1694e6221c171377324cc3e80a9c2260b9788335d87David Gibson
1704e6221c171377324cc3e80a9c2260b9788335d87David Gibsonvoid *load_blob_arg(int argc, char *argv[])
1714e6221c171377324cc3e80a9c2260b9788335d87David Gibson{
1724e6221c171377324cc3e80a9c2260b9788335d87David Gibson	if (argc != 2)
1734e6221c171377324cc3e80a9c2260b9788335d87David Gibson		CONFIG("Usage: %s <dtb file>", argv[0]);
1744e6221c171377324cc3e80a9c2260b9788335d87David Gibson	return load_blob(argv[1]);
1754e6221c171377324cc3e80a9c2260b9788335d87David Gibson}
176063693a9e42aea7beb7c6f49ecd8a8dc5ed1c387David Gibson
17773d60926a05814b8864c86c435e272b386513b0eDavid Gibsonvoid save_blob(const char *filename, void *fdt)
178063693a9e42aea7beb7c6f49ecd8a8dc5ed1c387David Gibson{
1791c25c0d520dee58bfd86626a07036fe9febfebe6Simon Glass	int ret = utilfdt_write_err(filename, fdt);
1801c25c0d520dee58bfd86626a07036fe9febfebe6Simon Glass
1811c25c0d520dee58bfd86626a07036fe9febfebe6Simon Glass	if (ret)
1821c25c0d520dee58bfd86626a07036fe9febfebe6Simon Glass		CONFIG("Couldn't write blob to \"%s\": %s", filename,
1831c25c0d520dee58bfd86626a07036fe9febfebe6Simon Glass		       strerror(ret));
184063693a9e42aea7beb7c6f49ecd8a8dc5ed1c387David Gibson}
185a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson
186a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibsonvoid *open_blob_rw(void *blob)
187a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson{
188a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	int err;
189a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	void *buf = blob;
190a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson
191a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	err = fdt_open_into(blob, buf, fdt_totalsize(blob));
192a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	if (err == -FDT_ERR_NOSPACE) {
193a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson		/* Ran out of space converting to v17 */
194a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson		int newsize = fdt_totalsize(blob) + 8;
195a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson
196a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson		buf = xmalloc(newsize);
197a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson		err = fdt_open_into(blob, buf, newsize);
198a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	}
199a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	if (err)
200a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson		FAIL("fdt_open_into(): %s", fdt_strerror(err));
201a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	return buf;
202a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson}
203