fdt: Sync up to the latest libfdt
authorSimon Glass <sjg@chromium.org>
Sun, 27 Oct 2019 15:47:42 +0000 (09:47 -0600)
committerSimon Glass <sjg@chromium.org>
Tue, 5 Nov 2019 01:15:32 +0000 (18:15 -0700)
Bring over the fdt from this commit:

430419c (origin/master) tests: fix some python warnings

adding in the 'assumptions' series designed to reduce code size.

Signed-off-by: Simon Glass <sjg@chromium.org>
16 files changed:
lib/libfdt/fdt_ro.c
scripts/dtc/libfdt/Makefile.libfdt
scripts/dtc/libfdt/fdt.c
scripts/dtc/libfdt/fdt.h
scripts/dtc/libfdt/fdt_addresses.c
scripts/dtc/libfdt/fdt_empty_tree.c
scripts/dtc/libfdt/fdt_overlay.c
scripts/dtc/libfdt/fdt_ro.c
scripts/dtc/libfdt/fdt_rw.c
scripts/dtc/libfdt/fdt_strerror.c
scripts/dtc/libfdt/fdt_sw.c
scripts/dtc/libfdt/fdt_wip.c
scripts/dtc/libfdt/libfdt.h
scripts/dtc/libfdt/libfdt_env.h
scripts/dtc/libfdt/libfdt_internal.h
tools/libfdt/fdt_rw.c

index 693de9aa5ad8032375b22749a25bc236dc15d950..560041b603e1a7a1928a5816bf76dc91bed38122 100644 (file)
 
 #include "libfdt_internal.h"
 
-static int _fdt_nodename_eq(const void *fdt, int offset,
+static int fdt_nodename_eq_(const void *fdt, int offset,
                            const char *s, int len)
 {
-       const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
+       int olen;
+       const char *p = fdt_get_name(fdt, offset, &olen);
 
-       if (!p)
+       if (!p || (fdt_chk_extra() && olen < len))
                /* short match */
                return 0;
 
@@ -34,46 +35,85 @@ static int _fdt_nodename_eq(const void *fdt, int offset,
                return 0;
 }
 
-const char *fdt_string(const void *fdt, int stroffset)
-{
-       return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
-}
-
-static int _fdt_string_eq(const void *fdt, int stroffset,
-                         const char *s, int len)
+const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
 {
-       const char *p = fdt_string(fdt, stroffset);
+       int32_t totalsize;
+       uint32_t absoffset;
+       size_t len;
+       int err;
+       const char *s, *n;
 
-       return (strnlen(p, len + 1) == len) && (memcmp(p, s, len) == 0);
-}
+       if (!fdt_chk_extra()) {
+               s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
 
-uint32_t fdt_get_max_phandle(const void *fdt)
-{
-       uint32_t max_phandle = 0;
-       int offset;
+               if (lenp)
+                       *lenp = strlen(s);
+               return s;
+       }
+       totalsize = fdt_ro_probe_(fdt);
+       err = totalsize;
+       if (totalsize < 0)
+               goto fail;
+
+       err = -FDT_ERR_BADOFFSET;
+       absoffset = stroffset + fdt_off_dt_strings(fdt);
+       if (absoffset >= totalsize)
+               goto fail;
+       len = totalsize - absoffset;
+
+       if (fdt_magic(fdt) == FDT_MAGIC) {
+               if (stroffset < 0)
+                       goto fail;
+               if (!fdt_chk_version() || fdt_version(fdt) >= 17) {
+                       if (stroffset >= fdt_size_dt_strings(fdt))
+                               goto fail;
+                       if ((fdt_size_dt_strings(fdt) - stroffset) < len)
+                               len = fdt_size_dt_strings(fdt) - stroffset;
+               }
+       } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
+               if ((stroffset >= 0)
+                   || (stroffset < -fdt_size_dt_strings(fdt)))
+                       goto fail;
+               if ((-stroffset) < len)
+                       len = -stroffset;
+       } else {
+               err = -FDT_ERR_INTERNAL;
+               goto fail;
+       }
 
-       for (offset = fdt_next_node(fdt, -1, NULL);;
-            offset = fdt_next_node(fdt, offset, NULL)) {
-               uint32_t phandle;
+       s = (const char *)fdt + absoffset;
+       n = memchr(s, '\0', len);
+       if (!n) {
+               /* missing terminating NULL */
+               err = -FDT_ERR_TRUNCATED;
+               goto fail;
+       }
 
-               if (offset == -FDT_ERR_NOTFOUND)
-                       return max_phandle;
+       if (lenp)
+               *lenp = n - s;
+       return s;
 
-               if (offset < 0)
-                       return (uint32_t)-1;
+fail:
+       if (lenp)
+               *lenp = err;
+       return NULL;
+}
 
-               phandle = fdt_get_phandle(fdt, offset);
-               if (phandle == (uint32_t)-1)
-                       continue;
+const char *fdt_string(const void *fdt, int stroffset)
+{
+       return fdt_get_string(fdt, stroffset, NULL);
+}
 
-               if (phandle > max_phandle)
-                       max_phandle = phandle;
-       }
+static int fdt_string_eq_(const void *fdt, int stroffset,
+                         const char *s, int len)
+{
+       int slen;
+       const char *p = fdt_get_string(fdt, stroffset, &slen);
 
-       return 0;
+       return p && (slen == len) && (memcmp(p, s, len) == 0);
 }
 
-int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
+int fdt_find_max_phandle(const void *fdt, uint32_t *phandle)
 {
        uint32_t max = 0;
        int offset = -1;
@@ -95,6 +135,21 @@ int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
                        max = value;
        }
 
+       if (phandle)
+               *phandle = max;
+
+       return 0;
+}
+
+int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
+{
+       uint32_t max;
+       int err;
+
+       err = fdt_find_max_phandle(fdt, &max);
+       if (err < 0)
+               return err;
+
        if (max == FDT_MAX_PHANDLE)
                return -FDT_ERR_NOPHANDLES;
 
@@ -104,24 +159,48 @@ int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
        return 0;
 }
 
+static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
+{
+       int offset = n * sizeof(struct fdt_reserve_entry);
+       int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
+
+       if (fdt_chk_extra()) {
+               if (absoffset < fdt_off_mem_rsvmap(fdt))
+                       return NULL;
+               if (absoffset > fdt_totalsize(fdt) -
+                   sizeof(struct fdt_reserve_entry))
+                       return NULL;
+       }
+       return fdt_mem_rsv_(fdt, n);
+}
+
 int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
 {
-       FDT_CHECK_HEADER(fdt);
-       *address = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->address);
-       *size = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->size);
+       const struct fdt_reserve_entry *re;
+
+       FDT_RO_PROBE(fdt);
+       re = fdt_mem_rsv(fdt, n);
+       if (fdt_chk_extra() && !re)
+               return -FDT_ERR_BADOFFSET;
+
+       *address = fdt64_ld(&re->address);
+       *size = fdt64_ld(&re->size);
        return 0;
 }
 
 int fdt_num_mem_rsv(const void *fdt)
 {
-       int i = 0;
+       int i;
+       const struct fdt_reserve_entry *re;
 
-       while (fdt64_to_cpu(fdt_mem_rsv_(fdt, i)->size) != 0)
-               i++;
-       return i;
+       for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
+               if (fdt64_ld(&re->size) == 0)
+                       return i;
+       }
+       return -FDT_ERR_TRUNCATED;
 }
 
-static int _nextprop(const void *fdt, int offset)
+static int nextprop_(const void *fdt, int offset)
 {
        uint32_t tag;
        int nextoffset;
@@ -150,13 +229,13 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset,
 {
        int depth;
 
-       FDT_CHECK_HEADER(fdt);
+       FDT_RO_PROBE(fdt);
 
        for (depth = 0;
             (offset >= 0) && (depth >= 0);
             offset = fdt_next_node(fdt, offset, &depth))
                if ((depth == 1)
-                   && _fdt_nodename_eq(fdt, offset, name, namelen))
+                   && fdt_nodename_eq_(fdt, offset, name, namelen))
                        return offset;
 
        if (depth < 0)
@@ -170,36 +249,17 @@ int fdt_subnode_offset(const void *fdt, int parentoffset,
        return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
 }
 
-/*
- * Find the next of path separator, note we need to search for both '/' and ':'
- * and then take the first one so that we do the right thing for e.g.
- * "foo/bar:option" and "bar:option/otheroption", both of which happen, so
- * first searching for either ':' or '/' does not work.
- */
-static const char *fdt_path_next_separator(const char *path, int len)
-{
-       const void *sep1 = memchr(path, '/', len);
-       const void *sep2 = memchr(path, ':', len);
-
-       if (sep1 && sep2)
-               return (sep1 < sep2) ? sep1 : sep2;
-       else if (sep1)
-               return sep1;
-       else
-               return sep2;
-}
-
 int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
 {
        const char *end = path + namelen;
        const char *p = path;
        int offset = 0;
 
-       FDT_CHECK_HEADER(fdt);
+       FDT_RO_PROBE(fdt);
 
        /* see if we have an alias */
        if (*path != '/') {
-               const char *q = fdt_path_next_separator(path, namelen);
+               const char *q = memchr(path, '/', end - p);
 
                if (!q)
                        q = end;
@@ -212,17 +272,16 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
                p = q;
        }
 
-       while (*p && (p < end)) {
+       while (p < end) {
                const char *q;
 
-               while (*p == '/')
+               while (*p == '/') {
                        p++;
-
-               if (*p == '\0' || *p == ':')
-                       return offset;
-
-               q = fdt_path_next_separator(p, end - p);
-               if (!q)
+                       if (p == end)
+                               return offset;
+               }
+               q = memchr(p, '/', end - p);
+               if (! q)
                        q = end;
 
                offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
@@ -243,16 +302,35 @@ 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 = fdt_offset_ptr_(fdt, nodeoffset);
+       const char *nameptr;
        int err;
 
-       if (((err = fdt_check_header(fdt)) != 0)
-           || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
+       if (fdt_chk_extra() &&
+           (((err = fdt_ro_probe_(fdt)) < 0)
+            || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)))
+               goto fail;
+
+       nameptr = nh->name;
+
+       if (fdt_chk_version() && fdt_version(fdt) < 0x10) {
+               /*
+                * For old FDT versions, match the naming conventions of V16:
+                * give only the leaf name (after all /). The actual tree
+                * contents are loosely checked.
+                */
+               const char *leaf;
+               leaf = strrchr(nameptr, '/');
+               if (leaf == NULL) {
+                       err = -FDT_ERR_BADSTRUCTURE;
                        goto fail;
+               }
+               nameptr = leaf+1;
+       }
 
        if (len)
-               *len = strlen(nh->name);
+               *len = strlen(nameptr);
 
-       return nh->name;
+       return nameptr;
 
  fail:
        if (len)
@@ -267,7 +345,7 @@ int fdt_first_property_offset(const void *fdt, int nodeoffset)
        if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
                return offset;
 
-       return _nextprop(fdt, offset);
+       return nextprop_(fdt, offset);
 }
 
 int fdt_next_property_offset(const void *fdt, int offset)
@@ -275,17 +353,17 @@ int fdt_next_property_offset(const void *fdt, int offset)
        if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0)
                return offset;
 
-       return _nextprop(fdt, offset);
+       return nextprop_(fdt, offset);
 }
 
-const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
-                                                     int offset,
-                                                     int *lenp)
+static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
+                                                             int offset,
+                                                             int *lenp)
 {
        int err;
        const struct fdt_property *prop;
 
-       if ((err = fdt_check_prop_offset_(fdt, offset)) < 0) {
+       if (fdt_chk_basic() && (err = fdt_check_prop_offset_(fdt, offset)) < 0) {
                if (lenp)
                        *lenp = err;
                return NULL;
@@ -294,28 +372,50 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
        prop = fdt_offset_ptr_(fdt, offset);
 
        if (lenp)
-               *lenp = fdt32_to_cpu(prop->len);
+               *lenp = fdt32_ld(&prop->len);
 
        return prop;
 }
 
-const struct fdt_property *fdt_get_property_namelen(const void *fdt,
-                                                   int offset,
-                                                   const char *name,
-                                                   int namelen, int *lenp)
+const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
+                                                     int offset,
+                                                     int *lenp)
+{
+       /* Prior to version 16, properties may need realignment
+        * and this API does not work. fdt_getprop_*() will, however. */
+
+       if (fdt_chk_version() && fdt_version(fdt) < 0x10) {
+               if (lenp)
+                       *lenp = -FDT_ERR_BADVERSION;
+               return NULL;
+       }
+
+       return fdt_get_property_by_offset_(fdt, offset, lenp);
+}
+
+static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
+                                                           int offset,
+                                                           const char *name,
+                                                           int namelen,
+                                                           int *lenp,
+                                                           int *poffset)
 {
        for (offset = fdt_first_property_offset(fdt, offset);
             (offset >= 0);
             (offset = fdt_next_property_offset(fdt, offset))) {
                const struct fdt_property *prop;
 
-               if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) {
+               prop = fdt_get_property_by_offset_(fdt, offset, lenp);
+               if (fdt_chk_extra() && !prop) {
                        offset = -FDT_ERR_INTERNAL;
                        break;
                }
-               if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),
-                                  name, namelen))
+               if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff),
+                                  name, namelen)) {
+                       if (poffset)
+                               *poffset = offset;
                        return prop;
+               }
        }
 
        if (lenp)
