u-boot.lists.denx.de archive mirror
 help / color / mirror / Atom feed
From: Simon Glass <sjg@chromium.org>
To: U-Boot Mailing List <u-boot@lists.denx.de>
Cc: Simon Glass <sjg@chromium.org>
Subject: [RFC PATCH 3/9] upl: Add basic tests
Date: Wed, 30 Aug 2023 17:29:17 -0600	[thread overview]
Message-ID: <20230830232928.2590178-4-sjg@chromium.org> (raw)
In-Reply-To: <20230830232928.2590178-1-sjg@chromium.org>

Add some unit tests to check that we can write a UPL handoff and read it
back.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 test/boot/Makefile |   2 +
 test/boot/upl.c    | 420 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 422 insertions(+)
 create mode 100644 test/boot/upl.c

diff --git a/test/boot/Makefile b/test/boot/Makefile
index 52947580ae6..9f97223eed3 100644
--- a/test/boot/Makefile
+++ b/test/boot/Makefile
@@ -12,3 +12,5 @@ ifdef CONFIG_OF_LIVE
 obj-$(CONFIG_BOOTMETH_VBE_SIMPLE) += vbe_simple.o
 endif
 obj-$(CONFIG_BOOTMETH_VBE) += vbe_fixup.o
+
+obj-$(CONFIG_UPL) += upl.o
diff --git a/test/boot/upl.c b/test/boot/upl.c
new file mode 100644
index 00000000000..8319a93e057
--- /dev/null
+++ b/test/boot/upl.c
@@ -0,0 +1,420 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * UPL handoff testing
+ *
+ * Copyright 2023 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <abuf.h>
+#include <mapmem.h>
+#include <upl.h>
+#include <dm/ofnode.h>
+#include <test/test.h>
+#include <test/ut.h>
+#include "bootstd_common.h"
+
+void upl_get_test_data(struct upl *upl)
+{
+	memset(upl, '\0', sizeof(struct upl));
+	upl->addr_cells = 1;
+	upl->size_cells = 1;
+	upl->smbios = 0x123;
+	upl->acpi = 0x456;
+	upl->bootmode = BIT(UPLBM_DEFAULT) | BIT(UPLBM_S3);
+	upl->fit = 0x789;
+	upl->conf_offset = 0x234;
+	upl->addr_width = 46;
+	upl->acpi_nvs_size = 0x100;
+
+	upl->num_images = 2;
+	upl->image[0].load = 0x1;
+	upl->image[0].size = 0x2;
+	upl->image[0].offset = 0x3;
+	upl->image[0].description = "U-Boot";
+	upl->image[1].load = 0x4;
+	upl->image[1].size = 0x5;
+	upl->image[1].offset = 0x6;
+	upl->image[1].description = "ATF";
+
+	upl->num_mems = 2;
+	upl->mem[0].num_regions = 3;
+	upl->mem[0].region[0].base = 0x10;
+	upl->mem[0].region[0].size = 0x20;
+	upl->mem[0].region[1].base = 0x30;
+	upl->mem[0].region[1].size = 0x40;
+	upl->mem[0].region[2].base = 0x50;
+	upl->mem[0].region[2].size = 0x60;
+	upl->mem[1].num_regions = 1;
+	upl->mem[1].region[0].base = 0x70;
+	upl->mem[1].region[0].size = 0x80;
+	upl->mem[1].hotpluggable = true;
+
+	upl->num_memmaps = 5;
+	upl->memmap[0].num_regions = 5;
+	upl->memmap[0].name = "acpi";
+	upl->memmap[0].usage = BIT(UPLUS_ACPI_RECLAIM);
+	upl->memmap[0].region[0].base = 0x11;
+	upl->memmap[0].region[0].size = 0x12;
+	upl->memmap[0].region[1].base = 0x13;
+	upl->memmap[0].region[1].size = 0x14;
+	upl->memmap[0].region[2].base = 0x15;
+	upl->memmap[0].region[2].size = 0x16;
+	upl->memmap[0].region[3].base = 0x17;
+	upl->memmap[0].region[3].size = 0x18;
+	upl->memmap[0].region[4].base = 0x19;
+	upl->memmap[0].region[4].size = 0x1a;
+	upl->memmap[1].name = "u-boot";
+	upl->memmap[1].num_regions = 1;
+	upl->memmap[1].usage = BIT(UPLUS_BOOT_DATA);
+	upl->memmap[1].region[0].base = 0x21;
+	upl->memmap[1].region[0].size = 0x22;
+	upl->memmap[2].name = "efi";
+	upl->memmap[2].num_regions = 1;
+	upl->memmap[2].usage = BIT(UPLUS_RUNTIME_CODE);
+	upl->memmap[2].region[0].base = 0x23;
+	upl->memmap[2].region[0].size = 0x24;
+	upl->memmap[3].num_regions = 2;
+	upl->memmap[3].name = "empty";
+	upl->memmap[3].usage = 0;
+	upl->memmap[3].region[0].base = 0x25;
+	upl->memmap[3].region[0].size = 0x26;
+	upl->memmap[3].region[1].base = 0x27;
+	upl->memmap[3].region[1].size = 0x28;
+	upl->memmap[4].name = "acpi-things";
+	upl->memmap[4].num_regions = 1;
+	upl->memmap[4].usage = BIT(UPLUS_RUNTIME_CODE) | BIT(UPLUS_ACPI_NVS);
+	upl->memmap[4].region[0].base = 0x29;
+	upl->memmap[4].region[0].base = 0x2a;
+
+	upl->num_memres = 2;
+	upl->memres[0].num_regions = 1;
+	upl->memres[0].name = "mmio";
+	upl->memres[0].region[0].base = 0x2b;
+	upl->memres[0].region[0].size = 0x2c;
+	upl->memres[1].num_regions = 2;
+	upl->memres[1].name = "memory";
+	upl->memres[1].region[0].base = 0x2d;
+	upl->memres[1].region[0].size = 0x2e;
+	upl->memres[1].region[1].base = 0x2f;
+	upl->memres[1].region[1].size = 0x30;
+	upl->memres[1].no_map = true;
+
+	upl->serial.compatible = "ns16550a";
+	upl->serial.clock_frequency = 1843200;
+	upl->serial.current_speed = 115200;
+	upl->serial.reg.base = 0xf1de0000;
+	upl->serial.reg.size = 0x100;
+	upl->serial.reg_io_shift = 2;
+	upl->serial.reg_offset = 0x40;
+	upl->serial.reg_io_width = 1;
+	upl->serial.virtual_reg = 0x20000000;
+	upl->serial.access_type = UPLSAT_MMIO;
+
+	upl->graphics.reg.base = 0xd0000000;
+	upl->graphics.reg.size = 0x10000000;
+	upl->graphics.width = 1280;
+	upl->graphics.height = 1280;
+	upl->graphics.stride = upl->graphics.width * 4;
+	upl->graphics.format = UPLGF_ARGB32;
+}
+
+static int compare_upl_image(struct unit_test_state *uts,
+			     struct upl_image *base, struct upl_image *cmp)
+{
+	ut_asserteq(base->load, cmp->load);
+	ut_asserteq(base->size, cmp->size);
+	ut_asserteq(base->offset, cmp->offset);
+	ut_asserteq_str(base->description, cmp->description);
+
+	return 0;
+}
+
+static int compare_upl_memregion(struct unit_test_state *uts,
+			      struct memregion *base, struct memregion *cmp)
+{
+	ut_asserteq(base->base, cmp->base);
+	ut_asserteq(base->size, cmp->size);
+
+	return 0;
+}
+
+static int compare_upl_mem(struct unit_test_state *uts, struct upl_mem *base,
+			   struct upl_mem *cmp)
+{
+	int i;
+
+	ut_asserteq(base->num_regions, cmp->num_regions);
+	ut_asserteq(base->hotpluggable, cmp->hotpluggable);
+	for (i = 0; i < base->num_regions; i++)
+		ut_assertok(compare_upl_memregion(uts, &base->region[i],
+						  &cmp->region[i]));
+
+	return 0;
+}
+
+static int check_device_name(struct unit_test_state *uts, const char *base,
+			     const char *cmp)
+{
+	const char *p;
+
+	p = strchr(cmp, '@');
+	if (p) {
+		ut_assertnonnull(p);
+		ut_asserteq_strn(base, cmp);
+		ut_asserteq(p - cmp, strlen(base));
+	} else {
+		ut_asserteq_str(base, cmp);
+	}
+
+	return 0;
+}
+
+static int compare_upl_memmap(struct unit_test_state *uts,
+			      struct upl_memmap *base, struct upl_memmap *cmp)
+{
+	int i;
+
+	ut_assertok(check_device_name(uts, base->name, cmp->name));
+	ut_asserteq(base->num_regions, cmp->num_regions);
+	ut_asserteq(base->usage, cmp->usage);
+	for (i = 0; i < base->num_regions; i++)
+		ut_assertok(compare_upl_memregion(uts, &base->region[i],
+						  &cmp->region[i]));
+
+	return 0;
+}
+
+static int compare_upl_memres(struct unit_test_state *uts,
+			      struct upl_memres *base, struct upl_memres *cmp)
+{
+	int i;
+
+	ut_assertok(check_device_name(uts, base->name, cmp->name));
+	ut_asserteq(base->num_regions, cmp->num_regions);
+	ut_asserteq(base->no_map, cmp->no_map);
+	for (i = 0; i < base->num_regions; i++)
+		ut_assertok(compare_upl_memregion(uts, &base->region[i],
+						  &cmp->region[i]));
+
+	return 0;
+}
+
+static int compare_upl_serial(struct unit_test_state *uts,
+			      struct upl_serial *base, struct upl_serial *cmp)
+{
+	ut_asserteq_str(base->compatible, cmp->compatible);
+	ut_asserteq(base->clock_frequency, cmp->clock_frequency);
+	ut_asserteq(base->current_speed, cmp->current_speed);
+	ut_assertok(compare_upl_memregion(uts, &base->reg, &cmp->reg));
+	ut_asserteq(base->reg_io_shift, cmp->reg_io_shift);
+	ut_asserteq(base->reg_offset, cmp->reg_offset);
+	ut_asserteq(base->reg_io_width, cmp->reg_io_width);
+	ut_asserteq(base->virtual_reg, cmp->virtual_reg);
+	ut_asserteq(base->access_type, cmp->access_type);
+
+	return 0;
+}
+
+static int compare_upl_graphics(struct unit_test_state *uts,
+				struct upl_graphics *base,
+				struct upl_graphics *cmp)
+{
+	ut_assertok(compare_upl_memregion(uts, &base->reg, &cmp->reg));
+	ut_asserteq(base->width, cmp->width);
+	ut_asserteq(base->height, cmp->height);
+	ut_asserteq(base->stride, cmp->stride);
+	ut_asserteq(base->format, cmp->format);
+
+	return 0;
+}
+
+static int compare_upl(struct unit_test_state *uts, struct upl *base,
+		       struct upl *cmp)
+{
+	int i;
+
+	ut_asserteq(base->addr_cells, cmp->addr_cells);
+	ut_asserteq(base->size_cells, cmp->size_cells);
+
+	ut_asserteq(base->smbios, cmp->smbios);
+	ut_asserteq(base->acpi, cmp->acpi);
+	ut_asserteq(base->bootmode, cmp->bootmode);
+	ut_asserteq(base->fit, cmp->fit);
+	ut_asserteq(base->conf_offset, cmp->conf_offset);
+	ut_asserteq(base->addr_width, cmp->addr_width);
+	ut_asserteq(base->acpi_nvs_size, cmp->acpi_nvs_size);
+
+	ut_asserteq(base->num_images, cmp->num_images);
+	for (i = 0; i < base->num_images; i++)
+		ut_assertok(compare_upl_image(uts, &base->image[i],
+					      &cmp->image[i]));
+
+	ut_asserteq(base->num_mems, cmp->num_mems);
+	for (i = 0; i < base->num_mems; i++)
+		ut_assertok(compare_upl_mem(uts, &base->mem[i], &cmp->mem[i]));
+
+	ut_asserteq(base->num_memmaps, cmp->num_memmaps);
+	for (i = 0; i < base->num_memmaps; i++)
+		ut_assertok(compare_upl_memmap(uts, &base->memmap[i],
+					       &cmp->memmap[i]));
+
+	ut_asserteq(base->num_memres, cmp->num_memres);
+	for (i = 0; i < base->num_memres; i++)
+		ut_assertok(compare_upl_memres(uts, &base->memres[i],
+					       &cmp->memres[i]));
+
+	ut_assertok(compare_upl_serial(uts, &base->serial, &cmp->serial));
+	ut_assertok(compare_upl_graphics(uts, &base->graphics, &cmp->graphics));
+
+	return 0;
+}
+
+/* Basic test of writing and reading UPL handoff */
+static int upl_test_base(struct unit_test_state *uts)
+{
+	oftree tree, check_tree;
+	struct upl upl, check;
+	struct abuf buf;
+
+	upl_get_test_data(&upl);
+
+	ut_assertok(upl_create_handoff_tree(&upl, &tree));
+	ut_assertok(oftree_to_fdt(tree, &buf));
+
+	/*
+	 * strings in check_tree and therefore check are only valid so long as
+	 * buf stays around. As soon as we call abuf_uninit they go away
+	 */
+	check_tree = oftree_from_fdt(abuf_data(&buf));
+	ut_assert(ofnode_valid(oftree_path(check_tree, "/")));
+
+	ut_assertok(upl_read_handoff(&check, check_tree));
+	ut_assertok(compare_upl(uts, &upl, &check));
+	abuf_uninit(&buf);
+
+	return 0;
+}
+BOOTSTD_TEST(upl_test_base, 0);
+
+/* Write an invalid structure */
+static int upl_test_write_failure(struct unit_test_state *uts)
+{
+	struct upl upl;
+	oftree tree;
+
+	upl_get_test_data(&upl);
+	upl.num_images = UPL_MAX_IMAGES;
+	ut_asserteq(-E2BIG, upl_create_handoff_tree(&upl, &tree));
+
+	upl_get_test_data(&upl);
+	upl.num_mems = UPL_MAX_MEMS;
+	ut_asserteq(-E2BIG, upl_create_handoff_tree(&upl, &tree));
+
+	upl_get_test_data(&upl);
+	upl.num_memmaps = UPL_MAX_MEMMAPS;
+	ut_asserteq(-E2BIG, upl_create_handoff_tree(&upl, &tree));
+
+	upl_get_test_data(&upl);
+	upl.num_memres = UPL_MAX_MEMRESERVED;
+	ut_asserteq(-E2BIG, upl_create_handoff_tree(&upl, &tree));
+
+	return 0;
+}
+BOOTSTD_TEST(upl_test_write_failure, 0);
+
+/**
+ * add_more_nodes() - Add enough extra nodes of a given type to check failures
+ *
+ * Adding too many nodes of node like memory@ and memory-map subnode eventually
+ * hits the limit, e,g. UPL_MAX_MEMS for /memory@ nodes. This makes more and
+ * more copies of an existing node until it reaches the limit, at which point it
+ * checks that upl_read_handoff() returns -E2BIG
+ *
+ * @uts: Unit-test state
+ * @tree: Devicetree to test with
+ * @dst: Parent path (e.g. "/memory-map"), or, for root nodes, a node template
+ * (e.g. "memory@"). This is used to figure out what nodes to copy. In the
+ * former case it copies one of the subnodes (e.g. "/memory-map/acpi@123") and
+ * in the latter case it copies one of the root subnodes (e.g. /memory@123)
+ * @total_nodes: Total number of nodes which upl_read_handoff() can handle
+ * before failing
+ * Returns 0 if OK, 1 on failure
+ */
+static int add_more_nodes(struct unit_test_state *uts, oftree tree,
+			  const char *dst, int total_nodes)
+{
+	ofnode parent, to_copy, node;
+	bool top_level;
+	struct upl check;
+	int count;
+
+	/* Check we should create subnodes in the root node (at top level)  */
+	top_level = *dst != '/';
+
+	parent = top_level ? oftree_root(tree) : oftree_path(tree, dst);
+	ut_assert(ofnode_valid(parent));
+
+	/* count the number of nodes in the parent and find a node to copy */
+	count = 0;
+	ofnode_for_each_subnode(node, parent) {
+		if (top_level &&
+		    strncmp(dst, ofnode_get_name(node), strlen(dst)))
+			continue;
+		to_copy = node;
+		count++;
+	}
+
+	/* add one node at a time until it fails */
+	for (; count < total_nodes;) {
+		char str[30];
+
+		if (top_level)
+			sprintf(str, "%s%d", dst, count + 1);
+		else
+			sprintf(str, "any-%d", count + 1);
+		ut_assertok(ofnode_copy_node(parent, str, to_copy, &node));
+		if (++count < total_nodes)
+			ut_assertok(upl_read_handoff(&check, tree));
+		else
+			ut_asserteq(-E2BIG, upl_read_handoff(&check, tree));
+	}
+
+	/* delete the last node and see that it works */
+	ut_assertok(ofnode_delete(&node));
+	ut_assertok(upl_read_handoff(&check, tree));
+
+	return 0;
+}
+
+/* Read a structure we cannot parse */
+static int upl_test_read_failure(struct unit_test_state *uts)
+{
+	oftree base_tree, tree;
+	struct abuf buf;
+	struct upl upl;
+
+	upl_get_test_data(&upl);
+	ut_assertok(upl_create_handoff_tree(&upl, &base_tree));
+	ut_assertok(oftree_to_fdt(base_tree, &buf));
+	tree = oftree_from_fdt(abuf_data(&buf));
+
+	/* Add more and more nodes to /options/upl-image until it fails */
+	ut_assertok(add_more_nodes(uts, tree, UPLPATH_UPL_IMAGE,
+				   UPL_MAX_IMAGES + 1));
+
+	/*
+	 * Do the same with the other node which have implementation-defined
+	 * limits
+	 */
+	ut_assertok(add_more_nodes(uts, tree, UPLN_MEMORY "@",
+				   UPL_MAX_MEMS + 1));
+	ut_assertok(add_more_nodes(uts, tree, UPLPATH_MEMORY_MAP,
+				   UPL_MAX_MEMMAPS + 1));
+	ut_assertok(add_more_nodes(uts, tree, UPLPATH_MEMORY_RESERVED,
+				   UPL_MAX_MEMRESERVED + 1));
+
+	return 0;
+}
+BOOTSTD_TEST(upl_test_read_failure, 0);
-- 
2.42.0.rc2.253.gd59a3bf2b4-goog


  parent reply	other threads:[~2023-08-30 23:30 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-08-30 23:29 [RFC PATCH 0/9] Universal Payload initial series Simon Glass
2023-08-30 23:29 ` [RFC PATCH 1/9] upl: Add support for reading a upl handoff Simon Glass
2023-08-30 23:29 ` [RFC PATCH 2/9] upl: Add support for writing " Simon Glass
2023-08-30 23:29 ` Simon Glass [this message]
2023-08-30 23:29 ` [RFC PATCH 4/9] upl: Add a command Simon Glass
2023-08-30 23:29 ` [RFC PATCH 5/9] upl: Add support for Universal Payload in SPL Simon Glass
2023-08-30 23:29 ` [RFC PATCH 6/9] spl: Plumb in the Universal Payload handoff Simon Glass
2023-08-30 23:29 ` [RFC PATCH 7/9] Plumb in universal payload to the init process Simon Glass
2023-08-30 23:29 ` [RFC PATCH 8/9] sandbox_vpl: Enable Universal Payload Simon Glass
2023-08-30 23:29 ` [RFC PATCH 9/9] upl: Add initial documentation Simon Glass
2023-08-31  3:58   ` Heinrich Schuchardt

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230830232928.2590178-4-sjg@chromium.org \
    --to=sjg@chromium.org \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).