diff options
Diffstat (limited to 'libfdt')
-rw-r--r-- | libfdt/fdt.c | 46 | ||||
-rw-r--r-- | libfdt/fdt_ro.c | 277 | ||||
-rw-r--r-- | libfdt/fdt_rw.c | 34 | ||||
-rw-r--r-- | libfdt/libfdt_internal.h | 7 |
4 files changed, 161 insertions, 203 deletions
diff --git a/libfdt/fdt.c b/libfdt/fdt.c index 586a361..bd91712 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 12a37d5..63fa129 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; - - 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); + 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; + } - 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; - - case FDT_END_NODE: - if (overflow) { - overflow--; - break; - } - do { - p--; - } while (buf[p-1] != '/'); - break; + pdepth++; + } - case FDT_PROP: - case FDT_NOP: - break; + if (offset == nodeoffset) { + if (pdepth < (depth + 1)) + return -FDT_ERR_NOSPACE; - default: - return -FDT_ERR_BADSTRUCTURE; + if (p > 1) /* special case so that root path is "/", not "" */ + p--; + 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; - - case FDT_BEGIN_NODE: - level++; - if (level == supernodedepth) - supernodeoffset = offset; - break; - - case FDT_END_NODE: - level--; - break; + for (offset = 0, depth = 0; + (offset >= 0) && (offset <= nodeoffset); + offset = fdt_next_node(fdt, offset, &depth)) { + if (depth == supernodedepth) + supernodeoffset = offset; - case FDT_PROP: - case FDT_NOP: - break; + if (offset == nodeoffset) { + if (nodedepth) + *nodedepth = depth; - 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); - - 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); + 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; + } - 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); - - 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); + 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; + } - return -FDT_ERR_NOTFOUND; + return offset; /* error from fdt_next_node() */ } diff --git a/libfdt/fdt_rw.c b/libfdt/fdt_rw.c index 6673f8e..0df472b 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 1e60936..52e1b8d 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); |