@@ -323,6 +423,25 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt,
        return NULL;
 }
 
+
+const struct fdt_property *fdt_get_property_namelen(const void *fdt,
+                                                   int offset,
+                                                   const char *name,
+                                                   int namelen, int *lenp)
+{
+       /* Prior to version 16, properties may need realignment
+        * and this API does not work. fdt_getprop_*() will, however. */
+       if (fdt_chk_version() && fdt_version(fdt) < 0x10) {
+               if (lenp)
+                       *lenp = -FDT_ERR_BADVERSION;
+               return NULL;
+       }
+
+       return fdt_get_property_namelen_(fdt, offset, name, namelen, lenp,
+                                        NULL);
+}
+
+
 const struct fdt_property *fdt_get_property(const void *fdt,
                                            int nodeoffset,
                                            const char *name, int *lenp)
@@ -334,12 +453,18 @@ const struct fdt_property *fdt_get_property(const void *fdt,
 const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
                                const char *name, int namelen, int *lenp)
 {
+       int poffset;
        const struct fdt_property *prop;
 
-       prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
+       prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp,
+                                        &poffset);
        if (!prop)
                return NULL;
 
+       /* Handle realignment */
+       if (fdt_chk_version() && fdt_version(fdt) < 0x10 &&
+           (poffset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
+               return prop->data + 4;
        return prop->data;
 }
 
@@ -348,11 +473,31 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
 {
        const struct fdt_property *prop;
 
-       prop = fdt_get_property_by_offset(fdt, offset, lenp);
+       prop = fdt_get_property_by_offset_(fdt, offset, lenp);
        if (!prop)
                return NULL;
-       if (namep)
-               *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+       if (namep) {
+               const char *name;
+               int namelen;
+
+               if (fdt_chk_extra()) {
+                       name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff),
+                                             &namelen);
+                       if (!name) {
+                               if (lenp)
+                                       *lenp = namelen;
+                               return NULL;
+                       }
+                       *namep = name;
+               } else {
+                       *namep = fdt_string(fdt, fdt32_ld(&prop->nameoff));
+               }
+       }
+
+       /* Handle realignment */
+       if (fdt_chk_version() && fdt_version(fdt) < 0x10 &&
+           (offset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
+               return prop->data + 4;
        return prop->data;
 }
 
@@ -376,7 +521,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
                        return 0;
        }
 
-       return fdt32_to_cpu(*php);
+       return fdt32_ld(php);
 }
 
 const char *fdt_get_alias_namelen(const void *fdt,
@@ -402,7 +547,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
        int offset, depth, namelen;
        const char *name;
 
-       FDT_CHECK_HEADER(fdt);
+       FDT_RO_PROBE(fdt);
 
        if (buflen < 2)
                return -FDT_ERR_NOSPACE;
@@ -454,7 +599,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
        int offset, depth;
        int supernodeoffset = -FDT_ERR_INTERNAL;
 
-       FDT_CHECK_HEADER(fdt);
+       FDT_RO_PROBE(fdt);
 
        if (supernodedepth < 0)
                return -FDT_ERR_NOTFOUND;
@@ -476,10 +621,12 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
                }
        }
 
-       if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
-               return -FDT_ERR_BADOFFSET;
-       else if (offset == -FDT_ERR_BADOFFSET)
-               return -FDT_ERR_BADSTRUCTURE;
+       if (fdt_chk_extra()) {
+               if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+                       return -FDT_ERR_BADOFFSET;
+               else if (offset == -FDT_ERR_BADOFFSET)
+                       return -FDT_ERR_BADSTRUCTURE;
+       }
 
        return offset; /* error from fdt_next_node() */
 }
@@ -491,7 +638,7 @@ int fdt_node_depth(const void *fdt, int nodeoffset)
 
        err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
        if (err)
-               return (err < 0) ? err : -FDT_ERR_INTERNAL;
+               return (!fdt_chk_extra() || err < 0) ? err : -FDT_ERR_INTERNAL;
        return nodedepth;
 }
 
@@ -513,7 +660,7 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
        const void *val;
        int len;
 
-       FDT_CHECK_HEADER(fdt);
+       FDT_RO_PROBE(fdt);
 
        /* FIXME: The algorithm here is pretty horrible: we scan each
         * property of a node in fdt_getprop(), then if that didn't
@@ -539,7 +686,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
        if ((phandle == 0) || (phandle == -1))
                return -FDT_ERR_BADPHANDLE;
 
-       FDT_CHECK_HEADER(fdt);
+       FDT_RO_PROBE(fdt);
 
        /* FIXME: The algorithm here is pretty horrible: we
         * potentially scan each property of a node in
@@ -692,7 +839,7 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
 {
        int offset, err;
 
-       FDT_CHECK_HEADER(fdt);
+       FDT_RO_PROBE(fdt);
 
        /* FIXME: The algorithm here is pretty horrible: we scan each
         * property of a node in fdt_node_check_compatible(), then if
@@ -711,3 +858,68 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
 
        return offset; /* error from fdt_next_node() */
 }
+
+#if !defined(CHECK_LEVEL) || CHECK_LEVEL > 0
+int fdt_check_full(const void *fdt, size_t bufsize)
+{
+       int err;
+       int num_memrsv;
+       int offset, nextoffset = 0;
+       uint32_t tag;
+       unsigned depth = 0;
+       const void *prop;
+       const char *propname;
+
+       if (bufsize < FDT_V1_SIZE)
+               return -FDT_ERR_TRUNCATED;
+       err = fdt_check_header(fdt);
+       if (err != 0)
+               return err;
+       if (bufsize < fdt_totalsize(fdt))
+               return -FDT_ERR_TRUNCATED;
+
+       num_memrsv = fdt_num_mem_rsv(fdt);
+       if (num_memrsv < 0)
+               return num_memrsv;
+
+       while (1) {
+               offset = nextoffset;
+               tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+               if (nextoffset < 0)
+                       return nextoffset;
+
+               switch (tag) {
+               case FDT_NOP:
+                       break;
+
+               case FDT_END:
+                       if (depth != 0)
+                               return -FDT_ERR_BADSTRUCTURE;
+                       return 0;
+
+               case FDT_BEGIN_NODE:
+                       depth++;
+                       if (depth > INT_MAX)
+                               return -FDT_ERR_BADSTRUCTURE;
+                       break;
+
+               case FDT_END_NODE:
+                       if (depth == 0)
+                               return -FDT_ERR_BADSTRUCTURE;
+                       depth--;
+                       break;
+
+               case FDT_PROP:
+                       prop = fdt_getprop_by_offset(fdt, offset, &propname,
+                                                    &err);
+                       if (!prop)
+                               return err;
+                       break;
+
+               default:
+                       return -FDT_ERR_INTERNAL;
+               }
+       }
+}
+#endif
index 098b3f36e668f8024a639dea5fa5bb7f553fa028..e54639738c8e8f8e3087906f21b2527fb135c654 100644 (file)
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 # Makefile.libfdt
 #
 # This is not a complete Makefile of itself.  Instead, it is designed to
@@ -9,3 +10,9 @@ LIBFDT_VERSION = version.lds
 LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c \
        fdt_addresses.c fdt_overlay.c
 LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
+LIBFDT_LIB = libfdt-$(DTC_VERSION).$(SHAREDLIB_EXT)
+
+libfdt_clean:
+       @$(VECHO) CLEAN "(libfdt)"
+       rm -f $(STD_CLEANFILES:%=$(LIBFDT_dir)/%)
+       rm -f $(LIBFDT_dir)/$(LIBFDT_soname)
index 7855a1787763aa3d891f8f3799519ebb4be477dd..8e4cce3b9be28de9de0f0fb88536933780fe3703 100644 (file)
@@ -1,52 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "libfdt_env.h"
 
 
 #include "libfdt_internal.h"
 
