Add a test that reserved-memory nodes above ram_top are skipped without
an error, and that the part of a node crossing ram_top which lies below
it is still reserved.

Enable LMB_LIMIT_DMA_BELOW_RAM_TOP on sandbox so that the test runs. The
sandbox RAM ends at ram_top, so nothing is reserved above it outside the
test.

Signed-off-by: David Lechner <[email protected]>
---
 lib/Kconfig           |  1 +
 test/boot/image_fdt.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 76 insertions(+)

diff --git a/lib/Kconfig b/lib/Kconfig
index 021a82d4709..96d3da335d2 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -1372,6 +1372,7 @@ config LMB_LIMIT_DMA_BELOW_RAM_TOP
        bool
        depends on LMB
        default y if ARCH_BCM283X || ARCH_MVEBU || ARCH_ROCKCHIP || 
STARFIVE_JH7110
+       default y if SANDBOX
        help
          Some architectures can not DMA above ram_top boundary,
          which is after 4 GiB or 32-bit boundary too. Limit the
diff --git a/test/boot/image_fdt.c b/test/boot/image_fdt.c
index 5417689a683..13d2f83983c 100644
--- a/test/boot/image_fdt.c
+++ b/test/boot/image_fdt.c
@@ -6,11 +6,14 @@
 #include <config.h>
 
 #include <fdt_support.h>
+#include <fdtdec.h>
 #include <image.h>
 #include <lmb.h>
 #include <malloc.h>
 
 #include <asm/global_data.h>
+#include <linux/libfdt.h>
+#include <linux/sizes.h>
 
 #include <test/test.h>
 #include <test/ut.h>
@@ -81,3 +84,75 @@ free_blob:
        return ret;
 }
 IMAGE_FDT_TEST(test_boot_fdt_add_mem_rsv_regions, UTF_CONSOLE);
+
+/**
+ * test_boot_fdt_rsv_above_ram_top - Make sure dt reservations above ram_top
+ *                                   are handled quietly
+ * @uts: Test state
+ *
+ * With LMB_LIMIT_DMA_BELOW_RAM_TOP, LMB reserves the memory above ram_top
+ * itself. A reservation above ram_top must then be skipped without an error,
+ * and a reservation that crosses ram_top must still reserve its part below
+ * ram_top.
+ */
+static int test_boot_fdt_rsv_above_ram_top(struct unit_test_state *uts)
+{
+       phys_addr_t ram_top = gd->ram_base + gd->ram_size / 2;
+       phys_addr_t old_ram_top = gd->ram_top;
+       phys_size_t size = gd->ram_base + gd->ram_size - ram_top;
+       struct fdt_memory above = {
+               .start = ram_top + SZ_4K,
+               .end = ram_top + 2 * SZ_4K - 1,
+       };
+       struct fdt_memory across = {
+               .start = ram_top - SZ_4K,
+               .end = ram_top + SZ_4K - 1,
+       };
+       phys_addr_t addr = ram_top;
+       int nomap_start, nomap_end, nomap_above, noov_above;
+       struct lmb store;
+       void *blob;
+       int ret;
+
+       if (!IS_ENABLED(CONFIG_LMB_LIMIT_DMA_BELOW_RAM_TOP))
+               return -EAGAIN;
+
+       blob = malloc(SZ_4K);
+       ut_assertnonnull(blob);
+       ut_assertok(fdt_create_empty_tree(blob, SZ_4K));
+       ut_assertok(fdtdec_add_reserved_memory(blob, "above", &above, NULL, 0,
+                                              NULL,
+                                              FDTDEC_RESERVED_MEMORY_NO_MAP));
+       ut_assertok(fdtdec_add_reserved_memory(blob, "across", &across, NULL,
+                                              0, NULL,
+                                              FDTDEC_RESERVED_MEMORY_NO_MAP));
+
+       /* Set up LMB as lmb_add_memory() does for a lower ram_top */
+       ut_assertok(lmb_push(&store));
+       ut_assertok(lmb_add(gd->ram_base, gd->ram_size));
+       ut_assertok(lmb_alloc_mem(LMB_MEM_ALLOC_ADDR, 0, &addr, size,
+                                 LMB_NOOVERWRITE));
+       gd->ram_top = ram_top;
+
+       boot_fdt_add_mem_rsv_regions(blob);
+       ret = ut_check_console_end(uts);
+       nomap_start = lmb_is_reserved_flags(across.start, LMB_NOMAP);
+       nomap_end = lmb_is_reserved_flags(ram_top - 1, LMB_NOMAP);
+       nomap_above = lmb_is_reserved_flags(ram_top, LMB_NOMAP);
+       noov_above = lmb_is_reserved_flags(ram_top, LMB_NOOVERWRITE);
+
+       gd->ram_top = old_ram_top;
+       lmb_pop(&store);
+       free(blob);
+
+       ut_assertok(ret);
+       /* The part of the region below ram_top is reserved up to ram_top */
+       ut_asserteq(1, nomap_start);
+       ut_asserteq(1, nomap_end);
+       /* The reservation of LMB above ram_top is left alone */
+       ut_asserteq(0, nomap_above);
+       ut_asserteq(1, noov_above);
+
+       return 0;
+}
+IMAGE_FDT_TEST(test_boot_fdt_rsv_above_ram_top, UTF_CONSOLE);

-- 
2.53.0

Reply via email to