Commit f0921f50 authored by Simon Glass's avatar Simon Glass
Browse files

fdt: Sync up to the latest libfdt



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's avatarSimon Glass <sjg@chromium.org>
parent e9bae5c5
......@@ -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;