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 <sjg@chromium.org>
This commit is contained in:
Simon Glass 2019-10-27 09:47:42 -06:00
parent e9bae5c534
commit f0921f5098
16 changed files with 1278 additions and 874 deletions

View file

@ -14,12 +14,13 @@
#include "libfdt_internal.h" #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 *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 */ /* short match */
return 0; return 0;
@ -34,46 +35,85 @@ static int _fdt_nodename_eq(const void *fdt, int offset,
return 0; return 0;
} }
const char *fdt_string(const void *fdt, int stroffset) const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
{ {
return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; int32_t totalsize;
} uint32_t absoffset;
size_t len;
int err;
const char *s, *n;
static int _fdt_string_eq(const void *fdt, int stroffset, if (!fdt_chk_extra()) {
const char *s, int len) s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
{
const char *p = fdt_string(fdt, stroffset);
return (strnlen(p, len + 1) == len) && (memcmp(p, s, len) == 0); if (lenp)
} *lenp = strlen(s);
return s;
}
totalsize = fdt_ro_probe_(fdt);
err = totalsize;
if (totalsize < 0)
goto fail;
uint32_t fdt_get_max_phandle(const void *fdt) err = -FDT_ERR_BADOFFSET;
{ absoffset = stroffset + fdt_off_dt_strings(fdt);
uint32_t max_phandle = 0; if (absoffset >= totalsize)
int offset; goto fail;
len = totalsize - absoffset;
for (offset = fdt_next_node(fdt, -1, NULL);; if (fdt_magic(fdt) == FDT_MAGIC) {
offset = fdt_next_node(fdt, offset, NULL)) { if (stroffset < 0)
uint32_t phandle; goto fail;
if (!fdt_chk_version() || fdt_version(fdt) >= 17) {
if (offset == -FDT_ERR_NOTFOUND) if (stroffset >= fdt_size_dt_strings(fdt))
return max_phandle; goto fail;
if ((fdt_size_dt_strings(fdt) - stroffset) < len)
if (offset < 0) len = fdt_size_dt_strings(fdt) - stroffset;
return (uint32_t)-1; }
} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
phandle = fdt_get_phandle(fdt, offset); if ((stroffset >= 0)
if (phandle == (uint32_t)-1) || (stroffset < -fdt_size_dt_strings(fdt)))
continue; goto fail;
if ((-stroffset) < len)
if (phandle > max_phandle) len = -stroffset;
max_phandle = phandle; } else {
err = -FDT_ERR_INTERNAL;
goto fail;
} }
return 0; s = (const char *)fdt + absoffset;
n = memchr(s, '\0', len);
if (!n) {
/* missing terminating NULL */
err = -FDT_ERR_TRUNCATED;
goto fail;
}
if (lenp)
*lenp = n - s;
return s;
fail:
if (lenp)
*lenp = err;
return NULL;
} }
int fdt_generate_phandle(const void *fdt, uint32_t *phandle) const char *fdt_string(const void *fdt, int stroffset)
{
return fdt_get_string(fdt, stroffset, NULL);
}
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 p && (slen == len) && (memcmp(p, s, len) == 0);
}
int fdt_find_max_phandle(const void *fdt, uint32_t *phandle)
{ {
uint32_t max = 0; uint32_t max = 0;
int offset = -1; int offset = -1;
@ -95,6 +135,21 @@ int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
max = value; 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) if (max == FDT_MAX_PHANDLE)
return -FDT_ERR_NOPHANDLES; return -FDT_ERR_NOPHANDLES;
@ -104,24 +159,48 @@ int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
return 0; 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) int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
{ {
FDT_CHECK_HEADER(fdt); const struct fdt_reserve_entry *re;
*address = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->address);
*size = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->size); 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; return 0;
} }
int fdt_num_mem_rsv(const void *fdt) 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) for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
i++; if (fdt64_ld(&re->size) == 0)
return i; 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; uint32_t tag;
int nextoffset; int nextoffset;
@ -150,13 +229,13 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset,
{ {
int depth; int depth;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
for (depth = 0; for (depth = 0;
(offset >= 0) && (depth >= 0); (offset >= 0) && (depth >= 0);
offset = fdt_next_node(fdt, offset, &depth)) offset = fdt_next_node(fdt, offset, &depth))
if ((depth == 1) if ((depth == 1)
&& _fdt_nodename_eq(fdt, offset, name, namelen)) && fdt_nodename_eq_(fdt, offset, name, namelen))
return offset; return offset;
if (depth < 0) 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)); 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) int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
{ {
const char *end = path + namelen; const char *end = path + namelen;
const char *p = path; const char *p = path;
int offset = 0; int offset = 0;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
/* see if we have an alias */ /* see if we have an alias */
if (*path != '/') { if (*path != '/') {
const char *q = fdt_path_next_separator(path, namelen); const char *q = memchr(path, '/', end - p);
if (!q) if (!q)
q = end; q = end;
@ -212,17 +272,16 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
p = q; p = q;
} }
while (*p && (p < end)) { while (p < end) {
const char *q; const char *q;
while (*p == '/') while (*p == '/') {
p++; p++;
if (p == end)
if (*p == '\0' || *p == ':') return offset;
return offset; }
q = memchr(p, '/', end - p);
q = fdt_path_next_separator(p, end - p); if (! q)
if (!q)
q = end; q = end;
offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); 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 char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
{ {
const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset); const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset);
const char *nameptr;
int err; int err;
if (((err = fdt_check_header(fdt)) != 0) if (fdt_chk_extra() &&
|| ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)) (((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; goto fail;
}
nameptr = leaf+1;
}
if (len) if (len)
*len = strlen(nh->name); *len = strlen(nameptr);
return nh->name; return nameptr;
fail: fail:
if (len) 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) if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
return offset; return offset;
return _nextprop(fdt, offset); return nextprop_(fdt, offset);
} }
int fdt_next_property_offset(const void *fdt, int 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) if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0)
return offset; return offset;
return _nextprop(fdt, offset); return nextprop_(fdt, offset);
} }
const struct fdt_property *fdt_get_property_by_offset(const void *fdt, static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
int offset, int offset,
int *lenp) int *lenp)
{ {
int err; int err;
const struct fdt_property *prop; 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) if (lenp)
*lenp = err; *lenp = err;
return NULL; return NULL;
@ -294,28 +372,50 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
prop = fdt_offset_ptr_(fdt, offset); prop = fdt_offset_ptr_(fdt, offset);
if (lenp) if (lenp)
*lenp = fdt32_to_cpu(prop->len); *lenp = fdt32_ld(&prop->len);
return prop; return prop;
} }
const struct fdt_property *fdt_get_property_namelen(const void *fdt, const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
int offset, int offset,
const char *name, int *lenp)
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_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); for (offset = fdt_first_property_offset(fdt, offset);
(offset >= 0); (offset >= 0);
(offset = fdt_next_property_offset(fdt, offset))) { (offset = fdt_next_property_offset(fdt, offset))) {
const struct fdt_property *prop; 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; offset = -FDT_ERR_INTERNAL;
break; break;
} }
if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff), if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff),
name, namelen)) name, namelen)) {
if (poffset)
*poffset = offset;
return prop; return prop;
}
} }
if (lenp) if (lenp)
@ -323,6 +423,25 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt,
return NULL; 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, const struct fdt_property *fdt_get_property(const void *fdt,
int nodeoffset, int nodeoffset,
const char *name, int *lenp) 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 void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
const char *name, int namelen, int *lenp) const char *name, int namelen, int *lenp)
{ {
int poffset;
const struct fdt_property *prop; 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) if (!prop)
return NULL; 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; return prop->data;
} }
@ -348,11 +473,31 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
{ {
const struct fdt_property *prop; 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) if (!prop)
return NULL; return NULL;
if (namep) if (namep) {
*namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); 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; return prop->data;
} }
@ -376,7 +521,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
return 0; return 0;
} }
return fdt32_to_cpu(*php); return fdt32_ld(php);
} }
const char *fdt_get_alias_namelen(const void *fdt, 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; int offset, depth, namelen;
const char *name; const char *name;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
if (buflen < 2) if (buflen < 2)
return -FDT_ERR_NOSPACE; return -FDT_ERR_NOSPACE;
@ -454,7 +599,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
int offset, depth; int offset, depth;
int supernodeoffset = -FDT_ERR_INTERNAL; int supernodeoffset = -FDT_ERR_INTERNAL;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
if (supernodedepth < 0) if (supernodedepth < 0)
return -FDT_ERR_NOTFOUND; 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)) if (fdt_chk_extra()) {
return -FDT_ERR_BADOFFSET; if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
else if (offset == -FDT_ERR_BADOFFSET) return -FDT_ERR_BADOFFSET;
return -FDT_ERR_BADSTRUCTURE; else if (offset == -FDT_ERR_BADOFFSET)
return -FDT_ERR_BADSTRUCTURE;
}
return offset; /* error from fdt_next_node() */ 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); err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
if (err) if (err)
return (err < 0) ? err : -FDT_ERR_INTERNAL; return (!fdt_chk_extra() || err < 0) ? err : -FDT_ERR_INTERNAL;
return nodedepth; return nodedepth;
} }
@ -513,7 +660,7 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
const void *val; const void *val;
int len; int len;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
/* FIXME: The algorithm here is pretty horrible: we scan each /* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_getprop(), then if that didn't * 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)) if ((phandle == 0) || (phandle == -1))
return -FDT_ERR_BADPHANDLE; return -FDT_ERR_BADPHANDLE;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
/* FIXME: The algorithm here is pretty horrible: we /* FIXME: The algorithm here is pretty horrible: we
* potentially scan each property of a node in * 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; int offset, err;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
/* FIXME: The algorithm here is pretty horrible: we scan each /* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_node_check_compatible(), then if * 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() */ 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

