aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2013-10-26 00:17:37 +1100
committerDavid Gibson <david@gibson.dropbear.id.au>2013-10-26 00:17:37 +1100
commit79eebb23dbf1f6eeff1789cd0d6f1c1fe620a487 (patch)
tree37e1dfc643762fba4d7a7a2b2277d027aabd3f32
parent883238dc508e721db694277c5273a4c3e9a7132f (diff)
downloaddtc-79eebb23dbf1f6eeff1789cd0d6f1c1fe620a487.tar.gz
libfdt: Add function to resize the buffer for a sequential write tree
At present, when using sequential write mode, there's no straightforward means of resizing the buffer the fdt is being built into. This patch adds an fdt_resize() function for this purpose. Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
-rw-r--r--libfdt/fdt_sw.c32
-rw-r--r--libfdt/libfdt.h1
-rwxr-xr-xtests/run_tests.sh8
-rw-r--r--tests/sw_tree1.c81
4 files changed, 114 insertions, 8 deletions
diff --git a/libfdt/fdt_sw.c b/libfdt/fdt_sw.c
index f422754..6a80485 100644
--- a/libfdt/fdt_sw.c
+++ b/libfdt/fdt_sw.c
@@ -107,6 +107,38 @@ int fdt_create(void *buf, int bufsize)
return 0;
}
+int fdt_resize(void *fdt, void *buf, int bufsize)
+{
+ size_t headsize, tailsize;
+ char *oldtail, *newtail;
+
+ FDT_SW_CHECK_HEADER(fdt);
+
+ headsize = fdt_off_dt_struct(fdt);
+ tailsize = fdt_size_dt_strings(fdt);
+
+ if ((headsize + tailsize) > bufsize)
+ return -FDT_ERR_NOSPACE;
+
+ oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize;
+ newtail = (char *)buf + bufsize - tailsize;
+
+ /* Two cases to avoid clobbering data if the old and new
+ * buffers partially overlap */
+ if (buf <= fdt) {
+ memmove(buf, fdt, headsize);
+ memmove(newtail, oldtail, tailsize);
+ } else {
+ memmove(newtail, oldtail, tailsize);
+ memmove(buf, fdt, headsize);
+ }
+
+ fdt_set_off_dt_strings(buf, bufsize);
+ fdt_set_totalsize(buf, bufsize);
+
+ return 0;
+}
+
int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
{
struct fdt_reserve_entry *re;
diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h
index 02baa84..c4d5a91 100644
--- a/libfdt/libfdt.h
+++ b/libfdt/libfdt.h
@@ -1023,6 +1023,7 @@ int fdt_nop_node(void *fdt, int nodeoffset);
/**********************************************************************/
int fdt_create(void *buf, int bufsize);
+int fdt_resize(void *fdt, void *buf, int bufsize);
int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
int fdt_finish_reservemap(void *fdt);
int fdt_begin_node(void *fdt, const char *name);
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index c0a136b..a8905a7 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -190,6 +190,14 @@ libfdt_tests () {
tree1_tests unfinished_tree1.test.dtb
run_test dtbs_equal_ordered test_tree1.dtb sw_tree1.test.dtb
+ # Resizing tests
+ for mode in resize realloc; do
+ run_test sw_tree1 $mode
+ tree1_tests sw_tree1.test.dtb
+ tree1_tests unfinished_tree1.test.dtb
+ run_test dtbs_equal_ordered test_tree1.dtb sw_tree1.test.dtb
+ done
+
# fdt_move tests
for tree in test_tree1.dtb sw_tree1.test.dtb unfinished_tree1.test.dtb; do
rm -f moved.$tree shunted.$tree deshunted.$tree
diff --git a/tests/sw_tree1.c b/tests/sw_tree1.c
index e9ea7e7..de00707 100644
--- a/tests/sw_tree1.c
+++ b/tests/sw_tree1.c
@@ -31,22 +31,87 @@
#define SPACE 65536
-#define CHECK(code) \
- { \
- err = (code); \
- if (err) \
- FAIL(#code ": %s", fdt_strerror(err)); \
+static enum {
+ FIXED = 0,
+ RESIZE,
+ REALLOC,
+} alloc_mode;
+
+static void realloc_fdt(void **fdt, size_t *size)
+{
+ switch (alloc_mode) {
+ case FIXED:
+ if (!(*fdt))
+ fdt = xmalloc(*size);
+ else
+ FAIL("Ran out of space");
+ return;
+
+ case RESIZE:
+ if (!(*fdt)) {
+ fdt = xmalloc(SPACE);
+ } else if (*size < SPACE) {
+ *size += 1;
+ fdt_resize(*fdt, *fdt, *size);
+ } else {
+ FAIL("Ran out of space");
+ }
+ return;
+
+ case REALLOC:
+ *size += 1;
+ *fdt = xrealloc(*fdt, *size);
+ fdt_resize(*fdt, *fdt, *size);
+ return;
+
+ default:
+ CONFIG("Bad allocation mode");
}
+}
+
+#define CHECK(code) \
+ do { \
+ err = (code); \
+ if (err == -FDT_ERR_NOSPACE) \
+ realloc_fdt(&fdt, &size); \
+ else if (err) \
+ FAIL(#code ": %s", fdt_strerror(err)); \
+ } while (err != 0)
int main(int argc, char *argv[])
{
- void *fdt;
+ void *fdt = NULL;
+ size_t size;
int err;
test_init(argc, argv);
- fdt = xmalloc(SPACE);
- CHECK(fdt_create(fdt, SPACE));
+ if (argc == 1) {
+ alloc_mode = FIXED;
+ size = SPACE;
+ } else if (argc == 2) {
+ if (streq(argv[1], "resize")) {
+ alloc_mode = REALLOC;
+ size = 0;
+ } else if (streq(argv[1], "realloc")) {
+ alloc_mode = REALLOC;
+ size = 0;
+ } else {
+ char *endp;
+
+ size = strtoul(argv[1], &endp, 0);
+ if (*endp == '\0')
+ alloc_mode = FIXED;
+ else
+ CONFIG("Bad allocation mode \"%s\" specified",
+ argv[1]);
+ }
+ }
+
+ realloc_fdt(&fdt, &size);
+
+ fdt = xmalloc(size);
+ CHECK(fdt_create(fdt, size));
CHECK(fdt_add_reservemap_entry(fdt, TEST_ADDR_1, TEST_SIZE_1));
CHECK(fdt_add_reservemap_entry(fdt, TEST_ADDR_2, TEST_SIZE_2));