diff --git a/libfdt/fdt_rw.c b/libfdt/fdt_rw.c index 78231d0..dfe5628 100644 --- a/libfdt/fdt_rw.c +++ b/libfdt/fdt_rw.c @@ -55,6 +55,18 @@ #include "libfdt_internal.h" +static int _blocks_misordered(const void *fdt, + int mem_rsv_size, int struct_size) +{ + return (fdt_off_mem_rsvmap(fdt) < ALIGN(sizeof(struct fdt_header), 8)) + || (fdt_off_dt_struct(fdt) < + (fdt_off_mem_rsvmap(fdt) + mem_rsv_size)) + || (fdt_off_dt_strings(fdt) < + (fdt_off_dt_struct(fdt) + struct_size)) + || (fdt_totalsize(fdt) < + (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); +} + static int rw_check_header(void *fdt) { int err; @@ -63,16 +75,8 @@ static int rw_check_header(void *fdt) return err; if (fdt_version(fdt) < 17) return -FDT_ERR_BADVERSION; - if (fdt_off_mem_rsvmap(fdt) < ALIGN(sizeof(struct fdt_header), 8)) - return -FDT_ERR_BADLAYOUT; - if (fdt_off_dt_struct(fdt) < - (fdt_off_mem_rsvmap(fdt) + sizeof(struct fdt_reserve_entry))) - return -FDT_ERR_BADLAYOUT; - if (fdt_off_dt_strings(fdt) < - (fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt))) - return -FDT_ERR_BADLAYOUT; - if (fdt_totalsize(fdt) < - (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))) + if (_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry), + fdt_size_dt_struct(fdt))) return -FDT_ERR_BADLAYOUT; if (fdt_version(fdt) > 17) fdt_set_version(fdt, 17); @@ -342,36 +346,102 @@ int fdt_del_node(void *fdt, int nodeoffset) endoffset - nodeoffset, 0); } -int fdt_open_into(void *fdt, void *buf, int bufsize) +static void _packblocks(const void *fdt, void *buf, + int mem_rsv_size, int struct_size) +{ + int mem_rsv_off, struct_off, strings_off; + + mem_rsv_off = ALIGN(sizeof(struct fdt_header), 8); + struct_off = mem_rsv_off + mem_rsv_size; + strings_off = struct_off + struct_size; + + memmove(buf + mem_rsv_off, fdt + fdt_off_mem_rsvmap(fdt), mem_rsv_size); + fdt_set_off_mem_rsvmap(buf, mem_rsv_off); + + memcpy(buf + struct_off, fdt + fdt_off_dt_struct(fdt), struct_size); + fdt_set_off_dt_struct(buf, struct_off); + fdt_set_size_dt_struct(buf, struct_size); + + memcpy(buf + strings_off, fdt + fdt_off_dt_strings(fdt), + fdt_size_dt_strings(fdt)); + fdt_set_off_dt_strings(buf, strings_off); + fdt_set_size_dt_strings(buf, fdt_size_dt_strings(fdt)); +} + +int fdt_open_into(const void *fdt, void *buf, int bufsize) { int err; + int mem_rsv_size, struct_size; + int newsize; + void *tmp; - err = fdt_move(fdt, buf, bufsize); + err = fdt_check_header(fdt); if (err) return err; - fdt = buf; + mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) + * sizeof(struct fdt_reserve_entry); - fdt_set_totalsize(fdt, bufsize); + if (fdt_version(fdt) >= 17) { + struct_size = fdt_size_dt_struct(fdt); + } else { + struct_size = 0; + while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) + ; + } - /* FIXME: re-order if necessary */ + if (!_blocks_misordered(fdt, mem_rsv_size, struct_size)) { + /* no further work necessary */ + err = fdt_move(fdt, buf, bufsize); + if (err) + return err; + fdt_set_version(buf, 17); + fdt_set_size_dt_struct(buf, struct_size); + fdt_set_totalsize(buf, bufsize); + return 0; + } - err = rw_check_header(fdt); - if (err) - return err; + /* Need to reorder */ + newsize = ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size + + struct_size + fdt_size_dt_strings(fdt); + + if (bufsize < newsize) + return -FDT_ERR_NOSPACE; + + if (((buf + newsize) <= fdt) + || (buf >= (fdt + fdt_totalsize(fdt)))) { + tmp = buf; + } else { + tmp = (void *)fdt + fdt_totalsize(fdt); + if ((tmp + newsize) > (buf + bufsize)) + return -FDT_ERR_NOSPACE; + } + + _packblocks(fdt, tmp, mem_rsv_size, struct_size); + memmove(buf, tmp, newsize); + + fdt_set_magic(buf, FDT_MAGIC); + fdt_set_totalsize(buf, bufsize); + fdt_set_version(buf, 17); + fdt_set_last_comp_version(buf, 16); + fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt)); return 0; } int fdt_pack(void *fdt) { + int mem_rsv_size; int err; err = rw_check_header(fdt); if (err) return err; - /* FIXME: pack components */ + mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) + * sizeof(struct fdt_reserve_entry); + _packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt)); fdt_set_totalsize(fdt, _blob_data_size(fdt)); + return 0; } diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h index 5710bb3..4ef65bc 100644 --- a/libfdt/libfdt.h +++ b/libfdt/libfdt.h @@ -412,7 +412,7 @@ int fdt_finish(void *fdt); /* Read-write functions */ /**********************************************************************/ -int fdt_open_into(void *fdt, void *buf, int bufsize); +int fdt_open_into(const void *fdt, void *buf, int bufsize); int fdt_pack(void *fdt); int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size); diff --git a/tests/del_node.c b/tests/del_node.c index 51b12b2..fad777e 100644 --- a/tests/del_node.c +++ b/tests/del_node.c @@ -40,6 +40,8 @@ int main(int argc, char *argv[]) test_init(argc, argv); fdt = load_blob_arg(argc, argv); + fdt = open_blob_rw(fdt); + oldsize = fdt_totalsize(fdt); subnode1_offset = fdt_path_offset(fdt, "/subnode@1"); diff --git a/tests/del_property.c b/tests/del_property.c index 35dc932..2c412c3 100644 --- a/tests/del_property.c +++ b/tests/del_property.c @@ -41,6 +41,8 @@ int main(int argc, char *argv[]) test_init(argc, argv); fdt = load_blob_arg(argc, argv); + fdt = open_blob_rw(fdt); + oldsize = fdt_totalsize(fdt); intp = check_getprop_typed(fdt, 0, "prop-int", TEST_VALUE_1); diff --git a/tests/run_tests.sh b/tests/run_tests.sh index 25bacbf..8fcc44a 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -61,6 +61,8 @@ tree1_tests_rw () { run_test del_node $TREE } +ALL_LAYOUTS="mts mst tms tsm smt stm" + libfdt_tests () { tree1_tests test_tree1.dtb @@ -81,7 +83,7 @@ libfdt_tests () { # v16 and alternate layout tests for tree in test_tree1.dtb; do for version in 17 16; do - for layout in mts mst tms tsm smt stm; do + for layout in $ALL_LAYOUTS; do run_test mangle-layout $tree $version $layout tree1_tests v$version.$layout.$tree run_test dtbs_equal_ordered $tree v$version.$layout.$tree @@ -90,18 +92,21 @@ libfdt_tests () { done # Read-write tests - for tree in test_tree1.dtb sw_tree1.test.dtb; do - rm -f opened.$tree repacked.$tree - run_test open_pack $tree - tree1_tests opened.$tree - tree1_tests repacked.$tree - done + for basetree in test_tree1.dtb; do + for version in 17 16; do + for layout in $ALL_LAYOUTS; do + tree=v$version.$layout.$basetree + rm -f opened.$tree repacked.$tree + run_test open_pack $tree + tree1_tests $tree + tree1_tests opened.$tree + tree1_tests repacked.$tree - for tree in test_tree1.dtb sw_tree1.test.dtb; do - tree1_tests_rw $tree - tree1_tests_rw moved.$tree - tree1_tests_rw shunted.$tree - tree1_tests_rw deshunted.$tree + tree1_tests_rw $tree + tree1_tests_rw opened.$tree + tree1_tests_rw repacked.$tree + done + done done run_test rw_tree1 tree1_tests rw_tree1.test.dtb diff --git a/tests/tests.h b/tests/tests.h index 0029a84..f6dcd15 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -132,5 +132,6 @@ int nodename_eq(const char *s1, const char *s2); void *load_blob(const char *filename); void *load_blob_arg(int argc, char *argv[]); void save_blob(const char *filename, void *blob); +void *open_blob_rw(void *blob); #endif /* _TESTS_H */ diff --git a/tests/testutils.c b/tests/testutils.c index 6d6112b..338e3bd 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -220,3 +220,21 @@ void save_blob(const char *filename, void *fdt) offset += ret; } } + +void *open_blob_rw(void *blob) +{ + int err; + void *buf = blob; + + err = fdt_open_into(blob, buf, fdt_totalsize(blob)); + if (err == -FDT_ERR_NOSPACE) { + /* Ran out of space converting to v17 */ + int newsize = fdt_totalsize(blob) + 8; + + buf = xmalloc(newsize); + err = fdt_open_into(blob, buf, newsize); + } + if (err) + FAIL("fdt_open_into(): %s", fdt_strerror(err)); + return buf; +}