diff --git a/common/cmd_fdt.c b/common/cmd_fdt.c index 9cd22ee94a..14c3fa022e 100644 --- a/common/cmd_fdt.c +++ b/common/cmd_fdt.c @@ -260,7 +260,7 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) /******************************************************************** * Remove a property/node ********************************************************************/ - } else if (argv[1][0] == 'r') { + } else if ((argv[1][0] == 'r') && (argv[1][1] == 'm')) { int nodeoffset; /* node offset from libfdt */ int err; @@ -296,6 +296,111 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) return err; } } + + /******************************************************************** + * Display header info + ********************************************************************/ + } else if (argv[1][0] == 'h') { + u32 version = fdt_version(fdt); + printf("magic:\t\t\t0x%x\n", fdt_magic(fdt)); + printf("totalsize:\t\t0x%x (%d)\n", fdt_totalsize(fdt), fdt_totalsize(fdt)); + printf("off_dt_struct:\t\t0x%x\n", fdt_off_dt_struct(fdt)); + printf("off_dt_strings:\t\t0x%x\n", fdt_off_dt_strings(fdt)); + printf("off_mem_rsvmap:\t\t0x%x\n", fdt_off_mem_rsvmap(fdt)); + printf("version:\t\t%d\n", version); + printf("last_comp_version:\t%d\n", fdt_last_comp_version(fdt)); + if (version >= 2) + printf("boot_cpuid_phys:\t0x%x\n", + fdt_boot_cpuid_phys(fdt)); + if (version >= 3) + printf("size_dt_strings:\t0x%x\n", + fdt_size_dt_strings(fdt)); + if (version >= 17) + printf("size_dt_struct:\t\t0x%x\n", + fdt_size_dt_struct(fdt)); + printf("number mem_rsv:\t\t0x%x\n", fdt_num_mem_rsv(fdt)); + printf("\n"); + + /******************************************************************** + * Set boot cpu id + ********************************************************************/ + } else if ((argv[1][0] == 'b') && (argv[1][1] == 'o') && + (argv[1][2] == 'o')) { + unsigned long tmp = simple_strtoul(argv[2], NULL, 16); + fdt_set_boot_cpuid_phys(fdt, tmp); + + /******************************************************************** + * memory command + ********************************************************************/ + } else if ((argv[1][0] == 'm') && (argv[1][1] == 'e')) { + uint64_t addr, size; + int err; +#ifdef CFG_64BIT_STRTOUL + addr = simple_strtoull(argv[2], NULL, 16); + size = simple_strtoull(argv[3], NULL, 16); +#else + addr = simple_strtoul(argv[2], NULL, 16); + size = simple_strtoul(argv[3], NULL, 16); +#endif + err = fdt_fixup_memory(fdt, addr, size); + if (err < 0) + return err; + + /******************************************************************** + * mem reserve commands + ********************************************************************/ + } else if ((argv[1][0] == 'r') && (argv[1][1] == 's')) { + if (argv[2][0] == 'p') { + uint64_t addr, size; + int total = fdt_num_mem_rsv(fdt); + int j, err; + printf("index\t\t start\t\t size\n"); + printf("-------------------------------" + "-----------------\n"); + for (j = 0; j < total; j++) { + err = fdt_get_mem_rsv(fdt, j, &addr, &size); + if (err < 0) { + printf("libfdt fdt_get_mem_rsv(): %s\n", + fdt_strerror(err)); + return err; + } + printf(" %x\t%08x%08x\t%08x%08x\n", j, + (u32)(addr >> 32), + (u32)(addr & 0xffffffff), + (u32)(size >> 32), + (u32)(size & 0xffffffff)); + } + } else if (argv[2][0] == 'a') { + uint64_t addr, size; + int err; +#ifdef CFG_64BIT_STRTOUL + addr = simple_strtoull(argv[3], NULL, 16); + size = simple_strtoull(argv[4], NULL, 16); +#else + addr = simple_strtoul(argv[3], NULL, 16); + size = simple_strtoul(argv[4], NULL, 16); +#endif + err = fdt_add_mem_rsv(fdt, addr, size); + + if (err < 0) { + printf("libfdt fdt_add_mem_rsv(): %s\n", + fdt_strerror(err)); + return err; + } + } else if (argv[2][0] == 'd') { + unsigned long idx = simple_strtoul(argv[3], NULL, 16); + int err = fdt_del_mem_rsv(fdt, idx); + + if (err < 0) { + printf("libfdt fdt_del_mem_rsv(): %s\n", + fdt_strerror(err)); + return err; + } + } else { + /* Unrecognized command */ + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } } #ifdef CONFIG_OF_BOARD_SETUP /* Call the board-specific fixup routine */ @@ -689,6 +794,12 @@ U_BOOT_CMD( "fdt set [] - Set [to ]\n" "fdt mknode - Create a new node after \n" "fdt rm [] - Delete the node or \n" + "fdt header - Display header info\n" + "fdt bootcpu - Set boot cpuid\n" + "fdt memory - Add/Update memory node\n" + "fdt rsvmem print - Show current mem reserves\n" + "fdt rsvmem add - Add a mem reserve\n" + "fdt rsvmem delete - Delete a mem reserves\n" "fdt chosen - Add/update the /chosen branch in the tree\n" #ifdef CONFIG_OF_HAS_UBOOT_ENV "fdt env - Add/replace the /u-boot-env branch in the tree\n" diff --git a/include/libfdt.h b/include/libfdt.h index 6c05236858..beeacb2e07 100644 --- a/include/libfdt.h +++ b/include/libfdt.h @@ -130,6 +130,12 @@ static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); +/**********************************************************************/ +/* Traversal functions */ +/**********************************************************************/ + +int fdt_next_node(const void *fdt, int offset, int *depth); + /**********************************************************************/ /* General functions */ /**********************************************************************/ @@ -845,6 +851,32 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size); */ int fdt_del_mem_rsv(void *fdt, int n); +/** + * fdt_set_name - change the name of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of a node + * @name: name to give the node + * + * fdt_set_name() replaces the name (including unit address, if any) + * of the given node with the given string. NOTE: this function can't + * efficiently check if the new name is unique amongst the given + * node's siblings; results are undefined if this function is invoked + * with a name equal to one of the given node's siblings. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob + * to contain the new name + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings + */ +int fdt_set_name(void *fdt, int nodeoffset, const char *name); + /** * fdt_setprop - create or change a property * @fdt: pointer to the device tree blob diff --git a/libfdt/fdt.c b/libfdt/fdt.c index 586a36136d..bd91712378 100644 --- a/libfdt/fdt.c +++ b/libfdt/fdt.c @@ -129,6 +129,47 @@ uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset) return tag; } +int fdt_next_node(const void *fdt, int offset, int *depth) +{ + int nextoffset = 0; + uint32_t tag; + + if (offset >= 0) { + tag = fdt_next_tag(fdt, offset, &nextoffset); + if (tag != FDT_BEGIN_NODE) + return -FDT_ERR_BADOFFSET; + } + + do { + offset = nextoffset; + tag = fdt_next_tag(fdt, offset, &nextoffset); + + switch (tag) { + case FDT_PROP: + case FDT_NOP: + break; + + case FDT_BEGIN_NODE: + if (depth) + (*depth)++; + break; + + case FDT_END_NODE: + if (depth) + (*depth)--; + break; + + case FDT_END: + return -FDT_ERR_NOTFOUND; + + default: + return -FDT_ERR_BADSTRUCTURE; + } + } while (tag != FDT_BEGIN_NODE); + + return offset; +} + const char *_fdt_find_string(const char *strtab, int tabsize, const char *s) { int len = strlen(s) + 1; @@ -143,10 +184,7 @@ const char *_fdt_find_string(const char *strtab, int tabsize, const char *s) int fdt_move(const void *fdt, void *buf, int bufsize) { - int err = fdt_check_header(fdt); - - if (err) - return err; + CHECK_HEADER(fdt); if (fdt_totalsize(fdt) > bufsize) return -FDT_ERR_NOSPACE; diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c index 12a37d59f9..63fa1290be 100644 --- a/libfdt/fdt_ro.c +++ b/libfdt/fdt_ro.c @@ -55,17 +55,10 @@ #include "libfdt_internal.h" -#define CHECK_HEADER(fdt) \ - { \ - int err; \ - if ((err = fdt_check_header(fdt)) != 0) \ - return err; \ - } - static int nodename_eq(const void *fdt, int offset, const char *s, int len) { - const char *p = fdt_offset_ptr(fdt, offset, len+1); + const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1); if (! p) /* short match */ @@ -104,50 +97,24 @@ int fdt_num_mem_rsv(const void *fdt) return i; } -int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, +int fdt_subnode_offset_namelen(const void *fdt, int offset, const char *name, int namelen) { - int level = 0; - uint32_t tag; - int offset, nextoffset; + int depth; CHECK_HEADER(fdt); - tag = fdt_next_tag(fdt, parentoffset, &nextoffset); - if (tag != FDT_BEGIN_NODE) - return -FDT_ERR_BADOFFSET; + for (depth = 0; + offset >= 0; + offset = fdt_next_node(fdt, offset, &depth)) { + if (depth < 0) + return -FDT_ERR_NOTFOUND; + else if ((depth == 1) + && nodename_eq(fdt, offset, name, namelen)) + return offset; + } - do { - offset = nextoffset; - tag = fdt_next_tag(fdt, offset, &nextoffset); - - switch (tag) { - case FDT_END: - return -FDT_ERR_TRUNCATED; - - case FDT_BEGIN_NODE: - level++; - if (level != 1) - continue; - if (nodename_eq(fdt, offset+FDT_TAGSIZE, name, namelen)) - /* Found it! */ - return offset; - break; - - case FDT_END_NODE: - level--; - break; - - case FDT_PROP: - case FDT_NOP: - break; - - default: - return -FDT_ERR_BADSTRUCTURE; - } - } while (level >= 0); - - return -FDT_ERR_NOTFOUND; + return offset; /* error */ } int fdt_subnode_offset(const void *fdt, int parentoffset, @@ -307,76 +274,61 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) { - uint32_t tag; - int p = 0, overflow = 0; - int offset, nextoffset, namelen; + int pdepth = 0, p = 0; + int offset, depth, namelen; const char *name; CHECK_HEADER(fdt); - tag = fdt_next_tag(fdt, 0, &nextoffset); - if (tag != FDT_BEGIN_NODE) - return -FDT_ERR_BADSTRUCTURE; - if (buflen < 2) return -FDT_ERR_NOSPACE; - buf[0] = '/'; - p = 1; - while (nextoffset <= nodeoffset) { - offset = nextoffset; - tag = fdt_next_tag(fdt, offset, &nextoffset); - switch (tag) { - case FDT_END: - return -FDT_ERR_BADOFFSET; + for (offset = 0, depth = 0; + (offset >= 0) && (offset <= nodeoffset); + offset = fdt_next_node(fdt, offset, &depth)) { + if (pdepth < depth) + continue; /* overflowed buffer */ - case FDT_BEGIN_NODE: - name = fdt_get_name(fdt, offset, &namelen); - if (!name) - return namelen; - if (overflow || ((p + namelen + 1) > buflen)) { - overflow++; - break; - } + while (pdepth > depth) { + do { + p--; + } while (buf[p-1] != '/'); + pdepth--; + } + + name = fdt_get_name(fdt, offset, &namelen); + if (!name) + return namelen; + if ((p + namelen + 1) <= buflen) { memcpy(buf + p, name, namelen); p += namelen; buf[p++] = '/'; - break; + pdepth++; + } - case FDT_END_NODE: - if (overflow) { - overflow--; - break; - } - do { + if (offset == nodeoffset) { + if (pdepth < (depth + 1)) + return -FDT_ERR_NOSPACE; + + if (p > 1) /* special case so that root path is "/", not "" */ p--; - } while (buf[p-1] != '/'); - break; - - case FDT_PROP: - case FDT_NOP: - break; - - default: - return -FDT_ERR_BADSTRUCTURE; + buf[p] = '\0'; + return p; } } - if (overflow) - return -FDT_ERR_NOSPACE; + if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) + return -FDT_ERR_BADOFFSET; + else if (offset == -FDT_ERR_BADOFFSET) + return -FDT_ERR_BADSTRUCTURE; - if (p > 1) /* special case so that root path is "/", not "" */ - p--; - buf[p] = '\0'; - return p; + return offset; /* error from fdt_next_node() */ } int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, int supernodedepth, int *nodedepth) { - int level = -1; - uint32_t tag; - int offset, nextoffset = 0; + int offset, depth; int supernodeoffset = -FDT_ERR_INTERNAL; CHECK_HEADER(fdt); @@ -384,38 +336,29 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, if (supernodedepth < 0) return -FDT_ERR_NOTFOUND; - do { - offset = nextoffset; - tag = fdt_next_tag(fdt, offset, &nextoffset); - switch (tag) { - case FDT_END: - return -FDT_ERR_BADOFFSET; + for (offset = 0, depth = 0; + (offset >= 0) && (offset <= nodeoffset); + offset = fdt_next_node(fdt, offset, &depth)) { + if (depth == supernodedepth) + supernodeoffset = offset; - case FDT_BEGIN_NODE: - level++; - if (level == supernodedepth) - supernodeoffset = offset; - break; + if (offset == nodeoffset) { + if (nodedepth) + *nodedepth = depth; - case FDT_END_NODE: - level--; - break; - - case FDT_PROP: - case FDT_NOP: - break; - - default: - return -FDT_ERR_BADSTRUCTURE; + if (supernodedepth > depth) + return -FDT_ERR_NOTFOUND; + else + return supernodeoffset; } - } while (offset < nodeoffset); + } - if (nodedepth) - *nodedepth = level; + if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) + return -FDT_ERR_BADOFFSET; + else if (offset == -FDT_ERR_BADOFFSET) + return -FDT_ERR_BADSTRUCTURE; - if (supernodedepth > level) - return -FDT_ERR_NOTFOUND; - return supernodeoffset; + return offset; /* error from fdt_next_node() */ } int fdt_node_depth(const void *fdt, int nodeoffset) @@ -443,51 +386,27 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, const char *propname, const void *propval, int proplen) { - uint32_t tag; - int offset, nextoffset; + int offset; const void *val; int len; CHECK_HEADER(fdt); - if (startoffset >= 0) { - tag = fdt_next_tag(fdt, startoffset, &nextoffset); - if (tag != FDT_BEGIN_NODE) - return -FDT_ERR_BADOFFSET; - } else { - nextoffset = 0; - } - /* FIXME: The algorithm here is pretty horrible: we scan each * property of a node in fdt_getprop(), then if that didn't * find what we want, we scan over them again making our way * to the next node. Still it's the easiest to implement * approach; performance can come later. */ - do { - offset = nextoffset; - tag = fdt_next_tag(fdt, offset, &nextoffset); + for (offset = fdt_next_node(fdt, startoffset, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + val = fdt_getprop(fdt, offset, propname, &len); + if (val && (len == proplen) + && (memcmp(val, propval, len) == 0)) + return offset; + } - switch (tag) { - case FDT_BEGIN_NODE: - val = fdt_getprop(fdt, offset, propname, &len); - if (val - && (len == proplen) - && (memcmp(val, propval, len) == 0)) - return offset; - break; - - case FDT_PROP: - case FDT_END: - case FDT_END_NODE: - case FDT_NOP: - break; - - default: - return -FDT_ERR_BADSTRUCTURE; - } - } while (tag != FDT_END); - - return -FDT_ERR_NOTFOUND; + return offset; /* error from fdt_next_node() */ } int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) @@ -534,50 +453,24 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset, int fdt_node_offset_by_compatible(const void *fdt, int startoffset, const char *compatible) { - uint32_t tag; - int offset, nextoffset; - int err; + int offset, err; CHECK_HEADER(fdt); - if (startoffset >= 0) { - tag = fdt_next_tag(fdt, startoffset, &nextoffset); - if (tag != FDT_BEGIN_NODE) - return -FDT_ERR_BADOFFSET; - } else { - nextoffset = 0; - } - /* FIXME: The algorithm here is pretty horrible: we scan each * property of a node in fdt_node_check_compatible(), then if * that didn't find what we want, we scan over them again * making our way to the next node. Still it's the easiest to * implement approach; performance can come later. */ - do { - offset = nextoffset; - tag = fdt_next_tag(fdt, offset, &nextoffset); + for (offset = fdt_next_node(fdt, startoffset, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + err = fdt_node_check_compatible(fdt, offset, compatible); + if ((err < 0) && (err != -FDT_ERR_NOTFOUND)) + return err; + else if (err == 0) + return offset; + } - switch (tag) { - case FDT_BEGIN_NODE: - err = fdt_node_check_compatible(fdt, offset, - compatible); - if ((err < 0) - && (err != -FDT_ERR_NOTFOUND)) - return err; - else if (err == 0) - return offset; - break; - - case FDT_PROP: - case FDT_END: - case FDT_END_NODE: - case FDT_NOP: - break; - - default: - return -FDT_ERR_BADSTRUCTURE; - } - } while (tag != FDT_END); - - return -FDT_ERR_NOTFOUND; + return offset; /* error from fdt_next_node() */ } diff --git a/libfdt/fdt_rw.c b/libfdt/fdt_rw.c index 6673f8ec96..0df472bc5e 100644 --- a/libfdt/fdt_rw.c +++ b/libfdt/fdt_rw.c @@ -69,10 +69,8 @@ static int _blocks_misordered(const void *fdt, static int rw_check_header(void *fdt) { - int err; + CHECK_HEADER(fdt); - if ((err = fdt_check_header(fdt))) - return err; if (fdt_version(fdt) < 17) return -FDT_ERR_BADVERSION; if (_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry), @@ -252,6 +250,30 @@ static int _add_property(void *fdt, int nodeoffset, const char *name, int len, return 0; } +int fdt_set_name(void *fdt, int nodeoffset, const char *name) +{ + char *namep; + int oldlen, newlen; + int err; + + if ((err = rw_check_header(fdt))) + return err; + + namep = (char *)fdt_get_name(fdt, nodeoffset, &oldlen); + if (!namep) + return oldlen; + + newlen = strlen(name); + + err = _blob_splice_struct(fdt, namep, ALIGN(oldlen+1, FDT_TAGSIZE), + ALIGN(newlen+1, FDT_TAGSIZE)); + if (err) + return err; + + memcpy(namep, name, newlen+1); + return 0; +} + int fdt_setprop(void *fdt, int nodeoffset, const char *name, const void *val, int len) { @@ -309,7 +331,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, do { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); - } while (tag == FDT_PROP); + } while ((tag == FDT_PROP) || (tag == FDT_NOP)); nh = _fdt_offset_ptr_w(fdt, offset); nodelen = sizeof(*nh) + ALIGN(namelen+1, FDT_TAGSIZE) + FDT_TAGSIZE; @@ -375,9 +397,7 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) int newsize; void *tmp; - err = fdt_check_header(fdt); - if (err) - return err; + CHECK_HEADER(fdt); mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) * sizeof(struct fdt_reserve_entry); diff --git a/libfdt/libfdt_internal.h b/libfdt/libfdt_internal.h index 1e60936beb..52e1b8d810 100644 --- a/libfdt/libfdt_internal.h +++ b/libfdt/libfdt_internal.h @@ -58,6 +58,13 @@ #define memeq(p, q, n) (memcmp((p), (q), (n)) == 0) #define streq(p, q) (strcmp((p), (q)) == 0) +#define CHECK_HEADER(fdt) \ + { \ + int err; \ + if ((err = fdt_check_header(fdt)) != 0) \ + return err; \ + } + uint32_t _fdt_next_tag(const void *fdt, int startoffset, int *nextoffset); const char *_fdt_find_string(const char *strtab, int tabsize, const char *s); int _fdt_node_end_offset(void *fdt, int nodeoffset);