]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
test: Make a copy of the device tree before running a test
authorSimon Glass <sjg@chromium.org>
Wed, 7 Sep 2022 02:27:05 +0000 (20:27 -0600)
committerTom Rini <trini@konsulko.com>
Thu, 29 Sep 2022 20:09:56 +0000 (16:09 -0400)
When the flat device tree changes it can mess up the live tree since that
uses the flat tree for its strings. This affects only a few sandbox tests
which modify the device tree, but the number will grow as ofnode support
for writing improves.

While the control FDT is not intended to change while U-Boot is running,
some tests do so. For example, the ofnode interface only supports
modifying properties in the control FDT, so tests must use that.

To solve this problem, keep a copy of the FDT and restore it as needed
when the test is finished. The copy only happens on sandbox (except SPL
builds), to reduce memory usage and because these tests are not useful on
other boards. For other boards, a checksum is taken to ensure that nothing
changes.

It would be possible to always checksum the FDT on sandbox and only
restore it if needed, but this is slightly slower than restoring it every
time, at least with crc8.

Move the code which checks for success to the very end, for clarity.

Signed-off-by: Simon Glass <sjg@chromium.org>
doc/develop/driver-model/livetree.rst
include/test/test.h
test/test-main.c

index faf3eb5b5f0e5a9f7e2a61e48e982596176c149a..4ef8c517325633311e389e97595c8f0daa43680e 100644 (file)
@@ -235,20 +235,9 @@ tree either present or absent. This is to make sure that the flat tree functions
 work correctly even with OF_LIVE is enabled. But if a test modifies the flat
 device tree, then the live tree can become invalid. Any live tree tests that run
 after that point will use a corrupted tree, e.g. with an incorrect property name
-or worse. To deal with this we use a flag UT_TESTF_LIVE_OR_FLAT then ensures
-that tests which write to the flat tree are not run if OF_LIVE is enabled. Only
-the live tree version of the test is run, when OF_LIVE is enabled, with
-sandbox_flattree running the flat tree version.
-
-This is of course a work-around, even if a reasonable one. One solution to this
-problem would be to make a copy of the flat tree before the test and restore it
-afterwards, in the same memory location, so that the live tree pointers work
-again. Another would be to regenerate the live tree if a test modified the flat
-tree.
-
-Neither of these solutions is currently implemented, since the situation that
-causes the problem can only occur in sandbox tests, is somewhat esoteric and
-the UT_TESTF_LIVE_OR_FLAT flag deals with it in a reasonable way.
+or worse. To deal with this we take a copy of the device tree and restore it
+after any test that modifies it. Note that this copy is not made on other
+boards, only sandbox.
 
 
 Multiple livetrees
index 799e91808630ddeeb348a5849f6b07bfc21555d7..92215d427b02356ac1df69374965e7ca97332531 100644 (file)
@@ -20,6 +20,9 @@
  * @testdev: Test device
  * @force_fail_alloc: Force all memory allocs to fail
  * @skip_post_probe: Skip uclass post-probe processing
+ * @fdt_chksum: crc8 of the device tree contents
+ * @fdt_copy: Copy of the device tree
+ * @fdt_size: Size of the device-tree copy
  * @runs_per_test: Number of times to run each test (typically 1)
  * @expect_str: Temporary string used to hold expected string value
  * @actual_str: Temporary string used to hold actual string value
