diff options
author | Paul Mundt <lethal@linux-sh.org> | 2008-10-20 11:17:52 +0900 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2008-10-20 11:17:52 +0900 |
commit | 4cb40f795af36b3deb743f6ccf6c3fd542c61c8d (patch) | |
tree | db3d7519932549bf528f5b8e4cb8350356cd544d /arch/powerpc/boot/libfdt | |
parent | 79ed2a9216dd3cc35c4f2c5dbaddadb195af83ac (diff) | |
parent | 0cfd81031a26717fe14380d18275f8e217571615 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts:
Documentation/kernel-parameters.txt
arch/sh/include/asm/elf.h
Diffstat (limited to 'arch/powerpc/boot/libfdt')
-rw-r--r-- | arch/powerpc/boot/libfdt/Makefile.libfdt | 8 | ||||
-rw-r--r-- | arch/powerpc/boot/libfdt/fdt.c | 61 | ||||
-rw-r--r-- | arch/powerpc/boot/libfdt/fdt_ro.c | 329 | ||||
-rw-r--r-- | arch/powerpc/boot/libfdt/fdt_rw.c | 200 | ||||
-rw-r--r-- | arch/powerpc/boot/libfdt/fdt_strerror.c | 34 | ||||
-rw-r--r-- | arch/powerpc/boot/libfdt/fdt_sw.c | 55 | ||||
-rw-r--r-- | arch/powerpc/boot/libfdt/fdt_wip.c | 9 | ||||
-rw-r--r-- | arch/powerpc/boot/libfdt/libfdt.h | 383 | ||||
-rw-r--r-- | arch/powerpc/boot/libfdt/libfdt_internal.h | 24 |
9 files changed, 701 insertions, 402 deletions
diff --git a/arch/powerpc/boot/libfdt/Makefile.libfdt b/arch/powerpc/boot/libfdt/Makefile.libfdt index 82f9c6a8287..6c42acfa21e 100644 --- a/arch/powerpc/boot/libfdt/Makefile.libfdt +++ b/arch/powerpc/boot/libfdt/Makefile.libfdt @@ -3,12 +3,6 @@ # This is not a complete Makefile of itself. Instead, it is designed to # be easily embeddable into other systems of Makefiles. # -LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c LIBFDT_INCLUDES = fdt.h libfdt.h -LIBFDT_EXTRA = libfdt_internal.h -LIBFDT_LIB = libfdt/libfdt.a - +LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) - -$(LIBFDT_objdir)/$(LIBFDT_LIB): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS)) - diff --git a/arch/powerpc/boot/libfdt/fdt.c b/arch/powerpc/boot/libfdt/fdt.c index 586a36136db..2acaec5923a 100644 --- a/arch/powerpc/boot/libfdt/fdt.c +++ b/arch/powerpc/boot/libfdt/fdt.c @@ -63,7 +63,7 @@ int fdt_check_header(const void *fdt) 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) { + } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { /* Unfinished sequential-write blob */ if (fdt_size_dt_struct(fdt) == 0) return -FDT_ERR_BADSTATE; @@ -76,7 +76,7 @@ int fdt_check_header(const void *fdt) const void *fdt_offset_ptr(const void *fdt, int offset, int len) { - const void *p; + const char *p; if (fdt_version(fdt) >= 0x11) if (((offset + len) < offset) @@ -124,11 +124,59 @@ uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset) } if (nextoffset) - *nextoffset = ALIGN(offset, FDT_TAGSIZE); + *nextoffset = FDT_TAGALIGN(offset); return tag; } +int _fdt_check_node_offset(const void *fdt, int offset) +{ + if ((offset < 0) || (offset % FDT_TAGSIZE) + || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)) + return -FDT_ERR_BADOFFSET; + + return offset; +} + +int fdt_next_node(const void *fdt, int offset, int *depth) +{ + int nextoffset = 0; + uint32_t tag; + + if (offset >= 0) + if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0) + return nextoffset; + + 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; @@ -136,17 +184,14 @@ const char *_fdt_find_string(const char *strtab, int tabsize, const char *s) const char *p; for (p = strtab; p <= last; p++) - if (memeq(p, s, len)) + if (memcmp(p, s, len) == 0) return p; return NULL; } int fdt_move(const void *fdt, void *buf, int bufsize) { - int err = fdt_check_header(fdt); - - if (err) - return err; + FDT_CHECK_HEADER(fdt); if (fdt_totalsize(fdt) > bufsize) return -FDT_ERR_NOSPACE; diff --git a/arch/powerpc/boot/libfdt/fdt_ro.c b/arch/powerpc/boot/libfdt/fdt_ro.c index 12a37d59f96..129b532bcc1 100644 --- a/arch/powerpc/boot/libfdt/fdt_ro.c +++ b/arch/powerpc/boot/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) +static int _fdt_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 */ @@ -84,12 +77,12 @@ static int nodename_eq(const void *fdt, int offset, const char *fdt_string(const void *fdt, int stroffset) { - return (char *)fdt + fdt_off_dt_strings(fdt) + stroffset; + return (const 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); + FDT_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; @@ -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; - - 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; + int depth; - case FDT_PROP: - case FDT_NOP: - break; + FDT_CHECK_HEADER(fdt); - 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) + && _fdt_nodename_eq(fdt, offset, name, namelen)) + return offset; + } - return -FDT_ERR_NOTFOUND; + return offset; /* error */ } int fdt_subnode_offset(const void *fdt, int parentoffset, @@ -162,7 +129,7 @@ int fdt_path_offset(const void *fdt, const char *path) const char *p = path; int offset = 0; - CHECK_HEADER(fdt); + FDT_CHECK_HEADER(fdt); if (*path != '/') return -FDT_ERR_BADPATH; @@ -190,16 +157,12 @@ int fdt_path_offset(const void *fdt, const char *path) const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) { - const struct fdt_node_header *nh; + const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset); int err; - if ((err = fdt_check_header(fdt)) != 0) - goto fail; - - err = -FDT_ERR_BADOFFSET; - nh = fdt_offset_ptr(fdt, nodeoffset, sizeof(*nh)); - if (!nh || (fdt32_to_cpu(nh->tag) != FDT_BEGIN_NODE)) - goto fail; + if (((err = fdt_check_header(fdt)) != 0) + || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) + goto fail; if (len) *len = strlen(nh->name); @@ -222,17 +185,11 @@ const struct fdt_property *fdt_get_property(const void *fdt, int offset, nextoffset; int err; - if ((err = fdt_check_header(fdt)) != 0) - goto fail; - - err = -FDT_ERR_BADOFFSET; - if (nodeoffset % FDT_TAGSIZE) - goto fail; - - tag = fdt_next_tag(fdt, nodeoffset, &nextoffset); - if (tag != FDT_BEGIN_NODE) - goto fail; + if (((err = fdt_check_header(fdt)) != 0) + || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) + goto fail; + nextoffset = err; do { offset = nextoffset; @@ -253,7 +210,7 @@ const struct fdt_property *fdt_get_property(const void *fdt, if (! prop) goto fail; namestroff = fdt32_to_cpu(prop->nameoff); - if (streq(fdt_string(fdt, namestroff), name)) { + if (strcmp(fdt_string(fdt, namestroff), name) == 0) { /* Found it! */ int len = fdt32_to_cpu(prop->len); prop = fdt_offset_ptr(fdt, offset, @@ -307,115 +264,91 @@ 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; + FDT_CHECK_HEADER(fdt); 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); + FDT_CHECK_HEADER(fdt); 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 +376,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; - } + FDT_CHECK_HEADER(fdt); /* 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) @@ -499,10 +408,10 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) &phandle, sizeof(phandle)); } -int _stringlist_contains(const void *strlist, int listlen, const char *str) +int _stringlist_contains(const char *strlist, int listlen, const char *str) { int len = strlen(str); - const void *p; + const char *p; while (listlen >= len) { if (memcmp(str, strlist, len+1) == 0) @@ -534,50 +443,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; - - CHECK_HEADER(fdt); + int offset, err; - if (startoffset >= 0) { - tag = fdt_next_tag(fdt, startoffset, &nextoffset); - if (tag != FDT_BEGIN_NODE) - return -FDT_ERR_BADOFFSET; - } else { - nextoffset = 0; - } + FDT_CHECK_HEADER(fdt); /* 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/arch/powerpc/boot/libfdt/fdt_rw.c b/arch/powerpc/boot/libfdt/fdt_rw.c index 6673f8ec962..8e7ec4cb7bc 100644 --- a/arch/powerpc/boot/libfdt/fdt_rw.c +++ b/arch/powerpc/boot/libfdt/fdt_rw.c @@ -55,10 +55,10 @@ #include "libfdt_internal.h" -static int _blocks_misordered(const void *fdt, +static int _fdt_blocks_misordered(const void *fdt, int mem_rsv_size, int struct_size) { - return (fdt_off_mem_rsvmap(fdt) < ALIGN(sizeof(struct fdt_header), 8)) + return (fdt_off_mem_rsvmap(fdt) < 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) < @@ -67,16 +67,14 @@ static int _blocks_misordered(const void *fdt, (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); } -static int rw_check_header(void *fdt) +static int _fdt_rw_check_header(void *fdt) { - int err; + FDT_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), - fdt_size_dt_struct(fdt))) + if (_fdt_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); @@ -84,36 +82,37 @@ static int rw_check_header(void *fdt) return 0; } -#define RW_CHECK_HEADER(fdt) \ +#define FDT_RW_CHECK_HEADER(fdt) \ { \ int err; \ - if ((err = rw_check_header(fdt)) != 0) \ + if ((err = _fdt_rw_check_header(fdt)) != 0) \ return err; \ } -static inline int _blob_data_size(void *fdt) +static inline int _fdt_data_size(void *fdt) { return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); } -static int _blob_splice(void *fdt, void *p, int oldlen, int newlen) +static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen) { - void *end = fdt + _blob_data_size(fdt); + char *p = splicepoint; + char *end = (char *)fdt + _fdt_data_size(fdt); if (((p + oldlen) < p) || ((p + oldlen) > end)) return -FDT_ERR_BADOFFSET; - if ((end - oldlen + newlen) > (fdt + fdt_totalsize(fdt))) + if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt))) return -FDT_ERR_NOSPACE; memmove(p + newlen, p + oldlen, end - p - oldlen); return 0; } -static int _blob_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p, - int oldn, int newn) +static int _fdt_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)); + err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p)); if (err) return err; fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta); @@ -121,13 +120,13 @@ static int _blob_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p, return 0; } -static int _blob_splice_struct(void *fdt, void *p, - int oldlen, int newlen) +static int _fdt_splice_struct(void *fdt, void *p, + int oldlen, int newlen) { int delta = newlen - oldlen; int err; - if ((err = _blob_splice(fdt, p, oldlen, newlen))) + if ((err = _fdt_splice(fdt, p, oldlen, newlen))) return err; fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta); @@ -135,19 +134,20 @@ static int _blob_splice_struct(void *fdt, void *p, return 0; } -static int _blob_splice_string(void *fdt, int newlen) +static int _fdt_splice_string(void *fdt, int newlen) { - void *p = fdt + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); + void *p = (char *)fdt + + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); int err; - if ((err = _blob_splice(fdt, p, 0, newlen))) + if ((err = _fdt_splice(fdt, p, 0, newlen))) return err; fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen); return 0; } -static int _find_add_string(void *fdt, const char *s) +static int _fdt_find_add_string(void *fdt, const char *s) { char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); const char *p; @@ -161,7 +161,7 @@ static int _find_add_string(void *fdt, const char *s) return (p - strtab); new = strtab + fdt_size_dt_strings(fdt); - err = _blob_splice_string(fdt, len); + err = _fdt_splice_string(fdt, len); if (err) return err; @@ -174,11 +174,10 @@ 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; + FDT_RW_CHECK_HEADER(fdt); re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt)); - err = _blob_splice_mem_rsv(fdt, re, 0, 1); + err = _fdt_splice_mem_rsv(fdt, re, 0, 1); if (err) return err; @@ -192,19 +191,19 @@ 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; + FDT_RW_CHECK_HEADER(fdt); + if (n >= fdt_num_mem_rsv(fdt)) return -FDT_ERR_NOTFOUND; - err = _blob_splice_mem_rsv(fdt, re, 1, 0); + err = _fdt_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) +static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name, + int len, struct fdt_property **prop) { int oldlen; int err; @@ -213,36 +212,33 @@ static int _resize_property(void *fdt, int nodeoffset, const char *name, int len if (! (*prop)) return oldlen; - if ((err = _blob_splice_struct(fdt, (*prop)->data, - ALIGN(oldlen, FDT_TAGSIZE), - ALIGN(len, FDT_TAGSIZE)))) + if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen), + FDT_TAGALIGN(len)))) return err; (*prop)->len = cpu_to_fdt32(len); return 0; } -static int _add_property(void *fdt, int nodeoffset, const char *name, int len, - struct fdt_property **prop) +static int _fdt_add_property(void *fdt, int nodeoffset, const char *name, + int len, struct fdt_property **prop) { - uint32_t tag; int proplen; int nextoffset; int namestroff; int err; - tag = fdt_next_tag(fdt, nodeoffset, &nextoffset); - if (tag != FDT_BEGIN_NODE) - return -FDT_ERR_BADOFFSET; + if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) + return nextoffset; - namestroff = _find_add_string(fdt, name); + namestroff = _fdt_find_add_string(fdt, name); if (namestroff < 0) return namestroff; *prop = _fdt_offset_ptr_w(fdt, nextoffset); - proplen = sizeof(**prop) + ALIGN(len, FDT_TAGSIZE); + proplen = sizeof(**prop) + FDT_TAGALIGN(len); - err = _blob_splice_struct(fdt, *prop, 0, proplen); + err = _fdt_splice_struct(fdt, *prop, 0, proplen); if (err) return err; @@ -252,18 +248,40 @@ 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; + + FDT_RW_CHECK_HEADER(fdt); + + namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); + if (!namep) + return oldlen; + + newlen = strlen(name); + + err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1), + FDT_TAGALIGN(newlen+1)); + 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) { struct fdt_property *prop; int err; - if ((err = rw_check_header(fdt))) - return err; + FDT_RW_CHECK_HEADER(fdt); - err = _resize_property(fdt, nodeoffset, name, len, &prop); + err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop); if (err == -FDT_ERR_NOTFOUND) - err = _add_property(fdt, nodeoffset, name, len, &prop); + err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); if (err) return err; @@ -276,14 +294,14 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name) struct fdt_property *prop; int len, proplen; - RW_CHECK_HEADER(fdt); + FDT_RW_CHECK_HEADER(fdt); prop = fdt_get_property_w(fdt, nodeoffset, name, &len); if (! prop) return len; - proplen = sizeof(*prop) + ALIGN(len, FDT_TAGSIZE); - return _blob_splice_struct(fdt, prop, proplen, 0); + proplen = sizeof(*prop) + FDT_TAGALIGN(len); + return _fdt_splice_struct(fdt, prop, proplen, 0); } int fdt_add_subnode_namelen(void *fdt, int parentoffset, @@ -296,7 +314,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, uint32_t tag; uint32_t *endtag; - RW_CHECK_HEADER(fdt); + FDT_RW_CHECK_HEADER(fdt); offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); if (offset >= 0) @@ -309,19 +327,19 @@ 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; + nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE; - err = _blob_splice_struct(fdt, nh, 0, nodelen); + err = _fdt_splice_struct(fdt, nh, 0, nodelen); if (err) return err; nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); - memset(nh->name, 0, ALIGN(namelen+1, FDT_TAGSIZE)); + memset(nh->name, 0, FDT_TAGALIGN(namelen+1)); memcpy(nh->name, name, namelen); - endtag = (uint32_t *)((void *)nh + nodelen - FDT_TAGSIZE); + endtag = (uint32_t *)((char *)nh + nodelen - FDT_TAGSIZE); *endtag = cpu_to_fdt32(FDT_END_NODE); return offset; @@ -336,36 +354,36 @@ int fdt_del_node(void *fdt, int nodeoffset) { int endoffset; - RW_CHECK_HEADER(fdt); + FDT_RW_CHECK_HEADER(fdt); endoffset = _fdt_node_end_offset(fdt, nodeoffset); if (endoffset < 0) return endoffset; - return _blob_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset), - endoffset - nodeoffset, 0); + return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset), + endoffset - nodeoffset, 0); } -static void _packblocks(const void *fdt, void *buf, - int mem_rsv_size, int struct_size) +static void _fdt_packblocks(const char *old, char *new, + int mem_rsv_size, int struct_size) { int mem_rsv_off, struct_off, strings_off; - mem_rsv_off = ALIGN(sizeof(struct fdt_header), 8); + mem_rsv_off = FDT_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); + memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size); + fdt_set_off_mem_rsvmap(new, mem_rsv_off); - memmove(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); + memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size); + fdt_set_off_dt_struct(new, struct_off); + fdt_set_size_dt_struct(new, struct_size); - memmove(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)); + memmove(new + strings_off, old + fdt_off_dt_strings(old), + fdt_size_dt_strings(old)); + fdt_set_off_dt_strings(new, strings_off); + fdt_set_size_dt_strings(new, fdt_size_dt_strings(old)); } int fdt_open_into(const void *fdt, void *buf, int bufsize) @@ -373,11 +391,11 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) int err; int mem_rsv_size, struct_size; int newsize; - void *tmp; + const char *fdtstart = fdt; + const char *fdtend = fdtstart + fdt_totalsize(fdt); + char *tmp; - err = fdt_check_header(fdt); - if (err) - return err; + FDT_CHECK_HEADER(fdt); mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) * sizeof(struct fdt_reserve_entry); @@ -390,7 +408,7 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) ; } - if (!_blocks_misordered(fdt, mem_rsv_size, struct_size)) { + if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) { /* no further work necessary */ err = fdt_move(fdt, buf, bufsize); if (err) @@ -402,22 +420,23 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) } /* Need to reorder */ - newsize = ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size + newsize = FDT_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)) + /* First attempt to build converted tree at beginning of buffer */ + tmp = buf; + /* But if that overlaps with the old tree... */ + if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) { + /* Try right after the old tree instead */ + tmp = (char *)(uintptr_t)fdtend; + if ((tmp + newsize) > ((char *)buf + bufsize)) return -FDT_ERR_NOSPACE; } - _packblocks(fdt, tmp, mem_rsv_size, struct_size); + _fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size); memmove(buf, tmp, newsize); fdt_set_magic(buf, FDT_MAGIC); @@ -432,16 +451,13 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) int fdt_pack(void *fdt) { int mem_rsv_size; - int err; - err = rw_check_header(fdt); - if (err) - return err; + FDT_RW_CHECK_HEADER(fdt); 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)); + _fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt)); + fdt_set_totalsize(fdt, _fdt_data_size(fdt)); return 0; } diff --git a/arch/powerpc/boot/libfdt/fdt_strerror.c b/arch/powerpc/boot/libfdt/fdt_strerror.c index f9d32ef5360..e6c3ceee8c5 100644 --- a/arch/powerpc/boot/libfdt/fdt_strerror.c +++ b/arch/powerpc/boot/libfdt/fdt_strerror.c @@ -55,29 +55,29 @@ #include "libfdt_internal.h" -struct errtabent { +struct fdt_errtabent { const char *str; }; -#define ERRTABENT(val) \ +#define FDT_ERRTABENT(val) \ [(val)] = { .str = #val, } -static struct errtabent errtable[] = { - ERRTABENT(FDT_ERR_NOTFOUND), - ERRTABENT(FDT_ERR_EXISTS), - ERRTABENT(FDT_ERR_NOSPACE), +static struct fdt_errtabent fdt_errtable[] = { + FDT_ERRTABENT(FDT_ERR_NOTFOUND), + FDT_ERRTABENT(FDT_ERR_EXISTS), + FDT_ERRTABENT(FDT_ERR_NOSPACE), - ERRTABENT(FDT_ERR_BADOFFSET), - ERRTABENT(FDT_ERR_BADPATH), - ERRTABENT(FDT_ERR_BADSTATE), + FDT_ERRTABENT(FDT_ERR_BADOFFSET), + FDT_ERRTABENT(FDT_ERR_BADPATH), + FDT_ERRTABENT(FDT_ERR_BADSTATE), - ERRTABENT(FDT_ERR_TRUNCATED), - ERRTABENT(FDT_ERR_BADMAGIC), - ERRTABENT(FDT_ERR_BADVERSION), - ERRTABENT(FDT_ERR_BADSTRUCTURE), - ERRTABENT(FDT_ERR_BADLAYOUT), + FDT_ERRTABENT(FDT_ERR_TRUNCATED), + FDT_ERRTABENT(FDT_ERR_BADMAGIC), + FDT_ERRTABENT(FDT_ERR_BADVERSION), + FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), + FDT_ERRTABENT(FDT_ERR_BADLAYOUT), }; -#define ERRTABSIZE (sizeof(errtable) / sizeof(errtable[0])) +#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) const char *fdt_strerror(int errval) { @@ -85,8 +85,8 @@ const char *fdt_strerror(int errval) return "<valid offset/length>"; else if (errval == 0) return "<no error>"; - else if (errval > -ERRTABSIZE) { - const char *s = errtable[-errval].str; + else if (errval > -FDT_ERRTABSIZE) { + const char *s = fdt_errtable[-errval].str; if (s) return s; diff --git a/arch/powerpc/boot/libfdt/fdt_sw.c b/arch/powerpc/boot/libfdt/fdt_sw.c index dda2de34b2e..698329e0cca 100644 --- a/arch/powerpc/boot/libfdt/fdt_sw.c +++ b/arch/powerpc/boot/libfdt/fdt_sw.c @@ -55,14 +55,22 @@ #include "libfdt_internal.h" -static int check_header_sw(void *fdt) +static int _fdt_sw_check_header(void *fdt) { - if (fdt_magic(fdt) != SW_MAGIC) + if (fdt_magic(fdt) != FDT_SW_MAGIC) return -FDT_ERR_BADMAGIC; + /* FIXME: should check more details about the header state */ return 0; } -static void *grab_space(void *fdt, int len) +#define FDT_SW_CHECK_HEADER(fdt) \ + { \ + int err; \ + if ((err = _fdt_sw_check_header(fdt)) != 0) \ + return err; \ + } + +static void *_fdt_grab_space(void *fdt, int len) { int offset = fdt_size_dt_struct(fdt); int spaceleft; @@ -86,13 +94,13 @@ int fdt_create(void *buf, int bufsize) memset(buf, 0, bufsize); - fdt_set_magic(fdt, SW_MAGIC); + fdt_set_magic(fdt, FDT_SW_MAGIC); fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); fdt_set_totalsize(fdt, bufsize); - fdt_set_off_mem_rsvmap(fdt, ALIGN(sizeof(struct fdt_header), - sizeof(struct fdt_reserve_entry))); + fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header), + sizeof(struct fdt_reserve_entry))); fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); fdt_set_off_dt_strings(fdt, bufsize); @@ -102,11 +110,10 @@ int fdt_create(void *buf, int bufsize) int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) { struct fdt_reserve_entry *re; - int err = check_header_sw(fdt); int offset; - if (err) - return err; + FDT_SW_CHECK_HEADER(fdt); + if (fdt_size_dt_struct(fdt)) return -FDT_ERR_BADSTATE; @@ -114,7 +121,7 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) return -FDT_ERR_NOSPACE; - re = (struct fdt_reserve_entry *)(fdt + offset); + re = (struct fdt_reserve_entry *)((char *)fdt + offset); re->address = cpu_to_fdt64(addr); re->size = cpu_to_fdt64(size); @@ -131,13 +138,11 @@ int fdt_finish_reservemap(void *fdt) int fdt_begin_node(void *fdt, const char *name) { struct fdt_node_header *nh; - int err = check_header_sw(fdt); int namelen = strlen(name) + 1; - if (err) - return err; + FDT_SW_CHECK_HEADER(fdt); - nh = grab_space(fdt, sizeof(*nh) + ALIGN(namelen, FDT_TAGSIZE)); + nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); if (! nh) return -FDT_ERR_NOSPACE; @@ -149,12 +154,10 @@ int fdt_begin_node(void *fdt, const char *name) int fdt_end_node(void *fdt) { uint32_t *en; - int err = check_header_sw(fdt); - if (err) - return err; + FDT_SW_CHECK_HEADER(fdt); - en = grab_space(fdt, FDT_TAGSIZE); + en = _fdt_grab_space(fdt, FDT_TAGSIZE); if (! en) return -FDT_ERR_NOSPACE; @@ -162,7 +165,7 @@ int fdt_end_node(void *fdt) return 0; } -static int find_add_string(void *fdt, const char *s) +static int _fdt_find_add_string(void *fdt, const char *s) { char *strtab = (char *)fdt + fdt_totalsize(fdt); const char *p; @@ -188,17 +191,15 @@ static int find_add_string(void *fdt, const char *s) int fdt_property(void *fdt, const char *name, const void *val, int len) { struct fdt_property *prop; - int err = check_header_sw(fdt); int nameoff; - if (err) - return err; + FDT_SW_CHECK_HEADER(fdt); - nameoff = find_add_string(fdt, name); + nameoff = _fdt_find_add_string(fdt, name); if (nameoff == 0) return -FDT_ERR_NOSPACE; - prop = grab_space(fdt, sizeof(*prop) + ALIGN(len, FDT_TAGSIZE)); + prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); if (! prop) return -FDT_ERR_NOSPACE; @@ -211,18 +212,16 @@ int fdt_property(void *fdt, const char *name, const void *val, int len) int fdt_finish(void *fdt) { - int err = check_header_sw(fdt); char *p = (char *)fdt; uint32_t *end; int oldstroffset, newstroffset; uint32_t tag; int offset, nextoffset; - if (err) - return err; + FDT_SW_CHECK_HEADER(fdt); /* Add terminator */ - end = grab_space(fdt, sizeof(*end)); + end = _fdt_grab_space(fdt, sizeof(*end)); if (! end) return -FDT_ERR_NOSPACE; *end = cpu_to_fdt32(FDT_END); diff --git a/arch/powerpc/boot/libfdt/fdt_wip.c b/arch/powerpc/boot/libfdt/fdt_wip.c index 88e24b8318f..a4652c6e787 100644 --- a/arch/powerpc/boot/libfdt/fdt_wip.c +++ b/arch/powerpc/boot/libfdt/fdt_wip.c @@ -72,11 +72,11 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, return 0; } -static void nop_region(void *start, int len) +static void _fdt_nop_region(void *start, int len) { uint32_t *p; - for (p = start; (void *)p < (start + len); p++) + for (p = start; (char *)p < ((char *)start + len); p++) *p = cpu_to_fdt32(FDT_NOP); } @@ -89,7 +89,7 @@ int fdt_nop_property(void *fdt, int nodeoffset, const char *name) if (! prop) return len; - nop_region(prop, len + sizeof(*prop)); + _fdt_nop_region(prop, len + sizeof(*prop)); return 0; } @@ -139,6 +139,7 @@ int fdt_nop_node(void *fdt, int nodeoffset) if (endoffset < 0) return endoffset; - nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0), endoffset - nodeoffset); + _fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0), + endoffset - nodeoffset); return 0; } diff --git a/arch/powerpc/boot/libfdt/libfdt.h b/arch/powerpc/boot/libfdt/libfdt.h index 6b2fb92ea35..ce80e4fb41b 100644 --- a/arch/powerpc/boot/libfdt/libfdt.h +++ b/arch/powerpc/boot/libfdt/libfdt.h @@ -125,12 +125,18 @@ const void *fdt_offset_ptr(const void *fdt, int offset, int checklen); static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) { - return (void *)fdt_offset_ptr(fdt, offset, checklen); + return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, 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 */ /**********************************************************************/ @@ -207,7 +213,7 @@ int fdt_move(const void *fdt, void *buf, int bufsize); /**********************************************************************/ /** - * fdt_string - retreive a string from the strings block of a device tree + * fdt_string - retrieve a string from the strings block of a device tree * @fdt: pointer to the device tree blob * @stroffset: offset of the string within the strings block (native endian) * @@ -221,7 +227,7 @@ int fdt_move(const void *fdt, void *buf, int bufsize); const char *fdt_string(const void *fdt, int stroffset); /** - * fdt_num_mem_rsv - retreive the number of memory reserve map entries + * fdt_num_mem_rsv - retrieve the number of memory reserve map entries * @fdt: pointer to the device tree blob * * Returns the number of entries in the device tree blob's memory @@ -234,7 +240,7 @@ const char *fdt_string(const void *fdt, int stroffset); int fdt_num_mem_rsv(const void *fdt); /** - * fdt_get_mem_rsv - retreive one memory reserve map entry + * fdt_get_mem_rsv - retrieve one memory reserve map entry * @fdt: pointer to the device tree blob * @address, @size: pointers to 64-bit variables * @@ -314,7 +320,7 @@ int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); int fdt_path_offset(const void *fdt, const char *path); /** - * fdt_get_name - retreive the name of a given node + * fdt_get_name - retrieve the name of a given node * @fdt: pointer to the device tree blob * @nodeoffset: structure block offset of the starting node * @lenp: pointer to an integer variable (will be overwritten) or NULL @@ -346,7 +352,7 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp); * fdt_get_property() retrieves a pointer to the fdt_property * structure within the device tree blob corresponding to the property * named 'name' of the node at offset nodeoffset. If lenp is - * non-NULL, the length of the property value also returned, in the + * non-NULL, the length of the property value is also returned, in the * integer pointed to by lenp. * * returns: @@ -369,8 +375,8 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, const char *name, int *lenp) { - return (struct fdt_property *)fdt_get_property(fdt, nodeoffset, - name, lenp); + return (struct fdt_property *)(uintptr_t) + fdt_get_property(fdt, nodeoffset, name, lenp); } /** @@ -383,7 +389,7 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, * fdt_getprop() retrieves a pointer to the value of the property * named 'name' of the node at offset nodeoffset (this will be a * pointer to within the device blob itself, not a copy of the value). - * If lenp is non-NULL, the length of the property value also + * If lenp is non-NULL, the length of the property value is also * returned, in the integer pointed to by lenp. * * returns: @@ -405,11 +411,11 @@ const void *fdt_getprop(const void *fdt, int nodeoffset, static inline void *fdt_getprop_w(void *fdt, int nodeoffset, const char *name, int *lenp) { - return (void *)fdt_getprop(fdt, nodeoffset, name, lenp); + return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp); } /** - * fdt_get_phandle - retreive the phandle of a given node + * fdt_get_phandle - retrieve the phandle of a given node * @fdt: pointer to the device tree blob * @nodeoffset: structure block offset of the node * @@ -417,7 +423,7 @@ static inline void *fdt_getprop_w(void *fdt, int nodeoffset, * structure block offset nodeoffset. * * returns: - * the phandle of the node at nodeoffset, on succes (!= 0, != -1) + * the phandle of the node at nodeoffset, on success (!= 0, != -1) * 0, if the node has no phandle, or another error occurs */ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); @@ -516,7 +522,7 @@ int fdt_node_depth(const void *fdt, int nodeoffset); * structure from the start to nodeoffset, *twice*. * * returns: - * stucture block offset of the parent of the node at nodeoffset + * structure block offset of the parent of the node at nodeoffset * (>=0), on success * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, @@ -573,7 +579,7 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, * @fdt: pointer to the device tree blob * @phandle: phandle value * - * fdt_node_offset_by_prop_value() returns the offset of the node + * fdt_node_offset_by_phandle() returns the offset of the node * which has the given phandle value. If there is more than one node * in the tree with the given phandle (an invalid tree), results are * undefined. @@ -655,8 +661,65 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, /* Write-in-place functions */ /**********************************************************************/ +/** + * fdt_setprop_inplace - change a property's value, but not its size + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: pointer to data to replace the property value with + * @len: length of the property value + * + * fdt_setprop_inplace() replaces the value of a given property with + * the data in val, of length len. This function cannot change the + * size of a property, and so will only work if len is equal to the + * current length of the property. + * + * This function will alter only the bytes in the blob which contain + * the given property value, and will not alter or move any other part + * of the tree. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, if len is not equal to the property's current length + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, const void *val, int len); + +/** + * fdt_setprop_inplace_cell - change the value of a single-cell property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: cell (32-bit integer) value to replace the property with + * + * fdt_setprop_inplace_cell() replaces the value of a given property + * with the 32-bit integer cell value in val, converting val to + * big-endian if necessary. This function cannot change the size of a + * property, and so will only work if the property already exists and + * has length 4. + * + * This function will alter only the bytes in the blob which contain + * the given property value, and will not alter or move any other part + * of the tree. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, if the property's length is not equal to 4 + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, const char *name, uint32_t val) { @@ -664,7 +727,54 @@ static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val)); } +/** + * fdt_nop_property - replace a property with nop tags + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to nop + * @name: name of the property to nop + * + * fdt_nop_property() will replace a given property's representation + * in the blob with FDT_NOP tags, effectively removing it from the + * tree. + * + * This function will alter only the bytes in the blob which contain + * the property, and will not alter or move any other part of the + * tree. + * + * returns: + * 0, on success + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ int fdt_nop_property(void *fdt, int nodeoffset, const char *name); + +/** + * fdt_nop_node - replace a node (subtree) with nop tags + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node to nop + * + * fdt_nop_node() will replace a given node's representation in the + * blob, including all its subnodes, if any, with FDT_NOP tags, + * effectively removing it from the tree. + * + * This function will alter only the bytes in the blob which contain + * the node and its properties and subnodes, and will not alter or + * move any other part of the tree. + * + * returns: + * 0, on success + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ int fdt_nop_node(void *fdt, int nodeoffset); /**********************************************************************/ @@ -693,23 +803,268 @@ int fdt_finish(void *fdt); int fdt_open_into(const void *fdt, void *buf, int bufsize); int fdt_pack(void *fdt); +/** + * fdt_add_mem_rsv - add one memory reserve map entry + * @fdt: pointer to the device tree blob + * @address, @size: 64-bit values (native endian) + * + * Adds a reserve map entry to the given blob reserving a region at + * address address of length size. + * + * This function will insert data into the reserve map and will + * therefore change the indexes of some entries in the table. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new reservation entry + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size); + +/** + * fdt_del_mem_rsv - remove a memory reserve map entry + * @fdt: pointer to the device tree blob + * @n: entry to remove + * + * fdt_del_mem_rsv() removes the n-th memory reserve map entry from + * the blob. + * + * This function will delete data from the reservation table and will + * therefore change the indexes of some entries in the table. + * + * returns: + * 0, on success + * -FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there + * are less than n+1 reserve map entries) + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ 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 + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: pointer to data to set the property value to + * @len: length of the property value + * + * fdt_setprop() sets the value of the named property in the given + * node to the given value and length, creating the property if it + * does not already exist. + * + * 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 property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ int fdt_setprop(void *fdt, int nodeoffset, const char *name, const void *val, int len); + +/** + * fdt_setprop_cell - set a property to a single cell value + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 32-bit integer value for the property (native endian) + * + * fdt_setprop_cell() sets the value of the named property in the + * given node to the given cell value (converting to big-endian if + * necessary), or creates a new property with that value if it does + * not already exist. + * + * 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 property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, uint32_t val) { val = cpu_to_fdt32(val); return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val)); } + +/** + * fdt_setprop_string - set a property to a string value + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @str: string value for the property + * + * fdt_setprop_string() sets the value of the named property in the + * given node to the given string value (using the length of the + * string to determine the new length of the property), or creates a + * new property with that value if it does not already exist. + * + * 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 property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ #define fdt_setprop_string(fdt, nodeoffset, name, str) \ fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) + +/** + * fdt_delprop - delete a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to nop + * @name: name of the property to nop + * + * fdt_del_property() will delete the given property. + * + * This function will delete data from the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ int fdt_delprop(void *fdt, int nodeoffset, const char *name); + +/** + * fdt_add_subnode_namelen - creates a new node based on substring + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * @namelen: number of characters of name to consider + * + * Identical to fdt_add_subnode(), but use only the first namelen + * characters of name as the name of the new node. This is useful for + * creating subnodes based on a portion of a larger string, such as a + * full path. + */ int fdt_add_subnode_namelen(void *fdt, int parentoffset, const char *name, int namelen); + +/** + * fdt_add_subnode - creates a new node + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * + * fdt_add_subnode() creates a new node as a subnode of the node at + * structure block offset parentoffset, with the given name (which + * should include the unit address, if any). + * + * This function will insert data into the blob, and will therefore + * change the offsets of some existing nodes. + + * returns: + * structure block offset of the created nodeequested subnode (>=0), on success + * -FDT_ERR_NOTFOUND, if the requested subnode does not exist + * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag + * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of + * the given name + * -FDT_ERR_NOSPACE, if there is insufficient free space in the + * blob to contain the new node + * -FDT_ERR_NOSPACE + * -FDT_ERR_BADLAYOUT + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ int fdt_add_subnode(void *fdt, int parentoffset, const char *name); + +/** + * fdt_del_node - delete a node (subtree) + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node to nop + * + * fdt_del_node() will remove the given node, including all its + * subnodes if any, from the blob. + * + * This function will delete data from the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ int fdt_del_node(void *fdt, int nodeoffset); /**********************************************************************/ diff --git a/arch/powerpc/boot/libfdt/libfdt_internal.h b/arch/powerpc/boot/libfdt/libfdt_internal.h index 1e60936beb5..46eb93e4af5 100644 --- a/arch/powerpc/boot/libfdt/libfdt_internal.h +++ b/arch/powerpc/boot/libfdt/libfdt_internal.h @@ -52,38 +52,44 @@ */ #include <fdt.h> -#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) -#define PALIGN(p, a) ((void *)ALIGN((unsigned long)(p), (a))) +#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) -#define memeq(p, q, n) (memcmp((p), (q), (n)) == 0) -#define streq(p, q) (strcmp((p), (q)) == 0) +#define FDT_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); +int _fdt_check_node_offset(const void *fdt, int offset); const char *_fdt_find_string(const char *strtab, int tabsize, const char *s); int _fdt_node_end_offset(void *fdt, int nodeoffset); static inline const void *_fdt_offset_ptr(const void *fdt, int offset) { - return fdt + fdt_off_dt_struct(fdt) + offset; + return (const char *)fdt + fdt_off_dt_struct(fdt) + offset; } static inline void *_fdt_offset_ptr_w(void *fdt, int offset) { - return (void *)_fdt_offset_ptr(fdt, offset); + return (void *)(uintptr_t)_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); + (const struct fdt_reserve_entry *) + ((const char *)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); + return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n); } -#define SW_MAGIC (~FDT_MAGIC) +#define FDT_SW_MAGIC (~FDT_MAGIC) #endif /* _LIBFDT_INTERNAL_H */ |