View file

@ -1,3 +1,4 @@
# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
# Makefile.libfdt # Makefile.libfdt
# #
# This is not a complete Makefile of itself. Instead, it is designed to # 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 \ 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 fdt_addresses.c fdt_overlay.c
LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) 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)

View file

@ -1,52 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation. * 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_env.h"
@ -55,14 +10,24 @@
#include "libfdt_internal.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) { if (fdt_magic(fdt) == FDT_MAGIC) {
/* Complete tree */ /* Complete tree */
if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) if (fdt_chk_version()) {
return -FDT_ERR_BADVERSION; if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) return -FDT_ERR_BADVERSION;
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) { } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
/* Unfinished sequential-write blob */ /* Unfinished sequential-write blob */
if (fdt_size_dt_struct(fdt) == 0) if (fdt_size_dt_struct(fdt) == 0)
@ -71,6 +36,96 @@ int fdt_check_header(const void *fdt)
return -FDT_ERR_BADMAGIC; 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; 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); unsigned absoffset = offset + fdt_off_dt_struct(fdt);
if ((absoffset < offset) if (fdt_chk_basic())
|| ((absoffset + len) < absoffset) if ((absoffset < offset)
|| (absoffset + len) > fdt_totalsize(fdt)) || ((absoffset + len) < absoffset)
return NULL; || (absoffset + len) > fdt_totalsize(fdt))
return NULL;
if (fdt_version(fdt) >= 0x11) if (!fdt_chk_version() || fdt_version(fdt) >= 0x11)
if (((offset + len) < offset) if (((offset + len) < offset)
|| ((offset + len) > fdt_size_dt_struct(fdt))) || ((offset + len) > fdt_size_dt_struct(fdt)))
return NULL; return NULL;
@ -100,7 +156,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
*nextoffset = -FDT_ERR_TRUNCATED; *nextoffset = -FDT_ERR_TRUNCATED;
tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
if (!tagp) if (fdt_chk_basic() && !tagp)
return FDT_END; /* premature end */ return FDT_END; /* premature end */
tag = fdt32_to_cpu(*tagp); tag = fdt32_to_cpu(*tagp);
offset += FDT_TAGSIZE; offset += FDT_TAGSIZE;
@ -112,18 +168,19 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
do { do {
p = fdt_offset_ptr(fdt, offset++, 1); p = fdt_offset_ptr(fdt, offset++, 1);
} while (p && (*p != '\0')); } while (p && (*p != '\0'));
if (!p) if (fdt_chk_basic() && !p)
return FDT_END; /* premature end */ return FDT_END; /* premature end */
break; break;
case FDT_PROP: case FDT_PROP:
lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
if (!lenp) if (fdt_chk_basic() && !lenp)
return FDT_END; /* premature end */ return FDT_END; /* premature end */
/* skip-name offset, length and value */ /* skip-name offset, length and value */
offset += sizeof(struct fdt_property) - FDT_TAGSIZE offset += sizeof(struct fdt_property) - FDT_TAGSIZE
+ fdt32_to_cpu(*lenp); + 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 - fdt32_to_cpu(*lenp)) % 8) != 0)
offset += 4; offset += 4;
break; break;
@ -137,7 +194,8 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
return FDT_END; 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 */ return FDT_END; /* premature end */
*nextoffset = FDT_TAGALIGN(offset); *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) int fdt_move(const void *fdt, void *buf, int bufsize)
{ {
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
if (fdt_totalsize(fdt) > bufsize) if (fdt_totalsize(fdt) > bufsize)
return -FDT_ERR_NOSPACE; return -FDT_ERR_NOSPACE;

View file

@ -1,55 +1,10 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
#ifndef FDT_H #ifndef FDT_H
#define FDT_H #define FDT_H
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation. * Copyright (C) 2006 David Gibson, IBM Corporation.
* Copyright 2012 Kim Phillips, Freescale Semiconductor. * 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__ #ifndef __ASSEMBLY__

View file

@ -1,53 +1,8 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au> * Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au>
* Copyright (C) 2018 embedded brains GmbH * 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" #include "libfdt_env.h"
@ -97,3 +52,50 @@ int fdt_size_cells(const void *fdt, int nodeoffset)
return 1; return 1;
return val; 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));
}