-int fdt_check_header(const void *fdt)
+/*
+ * Minimal sanity check for a read-only tree. fdt_ro_probe_() checks
+ * that the given buffer contains what appears to be a flattened
+ * device tree with sane information in its header.
+ */
+int32_t fdt_ro_probe_(const void *fdt)
 {
+       uint32_t totalsize = fdt_totalsize(fdt);
+
        if (fdt_magic(fdt) == FDT_MAGIC) {
                /* Complete tree */
-               if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
-                       return -FDT_ERR_BADVERSION;
-               if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
-                       return -FDT_ERR_BADVERSION;
+               if (fdt_chk_version()) {
+                       if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
+                               return -FDT_ERR_BADVERSION;
+                       if (fdt_last_comp_version(fdt) >
+                                       FDT_LAST_SUPPORTED_VERSION)
+                               return -FDT_ERR_BADVERSION;
+               }
        } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
                /* Unfinished sequential-write blob */
                if (fdt_size_dt_struct(fdt) == 0)
@@ -71,6 +36,96 @@ int fdt_check_header(const void *fdt)
                return -FDT_ERR_BADMAGIC;
        }
 
+       if (totalsize < INT32_MAX)
+               return totalsize;
+       else
+               return -FDT_ERR_TRUNCATED;
+}
+
+static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off)
+{
+       return (off >= hdrsize) && (off <= totalsize);
+}
+
+static int check_block_(uint32_t hdrsize, uint32_t totalsize,
+                       uint32_t base, uint32_t size)
+{
+       if (!check_off_(hdrsize, totalsize, base))
+               return 0; /* block start out of bounds */
+       if ((base + size) < base)
+               return 0; /* overflow */
+       if (!check_off_(hdrsize, totalsize, base + size))
+               return 0; /* block end out of bounds */
+       return 1;
+}
+
+size_t fdt_header_size_(uint32_t version)
+{
+       if (version <= 1)
+               return FDT_V1_SIZE;
+       else if (version <= 2)
+               return FDT_V2_SIZE;
+       else if (version <= 3)
+               return FDT_V3_SIZE;
+       else if (version <= 16)
+               return FDT_V16_SIZE;
+       else
+               return FDT_V17_SIZE;
+}
+
+size_t fdt_header_size(const void *fdt)
+{
+       return fdt_chk_version() ? fdt_header_size_(fdt_version(fdt)) :
+               FDT_V17_SIZE;
+}
+
+int fdt_check_header(const void *fdt)
+{
+       size_t hdrsize;
+
+       if (fdt_magic(fdt) != FDT_MAGIC)
+               return -FDT_ERR_BADMAGIC;
+       if (fdt_chk_version()) {
+               if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
+                   || (fdt_last_comp_version(fdt) >
+                       FDT_LAST_SUPPORTED_VERSION))
+                       return -FDT_ERR_BADVERSION;
+               if (fdt_version(fdt) < fdt_last_comp_version(fdt))
+                       return -FDT_ERR_BADVERSION;
+       }
+       hdrsize = fdt_header_size(fdt);
+       if (fdt_chk_basic()) {
+
+               if ((fdt_totalsize(fdt) < hdrsize)
+                   || (fdt_totalsize(fdt) > INT_MAX))
+                       return -FDT_ERR_TRUNCATED;
+
+               /* Bounds check memrsv block */
+               if (!check_off_(hdrsize, fdt_totalsize(fdt),
+                               fdt_off_mem_rsvmap(fdt)))
+                       return -FDT_ERR_TRUNCATED;
+       }
+
+       if (fdt_chk_extra()) {
+               /* Bounds check structure block */
+               if (fdt_chk_version() && fdt_version(fdt) < 17) {
+                       if (!check_off_(hdrsize, fdt_totalsize(fdt),
+                                       fdt_off_dt_struct(fdt)))
+                               return -FDT_ERR_TRUNCATED;
+               } else {
+                       if (!check_block_(hdrsize, fdt_totalsize(fdt),
+                                         fdt_off_dt_struct(fdt),
+                                         fdt_size_dt_struct(fdt)))
+                               return -FDT_ERR_TRUNCATED;
+               }
+
+               /* Bounds check strings block */
+               if (!check_block_(hdrsize, fdt_totalsize(fdt),
+                                 fdt_off_dt_strings(fdt),
+                                 fdt_size_dt_strings(fdt)))
+                       return -FDT_ERR_TRUNCATED;
+       }
+
        return 0;
 }
 
@@ -78,12 +133,13 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
 {
        unsigned absoffset = offset + fdt_off_dt_struct(fdt);
 
-       if ((absoffset < offset)
-           || ((absoffset + len) < absoffset)
-           || (absoffset + len) > fdt_totalsize(fdt))
-               return NULL;
+       if (fdt_chk_basic())
+               if ((absoffset < offset)
+                   || ((absoffset + len) < absoffset)
+                   || (absoffset + len) > fdt_totalsize(fdt))
+                       return NULL;
 
-       if (fdt_version(fdt) >= 0x11)
+       if (!fdt_chk_version() || fdt_version(fdt) >= 0x11)
                if (((offset + len) < offset)
                    || ((offset + len) > fdt_size_dt_struct(fdt)))
                        return NULL;
@@ -100,7 +156,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
 
        *nextoffset = -FDT_ERR_TRUNCATED;
        tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
-       if (!tagp)
+       if (fdt_chk_basic() && !tagp)
                return FDT_END; /* premature end */
        tag = fdt32_to_cpu(*tagp);
        offset += FDT_TAGSIZE;
@@ -112,18 +168,19 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
                do {
                        p = fdt_offset_ptr(fdt, offset++, 1);
                } while (p && (*p != '\0'));
-               if (!p)
+               if (fdt_chk_basic() && !p)
                        return FDT_END; /* premature end */
                break;
 
        case FDT_PROP:
                lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
-               if (!lenp)
+               if (fdt_chk_basic() && !lenp)
                        return FDT_END; /* premature end */
                /* skip-name offset, length and value */
                offset += sizeof(struct fdt_property) - FDT_TAGSIZE
                        + fdt32_to_cpu(*lenp);
-               if (fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 &&
+               if (fdt_chk_version() &&
+                   fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 &&
                    ((offset - fdt32_to_cpu(*lenp)) % 8) != 0)
                        offset += 4;
                break;
@@ -137,7 +194,8 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
                return FDT_END;
        }
 
-       if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset))
+       if (fdt_chk_basic() &&
+           !fdt_offset_ptr(fdt, startoffset, offset - startoffset))
                return FDT_END; /* premature end */
 
        *nextoffset = FDT_TAGALIGN(offset);
@@ -244,7 +302,7 @@ const char *fdt_find_string_(const char *strtab, int tabsize, const char *s)
 
 int fdt_move(const void *fdt, void *buf, int bufsize)
 {
-       FDT_CHECK_HEADER(fdt);
+       FDT_RO_PROBE(fdt);
 
        if (fdt_totalsize(fdt) > bufsize)
                return -FDT_ERR_NOSPACE;
index 74961f9026d160650f68a5880c1a8a4d8b43c147..f2e68807f277c5009641c54f5198bebb7cb1c28f 100644 (file)
@@ -1,55 +1,10 @@
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
 #ifndef FDT_H
 #define FDT_H
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
  * Copyright 2012 Kim Phillips, Freescale Semiconductor.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #ifndef __ASSEMBLY__
index 788c14311369f99589f0203483941e000afb0eb4..9a82cd0ba2f9714c748d40ba75cd61cb6fe25005 100644 (file)
@@ -1,53 +1,8 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au>
  * Copyright (C) 2018 embedded brains GmbH
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "libfdt_env.h"
 
@@ -97,3 +52,50 @@ int fdt_size_cells(const void *fdt, int nodeoffset)
                return 1;
        return val;
 }
+
+/* This function assumes that [address|size]_cells is 1 or 2 */
+int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
+                            const char *name, uint64_t addr, uint64_t size)
+{
+       int addr_cells, size_cells, ret;
+       uint8_t data[sizeof(fdt64_t) * 2], *prop;
+
+       ret = fdt_address_cells(fdt, parent);
+       if (ret < 0)
+               return ret;
+       addr_cells = ret;
+
+       ret = fdt_size_cells(fdt, parent);
+       if (ret < 0)
+               return ret;
+       size_cells = ret;
+
+       /* check validity of address */
+       prop = data;
+       if (addr_cells == 1) {
+               if ((addr > UINT32_MAX) || ((UINT32_MAX + 1 - addr) < size))
+                       return -FDT_ERR_BADVALUE;
+
+               fdt32_st(prop, (uint32_t)addr);
+       } else if (addr_cells == 2) {
+               fdt64_st(prop, addr);
+       } else {
+               return -FDT_ERR_BADNCELLS;
+       }
+
+       /* check validity of size */
+       prop += addr_cells * sizeof(fdt32_t);
+       if (size_cells == 1) {
+               if (size > UINT32_MAX)
+                       return -FDT_ERR_BADVALUE;
+
+               fdt32_st(prop, (uint32_t)size);
+       } else if (size_cells == 2) {
+               fdt64_st(prop, size);
+       } else {
+               return -FDT_ERR_BADNCELLS;
+       }
+
+       return fdt_appendprop(fdt, nodeoffset, name, data,
+                             (addr_cells + size_cells) * sizeof(fdt32_t));
+}
index f2ae9b77c285733e50b4b496407471149650d290..49d54d44b8e78be6d110c41db97312ef66ff89aa 100644 (file)
@@ -1,52 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2012 David Gibson, IBM Corporation.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "libfdt_env.h"
 
index bf75388ec9a20d9e4878ddd0f9636889dcaa18c3..be7187336615432d5659ab1cc90a2ac6cfaa7d7d 100644 (file)
@@ -1,53 +1,8 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2016 Free Electrons
  * Copyright (C) 2016 NextThing Co.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "libfdt_env.h"
 
@@ -93,11 +48,11 @@ static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
  * @pathp: pointer which receives the path of the target (or NULL)
  *
  * overlay_get_target() retrieves the target offset in the base
- * device tree of a fragment, no matter how the actual targetting is
+ * device tree of a fragment, no matter how the actual targeting is
  * done (through a phandle or a path)
  *
  * returns:
