libfdt: add fdt_append_addrrange()

This function will append an address range property using parent node's
"#address-cells" and "#size-cells" properties.

It will be used in implementing kdump with kexec_file_load system call
at linux kernel for arm64 once it is merged into kernel tree.

Signed-off-by: AKASHI Takahiro <[email protected]>
Message-Id: <[email protected]>
[dwg: Correct a SEGV error in the testcase]
Signed-off-by: David Gibson <[email protected]>
diff --git a/tests/testutils.c b/tests/testutils.c
index bbfda90..a250d5a 100644
--- a/tests/testutils.c
+++ b/tests/testutils.c
@@ -45,6 +45,7 @@
 #include <libfdt.h>
 
 #include "tests.h"
+#include "testdata.h"
 
 /* For FDT_SW_MAGIC */
 #include "libfdt_internal.h"
@@ -184,6 +185,63 @@
 	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)
 {