View file

@ -1,52 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2012 David Gibson, IBM Corporation. * 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" #include "libfdt_env.h"

View file

@ -1,53 +1,8 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2016 Free Electrons * Copyright (C) 2016 Free Electrons
* Copyright (C) 2016 NextThing Co. * 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" #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) * @pathp: pointer which receives the path of the target (or NULL)
* *
* overlay_get_target() retrieves the target offset in the base * 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) * done (through a phandle or a path)
* *
* returns: * returns:
* the targetted node offset in the base device tree * the targeted node offset in the base device tree
* Negative error code on error * Negative error code on error
*/ */
static int overlay_get_target(const void *fdt, const void *fdto, 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; int len = 0, namelen;
const char *name; const char *name;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
for (;;) { for (;;) {
name = fdt_get_name(fdt, nodeoffset, &namelen); 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() */ /* keep end marker to avoid strlen() */
e = path + path_len; e = path + path_len;
/* format: /<fragment-name>/__overlay__/<relative-subnode-path> */
if (*path != '/') if (*path != '/')
return -FDT_ERR_BADVALUE; return -FDT_ERR_BADVALUE;
/* get fragment name first */ /* get fragment name first */
s = strchr(path + 1, '/'); s = strchr(path + 1, '/');
if (!s) if (!s) {
return -FDT_ERR_BADOVERLAY; /* Symbol refers to something that won't end
* up in the target tree */
continue;
}
frag_name = path + 1; frag_name = path + 1;
frag_name_len = s - path - 1; frag_name_len = s - path - 1;
/* verify format; safe since "s" lies in \0 terminated prop */ /* verify format; safe since "s" lies in \0 terminated prop */
len = sizeof("/__overlay__/") - 1; len = sizeof("/__overlay__/") - 1;
if ((e - s) < len || memcmp(s, "/__overlay__/", len)) if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) {
return -FDT_ERR_BADOVERLAY; /* /<fragment-name>/__overlay__/<relative-subnode-path> */
rel_path = s + len;
rel_path = s + len; rel_path_len = e - rel_path;
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 */ /* find the fragment index in which the symbol lies */
ret = fdt_subnode_offset_namelen(fdto, 0, frag_name, 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) int fdt_overlay_apply(void *fdt, void *fdto)
{ {
uint32_t delta = fdt_get_max_phandle(fdt); uint32_t delta;
int ret; int ret;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
FDT_CHECK_HEADER(fdto); FDT_RO_PROBE(fdto);
ret = fdt_find_max_phandle(fdt, &delta);
if (ret)
goto err;
ret = overlay_adjust_local_phandles(fdto, delta); ret = overlay_adjust_local_phandles(fdto, delta);
if (ret) if (ret)

View file

@ -1,52 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation. * 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_env.h"
@ -61,7 +16,7 @@ static int fdt_nodename_eq_(const void *fdt, int offset,
int olen; int olen;
const char *p = fdt_get_name(fdt, offset, &olen); const char *p = fdt_get_name(fdt, offset, &olen);
if (!p || olen < len) if (!p || (fdt_chk_extra() && olen < len))
/* short match */ /* short match */
return 0; return 0;
@ -76,46 +31,85 @@ static int fdt_nodename_eq_(const void *fdt, int offset,
return 0; return 0;
} }
const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
{
int32_t totalsize;
uint32_t absoffset;
size_t len;
int err;
const char *s, *n;
if (!fdt_chk_extra()) {
s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
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;
}
s = (const char *)fdt + absoffset;
n = memchr(s, '\0', len);
if (!n) {
/* missing terminating NULL */
err = -FDT_ERR_TRUNCATED;
goto fail;
}
if (lenp)
*lenp = n - s;
return s;
fail:
if (lenp)
*lenp = err;
return NULL;
}
const char *fdt_string(const void *fdt, int stroffset) const char *fdt_string(const void *fdt, int stroffset)
{ {
return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; return fdt_get_string(fdt, stroffset, NULL);
} }
static int fdt_string_eq_(const void *fdt, int stroffset, static int fdt_string_eq_(const void *fdt, int stroffset,
const char *s, int len) const char *s, int len)
{ {
const char *p = fdt_string(fdt, stroffset); int slen;
const char *p = fdt_get_string(fdt, stroffset, &slen);
return (strlen(p) == len) && (memcmp(p, s, len) == 0); return p && (slen == len) && (memcmp(p, s, len) == 0);
} }
uint32_t fdt_get_max_phandle(const void *fdt) int fdt_find_max_phandle(const void *fdt, uint32_t *phandle)
{
uint32_t max_phandle = 0;
int offset;
for (offset = fdt_next_node(fdt, -1, NULL);;
offset = fdt_next_node(fdt, offset, NULL)) {
uint32_t phandle;
if (offset == -FDT_ERR_NOTFOUND)
return max_phandle;
if (offset < 0)
return (uint32_t)-1;
phandle = fdt_get_phandle(fdt, offset);
if (phandle == (uint32_t)-1)
continue;
if (phandle > max_phandle)
max_phandle = phandle;
}
return 0;
}
int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
{ {
uint32_t max = 0; uint32_t max = 0;
int offset = -1; int offset = -1;
@ -137,6 +131,21 @@ int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
max = value; 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) if (max == FDT_MAX_PHANDLE)
return -FDT_ERR_NOPHANDLES; return -FDT_ERR_NOPHANDLES;
@ -146,21 +155,45 @@ int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
return 0; 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) int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
{ {
FDT_CHECK_HEADER(fdt); const struct fdt_reserve_entry *re;
*address = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->address);
*size = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->size); 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; return 0;
} }
int fdt_num_mem_rsv(const void *fdt) 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) for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
i++; if (fdt64_ld(&re->size) == 0)
return i; return i;
}
return -FDT_ERR_TRUNCATED;
} }
static int nextprop_(const void *fdt, int offset) static int nextprop_(const void *fdt, int offset)
@ -192,7 +225,7 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset,
{ {
int depth; int depth;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
for (depth = 0; for (depth = 0;
(offset >= 0) && (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; const char *p = path;
int offset = 0; int offset = 0;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
/* see if we have an alias */ /* see if we have an alias */
if (*path != '/') { if (*path != '/') {
@ -268,13 +301,14 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
const char *nameptr; const char *nameptr;
int err; int err;
if (((err = fdt_check_header(fdt)) != 0) if (fdt_chk_extra() &&
|| ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)) (((err = fdt_ro_probe_(fdt)) < 0)
goto fail; || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)))
goto fail;
nameptr = nh->name; 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: * For old FDT versions, match the naming conventions of V16:
* give only the leaf name (after all /). The actual tree * 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; int err;
const struct fdt_property *prop; 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) if (lenp)
*lenp = err; *lenp = err;
return NULL; 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); prop = fdt_offset_ptr_(fdt, offset);
if (lenp) if (lenp)
*lenp = fdt32_to_cpu(prop->len); *lenp = fdt32_ld(&prop->len);
return prop; 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 /* Prior to version 16, properties may need realignment
* and this API does not work. fdt_getprop_*() will, however. */ * 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) if (lenp)
*lenp = -FDT_ERR_BADVERSION; *lenp = -FDT_ERR_BADVERSION;
return NULL; 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))) { (offset = fdt_next_property_offset(fdt, offset))) {
const struct fdt_property *prop; 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; offset = -FDT_ERR_INTERNAL;
break; break;
} }
if (fdt_string_eq_(fdt, fdt32_to_cpu(prop->nameoff), if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff),
name, namelen)) { name, namelen)) {
if (poffset) if (poffset)
*poffset = offset; *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 /* Prior to version 16, properties may need realignment
* and this API does not work. fdt_getprop_*() will, however. */ * 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) if (lenp)
*lenp = -FDT_ERR_BADVERSION; *lenp = -FDT_ERR_BADVERSION;
return NULL; return NULL;
@ -423,8 +458,8 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
return NULL; return NULL;
/* Handle realignment */ /* Handle realignment */
if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 && if (fdt_chk_version() && fdt_version(fdt) < 0x10 &&
fdt32_to_cpu(prop->len) >= 8) (poffset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
return prop->data + 4; return prop->data + 4;
return prop->data; 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); prop = fdt_get_property_by_offset_(fdt, offset, lenp);
if (!prop) if (!prop)
return NULL; return NULL;
if (namep) if (namep) {
*namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); 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 */ /* Handle realignment */
if (fdt_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 && if (fdt_chk_version() && fdt_version(fdt) < 0x10 &&
fdt32_to_cpu(prop->len) >= 8) (offset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
return prop->data + 4; return prop->data + 4;
return prop->data; return prop->data;
} }
@ -467,7 +517,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
return 0; return 0;
} }
return fdt32_to_cpu(*php); return fdt32_ld(php);
} }
const char *fdt_get_alias_namelen(const void *fdt, 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; int offset, depth, namelen;
const char *name; const char *name;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
if (buflen < 2) if (buflen < 2)
return -FDT_ERR_NOSPACE; return -FDT_ERR_NOSPACE;
@ -545,7 +595,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
int offset, depth; int offset, depth;
int supernodeoffset = -FDT_ERR_INTERNAL; int supernodeoffset = -FDT_ERR_INTERNAL;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
if (supernodedepth < 0) if (supernodedepth < 0)
return -FDT_ERR_NOTFOUND; 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)) if (fdt_chk_extra()) {
return -FDT_ERR_BADOFFSET; if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
else if (offset == -FDT_ERR_BADOFFSET) return -FDT_ERR_BADOFFSET;
return -FDT_ERR_BADSTRUCTURE; else if (offset == -FDT_ERR_BADOFFSET)
return -FDT_ERR_BADSTRUCTURE;
}
return offset; /* error from fdt_next_node() */ 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); err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
if (err) if (err)
return (err < 0) ? err : -FDT_ERR_INTERNAL; return (!fdt_chk_extra() || err < 0) ? err : -FDT_ERR_INTERNAL;
return nodedepth; return nodedepth;
} }
@ -604,7 +656,7 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
const void *val; const void *val;
int len; int len;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
/* FIXME: The algorithm here is pretty horrible: we scan each /* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_getprop(), then if that didn't * 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)) if ((phandle == 0) || (phandle == -1))
return -FDT_ERR_BADPHANDLE; return -FDT_ERR_BADPHANDLE;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
/* FIXME: The algorithm here is pretty horrible: we /* FIXME: The algorithm here is pretty horrible: we
* potentially scan each property of a node in * 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; int offset, err;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
/* FIXME: The algorithm here is pretty horrible: we scan each /* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_node_check_compatible(), then if * 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() */ 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