- *      the targetted node offset in the base device tree
+ *      the targeted node offset in the base device tree
  *      Negative error code on error
  */
 static int overlay_get_target(const void *fdt, const void *fdto,
@@ -697,7 +652,7 @@ static int get_path_len(const void *fdt, int nodeoffset)
        int len = 0, namelen;
        const char *name;
 
-       FDT_CHECK_HEADER(fdt);
+       FDT_RO_PROBE(fdt);
 
        for (;;) {
                name = fdt_get_name(fdt, nodeoffset, &namelen);
@@ -778,26 +733,36 @@ static int overlay_symbol_update(void *fdt, void *fdto)
                /* keep end marker to avoid strlen() */
                e = path + path_len;
 
-               /* format: /<fragment-name>/__overlay__/<relative-subnode-path> */
-
                if (*path != '/')
                        return -FDT_ERR_BADVALUE;
 
                /* get fragment name first */
                s = strchr(path + 1, '/');
-               if (!s)
-                       return -FDT_ERR_BADOVERLAY;
+               if (!s) {
+                       /* Symbol refers to something that won't end
+                        * up in the target tree */
+                       continue;
+               }
 
                frag_name = path + 1;
                frag_name_len = s - path - 1;
 
                /* verify format; safe since "s" lies in \0 terminated prop */
                len = sizeof("/__overlay__/") - 1;
-               if ((e - s) < len || memcmp(s, "/__overlay__/", len))
-                       return -FDT_ERR_BADOVERLAY;
-
-               rel_path = s + len;
-               rel_path_len = e - rel_path;
+               if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) {
+                       /* /<fragment-name>/__overlay__/<relative-subnode-path> */
+                       rel_path = s + len;
+                       rel_path_len = e - rel_path;
+               } else if ((e - s) == len
+                          && (memcmp(s, "/__overlay__", len - 1) == 0)) {
+                       /* /<fragment-name>/__overlay__ */
+                       rel_path = "";
+                       rel_path_len = 0;
+               } else {
+                       /* Symbol refers to something that won't end
+                        * up in the target tree */
+                       continue;
+               }
 
                /* find the fragment index in which the symbol lies */
                ret = fdt_subnode_offset_namelen(fdto, 0, frag_name,
@@ -863,11 +828,15 @@ static int overlay_symbol_update(void *fdt, void *fdto)
 
 int fdt_overlay_apply(void *fdt, void *fdto)
 {
-       uint32_t delta = fdt_get_max_phandle(fdt);
+       uint32_t delta;
        int ret;
 
-       FDT_CHECK_HEADER(fdt);
-       FDT_CHECK_HEADER(fdto);
+       FDT_RO_PROBE(fdt);
+       FDT_RO_PROBE(fdto);
+
+       ret = fdt_find_max_phandle(fdt, &delta);
+       if (ret)
+               goto err;
 
        ret = overlay_adjust_local_phandles(fdto, delta);
        if (ret)
index dc499884e4d1a7f1858225024cc97799af4f57ce..e398815485d6d9a467c86f116575e7a348c17863 100644 (file)
@@ -1,52 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "libfdt_env.h"
 
@@ -61,7 +16,7 @@ static int fdt_nodename_eq_(const void *fdt, int offset,
        int olen;
        const char *p = fdt_get_name(fdt, offset, &olen);
 
-       if (!p || olen < len)
+       if (!p || (fdt_chk_extra() && olen < len))
                /* short match */
                return 0;
 
@@ -76,46 +31,85 @@ static int fdt_nodename_eq_(const void *fdt, int offset,
                return 0;
 }
 
-const char *fdt_string(const void *fdt, int stroffset)
-{
-       return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
-}
-
-static int fdt_string_eq_(const void *fdt, int stroffset,
-                         const char *s, int len)
+const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
 {
-       const char *p = fdt_string(fdt, stroffset);
+       int32_t totalsize;
+       uint32_t absoffset;
+       size_t len;
+       int err;
+       const char *s, *n;
 
-       return (strlen(p) == len) && (memcmp(p, s, len) == 0);
-}
+       if (!fdt_chk_extra()) {
+               s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
 
-uint32_t fdt_get_max_phandle(const void *fdt)
-{
-       uint32_t max_phandle = 0;
-       int offset;
+               if (lenp)
+                       *lenp = strlen(s);
+               return s;
+       }
+       totalsize = fdt_ro_probe_(fdt);
+       err = totalsize;
+       if (totalsize < 0)
+               goto fail;
+
+       err = -FDT_ERR_BADOFFSET;
+       absoffset = stroffset + fdt_off_dt_strings(fdt);
+       if (absoffset >= totalsize)
+               goto fail;
+       len = totalsize - absoffset;
+
+       if (fdt_magic(fdt) == FDT_MAGIC) {
+               if (stroffset < 0)
+                       goto fail;
+               if (!fdt_chk_version() || fdt_version(fdt) >= 17) {
+                       if (stroffset >= fdt_size_dt_strings(fdt))
+                               goto fail;
+                       if ((fdt_size_dt_strings(fdt) - stroffset) < len)
+                               len = fdt_size_dt_strings(fdt) - stroffset;
+               }
+       } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
+               if ((stroffset >= 0)
+                   || (stroffset < -fdt_size_dt_strings(fdt)))
+                       goto fail;
+               if ((-stroffset) < len)
+                       len = -stroffset;
+       } else {
+               err = -FDT_ERR_INTERNAL;
+               goto fail;
+       }
 
-       for (offset = fdt_next_node(fdt, -1, NULL);;
-            offset = fdt_next_node(fdt, offset, NULL)) {
-               uint32_t phandle;
+       s = (const char *)fdt + absoffset;
+       n = memchr(s, '\0', len);
+       if (!n) {
+               /* missing terminating NULL */
+               err = -FDT_ERR_TRUNCATED;
+               goto fail;
+       }
 
-               if (offset == -FDT_ERR_NOTFOUND)
-                       return max_phandle;
+       if (lenp)
+               *lenp = n - s;
+       return s;
 
-               if (offset < 0)
-                       return (uint32_t)-1;
+fail:
+       if (lenp)
+               *lenp = err;
+       return NULL;
+}
 
-               phandle = fdt_get_phandle(fdt, offset);
-               if (phandle == (uint32_t)-1)
-                       continue;
+const char *fdt_string(const void *fdt, int stroffset)
+{
+       return fdt_get_string(fdt, stroffset, NULL);
+}
 
-               if (phandle > max_phandle)
-                       max_phandle = phandle;
-       }
+static int fdt_string_eq_(const void *fdt, int stroffset,
+                         const char *s, int len)
+{
+       int slen;
+       const char *p = fdt_get_string(fdt, stroffset, &slen);
 
-       return 0;
+       return p && (slen == len) && (memcmp(p, s, len) == 0);
 }
 
-int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
+int fdt_find_max_phandle(const void *fdt, uint32_t *phandle)
 {
        uint32_t max = 0;
        int offset = -1;
@@ -137,6 +131,21 @@ int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
                        max = value;
        }
 
+       if (phandle)
+               *phandle = max;
+
+       return 0;
+}
+
+int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
+{
+       uint32_t max;
+       int err;
+
+       err = fdt_find_max_phandle(fdt, &max);
+       if (err < 0)
+               return err;
+
        if (max == FDT_MAX_PHANDLE)
                return -FDT_ERR_NOPHANDLES;
 
@@ -146,21 +155,45 @@ int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
        return 0;
 }
 
+static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
+{
+       int offset = n * sizeof(struct fdt_reserve_entry);
+       int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
+
+       if (fdt_chk_extra()) {
+               if (absoffset < fdt_off_mem_rsvmap(fdt))
+                       return NULL;
+               if (absoffset > fdt_totalsize(fdt) -
+                   sizeof(struct fdt_reserve_entry))
+                       return NULL;
+       }
+       return fdt_mem_rsv_(fdt, n);
+}
+
 int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
 {
-       FDT_CHECK_HEADER(fdt);
-       *address = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->address);
-       *size = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->size);
+       const struct fdt_reserve_entry *re;
+
+       FDT_RO_PROBE(fdt);
+       re = fdt_mem_rsv(fdt, n);
+       if (fdt_chk_extra() && !re)
+               return -FDT_ERR_BADOFFSET;
+
+       *address = fdt64_ld(&re->address);
+       *size = fdt64_ld(&re->size);
        return 0;
 }
 
 int fdt_num_mem_rsv(const void *fdt)
 {
-       int i = 0;
+       int i;
+       const struct fdt_reserve_entry *re;
 
-       while (fdt64_to_cpu(fdt_mem_rsv_(fdt, i)->size) != 0)
-               i++;
-       return i;
+       for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
+               if (fdt64_ld(&re->size) == 0)
+                       return i;
+       }
+       return -FDT_ERR_TRUNCATED;
 }
 
 static int nextprop_(const void *fdt, int offset)