@@ -33,6 +36,9 @@ struct unit_test_state {
        struct udevice *testdev;
        int force_fail_alloc;
        int skip_post_probe;
+       uint fdt_chksum;
+       void *fdt_copy;
+       uint fdt_size;
        int runs_per_test;
        char expect_str[512];
        char actual_str[512];
index 7a3871624cb9f615799b8ab9c3ebc53e28b4899e..082821ef3e032ea083f5f3d26a52905a2ff4d8c6 100644 (file)
@@ -9,14 +9,51 @@
 #include <cyclic.h>
 #include <dm.h>
 #include <event.h>
+#include <os.h>
 #include <dm/root.h>
 #include <dm/test.h>
 #include <dm/uclass-internal.h>
 #include <test/test.h>
 #include <test/ut.h>
+#include <u-boot/crc.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
+/**
+ * enum fdtchk_t - what to do with the device tree (gd->fdt_blob)
+ *
+ * This affects what happens with the device tree before and after a test
+ *
+ * @FDTCHK_NONE: Do nothing
+ * @FDTCHK_CHECKSUM: Take a checksum of the FDT before the test runs and
+ *     compare it afterwards to detect any changes
+ * @FDTCHK_COPY: Make a copy of the FDT and restore it afterwards
+ */
+enum fdtchk_t {
+       FDTCHK_NONE,
+       FDTCHK_CHECKSUM,
+       FDTCHK_COPY,
+};
+
+/**
+ * fdt_action() - get the required action for the FDT
+ *
+ * @return the action that should be taken for this build
+ */
+static enum fdtchk_t fdt_action(void)
+{
+       /* Do a copy for sandbox (but only the U-Boot build, not SPL) */
+       if (CONFIG_IS_ENABLED(SANDBOX))
+               return FDTCHK_COPY;
+
+       /* For sandbox SPL builds, do nothing */
+       if (IS_ENABLED(CONFIG_SANDBOX))
+               return FDTCHK_NONE;
+
+       /* For all other boards, do a checksum */
+       return FDTCHK_CHECKSUM;
+}
+
 /* This is valid when a test is running, NULL otherwise */
 static struct unit_test_state *cur_test_state;
 
@@ -46,6 +83,9 @@ static int dm_test_pre_run(struct unit_test_state *uts)
        uts->testdev = NULL;
        uts->force_fail_alloc = false;
        uts->skip_post_probe = false;
+       if (fdt_action() == FDTCHK_CHECKSUM)
+               uts->fdt_chksum = crc8(0, gd->fdt_blob,
+                                      fdt_totalsize(gd->fdt_blob));
        gd->dm_root = NULL;
        malloc_disable_testing();
        if (CONFIG_IS_ENABLED(UT_DM) && !CONFIG_IS_ENABLED(OF_PLATDATA))
@@ -64,6 +104,25 @@ static int dm_test_post_run(struct unit_test_state *uts)
 {
        int id;
 
+       if (gd->fdt_blob) {
+               switch (fdt_action()) {
+               case FDTCHK_COPY:
+                       memcpy((void *)gd->fdt_blob, uts->fdt_copy, uts->fdt_size);
+                       break;
+               case FDTCHK_CHECKSUM: {
+                       uint chksum;
+
+                       chksum = crc8(0, gd->fdt_blob, fdt_totalsize(gd->fdt_blob));
+
+                       if (chksum != uts->fdt_chksum)
+                               printf("Device tree changed: cannot run live tree tests\n");
+                       break;
+               }
+               case FDTCHK_NONE:
+                       break;
+               }
+       }
+
        /*
         * With of-platdata-inst the uclasses are created at build time. If we
         * destroy them we cannot get them back since uclass_add() is not
@@ -443,8 +502,23 @@ int ut_run_list(const char *category, const char *prefix,
 
        uts.of_root = gd_of_root();
        uts.runs_per_test = runs_per_test;
+       if (fdt_action() == FDTCHK_COPY && gd->fdt_blob) {
+               uts.fdt_size = fdt_totalsize(gd->fdt_blob);
+               uts.fdt_copy = os_malloc(uts.fdt_size);
+               if (!uts.fdt_copy) {
+                       printf("Out of memory for device tree copy\n");
+                       return -ENOMEM;
+               }
+               memcpy(uts.fdt_copy, gd->fdt_blob, uts.fdt_size);
+       }
        ret = ut_run_tests(&uts, prefix, tests, count, select_name);
 
+       /* Best efforts only...ignore errors */
+       if (has_dm_tests)
+               dm_test_restore(uts.of_root);
+       if (IS_ENABLED(CONFIG_SANDBOX))
+               os_free(uts.fdt_copy);
+
        if (ret == -ENOENT)
                printf("Test '%s' not found\n", select_name);
        else