View file

@ -1,52 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation. * 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_env.h"
@ -58,6 +13,8 @@
static int fdt_blocks_misordered_(const void *fdt, static int fdt_blocks_misordered_(const void *fdt,
int mem_rsv_size, int struct_size) 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)) return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
|| (fdt_off_dt_struct(fdt) < || (fdt_off_dt_struct(fdt) <
(fdt_off_mem_rsvmap(fdt) + mem_rsv_size)) (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))); (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; return -FDT_ERR_BADVERSION;
if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry), if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry),
fdt_size_dt_struct(fdt))) fdt_size_dt_struct(fdt)))
return -FDT_ERR_BADLAYOUT; return -FDT_ERR_BADLAYOUT;
if (fdt_version(fdt) > 17) if (fdt_chk_version() && fdt_version(fdt) > 17)
fdt_set_version(fdt, 17); fdt_set_version(fdt, 17);
return 0; return 0;
} }
#define FDT_RW_CHECK_HEADER(fdt) \ #define FDT_RW_PROBE(fdt) \
{ \ { \
int err_; \ int err_; \
if ((err_ = fdt_rw_check_header_(fdt)) != 0) \ if (fdt_chk_extra() && (err_ = fdt_rw_probe_(fdt)) != 0) \
return err_; \ return err_; \
} }
@ -136,6 +95,14 @@ static int fdt_splice_struct_(void *fdt, void *p,
return 0; 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) static int fdt_splice_string_(void *fdt, int newlen)
{ {
void *p = (char *)fdt void *p = (char *)fdt
@ -149,7 +116,16 @@ static int fdt_splice_string_(void *fdt, int newlen)
return 0; 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); char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
const char *p; const char *p;
@ -157,6 +133,9 @@ static int fdt_find_add_string_(void *fdt, const char *s)
int len = strlen(s) + 1; int len = strlen(s) + 1;
int err; int err;
if (fdt_chk_basic())
*allocated = 0;
p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s); p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s);
if (p) if (p)
/* found it */ /* found it */
@ -167,6 +146,9 @@ static int fdt_find_add_string_(void *fdt, const char *s)
if (err) if (err)
return err; return err;
if (fdt_chk_basic())
*allocated = 1;
memcpy(new, s, len); memcpy(new, s, len);
return (new - strtab); 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; struct fdt_reserve_entry *re;
int err; int err;
FDT_RW_CHECK_HEADER(fdt); FDT_RW_PROBE(fdt);
re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt)); re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt));
err = fdt_splice_mem_rsv_(fdt, re, 0, 1); 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); 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)) if (n >= fdt_num_mem_rsv(fdt))
return -FDT_ERR_NOTFOUND; return -FDT_ERR_NOTFOUND;
@ -225,11 +207,12 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
int nextoffset; int nextoffset;
int namestroff; int namestroff;
int err; int err;
int allocated;
if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0) if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
return nextoffset; return nextoffset;
namestroff = fdt_find_add_string_(fdt, name); namestroff = fdt_find_add_string_(fdt, name, &allocated);
if (namestroff < 0) if (namestroff < 0)
return namestroff; return namestroff;
@ -237,8 +220,12 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
proplen = sizeof(**prop) + FDT_TAGALIGN(len); proplen = sizeof(**prop) + FDT_TAGALIGN(len);
err = fdt_splice_struct_(fdt, *prop, 0, proplen); 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; return err;
}
(*prop)->tag = cpu_to_fdt32(FDT_PROP); (*prop)->tag = cpu_to_fdt32(FDT_PROP);
(*prop)->nameoff = cpu_to_fdt32(namestroff); (*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 oldlen, newlen;
int err; int err;
FDT_RW_CHECK_HEADER(fdt); FDT_RW_PROBE(fdt);
namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
if (!namep) if (!namep)
@ -275,7 +262,7 @@ int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
struct fdt_property *prop; struct fdt_property *prop;
int err; int err;
FDT_RW_CHECK_HEADER(fdt); FDT_RW_PROBE(fdt);
err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop); err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop);
if (err == -FDT_ERR_NOTFOUND) if (err == -FDT_ERR_NOTFOUND)
@ -308,7 +295,7 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
struct fdt_property *prop; struct fdt_property *prop;
int err, oldlen, newlen; int err, oldlen, newlen;
FDT_RW_CHECK_HEADER(fdt); FDT_RW_PROBE(fdt);
prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
if (prop) { if (prop) {
@ -334,7 +321,7 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name)
struct fdt_property *prop; struct fdt_property *prop;
int len, proplen; int len, proplen;
FDT_RW_CHECK_HEADER(fdt); FDT_RW_PROBE(fdt);
prop = fdt_get_property_w(fdt, nodeoffset, name, &len); prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
if (!prop) if (!prop)
@ -354,7 +341,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
uint32_t tag; uint32_t tag;
fdt32_t *endtag; fdt32_t *endtag;
FDT_RW_CHECK_HEADER(fdt); FDT_RW_PROBE(fdt);
offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
if (offset >= 0) if (offset >= 0)
@ -394,7 +381,7 @@ int fdt_del_node(void *fdt, int nodeoffset)
{ {
int endoffset; int endoffset;
FDT_RW_CHECK_HEADER(fdt); FDT_RW_PROBE(fdt);
endoffset = fdt_node_end_offset_(fdt, nodeoffset); endoffset = fdt_node_end_offset_(fdt, nodeoffset);
if (endoffset < 0) 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); const char *fdtend = fdtstart + fdt_totalsize(fdt);
char *tmp; char *tmp;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry); * 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); struct_size = fdt_size_dt_struct(fdt);
} else { } else {
struct_size = 0; struct_size = 0;
@ -494,7 +481,7 @@ int fdt_pack(void *fdt)
{ {
int mem_rsv_size; int mem_rsv_size;
FDT_RW_CHECK_HEADER(fdt); FDT_RW_PROBE(fdt);
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry); * sizeof(struct fdt_reserve_entry);

View file

@ -1,51 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation. * 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. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "libfdt_env.h" #include "libfdt_env.h"
@ -82,6 +38,7 @@ static struct fdt_errtabent fdt_errtable[] = {
FDT_ERRTABENT(FDT_ERR_BADVALUE), FDT_ERRTABENT(FDT_ERR_BADVALUE),
FDT_ERRTABENT(FDT_ERR_BADOVERLAY), FDT_ERRTABENT(FDT_ERR_BADOVERLAY),
FDT_ERRTABENT(FDT_ERR_NOPHANDLES), FDT_ERRTABENT(FDT_ERR_NOPHANDLES),
FDT_ERRTABENT(FDT_ERR_BADFLAGS),
}; };
#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) #define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))

View file

@ -1,52 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation. * 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_env.h"
@ -55,21 +10,90 @@
#include "libfdt_internal.h" #include "libfdt_internal.h"
static int fdt_sw_check_header_(void *fdt) static int fdt_sw_probe_(void *fdt)
{ {
if (fdt_magic(fdt) != FDT_SW_MAGIC) if (fdt_chk_basic()) {
return -FDT_ERR_BADMAGIC; if (fdt_magic(fdt) == FDT_MAGIC)
/* FIXME: should check more details about the header state */ return -FDT_ERR_BADSTATE;
else if (fdt_magic(fdt) != FDT_SW_MAGIC)
return -FDT_ERR_BADMAGIC;
}
return 0; return 0;
} }
#define FDT_SW_CHECK_HEADER(fdt) \ #define FDT_SW_PROBE(fdt) \
{ \ { \
int err; \ int err; \
if ((err = fdt_sw_check_header_(fdt)) != 0) \ if (fdt_chk_basic() && (err = fdt_sw_probe_(fdt)) != 0) \
return err; \ 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)
{
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_PROBE_STRUCT(fdt) \
{ \
int err; \
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) static void *fdt_grab_space_(void *fdt, size_t len)
{ {
int offset = fdt_size_dt_struct(fdt); 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); 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; void *fdt = buf;
if (bufsize < sizeof(struct fdt_header)) if (bufsize < hdrsize)
return -FDT_ERR_NOSPACE; return -FDT_ERR_NOSPACE;
if (flags & ~FDT_CREATE_FLAGS_ALL)
return -FDT_ERR_BADFLAGS;
memset(buf, 0, bufsize); 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_magic(fdt, FDT_SW_MAGIC);
fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); 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_totalsize(fdt, bufsize);
fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header), fdt_set_off_mem_rsvmap(fdt, hdrsize);
sizeof(struct fdt_reserve_entry)));
fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); 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; 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) int fdt_resize(void *fdt, void *buf, int bufsize)
{ {
size_t headsize, tailsize; size_t headsize, tailsize;
char *oldtail, *newtail; char *oldtail, *newtail;
FDT_SW_CHECK_HEADER(fdt); FDT_SW_PROBE(fdt);
headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
tailsize = fdt_size_dt_strings(fdt); tailsize = fdt_size_dt_strings(fdt);
if (fdt_chk_extra() && (headsize + tailsize) > fdt_totalsize(fdt))
return -FDT_ERR_INTERNAL;
if ((headsize + tailsize) > bufsize) if ((headsize + tailsize) > bufsize)
return -FDT_ERR_NOSPACE; return -FDT_ERR_NOSPACE;
@ -133,8 +177,9 @@ int fdt_resize(void *fdt, void *buf, int bufsize)
memmove(buf, fdt, headsize); memmove(buf, fdt, headsize);
} }
fdt_set_off_dt_strings(buf, bufsize);
fdt_set_totalsize(buf, bufsize); fdt_set_totalsize(buf, bufsize);
if (fdt_off_dt_strings(buf))
fdt_set_off_dt_strings(buf, bufsize);
return 0; return 0;
} }
@ -144,10 +189,7 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
struct fdt_reserve_entry *re; struct fdt_reserve_entry *re;
int offset; int offset;
FDT_SW_CHECK_HEADER(fdt); FDT_SW_PROBE_MEMRSV(fdt);
if (fdt_size_dt_struct(fdt))
return -FDT_ERR_BADSTATE;
offset = fdt_off_dt_struct(fdt); offset = fdt_off_dt_struct(fdt);
if ((offset + sizeof(*re)) > fdt_totalsize(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) 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) int fdt_begin_node(void *fdt, const char *name)
{ {
struct fdt_node_header *nh; 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)); nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
if (! nh) if (! nh)
return -FDT_ERR_NOSPACE; return -FDT_ERR_NOSPACE;
@ -187,7 +236,7 @@ int fdt_end_node(void *fdt)
{ {
fdt32_t *en; fdt32_t *en;
FDT_SW_CHECK_HEADER(fdt); FDT_SW_PROBE_STRUCT(fdt);
en = fdt_grab_space_(fdt, FDT_TAGSIZE); en = fdt_grab_space_(fdt, FDT_TAGSIZE);
if (! en) if (! en)
@ -197,19 +246,13 @@ int fdt_end_node(void *fdt)
return 0; 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); char *strtab = (char *)fdt + fdt_totalsize(fdt);
const char *p;
int strtabsize = fdt_size_dt_strings(fdt); int strtabsize = fdt_size_dt_strings(fdt);
int len = strlen(s) + 1; int len = strlen(s) + 1;
int struct_top, offset; int struct_top, offset;
p = fdt_find_string_(strtab - strtabsize, strtabsize, s);
if (p)
return p - strtab;
/* Add it */
offset = -strtabsize - len; offset = -strtabsize - len;
struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
if (fdt_totalsize(fdt) + offset < struct_top) if (fdt_totalsize(fdt) + offset < struct_top)
@ -220,20 +263,56 @@ static int fdt_find_add_string_(void *fdt, const char *s)
return offset; 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) int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)
{ {
struct fdt_property *prop; struct fdt_property *prop;
int nameoff; 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) if (nameoff == 0)
return -FDT_ERR_NOSPACE; return -FDT_ERR_NOSPACE;
prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); 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; return -FDT_ERR_NOSPACE;
}
prop->tag = cpu_to_fdt32(FDT_PROP); prop->tag = cpu_to_fdt32(FDT_PROP);
prop->nameoff = cpu_to_fdt32(nameoff); prop->nameoff = cpu_to_fdt32(nameoff);
@ -262,7 +341,7 @@ int fdt_finish(void *fdt)
uint32_t tag; uint32_t tag;
int offset, nextoffset; int offset, nextoffset;
FDT_SW_CHECK_HEADER(fdt); FDT_SW_PROBE_STRUCT(fdt);
/* Add terminator */ /* Add terminator */
end = fdt_grab_space_(fdt, sizeof(*end)); end = fdt_grab_space_(fdt, sizeof(*end));
@ -295,6 +374,10 @@ int fdt_finish(void *fdt)
/* Finally, adjust the header */ /* Finally, adjust the header */
fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); 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); fdt_set_magic(fdt, FDT_MAGIC);
return 0; return 0;
} }