@@ -192,7 +225,7 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset,
 {
        int depth;
 
-       FDT_CHECK_HEADER(fdt);
+       FDT_RO_PROBE(fdt);
 
        for (depth = 0;
             (offset >= 0) && (depth >= 0);
@@ -218,7 +251,7 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
        const char *p = path;
        int offset = 0;
 
-       FDT_CHECK_HEADER(fdt);
+       FDT_RO_PROBE(fdt);
 
        /* see if we have an alias */
        if (*path != '/') {
@@ -268,13 +301,14 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
        const char *nameptr;
        int err;
 
-       if (((err = fdt_check_header(fdt)) != 0)
-           || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
-                       goto fail;
+       if (fdt_chk_extra() &&
+           (((err = fdt_ro_probe_(fdt)) < 0)
+            || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)))
+               goto fail;
 
        nameptr = nh->name;
 
-       if (fdt_version(fdt) < 0x10) {
+       if (fdt_chk_version() && fdt_version(fdt) < 0x10) {
                /*
                 * For old FDT versions, match the naming conventions of V16:
                 * give only the leaf name (after all /). The actual tree
@@ -325,7 +359,7 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
        int err;
        const struct fdt_property *prop;
 
-       if ((err = fdt_check_prop_offset_(fdt, offset)) < 0) {
+       if (fdt_chk_basic() && (err = fdt_check_prop_offset_(fdt, offset)) < 0) {
                if (lenp)
                        *lenp = err;
                return NULL;
@@ -334,7 +368,7 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
        prop = fdt_offset_ptr_(fdt, offset);
 
        if (lenp)
-               *lenp = fdt32_to_cpu(prop->len);
+               *lenp = fdt32_ld(&prop->len);
 
        return prop;
 }
@@ -346,7 +380,7 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
        /* Prior to version 16, properties may need realignment
         * and this API does not work. fdt_getprop_*() will, however. */
 
-       if (fdt_version(fdt) < 0x10) {
+       if (fdt_chk_version() && fdt_version(fdt) < 0x10) {
                if (lenp)
                        *lenp = -FDT_ERR_BADVERSION;
                return NULL;
@@ -367,11 +401,12 @@ static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
             (offset = fdt_next_property_offset(fdt, offset))) {
                const struct fdt_property *prop;
 
-               if (!(prop = fdt_get_property_by_offset_(fdt, offset, lenp))) {
+               prop = fdt_get_property_by_offset_(fdt, offset, lenp);
+               if (fdt_chk_extra() && !prop) {
                        offset = -FDT_ERR_INTERNAL;
                        break;
                }
-               if (fdt_string_eq_(fdt, fdt32_to_cpu(prop->nameoff),
+               if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff),
                                   name, namelen)) {
                        if (poffset)
                                *poffset = offset;
@@ -392,7 +427,7 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt,
 {
        /* Prior to version 16, properties may need realignment
         * and this API does not work. fdt_getprop_*() will, however. */
-       if (fdt_version(fdt) < 0x10) {
+       if (fdt_chk_version() && fdt_version(fdt) < 0x10) {
                if (lenp)
                        *lenp = -FDT_ERR_BADVERSION;
                return NULL;
@@ -423,8 +458,8 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
                return NULL;
 
        /* Handle realignment */
-       if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 &&
-           fdt32_to_cpu(prop->len) >= 8)
+       if (fdt_chk_version() && fdt_version(fdt) < 0x10 &&
+           (poffset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
                return prop->data + 4;
        return prop->data;
 }
@@ -437,12 +472,27 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
        prop = fdt_get_property_by_offset_(fdt, offset, lenp);
        if (!prop)
                return NULL;
-       if (namep)
-               *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+       if (namep) {
+               const char *name;
+               int namelen;
+
+               if (fdt_chk_extra()) {
+                       name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff),
+                                             &namelen);
+                       if (!name) {
+                               if (lenp)
+                                       *lenp = namelen;
+                               return NULL;
+                       }
+                       *namep = name;
+               } else {
+                       *namep = fdt_string(fdt, fdt32_ld(&prop->nameoff));
+               }
+       }
 
        /* Handle realignment */
-       if (fdt_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 &&
-           fdt32_to_cpu(prop->len) >= 8)
+       if (fdt_chk_version() && fdt_version(fdt) < 0x10 &&
+           (offset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
                return prop->data + 4;
        return prop->data;
 }
@@ -467,7 +517,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
                        return 0;
        }
 
-       return fdt32_to_cpu(*php);
+       return fdt32_ld(php);
 }
 
 const char *fdt_get_alias_namelen(const void *fdt,
@@ -493,7 +543,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
        int offset, depth, namelen;
        const char *name;
 
-       FDT_CHECK_HEADER(fdt);
+       FDT_RO_PROBE(fdt);
 
        if (buflen < 2)
                return -FDT_ERR_NOSPACE;
@@ -545,7 +595,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
        int offset, depth;
        int supernodeoffset = -FDT_ERR_INTERNAL;
 
-       FDT_CHECK_HEADER(fdt);
+       FDT_RO_PROBE(fdt);
 
        if (supernodedepth < 0)
                return -FDT_ERR_NOTFOUND;
@@ -567,10 +617,12 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
                }
        }
 
-       if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
-               return -FDT_ERR_BADOFFSET;
-       else if (offset == -FDT_ERR_BADOFFSET)
-               return -FDT_ERR_BADSTRUCTURE;
+       if (fdt_chk_extra()) {
+               if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+                       return -FDT_ERR_BADOFFSET;
+               else if (offset == -FDT_ERR_BADOFFSET)
+                       return -FDT_ERR_BADSTRUCTURE;
+       }
 
        return offset; /* error from fdt_next_node() */
 }
@@ -582,7 +634,7 @@ int fdt_node_depth(const void *fdt, int nodeoffset)
 
        err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
        if (err)
-               return (err < 0) ? err : -FDT_ERR_INTERNAL;
+               return (!fdt_chk_extra() || err < 0) ? err : -FDT_ERR_INTERNAL;
        return nodedepth;
 }
 
@@ -604,7 +656,7 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
        const void *val;
        int len;
 
-       FDT_CHECK_HEADER(fdt);
+       FDT_RO_PROBE(fdt);
 
        /* FIXME: The algorithm here is pretty horrible: we scan each
         * property of a node in fdt_getprop(), then if that didn't
@@ -630,7 +682,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
        if ((phandle == 0) || (phandle == -1))
                return -FDT_ERR_BADPHANDLE;
 
-       FDT_CHECK_HEADER(fdt);
+       FDT_RO_PROBE(fdt);
 
        /* FIXME: The algorithm here is pretty horrible: we
         * potentially scan each property of a node in
@@ -783,7 +835,7 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
 {
        int offset, err;
 
-       FDT_CHECK_HEADER(fdt);
+       FDT_RO_PROBE(fdt);
 
        /* FIXME: The algorithm here is pretty horrible: we scan each
         * property of a node in fdt_node_check_compatible(), then if
@@ -802,3 +854,68 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
 
        return offset; /* error from fdt_next_node() */
 }
+
+#if !defined(FDT_ASSUME_MASK) || FDT_ASSUME_MASK != 0xff
+int fdt_check_full(const void *fdt, size_t bufsize)
+{
+       int err;
+       int num_memrsv;
+       int offset, nextoffset = 0;
+       uint32_t tag;
+       unsigned depth = 0;
+       const void *prop;
+       const char *propname;
+
+       if (bufsize < FDT_V1_SIZE)
+               return -FDT_ERR_TRUNCATED;
+       err = fdt_check_header(fdt);
+       if (err != 0)
+               return err;
+       if (bufsize < fdt_totalsize(fdt))
+               return -FDT_ERR_TRUNCATED;
+
+       num_memrsv = fdt_num_mem_rsv(fdt);
+       if (num_memrsv < 0)
+               return num_memrsv;
+
+       while (1) {
+               offset = nextoffset;
+               tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+               if (nextoffset < 0)
+                       return nextoffset;
+
+               switch (tag) {
+               case FDT_NOP:
+                       break;
+
+               case FDT_END:
+                       if (depth != 0)
+                               return -FDT_ERR_BADSTRUCTURE;
+                       return 0;
+
+               case FDT_BEGIN_NODE:
+                       depth++;
+                       if (depth > INT_MAX)
+                               return -FDT_ERR_BADSTRUCTURE;
+                       break;
+
+               case FDT_END_NODE:
+                       if (depth == 0)
+                               return -FDT_ERR_BADSTRUCTURE;
+                       depth--;
+                       break;
+
+               case FDT_PROP:
+                       prop = fdt_getprop_by_offset(fdt, offset, &propname,
+                                                    &err);
+                       if (!prop)
+                               return err;
+                       break;
+
+               default:
+                       return -FDT_ERR_INTERNAL;
+               }
+       }
+}
+#endif
index 9b829051e4447015aad9972270e299cab4dc3053..08e2981a44f85bca6315dd11726a00d32da76fc2 100644 (file)
@@ -1,52 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "libfdt_env.h"
 
@@ -58,6 +13,8 @@
 static int fdt_blocks_misordered_(const void *fdt,
                                  int mem_rsv_size, int struct_size)
 {
+       if (!fdt_chk_basic())
+               return false;
        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))
@@ -67,25 +24,27 @@ static int fdt_blocks_misordered_(const void *fdt,
                    (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
 }
 
-static int fdt_rw_check_header_(void *fdt)
+static int fdt_rw_probe_(void *fdt)
 {
-       FDT_CHECK_HEADER(fdt);
+       if (!fdt_chk_basic())
+               return 0;
+       FDT_RO_PROBE(fdt);
 
-       if (fdt_version(fdt) < 17)
+       if (fdt_chk_version() && fdt_version(fdt) < 17)
                return -FDT_ERR_BADVERSION;
        if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry),
                                   fdt_size_dt_struct(fdt)))
                return -FDT_ERR_BADLAYOUT;
-       if (fdt_version(fdt) > 17)
+       if (fdt_chk_version() && fdt_version(fdt) > 17)
                fdt_set_version(fdt, 17);
 
        return 0;
 }
 
-#define FDT_RW_CHECK_HEADER(fdt) \
+#define FDT_RW_PROBE(fdt) \
        { \
                int err_; \
-               if ((err_ = fdt_rw_check_header_(fdt)) != 0) \
+               if (fdt_chk_extra() && (err_ = fdt_rw_probe_(fdt)) != 0) \
                        return err_; \
        }
 
@@ -136,6 +95,14 @@ static int fdt_splice_struct_(void *fdt, void *p,
        return 0;
 }
 
+/* Must only be used to roll back in case of error */
+static void fdt_del_last_string_(void *fdt, const char *s)
+{
+       int newlen = strlen(s) + 1;
+
+       fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) - newlen);
+}
+
 static int fdt_splice_string_(void *fdt, int newlen)
 {
        void *p = (char *)fdt
@@ -149,7 +116,16 @@ static int fdt_splice_string_(void *fdt, int newlen)
        return 0;
 }
 
-static int fdt_find_add_string_(void *fdt, const char *s)
+/**
+ * fdt_find_add_string_() - Find or allocate a string
+ *
+ * @fdt: pointer to the device tree to check/adjust
+ * @s: string to find/add
+ * @allocated: Set to 0 if the string was found, 1 if not found and so
+ *     allocated. Ignored if !fdt_chk_basic()
+ * @return offset of string in the string table (whether found or added)
+ */
+static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
 {
        char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
        const char *p;
@@ -157,6 +133,9 @@ static int fdt_find_add_string_(void *fdt, const char *s)
        int len = strlen(s) + 1;
        int err;
 
+       if (fdt_chk_basic())
+               *allocated = 0;
+
        p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s);
        if (p)
                /* found it */
@@ -167,6 +146,9 @@ static int fdt_find_add_string_(void *fdt, const char *s)
        if (err)
                return err;
 
+       if (fdt_chk_basic())
+               *allocated = 1;
+
        memcpy(new, s, len);
        return (new - strtab);
 }
@@ -176,7 +158,7 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
        struct fdt_reserve_entry *re;
        int err;
 
-       FDT_RW_CHECK_HEADER(fdt);
+       FDT_RW_PROBE(fdt);
 
        re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt));
        err = fdt_splice_mem_rsv_(fdt, re, 0, 1);
@@ -192,7 +174,7 @@ int fdt_del_mem_rsv(void *fdt, int n)
 {
        struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n);
 
-       FDT_RW_CHECK_HEADER(fdt);
+       FDT_RW_PROBE(fdt);
 
        if (n >= fdt_num_mem_rsv(fdt))
                return -FDT_ERR_NOTFOUND;
@@ -225,11 +207,12 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
        int nextoffset;
        int namestroff;
        int err;
+       int allocated;
 
        if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
                return nextoffset;
 
-       namestroff = fdt_find_add_string_(fdt, name);
+       namestroff = fdt_find_add_string_(fdt, name, &allocated);
        if (namestroff < 0)
                return namestroff;
 
@@ -237,8 +220,12 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
        proplen = sizeof(**prop) + FDT_TAGALIGN(len);
 
        err = fdt_splice_struct_(fdt, *prop, 0, proplen);
