diff options
Diffstat (limited to 'dtc/tests')
242 files changed, 12413 insertions, 0 deletions
diff --git a/dtc/tests/.gitignore b/dtc/tests/.gitignore new file mode 100644 index 000000000..d3f143406 --- /dev/null +++ b/dtc/tests/.gitignore @@ -0,0 +1,75 @@ +*.dtb +*.dts.test.s +*.test.dts +*.test.dt.yaml +tmp.* +/fs/ +/add_subnode_with_nops +/addr_size_cells +/addr_size_cells2 +/appendprop[12] +/appendprop_addrrange +/asm_tree_dump +/boot-cpuid +/char_literal +/check_full +/check_header +/check_path +/del_node +/del_property +/dtbs_equal_ordered +/dtbs_equal_unordered +/dtb_reverse +/dumptrees +/extra-terminating-null +/find_property +/get_alias +/get_mem_rsv +/get_name +/get_path +/get_phandle +/getprop +/get_prop_offset +/incbin +/integer-expressions +/fs_tree1 +/mangle-layout +/move_and_save +/node_check_compatible +/node_offset_by_compatible +/node_offset_by_phandle +/node_offset_by_prop_value +/nop_node +/nop_property +/nopulate +/notfound +/open_pack +/overlay +/overlay_bad_fixup +/parent_offset +/path-references +/path_offset +/path_offset_aliases +/phandle_format +/property_iterate +/propname_escapes +/references +/root_node +/rw_tree1 +/rw_oom +/set_name +/setprop +/setprop_inplace +/sized_cells +/string_escapes +/stringlist +/subnode_iterate +/subnode_offset +/supernode_atdepth_offset +/sw_tree1 +/sw_states +/truncated_property +/truncated_string +/truncated_memrsv +/utilfdt_test +/value-labels diff --git a/dtc/tests/Makefile.tests b/dtc/tests/Makefile.tests new file mode 100644 index 000000000..2b4762781 --- /dev/null +++ b/dtc/tests/Makefile.tests @@ -0,0 +1,102 @@ +LIB_TESTS_L = get_mem_rsv \ + root_node find_property subnode_offset path_offset \ + get_name getprop get_prop_offset get_phandle \ + get_path supernode_atdepth_offset parent_offset \ + node_offset_by_prop_value node_offset_by_phandle \ + node_check_compatible node_offset_by_compatible \ + get_alias \ + char_literal \ + sized_cells \ + notfound \ + addr_size_cells \ + addr_size_cells2 \ + appendprop_addrrange \ + stringlist \ + setprop_inplace nop_property nop_node \ + sw_tree1 sw_states \ + move_and_save mangle-layout nopulate \ + open_pack rw_tree1 rw_oom set_name setprop del_property del_node \ + appendprop1 appendprop2 propname_escapes \ + string_escapes references path-references phandle_format \ + boot-cpuid incbin \ + extra-terminating-null \ + dtbs_equal_ordered \ + dtb_reverse dtbs_equal_unordered \ + add_subnode_with_nops path_offset_aliases \ + utilfdt_test \ + integer-expressions \ + property_iterate \ + subnode_iterate \ + overlay overlay_bad_fixup \ + check_path check_header check_full \ + fs_tree1 +LIB_TESTS = $(LIB_TESTS_L:%=$(TESTS_PREFIX)%) + +LIBTREE_TESTS_L = truncated_property truncated_string truncated_memrsv \ + two_roots named_root + +LIBTREE_TESTS = $(LIBTREE_TESTS_L:%=$(TESTS_PREFIX)%) + +DL_LIB_TESTS_L = asm_tree_dump value-labels +DL_LIB_TESTS = $(DL_LIB_TESTS_L:%=$(TESTS_PREFIX)%) + +TESTS = $(LIB_TESTS) $(LIBTREE_TESTS) $(DL_LIB_TESTS) + +TESTS_TREES_L = test_tree1.dtb +TESTS_TREES = $(TESTS_TREES_L:%=$(TESTS_PREFIX)%) + +TESTS_TARGETS = $(TESTS) $(TESTS_TREES) + +TESTS_DEPFILES = $(TESTS:%=%.d) \ + $(addprefix $(TESTS_PREFIX),testutils.d trees.d dumptrees.d) + +TESTS_CLEANFILES_L = $(STD_CLEANFILES) \ + *.dtb *.test.dts *.test.dt.yaml *.dtsv1 tmp.* *.bak \ + dumptrees +TESTS_CLEANFILES = $(TESTS) $(TESTS_CLEANFILES_L:%=$(TESTS_PREFIX)%) +TESTS_CLEANDIRS_L = fs +TESTS_CLEANDIRS = $(TESTS_CLEANDIRS_L:%=$(TESTS_PREFIX)%) + +.PHONY: tests +tests: $(TESTS) $(TESTS_TREES) + +$(LIB_TESTS): %: $(TESTS_PREFIX)testutils.o util.o $(LIBFDT_lib) + +# Not necessary on all platforms; allow -ldl to be excluded instead of forcing +# other platforms to patch it out. +LIBDL = -ldl +$(DL_LIB_TESTS): %: %.o $(TESTS_PREFIX)testutils.o util.o $(LIBFDT_lib) + @$(VECHO) LD [libdl] $@ + $(LINK.c) -o $@ $^ $(LIBDL) + +$(LIBTREE_TESTS): %: $(TESTS_PREFIX)testutils.o $(TESTS_PREFIX)trees.o \ + util.o $(LIBFDT_lib) + +$(TESTS_PREFIX)dumptrees: $(TESTS_PREFIX)trees.o + +$(TESTS_TREES): $(TESTS_PREFIX)dumptrees + @$(VECHO) DUMPTREES + cd $(TESTS_PREFIX); ./dumptrees . >/dev/null + +tests_clean: + @$(VECHO) CLEAN "(tests)" + rm -f $(TESTS_CLEANFILES) + rm -rf $(TESTS_CLEANDIRS) + +check: tests ${TESTS_BIN} $(TESTS_PYLIBFDT) + cd $(TESTS_PREFIX); ./run_tests.sh + +ifeq ($(NO_VALGRIND),1) +checkm: + @echo "make checkm requires valgrind, but NO_VALGRIND=1" +else +checkm: tests ${TESTS_BIN} $(TESTS_PYLIBFDT) + cd $(TESTS_PREFIX); ./run_tests.sh -m +endif + +checkv: tests ${TESTS_BIN} $(TESTS_PYLIBFDT) + cd $(TESTS_PREFIX); ./run_tests.sh -v + +ifneq ($(DEPTARGETS),) +-include $(TESTS_DEPFILES) +endif diff --git a/dtc/tests/add_subnode_with_nops.c b/dtc/tests/add_subnode_with_nops.c new file mode 100644 index 000000000..29bd34ba4 --- /dev/null +++ b/dtc/tests/add_subnode_with_nops.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_nop_node() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +#define SPACE 65536 + +#define CHECK(code) \ + { \ + err = (code); \ + if (err) \ + FAIL(#code ": %s", fdt_strerror(err)); \ + } + +#define OFF_CHECK(off, code) \ + { \ + (off) = (code); \ + if (off < 0) \ + FAIL(#code ": %s", fdt_strerror(off)); \ + } + +int main(int argc, char *argv[]) +{ + void *fdt; + int err; + int offset; + + test_init(argc, argv); + + fdt = xmalloc(SPACE); + + CHECK(fdt_create(fdt, SPACE)); + + CHECK(fdt_finish_reservemap(fdt)); + CHECK(fdt_begin_node(fdt, "")); + CHECK(fdt_property_cell(fdt, "prop1", TEST_VALUE_1)); + CHECK(fdt_property_cell(fdt, "prop2", TEST_VALUE_2)); + CHECK(fdt_end_node(fdt)); + CHECK(fdt_finish(fdt)); + + verbose_printf("Built empty tree, totalsize = %d\n", + fdt_totalsize(fdt)); + + CHECK(fdt_open_into(fdt, fdt, SPACE)); + + check_getprop_cell(fdt, 0, "prop1", TEST_VALUE_1); + check_getprop_cell(fdt, 0, "prop2", TEST_VALUE_2); + + CHECK(fdt_nop_property(fdt, 0, "prop1")); + + check_getprop_cell(fdt, 0, "prop2", TEST_VALUE_2); + + OFF_CHECK(offset, fdt_add_subnode(fdt, 0, "subnode")); + + check_getprop_cell(fdt, 0, "prop2", TEST_VALUE_2); + + PASS(); +} diff --git a/dtc/tests/addr_size_cells.c b/dtc/tests/addr_size_cells.c new file mode 100644 index 000000000..783574d68 --- /dev/null +++ b/dtc/tests/addr_size_cells.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for #address-cells and #size-cells handling + * Copyright (C) 2014 David Gibson, <david@gibson.dropbear.id.au> + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static void check_node(const void *fdt, const char *path, int ac, int sc) +{ + int offset; + int xac, xsc; + + offset = fdt_path_offset(fdt, path); + if (offset < 0) + FAIL("Couldn't find path %s", path); + + xac = fdt_address_cells(fdt, offset); + xsc = fdt_size_cells(fdt, offset); + + if (xac != ac) + FAIL("Address cells for %s is %d instead of %d\n", + path, xac, ac); + if (xsc != sc) + FAIL("Size cells for %s is %d instead of %d\n", + path, xsc, sc); +} + +int main(int argc, char *argv[]) +{ + void *fdt; + + if (argc != 2) + CONFIG("Usage: %s <dtb file>\n", argv[0]); + + test_init(argc, argv); + fdt = load_blob(argv[1]); + + check_node(fdt, "/", 2, 2); + check_node(fdt, "/identity-bus@0", 2, 1); + check_node(fdt, "/simple-bus@1000000", 2, 1); + check_node(fdt, "/discrete-bus@2000000", 1, 0); + check_node(fdt, "/c0", -FDT_ERR_BADNCELLS, -FDT_ERR_BADNCELLS); + check_node(fdt, "/c1", -FDT_ERR_BADNCELLS, -FDT_ERR_BADNCELLS); + check_node(fdt, "/c2", -FDT_ERR_BADNCELLS, -FDT_ERR_BADNCELLS); + check_node(fdt, "/c3", -FDT_ERR_BADNCELLS, 0); + PASS(); +} diff --git a/dtc/tests/addr_size_cells2.c b/dtc/tests/addr_size_cells2.c new file mode 100644 index 000000000..d97541b42 --- /dev/null +++ b/dtc/tests/addr_size_cells2.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for #address-cells and #size-cells handling + * Copyright (C) 2014 David Gibson, <david@gibson.dropbear.id.au> + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static void check_node(const void *fdt, const char *path, int ac, int sc) +{ + int offset; + int xac, xsc; + + offset = fdt_path_offset(fdt, path); + if (offset < 0) + FAIL("Couldn't find path %s", path); + + xac = fdt_address_cells(fdt, offset); + xsc = fdt_size_cells(fdt, offset); + + if (xac != ac) + FAIL("Address cells for %s is %d instead of %d\n", + path, xac, ac); + if (xsc != sc) + FAIL("Size cells for %s is %d instead of %d\n", + path, xsc, sc); +} + +int main(int argc, char *argv[]) +{ + void *fdt; + + if (argc != 2) + CONFIG("Usage: %s <dtb file>\n", argv[0]); + + test_init(argc, argv); + fdt = load_blob(argv[1]); + + check_node(fdt, "/", 2, 1); + PASS(); +} diff --git a/dtc/tests/addresses.dts b/dtc/tests/addresses.dts new file mode 100644 index 000000000..1b307ab53 --- /dev/null +++ b/dtc/tests/addresses.dts @@ -0,0 +1,40 @@ +/dts-v1/; + +/ { + compatible = "test_addresses"; + #address-cells = <2>; + #size-cells = <2>; + + identity-bus@0 { + }; + + simple-bus@1000000 { + #address-cells = <2>; + #size-cells = <1>; + }; + + discrete-bus@2000000 { + #address-cells = <1>; + #size-cells = <0>; + }; + + c0@0 { + #address-cells = <1 1>; + #size-cells = <1 1>; + }; + + c1@0 { + #address-cells = <0x80000000>; + #size-cells = <0x80000000>; + }; + + c2@0 { + #address-cells = <5>; + #size-cells = <5>; + }; + + c3@0 { + #address-cells = <0>; + #size-cells = <0>; + }; +}; diff --git a/dtc/tests/aliases.dts b/dtc/tests/aliases.dts new file mode 100644 index 000000000..853479aee --- /dev/null +++ b/dtc/tests/aliases.dts @@ -0,0 +1,25 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <0>; + + aliases { + s1 = &sub1; + ss1 = &subsub1; + sss1 = &subsubsub1; + }; + + sub1: subnode@1 { + compatible = "subnode1"; + reg = <1>; + + subsub1: subsubnode { + compatible = "subsubnode1", "subsubnode"; + + subsubsub1: subsubsubnode { + compatible = "subsubsubnode1", "subsubsubnode"; + }; + }; + }; +}; diff --git a/dtc/tests/appendprop.dts b/dtc/tests/appendprop.dts new file mode 100644 index 000000000..f4bc730e5 --- /dev/null +++ b/dtc/tests/appendprop.dts @@ -0,0 +1,8 @@ +/dts-v1/; + +/ { + prop-str = "hello world", "nastystring: \a\b\t\n\v\f\r\\\""; + prop-int64 = /bits/ 64 <0xdeadbeef01abcdef 0xdeadbeef01abcdef>; + prop-int = <0xdeadbeef 123456789>; + prop-bytes = [00010203040001020304]; +}; diff --git a/dtc/tests/appendprop1.c b/dtc/tests/appendprop1.c new file mode 100644 index 000000000..a7b502aac --- /dev/null +++ b/dtc/tests/appendprop1.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_appendprop() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +#define SPACE 65536 + +#define CHECK(code) \ + { \ + err = (code); \ + if (err) \ + FAIL(#code ": %s", fdt_strerror(err)); \ + } + +int main(int argc, char *argv[]) +{ + void *fdt; + int err; + uint8_t bytes[] = {0x00, 0x01, 0x02, 0x03, 0x04}; + + test_init(argc, argv); + + /* Create an empty tree first */ + fdt = xmalloc(SPACE); + CHECK(fdt_create(fdt, SPACE)); + CHECK(fdt_finish_reservemap(fdt)); + CHECK(fdt_begin_node(fdt, "")); + CHECK(fdt_end_node(fdt)); + CHECK(fdt_finish(fdt)); + + /* Now use appendprop to add properties */ + CHECK(fdt_open_into(fdt, fdt, SPACE)); + + CHECK(fdt_appendprop(fdt, 0, "prop-bytes", bytes, sizeof(bytes))); + CHECK(fdt_appendprop_cell(fdt, 0, "prop-int", TEST_VALUE_1)); + CHECK(fdt_appendprop_u64(fdt, 0, "prop-int64", TEST_VALUE64_1)); + CHECK(fdt_appendprop_string(fdt, 0, "prop-str", TEST_STRING_1)); + + CHECK(fdt_pack(fdt)); + + save_blob("appendprop1.test.dtb", fdt); + + PASS(); +} diff --git a/dtc/tests/appendprop2.c b/dtc/tests/appendprop2.c new file mode 100644 index 000000000..a0c1f6f43 --- /dev/null +++ b/dtc/tests/appendprop2.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_appendprop() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +#define SPACE 65536 + +#define CHECK(code) \ + { \ + err = (code); \ + if (err) \ + FAIL(#code ": %s", fdt_strerror(err)); \ + } + +int main(int argc, char *argv[]) +{ + void *fdt, *buf; + int err; + uint8_t bytes[] = {0x00, 0x01, 0x02, 0x03, 0x04}; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + buf = xmalloc(SPACE); + CHECK(fdt_open_into(fdt, buf, SPACE)); + fdt = buf; + + CHECK(fdt_appendprop(fdt, 0, "prop-bytes", bytes, sizeof(bytes))); + CHECK(fdt_appendprop_cell(fdt, 0, "prop-int", TEST_VALUE_2)); + CHECK(fdt_appendprop_u64(fdt, 0, "prop-int64", TEST_VALUE64_1)); + CHECK(fdt_appendprop_string(fdt, 0, "prop-str", TEST_STRING_2)); + + CHECK(fdt_pack(fdt)); + + save_blob("appendprop2.test.dtb", fdt); + + PASS(); +} diff --git a/dtc/tests/appendprop_addrrange.c b/dtc/tests/appendprop_addrrange.c new file mode 100644 index 000000000..538afcf9a --- /dev/null +++ b/dtc/tests/appendprop_addrrange.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_appendprop_addrrange() + * Copyright (C) 2018 AKASHI Takahiro, Linaro Limited + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +int main(int argc, char *argv[]) +{ + void *fdt, *buf; + int offset, xac, xsc, num, i, err; + uint64_t addr, size; + + if (argc != 5) + CONFIG("Usage: %s <dtb file> <address-cells> <size-cells> <num>\n", + argv[0]); + + test_init(argc, argv); + fdt = load_blob(argv[1]); + xac = strtol(argv[2], NULL, 10); + xsc = strtol(argv[3], NULL, 10); + num = strtol(argv[4], NULL, 10); + + buf = xmalloc(0x1000); + if (!buf) + FAIL("Couldn't allocate temporary buffer"); + err = fdt_open_into(fdt, buf, 0x1000); + if (err) + FAIL("fdt_open_into(): %s", fdt_strerror(err)); + + fdt = buf; + + /* Set up */ + err = fdt_setprop_cell(fdt, 0, "#address-cells", xac); + if (err) + FAIL("fdt_setprop_cell(\"#address-cells\"): %s", + fdt_strerror(err)); + err = fdt_setprop_cell(fdt, 0, "#size-cells", xsc); + if (err) + FAIL("fdt_setprop_cell(\"#size-cells\"): %s", + fdt_strerror(err)); + + offset = fdt_path_offset(fdt, "/node@1"); + if (offset < 0) + FAIL("Couldn't find path %s", "/node@1"); + + addr = TEST_MEMREGION_ADDR; + if (xac > 1) + addr += TEST_MEMREGION_ADDR_HI; + size = TEST_MEMREGION_SIZE; + if (xsc > 1) + size += TEST_MEMREGION_SIZE_HI; + + /* + * Do test + */ + /* 1. repeat append's */ + for (i = 0; i < num; i++) { + err = fdt_appendprop_addrrange(fdt, 0, offset, + "prop-memregion", addr, size); + if (err) + FAIL("Failed to append[%d] \"prop-memregion\": %s", + i, fdt_strerror(err)); + + check_getprop_addrrange(fdt, 0, offset, "prop-memregion", + i + 1); + + addr += size; + size += TEST_MEMREGION_SIZE_INC; + } + + /* 2. default property name */ + addr = TEST_MEMREGION_ADDR; + if (xac > 1) + addr += TEST_MEMREGION_ADDR_HI; + size = TEST_MEMREGION_SIZE; + if (xsc > 1) + size += TEST_MEMREGION_SIZE_HI; + + err = fdt_appendprop_addrrange(fdt, 0, offset, "reg", addr, size); + if (err) + FAIL("Failed to set \"reg\": %s", fdt_strerror(err)); + check_getprop_addrrange(fdt, 0, offset, "reg", 1); + + PASS(); +} diff --git a/dtc/tests/asm_tree_dump.c b/dtc/tests/asm_tree_dump.c new file mode 100644 index 000000000..8236172d9 --- /dev/null +++ b/dtc/tests/asm_tree_dump.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Tests if an asm tree built into a shared object matches a given dtb + * Copyright (C) 2008 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <errno.h> + +#include <dlfcn.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +int main(int argc, char *argv[]) +{ + void *sohandle; + void *fdt; + int err; + + test_init(argc, argv); + if (argc != 3) + CONFIG("Usage: %s <so file> <dtb file>", argv[0]); + + sohandle = dlopen(argv[1], RTLD_NOW); + if (!sohandle) + FAIL("Couldn't dlopen() %s", argv[1]); + + fdt = dlsym(sohandle, "dt_blob_start"); + if (!fdt) + FAIL("Couldn't locate \"dt_blob_start\" symbol in %s", + argv[1]); + + err = fdt_check_header(fdt); + if (err != 0) + FAIL("%s contains invalid tree: %s", argv[1], + fdt_strerror(err)); + + save_blob(argv[2], fdt); + + PASS(); +} diff --git a/dtc/tests/bad-chosen.dts b/dtc/tests/bad-chosen.dts new file mode 100644 index 000000000..d6f53c68d --- /dev/null +++ b/dtc/tests/bad-chosen.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +/ { + node2 { + chosen { + bootargs = <0xdeadbeef>; + stdout-path = <1>; + }; + }; +}; diff --git a/dtc/tests/bad-dma-ranges.dts b/dtc/tests/bad-dma-ranges.dts new file mode 100644 index 000000000..fbe7ab82c --- /dev/null +++ b/dtc/tests/bad-dma-ranges.dts @@ -0,0 +1,12 @@ +/dts-v1/; + +/ { + #address-cells = <2>; + #size-cells = <2>; + node { + #address-cells = <1>; + #size-cells = <1>; + ranges; + dma-ranges = <0 0 0 0 0>; + }; +}; diff --git a/dtc/tests/bad-empty-ranges.dts b/dtc/tests/bad-empty-ranges.dts new file mode 100644 index 000000000..2be7bc858 --- /dev/null +++ b/dtc/tests/bad-empty-ranges.dts @@ -0,0 +1,11 @@ +/dts-v1/; + +/ { + #address-cells = <2>; + #size-cells = <2>; + node { + #address-cells = <1>; + #size-cells = <1>; + ranges; + }; +}; diff --git a/dtc/tests/bad-gpio.dts b/dtc/tests/bad-gpio.dts new file mode 100644 index 000000000..6b77be447 --- /dev/null +++ b/dtc/tests/bad-gpio.dts @@ -0,0 +1,13 @@ +/dts-v1/; + +/ { + gpio: gpio-controller { + #gpio-cells = <3>; + }; + + node { + nr-gpios = <1>; + foo-gpios = <&gpio>; + bar-gpio = <&gpio 1 2 3>; + }; +}; diff --git a/dtc/tests/bad-graph.dts b/dtc/tests/bad-graph.dts new file mode 100644 index 000000000..522da0edb --- /dev/null +++ b/dtc/tests/bad-graph.dts @@ -0,0 +1,24 @@ +/dts-v1/; + +/ { + ports { + #address-cells = <1>; + #size-cells = <0>; + + bad_endpoint: port-a@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + endpoint@d0 { + reg = <0>; + remote-endpoint = <0xdeadbeef>; + }; + + }; + + port@1 { + reg = <0>; + }; + }; +}; diff --git a/dtc/tests/bad-interrupt-cells.dts b/dtc/tests/bad-interrupt-cells.dts new file mode 100644 index 000000000..39fc78fdc --- /dev/null +++ b/dtc/tests/bad-interrupt-cells.dts @@ -0,0 +1,12 @@ +/dts-v1/; + +/ { + interrupt-parent = <&intc>; + intc: interrupt-controller { + #interrupt-cells = <3>; + }; + + node { + interrupts = <1>; + }; +}; diff --git a/dtc/tests/bad-interrupt-controller.dts b/dtc/tests/bad-interrupt-controller.dts new file mode 100644 index 000000000..62fa11889 --- /dev/null +++ b/dtc/tests/bad-interrupt-controller.dts @@ -0,0 +1,7 @@ +/dts-v1/; + +/ { + intc: interrupt-controller { + interrupt-controller; + }; +}; diff --git a/dtc/tests/bad-name-property.dts b/dtc/tests/bad-name-property.dts new file mode 100644 index 000000000..4fde4bef1 --- /dev/null +++ b/dtc/tests/bad-name-property.dts @@ -0,0 +1,7 @@ +/dts-v1/; + +/ { + node@0 { + name = "badthing"; + }; +}; diff --git a/dtc/tests/bad-ncells.dts b/dtc/tests/bad-ncells.dts new file mode 100644 index 000000000..636198cbf --- /dev/null +++ b/dtc/tests/bad-ncells.dts @@ -0,0 +1,7 @@ +/dts-v1/; + +/ { + #address-cells = "badthing"; + #size-cells = "badthing"; + #interrupt-cells = "badthing"; +}; diff --git a/dtc/tests/bad-octal-literal.dts b/dtc/tests/bad-octal-literal.dts new file mode 100644 index 000000000..26558a274 --- /dev/null +++ b/dtc/tests/bad-octal-literal.dts @@ -0,0 +1,5 @@ +/dts-v1/; + +/ { + x = <09>; +}; diff --git a/dtc/tests/bad-phandle-cells.dts b/dtc/tests/bad-phandle-cells.dts new file mode 100644 index 000000000..7f7c6a25f --- /dev/null +++ b/dtc/tests/bad-phandle-cells.dts @@ -0,0 +1,11 @@ +/dts-v1/; + +/ { + intc: interrupt-controller { + #interrupt-cells = <3>; + }; + + node { + interrupts-extended = <&intc>; + }; +}; diff --git a/dtc/tests/bad-reg-ranges.dts b/dtc/tests/bad-reg-ranges.dts new file mode 100644 index 000000000..77419f5bf --- /dev/null +++ b/dtc/tests/bad-reg-ranges.dts @@ -0,0 +1,12 @@ +/dts-v1/; + +/ { + #address-cells = <2>; + #size-cells = <2>; + node { + reg = <0 0>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0>; + }; +}; diff --git a/dtc/tests/bad-size-cells.dts b/dtc/tests/bad-size-cells.dts new file mode 100644 index 000000000..515c0cc7b --- /dev/null +++ b/dtc/tests/bad-size-cells.dts @@ -0,0 +1,12 @@ +/dts-v1/; + +/ { + mangled { + #address-cells = <0x0>; + #size-cells = <0x0>; + + valid { + reg = <0x0 0x4000000>; + }; + }; +}; diff --git a/dtc/tests/bad-string-props.dts b/dtc/tests/bad-string-props.dts new file mode 100644 index 000000000..6694704a5 --- /dev/null +++ b/dtc/tests/bad-string-props.dts @@ -0,0 +1,14 @@ +/dts-v1/; + +/ { + device_type = <0xdeadbeef>; + model = <0xdeadbeef>; + status = <0xdeadbeef>; + label = <0xdeadbeef>; + + foobar-names = "foo", <1>; + + node { + compatible = "good", <0xdeadbeef>; + }; +}; diff --git a/dtc/tests/base01.asm b/dtc/tests/base01.asm new file mode 100644 index 000000000..266e44651 --- /dev/null +++ b/dtc/tests/base01.asm @@ -0,0 +1,175 @@ +/* autogenerated by dtc, do not edit */ + +#define OF_DT_HEADER 0xd00dfeed +#define OF_DT_BEGIN_NODE 0x1 +#define OF_DT_END_NODE 0x2 +#define OF_DT_PROP 0x3 +#define OF_DT_END 0x9 + + .globl dt_blob_start +dt_blob_start: +_dt_blob_start: + .globl dt_header +dt_header: +_dt_header: + .long OF_DT_HEADER /* magic */ + .long _dt_blob_end - _dt_blob_start /* totalsize */ + .long _dt_struct_start - _dt_blob_start /* off_dt_struct */ + .long _dt_strings_start - _dt_blob_start /* off_dt_strings */ + .long _dt_reserve_map - _dt_blob_start /* off_dt_strings */ + .long 16 /* version */ + .long 16 /* last_comp_version */ + .long 0 /*boot_cpuid_phys*/ + .long _dt_strings_end - _dt_strings_start /* size_dt_strings */ + .balign 8 + .globl dt_reserve_map +dt_reserve_map: +_dt_reserve_map: +/* Memory reserve map from source file */ + .long 0, 0 + .long 0, 0 + .globl dt_struct_start +dt_struct_start: +_dt_struct_start: + .long OF_DT_BEGIN_NODE + .string "" + .balign 4 + .long OF_DT_PROP + .long 0xa + .long 0x0 + .long 0x536f6d65 + .long 0x4d6f6465 + .short 0x6c00 + .balign 4 + .long OF_DT_PROP + .long 0x8 + .long 0x6 + .long 0x4e6f7468 + .long 0x696e6700 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x11 + .long 0x2 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x20 + .long 0x2 + .balign 4 + .long OF_DT_BEGIN_NODE + .string "memory@0" + .balign 4 + .long OF_DT_PROP + .long 0x7 + .long 0x2c + .long 0x6d656d6f + .short 0x7279 + .byte 0x0 + .balign 4 + .long OF_DT_PROP + .long 0x10 + .long 0x38 + .long 0x0 + .long 0x0 + .long 0x0 + .long 0x20000000 + .balign 4 + .long OF_DT_END_NODE + .long OF_DT_BEGIN_NODE + .string "cpus" + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x11 + .long 0x1 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x20 + .long 0x0 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x3c + .long 0xa + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x40 + .long 0x17 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x44 + .long 0x5 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x49 + .long 0xf + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x4d + .long 0xd00d + .balign 4 + .long OF_DT_PROP + .long 0x10 + .long 0x53 + .long 0x4d2 + .long 0x162e + .long 0x2334 + .long 0xd80 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x59 + .long 0x0 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x61 + .long 0xffffffff + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x69 + .long 0x0 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x71 + .long 0xffffffff + .balign 4 + .long OF_DT_END_NODE + .long OF_DT_END_NODE + .long OF_DT_END + .globl dt_struct_end +dt_struct_end: +_dt_struct_end: + .globl dt_strings_start +dt_strings_start: +_dt_strings_start: + .string "model" + .string "compatible" + .string "#address-cells" + .string "#size-cells" + .string "device_type" + .string "reg" + .string "d10" + .string "d23" + .string "b101" + .string "o17" + .string "hd00d" + .string "stuff" + .string "bad-d-1" + .string "bad-d-2" + .string "bad-o-1" + .string "bad-o-2" + .globl dt_strings_end +dt_strings_end: +_dt_strings_end: + .globl dt_blob_end +dt_blob_end: +_dt_blob_end: diff --git a/dtc/tests/base01.cmd b/dtc/tests/base01.cmd new file mode 100644 index 000000000..e1fce6c88 --- /dev/null +++ b/dtc/tests/base01.cmd @@ -0,0 +1 @@ +dtc -f -b 0 -V 16 -I dts -O asm diff --git a/dtc/tests/base01.dts b/dtc/tests/base01.dts new file mode 100644 index 000000000..97a5dd50b --- /dev/null +++ b/dtc/tests/base01.dts @@ -0,0 +1,33 @@ +/dts-v1/; + +/ { + model = "SomeModel"; + compatible = "Nothing"; + #address-cells = <2>; + #size-cells = <2>; + + memory@0 { + device_type = "memory"; + reg = <0x00000000 0x00000000 0x00000000 0x20000000>; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + d10 = < 10>; // hex: 0xa + d23 = < 23>; // hex: 0x17 + b101 = < 0x5>; // hex: 0x5 + o17 = < 017>; // hex: 0xf + hd00d = < 0xd00d>; // hex: 0xd00d + + // hex: 0x4d2 0x163e 0x2334 0xd80 + stuff = < 1234 5678 9012 3456>; + + + bad-d-1 = < 0>; // Hrm. 0 + bad-d-2 = < 123456789012345>; + bad-o-1 = < 00>; + bad-o-2 = < 0123456123456>; + }; + +}; diff --git a/dtc/tests/base01.stderr b/dtc/tests/base01.stderr new file mode 100644 index 000000000..0510b0fb4 --- /dev/null +++ b/dtc/tests/base01.stderr @@ -0,0 +1,6 @@ +DTC: dts->asm on file "tests/base01.dts" +Line 26: Invalid cell value '123456789012345'; -1 assumed +Line 27: Invalid cell value '891'; 0 assumed +Line 28: Invalid cell value '123456123456'; -1 assumed +ERROR: Missing /chosen node +Input tree has errors diff --git a/dtc/tests/boot-cpuid.c b/dtc/tests/boot-cpuid.c new file mode 100644 index 000000000..5ed4f9af1 --- /dev/null +++ b/dtc/tests/boot-cpuid.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2008 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +int main(int argc, char *argv[]) +{ + void *fdt; + uint32_t cpuid; + + test_init(argc, argv); + + if (argc != 3) + CONFIG("Usage: %s <dtb file> <cpuid>", argv[0]); + + fdt = load_blob(argv[1]); + cpuid = strtoul(argv[2], NULL, 0); + + if (fdt_boot_cpuid_phys(fdt) != cpuid) + FAIL("Incorrect boot_cpuid_phys (0x%x instead of 0x%x)", + fdt_boot_cpuid_phys(fdt), cpuid); + + PASS(); +} diff --git a/dtc/tests/boot-cpuid.dts b/dtc/tests/boot-cpuid.dts new file mode 100644 index 000000000..7021a241f --- /dev/null +++ b/dtc/tests/boot-cpuid.dts @@ -0,0 +1,16 @@ +/dts-v1/; + +/ { + cpus { + cpu@10 { + device_type = "cpu"; + compatible = "fake-cpu"; + reg = <0x10>; + }; + cpu@11 { + device_type = "cpu"; + compatible = "fake-cpu"; + reg = <0x11>; + }; + }; +}; diff --git a/dtc/tests/char_literal.c b/dtc/tests/char_literal.c new file mode 100644 index 000000000..3a69e28a6 --- /dev/null +++ b/dtc/tests/char_literal.c @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for character literals in dtc + * Copyright (C) 2006 David Gibson, IBM Corporation. + * Copyright (C) 2011 The Chromium Authors. All rights reserved. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +int main(int argc, char *argv[]) +{ + void *fdt; + fdt32_t expected_cells[5]; + + expected_cells[0] = cpu_to_fdt32((unsigned char)TEST_CHAR1); + expected_cells[1] = cpu_to_fdt32((unsigned char)TEST_CHAR2); + expected_cells[2] = cpu_to_fdt32((unsigned char)TEST_CHAR3); + expected_cells[3] = cpu_to_fdt32((unsigned char)TEST_CHAR4); + expected_cells[4] = cpu_to_fdt32((unsigned char)TEST_CHAR5); + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + check_getprop(fdt, 0, "char-literal-cells", + sizeof(expected_cells), expected_cells); + + PASS(); +} diff --git a/dtc/tests/char_literal.dts b/dtc/tests/char_literal.dts new file mode 100644 index 000000000..22e17edaf --- /dev/null +++ b/dtc/tests/char_literal.dts @@ -0,0 +1,5 @@ +/dts-v1/; + +/ { + char-literal-cells = <'\r' 'b' '\0' '\'' '\xff'>; +}; diff --git a/dtc/tests/check_full.c b/dtc/tests/check_full.c new file mode 100644 index 000000000..b6d5fc3b1 --- /dev/null +++ b/dtc/tests/check_full.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Tests if two given dtbs are structurally equal (including order) + * Copyright (C) 2007 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static int expect_bad; /* = 0 */ + +int main(int argc, char *argv[]) +{ + const char *filename; + char *fdt; + size_t len; + int err; + + test_init(argc, argv); + if ((argc != 2) + && ((argc != 3) || !streq(argv[1], "-n"))) + CONFIG("Usage: %s [-n] <dtb file>", argv[0]); + if (argc == 3) + expect_bad = 1; + + filename = argv[argc-1]; + err = utilfdt_read_err(filename, &fdt, &len); + if (err) + CONFIG("Couldn't open blob from \"%s\": %s", + filename, strerror(err)); + + vg_prepare_blob(fdt, len); + + err = fdt_check_full(fdt, len); + + if (expect_bad && (err == 0)) + FAIL("fdt_check_full() succeeded unexpectedly"); + else if (!expect_bad && (err != 0)) + FAIL("fdt_check_full() failed: %s", fdt_strerror(err)); + + PASS(); +} diff --git a/dtc/tests/check_header.c b/dtc/tests/check_header.c new file mode 100644 index 000000000..ca26ec106 --- /dev/null +++ b/dtc/tests/check_header.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_check_header + * Copyright (C) 2018 David Gibson + */ + +#include <stdio.h> + +#include <libfdt.h> + +#include "tests.h" + +static void *dtdup(void *dt) +{ + size_t bufsize = fdt_totalsize(dt); + void *buf = xmalloc(bufsize); + fdt_move(dt, buf, bufsize); + return buf; +} + +#define CHECK_MANGLE(exerr, code) \ + do { \ + void *fdt = dtdup(template); \ + { code } \ + err = fdt_check_header(fdt); \ + verbose_printf("\"%s\" => %s\n", #code, fdt_strerror(err)); \ + if (err != (exerr)) \ + FAIL("fdt_check_header() didn't catch mangle %s", \ + #code); \ + free(fdt); \ + } while (0) + +int main(int argc, char *argv[]) +{ + void *template; + int err; + + test_init(argc, argv); + template = load_blob(argv[1]); + + /* Check that the base dt is valid before mangling it */ + err = fdt_check_header(template); + if (err != 0) + FAIL("Base tree fails: %s", fdt_strerror(err)); + + /* Check a no-op mangle doesn't break things */ + CHECK_MANGLE(0, ; ); + + /* Mess up the magic number */ + CHECK_MANGLE(-FDT_ERR_BADMAGIC, + fdt_set_magic(fdt, fdt_magic(fdt) ^ 0x1); + ); + CHECK_MANGLE(-FDT_ERR_BADMAGIC, + fdt_set_magic(fdt, fdt_magic(fdt) ^ 0x80000000); + ); + + /* Mess up the version */ + CHECK_MANGLE(-FDT_ERR_BADVERSION, + fdt_set_version(fdt, FDT_FIRST_SUPPORTED_VERSION - 1); + fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION - 1); + ); + CHECK_MANGLE(-FDT_ERR_BADVERSION, + fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION + 1); + fdt_set_last_comp_version(fdt, FDT_LAST_SUPPORTED_VERSION + 1); + ); + CHECK_MANGLE(-FDT_ERR_BADVERSION, + fdt_set_version(fdt, FDT_FIRST_SUPPORTED_VERSION); + fdt_set_last_comp_version(fdt, FDT_LAST_SUPPORTED_VERSION); + ); + + /* Out of bounds sizes */ + CHECK_MANGLE(-FDT_ERR_TRUNCATED, + fdt_set_totalsize(fdt, FDT_V1_SIZE - 1); + ); + CHECK_MANGLE(-FDT_ERR_TRUNCATED, + fdt_set_totalsize(fdt, (uint32_t)INT_MAX + 1); + ); + + /* Truncate within various blocks */ + CHECK_MANGLE(-FDT_ERR_TRUNCATED, + fdt_set_totalsize(fdt, fdt_off_dt_struct(fdt) - 1); + ); + CHECK_MANGLE(-FDT_ERR_TRUNCATED, + fdt_set_totalsize(fdt, fdt_off_dt_strings(fdt) - 1); + ); + CHECK_MANGLE(-FDT_ERR_TRUNCATED, + fdt_set_totalsize(fdt, fdt_off_mem_rsvmap(fdt) - 1); + ); + CHECK_MANGLE(-FDT_ERR_TRUNCATED, + fdt_set_totalsize(fdt, fdt_off_dt_struct(fdt) + 1); + ); + CHECK_MANGLE(-FDT_ERR_TRUNCATED, + fdt_set_totalsize(fdt, fdt_off_dt_strings(fdt) + 1); + ); + CHECK_MANGLE(-FDT_ERR_TRUNCATED, + fdt_set_totalsize(fdt, fdt_off_mem_rsvmap(fdt) + 1); + ); + + /* Negative block sizes */ + CHECK_MANGLE(-FDT_ERR_TRUNCATED, + fdt_set_size_dt_struct(fdt, (uint32_t)-1); + ); + CHECK_MANGLE(-FDT_ERR_TRUNCATED, + fdt_set_size_dt_strings(fdt, (uint32_t)-1); + ); + CHECK_MANGLE(-FDT_ERR_TRUNCATED, + fdt_set_size_dt_struct(fdt, (uint32_t)INT_MIN); + ); + CHECK_MANGLE(-FDT_ERR_TRUNCATED, + fdt_set_size_dt_strings(fdt, (uint32_t)INT_MIN); + ); + + PASS(); +} diff --git a/dtc/tests/check_path.c b/dtc/tests/check_path.c new file mode 100644 index 000000000..cc9757a0a --- /dev/null +++ b/dtc/tests/check_path.c @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for node existence + * Copyright (C) 2016 Konsulko Inc. + */ + +#include <stdio.h> + +#include <libfdt.h> + +#include "tests.h" + +#define CHECK(code) \ + { \ + int err = (code); \ + if (err) \ + FAIL(#code ": %s", fdt_strerror(err)); \ + } + +/* 4k ought to be enough for anybody */ +#define FDT_COPY_SIZE (4 * 1024) + +static void *open_dt(char *path) +{ + void *dt, *copy; + + dt = load_blob(path); + copy = xmalloc(FDT_COPY_SIZE); + + /* + * Resize our DTs to 4k so that we have room to operate on + */ + CHECK(fdt_open_into(dt, copy, FDT_COPY_SIZE)); + + return copy; +} + +int main(int argc, char *argv[]) +{ + void *fdt_base; + int fail_config, exists, check_exists; + + test_init(argc, argv); + fail_config = 0; + + if (argc != 4) + fail_config = 1; + + if (!fail_config) { + if (!strcmp(argv[2], "exists")) + check_exists = 1; + else if (!strcmp(argv[2], "not-exists")) + check_exists = 0; + else + fail_config = 1; + } + + if (fail_config) + CONFIG("Usage: %s <base dtb> <[exists|not-exists]> <node-path>", argv[0]); + + fdt_base = open_dt(argv[1]); + + exists = fdt_path_offset(fdt_base, argv[3]) >= 0; + + if (exists == check_exists) + PASS(); + else + FAIL(); +} diff --git a/dtc/tests/comments-cmp.dts b/dtc/tests/comments-cmp.dts new file mode 100644 index 000000000..4ee9f52dc --- /dev/null +++ b/dtc/tests/comments-cmp.dts @@ -0,0 +1,16 @@ +/dts-v1/; + +/ { + prop1; + prop2; + prop3; + prop4; + prop5; + prop6; + prop7; + prop8; + prop9; + prop10; + child { + }; +}; diff --git a/dtc/tests/comments.dts b/dtc/tests/comments.dts new file mode 100644 index 000000000..0b04b6b88 --- /dev/null +++ b/dtc/tests/comments.dts @@ -0,0 +1,39 @@ +/* regexps for lexing comments are.. tricky. Check if we've actually + * got it right */ +/dts-v1/; + +/ { + // line comment + prop1; + /* comment */ + prop2; + /* multiline + + notaprop1; + + comment */ + prop3; + /**/ + prop4; + /***/ + prop5; + /****/ + prop6; + /* another + * multiline + * comment */ + prop7; + /* yet + * another + * multline + * comment + */ + prop8; + /** try this */ + prop9; + /* and this **/ + prop10; + child /* finally */ { + }; +}; +/* final comment */ diff --git a/dtc/tests/data.S b/dtc/tests/data.S new file mode 100644 index 000000000..86ad539f2 --- /dev/null +++ b/dtc/tests/data.S @@ -0,0 +1,3 @@ +/* Used in combination with dtc -Oasm output to embed + * a device tree in the data section of a .o */ + .data diff --git a/dtc/tests/default-addr-size.dts b/dtc/tests/default-addr-size.dts new file mode 100644 index 000000000..e964a553f --- /dev/null +++ b/dtc/tests/default-addr-size.dts @@ -0,0 +1,7 @@ +/dts-v1/; + +/ { + node { + reg = <0 0 0>; + }; +}; diff --git a/dtc/tests/del_node.c b/dtc/tests/del_node.c new file mode 100644 index 000000000..10846dfbe --- /dev/null +++ b/dtc/tests/del_node.c @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_nop_node() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +int main(int argc, char *argv[]) +{ + void *fdt; + int subnode1_offset, subnode2_offset, subsubnode2_offset; + int err; + int oldsize, delsize, newsize; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + fdt = open_blob_rw(fdt); + + oldsize = fdt_totalsize(fdt); + + subnode1_offset = fdt_path_offset(fdt, "/subnode@1"); + if (subnode1_offset < 0) + FAIL("Couldn't find \"/subnode@1\": %s", + fdt_strerror(subnode1_offset)); + check_getprop_cell(fdt, subnode1_offset, "prop-int", TEST_VALUE_1); + + subnode2_offset = fdt_path_offset(fdt, "/subnode@2"); + if (subnode2_offset < 0) + FAIL("Couldn't find \"/subnode@2\": %s", + fdt_strerror(subnode2_offset)); + check_getprop_cell(fdt, subnode2_offset, "prop-int", TEST_VALUE_2); + + subsubnode2_offset = fdt_path_offset(fdt, "/subnode@2/subsubnode"); + if (subsubnode2_offset < 0) + FAIL("Couldn't find \"/subnode@2/subsubnode\": %s", + fdt_strerror(subsubnode2_offset)); + check_getprop_cell(fdt, subsubnode2_offset, "prop-int", TEST_VALUE_2); + + err = fdt_del_node(fdt, subnode1_offset); + if (err) + FAIL("fdt_del_node(subnode1): %s", fdt_strerror(err)); + + subnode1_offset = fdt_path_offset(fdt, "/subnode@1"); + if (subnode1_offset != -FDT_ERR_NOTFOUND) + FAIL("fdt_path_offset(subnode1) returned \"%s\" instead of \"%s\"", + fdt_strerror(subnode1_offset), + fdt_strerror(-FDT_ERR_NOTFOUND)); + + subnode2_offset = fdt_path_offset(fdt, "/subnode@2"); + if (subnode2_offset < 0) + FAIL("Couldn't find \"/subnode2\": %s", + fdt_strerror(subnode2_offset)); + check_getprop_cell(fdt, subnode2_offset, "prop-int", TEST_VALUE_2); + + subsubnode2_offset = fdt_path_offset(fdt, "/subnode@2/subsubnode"); + if (subsubnode2_offset < 0) + FAIL("Couldn't find \"/subnode@2/subsubnode\": %s", + fdt_strerror(subsubnode2_offset)); + check_getprop_cell(fdt, subsubnode2_offset, "prop-int", TEST_VALUE_2); + + err = fdt_del_node(fdt, subnode2_offset); + if (err) + FAIL("fdt_del_node(subnode2): %s", fdt_strerror(err)); + + subnode1_offset = fdt_path_offset(fdt, "/subnode@1"); + if (subnode1_offset != -FDT_ERR_NOTFOUND) + FAIL("fdt_path_offset(subnode1) returned \"%s\" instead of \"%s\"", + fdt_strerror(subnode1_offset), + fdt_strerror(-FDT_ERR_NOTFOUND)); + + subnode2_offset = fdt_path_offset(fdt, "/subnode@2"); + if (subnode2_offset != -FDT_ERR_NOTFOUND) + FAIL("fdt_path_offset(subnode2) returned \"%s\" instead of \"%s\"", + fdt_strerror(subnode2_offset), + fdt_strerror(-FDT_ERR_NOTFOUND)); + + subsubnode2_offset = fdt_path_offset(fdt, "/subnode@2/subsubnode"); + if (subsubnode2_offset != -FDT_ERR_NOTFOUND) + FAIL("fdt_path_offset(subsubnode2) returned \"%s\" instead of \"%s\"", + fdt_strerror(subsubnode2_offset), + fdt_strerror(-FDT_ERR_NOTFOUND)); + + delsize = fdt_totalsize(fdt); + + err = fdt_pack(fdt); + if (err) + FAIL("fdt_pack(): %s", fdt_strerror(err)); + + newsize = fdt_totalsize(fdt); + + verbose_printf("oldsize = %d, delsize = %d, newsize = %d\n", + oldsize, delsize, newsize); + + if (newsize >= oldsize) + FAIL("Tree failed to shrink after deletions"); + + PASS(); +} diff --git a/dtc/tests/del_property.c b/dtc/tests/del_property.c new file mode 100644 index 000000000..37e83034c --- /dev/null +++ b/dtc/tests/del_property.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_delprop() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +int main(int argc, char *argv[]) +{ + void *fdt; + const uint32_t *intp; + const char *strp; + int err, lenerr; + int oldsize, delsize, newsize; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + fdt = open_blob_rw(fdt); + + oldsize = fdt_totalsize(fdt); + + intp = check_getprop_cell(fdt, 0, "prop-int", TEST_VALUE_1); + verbose_printf("int value was 0x%08x\n", *intp); + + err = fdt_delprop(fdt, 0, "prop-int"); + if (err) + FAIL("Failed to delete \"prop-int\": %s", fdt_strerror(err)); + + intp = fdt_getprop(fdt, 0, "prop-int", &lenerr); + if (intp) + FAIL("prop-int still present after deletion"); + if (lenerr != -FDT_ERR_NOTFOUND) + FAIL("Unexpected error on second getprop: %s", + fdt_strerror(lenerr)); + + strp = check_getprop(fdt, 0, "prop-str", strlen(TEST_STRING_1)+1, + TEST_STRING_1); + verbose_printf("string value was \"%s\"\n", strp); + err = fdt_delprop(fdt, 0, "prop-str"); + if (err) + FAIL("Failed to delete \"prop-str\": %s", fdt_strerror(err)); + + strp = fdt_getprop(fdt, 0, "prop-str", &lenerr); + if (strp) + FAIL("prop-str still present after deletion"); + if (lenerr != -FDT_ERR_NOTFOUND) + FAIL("Unexpected error on second getprop: %s", + fdt_strerror(lenerr)); + + delsize = fdt_totalsize(fdt); + + err = fdt_pack(fdt); + if (err) + FAIL("fdt_pack(): %s\n", fdt_strerror(err)); + + newsize = fdt_totalsize(fdt); + + verbose_printf("oldsize = %d, delsize = %d, newsize = %d\n", + oldsize, delsize, newsize); + + if (newsize >= oldsize) + FAIL("Tree failed to shrink after deletions"); + + PASS(); +} diff --git a/dtc/tests/delete_reinstate_multilabel.dts b/dtc/tests/delete_reinstate_multilabel.dts new file mode 100644 index 000000000..281a6b289 --- /dev/null +++ b/dtc/tests/delete_reinstate_multilabel.dts @@ -0,0 +1,37 @@ +/dts-v1/; + +/* Create some nodes and properties with multiple labels */ + +/ { + label1: label2: prop = "value"; + + label3: label4: node { + label5: label6: prop = "value"; + }; +}; + +/* Delete them, and everything that's part of them, i.e. the labels */ + +/ { + /delete-property/ prop; + /delete-node/ node; +}; + +/* + * Re-instate them. None of the old labels should come back + * + * Note: Do not add any new/extra labels here. As of the time of writing, + * when dtc adds labels to an object, they are added to the head of the list + * of labels, and this test is specifically about ensuring the correct + * handling of lists of labels where the first label in the list is marked as + * deleted. Failure to observe this note may result in the test passing when + * it should not. + */ + +/ { + prop = "value"; + + node { + prop = "value"; + }; +}; diff --git a/dtc/tests/delete_reinstate_multilabel_ref.dts b/dtc/tests/delete_reinstate_multilabel_ref.dts new file mode 100644 index 000000000..28fa1174f --- /dev/null +++ b/dtc/tests/delete_reinstate_multilabel_ref.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +/ { + prop = "value"; + + node { + prop = "value"; + }; +}; diff --git a/dtc/tests/dependencies.cmp b/dtc/tests/dependencies.cmp new file mode 100644 index 000000000..bcd94320b --- /dev/null +++ b/dtc/tests/dependencies.cmp @@ -0,0 +1 @@ +dependencies.test.dtb: dependencies.dts deps_inc1.dtsi deps_inc2.dtsi diff --git a/dtc/tests/dependencies.dts b/dtc/tests/dependencies.dts new file mode 100644 index 000000000..2cfe31bd0 --- /dev/null +++ b/dtc/tests/dependencies.dts @@ -0,0 +1,6 @@ +/dts-v1/; + +/include/ "deps_inc1.dtsi" + +/ { +}; diff --git a/dtc/tests/deps_inc1.dtsi b/dtc/tests/deps_inc1.dtsi new file mode 100644 index 000000000..5c607dcf0 --- /dev/null +++ b/dtc/tests/deps_inc1.dtsi @@ -0,0 +1 @@ +/include/ "deps_inc2.dtsi" diff --git a/dtc/tests/deps_inc2.dtsi b/dtc/tests/deps_inc2.dtsi new file mode 100644 index 000000000..710cecca9 --- /dev/null +++ b/dtc/tests/deps_inc2.dtsi @@ -0,0 +1 @@ +/* Empty */ diff --git a/dtc/tests/division-by-zero.dts b/dtc/tests/division-by-zero.dts new file mode 100644 index 000000000..2984b29ff --- /dev/null +++ b/dtc/tests/division-by-zero.dts @@ -0,0 +1,6 @@ +/dts-v1/; + +/ { + prop-div = < (1/0) >; + prop-mod = < (1%0) >; +}; diff --git a/dtc/tests/dtb_reverse.c b/dtc/tests/dtb_reverse.c new file mode 100644 index 000000000..95b6c1c90 --- /dev/null +++ b/dtc/tests/dtb_reverse.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Tests if two given dtbs are structurally equal (including order) + * Copyright (C) 2010 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <limits.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +#define CHECK(code) \ + { \ + err = (code); \ + if (err) \ + FAIL(#code ": %s", fdt_strerror(err)); \ + } + +static void reverse_reservemap(void *in, void *out, int n) +{ + int err; + uint64_t addr, size; + + verbose_printf("reverse_reservemap(): %d/%d\n", + n, fdt_num_mem_rsv(in)); + + if (n < (fdt_num_mem_rsv(in)-1)) + reverse_reservemap(in, out, n+1); + + CHECK(fdt_get_mem_rsv(in, n, &addr, &size)); + CHECK(fdt_add_reservemap_entry(out, addr, size)); + verbose_printf("Added entry 0x%llx 0x%llx\n", + (unsigned long long)addr, (unsigned long long)size); +} + +static void reverse_properties(void *in, void *out, int offset) +{ + int err; + int len; + const char *name; + const void *data; + + data = fdt_getprop_by_offset(in, offset, &name, &len); + if (!data) + FAIL("fdt_getprop_by_offset(): %s\n", fdt_strerror(len)); + + verbose_printf("reverse_properties(): offset=%d name=%s\n", + offset, name); + + offset = fdt_next_property_offset(in, offset); + if (offset >= 0) + reverse_properties(in, out, offset); + else if (offset != -FDT_ERR_NOTFOUND) + FAIL("fdt_next_property_offset(): %s\n", fdt_strerror(offset)); + + CHECK(fdt_property(out, name, data, len)); + verbose_printf(" -> output property %s\n", name); +} + +static void reverse_node(void *in, void *out, int nodeoffset); + +static void reverse_children(void *in, void *out, int offset) +{ + int err; + int nextoffset = offset; + int depth = 1; + + do { + char path[PATH_MAX]; + + CHECK(fdt_get_path(in, nextoffset, path, sizeof(path))); + verbose_printf("reverse_children() offset=%d nextoffset=%d [%s]" + " depth=%d\n", offset, nextoffset, path, depth); + + nextoffset = fdt_next_node(in, nextoffset, &depth); + } while ((depth >= 0) && (depth != 1)); + + if (depth == 1) + reverse_children(in, out, nextoffset); + + reverse_node(in, out, offset); +} + +static void reverse_node(void *in, void *out, int nodeoffset) +{ + const char *name = fdt_get_name(in, nodeoffset, NULL); + char path[PATH_MAX]; + int err; + int offset; + int depth = 0; + + CHECK(fdt_get_path(in, nodeoffset, path, sizeof(path))); + verbose_printf("reverse_node(): nodeoffset=%d [%s]\n", + nodeoffset, path); + + CHECK(fdt_begin_node(out, name)); + + offset = fdt_first_property_offset(in, nodeoffset); + if (offset >= 0) + reverse_properties(in, out, offset); + else if (offset != -FDT_ERR_NOTFOUND) + FAIL("fdt_first_property(): %s\n", fdt_strerror(offset)); + + offset = fdt_next_node(in, nodeoffset, &depth); + + if (depth == 1) + reverse_children(in, out, offset); + + CHECK(fdt_end_node(out)); +} + +int main(int argc, char *argv[]) +{ + void *in, *out; + char outname[PATH_MAX]; + int bufsize; + int err; + + test_init(argc, argv); + if (argc != 2) + CONFIG("Usage: %s <dtb file>", argv[0]); + + in = load_blob(argv[1]); + sprintf(outname, "%s.reversed.test.dtb", argv[1]); + + bufsize = fdt_totalsize(in); + out = xmalloc(bufsize); + + CHECK(fdt_create(out, bufsize)); + + fdt_set_boot_cpuid_phys(out, fdt_boot_cpuid_phys(in)); + + reverse_reservemap(in, out, 0); + CHECK(fdt_finish_reservemap(out)); + + reverse_node(in, out, 0); + + CHECK(fdt_finish(out)); + + save_blob(outname, out); + + PASS(); +} diff --git a/dtc/tests/dtbs_equal_ordered.c b/dtc/tests/dtbs_equal_ordered.c new file mode 100644 index 000000000..90c7344d8 --- /dev/null +++ b/dtc/tests/dtbs_equal_ordered.c @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Tests if two given dtbs are structurally equal (including order) + * Copyright (C) 2007 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static int notequal; /* = 0 */ + +#define MISMATCH(fmt, ...) \ + do { \ + if (notequal) \ + PASS(); \ + else \ + FAIL(fmt, ##__VA_ARGS__); \ + } while (0) + +#define MATCH() \ + do { \ + if (!notequal) \ + PASS(); \ + else \ + FAIL("Trees match which shouldn't"); \ + } while (0) + +#define CHECK(code) \ + { \ + err = (code); \ + if (err) \ + FAIL(#code ": %s", fdt_strerror(err)); \ + } + +static void compare_mem_rsv(const void *fdt1, const void *fdt2) +{ + int i; + uint64_t addr1, size1, addr2, size2; + int err; + + if (fdt_num_mem_rsv(fdt1) != fdt_num_mem_rsv(fdt2)) + MISMATCH("Trees have different number of reserve entries"); + for (i = 0; i < fdt_num_mem_rsv(fdt1); i++) { + CHECK(fdt_get_mem_rsv(fdt1, i, &addr1, &size1)); + CHECK(fdt_get_mem_rsv(fdt2, i, &addr2, &size2)); + + if ((addr1 != addr2) || (size1 != size2)) + MISMATCH("Mismatch in reserve entry %d: " + "(0x%llx, 0x%llx) != (0x%llx, 0x%llx)", i, + (unsigned long long)addr1, + (unsigned long long)size1, + (unsigned long long)addr2, + (unsigned long long)size2); + } +} + +static void compare_structure(const void *fdt1, const void *fdt2) +{ + int nextoffset1 = 0, nextoffset2 = 0; + int offset1, offset2; + uint32_t tag1, tag2; + const char *name1, *name2; + int err; + const struct fdt_property *prop1, *prop2; + int len1, len2; + + while (1) { + do { + offset1 = nextoffset1; + tag1 = fdt_next_tag(fdt1, offset1, &nextoffset1); + } while (tag1 == FDT_NOP); + do { + offset2 = nextoffset2; + tag2 = fdt_next_tag(fdt2, offset2, &nextoffset2); + } while (tag2 == FDT_NOP); + + if (tag1 != tag2) + MISMATCH("Tag mismatch (%d != %d) at (%d, %d)", + tag1, tag2, offset1, offset2); + + switch (tag1) { + case FDT_BEGIN_NODE: + name1 = fdt_get_name(fdt1, offset1, &err); + if (!name1) + FAIL("fdt_get_name(fdt1, %d, ..): %s", + offset1, fdt_strerror(err)); + name2 = fdt_get_name(fdt2, offset2, NULL); + if (!name2) + FAIL("fdt_get_name(fdt2, %d, ..): %s", + offset2, fdt_strerror(err)); + + if (!streq(name1, name2)) + MISMATCH("Name mismatch (\"%s\" != \"%s\") at (%d, %d)", + name1, name2, offset1, offset2); + break; + + case FDT_PROP: + prop1 = fdt_offset_ptr(fdt1, offset1, sizeof(*prop1)); + if (!prop1) + FAIL("Could get fdt1 property at %d", offset1); + prop2 = fdt_offset_ptr(fdt2, offset2, sizeof(*prop2)); + if (!prop2) + FAIL("Could get fdt2 property at %d", offset2); + + name1 = fdt_string(fdt1, fdt32_to_cpu(prop1->nameoff)); + name2 = fdt_string(fdt2, fdt32_to_cpu(prop2->nameoff)); + if (!streq(name1, name2)) + MISMATCH("Property name mismatch \"%s\" != \"%s\" " + "at (%d, %d)", name1, name2, offset1, offset2); + len1 = fdt32_to_cpu(prop1->len); + len2 = fdt32_to_cpu(prop2->len); + if (len1 != len2) + MISMATCH("Property length mismatch %u != %u " + "at (%d, %d)", len1, len2, offset1, offset2); + + if (memcmp(prop1->data, prop2->data, len1) != 0) + MISMATCH("Property value mismatch at (%d, %d)", + offset1, offset2); + break; + + case FDT_END: + return; + } + } +} + +int main(int argc, char *argv[]) +{ + void *fdt1, *fdt2; + uint32_t cpuid1, cpuid2; + + test_init(argc, argv); + if ((argc != 3) + && ((argc != 4) || !streq(argv[1], "-n"))) + CONFIG("Usage: %s [-n] <dtb file> <dtb file>", argv[0]); + if (argc == 4) + notequal = 1; + + fdt1 = load_blob(argv[argc-2]); + fdt2 = load_blob(argv[argc-1]); + + compare_mem_rsv(fdt1, fdt2); + compare_structure(fdt1, fdt2); + + cpuid1 = fdt_boot_cpuid_phys(fdt1); + cpuid2 = fdt_boot_cpuid_phys(fdt2); + if (cpuid1 != cpuid2) + MISMATCH("boot_cpuid_phys mismatch 0x%x != 0x%x", + cpuid1, cpuid2); + + MATCH(); +} diff --git a/dtc/tests/dtbs_equal_unordered.c b/dtc/tests/dtbs_equal_unordered.c new file mode 100644 index 000000000..e5ff9e8b1 --- /dev/null +++ b/dtc/tests/dtbs_equal_unordered.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Tests if two given dtbs are structurally equal (including order) + * Copyright (C) 2007 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <limits.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static int notequal; /* = 0 */ +static int ignore_memrsv; /* = 0 */ + +#define MISMATCH(fmt, ...) \ + do { \ + if (notequal) \ + PASS(); \ + else \ + FAIL(fmt, ##__VA_ARGS__); \ + } while (0) + +#define MATCH() \ + do { \ + if (!notequal) \ + PASS(); \ + else \ + FAIL("Trees match which shouldn't"); \ + } while (0) + +#define CHECK(code) \ + { \ + err = (code); \ + if (err) \ + FAIL(#code ": %s", fdt_strerror(err)); \ + } + +static int mem_rsv_cmp(const void *p1, const void *p2) +{ + const struct fdt_reserve_entry *re1 = p1; + const struct fdt_reserve_entry *re2 = p2; + + if (fdt64_to_cpu(re1->address) < fdt64_to_cpu(re2->address)) + return -1; + else if (fdt64_to_cpu(re1->address) > fdt64_to_cpu(re2->address)) + return 1; + + if (fdt64_to_cpu(re1->size) < fdt64_to_cpu(re2->size)) + return -1; + else if (fdt64_to_cpu(re1->size) > fdt64_to_cpu(re2->size)) + return 1; + + return 0; +} + +static void compare_mem_rsv(void *fdt1, void *fdt2) +{ + int i; + uint64_t addr1, size1, addr2, size2; + int err; + + if (fdt_num_mem_rsv(fdt1) != fdt_num_mem_rsv(fdt2)) + MISMATCH("Trees have different number of reserve entries"); + + qsort((char *)fdt1 + fdt_off_mem_rsvmap(fdt1), fdt_num_mem_rsv(fdt1), + sizeof(struct fdt_reserve_entry), mem_rsv_cmp); + qsort((char *)fdt2 + fdt_off_mem_rsvmap(fdt2), fdt_num_mem_rsv(fdt2), + sizeof(struct fdt_reserve_entry), mem_rsv_cmp); + + for (i = 0; i < fdt_num_mem_rsv(fdt1); i++) { + CHECK(fdt_get_mem_rsv(fdt1, i, &addr1, &size1)); + CHECK(fdt_get_mem_rsv(fdt2, i, &addr2, &size2)); + + if ((addr1 != addr2) || (size1 != size2)) + MISMATCH("Mismatch in reserve entry %d: " + "(0x%llx, 0x%llx) != (0x%llx, 0x%llx)", i, + (unsigned long long)addr1, + (unsigned long long)size1, + (unsigned long long)addr2, + (unsigned long long)size2); + } +} + +static void compare_properties(const void *fdt1, int offset1, + const void *fdt2, int offset2) +{ + int offset = offset1; + + /* Check the properties */ + for (offset = fdt_first_property_offset(fdt1, offset1); + offset >= 0; + offset = fdt_next_property_offset(fdt1, offset)) { + const char *name; + int len1, len2; + const void *data1, *data2; + int i; + + data1 = fdt_getprop_by_offset(fdt1, offset, &name, &len1); + if (!data1) + FAIL("fdt_getprop_by_offset(): %s\n", + fdt_strerror(len1)); + + verbose_printf("Property '%s'\n", name); + + data2 = fdt_getprop(fdt2, offset2, name, &len2); + if (!data2) { + if (len2 == -FDT_ERR_NOTFOUND) + MISMATCH("Property '%s' missing\n", name); + else + FAIL("fdt_get_property(): %s\n", + fdt_strerror(len2)); + } + + verbose_printf("len1=%d data1=", len1); + for (i = 0; i < len1; i++) + verbose_printf(" %02x", ((const char *)data1)[i]); + verbose_printf("\nlen2=%d data2=", len2); + for (i = 0; i < len1; i++) + verbose_printf(" %02x", ((const char *)data2)[i]); + verbose_printf("\n"); + + if (len1 != len2) + MISMATCH("Property '%s' mismatched length %d vs. %d\n", + name, len1, len2); + else if (memcmp(data1, data2, len1) != 0) + MISMATCH("Property '%s' mismatched value\n", name); + } +} + +static void compare_node(const void *fdt1, int offset1, + const void *fdt2, int offset2); + +static void compare_subnodes(const void *fdt1, int offset1, + const void *fdt2, int offset2, + int recurse) +{ + int coffset1, coffset2, depth; + + for (depth = 0, coffset1 = offset1; + (coffset1 >= 0) && (depth >= 0); + coffset1 = fdt_next_node(fdt1, coffset1, &depth)) + if (depth == 1) { + const char *name = fdt_get_name(fdt1, coffset1, NULL); + + verbose_printf("Subnode %s\n", name); + coffset2 = fdt_subnode_offset(fdt2, offset2, name); + if (coffset2 == -FDT_ERR_NOTFOUND) + MISMATCH("Subnode %s missing\n", name); + else if (coffset2 < 0) + FAIL("fdt_subnode_offset(): %s\n", + fdt_strerror(coffset2)); + + if (recurse) + compare_node(fdt1, coffset1, fdt2, coffset2); + } +} + +static void compare_node(const void *fdt1, int offset1, + const void *fdt2, int offset2) +{ + int err; + char path1[PATH_MAX], path2[PATH_MAX]; + + CHECK(fdt_get_path(fdt1, offset1, path1, sizeof(path1))); + CHECK(fdt_get_path(fdt2, offset2, path2, sizeof(path2))); + + if (!streq(path1, path2)) + TEST_BUG("Path mismatch %s vs. %s\n", path1, path2); + + verbose_printf("Checking %s\n", path1); + + compare_properties(fdt1, offset1, fdt2, offset2); + compare_properties(fdt2, offset2, fdt1, offset1); + + compare_subnodes(fdt1, offset1, fdt2, offset2, 1); + compare_subnodes(fdt2, offset2, fdt1, offset1, 0); +} + +static void badargs(char **argv) +{ + CONFIG("Usage: %s [-n] [-m] <dtb file> <dtb file>", argv[0]); +} + +int main(int argc, char *argv[]) +{ + void *fdt1, *fdt2; + uint32_t cpuid1, cpuid2; + char **args; + int argsleft; + + test_init(argc, argv); + + args = &argv[1]; + argsleft = argc - 1; + + while (argsleft > 2) { + if (streq(args[0], "-n")) + notequal = 1; + else if (streq(args[0], "-m")) + ignore_memrsv = 1; + else + badargs(argv); + args++; + argsleft--; + } + if (argsleft != 2) + badargs(argv); + + fdt1 = load_blob(args[0]); + fdt2 = load_blob(args[1]); + + if (!ignore_memrsv) + compare_mem_rsv(fdt1, fdt2); + compare_node(fdt1, 0, fdt2, 0); + + cpuid1 = fdt_boot_cpuid_phys(fdt1); + cpuid2 = fdt_boot_cpuid_phys(fdt2); + if (cpuid1 != cpuid2) + MISMATCH("boot_cpuid_phys mismatch 0x%x != 0x%x", + cpuid1, cpuid2); + + MATCH(); +} diff --git a/dtc/tests/dtc-checkfails.sh b/dtc/tests/dtc-checkfails.sh new file mode 100755 index 000000000..4fd9691a2 --- /dev/null +++ b/dtc/tests/dtc-checkfails.sh @@ -0,0 +1,45 @@ +#! /bin/sh + +SRCDIR=`dirname "$0"` +. "$SRCDIR/testutils.sh" + +for x; do + shift + if [ "$x" = "-n" ]; then + for x; do + shift + if [ "$x" = "--" ]; then + break; + fi + NOCHECKS="$NOCHECKS $x" + done + break; + fi + if [ "$x" = "--" ]; then + break; + fi + YESCHECKS="$YESCHECKS $x" +done + +LOG=tmp.log.$$ +rm -f $LOG +trap "rm -f $LOG" 0 + +verbose_run_log "$LOG" $VALGRIND "$DTC" -o /dev/null "$@" +ret="$?" + +FAIL_IF_SIGNAL $ret + +for c in $YESCHECKS; do + if ! grep -E "(ERROR|Warning) \($c\):" $LOG > /dev/null; then + FAIL "Failed to trigger check \"$c\"" + fi +done + +for c in $NOCHECKS; do + if grep -E "(ERROR|Warning) \($c\):" $LOG > /dev/null; then + FAIL "Incorrectly triggered check \"$c\"" + fi +done + +PASS diff --git a/dtc/tests/dtc-fails.sh b/dtc/tests/dtc-fails.sh new file mode 100755 index 000000000..855b623a1 --- /dev/null +++ b/dtc/tests/dtc-fails.sh @@ -0,0 +1,31 @@ +#! /bin/sh + +SRCDIR=`dirname "$0"` +. "$SRCDIR/testutils.sh" + +if [ "$1" = "-n" ]; then + NEG="$1" + shift +fi + +OUTPUT="$1" +shift + +verbose_run $VALGRIND "$DTC" -o "$OUTPUT" "$@" +ret="$?" + +FAIL_IF_SIGNAL $ret + +if [ -n "$NEG" ]; then + if [ ! -e "$OUTPUT" ]; then + FAIL "Produced no output" + fi +else + if [ -e "$OUTPUT" ]; then + FAIL "Incorrectly produced output" + fi +fi + +rm -f "$OUTPUT" + +PASS diff --git a/dtc/tests/dtc-fatal.sh b/dtc/tests/dtc-fatal.sh new file mode 100755 index 000000000..08a4d295a --- /dev/null +++ b/dtc/tests/dtc-fatal.sh @@ -0,0 +1,15 @@ +#! /bin/sh + +SRCDIR=`dirname "$0"` +. "$SRCDIR/testutils.sh" + +verbose_run $VALGRIND "$DTC" -o/dev/null "$@" +ret="$?" + +if [ "$ret" -gt 127 ]; then + FAIL "dtc killed by signal (ret=$ret)" +elif [ "$ret" != "1" ]; then + FAIL "dtc returned incorrect status $ret instead of 1" +fi + +PASS diff --git a/dtc/tests/dumptrees.c b/dtc/tests/dumptrees.c new file mode 100644 index 000000000..f1e0ea970 --- /dev/null +++ b/dtc/tests/dumptrees.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * dumptrees - utility for libfdt testing + * + * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2006. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "testdata.h" + +static struct { + void *blob; + const char *filename; +} trees[] = { +#define TREE(name) { &name, #name ".dtb" } + TREE(test_tree1), + TREE(bad_node_char), TREE(bad_node_format), TREE(bad_prop_char), + TREE(ovf_size_strings), + TREE(truncated_property), TREE(truncated_string), + TREE(truncated_memrsv), + TREE(two_roots), + TREE(named_root) +}; + +#define NUM_TREES (sizeof(trees) / sizeof(trees[0])) + +int main(int argc, char *argv[]) +{ + int i; + + if (argc != 2) { + fprintf(stderr, "Missing output directory argument\n"); + return 1; + } + + if (chdir(argv[1]) != 0) { + perror("chdir()"); + return 1; + } + + for (i = 0; i < NUM_TREES; i++) { + void *blob = trees[i].blob; + const char *filename = trees[i].filename; + int size; + int fd; + int ret; + + size = fdt_totalsize(blob); + + printf("Tree \"%s\", %d bytes\n", filename, size); + + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (fd < 0) + perror("open()"); + + ret = write(fd, blob, size); + if (ret != size) + perror("write()"); + + close(fd); + } + exit(0); +} diff --git a/dtc/tests/dup-nodename.dts b/dtc/tests/dup-nodename.dts new file mode 100644 index 000000000..2a3aa7596 --- /dev/null +++ b/dtc/tests/dup-nodename.dts @@ -0,0 +1,8 @@ +/dts-v1/; + +/ { + node { + }; + node { + }; +}; diff --git a/dtc/tests/dup-phandle.dts b/dtc/tests/dup-phandle.dts new file mode 100644 index 000000000..c266c6127 --- /dev/null +++ b/dtc/tests/dup-phandle.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +/ { + node1 { + linux,phandle = <1>; + }; + node2 { + linux,phandle = <1>; + }; +}; diff --git a/dtc/tests/dup-propname.dts b/dtc/tests/dup-propname.dts new file mode 100644 index 000000000..8145f6e9d --- /dev/null +++ b/dtc/tests/dup-propname.dts @@ -0,0 +1,6 @@ +/dts-v1/; + +/ { + prop; + prop; +}; diff --git a/dtc/tests/embedded_nul.dts b/dtc/tests/embedded_nul.dts Binary files differnew file mode 100644 index 000000000..7b4993cc5 --- /dev/null +++ b/dtc/tests/embedded_nul.dts diff --git a/dtc/tests/embedded_nul_equiv.dts b/dtc/tests/embedded_nul_equiv.dts new file mode 100644 index 000000000..e978204f0 --- /dev/null +++ b/dtc/tests/embedded_nul_equiv.dts @@ -0,0 +1,6 @@ +/dts-v1/; + +/ { + reserved-names = "aaaaaaaaaaaaaaaaaa\0bbbbbb\0ccccccccccccc"; + reserved-ranges = < 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 >; +}; diff --git a/dtc/tests/empty.dts b/dtc/tests/empty.dts new file mode 100644 index 000000000..e160dad6a --- /dev/null +++ b/dtc/tests/empty.dts @@ -0,0 +1,4 @@ +/dts-v1/; + +/ { +}; diff --git a/dtc/tests/escapes.dts b/dtc/tests/escapes.dts new file mode 100644 index 000000000..e05ab46bc --- /dev/null +++ b/dtc/tests/escapes.dts @@ -0,0 +1,7 @@ +/dts-v1/; + +/ { + compatible = "test_string_escapes"; + escape-str = "nastystring: \a\b\t\n\v\f\r\\\""; + escape-str-2 = "\xde\xad\xbe\xef"; +}; diff --git a/dtc/tests/extra-terminating-null.c b/dtc/tests/extra-terminating-null.c new file mode 100644 index 000000000..0fa2ca8e1 --- /dev/null +++ b/dtc/tests/extra-terminating-null.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for properties with more than one terminating null + * Copyright (C) 2009 David Gibson, IBM Corporation. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static void check_extranull(void *fdt, const char *prop, const char *str, int numnulls) +{ + int len = strlen(str); + char checkbuf[len+numnulls]; + + memset(checkbuf, 0, sizeof(checkbuf)); + memcpy(checkbuf, TEST_STRING_1, len); + + check_getprop(fdt, 0, prop, len+numnulls, checkbuf); +} + +int main(int argc, char *argv[]) +{ + void *fdt; + + test_init(argc, argv); + + fdt = load_blob_arg(argc, argv); + + check_extranull(fdt, "extranull0", TEST_STRING_1, 1); + check_extranull(fdt, "extranull1,1", TEST_STRING_1, 2); + check_extranull(fdt, "extranull1,2", TEST_STRING_1, 2); + check_extranull(fdt, "extranull2,1", TEST_STRING_1, 3); + check_extranull(fdt, "extranull2,2", TEST_STRING_1, 3); + check_extranull(fdt, "extranull2,3", TEST_STRING_1, 3); + check_extranull(fdt, "extranull2,4", TEST_STRING_1, 3); + + PASS(); +} diff --git a/dtc/tests/extra-terminating-null.dts b/dtc/tests/extra-terminating-null.dts new file mode 100644 index 000000000..b6cc19c18 --- /dev/null +++ b/dtc/tests/extra-terminating-null.dts @@ -0,0 +1,11 @@ +/dts-v1/; + +/ { + extranull0 = "hello world"; + extranull1,1 = "hello world\0"; + extranull1,2 = "hello world", ""; + extranull2,1 = "hello world\0\0"; + extranull2,2 = "hello world", "", ""; + extranull2,3 = "hello world\0", ""; + extranull2,4 = "hello world", "\0"; +}; diff --git a/dtc/tests/fdtdump-runtest.sh b/dtc/tests/fdtdump-runtest.sh new file mode 100755 index 000000000..71ac86147 --- /dev/null +++ b/dtc/tests/fdtdump-runtest.sh @@ -0,0 +1,31 @@ +#! /bin/sh + +# Arguments: +# $1 - source file to compile and compare with fdtdump output of the +# compiled file. + +SRCDIR=`dirname "$0"` +. "$SRCDIR/testutils.sh" + +dts="$1" +dtb="${dts}.dtb" +out="${dts}.out" +LOG=tmp.log.$$ + +files="$dtb $out $LOG" + +rm -f $files +trap "rm -f $files" 0 + +verbose_run_log_check "$LOG" $VALGRIND $DTC -O dtb $dts -o $dtb +$FDTDUMP ${dtb} | grep -v "//" >${out} + +if diff -w $dts $out >/dev/null; then + PASS +else + if [ -z "$QUIET_TEST" ]; then + echo "DIFF :-:" + diff -u -w $dts $out + fi + FAIL "Results differ from expected" +fi diff --git a/dtc/tests/fdtdump.dts b/dtc/tests/fdtdump.dts new file mode 100644 index 000000000..b83b7dffa --- /dev/null +++ b/dtc/tests/fdtdump.dts @@ -0,0 +1,38 @@ +/dts-v1/; + +/memreserve/ 0 0xe; +/ { + model = "MyBoardName"; + compatible = "MyBoardName", "MyBoardFamilyName"; + #address-cells = <0x00000002>; + #size-cells = <0x00000002>; + cpus { + linux,phandle = <0x00000001>; + #address-cells = <0x00000001>; + #size-cells = <0x00000000>; + PowerPC,970@0 { + device_type = "cpu"; + reg = <0x00000000>; + linux,boot-cpu; + }; + PowerPC,970@1 { + device_type = "cpu"; + reg = <0x00000001>; + }; + }; + randomnode { + string = "foo", "stuff"; + bytes = [61 62 63 64 65]; + nbytes = [80 ff]; + child { + }; + }; + memory@0 { + device_type = "memory"; + reg = <0x00000000 0x00000123 0x00000456 0x87654321>; + }; + chosen { + bootargs = "root=/dev/sda2"; + linux,platform = <0x00000600>; + }; +}; diff --git a/dtc/tests/fdtget-runtest.sh b/dtc/tests/fdtget-runtest.sh new file mode 100755 index 000000000..18b7404a0 --- /dev/null +++ b/dtc/tests/fdtget-runtest.sh @@ -0,0 +1,25 @@ +#! /bin/sh + +SRCDIR=`dirname "$0"` +. "$SRCDIR/testutils.sh" + +LOG=tmp.log.$$ +EXPECT=tmp.expect.$$ +rm -f $LOG $EXPECT +trap "rm -f $LOG $EXPECT" 0 + +expect="$1" +printf '%b\n' "$expect" > $EXPECT +shift + +verbose_run_log_check "$LOG" $VALGRIND $DTGET "$@" + +if cmp $EXPECT $LOG>/dev/null; then + PASS +else + if [ -z "$QUIET_TEST" ]; then + echo "EXPECTED :-:" + cat $EXPECT + fi + FAIL "Results differ from expected" +fi diff --git a/dtc/tests/fdtoverlay-runtest.sh b/dtc/tests/fdtoverlay-runtest.sh new file mode 100755 index 000000000..0c648f499 --- /dev/null +++ b/dtc/tests/fdtoverlay-runtest.sh @@ -0,0 +1,41 @@ +#! /bin/sh + +# Run script for fdtoverlay tests +# We run fdtoverlay to generate a target device tree, then fdtget to check it + +# Usage +# fdtoverlay-runtest.sh name expected_output dtb_file node property flags value + +SRCDIR=`dirname "$0"` +. "$SRCDIR/testutils.sh" + +LOG=tmp.log.$$ +EXPECT=tmp.expect.$$ +rm -f $LOG $EXPECT +trap "rm -f $LOG $EXPECT" 0 + +expect="$1" +echo $expect >$EXPECT +node="$2" +property="$3" +flags="$4" +basedtb="$5" +targetdtb="$6" +shift 6 +overlays="$@" + +# First run fdtoverlay +verbose_run_check $VALGRIND "$FDTOVERLAY" -i "$basedtb" -o "$targetdtb" $overlays + +# Now fdtget to read the value +verbose_run_log_check "$LOG" $VALGRIND "$DTGET" "$targetdtb" "$node" "$property" $flags + +if cmp $EXPECT $LOG >/dev/null; then + PASS +else + if [ -z "$QUIET_TEST" ]; then + echo "EXPECTED :-:" + cat $EXPECT + fi + FAIL "Results differ from expected" +fi diff --git a/dtc/tests/fdtput-runtest.sh b/dtc/tests/fdtput-runtest.sh new file mode 100755 index 000000000..1210eabf4 --- /dev/null +++ b/dtc/tests/fdtput-runtest.sh @@ -0,0 +1,40 @@ +#! /bin/sh + +# Run script for fdtput tests +# We run fdtput to update the device tree, then fdtget to check it + +# Usage +# fdtput-runtest.sh name expected_output dtb_file node property flags value + +SRCDIR=`dirname "$0"` +. "$SRCDIR/testutils.sh" + +LOG=tmp.log.$$ +EXPECT=tmp.expect.$$ +rm -f $LOG $EXPECT +trap "rm -f $LOG $EXPECT" 0 + +expect="$1" +echo $expect >$EXPECT +dtb="$2" +node="$3" +property="$4" +flags="$5" +shift 5 +value="$@" + +# First run fdtput +verbose_run_check $VALGRIND "$DTPUT" "$dtb" "$node" "$property" $value $flags + +# Now fdtget to read the value +verbose_run_log_check "$LOG" $VALGRIND "$DTGET" "$dtb" "$node" "$property" $flags + +if cmp $EXPECT $LOG >/dev/null; then + PASS +else + if [ -z "$QUIET_TEST" ]; then + echo "EXPECTED :-:" + cat $EXPECT + fi + FAIL "Results differ from expected" +fi diff --git a/dtc/tests/find_property.c b/dtc/tests/find_property.c new file mode 100644 index 000000000..0404ea0bb --- /dev/null +++ b/dtc/tests/find_property.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_property_offset() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +int main(int argc, char *argv[]) +{ + void *fdt; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + check_property_cell(fdt, 0, "prop-int", TEST_VALUE_1); + check_property(fdt, 0, "prop-str", strlen(TEST_STRING_1)+1, TEST_STRING_1); + + PASS(); +} diff --git a/dtc/tests/fs_tree1.c b/dtc/tests/fs_tree1.c new file mode 100644 index 000000000..dff388083 --- /dev/null +++ b/dtc/tests/fs_tree1.c @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase/tool constructing an fs tree for further test + * Copyright (C) 2018 David Gibson, Red Hat Inc. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <limits.h> +#include <stdint.h> +#include <sys/stat.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static void start_dir(const char *name) +{ + int rc; + + rc = mkdir(name, 0777); + if (rc != 0) + FAIL("mkdir(\"%s\"): %s", name, strerror(errno)); + + rc = chdir(name); + if (rc != 0) + FAIL("chdir(\"%s\"): %s", name, strerror(errno)); +} + +static void end_dir(void) +{ + int rc; + + rc = chdir(".."); + if (rc != 0) + FAIL("chdir(..): %s", strerror(errno)); +} + +static void mkfile(const char *name, void *data, size_t len) +{ + int fd; + int rc; + + fd = open(name, O_WRONLY|O_CREAT, 0666); + if (fd < 0) + FAIL("open(\"%s\"): %s", name, strerror(errno)); + + rc = write(fd, data, len); + if (rc < 0) + FAIL("write(\"%s\"): %s", name, strerror(errno)); + if (rc != len) + FAIL("write(\"%s\"): short write", name); + + rc = close(fd); + if (rc != 0) + FAIL("close(\"%s\"): %s", name, strerror(errno)); +} + +#define mkfile_str(name, s) \ + do { \ + char str[] = s; \ + mkfile((name), str, sizeof(str)); \ + } while (0) + +static void mkfile_u32(const char *name, uint32_t val) +{ + val = cpu_to_fdt32(val); + mkfile(name, &val, sizeof(val)); +} + +static void mkfile_u64(const char *name, uint64_t val) +{ + val = cpu_to_fdt64(val); + mkfile(name, &val, sizeof(val)); +} + +int main(int argc, char *argv[]) +{ + const char *base; + + test_init(argc, argv); + if (argc != 2) + CONFIG("Usage: %s <path>", argv[0]); + + base = argv[1]; + + start_dir(base); + mkfile_str("compatible", "test_tree1"); + mkfile_u32("prop-int", TEST_VALUE_1); + mkfile_u64("prop-int64", 0xdeadbeef01abcdefULL); + mkfile_str("prop-str", "hello world"); + mkfile_u32("#address-cells", 1); + mkfile_u32("#size-cells", 0); + + { + start_dir("subnode@1"); + + mkfile_str("compatible", "subnode1"); + mkfile_u32("reg", 1); + mkfile_u32("prop-int", TEST_VALUE_1); + + { + start_dir("subsubnode"); + + mkfile_str("compatible", "subsubnode1\0subsubnode"); + mkfile_str("placeholder", "this is a placeholder string\0string2"); + mkfile_u32("prop-int", TEST_VALUE_1); + + end_dir(); + } + + { + start_dir("ss1"); + end_dir(); + } + + end_dir(); + } + + { + start_dir("subnode@2"); + + mkfile_u32("reg", 2); + mkfile_u32("linux,phandle", 0x2000); + mkfile_u32("prop-int", TEST_VALUE_2); + mkfile_u32("#address-cells", 1); + mkfile_u32("#size-cells", 0); + + { + start_dir("subsubnode@0"); + + mkfile_u32("reg", 0); + mkfile_u32("phandle", 0x2001); + mkfile_str("compatible", "subsubnode2\0subsubnode"); + mkfile_u32("prop-int", TEST_VALUE_2); + + end_dir(); + } + + { + start_dir("ss2"); + end_dir(); + } + + end_dir(); + } + + PASS(); +} diff --git a/dtc/tests/get_alias.c b/dtc/tests/get_alias.c new file mode 100644 index 000000000..fb2c38c07 --- /dev/null +++ b/dtc/tests/get_alias.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_get_alias() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static void check_alias(void *fdt, const char *path, const char *alias) +{ + const char *aliaspath; + + aliaspath = fdt_get_alias(fdt, alias); + + if (path && !aliaspath) + FAIL("fdt_get_alias(%s) failed\n", alias); + + if (strcmp(aliaspath, path) != 0) + FAIL("fdt_get_alias(%s) returned %s instead of %s\n", + alias, aliaspath, path); +} + +int main(int argc, char *argv[]) +{ + void *fdt; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + check_alias(fdt, "/subnode@1", "s1"); + check_alias(fdt, "/subnode@1/subsubnode", "ss1"); + check_alias(fdt, "/subnode@1/subsubnode/subsubsubnode", "sss1"); + + PASS(); +} diff --git a/dtc/tests/get_mem_rsv.c b/dtc/tests/get_mem_rsv.c new file mode 100644 index 000000000..f977d19d9 --- /dev/null +++ b/dtc/tests/get_mem_rsv.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_get_mem_rsv() and fdt_num_mem_rsv() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +int main(int argc, char *argv[]) +{ + void *fdt; + int rc; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + rc = fdt_num_mem_rsv(fdt); + if (rc < 0) + FAIL("fdt_num_mem_rsv(): %s", fdt_strerror(rc)); + if (rc != 2) + FAIL("fdt_num_mem_rsv() returned %d instead of 2", rc); + + check_mem_rsv(fdt, 0, TEST_ADDR_1, TEST_SIZE_1); + check_mem_rsv(fdt, 1, TEST_ADDR_2, TEST_SIZE_2); + PASS(); +} diff --git a/dtc/tests/get_name.c b/dtc/tests/get_name.c new file mode 100644 index 000000000..5a35103ff --- /dev/null +++ b/dtc/tests/get_name.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_get_name() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static void check_name(void *fdt, const char *path) +{ + int offset; + const char *getname, *getname2, *checkname; + int len; + + checkname = strrchr(path, '/'); + if (!checkname) + TEST_BUG(); + checkname += 1; + + offset = fdt_path_offset(fdt, path); + if (offset < 0) + FAIL("Couldn't find %s", path); + + getname = fdt_get_name(fdt, offset, &len); + verbose_printf("fdt_get_name(%d) returns \"%s\" (len=%d)\n", + offset, getname, len); + if (!getname) + FAIL("fdt_get_name(%d): %s", offset, fdt_strerror(len)); + + if (strcmp(getname, checkname) != 0) + FAIL("fdt_get_name(%s) returned \"%s\" instead of \"%s\"", + path, getname, checkname); + + if (len != strlen(getname)) + FAIL("fdt_get_name(%s) returned length %d instead of %zd", + path, len, strlen(getname)); + + /* Now check that it doesn't break if we omit len */ + getname2 = fdt_get_name(fdt, offset, NULL); + if (!getname2) + FAIL("fdt_get_name(%d, NULL) failed", offset); + if (strcmp(getname2, getname) != 0) + FAIL("fdt_get_name(%d, NULL) returned \"%s\" instead of \"%s\"", + offset, getname2, getname); +} + +int main(int argc, char *argv[]) +{ + void *fdt; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + check_name(fdt, "/"); + check_name(fdt, "/subnode@1"); + check_name(fdt, "/subnode@2"); + check_name(fdt, "/subnode@1/subsubnode"); + check_name(fdt, "/subnode@2/subsubnode@0"); + + PASS(); +} diff --git a/dtc/tests/get_path.c b/dtc/tests/get_path.c new file mode 100644 index 000000000..734989874 --- /dev/null +++ b/dtc/tests/get_path.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_get_path() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +#define POISON ('\xff') + +static void check_path_buf(void *fdt, const char *path, int pathlen, int buflen) +{ + int offset; + char buf[buflen+1]; + int len; + + offset = fdt_path_offset(fdt, path); + if (offset < 0) + FAIL("Couldn't find path \"%s\": %s", path, fdt_strerror(offset)); + + memset(buf, POISON, sizeof(buf)); /* poison the buffer */ + + len = fdt_get_path(fdt, offset, buf, buflen); + verbose_printf("get_path() %s -> %d -> %s\n", path, offset, + len >= 0 ? buf : "<error>"); + + if (buflen <= pathlen) { + if (len != -FDT_ERR_NOSPACE) + FAIL("fdt_get_path([%d bytes]) returns %d with " + "insufficient buffer space", buflen, len); + } else { + if (len < 0) + FAIL("fdt_get_path([%d bytes]): %s", buflen, + fdt_strerror(len)); + if (len != 0) + FAIL("fdt_get_path([%d bytes]) returns %d " + "instead of 0", buflen, len); + if (strcmp(buf, path) != 0) + FAIL("fdt_get_path([%d bytes]) returns \"%s\" " + "instead of \"%s\"", buflen, buf, path); + } + + if (buf[buflen] != POISON) + FAIL("fdt_get_path([%d bytes]) overran buffer", buflen); +} + +static void check_path(void *fdt, const char *path) +{ + int pathlen = strlen(path); + + check_path_buf(fdt, path, pathlen, 1024); + check_path_buf(fdt, path, pathlen, pathlen+1); + check_path_buf(fdt, path, pathlen, pathlen); + check_path_buf(fdt, path, pathlen, 0); + check_path_buf(fdt, path, pathlen, 2); +} + +int main(int argc, char *argv[]) +{ + void *fdt; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + check_path(fdt, "/"); + check_path(fdt, "/subnode@1"); + check_path(fdt, "/subnode@2"); + check_path(fdt, "/subnode@1/subsubnode"); + check_path(fdt, "/subnode@2/subsubnode@0"); + + PASS(); +} diff --git a/dtc/tests/get_phandle.c b/dtc/tests/get_phandle.c new file mode 100644 index 000000000..157b522d0 --- /dev/null +++ b/dtc/tests/get_phandle.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_get_phandle() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static void check_phandle(void *fdt, const char *path, uint32_t checkhandle) +{ + int offset; + uint32_t phandle; + + offset = fdt_path_offset(fdt, path); + if (offset < 0) + FAIL("Couldn't find %s", path); + + phandle = fdt_get_phandle(fdt, offset); + if (phandle != checkhandle) + FAIL("fdt_get_phandle(%s) returned 0x%x instead of 0x%x\n", + path, phandle, checkhandle); +} + +static void check_phandle_unique(const void *fdt, uint32_t checkhandle) +{ + uint32_t phandle; + int offset = -1; + + while (true) { + offset = fdt_next_node(fdt, offset, NULL); + if (offset < 0) { + if (offset == -FDT_ERR_NOTFOUND) + break; + + FAIL("error looking for phandle %#x", checkhandle); + } + + phandle = fdt_get_phandle(fdt, offset); + + if (phandle == checkhandle) + FAIL("generated phandle already exists"); + } +} + +int main(int argc, char *argv[]) +{ + uint32_t max, phandle; + void *fdt; + int err; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + check_phandle(fdt, "/", 0); + check_phandle(fdt, "/subnode@2", PHANDLE_1); + check_phandle(fdt, "/subnode@2/subsubnode@0", PHANDLE_2); + + err = fdt_find_max_phandle(fdt, &max); + if (err < 0) + FAIL("fdt_find_max_phandle returned %d instead of 0\n", err); + + if (max != PHANDLE_2) + FAIL("fdt_find_max_phandle found 0x%x instead of 0x%x", max, + PHANDLE_2); + + max = fdt_get_max_phandle(fdt); + if (max != PHANDLE_2) + FAIL("fdt_get_max_phandle returned 0x%x instead of 0x%x\n", + max, PHANDLE_2); + + err = fdt_generate_phandle(fdt, &phandle); + if (err < 0) + FAIL("failed to generate phandle: %d", err); + + check_phandle_unique(fdt, phandle); + + PASS(); +} diff --git a/dtc/tests/get_prop_offset.c b/dtc/tests/get_prop_offset.c new file mode 100644 index 000000000..cff3c18ca --- /dev/null +++ b/dtc/tests/get_prop_offset.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_getprop_by_offset() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +int main(int argc, char *argv[]) +{ + bool found_prop_int = false; + bool found_prop_str = false; + int poffset; + void *fdt; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + fdt_for_each_property_offset(poffset, fdt, 0) { + if (check_get_prop_offset_cell(fdt, poffset, "prop-int", + TEST_VALUE_1)) + found_prop_int = true; + if (check_get_prop_offset(fdt, poffset, "prop-str", + strlen(TEST_STRING_1) + 1, + TEST_STRING_1)) + found_prop_str = true; + } + if (!found_prop_int) + FAIL("Property 'prop-int' not found"); + if (!found_prop_str) + FAIL("Property 'prop-str' not found"); + + PASS(); +} diff --git a/dtc/tests/getprop.c b/dtc/tests/getprop.c new file mode 100644 index 000000000..cccc8e2d3 --- /dev/null +++ b/dtc/tests/getprop.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_getprop() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +int main(int argc, char *argv[]) +{ + void *fdt; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + check_getprop_cell(fdt, 0, "prop-int", TEST_VALUE_1); + check_getprop(fdt, 0, "prop-str", strlen(TEST_STRING_1)+1, TEST_STRING_1); + + PASS(); +} diff --git a/dtc/tests/good-gpio.dts b/dtc/tests/good-gpio.dts new file mode 100644 index 000000000..65d1c177a --- /dev/null +++ b/dtc/tests/good-gpio.dts @@ -0,0 +1,12 @@ +/dts-v1/; + +/ { + gpio: gpio-controller { + #gpio-cells = <3>; + }; + + node { + foo,nr-gpios = <1>; + foo-gpios = <&gpio 1 2 3>; + }; +}; diff --git a/dtc/tests/incbin.bin b/dtc/tests/incbin.bin new file mode 100644 index 000000000..e6e3e48d4 --- /dev/null +++ b/dtc/tests/incbin.bin @@ -0,0 +1 @@ +abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
\ No newline at end of file diff --git a/dtc/tests/incbin.c b/dtc/tests/incbin.c new file mode 100644 index 000000000..36ff66984 --- /dev/null +++ b/dtc/tests/incbin.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for string escapes in dtc + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <errno.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +#define CHUNKSIZE 1024 + +static char *load_file(const char *name, int *len) +{ + FILE *f; + char *buf = NULL; + int bufsize = 0, n; + + *len = 0; + + f = fopen(name, "r"); + if (!f) + FAIL("Couldn't open \"%s\": %s", name, strerror(errno)); + + while (!feof(f)) { + if (bufsize < (*len + CHUNKSIZE)) { + buf = xrealloc(buf, *len + CHUNKSIZE); + bufsize = *len + CHUNKSIZE; + } + + n = fread(buf + *len, 1, CHUNKSIZE, f); + if (ferror(f)) + FAIL("Error reading \"%s\": %s", name, strerror(errno)); + *len += n; + } + + return buf; +} + +int main(int argc, char *argv[]) +{ + void *fdt; + char *incbin; + int len; + + test_init(argc, argv); + + if (argc != 3) + CONFIG("Usage: %s <incbin file> <dtb file>", argv[0]); + + incbin = load_file(argv[1], &len); + fdt = load_blob(argv[2]); + + check_getprop(fdt, 0, "incbin", len, incbin); + check_getprop(fdt, 0, "incbin-partial", 17, incbin + 13); + + PASS(); +} diff --git a/dtc/tests/incbin.dts b/dtc/tests/incbin.dts new file mode 100644 index 000000000..7c30e0ec4 --- /dev/null +++ b/dtc/tests/incbin.dts @@ -0,0 +1,6 @@ +/dts-v1/; + +/ { + incbin = /incbin/("incbin.bin"); + incbin-partial = /incbin/("incbin.bin", 13, 17); +}; diff --git a/dtc/tests/include0.dts b/dtc/tests/include0.dts new file mode 100644 index 000000000..355ed6a92 --- /dev/null +++ b/dtc/tests/include0.dts @@ -0,0 +1 @@ +/include/ "include1.dts" diff --git a/dtc/tests/include1.dts b/dtc/tests/include1.dts new file mode 100644 index 000000000..0b4b773e6 --- /dev/null +++ b/dtc/tests/include1.dts @@ -0,0 +1,32 @@ +/dts-v1/; + +/include/ "include2.dts" +/memreserve/ /include/ "include3.dts"; + +/ { + /include/ "include4.dts" + /include/ "include5.dts" = <0xdeadbeef>; + prop-int64 /include/ "include5a.dts"; + prop-str = /include/ "include6.dts"; + #address-cells = <1>; + #size-cells = <0>; + + /include/ "include7.dts" + + subnode@2 { + reg = <2>; + linux,phandle = <0x2000>; + prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; + + /include/ "include8.dts" + phandle = <0x2001>; + compatible = "subsubnode2", "subsubnode"; + prop-int = <0726746425>; + }; + + ss2 { + }; + }; +}; diff --git a/dtc/tests/include2.dts b/dtc/tests/include2.dts new file mode 100644 index 000000000..7e189dd77 --- /dev/null +++ b/dtc/tests/include2.dts @@ -0,0 +1 @@ +/memreserve/ 0xdeadbeef00000000 0x100000; diff --git a/dtc/tests/include3.dts b/dtc/tests/include3.dts new file mode 100644 index 000000000..ee9d277aa --- /dev/null +++ b/dtc/tests/include3.dts @@ -0,0 +1 @@ +123456789 010000 diff --git a/dtc/tests/include4.dts b/dtc/tests/include4.dts new file mode 100644 index 000000000..b2ddbe5a0 --- /dev/null +++ b/dtc/tests/include4.dts @@ -0,0 +1 @@ + compatible = "test_tree1"; diff --git a/dtc/tests/include5.dts b/dtc/tests/include5.dts new file mode 100644 index 000000000..9a35dc54e --- /dev/null +++ b/dtc/tests/include5.dts @@ -0,0 +1 @@ +prop-int diff --git a/dtc/tests/include5a.dts b/dtc/tests/include5a.dts new file mode 100644 index 000000000..39ddba4fb --- /dev/null +++ b/dtc/tests/include5a.dts @@ -0,0 +1 @@ += /bits/ 64 <0xdeadbeef01abcdef>
\ No newline at end of file diff --git a/dtc/tests/include6.dts b/dtc/tests/include6.dts new file mode 100644 index 000000000..cd4bc1ab6 --- /dev/null +++ b/dtc/tests/include6.dts @@ -0,0 +1 @@ +"hello world" diff --git a/dtc/tests/include7.dts b/dtc/tests/include7.dts new file mode 100644 index 000000000..ab2c948f0 --- /dev/null +++ b/dtc/tests/include7.dts @@ -0,0 +1,14 @@ + subnode@1 { + compatible = "subnode1"; + reg = <1>; + prop-int = [deadbeef]; + + subsubnode { + compatible = "subsubnode1", "subsubnode"; + placeholder = "this is a placeholder string", "string2"; + prop-int = <0xdeadbeef>; + }; + + ss1 { + }; + }; diff --git a/dtc/tests/include8.dts b/dtc/tests/include8.dts new file mode 100644 index 000000000..7532ef51d --- /dev/null +++ b/dtc/tests/include8.dts @@ -0,0 +1,2 @@ +subsubnode@0 { + reg = <0>; diff --git a/dtc/tests/integer-expressions.c b/dtc/tests/integer-expressions.c new file mode 100644 index 000000000..6f33d818e --- /dev/null +++ b/dtc/tests/integer-expressions.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Testcase for dtc expression support + * + * Copyright (C) 2008 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <errno.h> + + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static struct test_expr { + const char *expr; + uint32_t result; +} expr_table[] = { +#define TE(expr) { #expr, (expr) } + TE(0xdeadbeef), + TE(-0x21524111), + TE(1+1), + TE(2*3), + TE(4/2), + TE(10/3), + TE(19%4), + TE(1 << 13), + TE(0x1000 >> 4), + TE(3*2+1), TE(3*(2+1)), + TE(1+2*3), TE((1+2)*3), + TE(1 < 2), TE(2 < 1), TE(1 < 1), + TE(1 <= 2), TE(2 <= 1), TE(1 <= 1), + TE(1 > 2), TE(2 > 1), TE(1 > 1), + TE(1 >= 2), TE(2 >= 1), TE(1 >= 1), + TE(1 == 1), TE(1 == 2), + TE(1 != 1), TE(1 != 2), + TE(0xabcdabcd & 0xffff0000), + TE(0xdead4110 ^ 0xf0f0f0f0), + TE(0xabcd0000 | 0x0000abcd), + TE(~0x21524110), + TE(~~0xdeadbeef), + TE(0 && 0), TE(17 && 0), TE(0 && 17), TE(17 && 17), + TE(0 || 0), TE(17 || 0), TE(0 || 17), TE(17 || 17), + TE(!0), TE(!1), TE(!17), TE(!!0), TE(!!17), + TE(0 ? 17 : 39), TE(1 ? 17 : 39), TE(17 ? 0xdeadbeef : 0xabcd1234), + TE(11 * 257 * 1321517ULL), + TE(123456790 - 4/2 + 17%4), +}; + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +int main(int argc, char *argv[]) +{ + void *fdt; + const fdt32_t *res; + int reslen; + int i; + + test_init(argc, argv); + + if ((argc == 3) && (strcmp(argv[1], "-g") == 0)) { + FILE *f = fopen(argv[2], "w"); + + if (!f) + FAIL("Couldn't open \"%s\" for output: %s\n", + argv[2], strerror(errno)); + + fprintf(f, "/dts-v1/;\n"); + fprintf(f, "/ {\n"); + fprintf(f, "\texpressions = <\n"); + for (i = 0; i < ARRAY_SIZE(expr_table); i++) + fprintf(f, "\t\t(%s)\n", expr_table[i].expr); + fprintf(f, "\t>;\n"); + fprintf(f, "};\n"); + fclose(f); + } else { + fdt = load_blob_arg(argc, argv); + + res = fdt_getprop(fdt, 0, "expressions", &reslen); + + if (!res) + FAIL("Error retrieving expression results: %s\n", + fdt_strerror(reslen)); + + if (reslen != (ARRAY_SIZE(expr_table) * sizeof(uint32_t))) + FAIL("Unexpected length of results %d instead of %zd\n", + reslen, ARRAY_SIZE(expr_table) * sizeof(uint32_t)); + + for (i = 0; i < ARRAY_SIZE(expr_table); i++) + if (fdt32_to_cpu(res[i]) != expr_table[i].result) + FAIL("Incorrect result for expression \"%s\"," + " 0x%x instead of 0x%x\n", + expr_table[i].expr, fdt32_to_cpu(res[i]), + expr_table[i].result); + } + + PASS(); +} diff --git a/dtc/tests/label01.dts b/dtc/tests/label01.dts new file mode 100644 index 000000000..a8958034f --- /dev/null +++ b/dtc/tests/label01.dts @@ -0,0 +1,63 @@ +/dts-v1/; + +/memreserve/ 0x1000000000000000 0x0000000002000000; +memrsv2: /memreserve/ 0x2000000000000000 0x0100000000000000; +/memreserve/ 0x0000000000000000 0x0000000000000014; + +/ { + model = "MyBoardName"; + compatible = "MyBoardName", "MyBoardFamilyName"; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + linux,phandle = <0x1>; + #address-cells = <1>; + #size-cells = <0>; + PowerPC,970@0 { + name = "PowerPC,970"; + device_type = "cpu"; + reg = <0x00000000>; + clock-frequency = <1600000000>; + timebase-frequency = <33333333>; + linux,boot-cpu; + i-cache-size = <65536>; + d-cache-size = <32768>; + }; + + PowerPC,970@1 { + name = "PowerPC,970"; + device_type = "cpu"; + reg = <0x00000001>; + clock-frequency = <1600000000>; + timebase-frequency = <33333333>; + i-cache-size = <65536>; + d-cache-size = <32768>; + }; + + }; + + node: randomnode { + prop: string = str: "foo", str_mid: "stuffstuff\t\t\t\n\n\n" str_end: ; + blob = [byte: 0a 0b 0c 0d byte_mid: de ea ad be ef byte_end: ]; + ref = < cell: &{/memory@0} 0x0 cell_mid: 0xffffffff cell_end: >; + mixed = "abc", pre: [1234] post: , gap: < aligned: 0xa 0xb 0xc>; + tricky1 = [61 lt1: 62 63 00]; + subnode: child { + }; + /* subnode_end: is auto-generated by node emit */ + }; + /* node_end: is auto-generated by node emit */ + + memory@0 { + device_type = "memory"; + memreg: reg = <0x00000000 0x00000000 0x00000000 0x20000000>; + }; + + chosen { + bootargs = "root=/dev/sda2"; + linux,platform = <0x600>; + }; + +}; + diff --git a/dtc/tests/label_repeated.dts b/dtc/tests/label_repeated.dts new file mode 100644 index 000000000..34225d331 --- /dev/null +++ b/dtc/tests/label_repeated.dts @@ -0,0 +1,15 @@ +/dts-v1/; + +/ { + l0: prop = "foo"; + + l1: node { + }; +}; + +/ { + l0: prop = "foo"; + + l1: node { + }; +}; diff --git a/dtc/tests/line_directives.dts b/dtc/tests/line_directives.dts new file mode 100644 index 000000000..67b5e084f --- /dev/null +++ b/dtc/tests/line_directives.dts @@ -0,0 +1,26 @@ +/dts-v1/; + +/* common format */ +#line 3 "foo.dts" +/* newer gcc format */ +# 9 "baz.dts" 1 +/* flags are optional */ +# 6 "bar.dts" + +/ { +/* + * Make sure optional flags don't consume integer data on next line. The issue + * was that the {WS} in the trailing ({WS}+[0-9]+)? could cross the * line- + * break, and consume the leading "0" of the hex constant, leaving "x12345678" + * to be parsed as a number, which is invalid syntax. + */ + prop1 = < +# 10 "qux.dts" + 0x12345678 + >; +/* + * Check processing of escapes in filenames + */ +# 100 "\".dts" +# 200 "\\.dts" +}; diff --git a/dtc/tests/lorem.txt b/dtc/tests/lorem.txt new file mode 100644 index 000000000..acff69837 --- /dev/null +++ b/dtc/tests/lorem.txt @@ -0,0 +1,35 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris eros +arcu, egestas non pellentesque non, euismod eu nibh. Proin arcu metus, +dapibus vitae sodales rhoncus, suscipit vel nulla. Etiam lorem est, +aliquam ut fringilla sit amet, condimentum et quam. Duis eu arcu odio, +at pulvinar nisi. Morbi condimentum eros ut turpis rhoncus +pharetra. Pellentesque habitant morbi tristique senectus et netus et +malesuada fames ac turpis egestas. Nam et nulla enim. Etiam fringilla +eleifend neque, at posuere ante lacinia a. Duis orci tortor, dictum ac +gravida ac, euismod eu leo. Sed eget dolor tortor. Pellentesque +venenatis, lectus eu vulputate porta, libero ipsum convallis mi, sit +amet vehicula arcu elit sit amet odio. + +Fusce iaculis massa metus, id sagittis diam. Praesent molestie ante +vel odio tincidunt auctor. Cum sociis natoque penatibus et magnis dis +parturient montes, nascetur ridiculus mus. Duis rutrum vehicula nisl +eget condimentum. In in justo nisl. Nullam id arcu at nisl eleifend +pretium. Nulla interdum ligula id elit mollis dictum a sit amet +quam. Nullam iaculis laoreet ipsum at tempus. Vestibulum in cursus +dui. Curabitur porta lectus eget urna bibendum congue eget elementum +nisi. Proin sit amet lectus ut neque iaculis consectetur eu sit amet +nibh. Maecenas rhoncus dolor ac nunc gravida blandit. Fusce sem felis, +aliquam a porttitor a, porta quis odio. + +Nunc purus lorem, sollicitudin non ultricies id, porta vitae +enim. Nulla tristique gravida leo ut suscipit. Phasellus vitae turpis +libero. Proin ac purus dolor, in suscipit magna. Sed et enim +arcu. Morbi semper aliquet suscipit. Aenean laoreet condimentum massa, +eu pharetra magna fermentum ut. Morbi euismod convallis tortor, eget +fringilla lacus sagittis non. Nullam bibendum posuere feugiat. + +In at pulvinar massa. Mauris nunc lectus, mollis et malesuada +pharetra, cursus sed lacus. Integer dolor urna, interdum a mollis at, +vestibulum non nisl. Sed in urna tortor. Mauris arcu felis, volutpat +quis euismod vel, congue sit amet ipsum. Morbi in aliquet purus. Duis +cras amet. diff --git a/dtc/tests/mangle-layout.c b/dtc/tests/mangle-layout.c new file mode 100644 index 000000000..59b16049a --- /dev/null +++ b/dtc/tests/mangle-layout.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase/tool for rearranging blocks of a dtb + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <limits.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +struct bufstate { + char *buf; + int size; +}; + +static void expand_buf(struct bufstate *buf, int newsize) +{ + buf->buf = realloc(buf->buf, newsize); + if (!buf->buf) + CONFIG("Allocation failure"); + buf->size = newsize; +} + +static void new_header(struct bufstate *buf, int version, const void *fdt) +{ + int hdrsize = fdt_header_size_(version); + + if ((version != 16) && (version != 17)) + CONFIG("Bad version %d", version); + + expand_buf(buf, hdrsize); + memset(buf->buf, 0, hdrsize); + + fdt_set_magic(buf->buf, FDT_MAGIC); + fdt_set_version(buf->buf, version); + fdt_set_last_comp_version(buf->buf, 16); + fdt_set_boot_cpuid_phys(buf->buf, fdt_boot_cpuid_phys(fdt)); +} + +static void add_block(struct bufstate *buf, int version, char block, const void *fdt) +{ + int align, size, oldsize; + const void *src; + int offset; + + switch (block) { + case 'm': + /* Memory reserve map */ + align = 8; + src = (const char *)fdt + fdt_off_mem_rsvmap(fdt); + size = (fdt_num_mem_rsv(fdt) + 1) + * sizeof(struct fdt_reserve_entry); + break; + + case 't': + /* Structure block */ + align = 4; + src = (const char *)fdt + fdt_off_dt_struct(fdt); + size = fdt_size_dt_struct(fdt); + break; + + case 's': + /* Strings block */ + align = 1; + src = (const char *)fdt + fdt_off_dt_strings(fdt); + size = fdt_size_dt_strings(fdt); + break; + default: + CONFIG("Bad block '%c'", block); + } + + oldsize = buf->size; + offset = ALIGN(oldsize, align); + expand_buf(buf, offset+size); + memset(buf->buf + oldsize, 0, offset - oldsize); + + memcpy(buf->buf + offset, src, size); + + switch (block) { + case 'm': + fdt_set_off_mem_rsvmap(buf->buf, offset); + break; + + case 't': + fdt_set_off_dt_struct(buf->buf, offset); + if (version >= 17) + fdt_set_size_dt_struct(buf->buf, size); + break; + + case 's': + fdt_set_off_dt_strings(buf->buf, offset); + fdt_set_size_dt_strings(buf->buf, size); + break; + } +} + +int main(int argc, char *argv[]) +{ + void *fdt; + int version; + const char *blockorder; + struct bufstate buf = {NULL, 0}; + int err; + const char *inname; + char outname[PATH_MAX]; + + test_init(argc, argv); + if (argc != 4) + CONFIG("Usage: %s <dtb file> <version> <block order>", argv[0]); + + inname = argv[1]; + fdt = load_blob(argv[1]); + version = atoi(argv[2]); + blockorder = argv[3]; + sprintf(outname, "v%d.%s.%s", version, blockorder, inname); + + if ((version != 16) && (version != 17)) + CONFIG("Version must be 16 or 17"); + + if (fdt_version(fdt) < 17) + CONFIG("Input tree must be v17"); + + new_header(&buf, version, fdt); + + while (*blockorder) { + add_block(&buf, version, *blockorder, fdt); + blockorder++; + } + + fdt_set_totalsize(buf.buf, buf.size); + + err = fdt_check_header(buf.buf); + if (err) + FAIL("Output tree fails check: %s", fdt_strerror(err)); + + save_blob(outname, buf.buf); + + PASS(); +} diff --git a/dtc/tests/meson.build b/dtc/tests/meson.build new file mode 100644 index 000000000..fa068241b --- /dev/null +++ b/dtc/tests/meson.build @@ -0,0 +1,131 @@ +trees = static_library('trees', files('trees.S'), c_args: '-D__ASSEMBLY__', + include_directories: libfdt_inc) + +dumptrees = executable('dumptrees', files('dumptrees.c'), + link_with: trees, dependencies: libfdt_dep) + +dumptrees_dtb = custom_target( + 'dumptrees', + command: [dumptrees, meson.current_build_dir()], + output: [ + 'test_tree1.dtb', + 'bad_node_char.dtb', + 'bad_node_format.dtb', + 'bad_prop_char.dtb', + 'ovf_size_strings.dtb', + 'truncated_property.dtb', + 'truncated_string.dtb', + 'truncated_memrsv.dtb', + ] +) + +testutil_dep = declare_dependency(sources: ['testutils.c'], link_with: trees) + +tests = [ + 'add_subnode_with_nops', + 'addr_size_cells', + 'addr_size_cells2', + 'appendprop1', + 'appendprop2', + 'appendprop_addrrange', + 'boot-cpuid', + 'char_literal', + 'check_full', + 'check_header', + 'check_path', + 'del_node', + 'del_property', + 'dtb_reverse', + 'dtbs_equal_ordered', + 'dtbs_equal_unordered', + 'extra-terminating-null', + 'find_property', + 'fs_tree1', + 'get_alias', + 'get_mem_rsv', + 'get_name', + 'get_path', + 'get_phandle', + 'get_prop_offset', + 'getprop', + 'incbin', + 'integer-expressions', + 'mangle-layout', + 'move_and_save', + 'node_check_compatible', + 'node_offset_by_compatible', + 'node_offset_by_phandle', + 'node_offset_by_prop_value', + 'nop_node', + 'nop_property', + 'nopulate', + 'notfound', + 'open_pack', + 'overlay', + 'overlay_bad_fixup', + 'parent_offset', + 'path-references', + 'path_offset', + 'path_offset_aliases', + 'phandle_format', + 'property_iterate', + 'propname_escapes', + 'references', + 'root_node', + 'rw_oom', + 'rw_tree1', + 'set_name', + 'setprop', + 'setprop_inplace', + 'sized_cells', + 'string_escapes', + 'stringlist', + 'subnode_iterate', + 'subnode_offset', + 'supernode_atdepth_offset', + 'sw_states', + 'sw_tree1', + 'utilfdt_test', +] + +tests += [ + 'truncated_memrsv', + 'truncated_property', + 'truncated_string', +] + +dl = cc.find_library('dl', required: false) +if dl.found() + tests += [ + 'asm_tree_dump', + 'value-labels', + ] +endif + +foreach t: tests + executable(t, files(t + '.c'), dependencies: [testutil_dep, util_dep, libfdt_dep, dl]) +endforeach + +run_tests = find_program('run_tests.sh') + +env = [] +if not py.found() + env += 'NO_PYTHON=1' +else + env += [ + 'PYTHON=' + py.path(), + 'PYTHONPATH=' + meson.source_root() / 'pylibfdt', + ] +endif +if not yaml.found() + env += 'NO_YAML=1' +endif + +test( + 'run-test', + run_tests, + workdir: meson.current_build_dir(), + depends: dumptrees_dtb, + env: env, + timeout: 1800, # mostly for valgrind +) diff --git a/dtc/tests/minusone-phandle.dts b/dtc/tests/minusone-phandle.dts new file mode 100644 index 000000000..21d99867a --- /dev/null +++ b/dtc/tests/minusone-phandle.dts @@ -0,0 +1,7 @@ +/dts-v1/; + +/ { + node { + linux,phandle = <0xffffffff>; + }; +}; diff --git a/dtc/tests/move_and_save.c b/dtc/tests/move_and_save.c new file mode 100644 index 000000000..a89f8dedd --- /dev/null +++ b/dtc/tests/move_and_save.c @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Basic testcase for read-only access + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <limits.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +int main(int argc, char *argv[]) +{ + void *fdt, *fdt1, *fdt2, *fdt3; + char *buf; + int shuntsize; + int bufsize; + int err; + const char *inname; + char outname[PATH_MAX]; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + inname = argv[1]; + + shuntsize = ALIGN(fdt_totalsize(fdt) / 2, sizeof(uint64_t)); + bufsize = fdt_totalsize(fdt) + shuntsize; + buf = xmalloc(bufsize); + + fdt1 = buf; + err = fdt_move(fdt, fdt1, bufsize); + if (err) + FAIL("Failed to move tree into new buffer: %s", + fdt_strerror(err)); + sprintf(outname, "moved.%s", inname); + save_blob(outname, fdt1); + + fdt2 = buf + shuntsize; + err = fdt_move(fdt1, fdt2, bufsize-shuntsize); + if (err) + FAIL("Failed to shunt tree %d bytes: %s", + shuntsize, fdt_strerror(err)); + sprintf(outname, "shunted.%s", inname); + save_blob(outname, fdt2); + + fdt3 = buf; + err = fdt_move(fdt2, fdt3, bufsize); + if (err) + FAIL("Failed to deshunt tree %d bytes: %s", + shuntsize, fdt_strerror(err)); + sprintf(outname, "deshunted.%s", inname); + save_blob(outname, fdt3); + + PASS(); +} diff --git a/dtc/tests/multilabel.dts b/dtc/tests/multilabel.dts new file mode 100644 index 000000000..d80ebe1fb --- /dev/null +++ b/dtc/tests/multilabel.dts @@ -0,0 +1,49 @@ +/dts-v1/; + +m1: mq: /memreserve/ 0 0x1000; + +/ { + p0: pw: prop = "foo"; + + rref = <&{/}>; + + /* Explicit phandles */ + n1: nx: node1 { + linux,phandle = <0x2000>; + ref = <&{/node2}>; /* reference precedes target */ + p1: px: lref = <&ny>; + }; + ny: n2: node2 { + p2: py: phandle = <0x1>; + ref = <&{/node1}>; /* reference after target */ + lref = <&nx>; + }; + + /* Implicit phandles */ + n3: node3 { + p3: ref = <&{/node4}>; + lref = <&n4>; + }; + n4: node4 { + p4: prop; + }; + + /* Explicit phandle with implicit value */ + /* This self-reference is the standard way to tag a node as requiring + * a phandle (perhaps for reference by nodes that will be dynamically + * added) without explicitly allocating it a phandle. + * The self-reference requires some special internal handling, though + * so check it actually works */ + n5: nz: node5 { + linux,phandle = <&n5>; + phandle = <&nz>; + n1 = &n1; + n2 = &n2; + n3 = &n3; + }; + + node6 { + linux,phandle = <0xfffffffe>; + phandle = <0xfffffffe>; + }; +}; diff --git a/dtc/tests/multilabel_merge.dts b/dtc/tests/multilabel_merge.dts new file mode 100644 index 000000000..a27d856f8 --- /dev/null +++ b/dtc/tests/multilabel_merge.dts @@ -0,0 +1,75 @@ +/dts-v1/; + +m1: mq: /memreserve/ 0 0x1000; + +/ { + p0: pw: prop = "foo"; + + /* Explicit phandles */ + n1: node1 { + linux,phandle = <0x2000>; + ref = <&{/node2}>; /* reference precedes target */ + p1: lref; + }; + node2 { + phandle = <0x1>; + ref = <&{/node1}>; /* reference after target */ + lref = <&nx>; + }; + + /* Implicit phandles */ + n3: node3 { + p3: ref = <&{/node4}>; + lref = <&n4>; + }; + n4: node4 { + p4: prop = "foo"; + }; + + /* Explicit phandle with implicit value */ + /* This self-reference is the standard way to tag a node as requiring + * a phandle (perhaps for reference by nodes that will be dynamically + * added) without explicitly allocating it a phandle. + * The self-reference requires some special internal handling, though + * so check it actually works */ + n5: nz: node5 { + linux,phandle = <&n5>; + phandle = <&nz>; + n1 = &n1; + n2 = &n2; + n3 = &n3; + }; + + node6 { + linux,phandle = <0xfffffffe>; + phandle = <0xfffffffe>; + }; +}; + +/ { + /* Append labels (also changes property content) */ + nx: node1 { + px: lref = <&ny>; + }; + + /* Add multiple labels */ + ny: n2: node2 { + /* Add a label to a property */ + p2: py: phandle = <0x1>; + }; + + /* Reassigning the same label should be a no-op */ + n3: node3 { + p3: ref = <&{/node4}>; + }; + + /* Redefining a node/property should not remove labels */ + node4 { + prop; + }; + +}; + +/ { + rref = <&{/}>; +}; diff --git a/dtc/tests/node_check_compatible.c b/dtc/tests/node_check_compatible.c new file mode 100644 index 000000000..81efe6211 --- /dev/null +++ b/dtc/tests/node_check_compatible.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_node_check_compatible() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static void check_compatible(const void *fdt, const char *path, + const char *compat) +{ + int offset, err; + + offset = fdt_path_offset(fdt, path); + if (offset < 0) + FAIL("fdt_path_offset(%s): %s", path, fdt_strerror(offset)); + + err = fdt_node_check_compatible(fdt, offset, compat); + if (err < 0) + FAIL("fdt_node_check_compatible(%s): %s", path, + fdt_strerror(err)); + if (err != 0) + FAIL("%s is not compatible with \"%s\"", path, compat); +} + +static void check_not_compatible(const void *fdt, const char *path, + const char *compat) +{ + int offset, err; + + offset = fdt_path_offset(fdt, path); + if (offset < 0) + FAIL("fdt_path_offset(%s): %s", path, fdt_strerror(offset)); + + err = fdt_node_check_compatible(fdt, offset, compat); + if (err < 0) + FAIL("fdt_node_check_compatible(%s): %s", path, + fdt_strerror(err)); + if (err == 0) + FAIL("%s is incorrectly compatible with \"%s\"", path, compat); +} + +int main(int argc, char *argv[]) +{ + void *fdt; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + check_compatible(fdt, "/", "test_tree1"); + check_compatible(fdt, "/subnode@1/subsubnode", "subsubnode1"); + check_compatible(fdt, "/subnode@1/subsubnode", "subsubnode"); + check_not_compatible(fdt, "/subnode@1/subsubnode", "subsubnode2"); + check_compatible(fdt, "/subnode@2/subsubnode", "subsubnode2"); + check_compatible(fdt, "/subnode@2/subsubnode", "subsubnode"); + check_not_compatible(fdt, "/subnode@2/subsubnode", "subsubnode1"); + + PASS(); +} diff --git a/dtc/tests/node_offset_by_compatible.c b/dtc/tests/node_offset_by_compatible.c new file mode 100644 index 000000000..a9e678357 --- /dev/null +++ b/dtc/tests/node_offset_by_compatible.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_node_offset_by_compatible() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <stdarg.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static void check_search(void *fdt, const char *compat, ...) +{ + va_list ap; + int offset = -1, target; + + va_start(ap, compat); + do { + target = va_arg(ap, int); + verbose_printf("Searching (target = %d): %d ->", + target, offset); + offset = fdt_node_offset_by_compatible(fdt, offset, compat); + verbose_printf("%d\n", offset); + + if (offset != target) + FAIL("fdt_node_offset_by_compatible(%s) returns %d " + "instead of %d", compat, offset, target); + } while (target >= 0); + + va_end(ap); +} + +int main(int argc, char *argv[]) +{ + void *fdt; + int subnode1_offset, subnode2_offset; + int subsubnode1_offset, subsubnode2_offset; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + subnode1_offset = fdt_path_offset(fdt, "/subnode@1"); + subnode2_offset = fdt_path_offset(fdt, "/subnode@2"); + subsubnode1_offset = fdt_path_offset(fdt, "/subnode@1/subsubnode"); + subsubnode2_offset = fdt_path_offset(fdt, "/subnode@2/subsubnode@0"); + + if ((subnode1_offset < 0) || (subnode2_offset < 0) + || (subsubnode1_offset < 0) || (subsubnode2_offset < 0)) + FAIL("Can't find required nodes"); + + check_search(fdt, "test_tree1", 0, -FDT_ERR_NOTFOUND); + check_search(fdt, "subnode1", subnode1_offset, -FDT_ERR_NOTFOUND); + check_search(fdt, "subsubnode1", subsubnode1_offset, -FDT_ERR_NOTFOUND); + check_search(fdt, "subsubnode2", subsubnode2_offset, -FDT_ERR_NOTFOUND); + /* Eek.. HACK to make this work whatever the order in the + * example tree */ + if (subsubnode1_offset < subsubnode2_offset) + check_search(fdt, "subsubnode", subsubnode1_offset, + subsubnode2_offset, -FDT_ERR_NOTFOUND); + else + check_search(fdt, "subsubnode", subsubnode2_offset, + subsubnode1_offset, -FDT_ERR_NOTFOUND); + check_search(fdt, "nothing-like-this", -FDT_ERR_NOTFOUND); + + PASS(); +} diff --git a/dtc/tests/node_offset_by_phandle.c b/dtc/tests/node_offset_by_phandle.c new file mode 100644 index 000000000..60af78a79 --- /dev/null +++ b/dtc/tests/node_offset_by_phandle.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_node_offset_by_phandle() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <stdarg.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static void check_search(void *fdt, uint32_t phandle, int target) +{ + int offset; + + offset = fdt_node_offset_by_phandle(fdt, phandle); + + if (offset != target) + FAIL("fdt_node_offset_by_phandle(0x%x) returns %d " + "instead of %d", phandle, offset, target); +} + +int main(int argc, char *argv[]) +{ + void *fdt; + int subnode2_offset, subsubnode2_offset; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + subnode2_offset = fdt_path_offset(fdt, "/subnode@2"); + subsubnode2_offset = fdt_path_offset(fdt, "/subnode@2/subsubnode@0"); + + if ((subnode2_offset < 0) || (subsubnode2_offset < 0)) + FAIL("Can't find required nodes"); + + check_search(fdt, PHANDLE_1, subnode2_offset); + check_search(fdt, PHANDLE_2, subsubnode2_offset); + check_search(fdt, ~PHANDLE_1, -FDT_ERR_NOTFOUND); + check_search(fdt, 0, -FDT_ERR_BADPHANDLE); + check_search(fdt, -1, -FDT_ERR_BADPHANDLE); + + PASS(); +} diff --git a/dtc/tests/node_offset_by_prop_value.c b/dtc/tests/node_offset_by_prop_value.c new file mode 100644 index 000000000..48ab1d93a --- /dev/null +++ b/dtc/tests/node_offset_by_prop_value.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_path_offset() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <stdarg.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static void vcheck_search(void *fdt, const char *propname, const void *propval, + int proplen, va_list ap) +{ + int offset = -1, target; + + do { + target = va_arg(ap, int); + verbose_printf("Searching (target = %d): %d ->", + target, offset); + offset = fdt_node_offset_by_prop_value(fdt, offset, propname, + propval, proplen); + verbose_printf("%d\n", offset); + + if (offset != target) + FAIL("fdt_node_offset_by_prop_value() returns %d " + "instead of %d", offset, target); + } while (target >= 0); +} + +static void check_search(void *fdt, const char *propname, const void *propval, + int proplen, ...) +{ + va_list ap; + + va_start(ap, proplen); + vcheck_search(fdt, propname, propval, proplen, ap); + va_end(ap); +} + +static void check_search_str(void *fdt, const char *propname, + const char *propval, ...) +{ + va_list ap; + + va_start(ap, propval); + vcheck_search(fdt, propname, propval, strlen(propval)+1, ap); + va_end(ap); +} + +#define check_search_cell(fdt, propname, propval, ...) \ + { \ + fdt32_t val = cpu_to_fdt32(propval); \ + check_search((fdt), (propname), &val, sizeof(val), \ + ##__VA_ARGS__); \ + } + +int main(int argc, char *argv[]) +{ + void *fdt; + int subnode1_offset, subnode2_offset; + int subsubnode1_offset, subsubnode2_offset; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + subnode1_offset = fdt_path_offset(fdt, "/subnode@1"); + subnode2_offset = fdt_path_offset(fdt, "/subnode@2"); + subsubnode1_offset = fdt_path_offset(fdt, "/subnode@1/subsubnode"); + subsubnode2_offset = fdt_path_offset(fdt, "/subnode@2/subsubnode@0"); + + if ((subnode1_offset < 0) || (subnode2_offset < 0) + || (subsubnode1_offset < 0) || (subsubnode2_offset < 0)) + FAIL("Can't find required nodes"); + + check_search_cell(fdt, "prop-int", TEST_VALUE_1, 0, subnode1_offset, + subsubnode1_offset, -FDT_ERR_NOTFOUND); + + check_search_cell(fdt, "prop-int", TEST_VALUE_2, subnode2_offset, + subsubnode2_offset, -FDT_ERR_NOTFOUND); + + check_search_str(fdt, "prop-str", TEST_STRING_1, 0, -FDT_ERR_NOTFOUND); + + check_search_str(fdt, "prop-str", "no such string", -FDT_ERR_NOTFOUND); + + check_search_cell(fdt, "prop-int", TEST_VALUE_1+1, -FDT_ERR_NOTFOUND); + + check_search(fdt, "no-such-prop", NULL, 0, -FDT_ERR_NOTFOUND); + + PASS(); +} diff --git a/dtc/tests/nonexist-label-ref.dts b/dtc/tests/nonexist-label-ref.dts new file mode 100644 index 000000000..25927a109 --- /dev/null +++ b/dtc/tests/nonexist-label-ref.dts @@ -0,0 +1,8 @@ +/dts-v1/; + +/ { + ref = <&label>; + badref = <&nosuchlabel>; + label: node { + }; +}; diff --git a/dtc/tests/nonexist-node-ref.dts b/dtc/tests/nonexist-node-ref.dts new file mode 100644 index 000000000..efd41404b --- /dev/null +++ b/dtc/tests/nonexist-node-ref.dts @@ -0,0 +1,8 @@ +/dts-v1/; + +/ { + ref = < &{/node} >; + badref = < &{/nosuchnode} >; + label: node { + }; +}; diff --git a/dtc/tests/nonexist-node-ref2.dts b/dtc/tests/nonexist-node-ref2.dts new file mode 100644 index 000000000..44b4ebeba --- /dev/null +++ b/dtc/tests/nonexist-node-ref2.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +/ { + label: node { + }; +}; + +/* Try to redefine a node using a non-existent label */ +&nosuchnode { +}; diff --git a/dtc/tests/nop_node.c b/dtc/tests/nop_node.c new file mode 100644 index 000000000..ee972d2a3 --- /dev/null +++ b/dtc/tests/nop_node.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_nop_node() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +int main(int argc, char *argv[]) +{ + void *fdt; + int subnode1_offset, subnode2_offset, subsubnode2_offset; + int err; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + subnode1_offset = fdt_path_offset(fdt, "/subnode@1"); + if (subnode1_offset < 0) + FAIL("Couldn't find \"/subnode1\": %s", + fdt_strerror(subnode1_offset)); + check_getprop_cell(fdt, subnode1_offset, "prop-int", TEST_VALUE_1); + + subnode2_offset = fdt_path_offset(fdt, "/subnode@2"); + if (subnode2_offset < 0) + FAIL("Couldn't find \"/subnode2\": %s", + fdt_strerror(subnode2_offset)); + check_getprop_cell(fdt, subnode2_offset, "prop-int", TEST_VALUE_2); + + subsubnode2_offset = fdt_path_offset(fdt, "/subnode@2/subsubnode"); + if (subsubnode2_offset < 0) + FAIL("Couldn't find \"/subnode@2/subsubnode\": %s", + fdt_strerror(subsubnode2_offset)); + check_getprop_cell(fdt, subsubnode2_offset, "prop-int", TEST_VALUE_2); + + err = fdt_nop_node(fdt, subnode1_offset); + if (err) + FAIL("fdt_nop_node(subnode1): %s", fdt_strerror(err)); + + subnode1_offset = fdt_path_offset(fdt, "/subnode@1"); + if (subnode1_offset != -FDT_ERR_NOTFOUND) + FAIL("fdt_path_offset(subnode1) returned \"%s\" instead of \"%s\"", + fdt_strerror(subnode1_offset), + fdt_strerror(-FDT_ERR_NOTFOUND)); + + subnode2_offset = fdt_path_offset(fdt, "/subnode@2"); + if (subnode2_offset < 0) + FAIL("Couldn't find \"/subnode2\": %s", + fdt_strerror(subnode2_offset)); + check_getprop_cell(fdt, subnode2_offset, "prop-int", TEST_VALUE_2); + + subsubnode2_offset = fdt_path_offset(fdt, "/subnode@2/subsubnode"); + if (subsubnode2_offset < 0) + FAIL("Couldn't find \"/subnode@2/subsubnode\": %s", + fdt_strerror(subsubnode2_offset)); + check_getprop_cell(fdt, subsubnode2_offset, "prop-int", TEST_VALUE_2); + + err = fdt_nop_node(fdt, subnode2_offset); + if (err) + FAIL("fdt_nop_node(subnode2): %s", fdt_strerror(err)); + + subnode1_offset = fdt_path_offset(fdt, "/subnode@1"); + if (subnode1_offset != -FDT_ERR_NOTFOUND) + FAIL("fdt_path_offset(subnode1) returned \"%s\" instead of \"%s\"", + fdt_strerror(subnode1_offset), + fdt_strerror(-FDT_ERR_NOTFOUND)); + + subnode2_offset = fdt_path_offset(fdt, "/subnode@2"); + if (subnode2_offset != -FDT_ERR_NOTFOUND) + FAIL("fdt_path_offset(subnode2) returned \"%s\" instead of \"%s\"", + fdt_strerror(subnode2_offset), + fdt_strerror(-FDT_ERR_NOTFOUND)); + + subsubnode2_offset = fdt_path_offset(fdt, "/subnode@2/subsubnode"); + if (subsubnode2_offset != -FDT_ERR_NOTFOUND) + FAIL("fdt_path_offset(subsubnode2) returned \"%s\" instead of \"%s\"", + fdt_strerror(subsubnode2_offset), + fdt_strerror(-FDT_ERR_NOTFOUND)); + + PASS(); +} diff --git a/dtc/tests/nop_property.c b/dtc/tests/nop_property.c new file mode 100644 index 000000000..65938289e --- /dev/null +++ b/dtc/tests/nop_property.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_nop_property() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +int main(int argc, char *argv[]) +{ + void *fdt; + const uint32_t *intp; + const char *strp; + int err; + int lenerr; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + intp = check_getprop_cell(fdt, 0, "prop-int", TEST_VALUE_1); + verbose_printf("int value was 0x%08x\n", *intp); + + err = fdt_nop_property(fdt, 0, "prop-int"); + if (err) + FAIL("Failed to nop \"prop-int\": %s", fdt_strerror(err)); + + intp = fdt_getprop(fdt, 0, "prop-int", &lenerr); + if (intp) + FAIL("prop-int still present after nopping"); + if (lenerr != -FDT_ERR_NOTFOUND) + FAIL("Unexpected error on second getprop: %s", fdt_strerror(err)); + + strp = check_getprop(fdt, 0, "prop-str", strlen(TEST_STRING_1)+1, + TEST_STRING_1); + verbose_printf("string value was \"%s\"\n", strp); + err = fdt_nop_property(fdt, 0, "prop-str"); + if (err) + FAIL("Failed to nop \"prop-str\": %s", fdt_strerror(err)); + + strp = fdt_getprop(fdt, 0, "prop-str", &lenerr); + if (strp) + FAIL("prop-str still present after nopping"); + if (lenerr != -FDT_ERR_NOTFOUND) + FAIL("Unexpected error on second getprop: %s", fdt_strerror(err)); + + PASS(); +} diff --git a/dtc/tests/nopulate.c b/dtc/tests/nopulate.c new file mode 100644 index 000000000..2ae175355 --- /dev/null +++ b/dtc/tests/nopulate.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase/tool for rearranging blocks of a dtb + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <limits.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static int nopulate_struct(char *buf, const char *fdt) +{ + int offset, nextoffset = 0; + uint32_t tag; + char *p; + + p = buf; + + do { + offset = nextoffset; + tag = fdt_next_tag(fdt, offset, &nextoffset); + + memcpy(p, (const char *)fdt + fdt_off_dt_struct(fdt) + offset, + nextoffset - offset); + p += nextoffset - offset; + + *((fdt32_t *)p) = cpu_to_fdt32(FDT_NOP); + p += FDT_TAGSIZE; + + } while (tag != FDT_END); + + return p - buf; +} + +int main(int argc, char *argv[]) +{ + char *fdt, *fdt2, *buf; + int newsize, struct_start, struct_end_old, struct_end_new, delta; + const char *inname; + char outname[PATH_MAX]; + + test_init(argc, argv); + if (argc != 2) + CONFIG("Usage: %s <dtb file>", argv[0]); + + inname = argv[1]; + fdt = load_blob(argv[1]); + sprintf(outname, "noppy.%s", inname); + + if (fdt_version(fdt) < 17) + FAIL("Can't deal with version <17"); + + buf = xmalloc(2 * fdt_size_dt_struct(fdt)); + + newsize = nopulate_struct(buf, fdt); + + verbose_printf("Nopulated structure block has new size %d\n", newsize); + + /* Replace old strcutre block with the new */ + + fdt2 = xmalloc(fdt_totalsize(fdt) + newsize); + + struct_start = fdt_off_dt_struct(fdt); + delta = newsize - fdt_size_dt_struct(fdt); + struct_end_old = struct_start + fdt_size_dt_struct(fdt); + struct_end_new = struct_start + newsize; + + memcpy(fdt2, fdt, struct_start); + memcpy(fdt2 + struct_start, buf, newsize); + memcpy(fdt2 + struct_end_new, fdt + struct_end_old, + fdt_totalsize(fdt) - struct_end_old); + + fdt_set_totalsize(fdt2, fdt_totalsize(fdt) + delta); + fdt_set_size_dt_struct(fdt2, newsize); + + if (fdt_off_mem_rsvmap(fdt) > struct_start) + fdt_set_off_mem_rsvmap(fdt2, fdt_off_mem_rsvmap(fdt) + delta); + if (fdt_off_dt_strings(fdt) > struct_start) + fdt_set_off_dt_strings(fdt2, fdt_off_dt_strings(fdt) + delta); + + save_blob(outname, fdt2); + + PASS(); +} diff --git a/dtc/tests/notfound.c b/dtc/tests/notfound.c new file mode 100644 index 000000000..70acbcda3 --- /dev/null +++ b/dtc/tests/notfound.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for behaviour on searching for a non-existent node + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static void check_error(const char *s, int err) +{ + if (err != -FDT_ERR_NOTFOUND) + FAIL("%s return error %s instead of -FDT_ERR_NOTFOUND", s, + fdt_strerror(err)); +} + +int main(int argc, char *argv[]) +{ + void *fdt; + int offset; + int subnode1_offset; + int lenerr; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + fdt_get_property(fdt, 0, "nonexistant-property", &lenerr); + check_error("fdt_get_property(\"nonexistant-property\")", lenerr); + + fdt_getprop(fdt, 0, "nonexistant-property", &lenerr); + check_error("fdt_getprop(\"nonexistant-property\"", lenerr); + + subnode1_offset = fdt_subnode_offset(fdt, 0, "subnode@1"); + if (subnode1_offset < 0) + FAIL("Couldn't find subnode1: %s", fdt_strerror(subnode1_offset)); + + fdt_getprop(fdt, subnode1_offset, "prop-str", &lenerr); + check_error("fdt_getprop(\"prop-str\")", lenerr); + + offset = fdt_subnode_offset(fdt, 0, "nonexistant-subnode"); + check_error("fdt_subnode_offset(\"nonexistant-subnode\")", offset); + + offset = fdt_subnode_offset(fdt, 0, "subsubnode"); + check_error("fdt_subnode_offset(\"subsubnode\")", offset); + + offset = fdt_path_offset(fdt, "/nonexistant-subnode"); + check_error("fdt_path_offset(\"/nonexistant-subnode\")", offset); + + PASS(); +} diff --git a/dtc/tests/nul-in-escape.dts b/dtc/tests/nul-in-escape.dts Binary files differnew file mode 100644 index 000000000..9bed351cf --- /dev/null +++ b/dtc/tests/nul-in-escape.dts diff --git a/dtc/tests/nul-in-line-info1.dts b/dtc/tests/nul-in-line-info1.dts Binary files differnew file mode 100644 index 000000000..ceb7261b7 --- /dev/null +++ b/dtc/tests/nul-in-line-info1.dts diff --git a/dtc/tests/nul-in-line-info2.dts b/dtc/tests/nul-in-line-info2.dts new file mode 100644 index 000000000..1157d2324 --- /dev/null +++ b/dtc/tests/nul-in-line-info2.dts @@ -0,0 +1 @@ +# 0 "\0" diff --git a/dtc/tests/obsolete-chosen-interrupt-controller.dts b/dtc/tests/obsolete-chosen-interrupt-controller.dts new file mode 100644 index 000000000..36dd6e81d --- /dev/null +++ b/dtc/tests/obsolete-chosen-interrupt-controller.dts @@ -0,0 +1,13 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + PIC: pic@0 { + reg = <0x0 0x10>; + interrupt-controller; + }; + chosen { + interrupt-controller = <&PIC>; + }; +}; diff --git a/dtc/tests/omit-no-ref.dts b/dtc/tests/omit-no-ref.dts new file mode 100644 index 000000000..8ace232ec --- /dev/null +++ b/dtc/tests/omit-no-ref.dts @@ -0,0 +1,26 @@ +/dts-v1/; + +/ { + test-phandle = <&node3>; + test-path = &node4; + + /omit-if-no-ref/ node1: node1 { + bar = <0xdeadbeef>; + }; + + node2: node2 { + foo = <0x42>; + }; + + node3: node3 { + test = "test"; + }; + + node4: node4 { + test; + }; +}; + +/omit-if-no-ref/ &node2; +/omit-if-no-ref/ &node3; +/omit-if-no-ref/ &node4; diff --git a/dtc/tests/open_pack.c b/dtc/tests/open_pack.c new file mode 100644 index 000000000..6ed4df7f6 --- /dev/null +++ b/dtc/tests/open_pack.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Basic testcase for read-only access + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <limits.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +int main(int argc, char *argv[]) +{ + void *fdt, *fdt1; + void *buf; + int oldsize, bufsize, packsize; + int err; + const char *inname; + char outname[PATH_MAX]; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + inname = argv[1]; + + oldsize = fdt_totalsize(fdt); + + bufsize = oldsize * 2; + + buf = xmalloc(bufsize); + /* don't leak uninitialized memory into our output */ + memset(buf, 0, bufsize); + + fdt1 = buf; + err = fdt_open_into(fdt, fdt1, bufsize); + if (err) + FAIL("fdt_open_into(): %s", fdt_strerror(err)); + sprintf(outname, "opened.%s", inname); + save_blob(outname, fdt1); + + err = fdt_pack(fdt1); + if (err) + FAIL("fdt_pack(): %s", fdt_strerror(err)); + sprintf(outname, "repacked.%s", inname); + save_blob(outname, fdt1); + + packsize = fdt_totalsize(fdt1); + + verbose_printf("oldsize = %d, bufsize = %d, packsize = %d\n", + oldsize, bufsize, packsize); + PASS(); +} diff --git a/dtc/tests/overlay.c b/dtc/tests/overlay.c new file mode 100644 index 000000000..91afa72a6 --- /dev/null +++ b/dtc/tests/overlay.c @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for DT overlays() + * Copyright (C) 2016 Free Electrons + * Copyright (C) 2016 NextThing Co. + */ + +#include <stdio.h> + +#include <libfdt.h> + +#include "tests.h" + +#define CHECK(code) \ + { \ + int err = (code); \ + if (err) \ + FAIL(#code ": %s", fdt_strerror(err)); \ + } + +/* 4k ought to be enough for anybody */ +#define FDT_COPY_SIZE (4 * 1024) + +static int fdt_getprop_u32_by_poffset(void *fdt, const char *path, + const char *name, int poffset, + unsigned long *out) +{ + const fdt32_t *val; + int node_off; + int len; + + node_off = fdt_path_offset(fdt, path); + if (node_off < 0) + return node_off; + + val = fdt_getprop(fdt, node_off, name, &len); + if (!val || (len < (sizeof(uint32_t) * (poffset + 1)))) + return -FDT_ERR_NOTFOUND; + + *out = fdt32_to_cpu(*(val + poffset)); + + return 0; +} + +static int check_getprop_string_by_name(void *fdt, const char *path, + const char *name, const char *val) +{ + int node_off; + + node_off = fdt_path_offset(fdt, path); + if (node_off < 0) + return node_off; + + check_getprop_string(fdt, node_off, name, val); + + return 0; +} + +static int check_getprop_u32_by_name(void *fdt, const char *path, + const char *name, uint32_t val) +{ + int node_off; + + node_off = fdt_path_offset(fdt, path); + CHECK(node_off < 0); + + check_getprop_cell(fdt, node_off, name, val); + + return 0; +} + +static int check_getprop_null_by_name(void *fdt, const char *path, + const char *name) +{ + int node_off; + + node_off = fdt_path_offset(fdt, path); + CHECK(node_off < 0); + + check_property(fdt, node_off, name, 0, NULL); + + return 0; +} + +static int fdt_overlay_change_int_property(void *fdt) +{ + return check_getprop_u32_by_name(fdt, "/test-node", "test-int-property", + 43); +} + +static int fdt_overlay_change_str_property(void *fdt) +{ + return check_getprop_string_by_name(fdt, "/test-node", + "test-str-property", "foobar"); +} + +static int fdt_overlay_add_str_property(void *fdt) +{ + return check_getprop_string_by_name(fdt, "/test-node", + "test-str-property-2", "foobar2"); +} + +static int fdt_overlay_add_node(void *fdt) +{ + return check_getprop_null_by_name(fdt, "/test-node/new-node", + "new-property"); +} + +static int fdt_overlay_add_subnode_property(void *fdt) +{ + check_getprop_null_by_name(fdt, "/test-node/sub-test-node", + "sub-test-property"); + check_getprop_null_by_name(fdt, "/test-node/sub-test-node", + "new-sub-test-property"); + + return 0; +} + +static int fdt_overlay_local_phandle(void *fdt) +{ + uint32_t local_phandle; + unsigned long val = 0; + int off; + + off = fdt_path_offset(fdt, "/test-node/new-local-node"); + CHECK(off < 0); + + local_phandle = fdt_get_phandle(fdt, off); + CHECK(!local_phandle); + + CHECK(fdt_getprop_u32_by_poffset(fdt, "/test-node", + "test-several-phandle", + 0, &val)); + CHECK(val != local_phandle); + + CHECK(fdt_getprop_u32_by_poffset(fdt, "/test-node", + "test-several-phandle", + 1, &val)); + CHECK(val != local_phandle); + + return 0; +} + +static int fdt_overlay_local_phandles(void *fdt) +{ + uint32_t local_phandle, test_phandle; + unsigned long val = 0; + int off; + + off = fdt_path_offset(fdt, "/test-node/new-local-node"); + CHECK(off < 0); + + local_phandle = fdt_get_phandle(fdt, off); + CHECK(!local_phandle); + + off = fdt_path_offset(fdt, "/test-node"); + CHECK(off < 0); + + test_phandle = fdt_get_phandle(fdt, off); + CHECK(!test_phandle); + + CHECK(fdt_getprop_u32_by_poffset(fdt, "/test-node", + "test-phandle", 0, &val)); + CHECK(test_phandle != val); + + CHECK(fdt_getprop_u32_by_poffset(fdt, "/test-node", + "test-phandle", 1, &val)); + CHECK(local_phandle != val); + + return 0; +} + +static void *open_dt(char *path) +{ + void *dt, *copy; + + dt = load_blob(path); + copy = xmalloc(FDT_COPY_SIZE); + + /* + * Resize our DTs to 4k so that we have room to operate on + */ + CHECK(fdt_open_into(dt, copy, FDT_COPY_SIZE)); + + return copy; +} + +int main(int argc, char *argv[]) +{ + void *fdt_base, *fdt_overlay; + + test_init(argc, argv); + if (argc != 3) + CONFIG("Usage: %s <base dtb> <overlay dtb>", argv[0]); + + fdt_base = open_dt(argv[1]); + fdt_overlay = open_dt(argv[2]); + + /* Apply the overlay */ + CHECK(fdt_overlay_apply(fdt_base, fdt_overlay)); + + fdt_overlay_change_int_property(fdt_base); + fdt_overlay_change_str_property(fdt_base); + fdt_overlay_add_str_property(fdt_base); + fdt_overlay_add_node(fdt_base); + fdt_overlay_add_subnode_property(fdt_base); + + /* + * If the base tree has a __symbols__ node, do the tests that + * are only successful with a proper phandle support, and thus + * dtc -@ + */ + if (fdt_path_offset(fdt_base, "/__symbols__") >= 0) { + fdt_overlay_local_phandle(fdt_base); + fdt_overlay_local_phandles(fdt_base); + } + + PASS(); +} diff --git a/dtc/tests/overlay_bad_fixup.c b/dtc/tests/overlay_bad_fixup.c new file mode 100644 index 000000000..029bc7982 --- /dev/null +++ b/dtc/tests/overlay_bad_fixup.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for DT overlays() + * Copyright (C) 2016 Free Electrons + * Copyright (C) 2016 NextThing Co. + */ + +#include <stdio.h> + +#include <libfdt.h> + +#include "tests.h" + +#define CHECK(code, expected) \ + { \ + err = (code); \ + if (err != expected) \ + FAIL(#code ": %s", fdt_strerror(err)); \ + } + +/* 4k ought to be enough for anybody */ +#define FDT_COPY_SIZE (4 * 1024) + +static void *open_dt(char *path) +{ + void *dt, *copy; + int err; + + dt = load_blob(path); + copy = xmalloc(FDT_COPY_SIZE); + + /* + * Resize our DTs to 4k so that we have room to operate on + */ + CHECK(fdt_open_into(dt, copy, FDT_COPY_SIZE), 0); + + return copy; +} + +int main(int argc, char *argv[]) +{ + void *fdt_base, *fdt_overlay; + int err; + + test_init(argc, argv); + if (argc != 3) + CONFIG("Usage: %s <base dtb> <overlay dtb>", argv[0]); + + fdt_base = open_dt(argv[1]); + fdt_overlay = open_dt(argv[2]); + + /* Apply the overlay */ + CHECK(fdt_overlay_apply(fdt_base, fdt_overlay), -FDT_ERR_BADOVERLAY); + + PASS(); +} diff --git a/dtc/tests/overlay_bad_fixup_bad_index.dts b/dtc/tests/overlay_bad_fixup_bad_index.dts new file mode 100644 index 000000000..b5cf13137 --- /dev/null +++ b/dtc/tests/overlay_bad_fixup_bad_index.dts @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/include/ "overlay_bad_fixup_base.dtsi" + +/ { + __fixups__ { + test = "/fragment@0:target:ab"; + }; +}; diff --git a/dtc/tests/overlay_bad_fixup_base.dtsi b/dtc/tests/overlay_bad_fixup_base.dtsi new file mode 100644 index 000000000..216bcab52 --- /dev/null +++ b/dtc/tests/overlay_bad_fixup_base.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/dts-v1/; + +/ { + fragment@0 { + target = <0xffffffff>; + + __overlay__ { + test-property; + }; + }; +}; diff --git a/dtc/tests/overlay_bad_fixup_empty.dts b/dtc/tests/overlay_bad_fixup_empty.dts new file mode 100644 index 000000000..e111db4c8 --- /dev/null +++ b/dtc/tests/overlay_bad_fixup_empty.dts @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/include/ "overlay_bad_fixup_base.dtsi" + +/ { + __fixups__ { + test = ""; + }; +}; diff --git a/dtc/tests/overlay_bad_fixup_empty_index.dts b/dtc/tests/overlay_bad_fixup_empty_index.dts new file mode 100644 index 000000000..9e12e2177 --- /dev/null +++ b/dtc/tests/overlay_bad_fixup_empty_index.dts @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/include/ "overlay_bad_fixup_base.dtsi" + +/ { + __fixups__ { + test = "/fragment@0:target:"; + }; +}; diff --git a/dtc/tests/overlay_bad_fixup_index_trailing.dts b/dtc/tests/overlay_bad_fixup_index_trailing.dts new file mode 100644 index 000000000..f586bef4d --- /dev/null +++ b/dtc/tests/overlay_bad_fixup_index_trailing.dts @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/include/ "overlay_bad_fixup_base.dtsi" + +/ { + __fixups__ { + test = "/fragment@0:target:0a"; + }; +}; diff --git a/dtc/tests/overlay_bad_fixup_path_empty_prop.dts b/dtc/tests/overlay_bad_fixup_path_empty_prop.dts new file mode 100644 index 000000000..608b5f924 --- /dev/null +++ b/dtc/tests/overlay_bad_fixup_path_empty_prop.dts @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/include/ "overlay_bad_fixup_base.dtsi" + +/ { + __fixups__ { + test = "/fragment@0::"; + }; +}; diff --git a/dtc/tests/overlay_bad_fixup_path_only.dts b/dtc/tests/overlay_bad_fixup_path_only.dts new file mode 100644 index 000000000..2485dd965 --- /dev/null +++ b/dtc/tests/overlay_bad_fixup_path_only.dts @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/include/ "overlay_bad_fixup_base.dtsi" + +/ { + __fixups__ { + test = "/fragment@0"; + }; +}; diff --git a/dtc/tests/overlay_bad_fixup_path_only_sep.dts b/dtc/tests/overlay_bad_fixup_path_only_sep.dts new file mode 100644 index 000000000..3cbf6c40f --- /dev/null +++ b/dtc/tests/overlay_bad_fixup_path_only_sep.dts @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/include/ "overlay_bad_fixup_base.dtsi" + +/ { + __fixups__ { + test = "/fragment@0:"; + }; +}; diff --git a/dtc/tests/overlay_bad_fixup_path_prop.dts b/dtc/tests/overlay_bad_fixup_path_prop.dts new file mode 100644 index 000000000..ca79b52bc --- /dev/null +++ b/dtc/tests/overlay_bad_fixup_path_prop.dts @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/include/ "overlay_bad_fixup_base.dtsi" + +/ { + __fixups__ { + test = "/fragment@0:target"; + }; +}; diff --git a/dtc/tests/overlay_base.dts b/dtc/tests/overlay_base.dts new file mode 100644 index 000000000..a5e55b2b2 --- /dev/null +++ b/dtc/tests/overlay_base.dts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/dts-v1/; + +/ { + test: test-node { + test-int-property = <42>; + test-str-property = "foo"; + + subtest: sub-test-node { + sub-test-property; + + subtest_with_long_path: sub-test-node-with-very-long-target-path { + long-test-path-property; + }; + }; + }; +}; + + diff --git a/dtc/tests/overlay_base_manual_symbols.dts b/dtc/tests/overlay_base_manual_symbols.dts new file mode 100644 index 000000000..7e4d17dcb --- /dev/null +++ b/dtc/tests/overlay_base_manual_symbols.dts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/dts-v1/; + +/ { + test: test-node { + phandle = <&test>; /* Force phandle generation */ + test-int-property = <42>; + test-str-property = "foo"; + + subtest: sub-test-node { + sub-test-property; + }; + }; + __symbols__ { + test = &test; + }; +}; + + diff --git a/dtc/tests/overlay_overlay.dts b/dtc/tests/overlay_overlay.dts new file mode 100644 index 000000000..c4ef1d47f --- /dev/null +++ b/dtc/tests/overlay_overlay.dts @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * Copyright (c) 2016 Konsulko Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/dts-v1/; +/plugin/; + +/* Test that we can change an int by another */ +&test { + test-int-property = <43>; +}; + +/* Test that we can replace a string by a longer one */ +&test { + test-str-property = "foobar"; +}; + +/* Test that we add a new property */ +&test { + test-str-property-2 = "foobar2"; +}; + +/* Test that we add a new node (by phandle) */ +&test { + new-node { + new-property; + }; +}; + +&test { + local: new-local-node { + new-property; + }; +}; + +&test { + test-phandle = <&test>, <&local>; +}; + +&test { + test-several-phandle = <&local>, <&local>; +}; + +&test { + sub-test-node { + new-sub-test-property; + }; +}; diff --git a/dtc/tests/overlay_overlay_bypath.dts b/dtc/tests/overlay_overlay_bypath.dts new file mode 100644 index 000000000..f23e7b603 --- /dev/null +++ b/dtc/tests/overlay_overlay_bypath.dts @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * Copyright (c) 2016 Konsulko Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/dts-v1/; +/plugin/; + +/* Test that we can change an int by another */ +&{/test-node} { + test-int-property = <43>; +}; + +/* Test that we can replace a string by a longer one */ +&{/test-node} { + test-str-property = "foobar"; +}; + +/* Test that we add a new property */ +&{/test-node} { + test-str-property-2 = "foobar2"; +}; + +/* Test that we add a new node (by phandle) */ +&{/test-node} { + new-node { + new-property; + }; +}; + +&{/} { + local: new-local-node { + new-property; + }; +}; + +&{/} { + test-several-phandle = <&local>, <&local>; +}; + +&{/test-node} { + sub-test-node { + new-sub-test-property; + }; +}; diff --git a/dtc/tests/overlay_overlay_local_merge.dts b/dtc/tests/overlay_overlay_local_merge.dts new file mode 100644 index 000000000..3ee622dfc --- /dev/null +++ b/dtc/tests/overlay_overlay_local_merge.dts @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * Copyright (c) 2016 Konsulko Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/dts-v1/; +/plugin/; + +&test { + parent: new-node { + parent-property; + }; +}; + +&parent { + new-merged-property; + new-merged-node { + new-property; + }; +}; + +&{/} { + new-root-node { + new-root-node-property; + }; +}; diff --git a/dtc/tests/overlay_overlay_long_path.dts b/dtc/tests/overlay_overlay_long_path.dts new file mode 100644 index 000000000..4f0d40b69 --- /dev/null +++ b/dtc/tests/overlay_overlay_long_path.dts @@ -0,0 +1,32 @@ +/dts-v1/; +/plugin/; + +&subtest_with_long_path { + lpath_0: test-0 { + prop = "lpath"; + }; + + lpath_1: test-1 { + prop = "lpath"; + }; + + lpath_2: test-2 { + prop = "lpath"; + }; + + lpath_3: test-3 { + prop = "lpath"; + }; + + lpath_4: test-4 { + prop = "lpath"; + }; + + lpath_5: test-5 { + prop = "lpath"; + }; + + lpath_6: test-6 { + prop = "lpath"; + }; +}; diff --git a/dtc/tests/overlay_overlay_manual_fixups.dts b/dtc/tests/overlay_overlay_manual_fixups.dts new file mode 100644 index 000000000..a5715b604 --- /dev/null +++ b/dtc/tests/overlay_overlay_manual_fixups.dts @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * Copyright (c) 2016 Konsulko Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/dts-v1/; + +/* Note no /plugin/ tag - we're manually generating the metadata for + testing purposes */ + +/ { + /* Test that we can change an int by another */ + fragment@0 { + target = <0xffffffff /*&test*/>; + + __overlay__ { + test-int-property = <43>; + }; + }; + + /* Test that we can replace a string by a longer one */ + fragment@1 { + target = <0xffffffff /*&test*/>; + + __overlay__ { + test-str-property = "foobar"; + }; + }; + + /* Test that we add a new property */ + fragment@2 { + target = <0xffffffff /*&test*/>; + + __overlay__ { + test-str-property-2 = "foobar2"; + }; + }; + + /* Test that we add a new node (by phandle) */ + fragment@3 { + target = <0xffffffff /*&test*/>; + + __overlay__ { + new-node { + new-property; + }; + }; + }; + + fragment@4 { + target = <0xffffffff /*&test*/>; + + __overlay__ { + local: new-local-node { + new-property; + }; + }; + }; + + fragment@5 { + target = <0xffffffff /*&test*/>; + + __overlay__ { + test-phandle = <0xffffffff /*&test*/>, <&local>; + }; + }; + + fragment@6 { + target = <0xffffffff /*&test*/>; + + __overlay__ { + test-several-phandle = <&local>, <&local>; + }; + }; + + fragment@7 { + target = <0xffffffff /*&test*/>; + + __overlay__ { + sub-test-node { + new-sub-test-property; + }; + }; + }; + + __fixups__ { + test = "/fragment@0:target:0", + "/fragment@1:target:0", + "/fragment@2:target:0", + "/fragment@3:target:0", + "/fragment@4:target:0", + "/fragment@5:target:0", + "/fragment@5/__overlay__:test-phandle:0", + "/fragment@6:target:0", + "/fragment@7:target:0"; + }; + __local_fixups__ { + fragment@5 { + __overlay__ { + test-phandle = <4>; + }; + }; + fragment@6 { + __overlay__ { + test-several-phandle = <0 4>; + }; + }; + }; +}; diff --git a/dtc/tests/overlay_overlay_no_fixups.dts b/dtc/tests/overlay_overlay_no_fixups.dts new file mode 100644 index 000000000..e8d0f96d8 --- /dev/null +++ b/dtc/tests/overlay_overlay_no_fixups.dts @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/dts-v1/; + +/ { + fragment@0 { + target-path = "/test-node"; + + __overlay__ { + test-int-property = <43>; + }; + }; + + /* Test that we can replace a string by a longer one */ + fragment@1 { + target-path = "/test-node"; + + __overlay__ { + test-str-property = "foobar"; + }; + }; + + /* Test that we add a new property */ + fragment@2 { + target-path = "/test-node"; + + __overlay__ { + test-str-property-2 = "foobar2"; + }; + }; + + fragment@3 { + target-path = "/test-node"; + + __overlay__ { + new-node { + new-property; + }; + }; + }; + + fragment@4 { + target-path = "/"; + + __overlay__ { + local: new-local-node { + new-property; + }; + }; + }; + + fragment@5 { + target-path = "/"; + + __overlay__ { + test-several-phandle = <&local>, <&local>; + }; + }; + + fragment@6 { + target-path = "/test-node"; + + __overlay__ { + sub-test-node { + new-sub-test-property; + }; + }; + }; + + __local_fixups__ { + fragment@5 { + __overlay__ { + test-several-phandle = <0 4>; + }; + }; + }; +}; diff --git a/dtc/tests/overlay_overlay_nosugar.dts b/dtc/tests/overlay_overlay_nosugar.dts new file mode 100644 index 000000000..b5947e96f --- /dev/null +++ b/dtc/tests/overlay_overlay_nosugar.dts @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * Copyright (c) 2016 Konsulko Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/dts-v1/; +/plugin/; + +/ { + /* Test that we can change an int by another */ + fragment@0 { + target = <&test>; + + __overlay__ { + test-int-property = <43>; + }; + }; + + /* Test that we can replace a string by a longer one */ + fragment@1 { + target = <&test>; + + __overlay__ { + test-str-property = "foobar"; + }; + }; + + /* Test that we add a new property */ + fragment@2 { + target = <&test>; + + __overlay__ { + test-str-property-2 = "foobar2"; + }; + }; + + /* Test that we add a new node (by phandle) */ + fragment@3 { + target = <&test>; + + __overlay__ { + new-node { + new-property; + }; + }; + }; + + fragment@4 { + target = <&test>; + + __overlay__ { + local: new-local-node { + new-property; + }; + }; + }; + + fragment@5 { + target = <&test>; + + __overlay__ { + test-phandle = <&test>, <&local>; + }; + }; + + fragment@6 { + target = <&test>; + + __overlay__ { + test-several-phandle = <&local>, <&local>; + }; + }; + + fragment@7 { + target = <&test>; + + __overlay__ { + sub-test-node { + new-sub-test-property; + }; + }; + }; +}; diff --git a/dtc/tests/overlay_overlay_simple.dts b/dtc/tests/overlay_overlay_simple.dts new file mode 100644 index 000000000..8657e1e7a --- /dev/null +++ b/dtc/tests/overlay_overlay_simple.dts @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2016 Konsulko Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/dts-v1/; +/plugin/; + +&test { + test-int-property = <43>; +}; diff --git a/dtc/tests/parent_offset.c b/dtc/tests/parent_offset.c new file mode 100644 index 000000000..a935a5374 --- /dev/null +++ b/dtc/tests/parent_offset.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_parent_offset() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static int path_parent_len(const char *path) +{ + const char *p = strrchr(path, '/'); + + if (!p) + TEST_BUG(); + if (p == path) + return 1; + else + return p - path; +} + +static void check_path(struct fdt_header *fdt, const char *path) +{ + char *parentpath; + int nodeoffset, parentoffset, parentpathoffset, pathparentlen; + + pathparentlen = path_parent_len(path); + parentpath = alloca(pathparentlen + 1); + strncpy(parentpath, path, pathparentlen); + parentpath[pathparentlen] = '\0'; + + verbose_printf("Path: \"%s\"\tParent: \"%s\"\n", path, parentpath); + + nodeoffset = fdt_path_offset(fdt, path); + if (nodeoffset < 0) + FAIL("fdt_path_offset(%s): %s", path, fdt_strerror(nodeoffset)); + + parentpathoffset = fdt_path_offset(fdt, parentpath); + if (parentpathoffset < 0) + FAIL("fdt_path_offset(%s): %s", parentpath, + fdt_strerror(parentpathoffset)); + + parentoffset = fdt_parent_offset(fdt, nodeoffset); + if (parentoffset < 0) + FAIL("fdt_parent_offset(): %s", fdt_strerror(parentoffset)); + + if (parentoffset != parentpathoffset) + FAIL("fdt_parent_offset() returns %d instead of %d", + parentoffset, parentpathoffset); +} + +int main(int argc, char *argv[]) +{ + void *fdt; + int err; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + check_path(fdt, "/subnode@1"); + check_path(fdt, "/subnode@2"); + check_path(fdt, "/subnode@1/subsubnode"); + check_path(fdt, "/subnode@2/subsubnode@0"); + err = fdt_parent_offset(fdt, 0); + if (err != -FDT_ERR_NOTFOUND) + FAIL("fdt_parent_offset(/) returns %d instead of " + "-FDT_ERR_NOTFOUND", err); + + PASS(); +} diff --git a/dtc/tests/path-references.c b/dtc/tests/path-references.c new file mode 100644 index 000000000..4db61a56d --- /dev/null +++ b/dtc/tests/path-references.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for string references in dtc + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static void check_ref(const void *fdt, int node, const char *checkpath) +{ + const char *p; + int len; + + p = fdt_getprop(fdt, node, "ref", &len); + if (!p) + FAIL("fdt_getprop(%d, \"ref\"): %s", node, fdt_strerror(len)); + if (!streq(p, checkpath)) + FAIL("'ref' in node at %d has value \"%s\" instead of \"%s\"", + node, p, checkpath); + + p = fdt_getprop(fdt, node, "lref", &len); + if (!p) + FAIL("fdt_getprop(%d, \"lref\"): %s", node, fdt_strerror(len)); + if (!streq(p, checkpath)) + FAIL("'lref' in node at %d has value \"%s\" instead of \"%s\"", + node, p, checkpath); +} + +static void check_rref(const void *fdt) +{ + const char *p; + int len; + + /* Check reference to root node */ + p = fdt_getprop(fdt, 0, "rref", &len); + if (!p) + FAIL("fdt_getprop(0, \"rref\"): %s", fdt_strerror(len)); + if (!streq(p, "/")) + FAIL("'rref' in root node has value \"%s\" instead of \"/\"", + p); +} + +int main(int argc, char *argv[]) +{ + void *fdt; + const char *p; + int len, multilen; + int n1, n2, n3, n4; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + n1 = fdt_path_offset(fdt, "/node1"); + if (n1 < 0) + FAIL("fdt_path_offset(/node1): %s", fdt_strerror(n1)); + n2 = fdt_path_offset(fdt, "/node2"); + if (n2 < 0) + FAIL("fdt_path_offset(/node2): %s", fdt_strerror(n2)); + + check_ref(fdt, n1, "/node2"); + check_ref(fdt, n2, "/node1"); + + /* Check multiple reference */ + multilen = strlen("/node1") + strlen("/node2") + 2; + p = fdt_getprop(fdt, 0, "multiref", &len); + if (!p) + FAIL("fdt_getprop(0, \"multiref\"): %s", fdt_strerror(len)); + if (len != multilen) + FAIL("multiref has wrong length, %d instead of %d", + len, multilen); + if ((!streq(p, "/node1") || !streq(p + strlen("/node1") + 1, "/node2"))) + FAIL("multiref has wrong value"); + + /* Check reference to nested nodes with common prefix */ + n3 = fdt_path_offset(fdt, "/foo/baz"); + if (n3 < 0) + FAIL("fdt_path_offset(/foo/baz): %s", fdt_strerror(n3)); + n4 = fdt_path_offset(fdt, "/foobar/baz"); + if (n4 < 0) + FAIL("fdt_path_offset(/foobar/baz): %s", fdt_strerror(n4)); + check_ref(fdt, n3, "/foobar/baz"); + check_ref(fdt, n4, "/foo/baz"); + + check_rref(fdt); + + PASS(); +} diff --git a/dtc/tests/path-references.dts b/dtc/tests/path-references.dts new file mode 100644 index 000000000..1fb7d7045 --- /dev/null +++ b/dtc/tests/path-references.dts @@ -0,0 +1,28 @@ +/dts-v1/; + +/ { + rref = &{/}; + /* Check multiple references case */ + multiref = &n1 , &n2; + n1: node1 { + ref = &{/node2}; /* reference precedes target */ + lref = &n2; + }; + n2: node2 { + ref = &{/node1}; /* reference after target */ + lref = &n1; + }; + /* Check references to nested nodes with common prefix */ + foobar { + n3: baz { + ref = &{/foo/baz}; + lref = start: &n4 end:; + }; + }; + foo { + n4: baz { + ref = &{/foobar/baz}; + lref = &n3; + }; + }; +}; diff --git a/dtc/tests/path_offset.c b/dtc/tests/path_offset.c new file mode 100644 index 000000000..82527d463 --- /dev/null +++ b/dtc/tests/path_offset.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_path_offset() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static int check_subnode(void *fdt, int parent, const char *name) +{ + int offset; + const struct fdt_node_header *nh; + uint32_t tag; + + verbose_printf("Checking subnode \"%s\" of %d...", name, parent); + offset = fdt_subnode_offset(fdt, parent, name); + verbose_printf("offset %d...", offset); + if (offset < 0) + FAIL("fdt_subnode_offset(\"%s\"): %s", name, fdt_strerror(offset)); + nh = fdt_offset_ptr(fdt, offset, sizeof(*nh)); + verbose_printf("pointer %p\n", nh); + if (! nh) + FAIL("NULL retrieving subnode \"%s\"", name); + + tag = fdt32_to_cpu(nh->tag); + + if (tag != FDT_BEGIN_NODE) + FAIL("Incorrect tag 0x%08x on property \"%s\"", tag, name); + if (!nodename_eq(nh->name, name)) + FAIL("Subnode name mismatch \"%s\" instead of \"%s\"", + nh->name, name); + + return offset; +} + +static void check_path_offset(void *fdt, char *path, int offset) +{ + int rc; + + verbose_printf("Checking offset of \"%s\" is %d...\n", path, offset); + + rc = fdt_path_offset(fdt, path); + if (rc < 0) + FAIL("fdt_path_offset(\"%s\") failed: %s", + path, fdt_strerror(rc)); + if (rc != offset) + FAIL("fdt_path_offset(\"%s\") returned incorrect offset" + " %d instead of %d", path, rc, offset); +} + +static void check_path_offset_namelen(void *fdt, char *path, int namelen, + int offset) +{ + int rc; + + verbose_printf("Checking offset of \"%s\" [first %d characters]" + " is %d...\n", path, namelen, offset); + + rc = fdt_path_offset_namelen(fdt, path, namelen); + if (rc == offset) + return; + + if (rc < 0) + FAIL("fdt_path_offset_namelen(\"%s\", %d) failed: %s", + path, namelen, fdt_strerror(rc)); + else + FAIL("fdt_path_offset_namelen(\"%s\", %d) returned incorrect" + " offset %d instead of %d", path, namelen, rc, offset); +} + +int main(int argc, char *argv[]) +{ + void *fdt; + int subnode1_offset, subnode2_offset; + int subsubnode1_offset, subsubnode2_offset, subsubnode2_offset2; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + check_path_offset(fdt, "/", 0); + + subnode1_offset = check_subnode(fdt, 0, "subnode@1"); + subnode2_offset = check_subnode(fdt, 0, "subnode@2"); + + check_path_offset(fdt, "/subnode@1", subnode1_offset); + check_path_offset(fdt, "/subnode@2", subnode2_offset); + + subsubnode1_offset = check_subnode(fdt, subnode1_offset, "subsubnode"); + subsubnode2_offset = check_subnode(fdt, subnode2_offset, "subsubnode@0"); + subsubnode2_offset2 = check_subnode(fdt, subnode2_offset, "subsubnode"); + + check_path_offset(fdt, "/subnode@1/subsubnode", subsubnode1_offset); + check_path_offset(fdt, "/subnode@2/subsubnode@0", subsubnode2_offset); + check_path_offset(fdt, "/subnode@2/subsubnode", subsubnode2_offset2); + + /* Test paths with extraneous separators */ + check_path_offset(fdt, "//", 0); + check_path_offset(fdt, "///", 0); + check_path_offset(fdt, "//subnode@1", subnode1_offset); + check_path_offset(fdt, "/subnode@1/", subnode1_offset); + check_path_offset(fdt, "//subnode@1///", subnode1_offset); + check_path_offset(fdt, "/subnode@2////subsubnode", subsubnode2_offset2); + + /* Test fdt_path_offset_namelen() */ + check_path_offset_namelen(fdt, "/subnode@1", 1, 0); + check_path_offset_namelen(fdt, "/subnode@1/subsubnode", 10, subnode1_offset); + check_path_offset_namelen(fdt, "/subnode@1/subsubnode", 11, subnode1_offset); + check_path_offset_namelen(fdt, "/subnode@2TRAILINGGARBAGE", 10, subnode2_offset); + check_path_offset_namelen(fdt, "/subnode@2TRAILINGGARBAGE", 11, -FDT_ERR_NOTFOUND); + check_path_offset_namelen(fdt, "/subnode@2/subsubnode@0/more", 23, subsubnode2_offset2); + check_path_offset_namelen(fdt, "/subnode@2/subsubnode@0/more", 22, -FDT_ERR_NOTFOUND); + check_path_offset_namelen(fdt, "/subnode@2/subsubnode@0/more", 24, subsubnode2_offset2); + check_path_offset_namelen(fdt, "/subnode@2/subsubnode@0/more", 25, -FDT_ERR_NOTFOUND); + + PASS(); +} diff --git a/dtc/tests/path_offset_aliases.c b/dtc/tests/path_offset_aliases.c new file mode 100644 index 000000000..0112e7250 --- /dev/null +++ b/dtc/tests/path_offset_aliases.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_path_offset() + * Copyright (C) 2006 David Gibson, IBM Corporation. + * Copyright 2008 Kumar Gala, Freescale Semiconductor, Inc. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static void check_alias(void *fdt, const char *full_path, const char *alias_path) +{ + int offset, offset_a; + + offset = fdt_path_offset(fdt, full_path); + offset_a = fdt_path_offset(fdt, alias_path); + + if (offset != offset_a) + FAIL("Mismatch between %s path_offset (%d) and %s path_offset alias (%d)", + full_path, offset, alias_path, offset_a); +} + +int main(int argc, char *argv[]) +{ + void *fdt; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + check_alias(fdt, "/subnode@1", "s1"); + check_alias(fdt, "/subnode@1/subsubnode", "ss1"); + check_alias(fdt, "/subnode@1/subsubnode", "s1/subsubnode"); + check_alias(fdt, "/subnode@1/subsubnode/subsubsubnode", "sss1"); + check_alias(fdt, "/subnode@1/subsubnode/subsubsubnode", "ss1/subsubsubnode"); + check_alias(fdt, "/subnode@1/subsubnode/subsubsubnode", "s1/subsubnode/subsubsubnode"); + + PASS(); +} diff --git a/dtc/tests/pci-bridge-bad1.dts b/dtc/tests/pci-bridge-bad1.dts new file mode 100644 index 000000000..17aac04ae --- /dev/null +++ b/dtc/tests/pci-bridge-bad1.dts @@ -0,0 +1,16 @@ +/dts-v1/; + +/ { + compatible = "example,pci-bridge-ok"; + #address-cells = < 2 >; + #size-cells = < 2 >; + abadname@0 { + device_type = "pci"; + compatible = "example,pci-bridge"; + #address-cells = < 3 >; + #size-cells = < 2 >; + reg = <0 0 0 0x1000>; + bus-range = <0 0xff>; + ranges = <0 0 0 0 0 0 0x10000>; + }; +}; diff --git a/dtc/tests/pci-bridge-bad2.dts b/dtc/tests/pci-bridge-bad2.dts new file mode 100644 index 000000000..a7e5c054a --- /dev/null +++ b/dtc/tests/pci-bridge-bad2.dts @@ -0,0 +1,16 @@ +/dts-v1/; + +/ { + compatible = "example,pci-bridge-ok"; + #address-cells = < 2 >; + #size-cells = < 2 >; + p@0 { + device_type = "pci"; + compatible = "example,pci-bridge"; + #address-cells = < 3 >; + #size-cells = < 2 >; + reg = <0 0 0 0x1000>; + bus-range = <0 0xff>; + ranges = <0 0 0 0 0 0 0x10000>; + }; +}; diff --git a/dtc/tests/pci-bridge-ok.dts b/dtc/tests/pci-bridge-ok.dts new file mode 100644 index 000000000..02e32e01a --- /dev/null +++ b/dtc/tests/pci-bridge-ok.dts @@ -0,0 +1,25 @@ +/dts-v1/; + +/ { + compatible = "example,pci-bridge-ok"; + #address-cells = < 2 >; + #size-cells = < 2 >; + pci@0 { + device_type = "pci"; + compatible = "example,pci-bridge"; + #address-cells = < 3 >; + #size-cells = < 2 >; + reg = <0 0 0 0x1000>; + bus-range = <0 0xff>; + ranges = <0 0 0 0 0 0 0x10000>; + }; + pcie@10000000000 { + device_type = "pci"; + compatible = "example,pcie-bridge"; + #address-cells = < 3 >; + #size-cells = < 2 >; + reg = <0x10 0x00000000 0 0x1000>; + bus-range = <0 0xff>; + ranges = <0 0 0 0 0 0 0x10000>; + }; +}; diff --git a/dtc/tests/phandle_format.c b/dtc/tests/phandle_format.c new file mode 100644 index 000000000..d00618f3b --- /dev/null +++ b/dtc/tests/phandle_format.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for phandle format options + * Copyright (C) 2009 David Gibson, IBM Corporation. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +#define PHANDLE_LEGACY 0x1 +#define PHANDLE_EPAPR 0x2 +#define PHANDLE_BOTH 0x3 + +int main(int argc, char *argv[]) +{ + void *fdt; + int phandle_format; + int n4; + uint32_t h4; + + if (argc != 3) + CONFIG("Usage: %s <dtb file> <legacy|epapr|both>\n", argv[0]); + + test_init(argc, argv); + fdt = load_blob(argv[1]); + + if (streq(argv[2], "legacy")) + phandle_format = PHANDLE_LEGACY; + else if (streq(argv[2], "epapr")) + phandle_format = PHANDLE_EPAPR; + else if (streq(argv[2], "both")) + phandle_format = PHANDLE_BOTH; + else + CONFIG("Usage: %s <dtb file> <legacy|epapr|both>\n", argv[0]); + + n4 = fdt_path_offset(fdt, "/node4"); + if (n4 < 0) + FAIL("fdt_path_offset(/node4): %s", fdt_strerror(n4)); + + h4 = fdt_get_phandle(fdt, n4); + if ((h4 == 0) || (h4 == -1)) + FAIL("/node4 has bad phandle 0x%x\n", h4); + + if (phandle_format & PHANDLE_LEGACY) + check_getprop_cell(fdt, n4, "linux,phandle", h4); + else + if (fdt_getprop(fdt, n4, "linux,phandle", NULL)) + FAIL("linux,phandle property present in non-legacy mode"); + + if (phandle_format & PHANDLE_EPAPR) + check_getprop_cell(fdt, n4, "phandle", h4); + else + if (fdt_getprop(fdt, n4, "phandle", NULL)) + FAIL("phandle property present in legacy-only mode"); + + PASS(); +} diff --git a/dtc/tests/prop-after-subnode.dts b/dtc/tests/prop-after-subnode.dts new file mode 100644 index 000000000..6dd0b660f --- /dev/null +++ b/dtc/tests/prop-after-subnode.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +/ { + node1 { + }; + prop; + node2 { + }; +}; diff --git a/dtc/tests/property_iterate.c b/dtc/tests/property_iterate.c new file mode 100644 index 000000000..9a67f4911 --- /dev/null +++ b/dtc/tests/property_iterate.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Tests that fdt_next_subnode() works as expected + * + * Copyright (C) 2013 Google, Inc + * + * Copyright (C) 2007 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static void test_node(void *fdt, int parent_offset) +{ + uint32_t properties; + const fdt32_t *prop; + int offset, property; + int count; + int len; + + /* + * This property indicates the number of properties in our + * test node to expect + */ + prop = fdt_getprop(fdt, parent_offset, "test-properties", &len); + if (!prop || len != sizeof(fdt32_t)) { + FAIL("Missing/invalid test-properties property at '%s'", + fdt_get_name(fdt, parent_offset, NULL)); + } + properties = fdt32_to_cpu(*prop); + + count = 0; + offset = fdt_first_subnode(fdt, parent_offset); + if (offset < 0) + FAIL("Missing test node\n"); + + fdt_for_each_property_offset(property, fdt, offset) + count++; + + if (count != properties) { + FAIL("Node '%s': Expected %d properties, got %d\n", + fdt_get_name(fdt, parent_offset, NULL), properties, + count); + } +} + +static void check_fdt_next_subnode(void *fdt) +{ + int offset; + int count = 0; + + fdt_for_each_subnode(offset, fdt, 0) { + test_node(fdt, offset); + count++; + } + + if (count != 2) + FAIL("Expected %d tests, got %d\n", 2, count); +} + +int main(int argc, char *argv[]) +{ + void *fdt; + + test_init(argc, argv); + if (argc != 2) + CONFIG("Usage: %s <dtb file>", argv[0]); + + fdt = load_blob(argv[1]); + if (!fdt) + FAIL("No device tree available"); + + check_fdt_next_subnode(fdt); + + PASS(); +} diff --git a/dtc/tests/property_iterate.dts b/dtc/tests/property_iterate.dts new file mode 100644 index 000000000..e8f5f8f4f --- /dev/null +++ b/dtc/tests/property_iterate.dts @@ -0,0 +1,23 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <0>; + + test1 { + test-properties = <3>; + + test { + linux,phandle = <0x1>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + test2 { + test-properties = <0>; + + test { + }; + }; +}; diff --git a/dtc/tests/propname_escapes.c b/dtc/tests/propname_escapes.c new file mode 100644 index 000000000..3e41e63b2 --- /dev/null +++ b/dtc/tests/propname_escapes.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_getprop() + * Copyright (C) 2006 David Gibson, IBM Corporation. + * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" + +int main(int argc, char *argv[]) +{ + void *fdt; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + check_getprop_cell(fdt, 0, "#address-cells", 1); + check_getprop_cell(fdt, 0, "#gpio-cells", 2); + + PASS(); +} diff --git a/dtc/tests/propname_escapes.dts b/dtc/tests/propname_escapes.dts new file mode 100644 index 000000000..9f70618b9 --- /dev/null +++ b/dtc/tests/propname_escapes.dts @@ -0,0 +1,6 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + \#gpio-cells = <2>; +}; diff --git a/dtc/tests/pylibfdt_tests.py b/dtc/tests/pylibfdt_tests.py new file mode 100644 index 000000000..64b5bd125 --- /dev/null +++ b/dtc/tests/pylibfdt_tests.py @@ -0,0 +1,592 @@ +# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +# pylibfdt - Tests for Flat Device Tree manipulation in Python +# Copyright (C) 2017 Google, Inc. +# Written by Simon Glass <sjg@chromium.org> +# + +import struct +import sys +import types +import unittest + +sys.path.insert(0, '../pylibfdt') +import libfdt +from libfdt import Fdt, FdtSw, FdtException, QUIET_NOTFOUND, QUIET_ALL + +TEST_ADDR_1H = 0xdeadbeef +TEST_ADDR_1L = 0x00000000 +TEST_ADDR_1 = (TEST_ADDR_1H << 32) | TEST_ADDR_1L +TEST_ADDR_1 = 0x8000000000000000 +TEST_SIZE_1H = 0x00000000 +TEST_SIZE_1L = 0x00100000 +TEST_SIZE_1 = (TEST_SIZE_1H << 32) | TEST_SIZE_1L +TEST_ADDR_2H = 0 +TEST_ADDR_2L = 123456789 +TEST_ADDR_2 = (TEST_ADDR_2H << 32) | TEST_ADDR_2L +TEST_SIZE_2H = 0 +TEST_SIZE_2L = 0o10000 +TEST_SIZE_2 = (TEST_SIZE_2H << 32) | TEST_SIZE_2L + +TEST_VALUE_1 = 0xdeadbeef +TEST_VALUE_2 = 123456789 + +TEST_VALUE64_1H = 0xdeadbeef +TEST_VALUE64_1L = 0x01abcdef +TEST_VALUE64_1 = (TEST_VALUE64_1H << 32) | TEST_VALUE64_1L + +PHANDLE_1 = 0x2000 +PHANDLE_2 = 0x2001 + +TEST_BYTES_1 = b'hello world' + +TEST_STRING_1 = 'hello world' +TEST_STRING_2 = 'hi world' +TEST_STRING_3 = u'unicode \u01d3' + + +def get_err(err_code): + """Convert an error code into an error message + + Args: + err_code: Error code value (FDT_ERR_...) + + Returns: + String error code + """ + return 'pylibfdt error %d: %s' % (-err_code, libfdt.strerror(-err_code)) + +def _ReadFdt(fname): + """Read a device tree file into an Fdt object, ready for use + + Args: + fname: Filename to read from + + Returns: + Fdt bytearray suitable for passing to libfdt functions + """ + with open(fname, mode='rb') as f: + return libfdt.Fdt(f.read()) + +class PyLibfdtBasicTests(unittest.TestCase): + """Test class for basic pylibfdt access functions + + Properties: + fdt: Device tree file used for testing + """ + + def setUp(self): + """Read in the device tree we use for testing""" + self.fdt = _ReadFdt('test_tree1.dtb') + self.fdt2 = _ReadFdt('test_props.dtb') + self.fdt3 = _ReadFdt('aliases.dtb') + + def GetPropList(self, node_path): + """Read a list of properties from a node + + Args: + node_path: Full path to node, e.g. '/subnode@1/subsubnode' + + Returns: + List of property names for that node, e.g. ['compatible', 'reg'] + """ + prop_list = [] + node = self.fdt.path_offset(node_path) + poffset = self.fdt.first_property_offset(node, QUIET_NOTFOUND) + while poffset > 0: + prop = self.fdt.get_property_by_offset(poffset) + prop_list.append(prop.name) + poffset = self.fdt.next_property_offset(poffset, QUIET_NOTFOUND) + return prop_list + + def GetSubnodes(self, node_path): + """Read a list of subnodes from a node + + Args: + node_path: Full path to node, e.g. '/subnode@1/subsubnode' + + Returns: + List of subnode names for that node, e.g. ['subsubnode', 'ss1'] + """ + subnode_list = [] + node = self.fdt.path_offset(node_path) + offset = self.fdt.first_subnode(node, QUIET_NOTFOUND) + while offset > 0: + name = self.fdt.get_name(offset) + subnode_list.append(name) + offset = self.fdt.next_subnode(offset, QUIET_NOTFOUND) + return subnode_list + + def testImport(self): + """Check that we can import the library correctly""" + self.assertEqual(type(libfdt), types.ModuleType) + + def testBadFdt(self): + """Check that a filename provided accidentally is not accepted""" + with self.assertRaises(FdtException) as e: + fdt = libfdt.Fdt(b'a string') + self.assertEqual(e.exception.err, -libfdt.BADMAGIC) + + def testSubnodeOffset(self): + """check that we can locate a subnode by name""" + node1 = self.fdt.path_offset('/subnode@1') + self.assertEqual(self.fdt.subnode_offset(0, 'subnode@1'), node1) + + with self.assertRaises(FdtException) as e: + self.fdt.subnode_offset(0, 'missing') + self.assertEqual(e.exception.err, -libfdt.NOTFOUND) + + node2 = self.fdt.path_offset('/subnode@1/subsubnode') + self.assertEqual(self.fdt.subnode_offset(node1, 'subsubnode'), node2) + + def testPathOffset(self): + """Check that we can find the offset of a node""" + self.assertEqual(self.fdt.path_offset('/'), 0) + self.assertTrue(self.fdt.path_offset('/subnode@1') > 0) + with self.assertRaises(FdtException) as e: + self.fdt.path_offset('/wibble') + self.assertEqual(e.exception.err, -libfdt.NOTFOUND) + self.assertEqual(self.fdt.path_offset('/wibble', QUIET_NOTFOUND), + -libfdt.NOTFOUND) + + def testPropertyOffset(self): + """Walk through all the properties in the root node""" + offset = self.fdt.first_property_offset(0) + self.assertTrue(offset > 0) + for i in range(5): + next_offset = self.fdt.next_property_offset(offset) + self.assertTrue(next_offset > offset) + offset = next_offset + self.assertEqual(self.fdt.next_property_offset(offset, QUIET_NOTFOUND), + -libfdt.NOTFOUND) + + def testPropertyOffsetExceptions(self): + """Check that exceptions are raised as expected""" + with self.assertRaises(FdtException) as e: + self.fdt.first_property_offset(107) + self.assertEqual(e.exception.err, -libfdt.BADOFFSET) + + # Quieten the NOTFOUND exception and check that a BADOFFSET + # exception is still raised. + with self.assertRaises(FdtException) as e: + self.fdt.first_property_offset(107, QUIET_NOTFOUND) + self.assertEqual(e.exception.err, -libfdt.BADOFFSET) + with self.assertRaises(FdtException) as e: + self.fdt.next_property_offset(107, QUIET_NOTFOUND) + self.assertEqual(e.exception.err, -libfdt.BADOFFSET) + + # Check that NOTFOUND can be quietened. + node = self.fdt.path_offset('/subnode@1/ss1') + self.assertEqual(self.fdt.first_property_offset(node, QUIET_NOTFOUND), + -libfdt.NOTFOUND) + with self.assertRaises(FdtException) as e: + self.fdt.first_property_offset(node) + self.assertEqual(e.exception.err, -libfdt.NOTFOUND) + + def testGetName(self): + """Check that we can get the name of a node""" + self.assertEqual(self.fdt.get_name(0), '') + node = self.fdt.path_offset('/subnode@1/subsubnode') + self.assertEqual(self.fdt.get_name(node), 'subsubnode') + + with self.assertRaises(FdtException) as e: + self.fdt.get_name(-2) + self.assertEqual(e.exception.err, -libfdt.BADOFFSET) + + def testGetPropertyByOffset(self): + """Check that we can read the name and contents of a property""" + root = 0 + poffset = self.fdt.first_property_offset(root) + prop = self.fdt.get_property_by_offset(poffset) + self.assertEqual(prop.name, 'compatible') + self.assertEqual(prop, b'test_tree1\0') + + with self.assertRaises(FdtException) as e: + self.fdt.get_property_by_offset(-2) + self.assertEqual(e.exception.err, -libfdt.BADOFFSET) + self.assertEqual( + -libfdt.BADOFFSET, + self.fdt.get_property_by_offset(-2, [libfdt.BADOFFSET])) + + def testGetProp(self): + """Check that we can read the contents of a property by name""" + root = self.fdt.path_offset('/') + value = self.fdt.getprop(root, "compatible") + self.assertEqual(value, b'test_tree1\0') + self.assertEqual(-libfdt.NOTFOUND, self.fdt.getprop(root, 'missing', + QUIET_NOTFOUND)) + + with self.assertRaises(FdtException) as e: + self.fdt.getprop(root, 'missing') + self.assertEqual(e.exception.err, -libfdt.NOTFOUND) + + node = self.fdt.path_offset('/subnode@1/subsubnode') + value = self.fdt.getprop(node, "compatible") + self.assertEqual(value, b'subsubnode1\0subsubnode\0') + + def testStrError(self): + """Check that we can get an error string""" + self.assertEqual(libfdt.strerror(-libfdt.NOTFOUND), + 'FDT_ERR_NOTFOUND') + + def testNextNodeOffset(self): + """Check that we can walk through nodes""" + node_list = [] + node = 0 + depth = 0 + while depth >= 0: + node_list.append([depth, self.fdt.get_name(node)]) + node, depth = self.fdt.next_node(node, depth, (libfdt.BADOFFSET,)) + self.assertEqual(node_list, [ + [0, ''], + [1, 'subnode@1'], + [2, 'subsubnode'], + [2, 'ss1'], + [1, 'subnode@2'], + [2, 'subsubnode@0'], + [2, 'ss2'], + ]) + + def testFirstNextSubnodeOffset(self): + """Check that we can walk through subnodes""" + node_list = [] + node = self.fdt.first_subnode(0, QUIET_NOTFOUND) + while node >= 0: + node_list.append(self.fdt.get_name(node)) + node = self.fdt.next_subnode(node, QUIET_NOTFOUND) + self.assertEqual(node_list, ['subnode@1', 'subnode@2']) + + def testFirstNextSubnodeOffsetExceptions(self): + """Check except handling for first/next subnode functions""" + node = self.fdt.path_offset('/subnode@1/subsubnode', QUIET_NOTFOUND) + self.assertEqual(self.fdt.first_subnode(node, QUIET_NOTFOUND), + -libfdt.NOTFOUND) + with self.assertRaises(FdtException) as e: + self.fdt.first_subnode(node) + self.assertEqual(e.exception.err, -libfdt.NOTFOUND) + + node = self.fdt.path_offset('/subnode@1/ss1', QUIET_NOTFOUND) + self.assertEqual(self.fdt.next_subnode(node, QUIET_NOTFOUND), + -libfdt.NOTFOUND) + with self.assertRaises(FdtException) as e: + self.fdt.next_subnode(node) + self.assertEqual(e.exception.err, -libfdt.NOTFOUND) + + def testDeleteProperty(self): + """Test that we can delete a property""" + node_name = '/subnode@1' + self.assertEqual(self.GetPropList(node_name), + ['compatible', 'reg', 'prop-int']) + node = self.fdt.path_offset('/%s' % node_name) + self.assertEqual(self.fdt.delprop(node, 'reg'), 0) + self.assertEqual(self.GetPropList(node_name), + ['compatible', 'prop-int']) + + def testHeader(self): + """Test that we can access the header values""" + self.assertEqual(self.fdt.magic(), 0xd00dfeed) + self.assertEqual(self.fdt.totalsize(), len(self.fdt._fdt)) + self.assertEqual(self.fdt.off_dt_struct(), 88) + self.assertEqual(self.fdt.off_dt_strings(), 652) + self.assertEqual(self.fdt.off_mem_rsvmap(), 40) + self.assertEqual(self.fdt.version(), 17) + self.assertEqual(self.fdt.last_comp_version(), 16) + self.assertEqual(self.fdt.boot_cpuid_phys(), 0) + self.assertEqual(self.fdt.size_dt_strings(), 105) + self.assertEqual(self.fdt.size_dt_struct(), 564) + + def testPack(self): + """Test that we can pack the tree after deleting something""" + orig_size = self.fdt.totalsize() + node = self.fdt.path_offset('/subnode@2', QUIET_NOTFOUND) + self.assertEqual(self.fdt.delprop(node, 'prop-int'), 0) + self.assertEqual(orig_size, self.fdt.totalsize()) + self.assertEqual(self.fdt.pack(), 0) + self.assertTrue(self.fdt.totalsize() < orig_size) + self.assertEqual(self.fdt.totalsize(), len(self.fdt.as_bytearray())) + + def testBadPropertyOffset(self): + """Test that bad property offsets are detected""" + with self.assertRaises(FdtException) as e: + self.fdt.get_property_by_offset(13) + self.assertEqual(e.exception.err, -libfdt.BADOFFSET) + with self.assertRaises(FdtException) as e: + self.fdt.first_property_offset(3) + self.assertEqual(e.exception.err, -libfdt.BADOFFSET) + with self.assertRaises(FdtException) as e: + self.fdt.next_property_offset(3) + self.assertEqual(e.exception.err, -libfdt.BADOFFSET) + + def testBadPathOffset(self): + """Test that bad path names are detected""" + with self.assertRaisesRegex(FdtException, get_err(libfdt.BADPATH)): + self.fdt.path_offset('not-present') + + def testQuietAll(self): + """Check that exceptions can be masked by QUIET_ALL""" + self.assertEqual(-libfdt.NOTFOUND, + self.fdt.path_offset('/missing', QUIET_ALL)) + self.assertEqual(-libfdt.BADOFFSET, + self.fdt.get_property_by_offset(13, QUIET_ALL)) + self.assertEqual(-libfdt.BADPATH, + self.fdt.path_offset('missing', QUIET_ALL)) + + def testIntegers(self): + """Check that integers can be passed and returned""" + self.assertEqual(0, libfdt.fdt_get_phandle(self.fdt._fdt, 0)) + node2 = self.fdt.path_offset('/subnode@2') + self.assertEqual(0x2000, libfdt.fdt_get_phandle(self.fdt._fdt, node2)) + + def testGetPhandle(self): + """Test for the get_phandle() method""" + self.assertEqual(0, self.fdt.get_phandle(0)) + node2 = self.fdt.path_offset('/subnode@2') + self.assertEqual(0x2000, self.fdt.get_phandle(node2)) + + def testGetAlias(self): + """Test for the get_alias() method""" + self.assertEqual("/subnode@1", self.fdt3.get_alias('s1')) + self.assertEqual("/subnode@1/subsubnode", self.fdt3.get_alias('ss1')) + self.assertEqual("/subnode@1/subsubnode/subsubsubnode", self.fdt3.get_alias('sss1')) + + def testParentOffset(self): + """Test for the parent_offset() method""" + self.assertEqual(-libfdt.NOTFOUND, + self.fdt.parent_offset(0, QUIET_NOTFOUND)) + with self.assertRaises(FdtException) as e: + self.fdt.parent_offset(0) + self.assertEqual(e.exception.err, -libfdt.NOTFOUND) + + node1 = self.fdt.path_offset('/subnode@2') + self.assertEqual(0, self.fdt.parent_offset(node1)) + node2 = self.fdt.path_offset('/subnode@2/subsubnode@0') + self.assertEqual(node1, self.fdt.parent_offset(node2)) + + def testNodeOffsetByPhandle(self): + """Test for the node_offset_by_phandle() method""" + self.assertEqual(-libfdt.NOTFOUND, + self.fdt.node_offset_by_phandle(1, QUIET_NOTFOUND)) + node1 = self.fdt.path_offset('/subnode@2') + self.assertEqual(node1, self.fdt.node_offset_by_phandle(0x2000)) + node2 = self.fdt.path_offset('/subnode@2/subsubnode@0') + self.assertEqual(node2, self.fdt.node_offset_by_phandle(0x2001)) + + def get_prop(self, name): + return self.fdt2.getprop(0, name) + + def testGetIntProperties(self): + """Test that we can access properties as integers""" + self.assertEqual(0xdeadbeef, self.get_prop("prop-hex32").as_uint32()) + self.assertEqual(123, self.get_prop("prop-uint32").as_uint32()) + self.assertEqual(-2, self.get_prop("prop-int32").as_int32()) + self.assertEqual(9223372036854775807, + self.get_prop("prop-uint64").as_uint64()) + self.assertEqual(-2, self.get_prop("prop-int64").as_int64()) + + def testReserveMap(self): + """Test that we can access the memory reserve map""" + self.assertEqual(2, self.fdt.num_mem_rsv()) + self.assertEqual([ 0xdeadbeef00000000, 0x100000], + self.fdt.get_mem_rsv(0)) + self.assertEqual([123456789, 0o10000], self.fdt.get_mem_rsv(1)) + + def testEmpty(self): + """Test that we can create an empty tree""" + self.assertEqual(-libfdt.NOSPACE, + Fdt.create_empty_tree(1, (libfdt.NOSPACE,))) + fdt = Fdt.create_empty_tree(128) + self.assertEqual(128, fdt.totalsize()) + + def testOpenInto(self): + """Test that we can resize a tree""" + fdt = Fdt.create_empty_tree(128) + self.assertEqual(128, fdt.totalsize()) + fdt.resize(256) + self.assertEqual(256, fdt.totalsize()) + fdt.pack() + self.assertTrue(fdt.totalsize() < 128) + + def testSetProp(self): + """Test that we can update and create properties""" + node = self.fdt.path_offset('/subnode@1') + self.fdt.setprop(node, 'compatible', TEST_BYTES_1) + self.assertEqual(TEST_BYTES_1, self.fdt.getprop(node, 'compatible')) + + # Check that this property is missing, and that we don't have space to + # add it + self.assertEqual(-libfdt.NOTFOUND, + self.fdt.getprop(node, 'missing', QUIET_NOTFOUND)) + self.assertEqual(-libfdt.NOSPACE, + self.fdt.setprop(node, 'missing', TEST_BYTES_1, + quiet=(libfdt.NOSPACE,))) + + # Expand the device tree so we now have room + self.fdt.resize(self.fdt.totalsize() + 50) + self.fdt.setprop(node, 'missing', TEST_BYTES_1) + self.assertEqual(TEST_BYTES_1, self.fdt.getprop(node, 'missing')) + + def testSetPropU32(self): + """Test that we can update and create integer properties""" + node = 0 + prop = 'prop-int' + self.fdt.setprop_u32(node, prop, TEST_VALUE_1) + self.assertEqual(struct.pack('>I', TEST_VALUE_1), + self.fdt.getprop(node, prop)) + + def testSetPropU64(self): + """Test that we can update and create integer properties""" + node = 0 + prop = 'prop-int64' + self.fdt.setprop_u64(node, prop, TEST_VALUE64_1) + self.assertEqual(struct.pack('>Q', TEST_VALUE64_1), + self.fdt.getprop(node, prop)) + + def testSetPropStr(self): + """Test that we can set a property to a particular string""" + node = 0 + prop = 'prop-str' + self.assertEqual(TEST_STRING_1, self.fdt.getprop(node, prop).as_str()) + self.fdt.setprop_str(node, prop, TEST_STRING_2) + self.assertEqual(TEST_STRING_2, self.fdt.getprop(node, prop).as_str()) + with self.assertRaises(ValueError) as e: + self.fdt.getprop(node, 'prop-int').as_str() + self.assertIn('lacks nul termination', str(e.exception)) + + node2 = self.fdt.path_offset('/subnode@1/subsubnode') + with self.assertRaises(ValueError) as e: + self.fdt.getprop(node2, 'compatible').as_str() + self.assertIn('embedded nul', str(e.exception)) + + # Expand the device tree so we now have room + self.fdt.resize(self.fdt.totalsize() + 50) + prop = 'prop-unicode' + self.fdt.setprop_str(node, prop, TEST_STRING_3) + self.assertEqual(TEST_STRING_3, + self.fdt.getprop(node, prop).as_str()) + + def testSetName(self): + """Test that we can update a node name""" + node = self.fdt.path_offset('/subnode@1') + old_val = self.fdt.get_name(node) + self.fdt.set_name(node, 'test') + self.assertEqual('test', self.fdt.get_name(node)) + + with self.assertRaises(ValueError) as e: + self.fdt.set_name(node, 'some\0name') + self.assertIn('embedded nul', str(e.exception)) + + with self.assertRaises(ValueError) as e: + self.fdt.set_name(node, 'name\0') + self.assertIn('embedded nul', str(e.exception)) + + def testAddDeleteNodes(self): + """Test that we can add and delete nodes""" + node_name = '/subnode@1' + self.assertEqual(self.GetSubnodes(node_name), ['subsubnode', 'ss1']) + node = self.fdt.path_offset('%s/subsubnode' % node_name) + self.assertEqual(self.fdt.del_node(node, 'subsubnode'), 0) + self.assertEqual(self.GetSubnodes(node_name), ['ss1']) + + node = self.fdt.path_offset(node_name) + offset = self.fdt.add_subnode(node, 'more') + self.assertTrue(offset > 0) + self.assertEqual(self.GetSubnodes(node_name), ['more', 'ss1']) + + +class PyLibfdtSwTests(unittest.TestCase): + """Test class for pylibfdt sequential-write DT creation + """ + def assertOk(self, err_code): + self.assertEqual(0, err_code) + + def testCreate(self): + # First check the minimum size and also the FdtSw() constructor + with self.assertRaisesRegex(FdtException, get_err(libfdt.NOSPACE)): + self.assertEqual(-libfdt.NOSPACE, FdtSw(3)) + + sw = FdtSw() + sw.add_reservemap_entry(TEST_ADDR_1, TEST_SIZE_1) + sw.add_reservemap_entry(TEST_ADDR_2, TEST_SIZE_2) + sw.finish_reservemap() + + sw.begin_node('') + sw.property_string('compatible', 'test_tree1') + sw.property_u32('prop-int', TEST_VALUE_1) + + sw.property_u32('prop-int', TEST_VALUE_1) + sw.property_u64('prop-int64', TEST_VALUE64_1) + sw.property_string('prop-str', TEST_STRING_1) + sw.property_u32('#address-cells', 1) + sw.property_u32('#size-cells', 0) + + sw.begin_node('subnode@1') + sw.property_string('compatible', 'subnode1') + sw.property_u32('reg', 1) + sw.property_cell('prop-int', TEST_VALUE_1) + sw.property('data', b'\x00data\x01') + sw.begin_node('subsubnode') + sw.property('compatible', b'subsubnode1\0subsubnode') + sw.property_cell('prop-int', TEST_VALUE_1) + sw.end_node() + sw.begin_node('ss1') + sw.end_node() + sw.end_node() + + for i in range(2, 11): + with sw.add_node('subnode@%d' % i): + sw.property_u32('reg', 2) + sw.property_cell('linux,phandle', PHANDLE_1) + sw.property_cell('prop-int', TEST_VALUE_2) + sw.property_u32('#address-cells', 1) + sw.property_u32('#size-cells', 0) + with sw.add_node('subsubnode@0'): + sw.property_u32('reg', 0) + sw.property_cell('phandle', PHANDLE_2) + sw.property('compatible', b'subsubnode2\0subsubnode') + sw.property_cell('prop-int', TEST_VALUE_2) + with sw.add_node('ss2'): + pass + sw.end_node() + + fdt = sw.as_fdt() + self.assertEqual(2, fdt.num_mem_rsv()) + self.assertEqual([TEST_ADDR_1, TEST_SIZE_1], fdt.get_mem_rsv(0)) + + # Make sure we can add a few more things + with sw.add_node('another'): + sw.property_u32('reg', 3) + + # Make sure we can read from the tree too + node = sw.path_offset('/subnode@1') + self.assertEqual(b'subnode1\0', sw.getprop(node, 'compatible')) + + # Make sure we did at least two resizes + self.assertTrue(len(fdt.as_bytearray()) > FdtSw.INC_SIZE * 2) + + +class PyLibfdtRoTests(unittest.TestCase): + """Test class for read-only pylibfdt access functions + + This just tests a few simple cases. Most of the tests are in + PyLibfdtBasicTests. + + Properties: + fdt: Device tree file used for testing + """ + + def setUp(self): + """Read in the device tree we use for testing""" + with open('test_tree1.dtb', mode='rb') as f: + self.fdt = libfdt.FdtRo(f.read()) + + def testAccess(self): + """Basic sanity check for the FdtRo class""" + node = self.fdt.path_offset('/subnode@1') + self.assertEqual(b'subnode1\0', + self.fdt.getprop(node, 'compatible')) + node = self.fdt.first_subnode(node) + self.assertEqual(b'this is a placeholder string\0string2\0', + self.fdt.getprop(node, 'placeholder')) + + +if __name__ == "__main__": + unittest.main() diff --git a/dtc/tests/references.c b/dtc/tests/references.c new file mode 100644 index 000000000..d18e72250 --- /dev/null +++ b/dtc/tests/references.c @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for phandle references in dtc + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static void check_ref(const void *fdt, int node, uint32_t checkref) +{ + const fdt32_t *p; + uint32_t ref; + int len; + + p = fdt_getprop(fdt, node, "ref", &len); + if (!p) + FAIL("fdt_getprop(%d, \"ref\"): %s", node, fdt_strerror(len)); + if (len != sizeof(*p)) + FAIL("'ref' in node at %d has wrong size (%d instead of %zd)", + node, len, sizeof(*p)); + ref = fdt32_to_cpu(*p); + if (ref != checkref) + FAIL("'ref' in node at %d has value 0x%x instead of 0x%x", + node, ref, checkref); + + p = fdt_getprop(fdt, node, "lref", &len); + if (!p) + FAIL("fdt_getprop(%d, \"lref\"): %s", node, fdt_strerror(len)); + if (len != sizeof(*p)) + FAIL("'lref' in node at %d has wrong size (%d instead of %zd)", + node, len, sizeof(*p)); + ref = fdt32_to_cpu(*p); + if (ref != checkref) + FAIL("'lref' in node at %d has value 0x%x instead of 0x%x", + node, ref, checkref); +} + +static void check_rref(const void *fdt) +{ + const fdt32_t *p; + uint32_t ref; + int len; + + p = fdt_getprop(fdt, 0, "rref", &len); + if (!p) + FAIL("fdt_getprop(0, \"rref\"): %s", fdt_strerror(len)); + if (len != sizeof(*p)) + FAIL("'rref' in root node has wrong size (%d instead of %zd)", + len, sizeof(*p)); + ref = fdt32_to_cpu(*p); + if (ref != fdt_get_phandle(fdt, 0)) + FAIL("'rref' in root node has value 0x%x instead of 0x0", ref); +} + +int main(int argc, char *argv[]) +{ + void *fdt; + int n1, n2, n3, n4, n5, n6, err; + uint32_t h1, h2, h4, h5, h6, hn; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + n1 = fdt_path_offset(fdt, "/node1"); + if (n1 < 0) + FAIL("fdt_path_offset(/node1): %s", fdt_strerror(n1)); + n2 = fdt_path_offset(fdt, "/node2"); + if (n2 < 0) + FAIL("fdt_path_offset(/node2): %s", fdt_strerror(n2)); + n3 = fdt_path_offset(fdt, "/node3"); + if (n3 < 0) + FAIL("fdt_path_offset(/node3): %s", fdt_strerror(n3)); + n4 = fdt_path_offset(fdt, "/node4"); + if (n4 < 0) + FAIL("fdt_path_offset(/node4): %s", fdt_strerror(n4)); + n5 = fdt_path_offset(fdt, "/node5"); + if (n5 < 0) + FAIL("fdt_path_offset(/node5): %s", fdt_strerror(n5)); + n6 = fdt_path_offset(fdt, "/node6"); + if (n6 < 0) + FAIL("fdt_path_offset(/node6): %s", fdt_strerror(n6)); + + h1 = fdt_get_phandle(fdt, n1); + h2 = fdt_get_phandle(fdt, n2); + h4 = fdt_get_phandle(fdt, n4); + h5 = fdt_get_phandle(fdt, n5); + h6 = fdt_get_phandle(fdt, n6); + + if (h1 != 0x2000) + FAIL("/node1 has wrong phandle, 0x%x instead of 0x%x", + h1, 0x2000); + if (h2 != 0x1) + FAIL("/node2 has wrong phandle, 0x%x instead of 0x%x", + h2, 0x1); + if (h6 != FDT_MAX_PHANDLE) + FAIL("/node6 has wrong phandle, 0x%x instead of 0x%x", + h6, FDT_MAX_PHANDLE); + if ((h4 == 0x2000) || (h4 == 0x1) || (h4 == 0)) + FAIL("/node4 has bad phandle, 0x%x", h4); + + if ((h5 == 0) || (h5 == -1)) + FAIL("/node5 has bad phandle, 0x%x", h5); + if ((h5 == h4) || (h5 == h2) || (h5 == h1)) + FAIL("/node5 has duplicate phandle, 0x%x", h5); + + /* + * /node6 has phandle FDT_MAX_PHANDLE, so fdt_generate_phandle() is + * expected to fail. + */ + err = fdt_generate_phandle(fdt, &hn); + if (err != -FDT_ERR_NOPHANDLES) + FAIL("generated invalid phandle 0x%x\n", hn); + + check_ref(fdt, n1, h2); + check_ref(fdt, n2, h1); + check_ref(fdt, n3, h4); + + check_rref(fdt); + + PASS(); +} diff --git a/dtc/tests/references.dts b/dtc/tests/references.dts new file mode 100644 index 000000000..b39063999 --- /dev/null +++ b/dtc/tests/references.dts @@ -0,0 +1,41 @@ +/dts-v1/; + +/ { + rref = <&{/}>; + + /* Explicit phandles */ + n1: node1 { + linux,phandle = <0x2000>; + ref = <&{/node2}>; /* reference precedes target */ + lref = <&n2>; + }; + n2: node2 { + phandle = <0x1>; + ref = <&{/node1}>; /* reference after target */ + lref = <&n1>; + }; + + /* Implicit phandles */ + n3: node3 { + ref = <&{/node4}>; + lref = <&n4>; + }; + n4: node4 { + }; + + /* Explicit phandle with implicit value */ + /* This self-reference is the standard way to tag a node as requiring + * a phandle (perhaps for reference by nodes that will be dynamically + * added) without explicitly allocating it a phandle. + * The self-reference requires some special internal handling, though + * so check it actually works */ + n5: node5 { + linux,phandle = <&n5>; + phandle = <&n5>; + }; + + node6 { + linux,phandle = <0xfffffffe>; + phandle = <0xfffffffe>; + }; +}; diff --git a/dtc/tests/reg-ranges-root.dts b/dtc/tests/reg-ranges-root.dts new file mode 100644 index 000000000..9935b415f --- /dev/null +++ b/dtc/tests/reg-ranges-root.dts @@ -0,0 +1,8 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + reg = <0x1000 0x10>; + ranges = <0x1000 0x2000 0x1000>; +}; diff --git a/dtc/tests/reg-without-unit-addr.dts b/dtc/tests/reg-without-unit-addr.dts new file mode 100644 index 000000000..aaf8af7a8 --- /dev/null +++ b/dtc/tests/reg-without-unit-addr.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + node { + reg = <0 1>; + }; +}; diff --git a/dtc/tests/reuse-label.dts b/dtc/tests/reuse-label.dts new file mode 100644 index 000000000..98b5ca9dc --- /dev/null +++ b/dtc/tests/reuse-label.dts @@ -0,0 +1,15 @@ +/dts-v1/; + +/ { + label: property1 = "foo"; + label: property2 = "bar"; + + test1 = &label; + + label: node1 { + prop = "foo"; + }; + label: node2 { + prop = "bar"; + }; +}; diff --git a/dtc/tests/reuse-label1.dts b/dtc/tests/reuse-label1.dts new file mode 100644 index 000000000..f22956932 --- /dev/null +++ b/dtc/tests/reuse-label1.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +/ { + label: node1 { + prop = "foo"; + }; + label: node2 { + prop = "bar"; + }; +}; diff --git a/dtc/tests/reuse-label2.dts b/dtc/tests/reuse-label2.dts new file mode 100644 index 000000000..01ea6b27f --- /dev/null +++ b/dtc/tests/reuse-label2.dts @@ -0,0 +1,6 @@ +/dts-v1/; + +/ { + label: property1 = "foo"; + label: property2 = "bar"; +}; diff --git a/dtc/tests/reuse-label3.dts b/dtc/tests/reuse-label3.dts new file mode 100644 index 000000000..fa3d2c72a --- /dev/null +++ b/dtc/tests/reuse-label3.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +/ { + label: property = "foo"; + + label: node { + property = "foo"; + }; +}; diff --git a/dtc/tests/reuse-label4.dts b/dtc/tests/reuse-label4.dts new file mode 100644 index 000000000..6805de322 --- /dev/null +++ b/dtc/tests/reuse-label4.dts @@ -0,0 +1,5 @@ +/dts-v1/; + +/ { + property = label: "foo" label:; +}; diff --git a/dtc/tests/reuse-label5.dts b/dtc/tests/reuse-label5.dts new file mode 100644 index 000000000..b7238e64a --- /dev/null +++ b/dtc/tests/reuse-label5.dts @@ -0,0 +1,6 @@ +/dts-v1/; + +/ { + prop1 = label: "foo"; + prop2 = "bar" label:; +}; diff --git a/dtc/tests/reuse-label6.dts b/dtc/tests/reuse-label6.dts new file mode 100644 index 000000000..f5d507c6d --- /dev/null +++ b/dtc/tests/reuse-label6.dts @@ -0,0 +1,6 @@ +/dts-v1/; + +/ { + label: prop1 = "foo"; + prop2 = "bar" label:; +}; diff --git a/dtc/tests/root_node.c b/dtc/tests/root_node.c new file mode 100644 index 000000000..37e6f0590 --- /dev/null +++ b/dtc/tests/root_node.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Basic testcase for read-only access + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +int main(int argc, char *argv[]) +{ + void *fdt; + const struct fdt_node_header *nh; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + nh = fdt_offset_ptr(fdt, 0, sizeof(*nh)); + + if (! nh) + FAIL("NULL retrieving root node"); + + if (fdt32_to_cpu(nh->tag) != FDT_BEGIN_NODE) + FAIL("Wrong tag on root node"); + + if (strlen(nh->name) != 0) + FAIL("Wrong name for root node, \"%s\" instead of empty", + nh->name); + + PASS(); +} diff --git a/dtc/tests/run_tests.sh b/dtc/tests/run_tests.sh new file mode 100755 index 000000000..0e270feb3 --- /dev/null +++ b/dtc/tests/run_tests.sh @@ -0,0 +1,1104 @@ +#! /bin/sh + +SRCDIR=`dirname "$0"` +. "$SRCDIR/testutils.sh" + +if [ -z "$CC" ]; then + CC=cc +fi + +if [ -z "$PYTHON" ]; then + PYTHON=python3 +fi + +if [ -n "$NO_PYTHON" ]; then + if [ "$NO_PYTHON" != "0" ]; then + no_python=true + else + no_python=false + fi +else + if [ -f ../pylibfdt/_libfdt.so ] || [ -f ../pylibfdt/_libfdt.cpython-3*.so ]; then + no_python=false + else + no_python=true + fi +fi + +if [ -n "$NO_YAML" ]; then + if [ "$NO_YAML" != "0" ]; then + no_yaml=true + else + no_yaml=false + fi +else + if pkg-config --exists yaml-0.1; then + no_yaml=false + else + no_yaml=true + fi +fi + +# stat differs between platforms +if [ -z "$STATSZ" ]; then + stat --version 2>/dev/null | grep -q 'GNU' + GNUSTAT=$? + if [ "$GNUSTAT" -ne 0 ]; then + # Assume BSD stat if we can't detect as GNU stat + STATSZ="stat -f %Uz" + else + STATSZ="stat -c %s" + fi +fi + +# Help things find the libfdt shared object +if [ -z "$TEST_LIBDIR" ]; then + TEST_LIBDIR=../libfdt +fi +export LD_LIBRARY_PATH="$TEST_LIBDIR" + +export QUIET_TEST=1 +STOP_ON_FAIL=0 + +export VALGRIND= +VGCODE=126 + +tot_tests=0 +tot_pass=0 +tot_fail=0 +tot_config=0 +tot_vg=0 +tot_strange=0 + +base_run_test() { + tot_tests=$((tot_tests + 1)) + if VALGRIND="$VALGRIND" "$@"; then + tot_pass=$((tot_pass + 1)) + else + ret="$?" + if [ "$STOP_ON_FAIL" -eq 1 ]; then + exit 1 + fi + if [ "$ret" -eq 1 ]; then + tot_config=$((tot_config + 1)) + elif [ "$ret" -eq 2 ]; then + tot_fail=$((tot_fail + 1)) + elif [ "$ret" -eq $VGCODE ]; then + tot_vg=$((tot_vg + 1)) + else + tot_strange=$((tot_strange + 1)) + fi + fi +} + +shorten_echo () { + limit=32 + printf "$1" + shift + for x; do + if [ ${#x} -le $limit ]; then + printf " $x" + else + short=$(echo "$x" | head -c$limit) + printf " \"$short\"...<${#x} bytes>" + fi + done +} + +run_test () { + printf "$*: " + if [ -n "$VALGRIND" -a -f $1.supp ]; then + VGSUPP="--suppressions=$1.supp" + fi + base_run_test $VALGRIND $VGSUPP "./$@" +} + +run_sh_test () { + printf "$*: " + base_run_test sh "$@" +} + +wrap_test () { + ( + if verbose_run "$@"; then + PASS + else + ret="$?" + if [ "$ret" -gt 127 ]; then + signame=$(kill -l $((ret - 128))) + FAIL "Killed by SIG$signame" + elif [ "$ret" -eq $VGCODE ]; then + echo "VALGRIND ERROR" + exit $VGCODE + else + FAIL "Returned error code $ret" + fi + fi + ) +} + +run_wrap_test () { + shorten_echo "$@: " + base_run_test wrap_test "$@" +} + +wrap_error () { + ( + if verbose_run "$@"; then + FAIL "Expected non-zero return code" + else + ret="$?" + if [ "$ret" -gt 127 ]; then + signame=$(kill -l $((ret - 128))) + FAIL "Killed by SIG$signame" + else + PASS + fi + fi + ) +} + +run_wrap_error_test () { + shorten_echo "$@" + printf " {!= 0}: " + base_run_test wrap_error "$@" +} + +# $1: dtb file +# $2: align base +check_align () { + shorten_echo "check_align $@: " + local size=$($STATSZ "$1") + local align="$2" + ( + if [ $(($size % $align)) -eq 0 ] ;then + PASS + else + FAIL "Output size $size is not $align-byte aligned" + fi + ) +} + +run_dtc_test () { + printf "dtc $*: " + base_run_test wrap_test $VALGRIND $DTC "$@" +} + +asm_to_so () { + $CC -shared -o $1.test.so "$SRCDIR/data.S" $1.test.s +} + +asm_to_so_test () { + run_wrap_test asm_to_so "$@" +} + +run_fdtget_test () { + expect="$1" + shift + printf "fdtget-runtest.sh %s $*: " "$(echo $expect)" + base_run_test sh "$SRCDIR/fdtget-runtest.sh" "$expect" "$@" +} + +run_fdtput_test () { + expect="$1" + shift + shorten_echo fdtput-runtest.sh "$expect" "$@" + printf ": " + base_run_test sh "$SRCDIR/fdtput-runtest.sh" "$expect" "$@" +} + +run_fdtdump_test() { + file="$1" + shorten_echo fdtdump-runtest.sh "$file" + printf ": " + base_run_test sh "$SRCDIR/fdtdump-runtest.sh" "$file" 2>/dev/null +} + +run_fdtoverlay_test() { + expect="$1" + shift + shorten_echo fdtoverlay-runtest.sh "$expect" "$@" + printf ": " + base_run_test sh "$SRCDIR/fdtoverlay-runtest.sh" "$expect" "$@" +} + +BAD_FIXUP_TREES="bad_index \ + empty \ + empty_index \ + index_trailing \ + path_empty_prop \ + path_only \ + path_only_sep \ + path_prop" + +# Test to exercise libfdt overlay application without dtc's overlay support +libfdt_overlay_tests () { + # First test a doctored overlay which requires only local fixups + run_dtc_test -I dts -O dtb -o overlay_base_no_symbols.test.dtb "$SRCDIR/overlay_base.dts" + run_test check_path overlay_base_no_symbols.test.dtb not-exists "/__symbols__" + run_test check_path overlay_base_no_symbols.test.dtb not-exists "/__fixups__" + run_test check_path overlay_base_no_symbols.test.dtb not-exists "/__local_fixups__" + + run_dtc_test -I dts -O dtb -o overlay_overlay_no_fixups.test.dtb "$SRCDIR/overlay_overlay_no_fixups.dts" + run_test check_path overlay_overlay_no_fixups.test.dtb not-exists "/__symbols__" + run_test check_path overlay_overlay_no_fixups.test.dtb not-exists "/__fixups__" + run_test check_path overlay_overlay_no_fixups.test.dtb exists "/__local_fixups__" + + run_test overlay overlay_base_no_symbols.test.dtb overlay_overlay_no_fixups.test.dtb + + # Then test with manually constructed fixups + run_dtc_test -I dts -O dtb -o overlay_base_manual_symbols.test.dtb "$SRCDIR/overlay_base_manual_symbols.dts" + run_test check_path overlay_base_manual_symbols.test.dtb exists "/__symbols__" + run_test check_path overlay_base_manual_symbols.test.dtb not-exists "/__fixups__" + run_test check_path overlay_base_manual_symbols.test.dtb not-exists "/__local_fixups__" + + run_dtc_test -I dts -O dtb -o overlay_overlay_manual_fixups.test.dtb "$SRCDIR/overlay_overlay_manual_fixups.dts" + run_test check_path overlay_overlay_manual_fixups.test.dtb not-exists "/__symbols__" + run_test check_path overlay_overlay_manual_fixups.test.dtb exists "/__fixups__" + run_test check_path overlay_overlay_manual_fixups.test.dtb exists "/__local_fixups__" + + run_test overlay overlay_base_manual_symbols.test.dtb overlay_overlay_manual_fixups.test.dtb + + # test simplified plugin syntax + run_dtc_test -@ -I dts -O dtb -o overlay_overlay_simple.dtb "$SRCDIR/overlay_overlay_simple.dts" + + # verify non-generation of local fixups + run_test check_path overlay_overlay_simple.dtb not-exists "/__local_fixups__" + + # Bad fixup tests + for test in $BAD_FIXUP_TREES; do + tree="overlay_bad_fixup_$test" + run_dtc_test -I dts -O dtb -o $tree.test.dtb "$SRCDIR/$tree.dts" + run_test overlay_bad_fixup overlay_base_no_symbols.test.dtb $tree.test.dtb + done +} + +# Tests to exercise dtc's overlay generation support +dtc_overlay_tests () { + # Overlay tests for dtc + run_dtc_test -@ -I dts -O dtb -o overlay_base.test.dtb "$SRCDIR/overlay_base.dts" + run_test check_path overlay_base.test.dtb exists "/__symbols__" + run_test check_path overlay_base.test.dtb not-exists "/__fixups__" + run_test check_path overlay_base.test.dtb not-exists "/__local_fixups__" + + # With syntactic sugar + run_dtc_test -I dts -O dtb -o overlay_overlay.test.dtb "$SRCDIR/overlay_overlay.dts" + run_test check_path overlay_overlay.test.dtb not-exists "/__symbols__" + run_test check_path overlay_overlay.test.dtb exists "/__fixups__" + run_test check_path overlay_overlay.test.dtb exists "/__local_fixups__" + + # Without syntactic sugar + run_dtc_test -I dts -O dtb -o overlay_overlay_nosugar.test.dtb "$SRCDIR/overlay_overlay_nosugar.dts" + run_test check_path overlay_overlay_nosugar.test.dtb not-exists "/__symbols__" + run_test check_path overlay_overlay_nosugar.test.dtb exists "/__fixups__" + run_test check_path overlay_overlay_nosugar.test.dtb exists "/__local_fixups__" + + # Using target-path + run_dtc_test -I dts -O dtb -o overlay_overlay_bypath.test.dtb "$SRCDIR/overlay_overlay_bypath.dts" + run_test check_path overlay_overlay_bypath.test.dtb not-exists "/__symbols__" + run_test check_path overlay_overlay_bypath.test.dtb not-exists "/__fixups__" + run_test check_path overlay_overlay_bypath.test.dtb exists "/__local_fixups__" + + # Make sure local target references are resolved and nodes are merged and that path references are not + run_dtc_test -I dts -O dtb -o overlay_overlay_local_merge.test.dtb "$SRCDIR/overlay_overlay_local_merge.dts" + run_test check_path overlay_overlay_local_merge.test.dtb exists "/fragment@0/__overlay__/new-node/new-merged-node" + run_test check_path overlay_overlay_local_merge.test.dtb exists "/fragment@1/__overlay__/new-root-node" + + # Check building works the same as manual constructions + run_test dtbs_equal_ordered overlay_overlay.test.dtb overlay_overlay_nosugar.test.dtb + + run_dtc_test -I dts -O dtb -o overlay_overlay_manual_fixups.test.dtb "$SRCDIR/overlay_overlay_manual_fixups.dts" + run_test dtbs_equal_ordered overlay_overlay.test.dtb overlay_overlay_manual_fixups.test.dtb + + run_dtc_test -I dts -O dtb -o overlay_overlay_no_fixups.test.dtb "$SRCDIR/overlay_overlay_no_fixups.dts" + run_test dtbs_equal_ordered overlay_overlay_bypath.test.dtb overlay_overlay_no_fixups.test.dtb + + # Check we can actually apply the result + run_dtc_test -I dts -O dtb -o overlay_base_no_symbols.test.dtb "$SRCDIR/overlay_base.dts" + run_test overlay overlay_base.test.dtb overlay_overlay.test.dtb + run_test overlay overlay_base_no_symbols.test.dtb overlay_overlay_bypath.test.dtb + + # test plugin source to dtb and back + run_dtc_test -I dtb -O dts -o overlay_overlay_decompile.test.dts overlay_overlay.test.dtb + run_dtc_test -I dts -O dtb -o overlay_overlay_decompile.test.dtb overlay_overlay_decompile.test.dts + run_test dtbs_equal_ordered overlay_overlay.test.dtb overlay_overlay_decompile.test.dtb + + # Test generation of aliases instead of symbols + run_dtc_test -A -I dts -O dtb -o overlay_base_with_aliases.dtb "$SRCDIR/overlay_base.dts" + run_test check_path overlay_base_with_aliases.dtb exists "/aliases" + run_test check_path overlay_base_with_aliases.dtb not-exists "/__symbols__" + run_test check_path overlay_base_with_aliases.dtb not-exists "/__fixups__" + run_test check_path overlay_base_with_aliases.dtb not-exists "/__local_fixups__" +} + +tree1_tests () { + TREE=$1 + + # Read-only tests + run_test get_mem_rsv $TREE + run_test root_node $TREE + run_test find_property $TREE + run_test subnode_offset $TREE + run_test path_offset $TREE + run_test get_name $TREE + run_test getprop $TREE + run_test get_prop_offset $TREE + run_test get_phandle $TREE + run_test get_path $TREE + run_test supernode_atdepth_offset $TREE + run_test parent_offset $TREE + run_test node_offset_by_prop_value $TREE + run_test node_offset_by_phandle $TREE + run_test node_check_compatible $TREE + run_test node_offset_by_compatible $TREE + run_test notfound $TREE + + # Write-in-place tests + run_test setprop_inplace $TREE + run_test nop_property $TREE + run_test nop_node $TREE +} + +tree1_tests_rw () { + TREE=$1 + + # Read-write tests + run_test set_name $TREE + run_test setprop $TREE + run_test del_property $TREE + run_test del_node $TREE +} + +check_tests () { + tree="$1" + shift + run_sh_test "$SRCDIR/dtc-checkfails.sh" "$@" -- -I dts -O dtb $tree + run_dtc_test -I dts -O dtb -o $tree.test.dtb -f $tree + run_sh_test "$SRCDIR/dtc-checkfails.sh" "$@" -- -I dtb -O dtb $tree.test.dtb +} + +ALL_LAYOUTS="mts mst tms tsm smt stm" + +libfdt_tests () { + tree1_tests test_tree1.dtb + + run_dtc_test -I dts -O dtb -o addresses.test.dtb "$SRCDIR/addresses.dts" + run_test addr_size_cells addresses.test.dtb + run_dtc_test -I dts -O dtb -o addresses2.test.dtb "$SRCDIR/empty.dts" + run_test addr_size_cells2 addresses2.test.dtb + + run_dtc_test -I dts -O dtb -o stringlist.test.dtb "$SRCDIR/stringlist.dts" + run_test stringlist stringlist.test.dtb + + for flags in default no_name_dedup; do + # Sequential write tests + run_test sw_tree1 fixed $flags + tree1_tests sw_tree1.test.dtb + tree1_tests unfinished_tree1.test.dtb + run_test dtbs_equal_ordered test_tree1.dtb sw_tree1.test.dtb + run_test sw_states + + # Resizing tests + for mode in resize realloc newalloc; do + run_test sw_tree1 $mode $flags + tree1_tests sw_tree1.test.dtb + tree1_tests unfinished_tree1.test.dtb + run_test dtbs_equal_ordered test_tree1.dtb sw_tree1.test.dtb + done + done + + # fdt_move tests + for tree in test_tree1.dtb sw_tree1.test.dtb unfinished_tree1.test.dtb; do + rm -f moved.$tree shunted.$tree deshunted.$tree + run_test move_and_save $tree + run_test dtbs_equal_ordered $tree moved.$tree + run_test dtbs_equal_ordered $tree shunted.$tree + run_test dtbs_equal_ordered $tree deshunted.$tree + done + + # v16 and alternate layout tests + for tree in test_tree1.dtb; do + for version in 17 16; do + for layout in $ALL_LAYOUTS; do + run_test mangle-layout $tree $version $layout + tree1_tests v$version.$layout.$tree + run_test dtbs_equal_ordered $tree v$version.$layout.$tree + done + done + done + + # Read-write tests + for basetree in test_tree1.dtb; do + for version in 17 16; do + for layout in $ALL_LAYOUTS; do + tree=v$version.$layout.$basetree + rm -f opened.$tree repacked.$tree + run_test open_pack $tree + tree1_tests opened.$tree + tree1_tests repacked.$tree + + tree1_tests_rw $tree + tree1_tests_rw opened.$tree + tree1_tests_rw repacked.$tree + done + done + done + run_test rw_tree1 + tree1_tests rw_tree1.test.dtb + tree1_tests_rw rw_tree1.test.dtb + run_test appendprop1 + run_test appendprop2 appendprop1.test.dtb + run_dtc_test -I dts -O dtb -o appendprop.test.dtb "$SRCDIR/appendprop.dts" + run_test dtbs_equal_ordered appendprop2.test.dtb appendprop.test.dtb + libfdt_overlay_tests + + for basetree in test_tree1.dtb sw_tree1.test.dtb rw_tree1.test.dtb; do + run_test nopulate $basetree + run_test dtbs_equal_ordered $basetree noppy.$basetree + tree1_tests noppy.$basetree + tree1_tests_rw noppy.$basetree + done + + run_test rw_oom + + run_dtc_test -I dts -O dtb -o subnode_iterate.dtb "$SRCDIR/subnode_iterate.dts" + run_test subnode_iterate subnode_iterate.dtb + + run_dtc_test -I dts -O dtb -o property_iterate.dtb "$SRCDIR/property_iterate.dts" + run_test property_iterate property_iterate.dtb + + run_dtc_test -I dts -O dtb -o unit-addr-without-reg.dtb "$SRCDIR/unit-addr-without-reg.dts" + run_test appendprop_addrrange unit-addr-without-reg.dtb 1 1 1 + run_test appendprop_addrrange unit-addr-without-reg.dtb 2 2 2 + run_test appendprop_addrrange unit-addr-without-reg.dtb 2 1 3 + + # Tests for behaviour on various sorts of corrupted trees + run_test truncated_property + run_test truncated_string + run_test truncated_memrsv + + # Check aliases support in fdt_path_offset + run_dtc_test -I dts -O dtb -o aliases.dtb "$SRCDIR/aliases.dts" + run_test get_alias aliases.dtb + run_test path_offset_aliases aliases.dtb + + # Specific bug tests + run_test add_subnode_with_nops + run_dtc_test -I dts -O dts -o sourceoutput.test.dts "$SRCDIR/sourceoutput.dts" + run_dtc_test -I dts -O dtb -o sourceoutput.test.dtb "$SRCDIR/sourceoutput.dts" + run_dtc_test -I dts -O dtb -o sourceoutput.test.dts.test.dtb sourceoutput.test.dts + run_test dtbs_equal_ordered sourceoutput.test.dtb sourceoutput.test.dts.test.dtb + + run_dtc_test -I dts -O dtb -o embedded_nul.test.dtb "$SRCDIR/embedded_nul.dts" + run_dtc_test -I dts -O dtb -o embedded_nul_equiv.test.dtb "$SRCDIR/embedded_nul_equiv.dts" + run_test dtbs_equal_ordered embedded_nul.test.dtb embedded_nul_equiv.test.dtb + + run_dtc_test -I dts -O dtb "$SRCDIR/bad-size-cells.dts" + + run_wrap_error_test $DTC division-by-zero.dts + run_wrap_error_test $DTC bad-octal-literal.dts + run_dtc_test -I dts -O dtb "$SRCDIR/nul-in-escape.dts" + run_wrap_error_test $DTC nul-in-line-info1.dts + run_wrap_error_test $DTC nul-in-line-info2.dts + + run_wrap_error_test $DTC -I dtb -O dts -o /dev/null ovf_size_strings.dtb + + run_test check_header test_tree1.dtb + + FSBASE=fs + rm -rf $FSBASE + mkdir -p $FSBASE + run_test fs_tree1 $FSBASE/test_tree1 + run_dtc_test -I fs -O dts -o fs.test_tree1.test.dts $FSBASE/test_tree1 + run_dtc_test -I fs -O dtb -o fs.test_tree1.test.dtb $FSBASE/test_tree1 + run_test dtbs_equal_unordered -m fs.test_tree1.test.dtb test_tree1.dtb + + # check full tests + for good in test_tree1.dtb; do + run_test check_full $good + done + for bad in truncated_property.dtb truncated_string.dtb \ + truncated_memrsv.dtb two_roots.dtb named_root.dtb; do + run_test check_full -n $bad + done +} + +dtc_tests () { + run_dtc_test -I dts -O dtb -o dtc_tree1.test.dtb "$SRCDIR/test_tree1.dts" + tree1_tests dtc_tree1.test.dtb + tree1_tests_rw dtc_tree1.test.dtb + run_test dtbs_equal_ordered dtc_tree1.test.dtb test_tree1.dtb + + run_dtc_test -I dts -O dtb -o dtc_escapes.test.dtb "$SRCDIR/propname_escapes.dts" + run_test propname_escapes dtc_escapes.test.dtb + + run_dtc_test -I dts -O dtb -o line_directives.test.dtb "$SRCDIR/line_directives.dts" + + run_dtc_test -I dts -O dtb -o dtc_escapes.test.dtb "$SRCDIR/escapes.dts" + run_test string_escapes dtc_escapes.test.dtb + + run_dtc_test -I dts -O dtb -o dtc_char_literal.test.dtb "$SRCDIR/char_literal.dts" + run_test char_literal dtc_char_literal.test.dtb + + run_dtc_test -I dts -O dtb -o dtc_sized_cells.test.dtb "$SRCDIR/sized_cells.dts" + run_test sized_cells dtc_sized_cells.test.dtb + + run_dtc_test -I dts -O dtb -o dtc_extra-terminating-null.test.dtb "$SRCDIR/extra-terminating-null.dts" + run_test extra-terminating-null dtc_extra-terminating-null.test.dtb + + run_dtc_test -I dts -O dtb -o dtc_references.test.dtb "$SRCDIR/references.dts" + run_test references dtc_references.test.dtb + + run_dtc_test -I dts -O dtb -o dtc_path-references.test.dtb "$SRCDIR/path-references.dts" + run_test path-references dtc_path-references.test.dtb + + run_test phandle_format dtc_references.test.dtb epapr + for f in legacy epapr both; do + run_dtc_test -I dts -O dtb -H $f -o dtc_references.test.$f.dtb "$SRCDIR/references.dts" + run_test phandle_format dtc_references.test.$f.dtb $f + done + + run_dtc_test -I dts -O dtb -o multilabel.test.dtb "$SRCDIR/multilabel.dts" + run_test references multilabel.test.dtb + + run_dtc_test -I dts -O dtb -o label_repeated.test.dtb "$SRCDIR/label_repeated.dts" + + run_dtc_test -I dts -O dtb -o dtc_comments.test.dtb "$SRCDIR/comments.dts" + run_dtc_test -I dts -O dtb -o dtc_comments-cmp.test.dtb "$SRCDIR/comments-cmp.dts" + run_test dtbs_equal_ordered dtc_comments.test.dtb dtc_comments-cmp.test.dtb + + # Check /include/ directive + run_dtc_test -I dts -O dtb -o includes.test.dtb "$SRCDIR/include0.dts" + run_test dtbs_equal_ordered includes.test.dtb test_tree1.dtb + + # Check /incbin/ directive + run_dtc_test -I dts -O dtb -o incbin.test.dtb "$SRCDIR/incbin.dts" + run_test incbin "$SRCDIR/incbin.bin" incbin.test.dtb + + # Check boot_cpuid_phys handling + run_dtc_test -I dts -O dtb -o boot_cpuid.test.dtb "$SRCDIR/boot-cpuid.dts" + run_test boot-cpuid boot_cpuid.test.dtb 16 + + run_dtc_test -I dts -O dtb -b 17 -o boot_cpuid_17.test.dtb "$SRCDIR/boot-cpuid.dts" + run_test boot-cpuid boot_cpuid_17.test.dtb 17 + + run_dtc_test -I dtb -O dtb -o preserve_boot_cpuid.test.dtb boot_cpuid.test.dtb + run_test boot-cpuid preserve_boot_cpuid.test.dtb 16 + run_test dtbs_equal_ordered preserve_boot_cpuid.test.dtb boot_cpuid.test.dtb + + run_dtc_test -I dtb -O dtb -o preserve_boot_cpuid_17.test.dtb boot_cpuid_17.test.dtb + run_test boot-cpuid preserve_boot_cpuid_17.test.dtb 17 + run_test dtbs_equal_ordered preserve_boot_cpuid_17.test.dtb boot_cpuid_17.test.dtb + + run_dtc_test -I dtb -O dtb -b17 -o override17_boot_cpuid.test.dtb boot_cpuid.test.dtb + run_test boot-cpuid override17_boot_cpuid.test.dtb 17 + + run_dtc_test -I dtb -O dtb -b0 -o override0_boot_cpuid_17.test.dtb boot_cpuid_17.test.dtb + run_test boot-cpuid override0_boot_cpuid_17.test.dtb 0 + + + # Check -Oasm mode + for tree in test_tree1.dts escapes.dts references.dts path-references.dts \ + comments.dts aliases.dts include0.dts incbin.dts \ + value-labels.dts ; do + run_dtc_test -I dts -O asm -o oasm_$tree.test.s "$SRCDIR/$tree" + asm_to_so_test oasm_$tree + run_dtc_test -I dts -O dtb -o $tree.test.dtb "$SRCDIR/$tree" + run_test asm_tree_dump ./oasm_$tree.test.so oasm_$tree.test.dtb + run_wrap_test cmp oasm_$tree.test.dtb $tree.test.dtb + done + + run_test value-labels ./oasm_value-labels.dts.test.so + + # Check -Odts mode preserve all dtb information + for tree in test_tree1.dtb dtc_tree1.test.dtb dtc_escapes.test.dtb \ + dtc_extra-terminating-null.test.dtb dtc_references.test.dtb; do + run_dtc_test -I dtb -O dts -o odts_$tree.test.dts $tree + run_dtc_test -I dts -O dtb -o odts_$tree.test.dtb odts_$tree.test.dts + run_test dtbs_equal_ordered $tree odts_$tree.test.dtb + done + + # Check -Odts preserving type information + for tree in type-preservation.dts; do + run_dtc_test -I dts -O dts -o $tree.test.dts "$SRCDIR/$tree" + run_dtc_test -I dts -O dts $tree.test.dts + run_wrap_test cmp "$SRCDIR/$tree" $tree.test.dts + done + for tree in path-references; do + run_dtc_test -I dts -O dtb -o $tree.test.dtb "$SRCDIR/$tree.dts" + run_dtc_test -I dts -O dts -o $tree.test.dts "$SRCDIR/$tree.dts" + run_dtc_test -I dts -O dtb -o $tree.test.dts.test.dtb $tree.test.dts + run_test dtbs_equal_ordered $tree.test.dtb $tree.test.dts.test.dtb + done + + # Check -Oyaml output + if ! $no_yaml; then + for tree in type-preservation; do + run_dtc_test -I dts -O yaml -o $tree.test.dt.yaml "$SRCDIR/$tree.dts" + run_wrap_test cmp "$SRCDIR/$tree.dt.yaml" $tree.test.dt.yaml + done + fi + + # Check version conversions + for tree in test_tree1.dtb ; do + for aver in 1 2 3 16 17; do + atree="ov${aver}_$tree.test.dtb" + run_dtc_test -I dtb -O dtb -V$aver -o $atree $tree + for bver in 16 17; do + btree="ov${bver}_$atree" + run_dtc_test -I dtb -O dtb -V$bver -o $btree $atree + run_test dtbs_equal_ordered $btree $tree + done + done + done + + # Check merge/overlay functionality + run_dtc_test -I dts -O dtb -o dtc_tree1_merge.test.dtb "$SRCDIR/test_tree1_merge.dts" + tree1_tests dtc_tree1_merge.test.dtb test_tree1.dtb + run_dtc_test -I dts -O dtb -o dtc_tree1_merge_labelled.test.dtb "$SRCDIR/test_tree1_merge_labelled.dts" + tree1_tests dtc_tree1_merge_labelled.test.dtb test_tree1.dtb + run_dtc_test -I dts -O dtb -o dtc_tree1_label_noderef.test.dtb "$SRCDIR/test_tree1_label_noderef.dts" + run_test dtbs_equal_unordered dtc_tree1_label_noderef.test.dtb test_tree1.dtb + run_dtc_test -I dts -O dtb -o multilabel_merge.test.dtb "$SRCDIR/multilabel_merge.dts" + run_test references multilabel.test.dtb + run_test dtbs_equal_ordered multilabel.test.dtb multilabel_merge.test.dtb + run_dtc_test -I dts -O dtb -o dtc_tree1_merge_path.test.dtb "$SRCDIR/test_tree1_merge_path.dts" + tree1_tests dtc_tree1_merge_path.test.dtb test_tree1.dtb + run_wrap_error_test $DTC -I dts -O dtb -o /dev/null "$SRCDIR/test_label_ref.dts" + + # Check prop/node delete functionality + run_dtc_test -I dts -O dtb -o dtc_tree1_delete.test.dtb "$SRCDIR/test_tree1_delete.dts" + tree1_tests dtc_tree1_delete.test.dtb + + # Check omit-if-no-ref functionality + run_dtc_test -I dts -O dtb -o omit-no-ref.test.dtb "$SRCDIR/omit-no-ref.dts" + run_test check_path omit-no-ref.test.dtb not-exists "/node1" + run_test check_path omit-no-ref.test.dtb not-exists "/node2" + run_test check_path omit-no-ref.test.dtb exists "/node3" + run_test check_path omit-no-ref.test.dtb exists "/node4" + + run_dtc_test -I dts -O dts -o delete_reinstate_multilabel.dts.test.dts "$SRCDIR/delete_reinstate_multilabel.dts" + run_wrap_test cmp delete_reinstate_multilabel.dts.test.dts "$SRCDIR/delete_reinstate_multilabel_ref.dts" + + # Check some checks + check_tests "$SRCDIR/dup-nodename.dts" duplicate_node_names + check_tests "$SRCDIR/dup-propname.dts" duplicate_property_names + check_tests "$SRCDIR/dup-phandle.dts" explicit_phandles + check_tests "$SRCDIR/zero-phandle.dts" explicit_phandles + check_tests "$SRCDIR/minusone-phandle.dts" explicit_phandles + run_sh_test "$SRCDIR/dtc-checkfails.sh" phandle_references -- -I dts -O dtb "$SRCDIR/nonexist-node-ref.dts" + run_sh_test "$SRCDIR/dtc-checkfails.sh" phandle_references -- -I dts -O dtb "$SRCDIR/nonexist-label-ref.dts" + run_sh_test "$SRCDIR/dtc-fatal.sh" -I dts -O dtb "$SRCDIR/nonexist-node-ref2.dts" + check_tests "$SRCDIR/bad-name-property.dts" name_properties + + check_tests "$SRCDIR/bad-ncells.dts" address_cells_is_cell size_cells_is_cell interrupts_extended_is_cell + check_tests "$SRCDIR/bad-string-props.dts" device_type_is_string model_is_string status_is_string label_is_string compatible_is_string_list names_is_string_list + check_tests "$SRCDIR/bad-chosen.dts" chosen_node_is_root + check_tests "$SRCDIR/bad-chosen.dts" chosen_node_bootargs + check_tests "$SRCDIR/bad-chosen.dts" chosen_node_stdout_path + check_tests "$SRCDIR/bad-reg-ranges.dts" reg_format ranges_format + check_tests "$SRCDIR/bad-empty-ranges.dts" ranges_format + check_tests "$SRCDIR/reg-ranges-root.dts" reg_format ranges_format + check_tests "$SRCDIR/bad-dma-ranges.dts" dma_ranges_format + check_tests "$SRCDIR/default-addr-size.dts" avoid_default_addr_size + check_tests "$SRCDIR/obsolete-chosen-interrupt-controller.dts" obsolete_chosen_interrupt_controller + check_tests "$SRCDIR/reg-without-unit-addr.dts" unit_address_vs_reg + check_tests "$SRCDIR/unit-addr-without-reg.dts" unit_address_vs_reg + check_tests "$SRCDIR/unit-addr-leading-0x.dts" unit_address_format + check_tests "$SRCDIR/unit-addr-leading-0s.dts" unit_address_format + check_tests "$SRCDIR/unit-addr-unique.dts" unique_unit_address + check_tests "$SRCDIR/bad-phandle-cells.dts" interrupts_extended_property + check_tests "$SRCDIR/bad-gpio.dts" gpios_property + check_tests "$SRCDIR/good-gpio.dts" -n gpios_property + check_tests "$SRCDIR/bad-graph.dts" graph_child_address + check_tests "$SRCDIR/bad-graph.dts" graph_port + check_tests "$SRCDIR/bad-graph.dts" graph_endpoint + run_sh_test "$SRCDIR/dtc-checkfails.sh" deprecated_gpio_property -- -Wdeprecated_gpio_property -I dts -O dtb "$SRCDIR/bad-gpio.dts" + run_sh_test "$SRCDIR/dtc-checkfails.sh" -n deprecated_gpio_property -- -Wdeprecated_gpio_property -I dts -O dtb "$SRCDIR/good-gpio.dts" + check_tests "$SRCDIR/bad-interrupt-cells.dts" interrupts_property + check_tests "$SRCDIR/bad-interrupt-controller.dts" interrupt_provider + run_sh_test "$SRCDIR/dtc-checkfails.sh" node_name_chars -- -I dtb -O dtb bad_node_char.dtb + run_sh_test "$SRCDIR/dtc-checkfails.sh" node_name_format -- -I dtb -O dtb bad_node_format.dtb + run_sh_test "$SRCDIR/dtc-checkfails.sh" property_name_chars -- -I dtb -O dtb bad_prop_char.dtb + + run_sh_test "$SRCDIR/dtc-checkfails.sh" duplicate_label -- -I dts -O dtb "$SRCDIR/reuse-label1.dts" + run_sh_test "$SRCDIR/dtc-checkfails.sh" duplicate_label -- -I dts -O dtb "$SRCDIR/reuse-label2.dts" + run_sh_test "$SRCDIR/dtc-checkfails.sh" duplicate_label -- -I dts -O dtb "$SRCDIR/reuse-label3.dts" + run_sh_test "$SRCDIR/dtc-checkfails.sh" duplicate_label -- -I dts -O dtb "$SRCDIR/reuse-label4.dts" + run_sh_test "$SRCDIR/dtc-checkfails.sh" duplicate_label -- -I dts -O dtb "$SRCDIR/reuse-label5.dts" + run_sh_test "$SRCDIR/dtc-checkfails.sh" duplicate_label -- -I dts -O dtb "$SRCDIR/reuse-label6.dts" + + run_test check_path test_tree1.dtb exists "/subnode@1" + run_test check_path test_tree1.dtb not-exists "/subnode@10" + + check_tests "$SRCDIR/pci-bridge-ok.dts" -n pci_bridge + check_tests "$SRCDIR/pci-bridge-bad1.dts" pci_bridge + check_tests "$SRCDIR/pci-bridge-bad2.dts" pci_bridge + + check_tests "$SRCDIR/unit-addr-simple-bus-reg-mismatch.dts" simple_bus_reg + check_tests "$SRCDIR/unit-addr-simple-bus-compatible.dts" simple_bus_reg + + + # Check warning options + run_sh_test "$SRCDIR/dtc-checkfails.sh" address_cells_is_cell interrupts_extended_is_cell -n size_cells_is_cell -- -Wno_size_cells_is_cell -I dts -O dtb "$SRCDIR/bad-ncells.dts" + run_sh_test "$SRCDIR/dtc-fails.sh" -n test-warn-output.test.dtb -I dts -O dtb "$SRCDIR/bad-ncells.dts" + run_sh_test "$SRCDIR/dtc-fails.sh" test-error-output.test.dtb -I dts -O dtb bad-ncells.dts -Esize_cells_is_cell + run_sh_test "$SRCDIR/dtc-checkfails.sh" always_fail -- -Walways_fail -I dts -O dtb "$SRCDIR/test_tree1.dts" + run_sh_test "$SRCDIR/dtc-checkfails.sh" -n always_fail -- -Walways_fail -Wno_always_fail -I dts -O dtb "$SRCDIR/test_tree1.dts" + run_sh_test "$SRCDIR/dtc-fails.sh" test-negation-1.test.dtb -Ealways_fail -I dts -O dtb "$SRCDIR/test_tree1.dts" + run_sh_test "$SRCDIR/dtc-fails.sh" -n test-negation-2.test.dtb -Ealways_fail -Eno_always_fail -I dts -O dtb "$SRCDIR/test_tree1.dts" + run_sh_test "$SRCDIR/dtc-fails.sh" test-negation-3.test.dtb -Ealways_fail -Wno_always_fail -I dts -O dtb "$SRCDIR/test_tree1.dts" + run_sh_test "$SRCDIR/dtc-fails.sh" -n test-negation-4.test.dtb -Esize_cells_is_cell -Eno_size_cells_is_cell -I dts -O dtb "$SRCDIR/bad-ncells.dts" + run_sh_test "$SRCDIR/dtc-checkfails.sh" size_cells_is_cell -- -Esize_cells_is_cell -Eno_size_cells_is_cell -I dts -O dtb "$SRCDIR/bad-ncells.dts" + + # Check for proper behaviour reading from stdin + run_dtc_test -I dts -O dtb -o stdin_dtc_tree1.test.dtb - < "$SRCDIR/test_tree1.dts" + run_wrap_test cmp stdin_dtc_tree1.test.dtb dtc_tree1.test.dtb + run_dtc_test -I dtb -O dts -o stdin_odts_test_tree1.dtb.test.dts - < test_tree1.dtb + run_wrap_test cmp stdin_odts_test_tree1.dtb.test.dts odts_test_tree1.dtb.test.dts + + # Check integer expresisons + run_test integer-expressions -g integer-expressions.test.dts + run_dtc_test -I dts -O dtb -o integer-expressions.test.dtb integer-expressions.test.dts + run_test integer-expressions integer-expressions.test.dtb + + # Check for graceful failure in some error conditions + run_sh_test "$SRCDIR/dtc-fatal.sh" -I dts -O dtb nosuchfile.dts + run_sh_test "$SRCDIR/dtc-fatal.sh" -I dtb -O dtb nosuchfile.dtb + run_sh_test "$SRCDIR/dtc-fatal.sh" -I fs -O dtb nosuchfile + + # Dependencies + run_dtc_test -I dts -O dtb -o dependencies.test.dtb -d dependencies.test.d "$SRCDIR/dependencies.dts" + sed -i.bak "s,$SRCDIR/,,g" dependencies.test.d + run_wrap_test cmp dependencies.test.d "$SRCDIR/dependencies.cmp" + + # Search paths + run_wrap_error_test $DTC -I dts -O dtb -o search_paths.dtb "$SRCDIR/search_paths.dts" + run_dtc_test -i "$SRCDIR/search_dir" -I dts -O dtb -o search_paths.dtb \ + "$SRCDIR/search_paths.dts" + run_wrap_error_test $DTC -i "$SRCDIR/search_dir_b" -I dts -O dtb \ + -o search_paths_b.dtb "$SRCDIR/search_paths_b.dts" + run_dtc_test -i "$SRCDIR/search_dir_b" -i "$SRCDIR/search_dir" -I dts -O dtb \ + -o search_paths_b.dtb "$SRCDIR/search_paths_b.dts" + run_dtc_test -I dts -O dtb -o search_paths_subdir.dtb \ + "$SRCDIR/search_dir_b/search_paths_subdir.dts" + + # Check -a option + for align in 2 4 8 16 32 64; do + # -p -a + run_dtc_test -O dtb -p 1000 -a $align -o align0.dtb "$SRCDIR/subnode_iterate.dts" + base_run_test check_align align0.dtb $align + # -S -a + run_dtc_test -O dtb -S 1999 -a $align -o align1.dtb "$SRCDIR/subnode_iterate.dts" + base_run_test check_align align1.dtb $align + done + + # Tests for overlay/plugin generation + dtc_overlay_tests +} + +cmp_tests () { + basetree="$1" + shift + wrongtrees="$@" + + run_test dtb_reverse $basetree + + # First dtbs_equal_ordered + run_test dtbs_equal_ordered $basetree $basetree + run_test dtbs_equal_ordered -n $basetree $basetree.reversed.test.dtb + for tree in $wrongtrees; do + run_test dtbs_equal_ordered -n $basetree $tree + done + + # now unordered + run_test dtbs_equal_unordered $basetree $basetree + run_test dtbs_equal_unordered $basetree $basetree.reversed.test.dtb + run_test dtbs_equal_unordered $basetree.reversed.test.dtb $basetree + for tree in $wrongtrees; do + run_test dtbs_equal_unordered -n $basetree $tree + done + + # now dtc --sort + run_dtc_test -I dtb -O dtb -s -o $basetree.sorted.test.dtb $basetree + run_test dtbs_equal_unordered $basetree $basetree.sorted.test.dtb + run_dtc_test -I dtb -O dtb -s -o $basetree.reversed.sorted.test.dtb $basetree.reversed.test.dtb + run_test dtbs_equal_unordered $basetree.reversed.test.dtb $basetree.reversed.sorted.test.dtb + run_test dtbs_equal_ordered $basetree.sorted.test.dtb $basetree.reversed.sorted.test.dtb +} + +dtbs_equal_tests () { + WRONG_TREE1="" + for x in 1 2 3 4 5 6 7 8 9; do + run_dtc_test -I dts -O dtb -o test_tree1_wrong$x.test.dtb "$SRCDIR/test_tree1_wrong$x.dts" + WRONG_TREE1="$WRONG_TREE1 test_tree1_wrong$x.test.dtb" + done + cmp_tests test_tree1.dtb $WRONG_TREE1 +} + +fdtget_tests () { + dts=label01.dts + dtb=$dts.fdtget.test.dtb + run_dtc_test -O dtb -o $dtb "$SRCDIR/$dts" + + # run_fdtget_test <expected-result> [<flags>] <file> <node> <property> + run_fdtget_test "MyBoardName" $dtb / model + run_fdtget_test "MyBoardName MyBoardFamilyName" $dtb / compatible + run_fdtget_test "77 121 66 111 \ +97 114 100 78 97 109 101 0 77 121 66 111 97 114 100 70 97 109 105 \ +108 121 78 97 109 101 0" -t bu $dtb / compatible + run_fdtget_test "MyBoardName MyBoardFamilyName" -t s $dtb / compatible + run_fdtget_test 32768 $dtb /cpus/PowerPC,970@1 d-cache-size + run_fdtget_test 8000 -tx $dtb /cpus/PowerPC,970@1 d-cache-size + run_fdtget_test "61 62 63 0" -tbx $dtb /randomnode tricky1 + run_fdtget_test "a b c d de ea ad be ef" -tbx $dtb /randomnode blob + + # Here the property size is not a multiple of 4 bytes, so it should fail + run_wrap_error_test $DTGET -tlx $dtb /randomnode mixed + run_fdtget_test "6162 6300 1234 0 a 0 b 0 c" -thx $dtb /randomnode mixed + run_fdtget_test "61 62 63 0 12 34 0 0 0 a 0 0 0 b 0 0 0 c" \ + -thhx $dtb /randomnode mixed + run_wrap_error_test $DTGET -ts $dtb /randomnode doctor-who + + # Test multiple arguments + run_fdtget_test "MyBoardName\nmemory" -ts $dtb / model /memory device_type + + # Test defaults + run_wrap_error_test $DTGET -tx $dtb /randomnode doctor-who + run_fdtget_test "<the dead silence>" -tx \ + -d "<the dead silence>" $dtb /randomnode doctor-who + run_fdtget_test "<blink>" -tx -d "<blink>" $dtb /memory doctor-who +} + +fdtput_tests () { + dts=label01.dts + dtb=$dts.fdtput.test.dtb + text="$SRCDIR/lorem.txt" + + # Allow just enough space for $text + run_dtc_test -O dtb -p $($STATSZ $text) -o $dtb "$SRCDIR/$dts" + + # run_fdtput_test <expected-result> <file> <node> <property> <flags> <value> + run_fdtput_test "a_model" $dtb / model -ts "a_model" + run_fdtput_test "board1 board2" $dtb / compatible -ts board1 board2 + run_fdtput_test "board1 board2" $dtb / compatible -ts "board1 board2" + run_fdtput_test "32768" $dtb /cpus/PowerPC,970@1 d-cache-size "" "32768" + run_fdtput_test "8001" $dtb /cpus/PowerPC,970@1 d-cache-size -tx 0x8001 + run_fdtput_test "2 3 12" $dtb /randomnode tricky1 -tbi "02 003 12" + run_fdtput_test "a b c ea ad be ef" $dtb /randomnode blob \ + -tbx "a b c ea ad be ef" + run_fdtput_test "a0b0c0d deeaae ef000000" $dtb /randomnode blob \ + -tx "a0b0c0d deeaae ef000000" + run_fdtput_test "$(cat $text)" $dtb /randomnode blob -ts "$(cat $text)" + + # Test expansion of the blob when insufficient room for property + run_fdtput_test "$(cat $text $text)" $dtb /randomnode blob -ts "$(cat $text $text)" + + # Start again with a fresh dtb + run_dtc_test -O dtb -p $($STATSZ $text) -o $dtb "$SRCDIR/$dts" + + # Node creation + run_wrap_error_test $DTPUT $dtb -c /baldrick sod + run_wrap_test $DTPUT $dtb -c /chosen/son /chosen/daughter + run_fdtput_test "eva" $dtb /chosen/daughter name "" -ts "eva" + run_fdtput_test "adam" $dtb /chosen/son name "" -ts "adam" + + # Not allowed to create an existing node + run_wrap_error_test $DTPUT $dtb -c /chosen + run_wrap_error_test $DTPUT $dtb -c /chosen/son + + # Automatic node creation + run_wrap_test $DTPUT $dtb -cp /blackadder/the-second/turnip \ + /blackadder/the-second/potato + run_fdtput_test 1000 $dtb /blackadder/the-second/turnip cost "" 1000 + run_fdtput_test "fine wine" $dtb /blackadder/the-second/potato drink \ + "-ts" "fine wine" + run_wrap_test $DTPUT $dtb -p /you/are/drunk/sir/winston slurp -ts twice + + # Test expansion of the blob when insufficient room for a new node + run_wrap_test $DTPUT $dtb -cp "$(cat $text $text)/longish" + + # Allowed to create an existing node with -p + run_wrap_test $DTPUT $dtb -cp /chosen + run_wrap_test $DTPUT $dtb -cp /chosen/son + + # Start again with a fresh dtb + run_dtc_test -O dtb -p $($STATSZ $text) -o $dtb "$SRCDIR/$dts" + + # Node delete + run_wrap_test $DTPUT $dtb -c /chosen/node1 /chosen/node2 /chosen/node3 + run_fdtget_test "node3\nnode2\nnode1" $dtb -l /chosen + run_wrap_test $DTPUT $dtb -r /chosen/node1 /chosen/node2 + run_fdtget_test "node3" $dtb -l /chosen + + # Delete the non-existent node + run_wrap_error_test $DTPUT $dtb -r /non-existent/node + + # Property delete + run_fdtput_test "eva" $dtb /chosen/ name "" -ts "eva" + run_fdtput_test "016" $dtb /chosen/ age "" -ts "016" + run_fdtget_test "age\nname\nbootargs\nlinux,platform" $dtb -p /chosen + run_wrap_test $DTPUT $dtb -d /chosen/ name age + run_fdtget_test "bootargs\nlinux,platform" $dtb -p /chosen + + # Delete the non-existent property + run_wrap_error_test $DTPUT $dtb -d /chosen non-existent-prop + + # TODO: Add tests for verbose mode? +} + +utilfdt_tests () { + run_test utilfdt_test +} + +fdtdump_tests () { + run_fdtdump_test "$SRCDIR/fdtdump.dts" +} + +fdtoverlay_tests() { + base="$SRCDIR/overlay_base.dts" + basedtb=overlay_base.fdoverlay.test.dtb + overlay="$SRCDIR/overlay_overlay_manual_fixups.dts" + overlaydtb=overlay_overlay_manual_fixups.fdoverlay.test.dtb + targetdtb=target.fdoverlay.test.dtb + + run_dtc_test -@ -I dts -O dtb -o $basedtb $base + run_dtc_test -@ -I dts -O dtb -o $overlaydtb $overlay + + # test that the new property is installed + run_fdtoverlay_test foobar "/test-node" "test-str-property" "-ts" ${basedtb} ${targetdtb} ${overlaydtb} + + stacked_base="$SRCDIR/stacked_overlay_base.dts" + stacked_basedtb=stacked_overlay_base.fdtoverlay.test.dtb + stacked_bar="$SRCDIR/stacked_overlay_bar.dts" + stacked_bardtb=stacked_overlay_bar.fdtoverlay.test.dtb + stacked_baz="$SRCDIR/stacked_overlay_baz.dts" + stacked_bazdtb=stacked_overlay_baz.fdtoverlay.test.dtb + stacked_targetdtb=stacked_overlay_target.fdtoverlay.test.dtb + + run_dtc_test -@ -I dts -O dtb -o $stacked_basedtb $stacked_base + run_dtc_test -@ -I dts -O dtb -o $stacked_bardtb $stacked_bar + run_dtc_test -@ -I dts -O dtb -o $stacked_bazdtb $stacked_baz + + # test that baz correctly inserted the property + run_fdtoverlay_test baz "/foonode/barnode/baznode" "baz-property" "-ts" ${stacked_basedtb} ${stacked_targetdtb} ${stacked_bardtb} ${stacked_bazdtb} + + # test that bar and baz are correctly appended to __symbols__ + run_fdtoverlay_test "/foonode/barnode" "/__symbols__" "bar" "-ts" ${stacked_basedtb} ${stacked_targetdtb} ${stacked_bardtb} + run_fdtoverlay_test "/foonode/barnode/baznode" "/__symbols__" "baz" "-ts" ${stacked_basedtb} ${stacked_targetdtb} ${stacked_bardtb} ${stacked_bazdtb} + + overlay_long_path="$SRCDIR/overlay_overlay_long_path.dts" + overlay_long_pathdtb=overlay_overlay_long_path.fdoverlay.test.dtb + target_long_pathdtb=overlay_overlay_long_path_target.fdoverlay.test.dtb + run_dtc_test -@ -I dts -O dtb -o $overlay_long_pathdtb $overlay_long_path + + # test that fdtoverlay manages to apply overlays with long target path + run_fdtoverlay_test lpath "/test-node/sub-test-node/sub-test-node-with-very-long-target-path/test-0" "prop" "-ts" ${basedtb} ${target_long_pathdtb} ${overlay_long_pathdtb} + + # test adding a label to the root of a fragment + stacked_base_nolabel="$SRCDIR/stacked_overlay_base_nolabel.dts" + stacked_base_nolabeldtb=stacked_overlay_base_nolabel.test.dtb + stacked_addlabel="$SRCDIR/stacked_overlay_addlabel.dts" + stacked_addlabeldtb=stacked_overlay_addlabel.test.dtb + stacked_addlabel_targetdtb=stacked_overlay_target_nolabel.fdtoverlay.test.dtb + + run_dtc_test -@ -I dts -O dtb -o $stacked_base_nolabeldtb $stacked_base_nolabel + run_dtc_test -@ -I dts -O dtb -o $stacked_addlabeldtb $stacked_addlabel + + run_fdtoverlay_test baz "/foonode/barnode/baznode" "baz-property" "-ts" ${stacked_base_nolabeldtb} ${stacked_addlabel_targetdtb} ${stacked_addlabeldtb} ${stacked_bardtb} ${stacked_bazdtb} +} + +pylibfdt_tests () { + run_dtc_test -I dts -O dtb -o test_props.dtb "$SRCDIR/test_props.dts" + TMP=/tmp/tests.stderr.$$ + $PYTHON "$SRCDIR/pylibfdt_tests.py" -v 2> $TMP + + # Use the 'ok' message meaning the test passed, 'ERROR' meaning it failed + # and the summary line for total tests (e.g. 'Ran 17 tests in 0.002s'). + # We could add pass + fail to get total tests, but this provides a useful + # sanity check. + pass_count=$(grep "ok$" $TMP | wc -l) + fail_count=$(grep "^ERROR: " $TMP | wc -l) + total_tests=$(sed -n 's/^Ran \([0-9]*\) tests.*$/\1/p' $TMP) + cat $TMP + rm $TMP + + # Extract the test results and add them to our totals + tot_fail=$((tot_fail + $fail_count)) + tot_pass=$((tot_pass + $pass_count)) + tot_tests=$((tot_tests + $total_tests)) +} + +while getopts "vt:me" ARG ; do + case $ARG in + "v") + unset QUIET_TEST + ;; + "t") + TESTSETS=$OPTARG + ;; + "m") + VALGRIND="valgrind --tool=memcheck -q --error-exitcode=$VGCODE" + ;; + "e") + STOP_ON_FAIL=1 + ;; + esac +done + +if [ -z "$TESTSETS" ]; then + TESTSETS="libfdt utilfdt dtc dtbs_equal fdtget fdtput fdtdump fdtoverlay" + + # Test pylibfdt if the libfdt Python module is available. + if ! $no_python; then + TESTSETS="$TESTSETS pylibfdt" + fi +fi + +# Make sure we don't have stale blobs lying around +rm -f *.test.dtb *.test.dts + +for set in $TESTSETS; do + case $set in + "libfdt") + libfdt_tests + ;; + "utilfdt") + utilfdt_tests + ;; + "dtc") + dtc_tests + ;; + "dtbs_equal") + dtbs_equal_tests + ;; + "fdtget") + fdtget_tests + ;; + "fdtput") + fdtput_tests + ;; + "fdtdump") + fdtdump_tests + ;; + "pylibfdt") + pylibfdt_tests + ;; + "fdtoverlay") + fdtoverlay_tests + ;; + esac +done + +echo "********** TEST SUMMARY" +echo "* Total testcases: $tot_tests" +echo "* PASS: $tot_pass" +echo "* FAIL: $tot_fail" +echo "* Bad configuration: $tot_config" +if [ -n "$VALGRIND" ]; then + echo "* valgrind errors: $tot_vg" +fi +echo "* Strange test result: $tot_strange" +echo "**********" + +[ "$tot_tests" -eq "$tot_pass" ] || exit 1 diff --git a/dtc/tests/rw_oom.c b/dtc/tests/rw_oom.c new file mode 100644 index 000000000..39fc312a6 --- /dev/null +++ b/dtc/tests/rw_oom.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_nop_node() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +/* This is not derived programmatically. May require adjustment to changes. */ +#define SPACE 285 + +#define CHECK(code) \ + { \ + err = (code); \ + if (err) \ + FAIL(#code ": %s", fdt_strerror(err)); \ + } + +#define OFF_CHECK(off, code) \ + { \ + (off) = (code); \ + if (off < 0) \ + FAIL(#code ": %s", fdt_strerror(off)); \ + } + +int main(int argc, char *argv[]) +{ + void *fdt; + int err; + int offset, s1; + int strsize1, strsize2; + + /* + * Check OOM path, and check that property is cleaned up if it fails + * with OOM, rather than adding an orphan name. + * + * SW OOM is tested with the realloc/resize strategies. + */ + test_init(argc, argv); + + fdt = xmalloc(SPACE); + + /* First create empty tree with SW */ + CHECK(fdt_create_empty_tree(fdt, SPACE)); + + CHECK(fdt_add_mem_rsv(fdt, TEST_ADDR_1, TEST_SIZE_1)); + CHECK(fdt_add_mem_rsv(fdt, TEST_ADDR_2, TEST_SIZE_2)); + + CHECK(fdt_setprop_string(fdt, 0, "compatible", "test_oom")); + CHECK(fdt_setprop_u32(fdt, 0, "prop-int", TEST_VALUE_1)); + CHECK(fdt_setprop_u64(fdt, 0, "prop-int64", TEST_VALUE64_1)); + CHECK(fdt_setprop_string(fdt, 0, "prop-str", TEST_STRING_1)); + + OFF_CHECK(offset, fdt_add_subnode(fdt, 0, "subnode@1")); + s1 = offset; + + strsize1 = fdt_size_dt_strings(fdt); + err = fdt_setprop_string(fdt, s1, "unique", "subnode1"); + if (err != -FDT_ERR_NOSPACE) + FAIL("fdt_setprop_string(fdt, s1, \"compatible\", \"subnode1\"): %s", fdt_strerror(err)); + strsize2 = fdt_size_dt_strings(fdt); + + if (strsize1 != strsize2) + FAIL("fdt_setprop NOSPACE error failed to clean up allocated string\n"); + err = 0; + + /* Ensure we failed in the right place */ + CHECK(fdt_setprop_string(fdt, s1, "unique", "")); + + CHECK(fdt_pack(fdt)); + + PASS(); +} diff --git a/dtc/tests/rw_tree1.c b/dtc/tests/rw_tree1.c new file mode 100644 index 000000000..1fe2351fc --- /dev/null +++ b/dtc/tests/rw_tree1.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_nop_node() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +#define SPACE 65536 + +#define CHECK(code) \ + { \ + err = (code); \ + if (err) \ + FAIL(#code ": %s", fdt_strerror(err)); \ + } + +#define OFF_CHECK(off, code) \ + { \ + (off) = (code); \ + if (off < 0) \ + FAIL(#code ": %s", fdt_strerror(off)); \ + } + +int main(int argc, char *argv[]) +{ + void *fdt; + int err; + int offset, s1, s2; + + test_init(argc, argv); + + fdt = xmalloc(SPACE); + + /* First create empty tree with SW */ + CHECK(fdt_create_empty_tree(fdt, SPACE)); + + CHECK(fdt_add_mem_rsv(fdt, TEST_ADDR_1, TEST_SIZE_1)); + CHECK(fdt_add_mem_rsv(fdt, TEST_ADDR_2, TEST_SIZE_2)); + + CHECK(fdt_setprop_string(fdt, 0, "compatible", "test_tree1")); + CHECK(fdt_setprop_u32(fdt, 0, "prop-int", TEST_VALUE_1)); + CHECK(fdt_setprop_u64(fdt, 0, "prop-int64", TEST_VALUE64_1)); + CHECK(fdt_setprop_string(fdt, 0, "prop-str", TEST_STRING_1)); + + OFF_CHECK(offset, fdt_add_subnode(fdt, 0, "subnode@1")); + s1 = offset; + CHECK(fdt_setprop_string(fdt, s1, "compatible", "subnode1")); + CHECK(fdt_setprop_cell(fdt, s1, "prop-int", TEST_VALUE_1)); + OFF_CHECK(offset, fdt_add_subnode(fdt, s1, "subsubnode")); + CHECK(fdt_setprop(fdt, offset, "compatible", + "subsubnode1\0subsubnode", 23)); + CHECK(fdt_setprop_cell(fdt, offset, "prop-int", TEST_VALUE_1)); + OFF_CHECK(offset, fdt_add_subnode(fdt, s1, "ss1")); + + OFF_CHECK(offset, fdt_add_subnode(fdt, 0, "subnode@2")); + s2 = offset; + CHECK(fdt_setprop_cell(fdt, s2, "linux,phandle", PHANDLE_1)); + CHECK(fdt_setprop_cell(fdt, s2, "prop-int", TEST_VALUE_2)); + OFF_CHECK(offset, fdt_add_subnode(fdt, s2, "subsubnode@0")); + CHECK(fdt_setprop_cell(fdt, offset, "linux,phandle", PHANDLE_2)); + CHECK(fdt_setprop(fdt, offset, "compatible", + "subsubnode2\0subsubnode", 23)); + CHECK(fdt_setprop_cell(fdt, offset, "prop-int", TEST_VALUE_2)); + OFF_CHECK(offset, fdt_add_subnode(fdt, s2, "ss2")); + + CHECK(fdt_pack(fdt)); + + save_blob("rw_tree1.test.dtb", fdt); + + PASS(); +} diff --git a/dtc/tests/search_dir/search_test.dtsi b/dtc/tests/search_dir/search_test.dtsi new file mode 100644 index 000000000..217fb80a8 --- /dev/null +++ b/dtc/tests/search_dir/search_test.dtsi @@ -0,0 +1,4 @@ +/include/ "search_test2.dtsi" + +/ { +}; diff --git a/dtc/tests/search_dir/search_test2.dtsi b/dtc/tests/search_dir/search_test2.dtsi new file mode 100644 index 000000000..7b9099e5c --- /dev/null +++ b/dtc/tests/search_dir/search_test2.dtsi @@ -0,0 +1,3 @@ + +/ { +}; diff --git a/dtc/tests/search_dir_b/search_paths_subdir.dts b/dtc/tests/search_dir_b/search_paths_subdir.dts new file mode 100644 index 000000000..5c5c9622c --- /dev/null +++ b/dtc/tests/search_dir_b/search_paths_subdir.dts @@ -0,0 +1,6 @@ +/dts-v1/; + +/include/ "search_test_c.dtsi" + +/ { +}; diff --git a/dtc/tests/search_dir_b/search_test_b.dtsi b/dtc/tests/search_dir_b/search_test_b.dtsi new file mode 100644 index 000000000..b06a7d6ec --- /dev/null +++ b/dtc/tests/search_dir_b/search_test_b.dtsi @@ -0,0 +1,4 @@ +/include/ "search_test_b2.dtsi" + +/ { +}; diff --git a/dtc/tests/search_dir_b/search_test_b2.dtsi b/dtc/tests/search_dir_b/search_test_b2.dtsi new file mode 100644 index 000000000..2526b43d6 --- /dev/null +++ b/dtc/tests/search_dir_b/search_test_b2.dtsi @@ -0,0 +1,5 @@ + +/include/ "search_test.dtsi" + +/ { +}; diff --git a/dtc/tests/search_dir_b/search_test_c.dtsi b/dtc/tests/search_dir_b/search_test_c.dtsi new file mode 100644 index 000000000..336d7a250 --- /dev/null +++ b/dtc/tests/search_dir_b/search_test_c.dtsi @@ -0,0 +1,2 @@ +/ { +}; diff --git a/dtc/tests/search_paths.dts b/dtc/tests/search_paths.dts new file mode 100644 index 000000000..a2bf179e5 --- /dev/null +++ b/dtc/tests/search_paths.dts @@ -0,0 +1,6 @@ +/dts-v1/; + +/include/ "search_test.dtsi" + +/ { +}; diff --git a/dtc/tests/search_paths_b.dts b/dtc/tests/search_paths_b.dts new file mode 100644 index 000000000..6ace6e24d --- /dev/null +++ b/dtc/tests/search_paths_b.dts @@ -0,0 +1,6 @@ +/dts-v1/; + +/include/ "search_test_b.dtsi" + +/ { +}; diff --git a/dtc/tests/set_name.c b/dtc/tests/set_name.c new file mode 100644 index 000000000..a62cb5874 --- /dev/null +++ b/dtc/tests/set_name.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_set_name() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static void check_set_name(void *fdt, const char *path, const char *newname) +{ + int offset; + const char *getname, *oldname; + int len, err; + + oldname = strrchr(path, '/'); + if (!oldname) + TEST_BUG(); + oldname += 1; + + offset = fdt_path_offset(fdt, path); + if (offset < 0) + FAIL("Couldn't find %s", path); + + getname = fdt_get_name(fdt, offset, &len); + verbose_printf("fdt_get_name(%d) returns \"%s\" (len=%d)\n", + offset, getname, len); + if (!getname) + FAIL("fdt_get_name(%d): %s", offset, fdt_strerror(len)); + + if (strcmp(getname, oldname) != 0) + FAIL("fdt_get_name(%s) returned \"%s\" instead of \"%s\"", + path, getname, oldname); + + if (len != strlen(getname)) + FAIL("fdt_get_name(%s) returned length %d instead of %zd", + path, len, strlen(getname)); + + err = fdt_set_name(fdt, offset, newname); + if (err) + FAIL("fdt_set_name(%d, \"%s\"): %s", offset, newname, + fdt_strerror(err)); + + getname = fdt_get_name(fdt, offset, &len); + if (!getname) + FAIL("fdt_get_name(%d): %s", offset, fdt_strerror(len)); + + if (strcmp(getname, newname) != 0) + FAIL("fdt_get_name(%s) returned \"%s\" instead of \"%s\"", + path, getname, newname); + + if (len != strlen(getname)) + FAIL("fdt_get_name(%s) returned length %d instead of %zd", + path, len, strlen(getname)); +} + +int main(int argc, char *argv[]) +{ + void *fdt; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + fdt = open_blob_rw(fdt); + + check_set_name(fdt, "/subnode@1", "subnode@17"); + check_set_name(fdt, "/subnode@2/subsubnode@0", "fred@0"); + check_set_name(fdt, "/subnode@17/subsubnode", "something@0"); + + PASS(); +} diff --git a/dtc/tests/setprop.c b/dtc/tests/setprop.c new file mode 100644 index 000000000..fa3938da7 --- /dev/null +++ b/dtc/tests/setprop.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_setprop() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +#define SPACE 65536 +#define NEW_STRING "here is quite a long test string, blah blah blah" + +int main(int argc, char *argv[]) +{ + void *fdt; + void *buf; + const uint32_t *intp; + const char *strp; + int err; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + buf = xmalloc(SPACE); + + err = fdt_open_into(fdt, buf, SPACE); + if (err) + FAIL("fdt_open_into(): %s", fdt_strerror(err)); + + fdt = buf; + + intp = check_getprop_cell(fdt, 0, "prop-int", TEST_VALUE_1); + + verbose_printf("Old int value was 0x%08x\n", *intp); + err = fdt_setprop_string(fdt, 0, "prop-int", NEW_STRING); + if (err) + FAIL("Failed to set \"prop-int\" to \"%s\": %s", + NEW_STRING, fdt_strerror(err)); + + strp = check_getprop_string(fdt, 0, "prop-int", NEW_STRING); + verbose_printf("New value is \"%s\"\n", strp); + + strp = check_getprop(fdt, 0, "prop-str", strlen(TEST_STRING_1)+1, + TEST_STRING_1); + + verbose_printf("Old string value was \"%s\"\n", strp); + err = fdt_setprop_empty(fdt, 0, "prop-str"); + if (err) + FAIL("Failed to empty \"prop-str\": %s", + fdt_strerror(err)); + + check_getprop(fdt, 0, "prop-str", 0, NULL); + + err = fdt_setprop_u32(fdt, 0, "prop-u32", TEST_VALUE_2); + if (err) + FAIL("Failed to set \"prop-u32\" to 0x%08x: %s", + TEST_VALUE_2, fdt_strerror(err)); + check_getprop_cell(fdt, 0, "prop-u32", TEST_VALUE_2); + + err = fdt_setprop_cell(fdt, 0, "prop-cell", TEST_VALUE_2); + if (err) + FAIL("Failed to set \"prop-cell\" to 0x%08x: %s", + TEST_VALUE_2, fdt_strerror(err)); + check_getprop_cell(fdt, 0, "prop-cell", TEST_VALUE_2); + + err = fdt_setprop_u64(fdt, 0, "prop-u64", TEST_VALUE64_1); + if (err) + FAIL("Failed to set \"prop-u64\" to 0x%016llx: %s", + TEST_VALUE64_1, fdt_strerror(err)); + check_getprop_64(fdt, 0, "prop-u64", TEST_VALUE64_1); + + PASS(); +} diff --git a/dtc/tests/setprop_inplace.c b/dtc/tests/setprop_inplace.c new file mode 100644 index 000000000..7e1198d3e --- /dev/null +++ b/dtc/tests/setprop_inplace.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_setprop_inplace() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#include <inttypes.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +int main(int argc, char *argv[]) +{ + void *fdt; + const uint32_t *intp; + const uint64_t *int64p; + const char *strp; + char *xstr; + int xlen, i; + int err; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + intp = check_getprop_cell(fdt, 0, "prop-int", TEST_VALUE_1); + + verbose_printf("Old int value was 0x%08x\n", *intp); + err = fdt_setprop_inplace_cell(fdt, 0, "prop-int", ~TEST_VALUE_1); + if (err) + FAIL("Failed to set \"prop-int\" to 0x%08x: %s", + ~TEST_VALUE_1, fdt_strerror(err)); + intp = check_getprop_cell(fdt, 0, "prop-int", ~TEST_VALUE_1); + verbose_printf("New int value is 0x%08x\n", *intp); + + strp = check_getprop(fdt, 0, "prop-str", strlen(TEST_STRING_1)+1, + TEST_STRING_1); + + + int64p = check_getprop_64(fdt, 0, "prop-int64", TEST_VALUE64_1); + + verbose_printf("Old int64 value was 0x%016" PRIx64 "\n", *int64p); + err = fdt_setprop_inplace_u64(fdt, 0, "prop-int64", ~TEST_VALUE64_1); + if (err) + FAIL("Failed to set \"prop-int64\" to 0x%016llx: %s", + ~TEST_VALUE64_1, fdt_strerror(err)); + int64p = check_getprop_64(fdt, 0, "prop-int64", ~TEST_VALUE64_1); + verbose_printf("New int64 value is 0x%016" PRIx64 "\n", *int64p); + + strp = check_getprop(fdt, 0, "prop-str", strlen(TEST_STRING_1)+1, + TEST_STRING_1); + + verbose_printf("Old string value was \"%s\"\n", strp); + xstr = strdup(strp); + xlen = strlen(xstr); + for (i = 0; i < xlen; i++) + xstr[i] = toupper(xstr[i]); + err = fdt_setprop_inplace(fdt, 0, "prop-str", xstr, xlen+1); + if (err) + FAIL("Failed to set \"prop-str\" to \"%s\": %s", + xstr, fdt_strerror(err)); + + strp = check_getprop(fdt, 0, "prop-str", xlen+1, xstr); + verbose_printf("New string value is \"%s\"\n", strp); + + err = fdt_setprop_inplace_namelen_partial(fdt, 0, "compatible", + strlen("compatible"), 4, + TEST_STRING_4_PARTIAL, + strlen(TEST_STRING_4_PARTIAL)); + if (err) + FAIL("Failed to set \"compatible\": %s\n", fdt_strerror(err)); + + check_getprop(fdt, 0, "compatible", strlen(TEST_STRING_4_RESULT) + 1, + TEST_STRING_4_RESULT); + + PASS(); +} diff --git a/dtc/tests/sized_cells.c b/dtc/tests/sized_cells.c new file mode 100644 index 000000000..9ca5a594e --- /dev/null +++ b/dtc/tests/sized_cells.c @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for variable sized cells in dtc + * Copyright (C) 2006 David Gibson, IBM Corporation. + * Copyright (C) 2011 The Chromium Authors. All rights reserved. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static void check_compare_properties(void *fdt, + char const *name_one, + char const *name_two) +{ + const void *propval; + int proplen; + + propval = fdt_getprop(fdt, 0, name_one, &proplen); + + if (!propval) + FAIL("fdt_getprop(\"%s\"): %s", + name_one, + fdt_strerror(proplen)); + + check_getprop(fdt, 0, name_two, proplen, propval); +} + +int main(int argc, char *argv[]) +{ + void *fdt; + uint8_t expected_8[6] = {TEST_CHAR1, + TEST_CHAR2, + TEST_CHAR3, + TEST_CHAR4, + TEST_CHAR5, + TEST_VALUE_1 >> 24}; + fdt16_t expected_16[6]; + fdt32_t expected_32[6]; + fdt64_t expected_64[6]; + int i; + + for (i = 0; i < 5; ++i) { + expected_16[i] = cpu_to_fdt16(expected_8[i]); + expected_32[i] = cpu_to_fdt32(expected_8[i]); + expected_64[i] = cpu_to_fdt64(expected_8[i]); + } + + expected_16[5] = cpu_to_fdt16(TEST_VALUE_1 >> 16); + expected_32[5] = cpu_to_fdt32(TEST_VALUE_1); + expected_64[5] = cpu_to_fdt64(TEST_ADDR_1); + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + check_getprop(fdt, 0, "cells-8b", sizeof(expected_8), expected_8); + check_getprop(fdt, 0, "cells-16b", sizeof(expected_16), expected_16); + check_getprop(fdt, 0, "cells-32b", sizeof(expected_32), expected_32); + check_getprop(fdt, 0, "cells-64b", sizeof(expected_64), expected_64); + + check_compare_properties(fdt, "cells-one-16b", "cells-one-32b"); + + PASS(); +} diff --git a/dtc/tests/sized_cells.dts b/dtc/tests/sized_cells.dts new file mode 100644 index 000000000..efea9f567 --- /dev/null +++ b/dtc/tests/sized_cells.dts @@ -0,0 +1,11 @@ +/dts-v1/; + +/ { + cells-8b = /bits/ 8 <'\r' 'b' '\0' '\'' '\xff' 0xde>; + cells-16b = /bits/ 16 <'\r' 'b' '\0' '\'' '\xff' 0xdead>; + cells-32b = /bits/ 32 <'\r' 'b' '\0' '\'' '\xff' 0xdeadbeef>; + cells-64b = /bits/ 64 <'\r' 'b' '\0' '\'' '\xff' 0xdeadbeef00000000>; + + cells-one-16b = /bits/ 16 <0x1234 0x5678 0x0 0xffff>; + cells-one-32b = <0x12345678 0x0000ffff>; +}; diff --git a/dtc/tests/sourceoutput.dts b/dtc/tests/sourceoutput.dts new file mode 100644 index 000000000..5a7459bff --- /dev/null +++ b/dtc/tests/sourceoutput.dts @@ -0,0 +1,14 @@ +/dts-v1/; + +/ { + /* Some versions had an off-by-2 bug which caused an abort + * when outputting labels within strings like this in source + * format */ + prop1: prop1 = start1: "foo", mid1: "bar" end1: ; + + /* Make sure that we correctly handle source output of things + * which could almost be expressed as strings, except for the + * embedded labels */ + prop2 = start2: [66 6f 6f], mid2: "bar" end2: ; +}; + diff --git a/dtc/tests/stacked_overlay_addlabel.dts b/dtc/tests/stacked_overlay_addlabel.dts new file mode 100644 index 000000000..e7187a36e --- /dev/null +++ b/dtc/tests/stacked_overlay_addlabel.dts @@ -0,0 +1,15 @@ +/dts-v1/; +/plugin/; +/ { + frag1: fragment@1 { + target-path = "/foonode"; + local: localinfo { + }; + foo: __overlay__ { + overlay-1-property; + bar: barnode { + bar-property = "bar"; + }; + }; + }; +}; diff --git a/dtc/tests/stacked_overlay_bar.dts b/dtc/tests/stacked_overlay_bar.dts new file mode 100644 index 000000000..c64639952 --- /dev/null +++ b/dtc/tests/stacked_overlay_bar.dts @@ -0,0 +1,13 @@ +/dts-v1/; +/plugin/; +/ { + fragment@1 { + target = <&foo>; + __overlay__ { + overlay-1-property; + bar: barnode { + bar-property = "bar"; + }; + }; + }; +}; diff --git a/dtc/tests/stacked_overlay_base.dts b/dtc/tests/stacked_overlay_base.dts new file mode 100644 index 000000000..29164230d --- /dev/null +++ b/dtc/tests/stacked_overlay_base.dts @@ -0,0 +1,6 @@ +/dts-v1/; +/ { + foo: foonode { + foo-property = "foo"; + }; +}; diff --git a/dtc/tests/stacked_overlay_base_nolabel.dts b/dtc/tests/stacked_overlay_base_nolabel.dts new file mode 100644 index 000000000..0c47f0ddc --- /dev/null +++ b/dtc/tests/stacked_overlay_base_nolabel.dts @@ -0,0 +1,6 @@ +/dts-v1/; +/ { + foonode { + foo-property = "foo"; + }; +}; diff --git a/dtc/tests/stacked_overlay_baz.dts b/dtc/tests/stacked_overlay_baz.dts new file mode 100644 index 000000000..a52f0cc60 --- /dev/null +++ b/dtc/tests/stacked_overlay_baz.dts @@ -0,0 +1,13 @@ +/dts-v1/; +/plugin/; +/ { + fragment@1 { + target = <&bar>; + __overlay__ { + overlay-2-property; + baz: baznode { + baz-property = "baz"; + }; + }; + }; +}; diff --git a/dtc/tests/string_escapes.c b/dtc/tests/string_escapes.c new file mode 100644 index 000000000..53c9dfc3d --- /dev/null +++ b/dtc/tests/string_escapes.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for string escapes in dtc + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +int main(int argc, char *argv[]) +{ + void *fdt; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + check_getprop(fdt, 0, "escape-str", + strlen(TEST_STRING_2)+1, TEST_STRING_2); + check_getprop(fdt, 0, "escape-str-2", + strlen(TEST_STRING_3)+1, TEST_STRING_3); + + PASS(); +} diff --git a/dtc/tests/stringlist.c b/dtc/tests/stringlist.c new file mode 100644 index 000000000..bbc302029 --- /dev/null +++ b/dtc/tests/stringlist.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for string handling + * Copyright (C) 2015 NVIDIA Corporation + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static void check_expected_failure(const void *fdt, const char *path, + const char *property) +{ + int offset, err; + + offset = fdt_path_offset(fdt, "/"); + if (offset < 0) + FAIL("Couldn't find path %s", path); + + err = fdt_stringlist_count(fdt, offset, "#address-cells"); + if (err != -FDT_ERR_BADVALUE) + FAIL("unexpectedly succeeded in parsing #address-cells\n"); + + err = fdt_stringlist_search(fdt, offset, "#address-cells", "foo"); + if (err != -FDT_ERR_BADVALUE) + FAIL("found string in #address-cells: %d\n", err); + + /* + * Note that the #address-cells property contains a small 32-bit + * unsigned integer, hence some bytes will be zero, and searching for + * the empty string will succeed. + * + * The reason for this oddity is that the function will exit when the + * first occurrence of the string is found, but in order to determine + * that the property does not contain a valid string list it would + * need to process the whole value. + */ + err = fdt_stringlist_search(fdt, offset, "#address-cells", ""); + if (err != 0) + FAIL("empty string not found in #address-cells: %d\n", err); + + /* + * fdt_getprop_string() can successfully extract strings from + * non-string properties. This is because it doesn't + * necessarily parse the whole property value, which would be + * necessary for it to determine if a valid string or string + * list is present. + */ +} + +static void check_string_count(const void *fdt, const char *path, + const char *property, int count) +{ + int offset, err; + + offset = fdt_path_offset(fdt, path); + if (offset < 0) + FAIL("Couldn't find path %s", path); + + err = fdt_stringlist_count(fdt, offset, property); + if (err < 0) + FAIL("Couldn't count strings in property %s of node %s: %d\n", + property, path, err); + + if (err != count) + FAIL("String count for property %s of node %s is %d instead of %d\n", + path, property, err, count); +} + +static void check_string_index(const void *fdt, const char *path, + const char *property, const char *string, + int idx) +{ + int offset, err; + + offset = fdt_path_offset(fdt, path); + if (offset < 0) + FAIL("Couldn't find path %s", path); + + err = fdt_stringlist_search(fdt, offset, property, string); + + if (err != idx) + FAIL("Index of %s in property %s of node %s is %d, expected %d\n", + string, property, path, err, idx); +} + +static void check_string(const void *fdt, const char *path, + const char *property, int idx, + const char *string) +{ + const char *result; + int offset, len; + + offset = fdt_path_offset(fdt, path); + if (offset < 0) + FAIL("Couldn't find path %s", path); + + result = fdt_stringlist_get(fdt, offset, property, idx, &len); + if (!result) + FAIL("Couldn't extract string %d from property %s of node %s: %d\n", + idx, property, path, len); + + if (strcmp(string, result) != 0) + FAIL("String %d in property %s of node %s is %s, expected %s\n", + idx, property, path, result, string); +} + +int main(int argc, char *argv[]) +{ + void *fdt; + + if (argc != 2) + CONFIG("Usage: %s <dtb file>\n", argv[0]); + + test_init(argc, argv); + fdt = load_blob(argv[1]); + + check_expected_failure(fdt, "/", "#address-cells"); + check_expected_failure(fdt, "/", "#size-cells"); + + check_string_count(fdt, "/", "compatible", 1); + check_string_count(fdt, "/device", "compatible", 2); + check_string_count(fdt, "/device", "big-endian", 0); + + check_string_index(fdt, "/", "compatible", "test-strings", 0); + check_string_index(fdt, "/device", "compatible", "foo", 0); + check_string_index(fdt, "/device", "compatible", "bar", 1); + check_string_index(fdt, "/device", "big-endian", "baz", -1); + + check_string(fdt, "/", "compatible", 0, "test-strings"); + check_string(fdt, "/device", "compatible", 0, "foo"); + check_string(fdt, "/device", "compatible", 1, "bar"); + + PASS(); +} diff --git a/dtc/tests/stringlist.dts b/dtc/tests/stringlist.dts new file mode 100644 index 000000000..1e4d31404 --- /dev/null +++ b/dtc/tests/stringlist.dts @@ -0,0 +1,12 @@ +/dts-v1/; + +/ { + compatible = "test-strings"; + #address-cells = <2>; + #size-cells = <2>; + + device { + compatible = "foo", "bar"; + big-endian; + }; +}; diff --git a/dtc/tests/subnode_iterate.c b/dtc/tests/subnode_iterate.c new file mode 100644 index 000000000..2dc9b2d35 --- /dev/null +++ b/dtc/tests/subnode_iterate.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Tests that fdt_next_subnode() works as expected + * + * Copyright (C) 2013 Google, Inc + * + * Copyright (C) 2007 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static void test_node(void *fdt, int parent_offset) +{ + uint32_t subnodes; + const fdt32_t *prop; + int offset; + int count; + int len; + + /* This property indicates the number of subnodes to expect */ + prop = fdt_getprop(fdt, parent_offset, "subnodes", &len); + if (!prop || len != sizeof(fdt32_t)) { + FAIL("Missing/invalid subnodes property at '%s'", + fdt_get_name(fdt, parent_offset, NULL)); + } + subnodes = fdt32_to_cpu(*prop); + + count = 0; + fdt_for_each_subnode(offset, fdt, parent_offset) + count++; + + if (count != subnodes) { + FAIL("Node '%s': Expected %d subnodes, got %d\n", + fdt_get_name(fdt, parent_offset, NULL), subnodes, + count); + } +} + +static void check_fdt_next_subnode(void *fdt) +{ + int offset; + int count = 0; + + fdt_for_each_subnode(offset, fdt, 0) { + test_node(fdt, offset); + count++; + } + + if (count != 2) + FAIL("Expected %d tests, got %d\n", 2, count); +} + +int main(int argc, char *argv[]) +{ + void *fdt; + + test_init(argc, argv); + if (argc != 2) + CONFIG("Usage: %s <dtb file>", argv[0]); + + fdt = load_blob(argv[1]); + if (!fdt) + FAIL("No device tree available"); + + check_fdt_next_subnode(fdt); + + PASS(); +} diff --git a/dtc/tests/subnode_iterate.dts b/dtc/tests/subnode_iterate.dts new file mode 100644 index 000000000..14a0d3aba --- /dev/null +++ b/dtc/tests/subnode_iterate.dts @@ -0,0 +1,44 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <0>; + + test1 { + subnodes = <2>; + linux,phandle = <0x1>; + #address-cells = <1>; + #size-cells = <0>; + PowerPC,970@0 { + name = "PowerPC,970"; + device_type = "cpu"; + reg = <0x00000000>; + clock-frequency = <1600000000>; + timebase-frequency = <33333333>; + linux,boot-cpu; + i-cache-size = <65536>; + d-cache-size = <32768>; + another-sub-node { + should-be-ignored; + yet-another { + should-also-be-ignored; + }; + }; + }; + + PowerPC,970@1 { + name = "PowerPC,970"; + device_type = "cpu"; + reg = <0x00000001>; + clock-frequency = <1600000000>; + timebase-frequency = <33333333>; + i-cache-size = <65536>; + d-cache-size = <32768>; + }; + }; + + test2 { + subnodes = <0>; + }; +}; + diff --git a/dtc/tests/subnode_offset.c b/dtc/tests/subnode_offset.c new file mode 100644 index 000000000..1362f998b --- /dev/null +++ b/dtc/tests/subnode_offset.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_subnode_offset() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static int check_subnode(struct fdt_header *fdt, int parent, const char *name) +{ + int offset; + const struct fdt_node_header *nh; + uint32_t tag; + + verbose_printf("Checking subnode \"%s\" of %d...", name, parent); + offset = fdt_subnode_offset(fdt, parent, name); + verbose_printf("offset %d...", offset); + if (offset < 0) + FAIL("fdt_subnode_offset(\"%s\"): %s", name, fdt_strerror(offset)); + nh = fdt_offset_ptr(fdt, offset, sizeof(*nh)); + verbose_printf("pointer %p\n", nh); + if (! nh) + FAIL("NULL retrieving subnode \"%s\"", name); + + tag = fdt32_to_cpu(nh->tag); + + if (tag != FDT_BEGIN_NODE) + FAIL("Incorrect tag 0x%08x on property \"%s\"", tag, name); + if (!nodename_eq(nh->name, name)) + FAIL("Subnode name mismatch \"%s\" instead of \"%s\"", + nh->name, name); + + return offset; +} + +int main(int argc, char *argv[]) +{ + void *fdt; + int subnode1_offset, subnode2_offset; + int subsubnode1_offset, subsubnode2_offset, subsubnode2_offset2; + int ss12_off, ss21_off; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + subnode1_offset = check_subnode(fdt, 0, "subnode@1"); + subnode2_offset = check_subnode(fdt, 0, "subnode@2"); + + if (subnode1_offset == subnode2_offset) + FAIL("Different subnodes have same offset"); + + check_property_cell(fdt, subnode1_offset, "prop-int", TEST_VALUE_1); + check_property_cell(fdt, subnode2_offset, "prop-int", TEST_VALUE_2); + + subsubnode1_offset = check_subnode(fdt, subnode1_offset, "subsubnode"); + subsubnode2_offset = check_subnode(fdt, subnode2_offset, "subsubnode@0"); + subsubnode2_offset2 = check_subnode(fdt, subnode2_offset, "subsubnode"); + + check_property_cell(fdt, subsubnode1_offset, "prop-int", TEST_VALUE_1); + check_property_cell(fdt, subsubnode2_offset, "prop-int", TEST_VALUE_2); + check_property_cell(fdt, subsubnode2_offset2, "prop-int", TEST_VALUE_2); + + if (subsubnode2_offset != subsubnode2_offset2) + FAIL("Different offsets with and without unit address"); + + check_subnode(fdt, subnode1_offset, "ss1"); + ss21_off = fdt_subnode_offset(fdt, subnode2_offset, "ss1"); + if (ss21_off != -FDT_ERR_NOTFOUND) + FAIL("Incorrectly found ss1 in subnode2"); + + ss12_off = fdt_subnode_offset(fdt, subnode1_offset, "ss2"); + if (ss12_off != -FDT_ERR_NOTFOUND) + FAIL("Incorrectly found ss2 in subnode1"); + check_subnode(fdt, subnode2_offset, "ss2"); + + PASS(); +} diff --git a/dtc/tests/supernode_atdepth_offset.c b/dtc/tests/supernode_atdepth_offset.c new file mode 100644 index 000000000..4435b4949 --- /dev/null +++ b/dtc/tests/supernode_atdepth_offset.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_supernode_atdepth_offset() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static int path_depth(const char *path) +{ + const char *p; + int depth = 0; + + if (path[0] != '/') + TEST_BUG(); + + if (strcmp(path, "/") == 0) + return 0; + for (p = path; *p; p++) + if (*p == '/') + depth++; + + /* Special case for path == "/" */ + if (p == (path + 1)) + return 0; + else + return depth; +} + +static int path_prefix(const char *path, int depth) +{ + const char *p; + int i; + + if (path[0] != '/') + TEST_BUG(); + + if (depth == 0) + return 1; + + p = path; + for (i = 0; i < depth; i++) + p = p+1 + strcspn(p+1, "/"); + + return p - path; +} + +static void check_supernode_atdepth(struct fdt_header *fdt, const char *path, + int depth) +{ + int pdepth = path_depth(path); + char *superpath; + int nodeoffset, supernodeoffset, superpathoffset, pathprefixlen; + int nodedepth; + + pathprefixlen = path_prefix(path, depth); + superpath = alloca(pathprefixlen + 1); + strncpy(superpath, path, pathprefixlen); + superpath[pathprefixlen] = '\0'; + + verbose_printf("Path %s (%d), depth %d, supernode is %s\n", + path, pdepth, depth, superpath); + + nodeoffset = fdt_path_offset(fdt, path); + if (nodeoffset < 0) + FAIL("fdt_path_offset(%s): %s", path, fdt_strerror(nodeoffset)); + superpathoffset = fdt_path_offset(fdt, superpath); + if (superpathoffset < 0) + FAIL("fdt_path_offset(%s): %s", superpath, + fdt_strerror(superpathoffset)); + + supernodeoffset = fdt_supernode_atdepth_offset(fdt, nodeoffset, + depth, &nodedepth); + if (supernodeoffset < 0) + FAIL("fdt_supernode_atdepth_offset(): %s", + fdt_strerror(supernodeoffset)); + + if (supernodeoffset != superpathoffset) + FAIL("fdt_supernode_atdepth_offset() returns %d instead of %d", + supernodeoffset, superpathoffset); + + if (nodedepth != pdepth) + FAIL("fdt_supernode_atdept_offset() returns node depth %d " + "instead of %d", nodedepth, pdepth); +} + +static void check_supernode_overdepth(struct fdt_header *fdt, const char *path) +{ + int pdepth = path_depth(path); + int nodeoffset, err; + + nodeoffset = fdt_path_offset(fdt, path); + if (nodeoffset < 0) + FAIL("fdt_path_offset(%s): %s", path, fdt_strerror(nodeoffset)); + + err = fdt_supernode_atdepth_offset(fdt, nodeoffset, pdepth + 1, NULL); + if (err != -FDT_ERR_NOTFOUND) + FAIL("fdt_supernode_atdept_offset(%s, %d) returns %d instead " + "of FDT_ERR_NOTFOUND", path, pdepth+1, err); +} + +static void check_path(struct fdt_header *fdt, const char *path) +{ + int i; + + for (i = 0; i <= path_depth(path); i++) + check_supernode_atdepth(fdt, path, i); + check_supernode_overdepth(fdt, path); +} +int main(int argc, char *argv[]) +{ + void *fdt; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + check_path(fdt, "/"); + check_path(fdt, "/subnode@1"); + check_path(fdt, "/subnode@2"); + check_path(fdt, "/subnode@1/subsubnode"); + check_path(fdt, "/subnode@2/subsubnode@0"); + + PASS(); +} diff --git a/dtc/tests/sw_states.c b/dtc/tests/sw_states.c new file mode 100644 index 000000000..42d57ae52 --- /dev/null +++ b/dtc/tests/sw_states.c @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for error handling with sequential write states + * Copyright (C) 2018 David Gibson, Red Hat Inc. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +#define SPACE 65536 + +#define CHECK_OK(code) \ + do { \ + verbose_printf(" OK: %s\n", #code); \ + err = (code); \ + if (err) \ + FAIL(#code ": %s", fdt_strerror(err)); \ + } while (0) + +#define CHECK_BADSTATE(code) \ + do { \ + verbose_printf("BAD: %s\n", #code); \ + err = (code); \ + if (err == 0) \ + FAIL(#code ": succeeded in bad state"); \ + else if (err != -FDT_ERR_BADSTATE) \ + FAIL(#code ": %s", fdt_strerror(err)); \ + } while (0) + +int main(int argc, char *argv[]) +{ + void *fdt = NULL; + int err; + + test_init(argc, argv); + + fdt = xmalloc(SPACE); + + err = fdt_create(fdt, SPACE); + if (err) + FAIL("fdt_create(): %s", fdt_strerror(err)); + + /* Memory reserve state */ + + CHECK_BADSTATE(fdt_begin_node(fdt, "")); + CHECK_BADSTATE(fdt_property_string(fdt, "bad-str", "TEST_STRING_1")); + CHECK_BADSTATE(fdt_end_node(fdt)); + CHECK_BADSTATE(fdt_finish(fdt)); + + CHECK_OK(fdt_add_reservemap_entry(fdt, TEST_ADDR_1, TEST_SIZE_1)); + CHECK_OK(fdt_add_reservemap_entry(fdt, TEST_ADDR_2, TEST_SIZE_2)); + + CHECK_BADSTATE(fdt_begin_node(fdt, "")); + CHECK_BADSTATE(fdt_property_string(fdt, "bad-str", "TEST_STRING_1")); + CHECK_BADSTATE(fdt_end_node(fdt)); + CHECK_BADSTATE(fdt_finish(fdt)); + + CHECK_OK(fdt_finish_reservemap(fdt)); + + /* Structure state */ + + CHECK_BADSTATE(fdt_add_reservemap_entry(fdt, TEST_ADDR_1, TEST_SIZE_1)); + CHECK_BADSTATE(fdt_finish_reservemap(fdt)); + + CHECK_OK(fdt_begin_node(fdt, "")); + CHECK_OK(fdt_property_string(fdt, "compatible", "test_tree1")); + CHECK_OK(fdt_property_u32(fdt, "prop-int", TEST_VALUE_1)); + CHECK_OK(fdt_property_u64(fdt, "prop-int64", TEST_VALUE64_1)); + CHECK_OK(fdt_property_string(fdt, "prop-str", TEST_STRING_1)); + CHECK_OK(fdt_property_u32(fdt, "#address-cells", 1)); + CHECK_OK(fdt_property_u32(fdt, "#size-cells", 0)); + + CHECK_OK(fdt_begin_node(fdt, "subnode@1")); + CHECK_OK(fdt_property_string(fdt, "compatible", "subnode1")); + CHECK_OK(fdt_property_u32(fdt, "reg", 1)); + CHECK_OK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_1)); + CHECK_OK(fdt_begin_node(fdt, "subsubnode")); + CHECK_OK(fdt_property(fdt, "compatible", "subsubnode1\0subsubnode", + 23)); + CHECK_OK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_1)); + CHECK_OK(fdt_end_node(fdt)); + CHECK_OK(fdt_begin_node(fdt, "ss1")); + CHECK_OK(fdt_end_node(fdt)); + CHECK_OK(fdt_end_node(fdt)); + + CHECK_OK(fdt_begin_node(fdt, "subnode@2")); + CHECK_OK(fdt_property_u32(fdt, "reg", 2)); + CHECK_OK(fdt_property_cell(fdt, "linux,phandle", PHANDLE_1)); + CHECK_OK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_2)); + CHECK_OK(fdt_property_u32(fdt, "#address-cells", 1)); + CHECK_OK(fdt_property_u32(fdt, "#size-cells", 0)); + CHECK_OK(fdt_begin_node(fdt, "subsubnode@0")); + CHECK_OK(fdt_property_u32(fdt, "reg", 0)); + CHECK_OK(fdt_property_cell(fdt, "phandle", PHANDLE_2)); + CHECK_OK(fdt_property(fdt, "compatible", "subsubnode2\0subsubnode", + 23)); + CHECK_OK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_2)); + CHECK_OK(fdt_end_node(fdt)); + CHECK_OK(fdt_begin_node(fdt, "ss2")); + CHECK_OK(fdt_end_node(fdt)); + + CHECK_OK(fdt_end_node(fdt)); + + CHECK_OK(fdt_end_node(fdt)); + + CHECK_OK(fdt_finish(fdt)); + + /* Completed state */ + + CHECK_BADSTATE(fdt_add_reservemap_entry(fdt, TEST_ADDR_1, TEST_SIZE_1)); + CHECK_BADSTATE(fdt_finish_reservemap(fdt)); + CHECK_BADSTATE(fdt_begin_node(fdt, "")); + CHECK_BADSTATE(fdt_property_string(fdt, "bad-str", "TEST_STRING_1")); + CHECK_BADSTATE(fdt_end_node(fdt)); + CHECK_BADSTATE(fdt_finish(fdt)); + + PASS(); +} diff --git a/dtc/tests/sw_tree1.c b/dtc/tests/sw_tree1.c new file mode 100644 index 000000000..7069ace0a --- /dev/null +++ b/dtc/tests/sw_tree1.c @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for fdt_nop_node() + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +#define SPACE 65536 + +static enum { + FIXED = 0, + RESIZE, + REALLOC, + NEWALLOC, +} alloc_mode; + +static void realloc_fdt(void **fdt, size_t *size, bool created) +{ + int err; + + switch (alloc_mode) { + case FIXED: + if (!(*fdt)) + *fdt = xmalloc(*size); + else + FAIL("Ran out of space"); + return; + + case RESIZE: + if (!(*fdt)) { + *fdt = xmalloc(SPACE); + } else if (*size < SPACE) { + *size += 1; + err = fdt_resize(*fdt, *fdt, *size); + if (err < 0) + FAIL("fdt_resize() failed: %s", + fdt_strerror(err)); + } else { + FAIL("Ran out of space"); + } + return; + + case REALLOC: + *size += 1; + *fdt = xrealloc(*fdt, *size); + if (created) { + err = fdt_resize(*fdt, *fdt, *size); + if (err < 0) + FAIL("fdt_resize() failed: %s", + fdt_strerror(err)); + } + return; + + case NEWALLOC: { + void *buf; + + *size += 1; + buf = xmalloc(*size); + if (created) { + err = fdt_resize(*fdt, buf, *size); + if (err < 0) + FAIL("fdt_resize() failed: %s", + fdt_strerror(err)); + } + free(*fdt); + *fdt = buf; + return; + } + + default: + CONFIG("Bad allocation mode"); + } +} + +#define CHECK(code) \ + do { \ + err = (code); \ + if (err == -FDT_ERR_NOSPACE) \ + realloc_fdt(&fdt, &size, created); \ + else if (err) \ + FAIL(#code ": %s", fdt_strerror(err)); \ + } while (err != 0) + +int main(int argc, char *argv[]) +{ + void *fdt = NULL; + size_t size; + int err; + bool created = false; + void *place; + const char place_str[] = "this is a placeholder string\0string2"; + int place_len = sizeof(place_str); + int create_flags; + + test_init(argc, argv); + + alloc_mode = FIXED; + size = SPACE; + create_flags = 0; + + if (argc == 2 || argc == 3) { + if (streq(argv[1], "fixed")) { + alloc_mode = FIXED; + size = SPACE; + } else if (streq(argv[1], "resize")) { + alloc_mode = REALLOC; + size = 0; + } else if (streq(argv[1], "realloc")) { + alloc_mode = REALLOC; + size = 0; + } else if (streq(argv[1], "newalloc")) { + alloc_mode = NEWALLOC; + size = 0; + } else { + char *endp; + + size = strtoul(argv[1], &endp, 0); + if (*endp == '\0') + alloc_mode = FIXED; + else + CONFIG("Bad allocation mode \"%s\" specified", + argv[1]); + } + } + if (argc == 3) { + char *str = argv[2], *saveptr, *tok; + bool default_flag = false; + + while ((tok = strtok_r(str, ",", &saveptr)) != NULL) { + str = NULL; + if (streq(tok, "default")) { + default_flag = true; + } else if (streq(tok, "no_name_dedup")) { + create_flags |= FDT_CREATE_FLAG_NO_NAME_DEDUP; + } else if (streq(tok, "bad")) { + create_flags |= 0xffffffff; + } else { + CONFIG("Bad creation flags \"%s\" specified", + argv[2]); + } + } + + if (default_flag && create_flags != 0) + CONFIG("Bad creation flags \"%s\" specified", + argv[2]); + } + + if (argc > 3) { + CONFIG("sw_tree1 [<allocation mode>] [<create flags>]"); + } + + fdt = xmalloc(size); + CHECK(fdt_create_with_flags(fdt, size, create_flags)); + + created = true; + + CHECK(fdt_add_reservemap_entry(fdt, TEST_ADDR_1, TEST_SIZE_1)); + + CHECK(fdt_add_reservemap_entry(fdt, TEST_ADDR_2, TEST_SIZE_2)); + CHECK(fdt_finish_reservemap(fdt)); + + CHECK(fdt_begin_node(fdt, "")); + CHECK(fdt_property_string(fdt, "compatible", "test_tree1")); + CHECK(fdt_property_u32(fdt, "prop-int", TEST_VALUE_1)); + CHECK(fdt_property_u64(fdt, "prop-int64", TEST_VALUE64_1)); + CHECK(fdt_property_string(fdt, "prop-str", TEST_STRING_1)); + CHECK(fdt_property_u32(fdt, "#address-cells", 1)); + CHECK(fdt_property_u32(fdt, "#size-cells", 0)); + + CHECK(fdt_begin_node(fdt, "subnode@1")); + CHECK(fdt_property_string(fdt, "compatible", "subnode1")); + CHECK(fdt_property_u32(fdt, "reg", 1)); + CHECK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_1)); + CHECK(fdt_begin_node(fdt, "subsubnode")); + CHECK(fdt_property(fdt, "compatible", "subsubnode1\0subsubnode", + 23)); + CHECK(fdt_property_placeholder(fdt, "placeholder", place_len, &place)); + memcpy(place, place_str, place_len); + CHECK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_1)); + CHECK(fdt_end_node(fdt)); + CHECK(fdt_begin_node(fdt, "ss1")); + CHECK(fdt_end_node(fdt)); + CHECK(fdt_end_node(fdt)); + + CHECK(fdt_begin_node(fdt, "subnode@2")); + CHECK(fdt_property_u32(fdt, "reg", 2)); + CHECK(fdt_property_cell(fdt, "linux,phandle", PHANDLE_1)); + CHECK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_2)); + CHECK(fdt_property_u32(fdt, "#address-cells", 1)); + CHECK(fdt_property_u32(fdt, "#size-cells", 0)); + CHECK(fdt_begin_node(fdt, "subsubnode@0")); + CHECK(fdt_property_u32(fdt, "reg", 0)); + CHECK(fdt_property_cell(fdt, "phandle", PHANDLE_2)); + CHECK(fdt_property(fdt, "compatible", "subsubnode2\0subsubnode", + 23)); + CHECK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_2)); + CHECK(fdt_end_node(fdt)); + CHECK(fdt_begin_node(fdt, "ss2")); + CHECK(fdt_end_node(fdt)); + + CHECK(fdt_end_node(fdt)); + + CHECK(fdt_end_node(fdt)); + + save_blob("unfinished_tree1.test.dtb", fdt); + + CHECK(fdt_finish(fdt)); + + verbose_printf("Completed tree, totalsize = %d\n", + fdt_totalsize(fdt)); + + save_blob("sw_tree1.test.dtb", fdt); + + PASS(); +} diff --git a/dtc/tests/test01.asm b/dtc/tests/test01.asm new file mode 100644 index 000000000..bbf66c771 --- /dev/null +++ b/dtc/tests/test01.asm @@ -0,0 +1,294 @@ +/* autogenerated by dtc, do not edit */ + +#define OF_DT_HEADER 0xd00dfeed +#define OF_DT_BEGIN_NODE 0x1 +#define OF_DT_END_NODE 0x2 +#define OF_DT_PROP 0x3 +#define OF_DT_END 0x9 + + .globl dt_blob_start +dt_blob_start: +_dt_blob_start: + .globl dt_header +dt_header: +_dt_header: + .long OF_DT_HEADER /* magic */ + .long _dt_blob_end - _dt_blob_start /* totalsize */ + .long _dt_struct_start - _dt_blob_start /* off_dt_struct */ + .long _dt_strings_start - _dt_blob_start /* off_dt_strings */ + .long _dt_reserve_map - _dt_blob_start /* off_dt_strings */ + .long 16 /* version */ + .long 16 /* last_comp_version */ + .long 0 /*boot_cpuid_phys*/ + .long _dt_strings_end - _dt_strings_start /* size_dt_strings */ + .balign 8 + .globl dt_reserve_map +dt_reserve_map: +_dt_reserve_map: +/* Memory reserve map from source file */ + .long 0x10000000 + .long 0x00000000 + .long 0x00000000 + .long 0x02000000 + .long 0x20000000 + .long 0x00000000 + .long 0x01000000 + .long 0x00000000 + .long 0x00000000 + .long 0x00000000 + .long 0x00000000 + .long 0x00000014 + .long 0, 0 + .long 0, 0 + .globl dt_struct_start +dt_struct_start: +_dt_struct_start: + .long OF_DT_BEGIN_NODE + .string "" + .balign 4 + .long OF_DT_PROP + .long 0xc + .long 0x0 + .long 0x4d79426f + .long 0x6172644e + .long 0x616d6500 + .balign 4 + .long OF_DT_PROP + .long 0x1e + .long 0x6 + .long 0x4d79426f + .long 0x6172644e + .long 0x616d6500 + .long 0x4d79426f + .long 0x61726446 + .long 0x616d696c + .long 0x794e616d + .short 0x6500 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x11 + .long 0x2 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x20 + .long 0x2 + .balign 4 + .long OF_DT_BEGIN_NODE + .string "cpus" + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x2c + .long 0x1 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x11 + .long 0x1 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x20 + .long 0x0 + .balign 4 + .long OF_DT_BEGIN_NODE + .string "PowerPC,970@0" + .balign 4 + .long OF_DT_PROP + .long 0xc + .long 0x3a + .long 0x506f7765 + .long 0x7250432c + .long 0x39373000 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x3f + .long 0x63707500 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x4b + .long 0x0 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x4f + .long 0x5f5e1000 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x5f + .long 0x1fca055 + .balign 4 + .long OF_DT_PROP + .long 0x0 + .long 0x72 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x81 + .long 0x10000 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x8e + .long 0x8000 + .balign 4 + .long OF_DT_END_NODE + .long OF_DT_BEGIN_NODE + .string "PowerPC,970@1" + .balign 4 + .long OF_DT_PROP + .long 0xc + .long 0x3a + .long 0x506f7765 + .long 0x7250432c + .long 0x39373000 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x3f + .long 0x63707500 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x4b + .long 0x1 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x4f + .long 0x5f5e1000 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x5f + .long 0x1fca055 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x81 + .long 0x10000 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x8e + .long 0x8000 + .balign 4 + .long OF_DT_END_NODE + .long OF_DT_END_NODE + .long OF_DT_BEGIN_NODE + .string "randomnode" + .balign 4 + .long OF_DT_PROP + .long 0x13 + .long 0x9b + .long 0xff007374 + .long 0x75666673 + .long 0x74756666 + .long 0x909090a + .short 0xa0a + .byte 0x0 + .balign 4 + .long OF_DT_PROP + .long 0x9 + .long 0xa2 + .long 0xa0b0c0d + .long 0xdeeaadbe + .byte 0xef + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0xa7 + .long 0x2 + .balign 4 + .long OF_DT_PROP + .long 0x14 + .long 0xab + .long 0x61626300 + .long 0x12340000 + .long 0xa + .long 0xb + .long 0xc + .balign 4 + .long OF_DT_END_NODE + .long OF_DT_BEGIN_NODE + .string "memory@0" + .balign 4 + .long OF_DT_PROP + .long 0x7 + .long 0x3f + .long 0x6d656d6f + .short 0x7279 + .byte 0x0 + .balign 4 + .globl memreg +memreg: + .long OF_DT_PROP + .long 0x10 + .long 0x4b + .long 0x0 + .long 0x0 + .long 0x0 + .long 0x20000000 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0x2c + .long 0x2 + .balign 4 + .long OF_DT_END_NODE + .long OF_DT_BEGIN_NODE + .string "chosen" + .balign 4 + .long OF_DT_PROP + .long 0xf + .long 0xb1 + .long 0x726f6f74 + .long 0x3d2f6465 + .long 0x762f7364 + .short 0x6132 + .byte 0x0 + .balign 4 + .long OF_DT_PROP + .long 0x4 + .long 0xba + .long 0x600 + .balign 4 + .long OF_DT_END_NODE + .long OF_DT_END_NODE + .long OF_DT_END + .globl dt_struct_end +dt_struct_end: +_dt_struct_end: + .globl dt_strings_start +dt_strings_start: +_dt_strings_start: + .string "model" + .string "compatible" + .string "#address-cells" + .string "#size-cells" + .string "linux,phandle" + .string "name" + .string "device_type" + .string "reg" + .string "clock-frequency" + .string "timebase-frequency" + .string "linux,boot-cpu" + .string "i-cache-size" + .string "d-cache-size" + .string "string" + .string "blob" + .string "ref" + .string "mixed" + .string "bootargs" + .string "linux,platform" + .globl dt_strings_end +dt_strings_end: +_dt_strings_end: + .globl dt_blob_end +dt_blob_end: +_dt_blob_end: diff --git a/dtc/tests/test01.dts b/dtc/tests/test01.dts new file mode 100644 index 000000000..f9fd16534 --- /dev/null +++ b/dtc/tests/test01.dts @@ -0,0 +1,57 @@ +/dts-v1/; + +/memreserve/ 0x1000000000000000 0x0000000002000000; +/memreserve/ 0x2000000000000000 0x0100000000000000; +/memreserve/ 0x0000000000000000 0x0000000000000014; + +/ { + model = "MyBoardName"; + compatible = "MyBoardName", "MyBoardFamilyName"; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + linux,phandle = <0x1>; + #address-cells = <1>; + #size-cells = <0>; + PowerPC,970@0 { + name = "PowerPC,970"; + device_type = "cpu"; + reg = <0x00000000>; + clock-frequency = <1600000000>; + timebase-frequency = <33333333>; + linux,boot-cpu; + i-cache-size = <65536>; + d-cache-size = <32768>; + }; + + PowerPC,970@1 { + name = "PowerPC,970"; + device_type = "cpu"; + reg = <0x00000001>; + clock-frequency = <1600000000>; + timebase-frequency = <33333333>; + i-cache-size = <65536>; + d-cache-size = <32768>; + }; + + }; + + randomnode { + string = "\xff\0stuffstuff\t\t\t\n\n\n"; + blob = [0a 0b 0c 0d de ea ad be ef]; + ref = < &{/memory@0} >; + mixed = "abc", [1234], <0xa 0xb 0xc>; + }; + + memory@0 { + device_type = "memory"; + memreg: reg = <0x00000000 0x00000000 0x00000000 0x20000000>; + }; + + chosen { + bootargs = "root=/dev/sda2"; + linux,platform = <0x600>; + }; + +}; diff --git a/dtc/tests/test01.stderr b/dtc/tests/test01.stderr new file mode 100644 index 000000000..82ea3f634 --- /dev/null +++ b/dtc/tests/test01.stderr @@ -0,0 +1,4 @@ +DTC: dts->asm on file "test.dts" +Warning: "linux,boot-cpu" property is deprecated in blob version 2 or higher +Warning: /chosen has no "linux,stdout-path" property +Warning: /chosen has no "interrupt-controller" property diff --git a/dtc/tests/test_kernel_dts b/dtc/tests/test_kernel_dts new file mode 100755 index 000000000..238f3f7c6 --- /dev/null +++ b/dtc/tests/test_kernel_dts @@ -0,0 +1,86 @@ +#!/usr/bin/perl + +my $dtc_old = "/home/jdl/FSL/dtc/dtc-old"; +my $dtc_new = "/home/jdl/FSL/dtc/dtc-new"; + +my $basic_options = "-b 0 -f -I dts -O dtb"; + +my $linux_dts_dir = "/usr/src/linux-2.6/arch/powerpc/boot/dts"; + +# Yeah, sure, we could, like, readdir() this instead... +my @boards = ( + "bamboo", + "ebony", + "ep88xc", + "holly", + "kilauea", + "kuroboxHD", + "kuroboxHG", + "lite5200", + "lite5200b", + "mpc7448hpc2", + "mpc8272ads", + "mpc8313erdb", + "mpc832x_mds", + "mpc832x_rdb", + "mpc8349emitx", + "mpc8349emitxgp", + "mpc834x_mds", + "mpc836x_mds", + "mpc8540ads", + "mpc8541cds", + "mpc8544ds", + "mpc8548cds", + "mpc8555cds", + "mpc8560ads", + "mpc8568mds", + "mpc8572ds", + "mpc8610_hpcd", + "mpc8641_hpcn", + "mpc866ads", # Feh. Bad node references... + "mpc885ads", + "pq2fads", + "prpmc2800", + "ps3", + "sequoia", + "walnut", +); + +foreach my $board (@boards) { + my $dts_file = "$linux_dts_dir/$board.dts"; + + my $old_dtb_file = "/tmp/$board.dtb.old"; + my $new_dtb_file = "/tmp/$board.dtb.new"; + + my $cmd_old = "$dtc_old $basic_options -o $old_dtb_file $dts_file"; + my $cmd_new = "$dtc_new $basic_options -o $new_dtb_file $dts_file"; + my $cmd_cmp = "cmp $old_dtb_file $new_dtb_file"; + + print "------------------------------------------------\n"; + print "OLD: $cmd_old\n"; + unlink($old_dtb_file) if (-f $old_dtb_file); + system("$cmd_old >& /dev/null"); + my $status = $?; + if ($status) { + print " FAILED to run old DTC on $board\n"; + } + + print "NEW: $cmd_new\n"; + unlink($new_dtb_file) if (-f $new_dtb_file); + system("$cmd_new >& /dev/null"); + $status = $?; + if ($status) { + print " FAILED to run new DTC on $board\n"; + } + + if (-f $old_dtb_file && -f $new_dtb_file) { + print "CMP: $cmd_cmp\n"; + system($cmd_cmp); + $status = $?; + if ($status) { + print " FAILED $board\n"; + } + } else { + printf " FAILED: Missing dtb file\n"; + } +} diff --git a/dtc/tests/test_label_ref.dts b/dtc/tests/test_label_ref.dts new file mode 100644 index 000000000..7009c7953 --- /dev/null +++ b/dtc/tests/test_label_ref.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +/ { + +}; + +label: &handle { + +}; diff --git a/dtc/tests/test_props.dts b/dtc/tests/test_props.dts new file mode 100644 index 000000000..7e59bd1b8 --- /dev/null +++ b/dtc/tests/test_props.dts @@ -0,0 +1,11 @@ +/dts-v1/; + +/ { + compatible = "test_props"; + prop-hex32 = <0xdeadbeef>; + prop-uint32 = <123>; + prop-int32 = <0xfffffffe>; + prop-hex64 = /bits/ 64 <0xdeadbeef01abcdef>; + prop-uint64 = /bits/ 64 <9223372036854775807>; + prop-int64 = /bits/ 64 <0xfffffffffffffffe>; +}; diff --git a/dtc/tests/test_tree1.dts b/dtc/tests/test_tree1.dts new file mode 100644 index 000000000..77ea32569 --- /dev/null +++ b/dtc/tests/test_tree1.dts @@ -0,0 +1,46 @@ +/dts-v1/; + +/memreserve/ 0xdeadbeef00000000 0x100000; +/memreserve/ 123456789 010000; + +/ { + compatible = "test_tree1"; + prop-int = <0xdeadbeef>; + prop-int64 = /bits/ 64 <0xdeadbeef01abcdef>; + prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; + + subnode@1 { + compatible = "subnode1"; + reg = <1>; + prop-int = [deadbeef]; + + subsubnode { + compatible = "subsubnode1", "subsubnode"; + placeholder = "this is a placeholder string", "string2"; + prop-int = <0xdeadbeef>; + }; + + ss1 { + }; + }; + + subnode@2 { + reg = <2>; + linux,phandle = <0x2000>; + prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; + + ssn0: subsubnode@0 { + reg = <0>; + phandle = <0x2001>; + compatible = "subsubnode2", "subsubnode"; + prop-int = <0726746425>; + }; + + ss2 { + }; + }; +}; diff --git a/dtc/tests/test_tree1_delete.dts b/dtc/tests/test_tree1_delete.dts new file mode 100644 index 000000000..b95ef1e71 --- /dev/null +++ b/dtc/tests/test_tree1_delete.dts @@ -0,0 +1,68 @@ +/dts-v1/; + +/include/ "test_tree1.dts" + +/ { + nonexistant-property = <0xdeadbeef>; + + nonexistant-subnode { + prop-int = <1>; + }; + + dellabel: deleted-by-label { + prop-int = <1>; + }; + + subnode@1 { + delete-this-str = "deadbeef"; + }; + +}; + +/ { + /delete-property/ nonexistant-property; + + /delete-node/ nonexistant-subnode; + + subnode@1 { + /delete-property/ delete-this-str; + }; +}; + +/delete-node/ &dellabel; + +/ { + /delete-property/ prop-str; +}; + +/ { + prop-str = "hello world"; +}; + +/ { + subnode@1 { + /delete-node/ ss1; + }; +}; + +/ { + subnode@1 { + ss1 { + }; + }; +}; + +/{ + duplabel1: foo1 = "bar"; + duplabel2: foo2 = "bar"; +}; + +/{ + duplabel1: baz1 = "qux"; + duplabel2: baz2 = "qux"; +}; + +/{ + /delete-property/ foo1; + /delete-property/ baz2; +}; diff --git a/dtc/tests/test_tree1_label_noderef.dts b/dtc/tests/test_tree1_label_noderef.dts new file mode 100644 index 000000000..cfe5946f8 --- /dev/null +++ b/dtc/tests/test_tree1_label_noderef.dts @@ -0,0 +1,56 @@ +/dts-v1/; + +/memreserve/ 0xdeadbeef00000000 0x100000; +/memreserve/ 123456789 010000; + +/ { + compatible = "test_tree1"; + prop-int = <0xdeadbeef>; + prop-int64 = /bits/ 64 <0xdeadbeef01abcdef>; + prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; + + subnode@1 { + compatible = "subnode1"; + reg = <1>; + prop-int = [deadbeef]; + + subsubnode { + compatible = "subsubnode1", "subsubnode"; + placeholder = "this is a placeholder string", "string2"; + prop-int = <0xdeadbeef>; + }; + + ss1 { + }; + }; + + subnode@2 { + reg = <2>; + linux,phandle = <0x2000>; + prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; + + ssn0: subsubnode@0 { + phandle = <0x2001>; + prop-int = <0xbad>; + }; + + ss2 { + }; + }; +}; + +/* Add label to a noderef */ +ssn1: &ssn0 { + reg = <0>; + prop-int = <123456789>; +}; + +/* Use the new label for merging */ +&ssn1 { + prop-int = <0726746425>; + compatible = "subsubnode2", "subsubnode"; +}; diff --git a/dtc/tests/test_tree1_merge.dts b/dtc/tests/test_tree1_merge.dts new file mode 100644 index 000000000..b100c12de --- /dev/null +++ b/dtc/tests/test_tree1_merge.dts @@ -0,0 +1,51 @@ +/dts-v1/; +/memreserve/ 0xdeadbeef00000000 0x100000; +/memreserve/ 123456789 010000; + +/ { + compatible = "test_tree1"; + prop-int = "wrong!"; + prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; + + subnode@1 { + compatible = "subnode1"; + reg = <1>; + + subsubnode { + compatible = "subsubnode1", "subsubnode"; + prop-int = <0xdeadbeef>; + }; + + ss1 { + }; + }; + + subnode@2 { + reg = <2>; + linux,phandle = <0x2000>; + prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; + + ss2 { + }; + }; +}; + +/ { + prop-int = <0xdeadbeef>; + prop-int64 = /bits/ 64 <0xdeadbeef01abcdef>; + subnode@1 { + prop-int = [deadbeef]; + }; + subnode@2 { + ssn0: subsubnode@0 { + reg = <0>; + phandle = <0x2001>; + compatible = "subsubnode2", "subsubnode"; + prop-int = <0726746425>; + }; + }; +}; diff --git a/dtc/tests/test_tree1_merge_labelled.dts b/dtc/tests/test_tree1_merge_labelled.dts new file mode 100644 index 000000000..fcf5dc45a --- /dev/null +++ b/dtc/tests/test_tree1_merge_labelled.dts @@ -0,0 +1,49 @@ +/dts-v1/; + +/memreserve/ 0xdeadbeef00000000 0x100000; +/memreserve/ 123456789 010000; + +/ { + compatible = "test_tree1"; + prop-int = <0xdeadbeef>; + prop-int64 = /bits/ 64 <0xdeadbeef01abcdef>; + prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; + + subnode@1 { + compatible = "subnode1"; + reg = <1>; + prop-int = [deadbeef]; + + subsubnode { + compatible = "subsubnode1", "subsubnode"; + prop-int = <0xdeadbeef>; + }; + + ss1 { + }; + }; + + subnode@2 { + reg = <2>; + linux,phandle = <0x2000>; + prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; + + ssn0: subsubnode@0 { + reg = <0>; + phandle = <0x2001>; + prop-int = <0xbad>; + }; + + ss2 { + }; + }; +}; + +&ssn0 { + compatible = "subsubnode2", "subsubnode"; + prop-int = <0726746425>; +}; diff --git a/dtc/tests/test_tree1_merge_path.dts b/dtc/tests/test_tree1_merge_path.dts new file mode 100644 index 000000000..c2ad82972 --- /dev/null +++ b/dtc/tests/test_tree1_merge_path.dts @@ -0,0 +1,49 @@ +/dts-v1/; + +/memreserve/ 0xdeadbeef00000000 0x100000; +/memreserve/ 123456789 010000; + +/ { + compatible = "test_tree1"; + prop-int = <0xdeadbeef>; + prop-int64 = /bits/ 64 <0xdeadbeef01abcdef>; + prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; + + subnode@1 { + compatible = "subnode1"; + reg = <1>; + prop-int = [deadbeef]; + + subsubnode { + compatible = "subsubnode1", "subsubnode"; + prop-int = <0xdeadbeef>; + }; + + ss1 { + }; + }; + + subnode@2 { + reg = <2>; + linux,phandle = <0x2000>; + prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; + + ssn0: subsubnode@0 { + reg = <0>; + phandle = <0x2001>; + prop-int = <0xbad>; + }; + + ss2 { + }; + }; +}; + +&{/subnode@2/subsubnode@0} { + compatible = "subsubnode2", "subsubnode"; + prop-int = <0726746425>; +}; diff --git a/dtc/tests/test_tree1_wrong1.dts b/dtc/tests/test_tree1_wrong1.dts new file mode 100644 index 000000000..900d38582 --- /dev/null +++ b/dtc/tests/test_tree1_wrong1.dts @@ -0,0 +1,43 @@ +/dts-v1/; + +/memreserve/ 123456789 010000; + +/ { + compatible = "test_tree1"; + prop-int = <0xdeadbeef>; + prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; + + subnode@1 { + compatible = "subnode1"; + reg = <1>; + prop-int = [deadbeef]; + + subsubnode { + compatible = "subsubnode1", "subsubnode"; + prop-int = <0xdeadbeef>; + }; + + ss1 { + }; + }; + + subnode@2 { + reg = <2>; + linux,phandle = <0x2000>; + prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; + + subsubnode@0 { + reg = <0>; + phandle = <0x2001>; + compatible = "subsubnode2", "subsubnode"; + prop-int = <0726746425>; + }; + + ss2 { + }; + }; +}; diff --git a/dtc/tests/test_tree1_wrong2.dts b/dtc/tests/test_tree1_wrong2.dts new file mode 100644 index 000000000..099752b37 --- /dev/null +++ b/dtc/tests/test_tree1_wrong2.dts @@ -0,0 +1,43 @@ +/dts-v1/; + +/memreserve/ 0xdeadbeef00000000 0x100000; +/memreserve/ 123456789 010000; + +/ { + compatible = "test_tree1"; + prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; + + subnode@1 { + compatible = "subnode1"; + reg = <1>; + prop-int = [deadbeef]; + + subsubnode { + compatible = "subsubnode1", "subsubnode"; + prop-int = <0xdeadbeef>; + }; + + ss1 { + }; + }; + + subnode@2 { + reg = <2>; + linux,phandle = <0x2000>; + prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; + + subsubnode@0 { + reg = <0>; + phandle = <0x2001>; + compatible = "subsubnode2", "subsubnode"; + prop-int = <0726746425>; + }; + + ss2 { + }; + }; +}; diff --git a/dtc/tests/test_tree1_wrong3.dts b/dtc/tests/test_tree1_wrong3.dts new file mode 100644 index 000000000..069353a94 --- /dev/null +++ b/dtc/tests/test_tree1_wrong3.dts @@ -0,0 +1,43 @@ +/dts-v1/; + +/memreserve/ 0xdeadbeef00000000 0x100000; +/memreserve/ 123456789 010000; + +/ { + compatible = "test_tree1"; + prop-int = <0xdeadbeef>; + prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; + + subnode@1 { + compatible = "subnode1"; + reg = <1>; + + subsubnode { + compatible = "subsubnode1", "subsubnode"; + prop-int = <0xdeadbeef>; + }; + + ss1 { + }; + }; + + subnode@2 { + reg = <2>; + linux,phandle = <0x2000>; + prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; + + subsubnode@0 { + reg = <0>; + phandle = <0x2001>; + compatible = "subsubnode2", "subsubnode"; + prop-int = <0726746425>; + }; + + ss2 { + }; + }; +}; diff --git a/dtc/tests/test_tree1_wrong4.dts b/dtc/tests/test_tree1_wrong4.dts new file mode 100644 index 000000000..2c5641618 --- /dev/null +++ b/dtc/tests/test_tree1_wrong4.dts @@ -0,0 +1,41 @@ +/dts-v1/; + +/memreserve/ 0xdeadbeef00000000 0x100000; +/memreserve/ 123456789 010000; + +/ { + compatible = "test_tree1"; + prop-int = <0xdeadbeef>; + prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; + + subnode@1 { + compatible = "subnode1"; + reg = <1>; + prop-int = [deadbeef]; + + subsubnode { + compatible = "subsubnode1", "subsubnode"; + prop-int = <0xdeadbeef>; + }; + + ss1 { + }; + }; + + subnode@2 { + reg = <2>; + linux,phandle = <0x2000>; + prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; + + subsubnode@0 { + reg = <0>; + phandle = <0x2001>; + compatible = "subsubnode2", "subsubnode"; + prop-int = <0726746425>; + }; + }; +}; diff --git a/dtc/tests/test_tree1_wrong5.dts b/dtc/tests/test_tree1_wrong5.dts new file mode 100644 index 000000000..6ddd72d52 --- /dev/null +++ b/dtc/tests/test_tree1_wrong5.dts @@ -0,0 +1,44 @@ +/dts-v1/; + +/memreserve/ 0xdeadbeef00000000 0x100000; +/memreserve/ 123456789 010000; + +/ { + compatible = "test_tree1"; + prop-int = <0xdeadbefe>; + prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; + + subnode@1 { + compatible = "subnode1"; + reg = <1>; + prop-int = [deadbeef]; + + subsubnode { + compatible = "subsubnode1", "subsubnode"; + prop-int = <0xdeadbeef>; + }; + + ss1 { + }; + }; + + subnode@2 { + reg = <2>; + linux,phandle = <0x2000>; + prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; + + subsubnode@0 { + reg = <0>; + phandle = <0x2001>; + compatible = "subsubnode2", "subsubnode"; + prop-int = <0726746425>; + }; + + ss2 { + }; + }; +}; diff --git a/dtc/tests/test_tree1_wrong6.dts b/dtc/tests/test_tree1_wrong6.dts new file mode 100644 index 000000000..36b4e1f66 --- /dev/null +++ b/dtc/tests/test_tree1_wrong6.dts @@ -0,0 +1,45 @@ +/dts-v1/; + +/memreserve/ 0xdeadbeef00000000 0x100000; +/memreserve/ 123456789 010000; + +/ { + compatible = "test_tree1"; + prop-int = <0xdeadbeef>; + prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; + + subnode@1 { + compatible = "subnode1"; + reg = <1>; + prop-int = [deadbeef]; + + subsubnode { + compatible = "subsubnode1", "subsubnode"; + prop-int = <0xdeadbeef>; + }; + + ss1 { + extra-prop; + }; + }; + + subnode@2 { + reg = <2>; + linux,phandle = <0x2000>; + prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; + + subsubnode@0 { + reg = <0>; + phandle = <0x2001>; + compatible = "subsubnode2", "subsubnode"; + prop-int = <0726746425>; + }; + + ss2 { + }; + }; +}; diff --git a/dtc/tests/test_tree1_wrong7.dts b/dtc/tests/test_tree1_wrong7.dts new file mode 100644 index 000000000..54150e6d9 --- /dev/null +++ b/dtc/tests/test_tree1_wrong7.dts @@ -0,0 +1,46 @@ +/dts-v1/; + +/memreserve/ 0xdeadbeef00000000 0x100000; +/memreserve/ 123456789 010000; + +/ { + compatible = "test_tree1"; + prop-int = <0xdeadbeef>; + prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; + + subnode@1 { + compatible = "subnode1"; + reg = <1>; + prop-int = [deadbeef]; + + subsubnode { + compatible = "subsubnode1", "subsubnode"; + prop-int = <0xdeadbeef>; + }; + + ss1 { + }; + }; + + subnode@2 { + reg = <2>; + linux,phandle = <0x2000>; + prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; + + subsubnode@0 { + reg = <0>; + phandle = <0x2001>; + compatible = "subsubnode2", "subsubnode"; + prop-int = <0726746425>; + }; + + ss2 { + extranode { + }; + }; + }; +}; diff --git a/dtc/tests/test_tree1_wrong8.dts b/dtc/tests/test_tree1_wrong8.dts new file mode 100644 index 000000000..7a28a9f29 --- /dev/null +++ b/dtc/tests/test_tree1_wrong8.dts @@ -0,0 +1,44 @@ +/dts-v1/; + +/memreserve/ 0xdeadbeef00000000 0x100000; +/memreserve/ 123456789 010001; + +/ { + compatible = "test_tree1"; + prop-int = <0xdeadbeef>; + prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; + + subnode@1 { + compatible = "subnode1"; + reg = <1>; + prop-int = [deadbeef]; + + subsubnode { + compatible = "subsubnode1", "subsubnode"; + prop-int = <0xdeadbeef>; + }; + + ss1 { + }; + }; + + subnode@2 { + linux,phandle = <0x2000>; + prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + + subsubnode@0 { + reg = <0>; + phandle = <0x2001>; + compatible = "subsubnode2", "subsubnode"; + prop-int = <0726746425>; + }; + + ss2 { + }; + }; +}; diff --git a/dtc/tests/test_tree1_wrong9.dts b/dtc/tests/test_tree1_wrong9.dts new file mode 100644 index 000000000..f6486fa93 --- /dev/null +++ b/dtc/tests/test_tree1_wrong9.dts @@ -0,0 +1,45 @@ +/dts-v1/; + +/memreserve/ 0xdeadbeef00000000 0x100000; +/memreserve/ 123456789 010000; +/memreserve/ 0 1; + +/ { + compatible = "test_tree1"; + prop-int = <0xdeadbeef>; + prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; + + subnode@1 { + compatible = "subnode1"; + reg = <1>; + prop-int = [deadbeef]; + + subsubnode { + compatible = "subsubnode1", "subsubnode"; + prop-int = <0xdeadbeef>; + }; + + ss1 { + }; + }; + + subnode@2 { + reg = <2>; + linux,phandle = <0x2000>; + prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; + + subsubnode@0 { + reg = <0>; + phandle = <0x2001>; + compatible = "subsubnode2", "subsubnode"; + prop-int = <0726746425>; + }; + + ss2 { + }; + }; +}; diff --git a/dtc/tests/testdata.h b/dtc/tests/testdata.h new file mode 100644 index 000000000..4f9e3ba07 --- /dev/null +++ b/dtc/tests/testdata.h @@ -0,0 +1,60 @@ +#ifdef __ASSEMBLY__ +#define ASM_CONST_LL(x) (x) +#else +#define ASM_CONST_LL(x) (x##ULL) +#endif + +#define TEST_ADDR_1H ASM_CONST_LL(0xdeadbeef) +#define TEST_ADDR_1L ASM_CONST_LL(0x00000000) +#define TEST_ADDR_1 ((TEST_ADDR_1H << 32) | TEST_ADDR_1L) +#define TEST_SIZE_1H ASM_CONST_LL(0x00000000) +#define TEST_SIZE_1L ASM_CONST_LL(0x00100000) +#define TEST_SIZE_1 ((TEST_SIZE_1H << 32) | TEST_SIZE_1L) +#define TEST_ADDR_2H ASM_CONST_LL(0) +#define TEST_ADDR_2L ASM_CONST_LL(123456789) +#define TEST_ADDR_2 ((TEST_ADDR_2H << 32) | TEST_ADDR_2L) +#define TEST_SIZE_2H ASM_CONST_LL(0) +#define TEST_SIZE_2L ASM_CONST_LL(010000) +#define TEST_SIZE_2 ((TEST_SIZE_2H << 32) | TEST_SIZE_2L) + +#define TEST_VALUE_1 0xdeadbeef +#define TEST_VALUE_2 123456789 + +#define TEST_VALUE64_1H ASM_CONST_LL(0xdeadbeef) +#define TEST_VALUE64_1L ASM_CONST_LL(0x01abcdef) +#define TEST_VALUE64_1 ((TEST_VALUE64_1H << 32) | TEST_VALUE64_1L) + +#define PHANDLE_1 0x2000 +#define PHANDLE_2 0x2001 + +#define TEST_STRING_1 "hello world" +#define TEST_STRING_2 "nastystring: \a\b\t\n\v\f\r\\\"" +#define TEST_STRING_3 "\xde\xad\xbe\xef" + +#define TEST_STRING_4_PARTIAL "foobar" +#define TEST_STRING_4_RESULT "testfoobar" + +#define TEST_CHAR1 '\r' +#define TEST_CHAR2 'b' +#define TEST_CHAR3 '\0' +#define TEST_CHAR4 '\'' +#define TEST_CHAR5 '\xff' + +#define TEST_MEMREGION_ADDR 0x12345678 +#define TEST_MEMREGION_ADDR_HI 0x8765432100000000 +#define TEST_MEMREGION_SIZE 0x9abcdef0 +#define TEST_MEMREGION_SIZE_HI 0x0fedcba900000000 +#define TEST_MEMREGION_SIZE_INC 0x1000 + +#ifndef __ASSEMBLY__ +extern struct fdt_header test_tree1; +extern struct fdt_header truncated_property; +extern struct fdt_header bad_node_char; +extern struct fdt_header bad_node_format; +extern struct fdt_header bad_prop_char; +extern struct fdt_header ovf_size_strings; +extern struct fdt_header truncated_string; +extern struct fdt_header truncated_memrsv; +extern struct fdt_header two_roots; +extern struct fdt_header named_root; +#endif /* ! __ASSEMBLY */ diff --git a/dtc/tests/tests.h b/dtc/tests/tests.h new file mode 100644 index 000000000..1017366b2 --- /dev/null +++ b/dtc/tests/tests.h @@ -0,0 +1,130 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#ifndef TESTS_H +#define TESTS_H +/* + * libfdt - Flat Device Tree manipulation + * Testcase definitions + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#define DEBUG + +/* Test return codes */ +#define RC_PASS 0 +#define RC_CONFIG 1 +#define RC_FAIL 2 +#define RC_BUG 99 + +extern int verbose_test; +extern char *test_name; +void test_init(int argc, char *argv[]); + +#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#define PALIGN(p, a) ((void *)ALIGN((unsigned long)(p), (a))) +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +#define streq(s1, s2) (strcmp((s1),(s2)) == 0) + +/* Each test case must define this function */ +void cleanup(void); + +#define verbose_printf(...) \ + if (verbose_test) { \ + printf(__VA_ARGS__); \ + fflush(stdout); \ + } +#define ERR "ERR: " +#define ERROR(fmt, args...) fprintf(stderr, ERR fmt, ## args) + + +#define PASS() \ + do { \ + cleanup(); \ + printf("PASS\n"); \ + exit(RC_PASS); \ + } while (0) + +#define PASS_INCONCLUSIVE() \ + do { \ + cleanup(); \ + printf("PASS (inconclusive)\n"); \ + exit(RC_PASS); \ + } while (0) + +#define IRRELEVANT() \ + do { \ + cleanup(); \ + printf("PASS (irrelevant)\n"); \ + exit(RC_PASS); \ + } while (0) + +/* Look out, gcc extension below... */ +#define FAIL(fmt, ...) \ + do { \ + cleanup(); \ + printf("FAIL\t" fmt "\n", ##__VA_ARGS__); \ + exit(RC_FAIL); \ + } while (0) + +#define CONFIG(fmt, ...) \ + do { \ + cleanup(); \ + printf("Bad configuration: " fmt "\n", ##__VA_ARGS__); \ + exit(RC_CONFIG); \ + } while (0) + +#define TEST_BUG(fmt, ...) \ + do { \ + cleanup(); \ + printf("BUG in testsuite: " fmt "\n", ##__VA_ARGS__); \ + exit(RC_BUG); \ + } while (0) + +void check_mem_rsv(void *fdt, int n, uint64_t addr, uint64_t size); + +void check_property(void *fdt, int nodeoffset, const char *name, + int len, const void *val); +#define check_property_cell(fdt, nodeoffset, name, val) \ + ({ \ + fdt32_t x = cpu_to_fdt32(val); \ + check_property(fdt, nodeoffset, name, sizeof(x), &x); \ + }) + + +const void *check_getprop(void *fdt, int nodeoffset, const char *name, + int len, const void *val); +#define check_getprop_cell(fdt, nodeoffset, name, val) \ + ({ \ + fdt32_t x = cpu_to_fdt32(val); \ + check_getprop(fdt, nodeoffset, name, sizeof(x), &x); \ + }) +#define check_getprop_64(fdt, nodeoffset, name, val) \ + ({ \ + fdt64_t x = cpu_to_fdt64(val); \ + check_getprop(fdt, nodeoffset, name, sizeof(x), &x); \ + }) +#define check_getprop_string(fdt, nodeoffset, name, s) \ + check_getprop((fdt), (nodeoffset), (name), strlen(s)+1, (s)) + +/* Returns non-NULL if the property at poffset has the name in_name */ +const void *check_get_prop_offset(void *fdt, int poffset, const char *in_name, + int in_len, const void *in_val); +#define check_get_prop_offset_cell(fdt, poffset, name, val) \ + ({ \ + fdt32_t x = cpu_to_fdt32(val); \ + check_get_prop_offset(fdt, poffset, name, sizeof(x), &x); \ + }) + +const void *check_getprop_addrrange(void *fdt, int parent, int nodeoffset, + const char *name, int num); + +int nodename_eq(const char *s1, const char *s2); +void vg_prepare_blob(void *fdt, size_t bufsize); +void *load_blob(const char *filename); +void *load_blob_arg(int argc, char *argv[]); +void save_blob(const char *filename, void *blob); +void *open_blob_rw(void *blob); + +#include "util.h" + +#endif /* TESTS_H */ diff --git a/dtc/tests/testutils.c b/dtc/tests/testutils.c new file mode 100644 index 000000000..5e494c559 --- /dev/null +++ b/dtc/tests/testutils.c @@ -0,0 +1,351 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase common utility functions + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#define _GNU_SOURCE /* for strsignal() in glibc. FreeBSD has it either way */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <limits.h> +#include <string.h> +#include <errno.h> +#include <signal.h> +#include <unistd.h> +#include <fcntl.h> + +#if NO_VALGRIND +static inline void VALGRIND_MAKE_MEM_UNDEFINED(void *p, size_t len) +{ +} + +static inline void VALGRIND_MAKE_MEM_DEFINED(void *p, size_t len) +{ +} +#else +#include <valgrind/memcheck.h> +#endif + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +/* For FDT_SW_MAGIC */ +#include "libfdt_internal.h" + +int verbose_test = 1; +char *test_name; + +void __attribute__((weak)) cleanup(void) +{ +} + +static void sigint_handler(int signum, siginfo_t *si, void *uc) +{ + cleanup(); + fprintf(stderr, "%s: %s (pid=%d)\n", test_name, + strsignal(signum), getpid()); + exit(RC_BUG); +} + +void test_init(int argc, char *argv[]) +{ + int err; + struct sigaction sa_int = { + .sa_sigaction = sigint_handler, + }; + + test_name = argv[0]; + + err = sigaction(SIGINT, &sa_int, NULL); + if (err) + FAIL("Can't install SIGINT handler"); + + if (getenv("QUIET_TEST")) + verbose_test = 0; + + verbose_printf("Starting testcase \"%s\", pid %d\n", + test_name, getpid()); +} + +void check_mem_rsv(void *fdt, int n, uint64_t addr, uint64_t size) +{ + int err; + uint64_t addr_v, size_v; + + err = fdt_get_mem_rsv(fdt, n, &addr_v, &size_v); + if (err < 0) + FAIL("fdt_get_mem_rsv(%d): %s", n, fdt_strerror(err)); + if ((addr_v != addr) || (size_v != size)) + FAIL("fdt_get_mem_rsv() returned (0x%llx,0x%llx) " + "instead of (0x%llx,0x%llx)", + (unsigned long long)addr_v, (unsigned long long)size_v, + (unsigned long long)addr, (unsigned long long)size); +} + +void check_property(void *fdt, int nodeoffset, const char *name, + int len, const void *val) +{ + const struct fdt_property *prop; + int retlen, namelen; + uint32_t tag, nameoff, proplen; + const char *propname; + + verbose_printf("Checking property \"%s\"...", name); + prop = fdt_get_property(fdt, nodeoffset, name, &retlen); + verbose_printf("pointer %p\n", prop); + if (! prop) + FAIL("Error retrieving \"%s\" pointer: %s", name, + fdt_strerror(retlen)); + + tag = fdt32_to_cpu(prop->tag); + nameoff = fdt32_to_cpu(prop->nameoff); + proplen = fdt32_to_cpu(prop->len); + + if (tag != FDT_PROP) + FAIL("Incorrect tag 0x%08x on property \"%s\"", tag, name); + + propname = fdt_get_string(fdt, nameoff, &namelen); + if (!propname) + FAIL("Couldn't get property name: %s", fdt_strerror(namelen)); + if (namelen != strlen(propname)) + FAIL("Incorrect prop name length: %d instead of %zd", + namelen, strlen(propname)); + if (!streq(propname, name)) + FAIL("Property name mismatch \"%s\" instead of \"%s\"", + propname, name); + if (proplen != retlen) + FAIL("Length retrieved for \"%s\" by fdt_get_property()" + " differs from stored length (%d != %d)", + name, retlen, proplen); + if (proplen != len) + FAIL("Size mismatch on property \"%s\": %d insead of %d", + name, proplen, len); + if (len && memcmp(val, prop->data, len) != 0) + FAIL("Data mismatch on property \"%s\"", name); +} + +const void *check_getprop(void *fdt, int nodeoffset, const char *name, + int len, const void *val) +{ + const void *propval; + int proplen; + + propval = fdt_getprop(fdt, nodeoffset, name, &proplen); + if (! propval) + FAIL("fdt_getprop(\"%s\"): %s", name, fdt_strerror(proplen)); + + if (proplen != len) + FAIL("Size mismatch on property \"%s\": %d insead of %d", + name, proplen, len); + if (len && memcmp(val, propval, len) != 0) + FAIL("Data mismatch on property \"%s\"", name); + + return propval; +} + +const void *check_get_prop_offset(void *fdt, int poffset, const char *exp_name, + int exp_len, const void *exp_val) +{ + const void *propval; + const char *name; + int proplen; + + propval = fdt_getprop_by_offset(fdt, poffset, &name, &proplen); + if (!propval) + FAIL("fdt_getprop(\"%s\"): %s", name, fdt_strerror(proplen)); + + /* Not testing for this field, so ignore */ + if (strcmp(name, exp_name)) + return NULL; + + if (proplen != exp_len) + FAIL("Size mismatch on property \"%s\": %d insead of %d", + name, proplen, exp_len); + if (exp_len && memcmp(exp_val, propval, exp_len)) + FAIL("Data mismatch on property \"%s\"", name); + + return propval; +} + +const void *check_getprop_addrrange(void *fdt, int parent, int nodeoffset, + const char *name, int num) +{ + const void *propval; + int xac, xsc, buf_size, cells, i; + char *buf, *p; + uint64_t addr, size; + fdt32_t val; + + xac = fdt_address_cells(fdt, parent); + xsc = fdt_size_cells(fdt, parent); + + if (xac <= 0) + FAIL("Couldn't identify #address-cells: %s", + fdt_strerror(xac)); + if (xsc <= 0) + FAIL("Couldn't identify #size-cells: %s", + fdt_strerror(xsc)); + + buf_size = (xac + xsc) * sizeof(fdt32_t) * num; + buf = malloc(buf_size); + if (!buf) + FAIL("Couldn't allocate temporary buffer"); + + /* expected value */ + addr = TEST_MEMREGION_ADDR; + if (xac > 1) + addr += TEST_MEMREGION_ADDR_HI; + size = TEST_MEMREGION_SIZE; + if (xsc > 1) + size += TEST_MEMREGION_SIZE_HI; + for (p = buf, i = 0; i < num; i++) { + cells = xac; + while (cells) { + val = cpu_to_fdt32(addr >> (32 * (--cells))); + memcpy(p, &val, sizeof(val)); + p += sizeof(val); + } + cells = xsc; + while (cells) { + val = cpu_to_fdt32(size >> (32 * (--cells))); + memcpy(p, &val, sizeof(val)); + p += sizeof(val); + } + + addr += size; + size += TEST_MEMREGION_SIZE_INC; + } + + /* check */ + propval = check_getprop(fdt, nodeoffset, name, buf_size, + (const void *)buf); + + free(buf); + + return propval; +} + +int nodename_eq(const char *s1, const char *s2) +{ + int len = strlen(s2); + + if (strncmp(s1, s2, len) != 0) + return 0; + if (s1[len] == '\0') + return 1; + else if (!memchr(s2, '@', len) && (s1[len] == '@')) + return 1; + else + return 0; +} + +void vg_prepare_blob(void *fdt, size_t bufsize) +{ + char *blob = fdt; + int off_memrsv, off_strings, off_struct; + int num_memrsv; + size_t size_memrsv, size_strings, size_struct; + + off_memrsv = fdt_off_mem_rsvmap(fdt); + num_memrsv = fdt_num_mem_rsv(fdt); + if (num_memrsv < 0) + size_memrsv = fdt_totalsize(fdt) - off_memrsv; + else + size_memrsv = (num_memrsv + 1) + * sizeof(struct fdt_reserve_entry); + + VALGRIND_MAKE_MEM_UNDEFINED(blob, bufsize); + VALGRIND_MAKE_MEM_DEFINED(blob, FDT_V1_SIZE); + VALGRIND_MAKE_MEM_DEFINED(blob, fdt_header_size(fdt)); + + if (fdt_magic(fdt) == FDT_MAGIC) { + off_strings = fdt_off_dt_strings(fdt); + if (fdt_version(fdt) >= 3) + size_strings = fdt_size_dt_strings(fdt); + else + size_strings = fdt_totalsize(fdt) - off_strings; + + off_struct = fdt_off_dt_struct(fdt); + if (fdt_version(fdt) >= 17) + size_struct = fdt_size_dt_struct(fdt); + else + size_struct = fdt_totalsize(fdt) - off_struct; + } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { + size_strings = fdt_size_dt_strings(fdt); + off_strings = fdt_off_dt_strings(fdt) - size_strings; + + off_struct = fdt_off_dt_struct(fdt); + size_struct = fdt_size_dt_struct(fdt); + size_struct = fdt_totalsize(fdt) - off_struct; + + } else { + CONFIG("Bad magic on vg_prepare_blob()"); + } + + VALGRIND_MAKE_MEM_DEFINED(blob + off_memrsv, size_memrsv); + VALGRIND_MAKE_MEM_DEFINED(blob + off_strings, size_strings); + VALGRIND_MAKE_MEM_DEFINED(blob + off_struct, size_struct); +} + +void *load_blob(const char *filename) +{ + char *blob; + size_t len; + int ret = utilfdt_read_err(filename, &blob, &len); + + if (ret) + CONFIG("Couldn't open blob from \"%s\": %s", filename, + strerror(ret)); + + vg_prepare_blob(blob, len); + + return blob; +} + +void *load_blob_arg(int argc, char *argv[]) +{ + if (argc != 2) + CONFIG("Usage: %s <dtb file>", argv[0]); + return load_blob(argv[1]); +} + +void save_blob(const char *filename, void *fdt) +{ + size_t size = fdt_totalsize(fdt); + void *tmp; + int ret; + + /* Make a temp copy of the blob so that valgrind won't check + * about uninitialized bits in the pieces between blocks */ + tmp = xmalloc(size); + fdt_move(fdt, tmp, size); + VALGRIND_MAKE_MEM_DEFINED(tmp, size); + ret = utilfdt_write_err(filename, tmp); + if (ret) + CONFIG("Couldn't write blob to \"%s\": %s", filename, + strerror(ret)); + free(tmp); +} + +void *open_blob_rw(void *blob) +{ + int err; + void *buf = blob; + + err = fdt_open_into(blob, buf, fdt_totalsize(blob)); + if (err == -FDT_ERR_NOSPACE) { + /* Ran out of space converting to v17 */ + int newsize = fdt_totalsize(blob) + 8; + + buf = xmalloc(newsize); + err = fdt_open_into(blob, buf, newsize); + } + if (err) + FAIL("fdt_open_into(): %s", fdt_strerror(err)); + return buf; +} diff --git a/dtc/tests/testutils.sh b/dtc/tests/testutils.sh new file mode 100644 index 000000000..6b2f0d14e --- /dev/null +++ b/dtc/tests/testutils.sh @@ -0,0 +1,67 @@ +# Common functions for shell testcases + +PASS () { + echo "PASS" + exit 0 +} + +FAIL () { + echo "FAIL" "$@" + exit 2 +} + +FAIL_IF_SIGNAL () { + ret="$1" + if [ "$ret" -gt 127 ]; then + signame=$(kill -l $((ret - 128))) + FAIL "Killed by SIG$signame" + fi +} + +if [ -z "$TEST_BINDIR" ]; then + TEST_BINDIR=.. +fi + +DTC=${TEST_BINDIR}/dtc +DTGET=${TEST_BINDIR}/fdtget +DTPUT=${TEST_BINDIR}/fdtput +FDTDUMP=${TEST_BINDIR}/fdtdump +FDTOVERLAY=${TEST_BINDIR}/fdtoverlay + +verbose_run () { + if [ -z "$QUIET_TEST" ]; then + "$@" + else + "$@" > /dev/null 2> /dev/null + fi +} + +verbose_run_check () { + verbose_run "$@" + ret="$?" + FAIL_IF_SIGNAL $ret + if [ $ret != 0 ]; then + FAIL "Returned error code $ret" + fi +} + +verbose_run_log () { + LOG="$1" + shift + "$@" > "$LOG" 2>&1 + ret=$? + if [ -z "$QUIET_TEST" ]; then + cat "$LOG" >&2 + fi + return $ret +} + +verbose_run_log_check () { + verbose_run_log "$@" + ret="$?" + FAIL_IF_SIGNAL $ret + if [ $ret != 0 ]; then + FAIL "Returned error code $ret" + fi +} + diff --git a/dtc/tests/trees.S b/dtc/tests/trees.S new file mode 100644 index 000000000..95d599d68 --- /dev/null +++ b/dtc/tests/trees.S @@ -0,0 +1,315 @@ +#include <fdt.h> +#include "testdata.h" + +#define FDTLONG(val) \ + .byte ((val) >> 24) & 0xff ; \ + .byte ((val) >> 16) & 0xff ; \ + .byte ((val) >> 8) & 0xff ; \ + .byte (val) & 0xff ; + +#define TREE_HDR(tree) \ + .balign 8 ; \ + .globl tree ; \ +tree: \ + FDTLONG(FDT_MAGIC) ; \ + FDTLONG(tree##_end - tree) ; \ + FDTLONG(tree##_struct - tree) ; \ + FDTLONG(tree##_strings - tree) ; \ + FDTLONG(tree##_rsvmap - tree) ; \ + FDTLONG(0x11) ; \ + FDTLONG(0x10) ; \ + FDTLONG(0) ; \ + FDTLONG(tree##_strings_end - tree##_strings) ; \ + FDTLONG(tree##_struct_end - tree##_struct) ; + +#define RSVMAP_ENTRY(addrh, addrl, lenh, lenl) \ + FDTLONG(addrh) ; \ + FDTLONG(addrl) ; \ + FDTLONG(lenh) ; \ + FDTLONG(lenl) + +#define EMPTY_RSVMAP(tree) \ + .balign 8 ; \ +tree##_rsvmap: ; \ + RSVMAP_ENTRY(0, 0, 0, 0) \ +tree##_rsvmap_end: ; + +#define PROPHDR(tree, name, len) \ + FDTLONG(FDT_PROP) ; \ + FDTLONG(len) ; \ + FDTLONG(tree##_##name - tree##_strings) ; + +#define PROP_EMPTY(tree, name) \ + PROPHDR(tree, name, 0) ; + +#define PROP_INT(tree, name, val) \ + PROPHDR(tree, name, 4) \ + FDTLONG(val) ; + +#define PROP_INT64(tree, name, valh, vall) \ + PROPHDR(tree, name, 8) \ + FDTLONG(valh) ; \ + FDTLONG(vall) ; + +#define PROP_STR(tree, name, str) \ + PROPHDR(tree, name, 55f - 54f) \ +54: \ + .string str ; \ +55: \ + .balign 4 ; + +#define BEGIN_NODE(name) \ + FDTLONG(FDT_BEGIN_NODE) ; \ + .string name ; \ + .balign 4 ; + +#define END_NODE \ + FDTLONG(FDT_END_NODE) ; + +#define STRING(tree, name, str) \ +tree##_##name: ; \ + .string str ; + + .data + + TREE_HDR(test_tree1) + + .balign 8 +test_tree1_rsvmap: + RSVMAP_ENTRY(TEST_ADDR_1H, TEST_ADDR_1L, TEST_SIZE_1H, TEST_SIZE_1L) + RSVMAP_ENTRY(TEST_ADDR_2H, TEST_ADDR_2L, TEST_SIZE_2H, TEST_SIZE_2L) + RSVMAP_ENTRY(0, 0, 0, 0) +test_tree1_rsvmap_end: + +test_tree1_struct: + BEGIN_NODE("") + PROP_STR(test_tree1, compatible, "test_tree1") + PROP_INT(test_tree1, prop_int, TEST_VALUE_1) + PROP_INT64(test_tree1, prop_int64, TEST_VALUE64_1H, TEST_VALUE64_1L) + PROP_STR(test_tree1, prop_str, TEST_STRING_1) + PROP_INT(test_tree1, address_cells, 1) + PROP_INT(test_tree1, size_cells, 0) + + BEGIN_NODE("subnode@1") + PROP_STR(test_tree1, compatible, "subnode1") + PROP_INT(test_tree1, reg, 1) + PROP_INT(test_tree1, prop_int, TEST_VALUE_1) + + BEGIN_NODE("subsubnode") + PROP_STR(test_tree1, compatible, "subsubnode1\0subsubnode") + PROP_STR(test_tree1, placeholder, "this is a placeholder string\0string2") + PROP_INT(test_tree1, prop_int, TEST_VALUE_1) + END_NODE + + BEGIN_NODE("ss1") + END_NODE + + END_NODE + + BEGIN_NODE("subnode@2") + PROP_INT(test_tree1, reg, 2) + PROP_INT(test_tree1, linux_phandle, PHANDLE_1) + PROP_INT(test_tree1, prop_int, TEST_VALUE_2) + PROP_INT(test_tree1, address_cells, 1) + PROP_INT(test_tree1, size_cells, 0) + + BEGIN_NODE("subsubnode@0") + PROP_INT(test_tree1, reg, 0) + PROP_INT(test_tree1, phandle, PHANDLE_2) + PROP_STR(test_tree1, compatible, "subsubnode2\0subsubnode") + PROP_INT(test_tree1, prop_int, TEST_VALUE_2) + END_NODE + + BEGIN_NODE("ss2") + END_NODE + + END_NODE + + END_NODE + FDTLONG(FDT_END) +test_tree1_struct_end: + +test_tree1_strings: + STRING(test_tree1, compatible, "compatible") + STRING(test_tree1, prop_int, "prop-int") + STRING(test_tree1, prop_int64, "prop-int64") + STRING(test_tree1, prop_str, "prop-str") + STRING(test_tree1, linux_phandle, "linux,phandle") + STRING(test_tree1, phandle, "phandle") + STRING(test_tree1, reg, "reg") + STRING(test_tree1, placeholder, "placeholder") + STRING(test_tree1, address_cells, "#address-cells") + STRING(test_tree1, size_cells, "#size-cells") +test_tree1_strings_end: +test_tree1_end: + + + TREE_HDR(truncated_property) + EMPTY_RSVMAP(truncated_property) + +truncated_property_struct: + BEGIN_NODE("") + PROPHDR(truncated_property, prop_truncated, 4) + /* Oops, no actual property data here */ +truncated_property_struct_end: + +truncated_property_strings: + STRING(truncated_property, prop_truncated, "truncated") +truncated_property_strings_end: + +truncated_property_end: + + + TREE_HDR(bad_node_char) + EMPTY_RSVMAP(bad_node_char) + +bad_node_char_struct: + BEGIN_NODE("") + BEGIN_NODE("sub$node") + END_NODE + END_NODE + FDTLONG(FDT_END) +bad_node_char_struct_end: + +bad_node_char_strings: +bad_node_char_strings_end: +bad_node_char_end: + + + TREE_HDR(bad_node_format) + EMPTY_RSVMAP(bad_node_format) + +bad_node_format_struct: + BEGIN_NODE("") + BEGIN_NODE("subnode@1@2") + END_NODE + END_NODE + FDTLONG(FDT_END) +bad_node_format_struct_end: + +bad_node_format_strings: +bad_node_format_strings_end: +bad_node_format_end: + + + TREE_HDR(bad_prop_char) + EMPTY_RSVMAP(bad_prop_char) + +bad_prop_char_struct: + BEGIN_NODE("") + PROP_INT(bad_prop_char, prop, TEST_VALUE_1) + END_NODE + FDTLONG(FDT_END) +bad_prop_char_struct_end: + +bad_prop_char_strings: + STRING(bad_prop_char, prop, "prop$erty") +bad_prop_char_strings_end: +bad_prop_char_end: + + + /* overflow_size_strings */ + .balign 8 + .globl ovf_size_strings +ovf_size_strings: + FDTLONG(FDT_MAGIC) + FDTLONG(ovf_size_strings_end - ovf_size_strings) + FDTLONG(ovf_size_strings_struct - ovf_size_strings) + FDTLONG(ovf_size_strings_strings - ovf_size_strings) + FDTLONG(ovf_size_strings_rsvmap - ovf_size_strings) + FDTLONG(0x11) + FDTLONG(0x10) + FDTLONG(0) + FDTLONG(0xffffffff) + FDTLONG(ovf_size_strings_struct_end - ovf_size_strings_struct) + EMPTY_RSVMAP(ovf_size_strings) + +ovf_size_strings_struct: + BEGIN_NODE("") + PROP_INT(ovf_size_strings, bad_string, 0) + END_NODE + FDTLONG(FDT_END) +ovf_size_strings_struct_end: + +ovf_size_strings_strings: + STRING(ovf_size_strings, x, "x") + ovf_size_strings_bad_string = ovf_size_strings_strings + 0x10000000 +ovf_size_strings_strings_end: +ovf_size_strings_end: + + + /* truncated_string */ + TREE_HDR(truncated_string) + EMPTY_RSVMAP(truncated_string) + +truncated_string_struct: + BEGIN_NODE("") + PROP_EMPTY(truncated_string, good_string) + PROP_EMPTY(truncated_string, bad_string) + END_NODE + FDTLONG(FDT_END) +truncated_string_struct_end: + +truncated_string_strings: + STRING(truncated_string, good_string, "good") +truncated_string_bad_string: + .byte 'b' + .byte 'a' + .byte 'd' + /* NOTE: terminating \0 deliberately missing */ +truncated_string_strings_end: +truncated_string_end: + + + /* truncated_memrsv */ + TREE_HDR(truncated_memrsv) + +truncated_memrsv_struct: + BEGIN_NODE("") + END_NODE + FDTLONG(FDT_END) +truncated_memrsv_struct_end: + +truncated_memrsv_strings: +truncated_memrsv_strings_end: + + .balign 8 +truncated_memrsv_rsvmap: + RSVMAP_ENTRY(TEST_ADDR_1H, TEST_ADDR_1L, TEST_SIZE_1H, TEST_SIZE_1L) +truncated_memrsv_rsvmap_end: + +truncated_memrsv_end: + + + /* two root nodes */ + TREE_HDR(two_roots) + EMPTY_RSVMAP(two_roots) + +two_roots_struct: + BEGIN_NODE("") + END_NODE + BEGIN_NODE("") + END_NODE + FDTLONG(FDT_END) +two_roots_struct_end: + +two_roots_strings: +two_roots_strings_end: + +two_roots_end: + + + /* root node with a non-empty name */ + TREE_HDR(named_root) + EMPTY_RSVMAP(named_root) + +named_root_struct: + BEGIN_NODE("fake") + END_NODE + FDTLONG(FDT_END) +named_root_struct_end: + +named_root_strings: +named_root_strings_end: + +named_root_end: diff --git a/dtc/tests/truncated_memrsv.c b/dtc/tests/truncated_memrsv.c new file mode 100644 index 000000000..d78036cc9 --- /dev/null +++ b/dtc/tests/truncated_memrsv.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for misbehaviour on a truncated string + * Copyright (C) 2018 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +int main(int argc, char *argv[]) +{ + void *fdt = &truncated_memrsv; + int err; + uint64_t addr, size; + + test_init(argc, argv); + + err = fdt_check_header(fdt); + if (err != 0) + FAIL("Bad header: %s", fdt_strerror(err)); + + err = fdt_num_mem_rsv(fdt); + if (err != -FDT_ERR_TRUNCATED) + FAIL("fdt_num_mem_rsv() returned %d instead of -FDT_ERR_TRUNCATED", + err); + + err = fdt_get_mem_rsv(fdt, 0, &addr, &size); + if (err != 0) + FAIL("fdt_get_mem_rsv() failed on first entry: %s", + fdt_strerror(err)); + if ((addr != TEST_ADDR_1) || (size != TEST_SIZE_1)) + FAIL("Entry doesn't match: (0x%llx, 0x%llx) != (0x%llx, 0x%llx)", + (unsigned long long)addr, (unsigned long long)size, + TEST_ADDR_1, TEST_SIZE_1); + + err = fdt_get_mem_rsv(fdt, 1, &addr, &size); + if (err != -FDT_ERR_BADOFFSET) + FAIL("fdt_get_mem_rsv(1) returned %d instead of -FDT_ERR_BADOFFSET", + err); + + PASS(); +} diff --git a/dtc/tests/truncated_property.c b/dtc/tests/truncated_property.c new file mode 100644 index 000000000..d9d52b2f3 --- /dev/null +++ b/dtc/tests/truncated_property.c @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for misbehaviour on a truncated property + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +int main(int argc, char *argv[]) +{ + void *fdt = &truncated_property; + const void *prop; + int len; + + test_init(argc, argv); + + vg_prepare_blob(fdt, fdt_totalsize(fdt)); + + prop = fdt_getprop(fdt, 0, "truncated", &len); + if (prop) + FAIL("fdt_getprop() succeeded on truncated property"); + if (len != -FDT_ERR_BADSTRUCTURE) + FAIL("fdt_getprop() failed with \"%s\" instead of \"%s\"", + fdt_strerror(len), fdt_strerror(-FDT_ERR_BADSTRUCTURE)); + + PASS(); +} diff --git a/dtc/tests/truncated_string.c b/dtc/tests/truncated_string.c new file mode 100644 index 000000000..d7454147b --- /dev/null +++ b/dtc/tests/truncated_string.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for misbehaviour on a truncated string + * Copyright (C) 2018 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +int main(int argc, char *argv[]) +{ + void *fdt = &truncated_string; + const struct fdt_property *good, *bad; + int off, len; + const char *name; + + test_init(argc, argv); + + vg_prepare_blob(fdt, fdt_totalsize(fdt)); + + off = fdt_first_property_offset(fdt, 0); + good = fdt_get_property_by_offset(fdt, off, NULL); + + off = fdt_next_property_offset(fdt, off); + bad = fdt_get_property_by_offset(fdt, off, NULL); + + if (fdt32_to_cpu(good->len) != 0) + FAIL("Unexpected length for good property"); + name = fdt_get_string(fdt, fdt32_to_cpu(good->nameoff), &len); + if (!name) + FAIL("fdt_get_string() failed on good property: %s", + fdt_strerror(len)); + if (len != 4) + FAIL("fdt_get_string() returned length %d (not 4) on good property", + len); + if (!streq(name, "good")) + FAIL("fdt_get_string() returned \"%s\" (not \"good\") on good property", + name); + + if (fdt32_to_cpu(bad->len) != 0) + FAIL("Unexpected length for bad property\n"); + name = fdt_get_string(fdt, fdt32_to_cpu(bad->nameoff), &len); + if (name) + FAIL("fdt_get_string() succeeded incorrectly on bad property"); + else if (len != -FDT_ERR_TRUNCATED) + FAIL("fdt_get_string() gave unexpected error on bad property: %s", + fdt_strerror(len)); + + /* Make sure the 'good' property breaks correctly if we + * truncate the strings section */ + fdt_set_size_dt_strings(fdt, fdt32_to_cpu(good->nameoff) + 4); + name = fdt_get_string(fdt, fdt32_to_cpu(good->nameoff), &len); + if (name) + FAIL("fdt_get_string() succeeded incorrectly on mangled property"); + else if (len != -FDT_ERR_TRUNCATED) + FAIL("fdt_get_string() gave unexpected error on mangled property: %s", + fdt_strerror(len)); + + PASS(); +} diff --git a/dtc/tests/type-preservation.dt.yaml b/dtc/tests/type-preservation.dt.yaml new file mode 100644 index 000000000..ee8cfdebe --- /dev/null +++ b/dtc/tests/type-preservation.dt.yaml @@ -0,0 +1,20 @@ +--- +- '#address-cells': [[0x1]] + '#size-cells': [[0x0]] + subnode@1: + compatible: ["subnode1"] + reg: [[0x1]] + int-array: [[0x0, 0x1], [0x2, 0x3]] + int8: [!u8 [0x56]] + int8-array: [!u8 [0x0, 0x12, 0x34, 0x56]] + int16: [!u16 [0x3210]] + int16-array: [!u16 [0x1234, 0x5678, 0x90ab, 0xcdef]] + int16-matrix: [!u16 [0x1234, 0x5678], [0x90ab, 0xcdef]] + int64: [!u64 [0x200000000]] + int64-array: [!u64 [0x100000000, 0x0]] + a-string-with-nulls: ["foo\0bar", "baz"] + subsubnode: + compatible: ["subsubnode1", "subsubnode"] + subsubsubnode: + compatible: ["subsubsubnode1", [0x1234], "subsubsubnode"] +... diff --git a/dtc/tests/type-preservation.dts b/dtc/tests/type-preservation.dts new file mode 100644 index 000000000..3e380ba6c --- /dev/null +++ b/dtc/tests/type-preservation.dts @@ -0,0 +1,28 @@ +/dts-v1/; + +/ { + #address-cells = <0x01>; + #size-cells = <0x00>; + + sub1: subnode@1 { + prop_label: compatible = value_label: "subnode1"; + reg = <0x01>; + int-array = <0x00 0x01>, int_value_label: <0x02 0x03>; + int8 = [56]; + int8-array = [00 12 34 56] label:; + int16 = /bits/ 16 <0x3210>; + int16-array = /bits/ 16 <0x1234 0x5678 0x90ab 0xcdef>; + int16-matrix = /bits/ 16 <0x1234 0x5678>, <0x90ab 0xcdef>; + int64 = /bits/ 64 <0x200000000>; + int64-array = /bits/ 64 <0x100000000 0x00> int64_array_label_end:; + a-string-with-nulls = "foo\0bar", "baz"; + + subsub1: subsubnode { + compatible = "subsubnode1", "subsubnode"; + + subsubsub1: subsubsubnode { + compatible = "subsubsubnode1", <0x1234>, valuea: valueb: "subsubsubnode"; + }; + }; + }; +}; diff --git a/dtc/tests/unit-addr-leading-0s.dts b/dtc/tests/unit-addr-leading-0s.dts new file mode 100644 index 000000000..cc017e943 --- /dev/null +++ b/dtc/tests/unit-addr-leading-0s.dts @@ -0,0 +1,12 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + bus { + node@001 { + reg = <1 0>; + }; + }; +}; diff --git a/dtc/tests/unit-addr-leading-0x.dts b/dtc/tests/unit-addr-leading-0x.dts new file mode 100644 index 000000000..74f19678c --- /dev/null +++ b/dtc/tests/unit-addr-leading-0x.dts @@ -0,0 +1,12 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + bus { + node@0x1 { + reg = <1 0>; + }; + }; +}; diff --git a/dtc/tests/unit-addr-simple-bus-compatible.dts b/dtc/tests/unit-addr-simple-bus-compatible.dts new file mode 100644 index 000000000..c8f9341c1 --- /dev/null +++ b/dtc/tests/unit-addr-simple-bus-compatible.dts @@ -0,0 +1,18 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + bus@10000000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "foo-bus", "simple-bus"; + ranges = <0x0 0x10000000 0x10000>; + + node@100 { + reg = <0x1000 1>; + }; + }; + +}; diff --git a/dtc/tests/unit-addr-simple-bus-reg-mismatch.dts b/dtc/tests/unit-addr-simple-bus-reg-mismatch.dts new file mode 100644 index 000000000..282337770 --- /dev/null +++ b/dtc/tests/unit-addr-simple-bus-reg-mismatch.dts @@ -0,0 +1,18 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + bus@10000000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges = <0x0 0x10000000 0x10000>; + + node@100 { + reg = <0x1000 1>; + }; + }; + +}; diff --git a/dtc/tests/unit-addr-unique.dts b/dtc/tests/unit-addr-unique.dts new file mode 100644 index 000000000..7cc650b40 --- /dev/null +++ b/dtc/tests/unit-addr-unique.dts @@ -0,0 +1,14 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <0>; + + foo@1 { + reg = <1>; + }; + + bar@1 { + reg = <1>; + }; +}; diff --git a/dtc/tests/unit-addr-without-reg.dts b/dtc/tests/unit-addr-without-reg.dts new file mode 100644 index 000000000..ac786ebb6 --- /dev/null +++ b/dtc/tests/unit-addr-without-reg.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + node@1 { + }; +}; diff --git a/dtc/tests/utilfdt_test.c b/dtc/tests/utilfdt_test.c new file mode 100644 index 000000000..c62175935 --- /dev/null +++ b/dtc/tests/utilfdt_test.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright 2011 The Chromium Authors, All Rights Reserved. + * + * utilfdt_test - Tests for utilfdt library + */ +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <stdarg.h> + +#include <libfdt.h> +#include <util.h> + +#include "tests.h" +#include "testdata.h" + +static void check(const char *fmt, int expect_type, int expect_size) +{ + int type; + int size; + + if (utilfdt_decode_type(fmt, &type, &size)) + FAIL("format '%s': valid format string returned failure", fmt); + if (expect_type != type) + FAIL("format '%s': expected type='%c', got type='%c'", fmt, + expect_type, type); + if (expect_size != size) + FAIL("format '%s': expected size=%d, got size=%d", fmt, + expect_size, size); +} + +static void checkfail(const char *fmt) +{ + int type; + int size; + + if (!utilfdt_decode_type(fmt, &type, &size)) + FAIL("format '%s': invalid format string returned success", + fmt); +} + +/** + * Add the given modifier to each of the valid sizes, and check that we get + * correct values. + * + * \param modifier Modifer string to use as a prefix + * \param expected_size The size (in bytes) that we expect (ignored for + * strings) + */ +static void check_sizes(char *modifier, int expected_size) +{ + char fmt[10], *ptr; + + /* set up a string with a hole in it for the format character */ + if (strlen(modifier) + 2 >= sizeof(fmt)) + FAIL("modifier string '%s' too long", modifier); + strcpy(fmt, modifier); + ptr = fmt + strlen(fmt); + ptr[1] = '\0'; + + /* now try each format character in turn */ + *ptr = 'i'; + check(fmt, 'i', expected_size); + + *ptr = 'u'; + check(fmt, 'u', expected_size); + + *ptr = 'x'; + check(fmt, 'x', expected_size); + + *ptr = 's'; + check(fmt, 's', -1); +} + +static void test_utilfdt_decode_type(void) +{ + char fmt[10]; + int ch; + + /* check all the valid modifiers and sizes */ + check_sizes("", -1); + check_sizes("b", 1); + check_sizes("hh", 1); + check_sizes("h", 2); + check_sizes("l", 4); + + /* try every other character */ + checkfail(""); + for (ch = ' '; ch < 127; ch++) { + if (!strchr("iuxs", ch)) { + *fmt = ch; + fmt[1] = '\0'; + checkfail(fmt); + } + } + + /* try a few modifiers at the end */ + checkfail("sx"); + checkfail("ihh"); + checkfail("xb"); + + /* and one for the doomsday archives */ + checkfail("He has all the virtues I dislike and none of the vices " + "I admire."); +} + +int main(int argc, char *argv[]) +{ + test_utilfdt_decode_type(); + PASS(); +} diff --git a/dtc/tests/value-labels.c b/dtc/tests/value-labels.c new file mode 100644 index 000000000..e3183574d --- /dev/null +++ b/dtc/tests/value-labels.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Test labels within values + * Copyright (C) 2008 David Gibson, IBM Corporation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <errno.h> + +#include <dlfcn.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +struct val_label { + const char *labelname; + int propoff; +}; + +static struct val_label labels1[] = { + { "start1", 0 }, + { "mid1", 2 }, + { "end1", -1 }, +}; + +static struct val_label labels2[] = { + { "start2", 0 }, + { "innerstart2", 0 }, + { "innermid2", 4 }, + { "innerend2", -1 }, + { "end2", -1 }, +}; + +static struct val_label labels3[] = { + { "start3", 0 }, + { "innerstart3", 0 }, + { "innermid3", 1 }, + { "innerend3", -1 }, + { "end3", -1 }, +}; + +static void check_prop_labels(void *sohandle, void *fdt, const char *name, + const struct val_label* labels, int n) +{ + const struct fdt_property *prop; + const char *p; + int len; + int i; + + prop = fdt_get_property(fdt, 0, name, &len); + if (!prop) + FAIL("Couldn't locate property \"%s\"", name); + + p = dlsym(sohandle, name); + if (!p) + FAIL("Couldn't locate label symbol \"%s\"", name); + + if (p != (const char *)prop) + FAIL("Label \"%s\" does not point to correct property", name); + + for (i = 0; i < n; i++) { + int off = labels[i].propoff; + + if (off == -1) + off = len; + + p = dlsym(sohandle, labels[i].labelname); + if (!p) + FAIL("Couldn't locate label symbol \"%s\"", name); + + if ((p - prop->data) != off) + FAIL("Label \"%s\" points to offset %ld instead of %d" + "in property \"%s\"", labels[i].labelname, + (long)(p - prop->data), off, name); + } +} + +int main(int argc, char *argv[]) +{ + void *sohandle; + void *fdt; + int err; + + test_init(argc, argv); + if (argc != 2) + CONFIG("Usage: %s <so file>", argv[0]); + + sohandle = dlopen(argv[1], RTLD_NOW); + if (!sohandle) + FAIL("Couldn't dlopen() %s", argv[1]); + + fdt = dlsym(sohandle, "dt_blob_start"); + if (!fdt) + FAIL("Couldn't locate \"dt_blob_start\" symbol in %s", + argv[1]); + + err = fdt_check_header(fdt); + if (err != 0) + FAIL("%s contains invalid tree: %s", argv[1], + fdt_strerror(err)); + + + check_prop_labels(sohandle, fdt, "prop1", labels1, ARRAY_SIZE(labels1)); + check_prop_labels(sohandle, fdt, "prop2", labels2, ARRAY_SIZE(labels2)); + check_prop_labels(sohandle, fdt, "prop3", labels3, ARRAY_SIZE(labels3)); + + PASS(); +} diff --git a/dtc/tests/value-labels.dts b/dtc/tests/value-labels.dts new file mode 100644 index 000000000..490c609f7 --- /dev/null +++ b/dtc/tests/value-labels.dts @@ -0,0 +1,8 @@ +/dts-v1/; + +/ { + prop1: prop1 = start1: "a", mid1: "b" end1:; + prop2: prop2 = start2: < innerstart2: 0xdeadbeef innermid2: 0xabcd1234 innerend2: > end2:; + prop3: prop3 = start3: [ innerstart3: ab innermid3: cd innerend3: ] end3:; +}; + diff --git a/dtc/tests/zero-phandle.dts b/dtc/tests/zero-phandle.dts new file mode 100644 index 000000000..7997d980d --- /dev/null +++ b/dtc/tests/zero-phandle.dts @@ -0,0 +1,7 @@ +/dts-v1/; + +/ { + node { + linux,phandle = <0>; + }; +}; |