|
@@ -14,12 +14,13 @@
|
|
|
|
|
|
#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
|