-       if (err)
+       if (err) {
+               /* Delete the string if we failed to add it */
+               if (fdt_chk_basic() && allocated)
+                       fdt_del_last_string_(fdt, name);
                return err;
+       }
 
        (*prop)->tag = cpu_to_fdt32(FDT_PROP);
        (*prop)->nameoff = cpu_to_fdt32(namestroff);
@@ -252,7 +239,7 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name)
        int oldlen, newlen;
        int err;
 
-       FDT_RW_CHECK_HEADER(fdt);
+       FDT_RW_PROBE(fdt);
 
        namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
        if (!namep)
@@ -275,7 +262,7 @@ int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
        struct fdt_property *prop;
        int err;
 
-       FDT_RW_CHECK_HEADER(fdt);
+       FDT_RW_PROBE(fdt);
 
        err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop);
        if (err == -FDT_ERR_NOTFOUND)
@@ -308,7 +295,7 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
        struct fdt_property *prop;
        int err, oldlen, newlen;
 
-       FDT_RW_CHECK_HEADER(fdt);
+       FDT_RW_PROBE(fdt);
 
        prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
        if (prop) {
@@ -334,7 +321,7 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name)
        struct fdt_property *prop;
        int len, proplen;
 
-       FDT_RW_CHECK_HEADER(fdt);
+       FDT_RW_PROBE(fdt);
 
        prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
        if (!prop)
@@ -354,7 +341,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
        uint32_t tag;
        fdt32_t *endtag;
 
-       FDT_RW_CHECK_HEADER(fdt);
+       FDT_RW_PROBE(fdt);
 
        offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
        if (offset >= 0)
@@ -394,7 +381,7 @@ int fdt_del_node(void *fdt, int nodeoffset)
 {
        int endoffset;
 
-       FDT_RW_CHECK_HEADER(fdt);
+       FDT_RW_PROBE(fdt);
 
        endoffset = fdt_node_end_offset_(fdt, nodeoffset);
        if (endoffset < 0)
@@ -435,12 +422,12 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
        const char *fdtend = fdtstart + fdt_totalsize(fdt);
        char *tmp;
 
-       FDT_CHECK_HEADER(fdt);
+       FDT_RO_PROBE(fdt);
 
        mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
                * sizeof(struct fdt_reserve_entry);
 
-       if (fdt_version(fdt) >= 17) {
+       if (!fdt_chk_version() || fdt_version(fdt) >= 17) {
                struct_size = fdt_size_dt_struct(fdt);
        } else {
                struct_size = 0;
@@ -494,7 +481,7 @@ int fdt_pack(void *fdt)
 {
        int mem_rsv_size;
 
-       FDT_RW_CHECK_HEADER(fdt);
+       FDT_RW_PROBE(fdt);
 
        mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
                * sizeof(struct fdt_reserve_entry);
index 9677a1887e572029a74ebb3dfa49b3f95b1ccb07..768db66eada5ea06c0595df6db4610522f01ec6c 100644 (file)
@@ -1,51 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "libfdt_env.h"
@@ -82,6 +38,7 @@ static struct fdt_errtabent fdt_errtable[] = {
        FDT_ERRTABENT(FDT_ERR_BADVALUE),
        FDT_ERRTABENT(FDT_ERR_BADOVERLAY),
        FDT_ERRTABENT(FDT_ERR_NOPHANDLES),
+       FDT_ERRTABENT(FDT_ERR_BADFLAGS),
 };
 #define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
 
index d8ef748a7212f489df98a94dac8faac399240a8b..a8c924675a6ad11f282c706bd346cd09ff7fd9d6 100644 (file)
@@ -1,52 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "libfdt_env.h"
 
 
 #include "libfdt_internal.h"
 
-static int fdt_sw_check_header_(void *fdt)
+static int fdt_sw_probe_(void *fdt)
+{
+       if (fdt_chk_basic()) {
+               if (fdt_magic(fdt) == FDT_MAGIC)
+                       return -FDT_ERR_BADSTATE;
+               else if (fdt_magic(fdt) != FDT_SW_MAGIC)
+                       return -FDT_ERR_BADMAGIC;
+       }
+
+       return 0;
+}
+
+#define FDT_SW_PROBE(fdt) \
+       { \
+               int err; \
+               if (fdt_chk_basic() && (err = fdt_sw_probe_(fdt)) != 0) \
+                       return err; \
+       }
+
+/* 'memrsv' state:     Initial state after fdt_create()
+ *
+ * Allowed functions:
+ *     fdt_add_reservmap_entry()
+ *     fdt_finish_reservemap()         [moves to 'struct' state]
+ */
+static int fdt_sw_probe_memrsv_(void *fdt)
+{
+       int err = fdt_sw_probe_(fdt);
+       if (err)
+               return err;
+
+       if (fdt_chk_extra() && fdt_off_dt_strings(fdt) != 0)
+               return -FDT_ERR_BADSTATE;
+       return 0;
+}
+
+#define FDT_SW_PROBE_MEMRSV(fdt) \
+       { \
+               int err; \
+               if (fdt_chk_extra() && (err = fdt_sw_probe_memrsv_(fdt)) != 0) \
+                       return err; \
+       }
+
+/* 'struct' state:     Enter this state after fdt_finish_reservemap()
+ *
+ * Allowed functions:
+ *     fdt_begin_node()
+ *     fdt_end_node()
+ *     fdt_property*()
+ *     fdt_finish()                    [moves to 'complete' state]
+ */
+static int fdt_sw_probe_struct_(void *fdt)
 {
-       if (fdt_magic(fdt) != FDT_SW_MAGIC)
-               return -FDT_ERR_BADMAGIC;
-       /* FIXME: should check more details about the header state */
+       int err;
+
+       if (!fdt_chk_extra())
+               return 0;
+       err = fdt_sw_probe_(fdt);
+       if (err)
+               return err;
+
+       if (fdt_off_dt_strings(fdt) != fdt_totalsize(fdt))
+               return -FDT_ERR_BADSTATE;
        return 0;
 }
 
-#define FDT_SW_CHECK_HEADER(fdt) \
+#define FDT_SW_PROBE_STRUCT(fdt) \
        { \
                int err; \
-               if ((err = fdt_sw_check_header_(fdt)) != 0) \
+               if (fdt_chk_extra() && (err = fdt_sw_probe_struct_(fdt)) != 0) \
                        return err; \
        }
 
+static inline uint32_t sw_flags(void *fdt)
+{
+       /* assert: (fdt_magic(fdt) == FDT_SW_MAGIC) */
+       return fdt_last_comp_version(fdt);
+}
+
+/* 'complete' state:   Enter this state after fdt_finish()
+ *
+ * Allowed functions: none
+ */
+
 static void *fdt_grab_space_(void *fdt, size_t len)
 {
        int offset = fdt_size_dt_struct(fdt);
@@ -85,38 +109,58 @@ static void *fdt_grab_space_(void *fdt, size_t len)
        return fdt_offset_ptr_w_(fdt, offset);
 }
 
-int fdt_create(void *buf, int bufsize)
+int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags)
 {
+       const size_t hdrsize = FDT_ALIGN(sizeof(struct fdt_header),
+                                        sizeof(struct fdt_reserve_entry));
        void *fdt = buf;
 
-       if (bufsize < sizeof(struct fdt_header))
+       if (bufsize < hdrsize)
                return -FDT_ERR_NOSPACE;
 
+       if (flags & ~FDT_CREATE_FLAGS_ALL)
+               return -FDT_ERR_BADFLAGS;
+
        memset(buf, 0, bufsize);
 
+       /*
+        * magic and last_comp_version keep intermediate state during the fdt
+        * creation process, which is replaced with the proper FDT format by
+        * fdt_finish().
+        *
+        * flags should be accessed with sw_flags().
+        */
        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_last_comp_version(fdt, flags);
+
        fdt_set_totalsize(fdt,  bufsize);
 
-       fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header),
-                                             sizeof(struct fdt_reserve_entry)));
+       fdt_set_off_mem_rsvmap(fdt, hdrsize);
        fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
-       fdt_set_off_dt_strings(fdt, bufsize);
+       fdt_set_off_dt_strings(fdt, 0);
 
        return 0;
 }
 
+int fdt_create(void *buf, int bufsize)
+{
+       return fdt_create_with_flags(buf, bufsize, 0);
+}
+
 int fdt_resize(void *fdt, void *buf, int bufsize)
 {
        size_t headsize, tailsize;
        char *oldtail, *newtail;
 
-       FDT_SW_CHECK_HEADER(fdt);
+       FDT_SW_PROBE(fdt);
 
        headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
        tailsize = fdt_size_dt_strings(fdt);
 
+       if (fdt_chk_extra() && (headsize + tailsize) > fdt_totalsize(fdt))
+               return -FDT_ERR_INTERNAL;
+
        if ((headsize + tailsize) > bufsize)
                return -FDT_ERR_NOSPACE;
 
@@ -133,8 +177,9 @@ int fdt_resize(void *fdt, void *buf, int bufsize)
                memmove(buf, fdt, headsize);
        }
 
-       fdt_set_off_dt_strings(buf, bufsize);
        fdt_set_totalsize(buf, bufsize);
+       if (fdt_off_dt_strings(buf))
+               fdt_set_off_dt_strings(buf, bufsize);
 
        return 0;
 }
@@ -144,10 +189,7 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
        struct fdt_reserve_entry *re;
        int offset;
 
-       FDT_SW_CHECK_HEADER(fdt);
-
-       if (fdt_size_dt_struct(fdt))
-               return -FDT_ERR_BADSTATE;
+       FDT_SW_PROBE_MEMRSV(fdt);
 
        offset = fdt_off_dt_struct(fdt);
        if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
