Browse Source

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>
main
David Gibson 11 years ago
parent
commit
79eebb23db
  1. 32
      libfdt/fdt_sw.c
  2. 1
      libfdt/libfdt.h
  3. 8
      tests/run_tests.sh
  4. 81
      tests/sw_tree1.c

32
libfdt/fdt_sw.c

@ -107,6 +107,38 @@ int fdt_create(void *buf, int bufsize)
return 0; 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) int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
{ {
struct fdt_reserve_entry *re; struct fdt_reserve_entry *re;

1
libfdt/libfdt.h

@ -1023,6 +1023,7 @@ int fdt_nop_node(void *fdt, int nodeoffset);
/**********************************************************************/ /**********************************************************************/


int fdt_create(void *buf, int bufsize); 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_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
int fdt_finish_reservemap(void *fdt); int fdt_finish_reservemap(void *fdt);
int fdt_begin_node(void *fdt, const char *name); int fdt_begin_node(void *fdt, const char *name);

8
tests/run_tests.sh

@ -190,6 +190,14 @@ libfdt_tests () {
tree1_tests unfinished_tree1.test.dtb tree1_tests unfinished_tree1.test.dtb
run_test dtbs_equal_ordered test_tree1.dtb sw_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 # fdt_move tests
for tree in test_tree1.dtb sw_tree1.test.dtb unfinished_tree1.test.dtb; do for tree in test_tree1.dtb sw_tree1.test.dtb unfinished_tree1.test.dtb; do
rm -f moved.$tree shunted.$tree deshunted.$tree rm -f moved.$tree shunted.$tree deshunted.$tree

81
tests/sw_tree1.c

@ -31,22 +31,87 @@


#define SPACE 65536 #define SPACE 65536


#define CHECK(code) \ static enum {
{ \ FIXED = 0,
err = (code); \ RESIZE,
if (err) \ REALLOC,
FAIL(#code ": %s", fdt_strerror(err)); \ } 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[]) int main(int argc, char *argv[])
{ {
void *fdt; void *fdt = NULL;
size_t size;
int err; int err;


test_init(argc, argv); test_init(argc, argv);


fdt = xmalloc(SPACE); if (argc == 1) {
CHECK(fdt_create(fdt, SPACE)); 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_1, TEST_SIZE_1));
CHECK(fdt_add_reservemap_entry(fdt, TEST_ADDR_2, TEST_SIZE_2)); CHECK(fdt_add_reservemap_entry(fdt, TEST_ADDR_2, TEST_SIZE_2));

Loading…
Cancel
Save