From f2a9942fbc47491cc5f5151670c42d43dc0544cb Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 5 Jul 2016 10:26:46 +0200 Subject: tests: Introduce DT overlay tests This adds a bunch of unit tests for the "fdt apply" command. They've all been run successfully in the sandbox. However, as you still require an out-of-tree dtc with overlay support, this is disabled by default. Acked-by: Simon Glass Acked-by: Pantelis Antoniou Signed-off-by: Maxime Ripard --- test/overlay/Kconfig | 11 ++ test/overlay/Makefile | 15 +++ test/overlay/cmd_ut_overlay.c | 268 ++++++++++++++++++++++++++++++++++++++ test/overlay/test-fdt-base.dts | 21 +++ test/overlay/test-fdt-overlay.dts | 96 ++++++++++++++ 5 files changed, 411 insertions(+) create mode 100644 test/overlay/Kconfig create mode 100644 test/overlay/Makefile create mode 100644 test/overlay/cmd_ut_overlay.c create mode 100644 test/overlay/test-fdt-base.dts create mode 100644 test/overlay/test-fdt-overlay.dts (limited to 'test/overlay') diff --git a/test/overlay/Kconfig b/test/overlay/Kconfig new file mode 100644 index 00000000000..13c85428cba --- /dev/null +++ b/test/overlay/Kconfig @@ -0,0 +1,11 @@ +config UT_OVERLAY + bool "Enable Device Tree Overlays Unit Tests" + depends on OF_LIBFDT_OVERLAY + depends on UNIT_TEST + help + This enables the 'ut overlay' command which runs a series of unit + tests on the fdt overlay code. + If all is well then all tests pass although there will be a few + messages printed along the way. + Be warned that it requires an out-of-tree dtc compiler with patches + to support the DT overlays, otherwise it will fail. diff --git a/test/overlay/Makefile b/test/overlay/Makefile new file mode 100644 index 00000000000..907f0854461 --- /dev/null +++ b/test/overlay/Makefile @@ -0,0 +1,15 @@ +# +# Copyright (c) 2016 NextThing Co +# Copyright (c) 2016 Free Electrons +# +# SPDX-License-Identifier: GPL-2.0+ +# + +# Test files +obj-y += cmd_ut_overlay.o + +DTC_FLAGS += -@ + +# DT overlays +obj-y += test-fdt-base.dtb.o +obj-y += test-fdt-overlay.dtb.o diff --git a/test/overlay/cmd_ut_overlay.c b/test/overlay/cmd_ut_overlay.c new file mode 100644 index 00000000000..87dc9328c67 --- /dev/null +++ b/test/overlay/cmd_ut_overlay.c @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +#include + +#include +#include + +/* 4k ought to be enough for anybody */ +#define FDT_COPY_SIZE (4 * SZ_1K) + +extern u32 __dtb_test_fdt_base_begin; +extern u32 __dtb_test_fdt_overlay_begin; + +static int fdt_getprop_u32_by_index(void *fdt, const char *path, + const char *name, int index, + u32 *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) * (index + 1)))) + return -FDT_ERR_NOTFOUND; + + *out = fdt32_to_cpu(*(val + index)); + + return 0; +} + +static int fdt_getprop_u32(void *fdt, const char *path, const char *name, + u32 *out) +{ + return fdt_getprop_u32_by_index(fdt, path, name, 0, out); +} + +static int fdt_getprop_str(void *fdt, const char *path, const char *name, + const char **out) +{ + int node_off; + + node_off = fdt_path_offset(fdt, path); + if (node_off < 0) + return node_off; + + return fdt_get_string(fdt, node_off, name, out); +} + +static int fdt_overlay_change_int_property(struct unit_test_state *uts) +{ + void *fdt = uts->priv; + u32 val = 0; + + ut_assertok(fdt_getprop_u32(fdt, "/test-node", "test-int-property", + &val)); + ut_asserteq(43, val); + + return CMD_RET_SUCCESS; +} +OVERLAY_TEST(fdt_overlay_change_int_property, 0); + +static int fdt_overlay_change_str_property(struct unit_test_state *uts) +{ + void *fdt = uts->priv; + const char *val = NULL; + + ut_assertok(fdt_getprop_str(fdt, "/test-node", "test-str-property", + &val)); + ut_asserteq_str("foobar", val); + + return CMD_RET_SUCCESS; +} +OVERLAY_TEST(fdt_overlay_change_str_property, 0); + +static int fdt_overlay_add_str_property(struct unit_test_state *uts) +{ + void *fdt = uts->priv; + const char *val = NULL; + + ut_assertok(fdt_getprop_str(fdt, "/test-node", "test-str-property-2", + &val)); + ut_asserteq_str("foobar2", val); + + return CMD_RET_SUCCESS; +} +OVERLAY_TEST(fdt_overlay_add_str_property, 0); + +static int fdt_overlay_add_node_by_phandle(struct unit_test_state *uts) +{ + void *fdt = uts->priv; + int off; + + off = fdt_path_offset(fdt, "/test-node/new-node"); + ut_assert(off >= 0); + + ut_assertnonnull(fdt_getprop(fdt, off, "new-property", NULL)); + + return CMD_RET_SUCCESS; +} +OVERLAY_TEST(fdt_overlay_add_node_by_phandle, 0); + +static int fdt_overlay_add_node_by_path(struct unit_test_state *uts) +{ + void *fdt = uts->priv; + int off; + + off = fdt_path_offset(fdt, "/new-node"); + ut_assert(off >= 0); + + ut_assertnonnull(fdt_getprop(fdt, off, "new-property", NULL)); + + return CMD_RET_SUCCESS; +} +OVERLAY_TEST(fdt_overlay_add_node_by_path, 0); + +static int fdt_overlay_add_subnode_property(struct unit_test_state *uts) +{ + void *fdt = uts->priv; + int off; + + off = fdt_path_offset(fdt, "/test-node/sub-test-node"); + ut_assert(off >= 0); + + ut_assertnonnull(fdt_getprop(fdt, off, "sub-test-property", NULL)); + ut_assertnonnull(fdt_getprop(fdt, off, "new-sub-test-property", NULL)); + + return CMD_RET_SUCCESS; +} +OVERLAY_TEST(fdt_overlay_add_subnode_property, 0); + +static int fdt_overlay_local_phandle(struct unit_test_state *uts) +{ + uint32_t local_phandle; + void *fdt = uts->priv; + u32 val = 0; + int off; + + off = fdt_path_offset(fdt, "/new-local-node"); + ut_assert(off >= 0); + + local_phandle = fdt_get_phandle(fdt, off); + ut_assert(local_phandle); + + ut_assertok(fdt_getprop_u32_by_index(fdt, "/", "test-several-phandle", + 0, &val)); + ut_asserteq(local_phandle, val); + + ut_assertok(fdt_getprop_u32_by_index(fdt, "/", "test-several-phandle", + 1, &val)); + ut_asserteq(local_phandle, val); + + return CMD_RET_SUCCESS; +} +OVERLAY_TEST(fdt_overlay_local_phandle, 0); + +static int fdt_overlay_local_phandles(struct unit_test_state *uts) +{ + uint32_t local_phandle, test_phandle; + void *fdt = uts->priv; + u32 val = 0; + int off; + + off = fdt_path_offset(fdt, "/new-local-node"); + ut_assert(off >= 0); + + local_phandle = fdt_get_phandle(fdt, off); + ut_assert(local_phandle); + + off = fdt_path_offset(fdt, "/test-node"); + ut_assert(off >= 0); + + test_phandle = fdt_get_phandle(fdt, off); + ut_assert(test_phandle); + + ut_assertok(fdt_getprop_u32_by_index(fdt, "/", "test-phandle", 0, + &val)); + ut_asserteq(test_phandle, val); + + ut_assertok(fdt_getprop_u32_by_index(fdt, "/", "test-phandle", 1, + &val)); + ut_asserteq(local_phandle, val); + + return CMD_RET_SUCCESS; +} +OVERLAY_TEST(fdt_overlay_local_phandles, 0); + +int do_ut_overlay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + struct unit_test *tests = ll_entry_start(struct unit_test, + overlay_test); + const int n_ents = ll_entry_count(struct unit_test, overlay_test); + struct unit_test_state *uts; + struct unit_test *test; + void *fdt_base = &__dtb_test_fdt_base_begin; + void *fdt_overlay = &__dtb_test_fdt_overlay_begin; + void *fdt_base_copy, *fdt_overlay_copy; + + uts = calloc(1, sizeof(*uts)); + if (!uts) + return -ENOMEM; + + ut_assertok(fdt_check_header(fdt_base)); + ut_assertok(fdt_check_header(fdt_overlay)); + + fdt_base_copy = malloc(FDT_COPY_SIZE); + if (!fdt_base_copy) + return -ENOMEM; + uts->priv = fdt_base_copy; + + fdt_overlay_copy = malloc(FDT_COPY_SIZE); + if (!fdt_overlay_copy) + return -ENOMEM; + + /* + * Resize the FDT to 4k so that we have room to operate on + * + * (and relocate it since the memory might be mapped + * read-only) + */ + ut_assertok(fdt_open_into(fdt_base, fdt_base_copy, FDT_COPY_SIZE)); + + /* + * Resize the overlay to 4k so that we have room to operate on + * + * (and relocate it since the memory might be mapped + * read-only) + */ + ut_assertok(fdt_open_into(fdt_overlay, fdt_overlay_copy, + FDT_COPY_SIZE)); + + /* Apply the overlay */ + ut_assertok(fdt_overlay_apply(fdt_base_copy, fdt_overlay_copy)); + + if (argc == 1) + printf("Running %d environment tests\n", n_ents); + + for (test = tests; test < tests + n_ents; test++) { + if (argc > 1 && strcmp(argv[1], test->name)) + continue; + printf("Test: %s\n", test->name); + + uts->start = mallinfo(); + + test->func(uts); + } + + printf("Failures: %d\n", uts->fail_count); + + free(fdt_overlay_copy); + free(fdt_base_copy); + free(uts); + + return uts->fail_count ? CMD_RET_FAILURE : 0; +} diff --git a/test/overlay/test-fdt-base.dts b/test/overlay/test-fdt-base.dts new file mode 100644 index 00000000000..2603adb6821 --- /dev/null +++ b/test/overlay/test-fdt-base.dts @@ -0,0 +1,21 @@ +/* + * 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; + }; + }; +}; + + diff --git a/test/overlay/test-fdt-overlay.dts b/test/overlay/test-fdt-overlay.dts new file mode 100644 index 00000000000..d30ecdf3661 --- /dev/null +++ b/test/overlay/test-fdt-overlay.dts @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * 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; + }; + }; + }; + + /* Test that we add a new node (by path) */ + fragment@4 { + target-path = "/"; + + __overlay__ { + new-node { + new-property; + }; + }; + }; + + fragment@5 { + target-path = "/"; + + __overlay__ { + local: new-local-node { + new-property; + }; + }; + }; + + fragment@6 { + target-path = "/"; + + __overlay__ { + test-phandle = <&test>, <&local>; + }; + }; + + fragment@7 { + target-path = "/"; + + __overlay__ { + test-several-phandle = <&local>, <&local>; + }; + }; + + fragment@8 { + target = <&test>; + + __overlay__ { + sub-test-node { + new-sub-test-property; + }; + }; + }; +}; -- cgit v1.2.3