@@ -164,16 +206,23 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
 
 int fdt_finish_reservemap(void *fdt)
 {
-       return fdt_add_reservemap_entry(fdt, 0, 0);
+       int err = fdt_add_reservemap_entry(fdt, 0, 0);
+
+       if (err)
+               return err;
+
+       fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt));
+       return 0;
 }
 
 int fdt_begin_node(void *fdt, const char *name)
 {
        struct fdt_node_header *nh;
-       int namelen = strlen(name) + 1;
+       int namelen;
 
-       FDT_SW_CHECK_HEADER(fdt);
+       FDT_SW_PROBE_STRUCT(fdt);
 
+       namelen = strlen(name) + 1;
        nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
        if (! nh)
                return -FDT_ERR_NOSPACE;
@@ -187,7 +236,7 @@ int fdt_end_node(void *fdt)
 {
        fdt32_t *en;
 
-       FDT_SW_CHECK_HEADER(fdt);
+       FDT_SW_PROBE_STRUCT(fdt);
 
        en = fdt_grab_space_(fdt, FDT_TAGSIZE);
        if (! en)
@@ -197,19 +246,13 @@ int fdt_end_node(void *fdt)
        return 0;
 }
 
-static int fdt_find_add_string_(void *fdt, const char *s)
+static int fdt_add_string_(void *fdt, const char *s)
 {
        char *strtab = (char *)fdt + fdt_totalsize(fdt);
-       const char *p;
        int strtabsize = fdt_size_dt_strings(fdt);
        int len = strlen(s) + 1;
        int struct_top, offset;
 
-       p = fdt_find_string_(strtab - strtabsize, strtabsize, s);
-       if (p)
-               return p - strtab;
-
-       /* Add it */
        offset = -strtabsize - len;
        struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
        if (fdt_totalsize(fdt) + offset < struct_top)
@@ -220,20 +263,56 @@ static int fdt_find_add_string_(void *fdt, const char *s)
        return offset;
 }
 
+/* Must only be used to roll back in case of error */
+static void fdt_del_last_string_(void *fdt, const char *s)
+{
+       int strtabsize = fdt_size_dt_strings(fdt);
+       int len = strlen(s) + 1;
+
+       fdt_set_size_dt_strings(fdt, strtabsize - len);
+}
+
+static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
+{
+       char *strtab = (char *)fdt + fdt_totalsize(fdt);
+       int strtabsize = fdt_size_dt_strings(fdt);
+       const char *p;
+
+       *allocated = 0;
+
+       p = fdt_find_string_(strtab - strtabsize, strtabsize, s);
+       if (p)
+               return p - strtab;
+
+       *allocated = 1;
+
+       return fdt_add_string_(fdt, s);
+}
+
 int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)
 {
        struct fdt_property *prop;
        int nameoff;
+       int allocated;
 
-       FDT_SW_CHECK_HEADER(fdt);
+       FDT_SW_PROBE_STRUCT(fdt);
 
-       nameoff = fdt_find_add_string_(fdt, name);
+       /* String de-duplication can be slow, _NO_NAME_DEDUP skips it */
+       if (sw_flags(fdt) & FDT_CREATE_FLAG_NO_NAME_DEDUP) {
+               allocated = 1;
+               nameoff = fdt_add_string_(fdt, name);
+       } else {
+               nameoff = fdt_find_add_string_(fdt, name, &allocated);
+       }
        if (nameoff == 0)
                return -FDT_ERR_NOSPACE;
 
        prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
-       if (! prop)
+       if (! prop) {
+               if (allocated)
+                       fdt_del_last_string_(fdt, name);
                return -FDT_ERR_NOSPACE;
+       }
 
        prop->tag = cpu_to_fdt32(FDT_PROP);
        prop->nameoff = cpu_to_fdt32(nameoff);
@@ -262,7 +341,7 @@ int fdt_finish(void *fdt)
        uint32_t tag;
        int offset, nextoffset;
 
-       FDT_SW_CHECK_HEADER(fdt);
+       FDT_SW_PROBE_STRUCT(fdt);
 
        /* Add terminator */
        end = fdt_grab_space_(fdt, sizeof(*end));
@@ -295,6 +374,10 @@ int fdt_finish(void *fdt)
 
        /* Finally, adjust the header */
        fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
+
+       /* And fix up fields that were keeping intermediate state. */
+       fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
        fdt_set_magic(fdt, FDT_MAGIC);
+
        return 0;
 }
index 534c1cbbb2f355deb7d7b69a19b7e5ac1c309989..f64139e0b3dc5010b28f71815ed6d97ddaa1de4a 100644 (file)
@@ -1,52 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "libfdt_env.h"
 
index c400f2f5d544cf7898c23978b318ac171e370cbb..36fadcdea516a2294212e5aa002f485f03e06d4b 100644 (file)
@@ -1,54 +1,9 @@
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
 #ifndef LIBFDT_H
 #define LIBFDT_H
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include "libfdt_env.h"
@@ -90,8 +45,9 @@
 
 /* Error codes: codes for bad device tree blobs */
 #define FDT_ERR_TRUNCATED      8
-       /* FDT_ERR_TRUNCATED: Structure block of the given device tree
-        * ends without an FDT_END tag. */
+       /* FDT_ERR_TRUNCATED: FDT or a sub-block is improperly
+        * terminated (overflows, goes outside allowed bounds, or
+        * isn't properly terminated).  */
 #define FDT_ERR_BADMAGIC       9
        /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
         * device tree at all - it is missing the flattened device
        /* FDT_ERR_NOPHANDLES: The device tree doesn't have any
         * phandle available anymore without causing an overflow */
 
-#define FDT_ERR_MAX            17
+#define FDT_ERR_BADFLAGS       18
+       /* FDT_ERR_BADFLAGS: The function was passed a flags field that
+        * contains invalid flags or an invalid combination of flags. */
+
+#define FDT_ERR_MAX            18
 
 /* constants */
 #define FDT_MAX_PHANDLE 0xfffffffe
@@ -157,6 +117,61 @@ 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);
 
+/*
+ * Alignment helpers:
+ *     These helpers access words from a device tree blob.  They're
+ *     built to work even with unaligned pointers on platforms (ike
+ *     ARM) that don't like unaligned loads and stores
+ */
+
+static inline uint32_t fdt32_ld(const fdt32_t *p)
+{
+       const uint8_t *bp = (const uint8_t *)p;
+
+       return ((uint32_t)bp[0] << 24)
+               | ((uint32_t)bp[1] << 16)
+               | ((uint32_t)bp[2] << 8)
+               | bp[3];
+}
+
+static inline void fdt32_st(void *property, uint32_t value)
+{
+       uint8_t *bp = (uint8_t *)property;
+
+       bp[0] = value >> 24;
+       bp[1] = (value >> 16) & 0xff;
+       bp[2] = (value >> 8) & 0xff;
+       bp[3] = value & 0xff;
+}
+
+static inline uint64_t fdt64_ld(const fdt64_t *p)
+{
+       const uint8_t *bp = (const uint8_t *)p;
+
+       return ((uint64_t)bp[0] << 56)
+               | ((uint64_t)bp[1] << 48)
+               | ((uint64_t)bp[2] << 40)
+               | ((uint64_t)bp[3] << 32)
+               | ((uint64_t)bp[4] << 24)
+               | ((uint64_t)bp[5] << 16)
+               | ((uint64_t)bp[6] << 8)
+               | bp[7];
+}
+
+static inline void fdt64_st(void *property, uint64_t value)
+{
+       uint8_t *bp = (uint8_t *)property;
+
+       bp[0] = value >> 56;
+       bp[1] = (value >> 48) & 0xff;
+       bp[2] = (value >> 40) & 0xff;
+       bp[3] = (value >> 32) & 0xff;
+       bp[4] = (value >> 24) & 0xff;
+       bp[5] = (value >> 16) & 0xff;
+       bp[6] = (value >> 8) & 0xff;
+       bp[7] = value & 0xff;
+}
+
 /**********************************************************************/
 /* Traversal functions                                                */
 /**********************************************************************/
@@ -199,7 +214,7 @@ int fdt_next_subnode(const void *fdt, int offset);
  *             ...
  *     }
  *
