diff --git a/fdt.c b/fdt.c index b24a3fe..0c1a5f0 100644 --- a/fdt.c +++ b/fdt.c @@ -23,6 +23,25 @@ #include "libfdt_internal.h" +int _fdt_check_header(const struct fdt_header *fdt) +{ + if (fdt_magic(fdt) == FDT_MAGIC) { + /* Complete tree */ + if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) + return FDT_ERR_BADVERSION; + if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) + return FDT_ERR_BADVERSION; + } else if (fdt_magic(fdt) == SW_MAGIC) { + /* Unfinished sequential-write blob */ + if (sw_size_dt_struct(fdt) == 0) + return FDT_ERR_BADSTATE; + } else { + return FDT_ERR_BADMAGIC; + } + + return 0; +} + void *fdt_offset_ptr(const struct fdt_header *fdt, int offset, int len) { void *p; @@ -72,3 +91,17 @@ uint32_t _fdt_next_tag(const struct fdt_header *fdt, int offset, int *nextoffset return tag; } + +struct fdt_header *fdt_move(const struct fdt_header *fdt, void *buf, int bufsize) +{ + int err = _fdt_check_header(fdt); + + if (err) + return PTR_ERROR(err); + + if (fdt_totalsize(fdt) > bufsize) + return PTR_ERROR(FDT_ERR_NOSPACE); + + memmove(buf, fdt, fdt_totalsize(fdt)); + return (struct fdt_header *)buf; +} diff --git a/fdt_ro.c b/fdt_ro.c index db5281c..bbc380a 100644 --- a/fdt_ro.c +++ b/fdt_ro.c @@ -23,29 +23,10 @@ #include "libfdt_internal.h" -static int check_header(const struct fdt_header *fdt) -{ - if (fdt_magic(fdt) == FDT_MAGIC) { - /* Complete tree */ - if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) - return FDT_ERR_BADVERSION; - if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) - return FDT_ERR_BADVERSION; - } else if (fdt_magic(fdt) == SW_MAGIC) { - /* Unfinished sequential-write blob */ - if (sw_size_dt_struct(fdt) == 0) - return FDT_ERR_BADSTATE; - } else { - return FDT_ERR_BADMAGIC; - } - - return 0; -} - #define OFFSET_CHECK_HEADER(fdt) \ { \ int err; \ - if ((err = check_header(fdt)) != 0) \ + if ((err = _fdt_check_header(fdt)) != 0) \ return OFFSET_ERROR(err); \ } diff --git a/libfdt.h b/libfdt.h index d4f98dc..c0ee2b7 100644 --- a/libfdt.h +++ b/libfdt.h @@ -64,6 +64,8 @@ void *fdt_offset_ptr(const struct fdt_header *fdt, int offset, int checklen); #define fdt_ptr_error(ptr) \ ( (((long)(ptr) < 0) && ((long)(ptr) >= -FDT_ERR_MAX)) ? -(long)(ptr) : 0 ) +struct fdt_header *fdt_move(const struct fdt_header *fdt, void *buf, int bufsize); + /* Read-only functions */ char *fdt_string(const struct fdt_header *fdt, int stroffset); @@ -115,9 +117,6 @@ int fdt_add_subnode(struct fdt_header *fdtx, void *node, const char *name); int fdt_set_property(struct fdt_header *fdtx, void *node, const char *name, const void *val, int len); int fdt_del_property(struct fdt_header *fdtx, void *node, const char *name); - -/* Misc functions */ -struct fdt_header *fdt_move(struct fdt_header *fdt, void *buf, int bufsize); #endif #endif /* _LIBFDT_H */ diff --git a/libfdt_internal.h b/libfdt_internal.h index 06fa1cc..91361c2 100644 --- a/libfdt_internal.h +++ b/libfdt_internal.h @@ -26,6 +26,7 @@ #define memeq(p, q, n) (memcmp((p), (q), (n)) == 0) #define streq(p, q) (strcmp((p), (q)) == 0) +int _fdt_check_header(const struct fdt_header *fdt); uint32_t _fdt_next_tag(const struct fdt_header *fdt, int startoffset, int *nextoffset); struct fdt_property *_fdt_getprop(const struct fdt_header *fdt, int nodeoffset, const char *name, int *lenp); diff --git a/tests/Makefile b/tests/Makefile index b6dc852..b430a68 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -3,7 +3,8 @@ PREFIX = /usr/local LIB_TESTS = root_node property_offset subnode_offset path_offset getprop \ notfound \ setprop_inplace nop_property nop_node \ - sw_tree1 + sw_tree1 \ + move_and_save TESTS = $(LIB_TESTS) UTILS = dumptrees diff --git a/tests/move_and_save.c b/tests/move_and_save.c new file mode 100644 index 0000000..526f615 --- /dev/null +++ b/tests/move_and_save.c @@ -0,0 +1,71 @@ +/* + * libfdt - Flat Device Tree manipulation + * Basic testcase for read-only access + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include + +#include "tests.h" +#include "testdata.h" + +int main(int argc, char *argv[]) +{ + struct fdt_header *fdt, *fdt1, *fdt2, *fdt3; + void *buf; + int shuntsize; + int bufsize; + int err; + const char *inname; + char outname[PATH_MAX]; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + inname = argv[1]; + + shuntsize = ALIGN(fdt_totalsize(fdt) / 2, sizeof(uint64_t)); + bufsize = fdt_totalsize(fdt) + shuntsize; + buf = xmalloc(bufsize); + + fdt1 = fdt_move(fdt, buf, bufsize); + if ((err = fdt_ptr_error(fdt1))) + FAIL("Failed to move tree into new buffer: %s", + fdt_strerror(err)); + sprintf(outname, "moved.%s", inname); + save_blob(outname, fdt1); + + fdt2 = fdt_move(fdt1, buf + shuntsize, bufsize-shuntsize); + if ((err = fdt_ptr_error(fdt2))) + FAIL("Failed to shunt tree %d bytes: %s", + shuntsize, fdt_strerror(err)); + sprintf(outname, "shunted.%s", inname); + save_blob(outname, fdt2); + + fdt3 = fdt_move(fdt2, buf, bufsize); + if ((err = fdt_ptr_error(fdt3))) + FAIL("Failed to deshunt tree %d bytes: %s", + shuntsize, fdt_strerror(err)); + sprintf(outname, "deshunted.%s", inname); + save_blob(outname, fdt3); + + PASS(); +} diff --git a/tests/run_tests.sh b/tests/run_tests.sh index 338e47a..fba7413 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -36,6 +36,15 @@ functional_tests () { run_test sw_tree1 tree1_tests sw_tree1.test.dtb tree1_tests unfinished_tree1.test.dtb + + # 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 + run_test move_and_save $tree + tree1_tests moved.$tree + tree1_tests shunted.$tree + tree1_tests deshunted.$tree + done } stress_tests () {