View file

@ -1,52 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation. * 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_env.h"

View file

@ -1,54 +1,9 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
#ifndef LIBFDT_H #ifndef LIBFDT_H
#define LIBFDT_H #define LIBFDT_H
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation. * 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_env.h"
@ -90,8 +45,9 @@
/* Error codes: codes for bad device tree blobs */ /* Error codes: codes for bad device tree blobs */
#define FDT_ERR_TRUNCATED 8 #define FDT_ERR_TRUNCATED 8
/* FDT_ERR_TRUNCATED: Structure block of the given device tree /* FDT_ERR_TRUNCATED: FDT or a sub-block is improperly
* ends without an FDT_END tag. */ * terminated (overflows, goes outside allowed bounds, or
* isn't properly terminated). */
#define FDT_ERR_BADMAGIC 9 #define FDT_ERR_BADMAGIC 9
/* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
* device tree at all - it is missing the flattened device * device tree at all - it is missing the flattened device
@ -137,7 +93,11 @@
/* FDT_ERR_NOPHANDLES: The device tree doesn't have any /* FDT_ERR_NOPHANDLES: The device tree doesn't have any
* phandle available anymore without causing an overflow */ * 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 */ /* constants */
#define FDT_MAX_PHANDLE 0xfffffffe #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); 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 */ /* 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 * Error handling
* } * }
* *
@ -217,7 +232,7 @@ int fdt_next_subnode(const void *fdt, int offset);
/* General functions */ /* General functions */
/**********************************************************************/ /**********************************************************************/
#define fdt_get_header(fdt, field) \ #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_magic(fdt) (fdt_get_header(fdt, magic))
#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) #define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize))
#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) #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_ #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: pointer to data which might be a flattened device tree
* *
* fdt_check_header() checks that the given buffer contains what * fdt_check_header() checks that the given buffer contains what
* appears to be a flattened device tree with sane information in its * appears to be a flattened device tree, and that the header contains
* header. * valid information (to the extent that can be determined from the
* header alone).
* *
* returns: * returns:
* 0, if the buffer appears to contain a valid device tree * 0, if the buffer appears to contain a valid device tree
* -FDT_ERR_BADMAGIC, * -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION, * -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); int fdt_check_header(const void *fdt);
@ -288,6 +317,24 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
/* Read-only functions */ /* 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_string - retrieve a string from the strings block of a device tree
* @fdt: pointer to the device tree blob * @fdt: pointer to the device tree blob
@ -298,10 +345,24 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
* *
* returns: * returns:
* a pointer to the string, on success * 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); 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_get_max_phandle - retrieves the highest phandle in a tree
* @fdt: pointer to the device tree blob * @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 * device tree. This will ignore badly formatted phandles, or phandles
* with a value of 0 or -1. * with a value of 0 or -1.
* *
* This function is deprecated in favour of fdt_find_max_phandle().
*
* returns: * returns:
* the highest phandle on success * the highest phandle on success
* 0, if no phandle was found in the device tree * 0, if no phandle was found in the device tree
* -1, if an error occurred * -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 * 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 * 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_getprop_by_offset - retrieve the value of a property at a given offset
* @fdt: pointer to the device tree blob * @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 * @namep: pointer to a string variable (will be overwritten) or NULL
* @lenp: pointer to an integer 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_get_alias_namelen - get alias based on substring
* @fdt: pointer to the device tree blob * @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 * @namelen: number of characters of name to consider
* *
* Identical to fdt_get_alias(), but only examine the first namelen * 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 */ /* 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_create(void *buf, int bufsize);
int fdt_resize(void *fdt, 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_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
int fdt_finish_reservemap(void *fdt); 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) \ #define fdt_appendprop_string(fdt, nodeoffset, name, str) \
fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) 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_delprop - delete a property
* @fdt: pointer to the device tree blob * @fdt: pointer to the device tree blob

View file

@ -1,55 +1,10 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
#ifndef LIBFDT_ENV_H #ifndef LIBFDT_ENV_H
#define LIBFDT_ENV_H #define LIBFDT_ENV_H
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation. * Copyright (C) 2006 David Gibson, IBM Corporation.
* Copyright 2012 Kim Phillips, Freescale Semiconductor. * 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> #include <stdbool.h>
@ -57,6 +12,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <limits.h>
#ifdef __CHECKER__ #ifdef __CHECKER__
#define FDT_FORCE __attribute__((force)) #define FDT_FORCE __attribute__((force))

View file

@ -1,65 +1,24 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
#ifndef LIBFDT_INTERNAL_H #ifndef LIBFDT_INTERNAL_H
#define LIBFDT_INTERNAL_H #define LIBFDT_INTERNAL_H
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation. * 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> #include <fdt.h>
#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) #define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) #define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
#define FDT_CHECK_HEADER(fdt) \ int fdt_ro_probe_(const void *fdt);
{ \ #define FDT_RO_PROBE(fdt) \
int err_; \ { \
if ((err_ = fdt_check_header(fdt)) != 0) \ int totalsize_; \
return err_; \ if (fdt_chk_basic()) { \
totalsize_ = fdt_ro_probe_(fdt); \
if (totalsize_ < 0) \
return totalsize_; \
} \
} }
int fdt_check_node_offset_(const void *fdt, int offset); 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) #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 */ #endif /* LIBFDT_INTERNAL_H */

View file

@ -11,6 +11,7 @@ int fdt_remove_unused_strings(const void *old, void *new)
const char *str; const char *str;
int ret; int ret;
int tag = FDT_PROP; int tag = FDT_PROP;
int allocated;
/* Make a copy and remove the strings */ /* Make a copy and remove the strings */
memcpy(new, old, size); 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) new_prop = (struct fdt_property *)(unsigned long)
fdt_get_property_by_offset(new, offset, NULL); fdt_get_property_by_offset(new, offset, NULL);
str = fdt_string(old, fdt32_to_cpu(old_prop->nameoff)); 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) if (ret < 0)
return ret; return ret;
new_prop->nameoff = cpu_to_fdt32(ret); new_prop->nameoff = cpu_to_fdt32(ret);