- *     if ((node < 0) && (node != -FDT_ERR_NOT_FOUND)) {
+ *     if ((node < 0) && (node != -FDT_ERR_NOTFOUND)) {
  *             Error handling
  *     }
  *
@@ -217,7 +232,7 @@ int fdt_next_subnode(const void *fdt, int offset);
 /* General functions                                                  */
 /**********************************************************************/
 #define fdt_get_header(fdt, field) \
-       (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
+       (fdt32_ld(&((const struct fdt_header *)(fdt))->field))
 #define fdt_magic(fdt)                 (fdt_get_header(fdt, magic))
 #define fdt_totalsize(fdt)             (fdt_get_header(fdt, totalsize))
 #define fdt_off_dt_struct(fdt)         (fdt_get_header(fdt, off_dt_struct))
@@ -248,18 +263,32 @@ fdt_set_hdr_(size_dt_struct);
 #undef fdt_set_hdr_
 
 /**
- * fdt_check_header - sanity check a device tree or possible device tree
+ * fdt_header_size - return the size of the tree's header
+ * @fdt: pointer to a flattened device tree
+ */
+size_t fdt_header_size(const void *fdt);
+
+/**
+ * fdt_header_size_ - internal function which takes a version number
+ */
+size_t fdt_header_size_(uint32_t version);
+
+/**
+ * fdt_check_header - sanity check a device tree header
+
  * @fdt: pointer to data which might be a flattened device tree
  *
  * fdt_check_header() checks that the given buffer contains what
- * appears to be a flattened device tree with sane information in its
- * header.
+ * appears to be a flattened device tree, and that the header contains
+ * valid information (to the extent that can be determined from the
+ * header alone).
  *
  * returns:
  *     0, if the buffer appears to contain a valid device tree
  *     -FDT_ERR_BADMAGIC,
  *     -FDT_ERR_BADVERSION,
- *     -FDT_ERR_BADSTATE, standard meanings, as above
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_TRUNCATED, standard meanings, as above
  */
 int fdt_check_header(const void *fdt);
 
@@ -288,6 +317,24 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
 /* Read-only functions                                                */
 /**********************************************************************/
 
+int fdt_check_full(const void *fdt, size_t bufsize);
+
+/**
+ * fdt_get_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)
+ * @lenp: optional pointer to return the string's length
+ *
+ * fdt_get_string() retrieves a pointer to a single string from the
+ * strings block of the device tree blob at fdt, and optionally also
+ * returns the string's length in *lenp.
+ *
+ * returns:
+ *     a pointer to the string, on success
+ *     NULL, if stroffset is out of bounds, or doesn't point to a valid string
+ */
+const char *fdt_get_string(const void *fdt, int stroffset, int *lenp);
+
 /**
  * fdt_string - retrieve a string from the strings block of a device tree
  * @fdt: pointer to the device tree blob
@@ -298,10 +345,24 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
  *
  * returns:
  *     a pointer to the string, on success
- *     NULL, if stroffset is out of bounds
+ *     NULL, if stroffset is out of bounds, or doesn't point to a valid string
  */
 const char *fdt_string(const void *fdt, int stroffset);
 
+/**
+ * fdt_find_max_phandle - find and return the highest phandle in a tree
+ * @fdt: pointer to the device tree blob
+ * @phandle: return location for the highest phandle value found in the tree
+ *
+ * fdt_find_max_phandle() finds the highest phandle value in the given device
+ * tree. The value returned in @phandle is only valid if the function returns
+ * success.
+ *
+ * returns:
+ *     0 on success or a negative error code on failure
+ */
+int fdt_find_max_phandle(const void *fdt, uint32_t *phandle);
+
 /**
  * fdt_get_max_phandle - retrieves the highest phandle in a tree
  * @fdt: pointer to the device tree blob
@@ -310,12 +371,24 @@ const char *fdt_string(const void *fdt, int stroffset);
  * device tree. This will ignore badly formatted phandles, or phandles
  * with a value of 0 or -1.
  *
+ * This function is deprecated in favour of fdt_find_max_phandle().
+ *
  * returns:
  *      the highest phandle on success
  *      0, if no phandle was found in the device tree
  *      -1, if an error occurred
  */
-uint32_t fdt_get_max_phandle(const void *fdt);
+static inline uint32_t fdt_get_max_phandle(const void *fdt)
+{
+       uint32_t phandle;
+       int err;
+
+       err = fdt_find_max_phandle(fdt, &phandle);
+       if (err < 0)
+               return (uint32_t)-1;
+
+       return phandle;
+}
 
 /**
  * fdt_generate_phandle - return a new, unused phandle for a device tree blob
@@ -522,7 +595,7 @@ int fdt_next_property_offset(const void *fdt, int offset);
  *             ...
  *     }
  *
- *     if ((property < 0) && (property != -FDT_ERR_NOT_FOUND)) {
+ *     if ((property < 0) && (property != -FDT_ERR_NOTFOUND)) {
  *             Error handling
  *     }
  *
@@ -625,7 +698,7 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
 /**
  * fdt_getprop_by_offset - retrieve the value of a property at a given offset
  * @fdt: pointer to the device tree blob
- * @ffset: offset of the property to read
+ * @offset: offset of the property to read
  * @namep: pointer to a string variable (will be overwritten) or NULL
  * @lenp: pointer to an integer variable (will be overwritten) or NULL
  *
@@ -734,7 +807,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset);
 /**
  * fdt_get_alias_namelen - get alias based on substring
  * @fdt: pointer to the device tree blob
- * @name: name of the alias to look up
+ * @name: name of the alias th look up
  * @namelen: number of characters of name to consider
  *
  * Identical to fdt_get_alias(), but only examine the first namelen
@@ -1316,7 +1389,45 @@ int fdt_nop_node(void *fdt, int nodeoffset);
 /* Sequential write functions                                         */
 /**********************************************************************/
 
+/* fdt_create_with_flags flags */
+#define FDT_CREATE_FLAG_NO_NAME_DEDUP 0x1
+       /* FDT_CREATE_FLAG_NO_NAME_DEDUP: Do not try to de-duplicate property
+        * names in the fdt. This can result in faster creation times, but
+        * a larger fdt. */
+
+#define FDT_CREATE_FLAGS_ALL   (FDT_CREATE_FLAG_NO_NAME_DEDUP)
+
+/**
+ * fdt_create_with_flags - begin creation of a new fdt
+ * @fdt: pointer to memory allocated where fdt will be created
+ * @bufsize: size of the memory space at fdt
+ * @flags: a valid combination of FDT_CREATE_FLAG_ flags, or 0.
+ *
+ * fdt_create_with_flags() begins the process of creating a new fdt with
+ * the sequential write interface.
+ *
+ * fdt creation process must end with fdt_finished() to produce a valid fdt.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, bufsize is insufficient for a minimal fdt
+ *     -FDT_ERR_BADFLAGS, flags is not valid
+ */
+int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags);
+
+/**
+ * fdt_create - begin creation of a new fdt
+ * @fdt: pointer to memory allocated where fdt will be created
+ * @bufsize: size of the memory space at fdt
+ *
+ * fdt_create() is equivalent to fdt_create_with_flags() with flags=0.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, bufsize is insufficient for a minimal fdt
+ */
 int fdt_create(void *buf, int bufsize);
+
 int fdt_resize(void *fdt, void *buf, int bufsize);
 int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
 int fdt_finish_reservemap(void *fdt);
@@ -1787,6 +1898,43 @@ static inline int fdt_appendprop_cell(void *fdt, int nodeoffset,
 #define fdt_appendprop_string(fdt, nodeoffset, name, str) \
        fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
 
+/**
+ * fdt_appendprop_addrrange - append a address range property
+ * @fdt: pointer to the device tree blob
+ * @parent: offset of the parent node
+ * @nodeoffset: offset of the node to add a property at
+ * @name: name of property
+ * @addr: start address of a given range
+ * @size: size of a given range
+ *
+ * fdt_appendprop_addrrange() appends an address range value (start
+ * address and size) to the value of the named property in the given
+ * node, or creates a new property with that value if it does not
+ * already exist.
+ * If "name" is not specified, a default "reg" is used.
+ * Cell sizes are determined by parent's #address-cells and #size-cells.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
+ *             #address-cells property
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADVALUE, addr or size doesn't fit to respective cells size
+ *     -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *             contain a new property
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
+                            const char *name, uint64_t addr, uint64_t size);
+
 /**
  * fdt_delprop - delete a property
  * @fdt: pointer to the device tree blob
index 3ff9e28630752c1f55052e8c47c300d1dfb13e67..73b6d40450aca51d94245be59490f6ee3454241d 100644 (file)
@@ -1,55 +1,10 @@
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
 #ifndef LIBFDT_ENV_H
 #define LIBFDT_ENV_H
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
  * Copyright 2012 Kim Phillips, Freescale Semiconductor.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include <stdbool.h>
@@ -57,6 +12,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
+#include <limits.h>
 
 #ifdef __CHECKER__
 #define FDT_FORCE __attribute__((force))
index 7681e192295b0a14cc07aa7a73ed3faca09b15d4..5436e2ceeacf1596dd1fb86ceba69f411b00d8d0 100644 (file)
@@ -1,65 +1,24 @@
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
 #ifndef LIBFDT_INTERNAL_H
 #define LIBFDT_INTERNAL_H
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include <fdt.h>
 
 #define FDT_ALIGN(x, a)                (((x) + (a) - 1) & ~((a) - 1))
 #define FDT_TAGALIGN(x)                (FDT_ALIGN((x), FDT_TAGSIZE))
 
-#define FDT_CHECK_HEADER(fdt) \
-       { \
-               int err_; \
-               if ((err_ = fdt_check_header(fdt)) != 0) \
-                       return err_; \
+int fdt_ro_probe_(const void *fdt);
+#define FDT_RO_PROBE(fdt)                                      \
+       {                                                       \
+               int totalsize_;                                 \
+               if (fdt_chk_basic()) {                          \
+                       totalsize_ = fdt_ro_probe_(fdt);        \
+                       if (totalsize_ < 0)                     \
+                               return totalsize_;              \
+               }                                               \
        }
 
 int fdt_check_node_offset_(const void *fdt, int offset);
@@ -92,4 +51,87 @@ static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n)
 
 #define FDT_SW_MAGIC           (~FDT_MAGIC)
 
+/**********************************************************************/
+/* Checking controls                                                  */
+/**********************************************************************/
+
+#ifndef FDT_ASSUME_MASK
+#define FDT_ASSUME_MASK 0
+#endif
+
+/*
+ * Defines assumptions which can be enabled. Each of these can be enabled
+ * individually. For maximum saftey, don't enable any assumptions!
+ *
+ * For minimal code size and no safety, use FDT_ASSUME_PERFECT at your own risk.
+ * You should have another method of validating the device tree, such as a
+ * signature or hash check before using libfdt.
+ *
+ * For situations where security is not a concern it may be safe to enable
+ * FDT_ASSUME_FRIENDLY.
+ */
+enum {
+       /*
+        * This does essentially no checks. Only the latest device-tree
+        * version is correctly handled. Incosistencies or errors in the device
+        * tree may cause undefined behaviour or crashes.
+        *
+        * If an error occurs when modifying the tree it may leave the tree in
+        * an intermediate (but valid) state. As an example, adding a property
+        * where there is insufficient space may result in the property name
+        * being added to the string table even though the property itself is
+        * not added to the struct section.
+        *
+        * Only use this if you have a fully validated device tree with
+        * the latest supported version and wish to minimise code size.
+        */
+       FDT_ASSUME_PERFECT      = 0xff,
+
+       /*
+        * This assumes that the device tree is sane. i.e. header metadata
+        * and basic hierarchy are correct.
+        *
+        * These checks will be sufficient if you have a valid device tree with
+        * no internal inconsistencies. With this assumption, libfdt will
+        * generally not return -FDT_ERR_INTERNAL, -FDT_ERR_BADLAYOUT, etc.
+        */
+       FDT_ASSUME_SANE         = 1 << 0,
+
+       /*
+        * This disables checks for device-tree version and removes all code
+        * which handles older versions.
+        *
+        * Only enable this if you know you have a device tree with the latest
+        * version.
+        */
+       FDT_ASSUME_LATEST       = 1 << 1,
+
+       /*
+        * This disables any extensive checking of parameters and the device
+        * tree, making various assumptions about correctness. Normal device
+        * trees produced by libfdt and the compiler should be handled safely.
+        * Malicious device trees and complete garbage may cause libfdt to
+        * behave badly or crash.
+        */
+       FDT_ASSUME_FRIENDLY     = 1 << 2,
+};
+
+/** fdt_chk_basic() - see if basic checking of params and DT data is enabled */
+static inline bool fdt_chk_basic(void)
+{
+       return !(FDT_ASSUME_MASK & FDT_ASSUME_SANE);
+}
+
+/** fdt_chk_version() - see if we need to handle old versions of the DT */
+static inline bool fdt_chk_version(void)
+{
+       return !(FDT_ASSUME_MASK & FDT_ASSUME_LATEST);
+}
+
+/** fdt_chk_extra() - see if extra checking is enabled */
+static inline bool fdt_chk_extra(void)
+{
+       return !(FDT_ASSUME_MASK & FDT_ASSUME_FRIENDLY);
+}
+
 #endif /* LIBFDT_INTERNAL_H */
index 68fc7c8c887fafb9721e4d4f3a2b573bfd9a1db0..7189f0142957b55c120aca37111122c534989649 100644 (file)
@@ -11,6 +11,7 @@ int fdt_remove_unused_strings(const void *old, void *new)
        const char *str;
        int ret;
        int tag = FDT_PROP;
+       int allocated;
 
        /* Make a copy and remove the strings */
        memcpy(new, old, size);
@@ -25,7 +26,7 @@ int fdt_remove_unused_strings(const void *old, void *new)
                new_prop = (struct fdt_property *)(unsigned long)
                        fdt_get_property_by_offset(new, offset, NULL);
                str = fdt_string(old, fdt32_to_cpu(old_prop->nameoff));
-               ret = fdt_find_add_string_(new, str);
+               ret = fdt_find_add_string_(new, str, &allocated);
                if (ret < 0)
                        return ret;
                new_prop->nameoff = cpu_to_fdt32(ret);