From fd1bf3a5ae46962528ef89a824261a88830758a2 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 10 Oct 2007 17:12:12 +1000 Subject: [PATCH] libfdt: Add functions to get/add/delete memory reservemap entries This patch adds functions to libfdt for accessing the memory reservation map section of a device tree blob. fdt_num_mem_rsv() retreives the number of reservation entries in a dtb, and fdt_get_mem_rsv() retreives a specific reservation entry. fdt_add_mem_rsv() adds a new entry, and fdt_del_mem_rsv() removes a specific numbered entry. Testcases for these new functions are also included. Signed-off-by: David Gibson --- libfdt/fdt_ro.c | 17 +++++++++++++++ libfdt/fdt_rw.c | 47 ++++++++++++++++++++++++++++++++++++++++ libfdt/libfdt.h | 6 +++++ libfdt/libfdt_internal.h | 12 ++++++++++ tests/Makefile.tests | 3 ++- tests/run_tests.sh | 1 + tests/rw_tree1.c | 3 +++ tests/sw_tree1.c | 3 +++ tests/test_tree1.dts | 3 +++ tests/testdata.h | 11 ++++++++++ tests/tests.h | 2 ++ tests/testutils.c | 15 +++++++++++++ tests/trees.S | 11 ++++++++-- 13 files changed, 131 insertions(+), 3 deletions(-) diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c index 8dab7a8..a5a15e3 100644 --- a/libfdt/fdt_ro.c +++ b/libfdt/fdt_ro.c @@ -87,6 +87,23 @@ char *fdt_string(const void *fdt, int stroffset) return (char *)fdt + fdt_off_dt_strings(fdt) + stroffset; } +int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) +{ + CHECK_HEADER(fdt); + *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address); + *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size); + return 0; +} + +int fdt_num_mem_rsv(const void *fdt) +{ + int i = 0; + + while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0) + i++; + return i; +} + int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, const char *name, int namelen) { diff --git a/libfdt/fdt_rw.c b/libfdt/fdt_rw.c index 6e4c808..85b6281 100644 --- a/libfdt/fdt_rw.c +++ b/libfdt/fdt_rw.c @@ -101,6 +101,19 @@ static int _blob_splice(void *fdt, void *p, int oldlen, int newlen) return 0; } +static int _blob_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p, + int oldn, int newn) +{ + int delta = (newn - oldn) * sizeof(*p); + int err; + err = _blob_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p)); + if (err) + return err; + fdt_set_header(fdt, off_dt_struct, fdt_off_dt_struct(fdt) + delta); + fdt_set_header(fdt, off_dt_strings, fdt_off_dt_strings(fdt) + delta); + return 0; +} + static int _blob_splice_struct(void *fdt, void *p, int oldlen, int newlen) { @@ -149,6 +162,40 @@ static int _find_add_string(void *fdt, const char *s) return (new - strtab); } +int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) +{ + struct fdt_reserve_entry *re; + int err; + + if ((err = rw_check_header(fdt))) + return err; + + re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt)); + err = _blob_splice_mem_rsv(fdt, re, 0, 1); + if (err) + return err; + + re->address = cpu_to_fdt64(address); + re->size = cpu_to_fdt64(size); + return 0; +} + +int fdt_del_mem_rsv(void *fdt, int n) +{ + struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n); + int err; + + if ((err = rw_check_header(fdt))) + return err; + if (n >= fdt_num_mem_rsv(fdt)) + return -FDT_ERR_NOTFOUND; + + err = _blob_splice_mem_rsv(fdt, re, 1, 0); + if (err) + return err; + return 0; +} + static int _resize_property(void *fdt, int nodeoffset, const char *name, int len, struct fdt_property **prop) { diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h index c059bdc..468e45f 100644 --- a/libfdt/libfdt.h +++ b/libfdt/libfdt.h @@ -112,6 +112,9 @@ int fdt_move(const void *fdt, void *buf, int bufsize); /* Read-only functions */ char *fdt_string(const void *fdt, int stroffset); +int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size); +int fdt_num_mem_rsv(const void *fdt); + int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, const char *name, int namelen); int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); @@ -183,6 +186,9 @@ int fdt_finish(void *fdt); int fdt_open_into(void *fdt, void *buf, int bufsize); int fdt_pack(void *fdt); +int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size); +int fdt_del_mem_rsv(void *fdt, int n); + int fdt_setprop(void *fdt, int nodeoffset, const char *name, const void *val, int len); #define fdt_setprop_typed(fdt, nodeoffset, name, val) \ diff --git a/libfdt/libfdt_internal.h b/libfdt/libfdt_internal.h index a1a548d..d2d5e6a 100644 --- a/libfdt/libfdt_internal.h +++ b/libfdt/libfdt_internal.h @@ -73,6 +73,18 @@ static inline void *_fdt_offset_ptr_w(void *fdt, int offset) return (void *)_fdt_offset_ptr(fdt, offset); } +static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n) +{ + const struct fdt_reserve_entry *rsv_table = + fdt + fdt_off_mem_rsvmap(fdt); + + return rsv_table + n; +} +static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n) +{ + return (void *)_fdt_mem_rsv(fdt, n); +} + #define SW_MAGIC (~FDT_MAGIC) #endif /* _LIBFDT_INTERNAL_H */ diff --git a/tests/Makefile.tests b/tests/Makefile.tests index e97e903..c84b63d 100644 --- a/tests/Makefile.tests +++ b/tests/Makefile.tests @@ -1,4 +1,5 @@ -LIB_TESTS_L = root_node find_property subnode_offset path_offset \ +LIB_TESTS_L = get_mem_rsv \ + root_node find_property subnode_offset path_offset \ get_name getprop get_path supernode_atdepth_offset parent_offset \ node_offset_by_prop_value \ notfound \ diff --git a/tests/run_tests.sh b/tests/run_tests.sh index b51bd8f..2a5e486 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -31,6 +31,7 @@ tree1_tests () { TREE=$1 # Read-only tests + run_test get_mem_rsv $TREE run_test root_node $TREE run_test find_property $TREE run_test subnode_offset $TREE diff --git a/tests/rw_tree1.c b/tests/rw_tree1.c index 099b3f4..7835362 100644 --- a/tests/rw_tree1.c +++ b/tests/rw_tree1.c @@ -69,6 +69,9 @@ int main(int argc, char *argv[]) CHECK(fdt_open_into(fdt, fdt, SPACE)); + CHECK(fdt_add_mem_rsv(fdt, TEST_ADDR_1, TEST_SIZE_1)); + CHECK(fdt_add_mem_rsv(fdt, TEST_ADDR_2, TEST_SIZE_2)); + CHECK(fdt_setprop_typed(fdt, 0, "prop-int", TEST_VALUE_1)); CHECK(fdt_setprop_string(fdt, 0, "prop-str", TEST_STRING_1)); diff --git a/tests/sw_tree1.c b/tests/sw_tree1.c index 34bee4f..d4b960e 100644 --- a/tests/sw_tree1.c +++ b/tests/sw_tree1.c @@ -49,7 +49,10 @@ int main(int argc, char *argv[]) fdt = xmalloc(SPACE); CHECK(fdt_create(fdt, SPACE)); + 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_finish_reservemap(fdt)); + CHECK(fdt_begin_node(fdt, "")); CHECK(fdt_property_typed(fdt, "prop-int", TEST_VALUE_1)); CHECK(fdt_property_string(fdt, "prop-str", TEST_STRING_1)); diff --git a/tests/test_tree1.dts b/tests/test_tree1.dts index 30091f1..212ffa7 100644 --- a/tests/test_tree1.dts +++ b/tests/test_tree1.dts @@ -1,3 +1,6 @@ +/memreserve/ deadbeef00000000-deadbeef000fffff; +/memreserve/ abcd1234 00001234; + / { prop-int = ; prop-str = "hello world"; diff --git a/tests/testdata.h b/tests/testdata.h index 15a4a35..3d08ff7 100644 --- a/tests/testdata.h +++ b/tests/testdata.h @@ -9,6 +9,17 @@ | (((x) << 8) & 0xff0000) | (((x) << 24) & 0xff000000)) #endif +#ifdef __ASSEMBLY__ +#define ASM_CONST_LL(x) (x) +#else +#define ASM_CONST_LL(x) (x##ULL) +#endif + +#define TEST_ADDR_1 ASM_CONST_LL(0xdeadbeef00000000) +#define TEST_SIZE_1 ASM_CONST_LL(0x100000) +#define TEST_ADDR_2 ASM_CONST_LL(0xabcd1234) +#define TEST_SIZE_2 ASM_CONST_LL(0x1234) + #define TEST_VALUE_1 cell_to_fdt(0xdeadbeef) #define TEST_VALUE_2 cell_to_fdt(0xabcd1234) diff --git a/tests/tests.h b/tests/tests.h index 62716ce..97f15d8 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -108,6 +108,8 @@ static inline void *xrealloc(void *p, size_t size) return p; } +void check_mem_rsv(void *fdt, int n, uint64_t addr, uint64_t size); + void check_property(void *fdt, int nodeoffset, const char *name, int len, const void *val); #define check_property_typed(fdt, nodeoffset, name, val) \ diff --git a/tests/testutils.c b/tests/testutils.c index 68cc88a..6d6112b 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -69,6 +69,21 @@ void test_init(int argc, char *argv[]) test_name, getpid()); } +void check_mem_rsv(void *fdt, int n, uint64_t addr, uint64_t size) +{ + int err; + uint64_t addr_v, size_v; + + err = fdt_get_mem_rsv(fdt, n, &addr_v, &size_v); + if (err < 0) + FAIL("fdt_get_mem_rsv(%d): %s", n, fdt_strerror(err)); + if ((addr_v != addr) || (size_v != size)) + FAIL("fdt_get_mem_rsv() returned (0x%llx,0x%llx) " + "instead of (0x%llx,0x%llx)", + (unsigned long long)addr_v, (unsigned long long)size_v, + (unsigned long long)addr, (unsigned long long)size); +} + void check_property(void *fdt, int nodeoffset, const char *name, int len, const void *val) { diff --git a/tests/trees.S b/tests/trees.S index 78c92d7..bb662a6 100644 --- a/tests/trees.S +++ b/tests/trees.S @@ -37,6 +37,11 @@ tree: \ FDTQUAD(addr) ; \ FDTQUAD(len) ; +#define EMPTY_RSVMAP(tree) \ + .balign 8 ; \ +tree##_rsvmap: ; \ + RSVMAP_ENTRY(0, 0) + #define PROPHDR(tree, name, len) \ FDTLONG(FDT_PROP) ; \ FDTLONG(len) ; \ @@ -70,7 +75,10 @@ tree##_##name: \ TREE_HDR(test_tree1) + .balign 8 test_tree1_rsvmap: + RSVMAP_ENTRY(TEST_ADDR_1, TEST_SIZE_1) + RSVMAP_ENTRY(TEST_ADDR_2, TEST_SIZE_2) RSVMAP_ENTRY(0, 0) test_tree1_struct: @@ -103,8 +111,7 @@ test_tree1_strings: test_tree1_end: TREE_HDR(truncated_property) -truncated_property_rsvmap: - RSVMAP_ENTRY(0, 0) + EMPTY_RSVMAP(truncated_property) truncated_property_struct: BEGIN_NODE("")