* [PATCH 0/3] Synchronize DTC to 1.7.2
@ 2025-11-13 12:21 Marek Vasut
2025-11-13 12:21 ` [PATCH 1/3] dm: core: Check ofnode_to_offset() return value Marek Vasut
` (3 more replies)
0 siblings, 4 replies; 32+ messages in thread
From: Marek Vasut @ 2025-11-13 12:21 UTC (permalink / raw)
To: u-boot
Cc: Marek Vasut, Adriano Cordova, Andrew Goodbody, Christian Marangi,
Heinrich Schuchardt, Ilias Apalodimas, Patrice Chotard,
Sam Edwards, Simon Glass, Tom Rini
Synchronize local copy of DTC with Linux 6.17 , using commits picked
from Linux kernel. This also includes two fix up patches to make the
DM core work with new 8-byte alignment checking in libfdt and another
fix for NULL pointer check that is missing in libfdt.
This depends on the following patches sent separately, which fix
various 8-byte alignment problems in the code base:
- boot: android: Always use 8-byte aligned DT with libfdt
- test/py: android: Point fdt command to aligned addresses
- test/py: Use aligned address for overlays in 'extension' test
- sandbox: Fix DT compiler address warnings in sandbox DTs
- sandbox: Fix DT compiler pin warnings in sandbox DTs
- boot: Assure FDT is always at 8-byte aligned address
- arm: qemu: Eliminate fdt_high and initrd_high misuse
- efi_loader: Assure fitImage from capsule is used from 8-byte aligned address
- MIPS: Assure end of U-Boot is at 8-byte aligned offset
Marek Vasut (3):
dm: core: Check ofnode_to_offset() return value
scripts/dtc: Update to upstream version v1.7.2-35-g52f07dcca47c
libfdt: Check fdt_offset_ptr() return value unconditionally
drivers/core/ofnode.c | 384 +++++++++++----
scripts/Makefile.lib | 4 +-
scripts/dtc/.gitignore | 1 +
scripts/dtc/Makefile | 23 +-
scripts/dtc/Makefile.dtc | 18 -
scripts/dtc/checks.c | 686 +++++++++++++++++++++------
scripts/dtc/data.c | 74 ++-
scripts/dtc/dtc-lexer.l | 38 +-
scripts/dtc/dtc-parser.y | 109 +++--
scripts/dtc/dtc.c | 58 ++-
scripts/dtc/dtc.h | 137 ++++--
scripts/dtc/fdtoverlay.c | 214 +++++++++
scripts/dtc/flattree.c | 70 ++-
scripts/dtc/fstree.c | 26 +-
scripts/dtc/libfdt/fdt.c | 84 ++--
scripts/dtc/libfdt/fdt.h | 4 +-
scripts/dtc/libfdt/fdt_addresses.c | 2 +-
scripts/dtc/libfdt/fdt_overlay.c | 386 +++++++++++----
scripts/dtc/libfdt/fdt_ro.c | 100 ++--
scripts/dtc/libfdt/fdt_rw.c | 101 ++--
scripts/dtc/libfdt/fdt_strerror.c | 1 +
scripts/dtc/libfdt/fdt_sw.c | 26 +-
scripts/dtc/libfdt/libfdt.h | 428 ++++++++++++++---
scripts/dtc/libfdt/libfdt_internal.h | 141 ++++--
scripts/dtc/livetree.c | 156 +++---
scripts/dtc/srcpos.c | 190 ++++++--
scripts/dtc/srcpos.h | 31 +-
scripts/dtc/treesource.c | 319 ++++++++-----
scripts/dtc/update-dtc-source.sh | 7 +-
scripts/dtc/util.c | 122 ++---
scripts/dtc/util.h | 61 +--
scripts/dtc/version_gen.h | 2 +-
scripts/dtc/yamltree.c | 235 +++++++++
tools/libfdt/fdt_rw.c | 2 +-
34 files changed, 3128 insertions(+), 1112 deletions(-)
delete mode 100644 scripts/dtc/Makefile.dtc
create mode 100644 scripts/dtc/fdtoverlay.c
create mode 100644 scripts/dtc/yamltree.c
---
Cc: Adriano Cordova <adrianox@gmail.com>
Cc: Andrew Goodbody <andrew.goodbody@linaro.org>
Cc: Christian Marangi <ansuelsmth@gmail.com>
Cc: Heinrich Schuchardt <xypron.glpk@gmx.de>
Cc: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Cc: Patrice Chotard <patrice.chotard@foss.st.com>
Cc: Sam Edwards <cfsworks@gmail.com>
Cc: Simon Glass <sjg@chromium.org>
Cc: Tom Rini <trini@konsulko.com>
Cc: u-boot@lists.denx.de
--
2.51.0
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH 1/3] dm: core: Check ofnode_to_offset() return value
2025-11-13 12:21 [PATCH 0/3] Synchronize DTC to 1.7.2 Marek Vasut
@ 2025-11-13 12:21 ` Marek Vasut
2025-11-13 19:33 ` Simon Glass
2025-11-13 12:21 ` [PATCH 2/3] scripts/dtc: Update to upstream version v1.7.2-35-g52f07dcca47c Marek Vasut
` (2 subsequent siblings)
3 siblings, 1 reply; 32+ messages in thread
From: Marek Vasut @ 2025-11-13 12:21 UTC (permalink / raw)
To: u-boot
Cc: Marek Vasut, Adriano Cordova, Andrew Goodbody, Christian Marangi,
Heinrich Schuchardt, Ilias Apalodimas, Patrice Chotard,
Sam Edwards, Simon Glass, Tom Rini
The ofnode_to_offset() may return -1 , which is not a valid value
and is not accepted by modern libfdt 1.7.2. Check the return value
from ofnode_to_offset() and exit early in case it is not a valid
offset.
Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
---
Cc: Adriano Cordova <adrianox@gmail.com>
Cc: Andrew Goodbody <andrew.goodbody@linaro.org>
Cc: Christian Marangi <ansuelsmth@gmail.com>
Cc: Heinrich Schuchardt <xypron.glpk@gmx.de>
Cc: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Cc: Patrice Chotard <patrice.chotard@foss.st.com>
Cc: Sam Edwards <cfsworks@gmail.com>
Cc: Simon Glass <sjg@chromium.org>
Cc: Tom Rini <trini@konsulko.com>
Cc: u-boot@lists.denx.de
---
drivers/core/ofnode.c | 384 +++++++++++++++++++++++++++++++-----------
1 file changed, 284 insertions(+), 100 deletions(-)
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index 071d998a0a5..55c2b3a10bb 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -335,7 +335,7 @@ bool ofnode_name_eq_unit(ofnode node, const char *name)
int ofnode_read_u8(ofnode node, const char *propname, u8 *outp)
{
const u8 *cell;
- int len;
+ int len, off;
assert(ofnode_valid(node));
log_debug("%s: %s: ", __func__, propname);
@@ -343,8 +343,13 @@ int ofnode_read_u8(ofnode node, const char *propname, u8 *outp)
if (ofnode_is_np(node))
return of_read_u8(ofnode_to_np(node), propname, outp);
- cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
- &len);
+ off = ofnode_to_offset(node);
+ if (off < 0) {
+ log_debug("(not valid)\n");
+ return -EINVAL;
+ }
+
+ cell = fdt_getprop(gd->fdt_blob, off, propname, &len);
if (!cell || len < sizeof(*cell)) {
log_debug("(not found)\n");
return -EINVAL;
@@ -366,7 +371,7 @@ u8 ofnode_read_u8_default(ofnode node, const char *propname, u8 def)
int ofnode_read_u16(ofnode node, const char *propname, u16 *outp)
{
const fdt16_t *cell;
- int len;
+ int len, off;
assert(ofnode_valid(node));
log_debug("%s: %s: ", __func__, propname);
@@ -374,8 +379,13 @@ int ofnode_read_u16(ofnode node, const char *propname, u16 *outp)
if (ofnode_is_np(node))
return of_read_u16(ofnode_to_np(node), propname, outp);
- cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
- &len);
+ off = ofnode_to_offset(node);
+ if (off < 0) {
+ log_debug("(not valid)\n");
+ return -EINVAL;
+ }
+
+ cell = fdt_getprop(gd->fdt_blob, off, propname, &len);
if (!cell || len < sizeof(*cell)) {
log_debug("(not found)\n");
return -EINVAL;
@@ -411,7 +421,7 @@ int ofnode_read_u32_index(ofnode node, const char *propname, int index,
u32 *outp)
{
const fdt32_t *cell;
- int len;
+ int len, off;
assert(ofnode_valid(node));
log_debug("%s: %s: ", __func__, propname);
@@ -420,8 +430,13 @@ int ofnode_read_u32_index(ofnode node, const char *propname, int index,
return of_read_u32_index(ofnode_to_np(node), propname, index,
outp);
- cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
- propname, &len);
+ off = ofnode_to_offset(node);
+ if (off < 0) {
+ log_debug("(not valid)\n");
+ return -EINVAL;
+ }
+
+ cell = fdt_getprop(ofnode_to_fdt(node), off, propname, &len);
if (!cell) {
log_debug("(not found)\n");
return -EINVAL;
@@ -442,7 +457,7 @@ int ofnode_read_u64_index(ofnode node, const char *propname, int index,
u64 *outp)
{
const fdt64_t *cell;
- int len;
+ int len, off;
assert(ofnode_valid(node));
@@ -450,8 +465,13 @@ int ofnode_read_u64_index(ofnode node, const char *propname, int index,
return of_read_u64_index(ofnode_to_np(node), propname, index,
outp);
- cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
- propname, &len);
+ off = ofnode_to_offset(node);
+ if (off < 0) {
+ log_debug("(not valid)\n");
+ return -EINVAL;
+ }
+
+ cell = fdt_getprop(ofnode_to_fdt(node), off, propname, &len);
if (!cell) {
log_debug("(not found)\n");
return -EINVAL;
@@ -488,7 +508,7 @@ int ofnode_read_s32_default(ofnode node, const char *propname, s32 def)
int ofnode_read_u64(ofnode node, const char *propname, u64 *outp)
{
const unaligned_fdt64_t *cell;
- int len;
+ int len, off;
assert(ofnode_valid(node));
log_debug("%s: %s: ", __func__, propname);
@@ -496,8 +516,13 @@ int ofnode_read_u64(ofnode node, const char *propname, u64 *outp)
if (ofnode_is_np(node))
return of_read_u64(ofnode_to_np(node), propname, outp);
- cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
- propname, &len);
+ off = ofnode_to_offset(node);
+ if (off < 0) {
+ log_debug("(not valid)\n");
+ return -EINVAL;
+ }
+
+ cell = fdt_getprop(ofnode_to_fdt(node), off, propname, &len);
if (!cell || len < sizeof(*cell)) {
log_debug("(not found)\n");
return -EINVAL;
@@ -534,7 +559,7 @@ bool ofnode_read_bool(ofnode node, const char *propname)
const void *ofnode_read_prop(ofnode node, const char *propname, int *sizep)
{
const char *val = NULL;
- int len;
+ int len, off;
assert(ofnode_valid(node));
log_debug("%s: %s: ", __func__, propname);
@@ -548,8 +573,13 @@ const void *ofnode_read_prop(ofnode node, const char *propname, int *sizep)
len = prop->length;
}
} else {
- val = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
- propname, &len);
+ off = ofnode_to_offset(node);
+ if (off < 0) {
+ log_debug("<not valid>\n");
+ return NULL;
+ }
+
+ val = fdt_getprop(ofnode_to_fdt(node), off, propname, &len);
}
if (!val) {
log_debug("<not found>\n");
@@ -602,8 +632,13 @@ ofnode ofnode_find_subnode(ofnode node, const char *subnode_name)
subnode = ofnode_find_subnode_unit(node, subnode_name);
} else {
/* special case to avoid code-size increase */
- int ooffset = fdt_subnode_offset(ofnode_to_fdt(node),
- ofnode_to_offset(node), subnode_name);
+ int ooffset, off;
+
+ off = ofnode_to_offset(node);
+ if (off < 0)
+ return ofnode_null();
+
+ ooffset = fdt_subnode_offset(ofnode_to_fdt(node), off, subnode_name);
subnode = noffset_to_ofnode(node, ooffset);
}
log_debug("%s\n", ofnode_valid(subnode) ?
@@ -642,11 +677,14 @@ int ofnode_read_u32_array(ofnode node, const char *propname,
return of_read_u32_array(ofnode_to_np(node), propname,
out_values, sz);
} else {
- int ret;
+ int ret, off;
+
+ off = ofnode_to_offset(node);
+ if (off < 0)
+ return -EINVAL;
- ret = fdtdec_get_int_array(ofnode_to_fdt(node),
- ofnode_to_offset(node), propname,
- out_values, sz);
+ ret = fdtdec_get_int_array(ofnode_to_fdt(node), off,
+ propname, out_values, sz);
/* get the error right, but space is more important in SPL */
if (!IS_ENABLED(CONFIG_XPL_BUILD)) {
@@ -665,48 +703,71 @@ bool ofnode_is_enabled(ofnode node)
if (ofnode_is_np(node)) {
return of_device_is_available(ofnode_to_np(node));
} else {
- return fdtdec_get_is_enabled(ofnode_to_fdt(node),
- ofnode_to_offset(node));
+ int off = ofnode_to_offset(node);
+
+ if (off < 0)
+ return false;
+
+ return fdtdec_get_is_enabled(ofnode_to_fdt(node), off);
}
}
ofnode ofnode_first_subnode(ofnode node)
{
+ int off;
+
assert(ofnode_valid(node));
if (ofnode_is_np(node))
return np_to_ofnode(node.np->child);
+ off = ofnode_to_offset(node);
+ if (off < 0)
+ return ofnode_null();
+
return noffset_to_ofnode(node,
- fdt_first_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
+ fdt_first_subnode(ofnode_to_fdt(node), off));
}
ofnode ofnode_next_subnode(ofnode node)
{
+ int off;
+
assert(ofnode_valid(node));
if (ofnode_is_np(node))
return np_to_ofnode(node.np->sibling);
+ off = ofnode_to_offset(node);
+ if (off < 0)
+ return ofnode_null();
+
return noffset_to_ofnode(node,
- fdt_next_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
+ fdt_next_subnode(ofnode_to_fdt(node), off));
}
#endif /* !DM_INLINE_OFNODE */
ofnode ofnode_get_parent(ofnode node)
{
ofnode parent;
+ int off;
assert(ofnode_valid(node));
- if (ofnode_is_np(node))
+ if (ofnode_is_np(node)) {
parent = np_to_ofnode(of_get_parent(ofnode_to_np(node)));
- else
- parent.of_offset = fdt_parent_offset(ofnode_to_fdt(node),
- ofnode_to_offset(node));
+ } else {
+ off = ofnode_to_offset(node);
+ if (off < 0)
+ return ofnode_null();
+
+ parent.of_offset = fdt_parent_offset(ofnode_to_fdt(node), off);
+ }
return parent;
}
const char *ofnode_get_name(ofnode node)
{
+ int off;
+
if (!ofnode_valid(node)) {
dm_warn("%s node not valid\n", __func__);
return NULL;
@@ -715,7 +776,11 @@ const char *ofnode_get_name(ofnode node)
if (ofnode_is_np(node))
return node.np->name;
- return fdt_get_name(ofnode_to_fdt(node), ofnode_to_offset(node), NULL);
+ off = ofnode_to_offset(node);
+ if (off < 0)
+ return NULL;
+
+ return fdt_get_name(ofnode_to_fdt(node), off, NULL);
}
int ofnode_get_path(ofnode node, char *buf, int buflen)
@@ -730,10 +795,13 @@ int ofnode_get_path(ofnode node, char *buf, int buflen)
return 0;
} else {
- int res;
+ int off, res;
- res = fdt_get_path(ofnode_to_fdt(node), ofnode_to_offset(node), buf,
- buflen);
+ off = ofnode_to_offset(node);
+ if (off < 0)
+ return -EINVAL;
+
+ res = fdt_get_path(ofnode_to_fdt(node), off, buf, buflen);
if (!res)
return res;
else if (res == -FDT_ERR_NOSPACE)
@@ -773,7 +841,7 @@ ofnode oftree_get_by_phandle(oftree tree, uint phandle)
static fdt_addr_t __ofnode_get_addr_size_index(ofnode node, int index,
fdt_size_t *size, bool translate)
{
- int na, ns;
+ int na, ns, off;
if (size)
*size = FDT_SIZE_T_NONE;
@@ -803,8 +871,13 @@ static fdt_addr_t __ofnode_get_addr_size_index(ofnode node, int index,
ofnode parent = ofnode_get_parent(node);
na = ofnode_read_simple_addr_cells(parent);
ns = ofnode_read_simple_size_cells(parent);
+
+ off = ofnode_to_offset(node);
+ if (off < 0)
+ return FDT_ADDR_T_NONE;
+
return fdtdec_get_addr_size_fixed(ofnode_to_fdt(node),
- ofnode_to_offset(node), "reg",
+ off, "reg",
index, na, ns, size,
translate);
}
@@ -849,10 +922,14 @@ int ofnode_stringlist_search(ofnode node, const char *property,
return of_property_match_string(ofnode_to_np(node),
property, string);
} else {
- int ret;
+ int ret, off;
+
+ off = ofnode_to_offset(node);
+ if (off < 0)
+ return -EINVAL;
ret = fdt_stringlist_search(ofnode_to_fdt(node),
- ofnode_to_offset(node), property,
+ off, property,
string);
if (ret == -FDT_ERR_NOTFOUND)
return -ENODATA;
@@ -870,10 +947,13 @@ int ofnode_read_string_index(ofnode node, const char *property, int index,
return of_property_read_string_index(ofnode_to_np(node),
property, index, outp);
} else {
- int len;
+ int len, off;
+
+ off = ofnode_to_offset(node);
+ if (off < 0)
+ return -EINVAL;
- *outp = fdt_stringlist_get(ofnode_to_fdt(node),
- ofnode_to_offset(node),
+ *outp = fdt_stringlist_get(ofnode_to_fdt(node), off,
property, index, &len);
if (len < 0)
return -EINVAL;
@@ -883,11 +963,17 @@ int ofnode_read_string_index(ofnode node, const char *property, int index,
int ofnode_read_string_count(ofnode node, const char *property)
{
+ int off;
+
if (ofnode_is_np(node)) {
return of_property_count_strings(ofnode_to_np(node), property);
} else {
+ off = ofnode_to_offset(node);
+ if (off < 0)
+ return -EINVAL;
+
return fdt_stringlist_count(ofnode_to_fdt(node),
- ofnode_to_offset(node), property);
+ off, property);
}
}
@@ -933,10 +1019,13 @@ ofnode ofnode_parse_phandle(ofnode node, const char *phandle_name,
phandle = np_to_ofnode(np);
} else {
struct fdtdec_phandle_args args;
+ int off = ofnode_to_offset(node);
+
+ if (off < 0)
+ return ofnode_null();
if (fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
- ofnode_to_offset(node),
- phandle_name, NULL,
+ off, phandle_name, NULL,
0, index, &args))
return ofnode_null();
@@ -962,10 +1051,13 @@ ofnode oftree_parse_phandle(oftree tree, ofnode node, const char *phandle_name,
phandle = np_to_ofnode(np);
} else {
struct fdtdec_phandle_args args;
+ int off = ofnode_to_offset(node);
+
+ if (off < 0)
+ return ofnode_null();
if (fdtdec_parse_phandle_with_args(tree.fdt,
- ofnode_to_offset(node),
- phandle_name, NULL,
+ off, phandle_name, NULL,
0, index, &args))
return ofnode_null();
@@ -1011,11 +1103,14 @@ int ofnode_parse_phandle_with_args(ofnode node, const char *list_name,
ofnode_from_of_phandle_args(&args, out_args);
} else {
struct fdtdec_phandle_args args;
+ int off = ofnode_to_offset(node);
int ret;
+ if (off < 0)
+ return -EINVAL;
+
ret = fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
- ofnode_to_offset(node),
- list_name, cells_name,
+ off, list_name, cells_name,
cell_count, index, &args);
if (ret)
return ret;
@@ -1044,11 +1139,14 @@ int oftree_parse_phandle_with_args(oftree tree, ofnode node, const char *list_na
ofnode_from_of_phandle_args(&args, out_args);
} else {
struct fdtdec_phandle_args args;
+ int off = ofnode_to_offset(node);
int ret;
+ if (off < 0)
+ return -EINVAL;
+
ret = fdtdec_parse_phandle_with_args(tree.fdt,
- ofnode_to_offset(node),
- list_name, cells_name,
+ off, list_name, cells_name,
cell_count, index, &args);
if (ret)
return ret;
@@ -1061,25 +1159,37 @@ int oftree_parse_phandle_with_args(oftree tree, ofnode node, const char *list_na
int ofnode_count_phandle_with_args(ofnode node, const char *list_name,
const char *cells_name, int cell_count)
{
- if (ofnode_is_np(node))
+ if (ofnode_is_np(node)) {
return of_count_phandle_with_args(ofnode_to_np(node),
list_name, cells_name, cell_count);
- else
+ } else {
+ int off = ofnode_to_offset(node);
+
+ if (off < 0)
+ return -EINVAL;
+
return fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
- ofnode_to_offset(node), list_name, cells_name,
+ off, list_name, cells_name,
cell_count, -1, NULL);
+ }
}
int oftree_count_phandle_with_args(oftree tree, ofnode node, const char *list_name,
const char *cells_name, int cell_count)
{
- if (ofnode_is_np(node))
+ if (ofnode_is_np(node)) {
return of_root_count_phandle_with_args(tree.np, ofnode_to_np(node),
list_name, cells_name, cell_count);
- else
+ } else {
+ int off = ofnode_to_offset(node);
+
+ if (off < 0)
+ return -EINVAL;
+
return fdtdec_parse_phandle_with_args(tree.fdt,
- ofnode_to_offset(node), list_name, cells_name,
+ off, list_name, cells_name,
cell_count, -1, NULL);
+ }
}
ofnode ofnode_path(const char *path)
@@ -1326,11 +1436,16 @@ int ofnode_decode_panel_timing(ofnode parent,
const void *ofnode_get_property(ofnode node, const char *propname, int *lenp)
{
- if (ofnode_is_np(node))
+ if (ofnode_is_np(node)) {
return of_get_property(ofnode_to_np(node), propname, lenp);
- else
- return fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
- propname, lenp);
+ } else {
+ int off = ofnode_to_offset(node);
+
+ if (off < 0)
+ return NULL;
+
+ return fdt_getprop(ofnode_to_fdt(node), off, propname, lenp);
+ }
}
bool ofnode_has_property(ofnode node, const char *propname)
@@ -1350,9 +1465,13 @@ int ofnode_first_property(ofnode node, struct ofprop *prop)
if (!prop->prop)
return -FDT_ERR_NOTFOUND;
} else {
+ int off = ofnode_to_offset(prop->node);
+
+ if (off < 0)
+ return -EINVAL;
+
prop->offset =
- fdt_first_property_offset(ofnode_to_fdt(node),
- ofnode_to_offset(prop->node));
+ fdt_first_property_offset(ofnode_to_fdt(node), off);
if (prop->offset < 0)
return prop->offset;
}
@@ -1410,9 +1529,13 @@ fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
else
return of_read_number(prop, na);
} else {
+ int off = ofnode_to_offset(node);
+
+ if (off < 0)
+ return FDT_ADDR_T_NONE;
+
return fdtdec_get_addr_size(ofnode_to_fdt(node),
- ofnode_to_offset(node), property,
- sizep);
+ off, property, sizep);
}
}
@@ -1429,8 +1552,13 @@ const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname,
return (uint8_t *)prop;
} else {
+ int off = ofnode_to_offset(node);
+
+ if (off < 0)
+ return NULL;
+
return fdtdec_locate_byte_array(ofnode_to_fdt(node),
- ofnode_to_offset(node), propname, sz);
+ off, propname, sz);
}
}
@@ -1570,8 +1698,12 @@ int ofnode_read_addr_cells(ofnode node)
if (ofnode_is_np(node)) {
return of_n_addr_cells(ofnode_to_np(node));
} else {
- int parent = fdt_parent_offset(ofnode_to_fdt(node),
- ofnode_to_offset(node));
+ int parent, off = ofnode_to_offset(node);
+
+ if (off < 0)
+ return -EINVAL;
+
+ parent = fdt_parent_offset(ofnode_to_fdt(node), off);
return fdt_address_cells(ofnode_to_fdt(node), parent);
}
@@ -1582,8 +1714,12 @@ int ofnode_read_size_cells(ofnode node)
if (ofnode_is_np(node)) {
return of_n_size_cells(ofnode_to_np(node));
} else {
- int parent = fdt_parent_offset(ofnode_to_fdt(node),
- ofnode_to_offset(node));
+ int parent, off = ofnode_to_offset(node);
+
+ if (off < 0)
+ return -EINVAL;
+
+ parent = fdt_parent_offset(ofnode_to_fdt(node), off);
return fdt_size_cells(ofnode_to_fdt(node), parent);
}
@@ -1591,20 +1727,30 @@ int ofnode_read_size_cells(ofnode node)
int ofnode_read_simple_addr_cells(ofnode node)
{
- if (ofnode_is_np(node))
+ if (ofnode_is_np(node)) {
return of_simple_addr_cells(ofnode_to_np(node));
- else
- return fdt_address_cells(ofnode_to_fdt(node),
- ofnode_to_offset(node));
+ } else {
+ int off = ofnode_to_offset(node);
+
+ if (off < 0)
+ return -EINVAL;
+
+ return fdt_address_cells(ofnode_to_fdt(node), off);
+ }
}
int ofnode_read_simple_size_cells(ofnode node)
{
- if (ofnode_is_np(node))
+ if (ofnode_is_np(node)) {
return of_simple_size_cells(ofnode_to_np(node));
- else
- return fdt_size_cells(ofnode_to_fdt(node),
- ofnode_to_offset(node));
+ } else {
+ int off = ofnode_to_offset(node);
+
+ if (off < 0)
+ return -EINVAL;
+
+ return fdt_size_cells(ofnode_to_fdt(node), off);
+ }
}
bool ofnode_pre_reloc(ofnode node)
@@ -1639,10 +1785,13 @@ int ofnode_read_resource(ofnode node, uint index, struct resource *res)
return of_address_to_resource(ofnode_to_np(node), index, res);
} else {
struct fdt_resource fres;
+ int off = ofnode_to_offset(node);
int ret;
- ret = fdt_get_resource(ofnode_to_fdt(node),
- ofnode_to_offset(node),
+ if (off < 0)
+ return -EINVAL;
+
+ ret = fdt_get_resource(ofnode_to_fdt(node), off,
"reg", index, &fres);
if (ret < 0)
return -EINVAL;
@@ -1668,41 +1817,61 @@ int ofnode_read_resource_byname(ofnode node, const char *name,
u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr)
{
- if (ofnode_is_np(node))
+ if (ofnode_is_np(node)) {
return of_translate_address(ofnode_to_np(node), in_addr);
- else
- return fdt_translate_address(ofnode_to_fdt(node),
- ofnode_to_offset(node), in_addr);
+ } else {
+ int off = ofnode_to_offset(node);
+
+ if (off < 0)
+ return OF_BAD_ADDR;
+
+ return fdt_translate_address(ofnode_to_fdt(node), off, in_addr);
+ }
}
u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
{
- if (ofnode_is_np(node))
+ if (ofnode_is_np(node)) {
return of_translate_dma_address(ofnode_to_np(node), in_addr);
- else
- return fdt_translate_dma_address(ofnode_to_fdt(node),
- ofnode_to_offset(node), in_addr);
+ } else {
+ int off = ofnode_to_offset(node);
+
+ if (off < 0)
+ return OF_BAD_ADDR;
+
+ return fdt_translate_dma_address(ofnode_to_fdt(node), off, in_addr);
+ }
}
int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus, u64 *size)
{
- if (ofnode_is_np(node))
+ if (ofnode_is_np(node)) {
return of_get_dma_range(ofnode_to_np(node), cpu, bus, size);
- else
- return fdt_get_dma_range(ofnode_to_fdt(node),
- ofnode_to_offset(node),
+ } else {
+ int off = ofnode_to_offset(node);
+
+ if (off < 0)
+ return -EINVAL;
+
+ return fdt_get_dma_range(ofnode_to_fdt(node), off,
cpu, bus, size);
+ }
}
int ofnode_device_is_compatible(ofnode node, const char *compat)
{
- if (ofnode_is_np(node))
+ if (ofnode_is_np(node)) {
return of_device_is_compatible(ofnode_to_np(node), compat,
NULL, NULL);
- else
- return !fdt_node_check_compatible(ofnode_to_fdt(node),
- ofnode_to_offset(node),
+ } else {
+ int off = ofnode_to_offset(node);
+
+ if (off < 0)
+ return 0;
+
+ return !fdt_node_check_compatible(ofnode_to_fdt(node), off,
compat);
+ }
}
ofnode ofnode_by_compatible(ofnode from, const char *compat)
@@ -1753,7 +1922,12 @@ int ofnode_write_prop(ofnode node, const char *propname, const void *value,
free(newval);
return ret;
} else {
- ret = fdt_setprop(ofnode_to_fdt(node), ofnode_to_offset(node),
+ int off = ofnode_to_offset(node);
+
+ if (off < 0)
+ return -EINVAL;
+
+ ret = fdt_setprop(ofnode_to_fdt(node), off,
propname, value, len);
if (ret)
return ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EINVAL;
@@ -1821,8 +1995,12 @@ int ofnode_delete_prop(ofnode node, const char *propname)
return of_remove_property(ofnode_to_np(node), prop);
return 0;
} else {
- return fdt_delprop(ofnode_to_fdt(node), ofnode_to_offset(node),
- propname);
+ int off = ofnode_to_offset(node);
+
+ if (off < 0)
+ return -EINVAL;
+
+ return fdt_delprop(ofnode_to_fdt(node), off, propname);
}
}
@@ -2040,6 +2218,9 @@ int ofnode_add_subnode(ofnode node, const char *name, ofnode *subnodep)
int poffset = ofnode_to_offset(node);
int offset;
+ if (poffset < 0)
+ return -FDT_ERR_NOTFOUND;
+
offset = fdt_add_subnode(fdt, poffset, name);
if (offset == -FDT_ERR_EXISTS) {
offset = fdt_subnode_offset(fdt, poffset, name);
@@ -2067,6 +2248,9 @@ int ofnode_delete(ofnode *nodep)
void *fdt = ofnode_to_fdt(node);
int offset = ofnode_to_offset(node);
+ if (offset < 0)
+ return -EINVAL;
+
ret = fdt_del_node(fdt, offset);
if (ret)
ret = -EFAULT;
--
2.51.0
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH 2/3] scripts/dtc: Update to upstream version v1.7.2-35-g52f07dcca47c
2025-11-13 12:21 [PATCH 0/3] Synchronize DTC to 1.7.2 Marek Vasut
2025-11-13 12:21 ` [PATCH 1/3] dm: core: Check ofnode_to_offset() return value Marek Vasut
@ 2025-11-13 12:21 ` Marek Vasut
2025-11-13 12:21 ` [PATCH 3/3] libfdt: Check fdt_offset_ptr() return value unconditionally Marek Vasut
2025-11-13 17:57 ` [PATCH 0/3] Synchronize DTC to 1.7.2 Tom Rini
3 siblings, 0 replies; 32+ messages in thread
From: Marek Vasut @ 2025-11-13 12:21 UTC (permalink / raw)
To: u-boot
Cc: Marek Vasut, Adriano Cordova, Andrew Goodbody, Christian Marangi,
Heinrich Schuchardt, Ilias Apalodimas, Patrice Chotard,
Sam Edwards, Simon Glass, Tom Rini
Synchronize local copy of DTC with Linux 6.17 . This includes the
following picked and squashed commits from Linux kernel. The squash
was necessary, since the DTC here contains changes which were also
part of DTC in Linux alraedy, and the squash helped resolve those
without going back and forth with the changes.
The following commits from Linux are picked:
8f324cd712df7 # scripts/dtc: consolidate include path options in Makefile
b5b3d9b63b0ee # scripts/dtc: Add yamltree.c to dtc sources
7d97a76f226d6 # scripts/dtc: Update to upstream version v1.4.7-14-gc86da84d30e4
ea6f243be74e5 # scripts/dtc: Update to upstream version v1.4.7-57-gf267e674d145
02d435d4eccd8 # scripts/dtc: Update to upstream version v1.5.0-23-g87963ee20693
6e321b7637396 # scripts/dtc: Update to upstream version v1.5.0-30-g702c1b6c0e73
9f19ec91a7a35 # scripts/dtc: dtx_diff - add color output support
8287d642f38d1 # scripts/dtc: Update to upstream version v1.5.1-22-gc40aeb60b47a
4c52deef9225d # scripts/dtc: Revert "yamltree: Ensure consistent bracketing of properties with phandles"
5d3827e1452ed # scripts/dtc: Remove unused makefile fragments
40dd266887654 # scripts/dtc: Update to upstream version v1.6.0-2-g87a656ae5ff9
8d4cf6b6acb59 # scripts/dtc: use pkg-config to include <yaml.h> in non-standard path
b9bf9ace5ae90 # scripts/dtc: Update to upstream version v1.6.0-11-g9d7888cbf19c
69a883b6f5ac0 # scripts/dtc: dtx_diff - make help text formatting consistent
8f829108b8aed # scripts/dtc: only append to HOST_EXTRACFLAGS instead of overwriting
b39b4342ac495 # scripts/dtc: Update to upstream version v1.6.0-31-gcbca977ea121
93c6424c486b3 # scripts: dtc: Fetch fdtoverlay.c from external DTC project
0dd574a1d75c3 # scripts/dtc: Update to upstream version v1.6.0-51-g183df9e9c2b9
ec38b5df8a231 # scripts: dtc: Build fdtoverlay tool
a0c8c431411f5 # scripts: dtc: Remove the unused fdtdump.c file
e7dc653d4e890 # scripts/dtc: Add missing fdtoverlay to gitignore
d2bf5d2e3f09c # scripts/dtc: Update to upstream version v1.6.1-19-g0a3a9d3449c8
a60878f5532d0 # scripts/dtc: dtx_diff: remove broken example from help text
8b739d8658a9b # scripts/dtc: Call pkg-config POSIXly correct
b6eeafa67df00 # scripts/dtc: Update to upstream version v1.6.1-63-g55778a03df61
f96cc4c787588 # scripts/dtc: Update to upstream version v1.6.1-66-gabbd523bae6e
09ab9c092ef2b # scripts/dtc: Update to upstream version v1.7.0-93-g1df7b047fe43
ded8a5a498f2d # scripts/dtc: Update to upstream version v1.7.0-95-gbcd02b523429
ee6ff6fca7e71 # scripts/dtc: Update to upstream version v1.7.2-35-g52f07dcca47c
Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
---
Cc: Adriano Cordova <adrianox@gmail.com>
Cc: Andrew Goodbody <andrew.goodbody@linaro.org>
Cc: Christian Marangi <ansuelsmth@gmail.com>
Cc: Heinrich Schuchardt <xypron.glpk@gmx.de>
Cc: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Cc: Patrice Chotard <patrice.chotard@foss.st.com>
Cc: Sam Edwards <cfsworks@gmail.com>
Cc: Simon Glass <sjg@chromium.org>
Cc: Tom Rini <trini@konsulko.com>
Cc: u-boot@lists.denx.de
---
scripts/Makefile.lib | 4 +-
scripts/dtc/.gitignore | 1 +
scripts/dtc/Makefile | 23 +-
scripts/dtc/Makefile.dtc | 18 -
scripts/dtc/checks.c | 686 +++++++++++++++++++++------
scripts/dtc/data.c | 74 ++-
scripts/dtc/dtc-lexer.l | 38 +-
scripts/dtc/dtc-parser.y | 109 +++--
scripts/dtc/dtc.c | 58 ++-
scripts/dtc/dtc.h | 137 ++++--
scripts/dtc/fdtoverlay.c | 214 +++++++++
scripts/dtc/flattree.c | 70 ++-
scripts/dtc/fstree.c | 26 +-
scripts/dtc/libfdt/fdt.c | 84 ++--
scripts/dtc/libfdt/fdt.h | 4 +-
scripts/dtc/libfdt/fdt_addresses.c | 2 +-
scripts/dtc/libfdt/fdt_overlay.c | 386 +++++++++++----
scripts/dtc/libfdt/fdt_ro.c | 100 ++--
scripts/dtc/libfdt/fdt_rw.c | 101 ++--
scripts/dtc/libfdt/fdt_strerror.c | 1 +
scripts/dtc/libfdt/fdt_sw.c | 26 +-
scripts/dtc/libfdt/libfdt.h | 428 ++++++++++++++---
scripts/dtc/libfdt/libfdt_internal.h | 141 ++++--
scripts/dtc/livetree.c | 156 +++---
scripts/dtc/srcpos.c | 190 ++++++--
scripts/dtc/srcpos.h | 31 +-
scripts/dtc/treesource.c | 319 ++++++++-----
scripts/dtc/update-dtc-source.sh | 7 +-
scripts/dtc/util.c | 122 ++---
scripts/dtc/util.h | 61 +--
scripts/dtc/version_gen.h | 2 +-
scripts/dtc/yamltree.c | 235 +++++++++
tools/libfdt/fdt_rw.c | 2 +-
33 files changed, 2844 insertions(+), 1012 deletions(-)
delete mode 100644 scripts/dtc/Makefile.dtc
create mode 100644 scripts/dtc/fdtoverlay.c
create mode 100644 scripts/dtc/yamltree.c
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 791eb1cb327..b062db7e87f 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -319,6 +319,7 @@ quiet_cmd_gzip = GZIP $@
# DTC
# ---------------------------------------------------------------------------
DTC ?= $(objtree)/scripts/dtc/dtc
+DTC_FLAGS += -Wno-interrupt_provider
# Disable noisy checks by default
ifeq ($(findstring 1,$(KBUILD_ENABLE_EXTRA_GCC_CHECKS)),)
@@ -338,7 +339,8 @@ endif
ifneq ($(findstring 2,$(KBUILD_ENABLE_EXTRA_GCC_CHECKS)),)
DTC_FLAGS += -Wnode_name_chars_strict \
- -Wproperty_name_chars_strict
+ -Wproperty_name_chars_strict \
+ -Winterrupt_provider
endif
DTC_FLAGS += $(DTC_FLAGS_$(basetarget))
diff --git a/scripts/dtc/.gitignore b/scripts/dtc/.gitignore
index 689b9be0f93..60984f72e27 100644
--- a/scripts/dtc/.gitignore
+++ b/scripts/dtc/.gitignore
@@ -1 +1,2 @@
/dtc
+/fdtoverlay
diff --git a/scripts/dtc/Makefile b/scripts/dtc/Makefile
index faa72d95e28..73081b17d18 100644
--- a/scripts/dtc/Makefile
+++ b/scripts/dtc/Makefile
@@ -1,15 +1,32 @@
# SPDX-License-Identifier: GPL-2.0
# scripts/dtc makefile
-hostprogs-y := dtc
-always := $(hostprogs-y)
+# *** Also keep .gitignore in sync when changing ***
+hostprogs-y += dtc fdtoverlay
+always += dtc
dtc-objs := dtc.o flattree.o fstree.o data.o livetree.o treesource.o \
srcpos.o checks.o util.o
dtc-objs += dtc-lexer.lex.o dtc-parser.tab.o
+# The upstream project builds libfdt as a separate library. We are choosing to
+# instead directly link the libfdt object files into fdtoverlay.
+libfdt-objs := fdt.o fdt_ro.o fdt_wip.o fdt_sw.o fdt_rw.o fdt_strerror.o fdt_empty_tree.o fdt_addresses.o fdt_overlay.o
+libfdt = $(addprefix libfdt/,$(libfdt-objs))
+fdtoverlay-objs := $(libfdt) fdtoverlay.o util.o
+
# Source files need to get at the userspace version of libfdt_env.h to compile
-HOST_EXTRACFLAGS := -I$(src)/libfdt
+HOST_EXTRACFLAGS += -I$(src)/libfdt
+
+ifeq ($(wildcard /usr/include/yaml.h),)
+HOST_EXTRACFLAGS += -DNO_YAML
+else
+dtc-objs += yamltree.o
+# To include <yaml.h> installed in a non-default path
+HOSTCFLAGS_yamltree.o := $(shell pkg-config --cflags yaml-0.1)
+# To link libyaml installed in a non-default path
+HOSTLDLIBS_dtc := $(shell pkg-config --libs yaml-0.1)
+endif
# Generated files need one more search path to include headers in source tree
HOSTCFLAGS_dtc-lexer.lex.o := -I$(src)
diff --git a/scripts/dtc/Makefile.dtc b/scripts/dtc/Makefile.dtc
deleted file mode 100644
index bece49b3553..00000000000
--- a/scripts/dtc/Makefile.dtc
+++ /dev/null
@@ -1,18 +0,0 @@
-# Makefile.dtc
-#
-# This is not a complete Makefile of itself. Instead, it is designed to
-# be easily embeddable into other systems of Makefiles.
-#
-DTC_SRCS = \
- checks.c \
- data.c \
- dtc.c \
- flattree.c \
- fstree.c \
- livetree.c \
- srcpos.c \
- treesource.c \
- util.c
-
-DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c
-DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o)
diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c
index 2feec44a0f7..d10c49eeb2a 100644
--- a/scripts/dtc/checks.c
+++ b/scripts/dtc/checks.c
@@ -1,24 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2007.
- *
- *
- * This program 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 program 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 program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
#include "dtc.h"
+#include "srcpos.h"
#ifdef TRACE_CHECKS
#define TRACE(c, ...) \
@@ -45,7 +31,7 @@ typedef void (*check_fn)(struct check *c, struct dt_info *dti, struct node *node
struct check {
const char *name;
check_fn fn;
- void *data;
+ const void *data;
bool warn, error;
enum checkstatus status;
bool inprogress;
@@ -78,23 +64,57 @@ static inline void PRINTF(5, 6) check_msg(struct check *c, struct dt_info *dti,
const char *fmt, ...)
{
va_list ap;
- va_start(ap, fmt);
+ char *str = NULL;
+ struct srcpos *pos = NULL;
+ char *file_str;
+
+ if (!(c->warn && (quiet < 1)) && !(c->error && (quiet < 2)))
+ return;
- if ((c->warn && (quiet < 1))
- || (c->error && (quiet < 2))) {
- fprintf(stderr, "%s: %s (%s): ",
- strcmp(dti->outname, "-") ? dti->outname : "<stdout>",
+ if (prop && prop->srcpos)
+ pos = prop->srcpos;
+ else if (node && node->srcpos)
+ pos = node->srcpos;
+
+ if (pos) {
+ file_str = srcpos_string(pos);
+ xasprintf(&str, "%s", file_str);
+ free(file_str);
+ } else if (streq(dti->outname, "-")) {
+ xasprintf(&str, "<stdout>");
+ } else {
+ xasprintf(&str, "%s", dti->outname);
+ }
+
+ xasprintf_append(&str, ": %s (%s): ",
(c->error) ? "ERROR" : "Warning", c->name);
- if (node) {
- fprintf(stderr, "%s", node->fullpath);
- if (prop)
- fprintf(stderr, ":%s", prop->name);
- fputs(": ", stderr);
- }
- vfprintf(stderr, fmt, ap);
- fprintf(stderr, "\n");
+
+ if (node) {
+ if (prop)
+ xasprintf_append(&str, "%s:%s: ", node->fullpath, prop->name);
+ else
+ xasprintf_append(&str, "%s: ", node->fullpath);
}
+
+ va_start(ap, fmt);
+ xavsprintf_append(&str, fmt, ap);
va_end(ap);
+
+ xasprintf_append(&str, "\n");
+
+ if (!prop && pos) {
+ pos = node->srcpos;
+ while (pos->next) {
+ pos = pos->next;
+
+ file_str = srcpos_string(pos);
+ xasprintf_append(&str, " also defined at %s\n", file_str);
+ free(file_str);
+ }
+ }
+
+ fputs(str, stderr);
+ free(str);
}
#define FAIL(c, dti, node, ...) \
@@ -123,6 +143,14 @@ static void check_nodes_props(struct check *c, struct dt_info *dti, struct node
check_nodes_props(c, dti, child);
}
+static bool is_multiple_of(int multiple, int divisor)
+{
+ if (divisor == 0)
+ return multiple == 0;
+ else
+ return (multiple % divisor) == 0;
+}
+
static bool run_check(struct check *c, struct dt_info *dti)
{
struct node *dt = dti->dt;
@@ -179,7 +207,7 @@ static void check_is_string(struct check *c, struct dt_info *dti,
struct node *node)
{
struct property *prop;
- char *propname = c->data;
+ const char *propname = c->data;
prop = get_property(node, propname);
if (!prop)
@@ -198,7 +226,7 @@ static void check_is_string_list(struct check *c, struct dt_info *dti,
{
int rem, l;
struct property *prop;
- char *propname = c->data;
+ const char *propname = c->data;
char *str;
prop = get_property(node, propname);
@@ -226,7 +254,7 @@ static void check_is_cell(struct check *c, struct dt_info *dti,
struct node *node)
{
struct property *prop;
- char *propname = c->data;
+ const char *propname = c->data;
prop = get_property(node, propname);
if (!prop)
@@ -277,19 +305,20 @@ ERROR(duplicate_property_names, check_duplicate_property_names, NULL);
#define LOWERCASE "abcdefghijklmnopqrstuvwxyz"
#define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define DIGITS "0123456789"
-#define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-"
+#define NODECHARS LOWERCASE UPPERCASE DIGITS ",._+-@"
+#define PROPCHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-"
#define PROPNODECHARSSTRICT LOWERCASE UPPERCASE DIGITS ",-"
static void check_node_name_chars(struct check *c, struct dt_info *dti,
struct node *node)
{
- int n = strspn(node->name, c->data);
+ size_t n = strspn(node->name, c->data);
if (n < strlen(node->name))
FAIL(c, dti, node, "Bad character '%c' in node name",
node->name[n]);
}
-ERROR(node_name_chars, check_node_name_chars, PROPNODECHARS "@");
+ERROR(node_name_chars, check_node_name_chars, NODECHARS);
static void check_node_name_chars_strict(struct check *c, struct dt_info *dti,
struct node *node)
@@ -310,6 +339,20 @@ static void check_node_name_format(struct check *c, struct dt_info *dti,
}
ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars);
+static void check_node_name_vs_property_name(struct check *c,
+ struct dt_info *dti,
+ struct node *node)
+{
+ if (!node->parent)
+ return;
+
+ if (get_property(node->parent, node->name)) {
+ FAIL(c, dti, node, "node name and property name conflict");
+ }
+}
+WARNING(node_name_vs_property_name, check_node_name_vs_property_name,
+ NULL, &node_name_chars);
+
static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti,
struct node *node)
{
@@ -332,7 +375,7 @@ static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti,
FAIL(c, dti, node, "node has a reg or ranges property, but no unit name");
} else {
if (unitname[0])
- FAIL(c, dti, node, "node has a unit name, but no reg property");
+ FAIL(c, dti, node, "node has a unit name, but no reg or ranges property");
}
}
WARNING(unit_address_vs_reg, check_unit_address_vs_reg, NULL);
@@ -343,14 +386,14 @@ static void check_property_name_chars(struct check *c, struct dt_info *dti,
struct property *prop;
for_each_property(node, prop) {
- int n = strspn(prop->name, c->data);
+ size_t n = strspn(prop->name, c->data);
if (n < strlen(prop->name))
FAIL_PROP(c, dti, node, prop, "Bad character '%c' in property name",
prop->name[n]);
}
}
-ERROR(property_name_chars, check_property_name_chars, PROPNODECHARS);
+ERROR(property_name_chars, check_property_name_chars, PROPCHARS);
static void check_property_name_chars_strict(struct check *c,
struct dt_info *dti,
@@ -360,7 +403,7 @@ static void check_property_name_chars_strict(struct check *c,
for_each_property(node, prop) {
const char *name = prop->name;
- int n = strspn(name, c->data);
+ size_t n = strspn(name, c->data);
if (n == strlen(prop->name))
continue;
@@ -477,7 +520,7 @@ static cell_t check_phandle_prop(struct check *c, struct dt_info *dti,
phandle = propval_cell(prop);
- if ((phandle == 0) || (phandle == -1)) {
+ if (!phandle_is_valid(phandle)) {
FAIL_PROP(c, dti, node, prop, "bad value (0x%x) in %s property",
phandle, prop->name);
return 0;
@@ -536,7 +579,7 @@ static void check_name_properties(struct check *c, struct dt_info *dti,
if (!prop)
return; /* No name property, that's fine */
- if ((prop->val.len != node->basenamelen+1)
+ if ((prop->val.len != node->basenamelen + 1U)
|| (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) {
FAIL(c, dti, node, "\"name\" property is incorrect (\"%s\" instead"
" of base node name)", prop->val.val);
@@ -625,6 +668,8 @@ ERROR(path_references, fixup_path_references, NULL, &duplicate_node_names);
static void fixup_omit_unused_nodes(struct check *c, struct dt_info *dti,
struct node *node)
{
+ if (generate_symbols && node->labels)
+ return;
if (node->omit_if_unused && !node->is_referenced)
delete_node(node);
}
@@ -635,7 +680,6 @@ ERROR(omit_unused_nodes, fixup_omit_unused_nodes, NULL, &phandle_references, &pa
*/
WARNING_IF_NOT_CELL(address_cells_is_cell, "#address-cells");
WARNING_IF_NOT_CELL(size_cells_is_cell, "#size-cells");
-WARNING_IF_NOT_CELL(interrupt_cells_is_cell, "#interrupt-cells");
WARNING_IF_NOT_STRING(device_type_is_string, "device_type");
WARNING_IF_NOT_STRING(model_is_string, "model");
@@ -650,8 +694,7 @@ static void check_names_is_string_list(struct check *c, struct dt_info *dti,
struct property *prop;
for_each_property(node, prop) {
- const char *s = strrchr(prop->name, '-');
- if (!s || !streq(s, "-names"))
+ if (!strends(prop->name, "-names"))
continue;
c->data = prop->name;
@@ -669,6 +712,11 @@ static void check_alias_paths(struct check *c, struct dt_info *dti,
return;
for_each_property(node, prop) {
+ if (streq(prop->name, "phandle")
+ || streq(prop->name, "linux,phandle")) {
+ continue;
+ }
+
if (!prop->val.val || !get_node_by_path(dti->dt, prop->val.val)) {
FAIL_PROP(c, dti, node, prop, "aliases property is not a valid node (%s)",
prop->val.val);
@@ -726,7 +774,7 @@ static void check_reg_format(struct check *c, struct dt_info *dti,
size_cells = node_size_cells(node->parent);
entrylen = (addr_cells + size_cells) * sizeof(cell_t);
- if (!entrylen || (prop->val.len % entrylen) != 0)
+ if (!is_multiple_of(prop->val.len, entrylen))
FAIL_PROP(c, dti, node, prop, "property has invalid length (%d bytes) "
"(#address-cells == %d, #size-cells == %d)",
prop->val.len, addr_cells, size_cells);
@@ -738,13 +786,15 @@ static void check_ranges_format(struct check *c, struct dt_info *dti,
{
struct property *prop;
int c_addr_cells, p_addr_cells, c_size_cells, p_size_cells, entrylen;
+ const char *ranges = c->data;
- prop = get_property(node, "ranges");
+ prop = get_property(node, ranges);
if (!prop)
return;
if (!node->parent) {
- FAIL_PROP(c, dti, node, prop, "Root node has a \"ranges\" property");
+ FAIL_PROP(c, dti, node, prop, "Root node has a \"%s\" property",
+ ranges);
return;
}
@@ -756,23 +806,24 @@ static void check_ranges_format(struct check *c, struct dt_info *dti,
if (prop->val.len == 0) {
if (p_addr_cells != c_addr_cells)
- FAIL_PROP(c, dti, node, prop, "empty \"ranges\" property but its "
+ FAIL_PROP(c, dti, node, prop, "empty \"%s\" property but its "
"#address-cells (%d) differs from %s (%d)",
- c_addr_cells, node->parent->fullpath,
+ ranges, c_addr_cells, node->parent->fullpath,
p_addr_cells);
if (p_size_cells != c_size_cells)
- FAIL_PROP(c, dti, node, prop, "empty \"ranges\" property but its "
+ FAIL_PROP(c, dti, node, prop, "empty \"%s\" property but its "
"#size-cells (%d) differs from %s (%d)",
- c_size_cells, node->parent->fullpath,
+ ranges, c_size_cells, node->parent->fullpath,
p_size_cells);
- } else if ((prop->val.len % entrylen) != 0) {
- FAIL_PROP(c, dti, node, prop, "\"ranges\" property has invalid length (%d bytes) "
+ } else if (!is_multiple_of(prop->val.len, entrylen)) {
+ FAIL_PROP(c, dti, node, prop, "\"%s\" property has invalid length (%d bytes) "
"(parent #address-cells == %d, child #address-cells == %d, "
- "#size-cells == %d)", prop->val.len,
+ "#size-cells == %d)", ranges, prop->val.len,
p_addr_cells, c_addr_cells, c_size_cells);
}
}
-WARNING(ranges_format, check_ranges_format, NULL, &addr_size_cells);
+WARNING(ranges_format, check_ranges_format, "ranges", &addr_size_cells);
+WARNING(dma_ranges_format, check_ranges_format, "dma-ranges", &addr_size_cells);
static const struct bus_type pci_bus = {
.name = "PCI",
@@ -842,7 +893,7 @@ static void check_pci_device_bus_num(struct check *c, struct dt_info *dti, struc
} else {
cells = (cell_t *)prop->val.val;
min_bus = fdt32_to_cpu(cells[0]);
- max_bus = fdt32_to_cpu(cells[0]);
+ max_bus = fdt32_to_cpu(cells[1]);
}
if ((bus_num < min_bus) || (bus_num > max_bus))
FAIL_PROP(c, dti, node, prop, "PCI bus number %d out of range, expected (%d - %d)",
@@ -862,10 +913,8 @@ static void check_pci_device_reg(struct check *c, struct dt_info *dti, struct no
return;
prop = get_property(node, "reg");
- if (!prop) {
- FAIL(c, dti, node, "missing PCI reg property");
+ if (!prop)
return;
- }
cells = (cell_t *)prop->val.val;
if (cells[1] || cells[2])
@@ -910,7 +959,7 @@ static bool node_is_compatible(struct node *node, const char *compat)
for (str = prop->val.val, end = str + prop->val.len; str < end;
str += strnlen(str, end - str) + 1) {
- if (strprefixeq(str, end - str, compat))
+ if (streq(str, compat))
return true;
}
return false;
@@ -921,7 +970,8 @@ static void check_simple_bus_bridge(struct check *c, struct dt_info *dti, struct
if (node_is_compatible(node, "simple-bus"))
node->bus = &simple_bus;
}
-WARNING(simple_bus_bridge, check_simple_bus_bridge, NULL, &addr_size_cells);
+WARNING(simple_bus_bridge, check_simple_bus_bridge, NULL,
+ &addr_size_cells, &compatible_is_string_list);
static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct node *node)
{
@@ -962,6 +1012,160 @@ static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct no
}
WARNING(simple_bus_reg, check_simple_bus_reg, NULL, ®_format, &simple_bus_bridge);
+static const struct bus_type i2c_bus = {
+ .name = "i2c-bus",
+};
+
+static void check_i2c_bus_bridge(struct check *c, struct dt_info *dti, struct node *node)
+{
+ if (strprefixeq(node->name, node->basenamelen, "i2c-bus") ||
+ strprefixeq(node->name, node->basenamelen, "i2c-arb")) {
+ node->bus = &i2c_bus;
+ } else if (strprefixeq(node->name, node->basenamelen, "i2c")) {
+ struct node *child;
+ for_each_child(node, child) {
+ if (strprefixeq(child->name, child->basenamelen, "i2c-bus"))
+ return;
+ }
+ node->bus = &i2c_bus;
+ } else
+ return;
+
+ if (!node->children)
+ return;
+
+ if (node_addr_cells(node) != 1)
+ FAIL(c, dti, node, "incorrect #address-cells for I2C bus");
+ if (node_size_cells(node) != 0)
+ FAIL(c, dti, node, "incorrect #size-cells for I2C bus");
+
+}
+WARNING(i2c_bus_bridge, check_i2c_bus_bridge, NULL, &addr_size_cells);
+
+#define I2C_OWN_SLAVE_ADDRESS (1U << 30)
+#define I2C_TEN_BIT_ADDRESS (1U << 31)
+
+static void check_i2c_bus_reg(struct check *c, struct dt_info *dti, struct node *node)
+{
+ struct property *prop;
+ const char *unitname = get_unitname(node);
+ char unit_addr[17];
+ uint32_t reg = 0;
+ int len;
+ cell_t *cells = NULL;
+
+ if (!node->parent || (node->parent->bus != &i2c_bus))
+ return;
+
+ prop = get_property(node, "reg");
+ if (prop)
+ cells = (cell_t *)prop->val.val;
+
+ if (!cells) {
+ FAIL(c, dti, node, "missing or empty reg property");
+ return;
+ }
+
+ reg = fdt32_to_cpu(*cells);
+ /* Ignore I2C_OWN_SLAVE_ADDRESS */
+ reg &= ~I2C_OWN_SLAVE_ADDRESS;
+ snprintf(unit_addr, sizeof(unit_addr), "%x", reg);
+ if (!streq(unitname, unit_addr))
+ FAIL(c, dti, node, "I2C bus unit address format error, expected \"%s\"",
+ unit_addr);
+
+ for (len = prop->val.len; len > 0; len -= 4) {
+ reg = fdt32_to_cpu(*(cells++));
+ /* Ignore I2C_OWN_SLAVE_ADDRESS */
+ reg &= ~I2C_OWN_SLAVE_ADDRESS;
+
+ if (reg & I2C_TEN_BIT_ADDRESS) {
+ if ((reg & ~I2C_TEN_BIT_ADDRESS) > 0x3ff)
+ FAIL_PROP(c, dti, node, prop, "I2C address must be less than 10-bits, got \"0x%x\"",
+ reg);
+ } else if (reg > 0x7f)
+ FAIL_PROP(c, dti, node, prop, "I2C address must be less than 7-bits, got \"0x%x\". Set I2C_TEN_BIT_ADDRESS for 10 bit addresses or fix the property",
+ reg);
+ }
+}
+WARNING(i2c_bus_reg, check_i2c_bus_reg, NULL, ®_format, &i2c_bus_bridge);
+
+static const struct bus_type spi_bus = {
+ .name = "spi-bus",
+};
+
+static void check_spi_bus_bridge(struct check *c, struct dt_info *dti, struct node *node)
+{
+ int spi_addr_cells = 1;
+
+ if (strprefixeq(node->name, node->basenamelen, "spi")) {
+ node->bus = &spi_bus;
+ } else {
+ /* Try to detect SPI buses which don't have proper node name */
+ struct node *child;
+
+ if (node_addr_cells(node) != 1 || node_size_cells(node) != 0)
+ return;
+
+ for_each_child(node, child) {
+ struct property *prop;
+ for_each_property(child, prop) {
+ if (strstarts(prop->name, "spi-")) {
+ node->bus = &spi_bus;
+ break;
+ }
+ }
+ if (node->bus == &spi_bus)
+ break;
+ }
+
+ if (node->bus == &spi_bus && get_property(node, "reg"))
+ FAIL(c, dti, node, "node name for SPI buses should be 'spi'");
+ }
+ if (node->bus != &spi_bus || !node->children)
+ return;
+
+ if (get_property(node, "spi-slave"))
+ spi_addr_cells = 0;
+ if (node_addr_cells(node) != spi_addr_cells)
+ FAIL(c, dti, node, "incorrect #address-cells for SPI bus");
+ if (node_size_cells(node) != 0)
+ FAIL(c, dti, node, "incorrect #size-cells for SPI bus");
+
+}
+WARNING(spi_bus_bridge, check_spi_bus_bridge, NULL, &addr_size_cells);
+
+static void check_spi_bus_reg(struct check *c, struct dt_info *dti, struct node *node)
+{
+ struct property *prop;
+ const char *unitname = get_unitname(node);
+ char unit_addr[9];
+ uint32_t reg = 0;
+ cell_t *cells = NULL;
+
+ if (!node->parent || (node->parent->bus != &spi_bus))
+ return;
+
+ if (get_property(node->parent, "spi-slave"))
+ return;
+
+ prop = get_property(node, "reg");
+ if (prop)
+ cells = (cell_t *)prop->val.val;
+
+ if (!cells) {
+ FAIL(c, dti, node, "missing or empty reg property");
+ return;
+ }
+
+ reg = fdt32_to_cpu(*cells);
+ snprintf(unit_addr, sizeof(unit_addr), "%x", reg);
+ if (!streq(unitname, unit_addr))
+ FAIL(c, dti, node, "SPI bus unit address format error, expected \"%s\"",
+ unit_addr);
+}
+WARNING(spi_bus_reg, check_spi_bus_reg, NULL, ®_format, &spi_bus_bridge);
+
static void check_unit_address_format(struct check *c, struct dt_info *dti,
struct node *node)
{
@@ -978,7 +1182,7 @@ static void check_unit_address_format(struct check *c, struct dt_info *dti,
/* skip over 0x for next test */
unitname += 2;
}
- if (unitname[0] == '0' && isxdigit(unitname[1]))
+ if (unitname[0] == '0' && isxdigit((unsigned char)unitname[1]))
FAIL(c, dti, node, "unit name should not have leading 0s");
}
WARNING(unit_address_format, check_unit_address_format, NULL,
@@ -1013,29 +1217,48 @@ WARNING(avoid_default_addr_size, check_avoid_default_addr_size, NULL,
static void check_avoid_unnecessary_addr_size(struct check *c, struct dt_info *dti,
struct node *node)
{
- struct property *prop;
struct node *child;
- bool has_reg = false;
if (!node->parent || node->addr_cells < 0 || node->size_cells < 0)
return;
- if (get_property(node, "ranges") || !node->children)
+ if (get_property(node, "ranges") || get_property(node, "dma-ranges") || !node->children)
return;
for_each_child(node, child) {
- prop = get_property(child, "reg");
- if (prop)
- has_reg = true;
+ /*
+ * Even if the child devices' address space is not mapped into
+ * the parent bus (no 'ranges' property on node), children can
+ * still have registers on a local bus, or map local addresses
+ * to another subordinate address space. The properties on the
+ * child nodes then make #address-cells/#size-cells necessary:
+ */
+ if (get_property(child, "reg") || get_property(child, "ranges"))
+ return;
}
- if (!has_reg)
- FAIL(c, dti, node, "unnecessary #address-cells/#size-cells without \"ranges\" or child \"reg\" property");
+ FAIL(c, dti, node, "unnecessary #address-cells/#size-cells without \"ranges\", \"dma-ranges\" or child \"reg\" or \"ranges\" property");
}
WARNING(avoid_unnecessary_addr_size, check_avoid_unnecessary_addr_size, NULL, &avoid_default_addr_size);
-static void check_unique_unit_address(struct check *c, struct dt_info *dti,
- struct node *node)
+static bool node_is_disabled(struct node *node)
+{
+ struct property *prop;
+
+ prop = get_property(node, "status");
+ if (prop) {
+ char *str = prop->val.val;
+ if (streq("disabled", str))
+ return true;
+ }
+
+ return false;
+}
+
+static void check_unique_unit_address_common(struct check *c,
+ struct dt_info *dti,
+ struct node *node,
+ bool disable_check)
{
struct node *childa;
@@ -1052,18 +1275,38 @@ static void check_unique_unit_address(struct check *c, struct dt_info *dti,
if (!strlen(addr_a))
continue;
+ if (disable_check && node_is_disabled(childa))
+ continue;
+
for_each_child(node, childb) {
const char *addr_b = get_unitname(childb);
if (childa == childb)
break;
+ if (disable_check && node_is_disabled(childb))
+ continue;
+
if (streq(addr_a, addr_b))
FAIL(c, dti, childb, "duplicate unit-address (also used in node %s)", childa->fullpath);
}
}
}
+
+static void check_unique_unit_address(struct check *c, struct dt_info *dti,
+ struct node *node)
+{
+ check_unique_unit_address_common(c, dti, node, false);
+}
WARNING(unique_unit_address, check_unique_unit_address, NULL, &avoid_default_addr_size);
+static void check_unique_unit_address_if_enabled(struct check *c, struct dt_info *dti,
+ struct node *node)
+{
+ check_unique_unit_address_common(c, dti, node, true);
+}
+CHECK_ENTRY(unique_unit_address_if_enabled, check_unique_unit_address_if_enabled,
+ NULL, false, false, &avoid_default_addr_size);
+
static void check_obsolete_chosen_interrupt_controller(struct check *c,
struct dt_info *dti,
struct node *node)
@@ -1143,15 +1386,15 @@ struct provider {
};
static void check_property_phandle_args(struct check *c,
- struct dt_info *dti,
- struct node *node,
- struct property *prop,
- const struct provider *provider)
+ struct dt_info *dti,
+ struct node *node,
+ struct property *prop,
+ const struct provider *provider)
{
struct node *root = dti->dt;
- int cell, cellsize = 0;
+ unsigned int cell, cellsize = 0;
- if (prop->val.len % sizeof(cell_t)) {
+ if (!is_multiple_of(prop->val.len, sizeof(cell_t))) {
FAIL_PROP(c, dti, node, prop,
"property size (%d) is invalid, expected multiple of %zu",
prop->val.len, sizeof(cell_t));
@@ -1161,14 +1404,15 @@ static void check_property_phandle_args(struct check *c,
for (cell = 0; cell < prop->val.len / sizeof(cell_t); cell += cellsize + 1) {
struct node *provider_node;
struct property *cellprop;
- int phandle;
+ cell_t phandle;
+ unsigned int expected;
phandle = propval_cell_n(prop, cell);
/*
* Some bindings use a cell value 0 or -1 to skip over optional
* entries when each index position has a specific definition.
*/
- if (phandle == 0 || phandle == -1) {
+ if (!phandle_is_valid(phandle)) {
/* Give up if this is an overlay with external references */
if (dti->dtsflags & DTSF_PLUGIN)
break;
@@ -1211,10 +1455,12 @@ static void check_property_phandle_args(struct check *c,
break;
}
- if (prop->val.len < ((cell + cellsize + 1) * sizeof(cell_t))) {
+ expected = (cell + cellsize + 1) * sizeof(cell_t);
+ if ((expected <= cell) || prop->val.len < expected) {
FAIL_PROP(c, dti, node, prop,
- "property size (%d) too small for cell size %d",
+ "property size (%d) too small for cell size %u",
prop->val.len, cellsize);
+ break;
}
}
}
@@ -1223,7 +1469,7 @@ static void check_provider_cells_property(struct check *c,
struct dt_info *dti,
struct node *node)
{
- struct provider *provider = c->data;
+ const struct provider *provider = c->data;
struct property *prop;
prop = get_property(node, provider->prop_name);
@@ -1234,7 +1480,8 @@ static void check_provider_cells_property(struct check *c,
}
#define WARNING_PROPERTY_PHANDLE_CELLS(nm, propname, cells_name, ...) \
static struct provider nm##_provider = { (propname), (cells_name), __VA_ARGS__ }; \
- WARNING(nm##_property, check_provider_cells_property, &nm##_provider, &phandle_references);
+ WARNING_IF_NOT_CELL(nm##_is_cell, cells_name); \
+ WARNING(nm##_property, check_provider_cells_property, &nm##_provider, &nm##_is_cell, &phandle_references);
WARNING_PROPERTY_PHANDLE_CELLS(clocks, "clocks", "#clock-cells");
WARNING_PROPERTY_PHANDLE_CELLS(cooling_device, "cooling-device", "#cooling-cells");
@@ -1255,24 +1502,17 @@ WARNING_PROPERTY_PHANDLE_CELLS(thermal_sensors, "thermal-sensors", "#thermal-sen
static bool prop_is_gpio(struct property *prop)
{
- char *str;
-
/*
* *-gpios and *-gpio can appear in property names,
* so skip over any false matches (only one known ATM)
*/
- if (strstr(prop->name, "nr-gpio"))
+ if (strends(prop->name, ",nr-gpios"))
return false;
- str = strrchr(prop->name, '-');
- if (str)
- str++;
- else
- str = prop->name;
- if (!(streq(str, "gpios") || streq(str, "gpio")))
- return false;
-
- return true;
+ return strends(prop->name, "-gpios") ||
+ streq(prop->name, "gpios") ||
+ strends(prop->name, "-gpio") ||
+ streq(prop->name, "gpio");
}
static void check_gpios_property(struct check *c,
@@ -1307,13 +1547,10 @@ static void check_deprecated_gpio_property(struct check *c,
struct property *prop;
for_each_property(node, prop) {
- char *str;
-
if (!prop_is_gpio(prop))
continue;
- str = strstr(prop->name, "gpio");
- if (!streq(str, "gpio"))
+ if (!strends(prop->name, "gpio"))
continue;
FAIL_PROP(c, dti, node, prop,
@@ -1337,6 +1574,121 @@ static bool node_is_interrupt_provider(struct node *node)
return false;
}
+
+static void check_interrupt_provider(struct check *c,
+ struct dt_info *dti,
+ struct node *node)
+{
+ struct property *prop;
+ bool irq_provider = node_is_interrupt_provider(node);
+
+ prop = get_property(node, "#interrupt-cells");
+ if (irq_provider && !prop) {
+ FAIL(c, dti, node,
+ "Missing '#interrupt-cells' in interrupt provider");
+ return;
+ }
+
+ if (!irq_provider && prop) {
+ FAIL(c, dti, node,
+ "'#interrupt-cells' found, but node is not an interrupt provider");
+ return;
+ }
+}
+WARNING(interrupt_provider, check_interrupt_provider, NULL, &interrupts_extended_is_cell);
+
+static void check_interrupt_map(struct check *c,
+ struct dt_info *dti,
+ struct node *node)
+{
+ struct node *root = dti->dt;
+ struct property *prop, *irq_map_prop;
+ size_t cellsize, cell, map_cells;
+
+ irq_map_prop = get_property(node, "interrupt-map");
+ if (!irq_map_prop)
+ return;
+
+ if (node->addr_cells < 0) {
+ FAIL(c, dti, node,
+ "Missing '#address-cells' in interrupt-map provider");
+ return;
+ }
+ cellsize = node_addr_cells(node);
+ cellsize += propval_cell(get_property(node, "#interrupt-cells"));
+
+ prop = get_property(node, "interrupt-map-mask");
+ if (prop && (prop->val.len != (cellsize * sizeof(cell_t))))
+ FAIL_PROP(c, dti, node, prop,
+ "property size (%d) is invalid, expected %zu",
+ prop->val.len, cellsize * sizeof(cell_t));
+
+ if (!is_multiple_of(irq_map_prop->val.len, sizeof(cell_t))) {
+ FAIL_PROP(c, dti, node, irq_map_prop,
+ "property size (%d) is invalid, expected multiple of %zu",
+ irq_map_prop->val.len, sizeof(cell_t));
+ return;
+ }
+
+ map_cells = irq_map_prop->val.len / sizeof(cell_t);
+ for (cell = 0; cell < map_cells; ) {
+ struct node *provider_node;
+ struct property *cellprop;
+ int phandle;
+ size_t parent_cellsize;
+
+ if ((cell + cellsize) >= map_cells) {
+ FAIL_PROP(c, dti, node, irq_map_prop,
+ "property size (%d) too small, expected > %zu",
+ irq_map_prop->val.len, (cell + cellsize) * sizeof(cell_t));
+ break;
+ }
+ cell += cellsize;
+
+ phandle = propval_cell_n(irq_map_prop, cell);
+ if (!phandle_is_valid(phandle)) {
+ /* Give up if this is an overlay with external references */
+ if (!(dti->dtsflags & DTSF_PLUGIN))
+ FAIL_PROP(c, dti, node, irq_map_prop,
+ "Cell %zu is not a phandle(%d)",
+ cell, phandle);
+ break;
+ }
+
+ provider_node = get_node_by_phandle(root, phandle);
+ if (!provider_node) {
+ FAIL_PROP(c, dti, node, irq_map_prop,
+ "Could not get phandle(%d) node for (cell %zu)",
+ phandle, cell);
+ break;
+ }
+
+ cellprop = get_property(provider_node, "#interrupt-cells");
+ if (cellprop) {
+ parent_cellsize = propval_cell(cellprop);
+ } else {
+ FAIL(c, dti, node, "Missing property '#interrupt-cells' in node %s or bad phandle (referred from interrupt-map[%zu])",
+ provider_node->fullpath, cell);
+ break;
+ }
+
+ cellprop = get_property(provider_node, "#address-cells");
+ if (cellprop)
+ parent_cellsize += propval_cell(cellprop);
+ else
+ FAIL_PROP(c, dti, node, irq_map_prop,
+ "Missing property '#address-cells' in node %s, using 0 as fallback",
+ provider_node->fullpath);
+
+ cell += 1 + parent_cellsize;
+ if (cell > map_cells)
+ FAIL_PROP(c, dti, node, irq_map_prop,
+ "property size (%d) mismatch, expected %zu",
+ irq_map_prop->val.len, cell * sizeof(cell_t));
+ }
+}
+WARNING(interrupt_map, check_interrupt_map, NULL, &phandle_references, &addr_size_cells, &interrupt_provider);
+
static void check_interrupts_property(struct check *c,
struct dt_info *dti,
struct node *node)
@@ -1344,13 +1696,13 @@ static void check_interrupts_property(struct check *c,
struct node *root = dti->dt;
struct node *irq_node = NULL, *parent = node;
struct property *irq_prop, *prop = NULL;
- int irq_cells, phandle;
+ cell_t irq_cells, phandle;
irq_prop = get_property(node, "interrupts");
if (!irq_prop)
return;
- if (irq_prop->val.len % sizeof(cell_t))
+ if (!is_multiple_of(irq_prop->val.len, sizeof(cell_t)))
FAIL_PROP(c, dti, node, irq_prop, "size (%d) is invalid, expected multiple of %zu",
irq_prop->val.len, sizeof(cell_t));
@@ -1363,10 +1715,14 @@ static void check_interrupts_property(struct check *c,
prop = get_property(parent, "interrupt-parent");
if (prop) {
phandle = propval_cell(prop);
- /* Give up if this is an overlay with external references */
- if ((phandle == 0 || phandle == -1) &&
- (dti->dtsflags & DTSF_PLUGIN))
+ if (!phandle_is_valid(phandle)) {
+ /* Give up if this is an overlay with
+ * external references */
+ if (dti->dtsflags & DTSF_PLUGIN)
return;
+ FAIL_PROP(c, dti, parent, prop, "Invalid phandle");
+ continue;
+ }
irq_node = get_node_by_phandle(root, phandle);
if (!irq_node) {
@@ -1390,12 +1746,12 @@ static void check_interrupts_property(struct check *c,
prop = get_property(irq_node, "#interrupt-cells");
if (!prop) {
- FAIL(c, dti, irq_node, "Missing #interrupt-cells in interrupt-parent");
+ /* We warn about that already in another test. */
return;
}
irq_cells = propval_cell(prop);
- if (irq_prop->val.len % (irq_cells * sizeof(cell_t))) {
+ if (!is_multiple_of(irq_prop->val.len, irq_cells * sizeof(cell_t))) {
FAIL_PROP(c, dti, node, prop,
"size is (%d), expected multiple of %d",
irq_prop->val.len, (int)(irq_cells * sizeof(cell_t)));
@@ -1421,6 +1777,11 @@ static void check_graph_nodes(struct check *c, struct dt_info *dti,
get_property(child, "remote-endpoint")))
continue;
+ /* The root node cannot be a port */
+ if (!node->parent) {
+ FAIL(c, dti, node, "root node contains endpoint node '%s', potentially misplaced remote-endpoint property", child->name);
+ continue;
+ }
node->bus = &graph_port_bus;
/* The parent of 'port' nodes can be either 'ports' or a device */
@@ -1434,31 +1795,6 @@ static void check_graph_nodes(struct check *c, struct dt_info *dti,
}
WARNING(graph_nodes, check_graph_nodes, NULL);
-static void check_graph_child_address(struct check *c, struct dt_info *dti,
- struct node *node)
-{
- int cnt = 0;
- struct node *child;
-
- if (node->bus != &graph_ports_bus && node->bus != &graph_port_bus)
- return;
-
- for_each_child(node, child) {
- struct property *prop = get_property(child, "reg");
-
- /* No error if we have any non-zero unit address */
- if (prop && propval_cell(prop) != 0)
- return;
-
- cnt++;
- }
-
- if (cnt == 1 && node->addr_cells != -1)
- FAIL(c, dti, node, "graph node has single child node '%s', #address-cells/#size-cells are not necessary",
- node->children->name);
-}
-WARNING(graph_child_address, check_graph_child_address, NULL, &graph_nodes);
-
static void check_graph_reg(struct check *c, struct dt_info *dti,
struct node *node)
{
@@ -1496,17 +1832,21 @@ static void check_graph_port(struct check *c, struct dt_info *dti,
if (node->bus != &graph_port_bus)
return;
+ check_graph_reg(c, dti, node);
+
+ /* skip checks below for overlays */
+ if (dti->dtsflags & DTSF_PLUGIN)
+ return;
+
if (!strprefixeq(node->name, node->basenamelen, "port"))
FAIL(c, dti, node, "graph port node name should be 'port'");
-
- check_graph_reg(c, dti, node);
}
WARNING(graph_port, check_graph_port, NULL, &graph_nodes);
static struct node *get_remote_endpoint(struct check *c, struct dt_info *dti,
struct node *endpoint)
{
- int phandle;
+ cell_t phandle;
struct node *node;
struct property *prop;
@@ -1516,7 +1856,7 @@ static struct node *get_remote_endpoint(struct check *c, struct dt_info *dti,
phandle = propval_cell(prop);
/* Give up if this is an overlay with external references */
- if (phandle == 0 || phandle == -1)
+ if (!phandle_is_valid(phandle))
return NULL;
node = get_node_by_phandle(dti->dt, phandle);
@@ -1534,11 +1874,15 @@ static void check_graph_endpoint(struct check *c, struct dt_info *dti,
if (!node->parent || node->parent->bus != &graph_port_bus)
return;
- if (!strprefixeq(node->name, node->basenamelen, "endpoint"))
- FAIL(c, dti, node, "graph endpont node name should be 'endpoint'");
-
check_graph_reg(c, dti, node);
+ /* skip checks below for overlays */
+ if (dti->dtsflags & DTSF_PLUGIN)
+ return;
+
+ if (!strprefixeq(node->name, node->basenamelen, "endpoint"))
+ FAIL(c, dti, node, "graph endpoint node name should be 'endpoint'");
+
remote_node = get_remote_endpoint(c, dti, node);
if (!remote_node)
return;
@@ -1549,10 +1893,35 @@ static void check_graph_endpoint(struct check *c, struct dt_info *dti,
}
WARNING(graph_endpoint, check_graph_endpoint, NULL, &graph_nodes);
+static void check_graph_child_address(struct check *c, struct dt_info *dti,
+ struct node *node)
+{
+ int cnt = 0;
+ struct node *child;
+
+ if (node->bus != &graph_ports_bus && node->bus != &graph_port_bus)
+ return;
+
+ for_each_child(node, child) {
+ struct property *prop = get_property(child, "reg");
+
+ /* No error if we have any non-zero unit address */
+ if (prop && propval_cell(prop) != 0 )
+ return;
+
+ cnt++;
+ }
+
+ if (cnt == 1 && node->addr_cells != -1)
+ FAIL(c, dti, node, "graph node has single child node '%s', #address-cells/#size-cells are not necessary",
+ node->children->name);
+}
+WARNING(graph_child_address, check_graph_child_address, NULL, &graph_nodes, &graph_port, &graph_endpoint);
+
static struct check *check_table[] = {
&duplicate_node_names, &duplicate_property_names,
&node_name_chars, &node_name_format, &property_name_chars,
- &name_is_string, &name_properties,
+ &name_is_string, &name_properties, &node_name_vs_property_name,
&duplicate_label,
@@ -1560,7 +1929,7 @@ static struct check *check_table[] = {
&phandle_references, &path_references,
&omit_unused_nodes,
- &address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell,
+ &address_cells_is_cell, &size_cells_is_cell,
&device_type_is_string, &model_is_string, &status_is_string,
&label_is_string,
@@ -1569,7 +1938,7 @@ static struct check *check_table[] = {
&property_name_chars_strict,
&node_name_chars_strict,
- &addr_size_cells, ®_format, &ranges_format,
+ &addr_size_cells, ®_format, &ranges_format, &dma_ranges_format,
&unit_address_vs_reg,
&unit_address_format,
@@ -1581,32 +1950,57 @@ static struct check *check_table[] = {
&simple_bus_bridge,
&simple_bus_reg,
+ &i2c_bus_bridge,
+ &i2c_bus_reg,
+
+ &spi_bus_bridge,
+ &spi_bus_reg,
+
&avoid_default_addr_size,
&avoid_unnecessary_addr_size,
&unique_unit_address,
+ &unique_unit_address_if_enabled,
&obsolete_chosen_interrupt_controller,
&chosen_node_is_root, &chosen_node_bootargs, &chosen_node_stdout_path,
&clocks_property,
+ &clocks_is_cell,
&cooling_device_property,
+ &cooling_device_is_cell,
&dmas_property,
+ &dmas_is_cell,
&hwlocks_property,
+ &hwlocks_is_cell,
&interrupts_extended_property,
+ &interrupts_extended_is_cell,
&io_channels_property,
+ &io_channels_is_cell,
&iommus_property,
+ &iommus_is_cell,
&mboxes_property,
+ &mboxes_is_cell,
&msi_parent_property,
+ &msi_parent_is_cell,
&mux_controls_property,
+ &mux_controls_is_cell,
&phys_property,
+ &phys_is_cell,
&power_domains_property,
+ &power_domains_is_cell,
&pwms_property,
+ &pwms_is_cell,
&resets_property,
+ &resets_is_cell,
&sound_dai_property,
+ &sound_dai_is_cell,
&thermal_sensors_property,
+ &thermal_sensors_is_cell,
&deprecated_gpio_property,
&gpios_property,
&interrupts_property,
+ &interrupt_provider,
+ &interrupt_map,
&alias_paths,
@@ -1630,7 +2024,7 @@ static void enable_warning_error(struct check *c, bool warn, bool error)
static void disable_warning_error(struct check *c, bool warn, bool error)
{
- int i;
+ unsigned int i;
/* Lowering level, also lower it for things this is the prereq
* for */
@@ -1651,7 +2045,7 @@ static void disable_warning_error(struct check *c, bool warn, bool error)
void parse_checks_option(bool warn, bool error, const char *arg)
{
- int i;
+ unsigned int i;
const char *name = arg;
bool enable = true;
@@ -1678,7 +2072,7 @@ void parse_checks_option(bool warn, bool error, const char *arg)
void process_checks(bool force, struct dt_info *dti)
{
- int i;
+ unsigned int i;
int error = 0;
for (i = 0; i < ARRAY_SIZE(check_table); i++) {
diff --git a/scripts/dtc/data.c b/scripts/dtc/data.c
index aa37a16c889..5b25aa06041 100644
--- a/scripts/dtc/data.c
+++ b/scripts/dtc/data.c
@@ -1,21 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
- *
- *
- * This program 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 program 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 program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
#include "dtc.h"
@@ -36,10 +21,10 @@ void data_free(struct data d)
free(d.val);
}
-struct data data_grow_for(struct data d, int xlen)
+struct data data_grow_for(struct data d, unsigned int xlen)
{
struct data nd;
- int newsize;
+ unsigned int newsize;
if (xlen == 0)
return d;
@@ -74,7 +59,8 @@ struct data data_copy_escape_string(const char *s, int len)
struct data d;
char *q;
- d = data_grow_for(empty_data, len + 1);
+ d = data_add_marker(empty_data, TYPE_STRING, NULL);
+ d = data_grow_for(d, len + 1);
q = d.val;
while (i < len) {
@@ -94,10 +80,11 @@ struct data data_copy_file(FILE *f, size_t maxlen)
{
struct data d = empty_data;
+ d = data_add_marker(d, TYPE_NONE, NULL);
while (!feof(f) && (d.len < maxlen)) {
size_t chunksize, ret;
- if (maxlen == -1)
+ if (maxlen == (size_t)-1)
chunksize = 4096;
else
chunksize = maxlen - d.len;
@@ -241,11 +228,7 @@ struct data data_add_marker(struct data d, enum markertype type, char *ref)
{
struct marker *m;
- m = xmalloc(sizeof(*m));
- m->offset = d.len;
- m->type = type;
- m->ref = ref;
- m->next = NULL;
+ m = alloc_marker(d.len, type, ref);
return data_append_markers(d, m);
}
@@ -267,3 +250,44 @@ bool data_is_one_string(struct data d)
return true;
}
+
+struct data data_insert_data(struct data d, struct marker *m, struct data old)
+{
+ unsigned int offset = m->offset;
+ struct marker *next = m->next;
+ struct marker *marker;
+ struct data new_data;
+ char *ref;
+
+ new_data = data_insert_at_marker(d, m, old.val, old.len);
+
+ /* Copy all markers from old value */
+ marker = old.markers;
+ for_each_marker(marker) {
+ ref = NULL;
+
+ if (marker->ref)
+ ref = xstrdup(marker->ref);
+
+ m->next = alloc_marker(marker->offset + offset, marker->type,
+ ref);
+ m = m->next;
+ }
+ m->next = next;
+
+ return new_data;
+}
+
+struct marker *alloc_marker(unsigned int offset, enum markertype type,
+ char *ref)
+{
+ struct marker *m;
+
+ m = xmalloc(sizeof(*m));
+ m->offset = offset;
+ m->type = type;
+ m->ref = ref;
+ m->next = NULL;
+
+ return m;
+}
diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l
index d34e1b04220..15d585c8079 100644
--- a/scripts/dtc/dtc-lexer.l
+++ b/scripts/dtc/dtc-lexer.l
@@ -1,21 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
- *
- *
- * This program 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 program 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 program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
%option noyywrap nounput noinput never-interactive
@@ -72,7 +57,7 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
push_input_file(name);
}
-<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)? {
+<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)* {
char *line, *fnstart, *fnend;
struct data fn;
/* skip text before line # */
@@ -166,6 +151,21 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
return DT_LABEL;
}
+<V1>{LABEL} {
+ /* Missed includes or macro definitions while
+ * preprocessing can lead to unexpected identifiers in
+ * the input. Report a slightly more informative error
+ * in this case */
+
+ lexical_error("Unexpected '%s'", yytext);
+
+ /* Treat it as a literal which often generates further
+ * useful error messages */
+
+ yylval.integer = 0;
+ return DT_LITERAL;
+ }
+
<V1>([0-9]+|0[xX][0-9a-fA-F]+)(U|L|UL|LL|ULL)? {
char *e;
DPRINT("Integer Literal: '%s'\n", yytext);
@@ -212,14 +212,14 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
<*>\&{LABEL} { /* label reference */
DPRINT("Ref: %s\n", yytext+1);
yylval.labelref = xstrdup(yytext+1);
- return DT_REF;
+ return DT_LABEL_REF;
}
<*>"&{"{PATHCHAR}*\} { /* new-style path reference */
yytext[yyleng-1] = '\0';
DPRINT("Ref: %s\n", yytext+2);
yylval.labelref = xstrdup(yytext+2);
- return DT_REF;
+ return DT_PATH_REF;
}
<BYTESTRING>[0-9a-fA-F]{2} {
diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y
index b3b9c83873d..4d5eece5262 100644
--- a/scripts/dtc/dtc-parser.y
+++ b/scripts/dtc/dtc-parser.y
@@ -1,22 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
- *
- *
- * This program 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 program 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 program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
+%locations
+
%{
#include <stdio.h>
#include <inttypes.h>
@@ -32,6 +19,8 @@ extern void yyerror(char const *s);
treesource_error = true; \
} while (0)
+#define YYERROR_CALL(msg) yyerror(msg)
+
extern struct dt_info *parser_output;
extern bool treesource_error;
@@ -76,7 +65,8 @@ static bool is_ref_relative(const char *ref)
%token <byte> DT_BYTE
%token <data> DT_STRING
%token <labelref> DT_LABEL
-%token <labelref> DT_REF
+%token <labelref> DT_LABEL_REF
+%token <labelref> DT_PATH_REF
%token DT_INCBIN
%type <data> propdata
@@ -89,6 +79,7 @@ static bool is_ref_relative(const char *ref)
%type <data> bytestring
%type <prop> propdef
%type <proplist> proplist
+%type <labelref> dt_ref
%type <node> devicetree
%type <node> nodedef
@@ -164,6 +155,8 @@ memreserve:
}
;
+dt_ref: DT_LABEL_REF | DT_PATH_REF;
+
devicetree:
'/' nodedef
{
@@ -173,7 +166,7 @@ devicetree:
{
$$ = merge_nodes($1, $3);
}
- | DT_REF nodedef
+ | dt_ref nodedef
{
/*
* We rely on the rule being always:
@@ -184,9 +177,12 @@ devicetree:
ERROR(&@2, "Label or path %s not found", $1);
else if (is_ref_relative($1))
ERROR(&@2, "Label-relative reference %s not supported in plugin", $1);
- $$ = add_orphan_node(name_node(build_node(NULL, NULL), ""), $2, $1);
+ $$ = add_orphan_node(
+ name_node(build_node(NULL, NULL, NULL),
+ ""),
+ $2, $1);
}
- | devicetree DT_LABEL DT_REF nodedef
+ | devicetree DT_LABEL dt_ref nodedef
{
struct node *target = get_node_by_ref($1, $3);
@@ -200,7 +196,7 @@ devicetree:
ERROR(&@3, "Label or path %s not found", $3);
$$ = $1;
}
- | devicetree DT_REF nodedef
+ | devicetree DT_PATH_REF nodedef
{
/*
* We rely on the rule being always:
@@ -221,7 +217,26 @@ devicetree:
}
$$ = $1;
}
- | devicetree DT_DEL_NODE DT_REF ';'
+ | devicetree DT_LABEL_REF nodedef
+ {
+ struct node *target = get_node_by_ref($1, $2);
+
+ if (target) {
+ merge_nodes(target, $3);
+ } else {
+ /*
+ * We rely on the rule being always:
+ * versioninfo plugindecl memreserves devicetree
+ * so $-1 is what we want (plugindecl)
+ */
+ if ($<flags>-1 & DTSF_PLUGIN)
+ add_orphan_node($1, $3, $2);
+ else
+ ERROR(&@2, "Label or path %s not found", $2);
+ }
+ $$ = $1;
+ }
+ | devicetree DT_DEL_NODE dt_ref ';'
{
struct node *target = get_node_by_ref($1, $3);
@@ -233,7 +248,7 @@ devicetree:
$$ = $1;
}
- | devicetree DT_OMIT_NO_REF DT_REF ';'
+ | devicetree DT_OMIT_NO_REF dt_ref ';'
{
struct node *target = get_node_by_ref($1, $3);
@@ -250,7 +265,7 @@ devicetree:
nodedef:
'{' proplist subnodes '}' ';'
{
- $$ = build_node($2, $3);
+ $$ = build_node($2, $3, &@$);
}
;
@@ -268,15 +283,18 @@ proplist:
propdef:
DT_PROPNODENAME '=' propdata ';'
{
- $$ = build_property($1, $3);
+ $$ = build_property($1, $3, &@$);
+ free($1);
}
| DT_PROPNODENAME ';'
{
- $$ = build_property($1, empty_data);
+ $$ = build_property($1, empty_data, &@$);
+ free($1);
}
| DT_DEL_PROP DT_PROPNODENAME ';'
{
$$ = build_property_delete($2);
+ free($2);
}
| DT_LABEL propdef
{
@@ -298,8 +316,9 @@ propdata:
{
$$ = data_merge($1, $3);
}
- | propdataprefix DT_REF
+ | propdataprefix dt_ref
{
+ $1 = data_add_marker($1, TYPE_STRING, $2);
$$ = data_add_marker($1, REF_PATH, $2);
}
| propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
@@ -353,22 +372,27 @@ arrayprefix:
DT_BITS DT_LITERAL '<'
{
unsigned long long bits;
+ enum markertype type = TYPE_UINT32;
bits = $2;
- if ((bits != 8) && (bits != 16) &&
- (bits != 32) && (bits != 64)) {
+ switch (bits) {
+ case 8: type = TYPE_UINT8; break;
+ case 16: type = TYPE_UINT16; break;
+ case 32: type = TYPE_UINT32; break;
+ case 64: type = TYPE_UINT64; break;
+ default:
ERROR(&@2, "Array elements must be"
" 8, 16, 32 or 64-bits");
bits = 32;
}
- $$.data = empty_data;
+ $$.data = data_add_marker(empty_data, type, NULL);
$$.bits = bits;
}
| '<'
{
- $$.data = empty_data;
+ $$.data = data_add_marker(empty_data, TYPE_UINT32, NULL);
$$.bits = 32;
}
| arrayprefix integer_prim
@@ -383,14 +407,19 @@ arrayprefix:
* within the mask to one (i.e. | in the
* mask), all bits are one.
*/
- if (($2 > mask) && (($2 | mask) != -1ULL))
- ERROR(&@2, "Value out of range for"
- " %d-bit array element", $1.bits);
+ if (($2 > mask) && (($2 | mask) != -1ULL)) {
+ char *loc = srcpos_string(&@2);
+ fprintf(stderr,
+ "WARNING: %s: Value 0x%016" PRIx64
+ " truncated to 0x%0*" PRIx64 "\n",
+ loc, $2, $1.bits / 4, ($2 & mask));
+ free(loc);
+ }
}
$$.data = data_append_integer($1.data, $2, $1.bits);
}
- | arrayprefix DT_REF
+ | arrayprefix dt_ref
{
uint64_t val = ~0ULL >> (64 - $1.bits);
@@ -468,8 +497,8 @@ integer_rela:
;
integer_shift:
- integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; }
- | integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; }
+ integer_shift DT_LSHIFT integer_add { $$ = ($3 < 64) ? ($1 << $3) : 0; }
+ | integer_shift DT_RSHIFT integer_add { $$ = ($3 < 64) ? ($1 >> $3) : 0; }
| integer_add
;
@@ -512,7 +541,7 @@ integer_unary:
bytestring:
/* empty */
{
- $$ = empty_data;
+ $$ = data_add_marker(empty_data, TYPE_UINT8, NULL);
}
| bytestring DT_BYTE
{
@@ -544,10 +573,12 @@ subnode:
DT_PROPNODENAME nodedef
{
$$ = name_node($2, $1);
+ free($1);
}
| DT_DEL_NODE DT_PROPNODENAME ';'
{
- $$ = name_node(build_node_delete(), $2);
+ $$ = name_node(build_node_delete(&@$), $2);
+ free($2);
}
| DT_OMIT_NO_REF subnode
{
diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c
index c36994e6eac..b3445b7d647 100644
--- a/scripts/dtc/dtc.c
+++ b/scripts/dtc/dtc.c
@@ -1,21 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
- *
- *
- * This program 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 program 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 program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
#include <sys/stat.h>
@@ -27,14 +12,16 @@
* Command line options
*/
int quiet; /* Level of quietness */
-int reservenum; /* Number of memory reservation slots */
+unsigned int reservenum;/* Number of memory reservation slots */
int minsize; /* Minimum blob size */
int padsize; /* Additional padding to blob */
-int alignsize; /* Additional padding to blob accroding to the alignsize */
+int alignsize; /* Additional padding to blob according to the alignsize */
int phandle_format = PHANDLE_EPAPR; /* Use linux,phandle or phandle properties */
int generate_symbols; /* enable symbols & fixup support */
int generate_fixups; /* suppress generation of fixups on symbol support */
int auto_label_aliases; /* auto generate labels -> aliases */
+int annotate; /* Level of annotation: 1 for input source location
+ >1 for full input source location. */
static int is_power_of_2(int x)
{
@@ -60,7 +47,7 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
/* Usage related data. */
static const char usage_synopsis[] = "dtc [options] <input file>";
-static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@Ahv";
+static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@LAThv";
static struct option const usage_long_opts[] = {
{"quiet", no_argument, NULL, 'q'},
{"in-format", a_argument, NULL, 'I'},
@@ -80,7 +67,9 @@ static struct option const usage_long_opts[] = {
{"warning", a_argument, NULL, 'W'},
{"error", a_argument, NULL, 'E'},
{"symbols", no_argument, NULL, '@'},
+ {"local-fixups", no_argument, NULL, 'L'},
{"auto-alias", no_argument, NULL, 'A'},
+ {"annotate", no_argument, NULL, 'T'},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'v'},
{NULL, no_argument, NULL, 0x0},
@@ -95,6 +84,9 @@ static const char * const usage_opts_help[] = {
"\n\tOutput formats are:\n"
"\t\tdts - device tree source text\n"
"\t\tdtb - device tree blob\n"
+#ifndef NO_YAML
+ "\t\tyaml - device tree encoded as YAML\n"
+#endif
"\t\tasm - assembler source",
"\n\tBlob version to produce, defaults to "stringify(DEFAULT_FDT_VERSION)" (for dtb and asm output)",
"\n\tOutput dependency file",
@@ -113,7 +105,9 @@ static const char * const usage_opts_help[] = {
"\n\tEnable/disable warnings (prefix with \"no-\")",
"\n\tEnable/disable errors (prefix with \"no-\")",
"\n\tEnable generation of symbols",
+ "\n\tPossibly generates a __local_fixups__ and a __fixups__ node at the root node",
"\n\tEnable auto-alias of labels",
+ "\n\tAnnotate output .dts with input source file and line (-T -T for more details)",
"\n\tPrint this help and exit",
"\n\tPrint version and exit",
NULL,
@@ -128,6 +122,10 @@ static const char *guess_type_by_name(const char *fname, const char *fallback)
return fallback;
if (!strcasecmp(s, ".dts"))
return "dts";
+ if (!strcasecmp(s, ".yaml"))
+ return "yaml";
+ if (!strcasecmp(s, ".dtbo"))
+ return "dtb";
if (!strcasecmp(s, ".dtb"))
return "dtb";
return fallback;
@@ -201,7 +199,7 @@ int main(int argc, char *argv[])
depname = optarg;
break;
case 'R':
- reservenum = strtol(optarg, NULL, 0);
+ reservenum = strtoul(optarg, NULL, 0);
break;
case 'S':
minsize = strtol(optarg, NULL, 0);
@@ -256,9 +254,17 @@ int main(int argc, char *argv[])
case '@':
generate_symbols = 1;
break;
+
+ case 'L':
+ generate_fixups = 1;
+ break;
+
case 'A':
auto_label_aliases = 1;
break;
+ case 'T':
+ annotate++;
+ break;
case 'h':
usage(NULL);
@@ -283,7 +289,9 @@ int main(int argc, char *argv[])
if (!depfile)
die("Couldn't open dependency file %s: %s\n", depname,
strerror(errno));
- fprintf(depfile, "%s:", outname);
+
+ fprint_path_escaped(depfile, outname);
+ fputc(':', depfile);
}
if (inform == NULL)
@@ -297,6 +305,8 @@ int main(int argc, char *argv[])
outform = "dts";
}
}
+ if (annotate && (!streq(inform, "dts") || !streq(outform, "dts")))
+ die("--annotate requires -I dts -O dts\n");
if (streq(inform, "dts"))
dti = dt_from_source(arg);
else if (streq(inform, "fs"))
@@ -350,6 +360,12 @@ int main(int argc, char *argv[])
if (streq(outform, "dts")) {
dt_to_source(outf, dti);
+#ifndef NO_YAML
+ } else if (streq(outform, "yaml")) {
+ if (!streq(inform, "dts"))
+ die("YAML output format requires dts input format\n");
+ dt_to_yaml(outf, dti);
+#endif
} else if (streq(outform, "dtb")) {
dt_to_blob(outf, dti, outversion);
} else if (streq(outform, "asm")) {
diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h
index 39c50a2c4fc..fcc97bbc70e 100644
--- a/scripts/dtc/dtc.h
+++ b/scripts/dtc/dtc.h
@@ -1,24 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef DTC_H
#define DTC_H
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
- *
- *
- * This program 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 program 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 program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
#include <stdio.h>
@@ -50,14 +35,15 @@
* Command line options
*/
extern int quiet; /* Level of quietness */
-extern int reservenum; /* Number of memory reservation slots */
+extern unsigned int reservenum; /* Number of memory reservation slots */
extern int minsize; /* Minimum blob size */
extern int padsize; /* Additional padding to blob */
-extern int alignsize; /* Additional padding to blob accroding to the alignsize */
+extern int alignsize; /* Additional padding to blob according to the alignsize */
extern int phandle_format; /* Use linux,phandle or phandle properties */
extern int generate_symbols; /* generate symbols for nodes with labels */
extern int generate_fixups; /* generate fixups */
extern int auto_label_aliases; /* auto generate labels -> aliases */
+extern int annotate; /* annotate .dts with input source location */
#define PHANDLE_LEGACY 0x1
#define PHANDLE_EPAPR 0x2
@@ -65,28 +51,88 @@ extern int auto_label_aliases; /* auto generate labels -> aliases */
typedef uint32_t cell_t;
+static inline bool phandle_is_valid(cell_t phandle)
+{
+ return phandle != 0 && phandle != ~0U;
+}
+
+static inline uint16_t dtb_ld16(const void *p)
+{
+ const uint8_t *bp = (const uint8_t *)p;
+
+ return ((uint16_t)bp[0] << 8)
+ | bp[1];
+}
+
+static inline uint32_t dtb_ld32(const void *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 uint64_t dtb_ld64(const void *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];
+}
+
#define streq(a, b) (strcmp((a), (b)) == 0)
#define strstarts(s, prefix) (strncmp((s), (prefix), strlen(prefix)) == 0)
#define strprefixeq(a, n, b) (strlen(b) == (n) && (memcmp(a, b, n) == 0))
+static inline bool strends(const char *str, const char *suffix)
+{
+ unsigned int len, suffix_len;
+
+ len = strlen(str);
+ suffix_len = strlen(suffix);
+ if (len < suffix_len)
+ return false;
+ return streq(str + len - suffix_len, suffix);
+}
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
/* Data blobs */
enum markertype {
+ TYPE_NONE,
REF_PHANDLE,
REF_PATH,
LABEL,
+ TYPE_UINT8,
+ TYPE_UINT16,
+ TYPE_UINT32,
+ TYPE_UINT64,
+ TYPE_STRING,
};
+static inline bool is_type_marker(enum markertype type)
+{
+ return type >= TYPE_UINT8;
+}
+
+extern const char *markername(enum markertype markertype);
+
struct marker {
enum markertype type;
- int offset;
+ unsigned int offset;
char *ref;
struct marker *next;
};
struct data {
- int len;
+ unsigned int len;
char *val;
struct marker *markers;
};
@@ -99,9 +145,26 @@ struct data {
for_each_marker(m) \
if ((m)->type == (t))
+static inline struct marker *next_type_marker(struct marker *m)
+{
+ for_each_marker(m)
+ if (is_type_marker(m->type))
+ break;
+ return m;
+}
+
+static inline size_t type_marker_length(struct marker *m)
+{
+ struct marker *next = next_type_marker(m->next);
+
+ if (next)
+ return next->offset - m->offset;
+ return 0;
+}
+
void data_free(struct data d);
-struct data data_grow_for(struct data d, int xlen);
+struct data data_grow_for(struct data d, unsigned int xlen);
struct data data_copy_mem(const char *mem, int len);
struct data data_copy_escape_string(const char *s, int len);
@@ -118,7 +181,10 @@ struct data data_append_addr(struct data d, uint64_t addr);
struct data data_append_byte(struct data d, uint8_t byte);
struct data data_append_zeroes(struct data d, int len);
struct data data_append_align(struct data d, int align);
+struct data data_insert_data(struct data d, struct marker *m, struct data old);
+struct marker *alloc_marker(unsigned int offset, enum markertype type,
+ char *ref);
struct data data_add_marker(struct data d, enum markertype type, char *ref);
bool data_is_one_string(struct data d);
@@ -147,6 +213,7 @@ struct property {
struct property *next;
struct label *labels;
+ struct srcpos *srcpos;
};
struct node {
@@ -166,6 +233,7 @@ struct node {
struct label *labels;
const struct bus_type *bus;
+ struct srcpos *srcpos;
bool omit_if_unused, is_referenced;
};
@@ -194,14 +262,16 @@ struct node {
void add_label(struct label **labels, char *label);
void delete_labels(struct label **labels);
-struct property *build_property(char *name, struct data val);
-struct property *build_property_delete(char *name);
+struct property *build_property(const char *name, struct data val,
+ struct srcpos *srcpos);
+struct property *build_property_delete(const char *name);
struct property *chain_property(struct property *first, struct property *list);
struct property *reverse_properties(struct property *first);
-struct node *build_node(struct property *proplist, struct node *children);
-struct node *build_node_delete(void);
-struct node *name_node(struct node *node, char *name);
+struct node *build_node(struct property *proplist, struct node *children,
+ struct srcpos *srcpos);
+struct node *build_node_delete(struct srcpos *srcpos);
+struct node *name_node(struct node *node, const char *name);
struct node *omit_node_if_unused(struct node *node);
struct node *reference_node(struct node *node);
struct node *chain_node(struct node *first, struct node *list);
@@ -215,12 +285,13 @@ void add_child(struct node *parent, struct node *child);
void delete_node_by_name(struct node *parent, char *name);
void delete_node(struct node *node);
void append_to_property(struct node *node,
- char *name, const void *data, int len);
+ char *name, const void *data, int len,
+ enum markertype type);
const char *get_unitname(struct node *node);
struct property *get_property(struct node *node, const char *propname);
cell_t propval_cell(struct property *prop);
-cell_t propval_cell_n(struct property *prop, int n);
+cell_t propval_cell_n(struct property *prop, unsigned int n);
struct property *get_property_by_label(struct node *tree, const char *label,
struct node **node);
struct marker *get_marker_label(struct node *tree, const char *label,
@@ -266,9 +337,9 @@ struct dt_info *build_dt_info(unsigned int dtsflags,
struct reserve_info *reservelist,
struct node *tree, uint32_t boot_cpuid_phys);
void sort_tree(struct dt_info *dti);
-void generate_label_tree(struct dt_info *dti, char *name, bool allocph);
-void generate_fixups_tree(struct dt_info *dti, char *name);
-void generate_local_fixups_tree(struct dt_info *dti, char *name);
+void generate_label_tree(struct dt_info *dti, const char *name, bool allocph);
+void generate_fixups_tree(struct dt_info *dti, const char *name);
+void generate_local_fixups_tree(struct dt_info *dti, const char *name);
/* Checks */
@@ -287,6 +358,10 @@ struct dt_info *dt_from_blob(const char *fname);
void dt_to_source(FILE *f, struct dt_info *dti);
struct dt_info *dt_from_source(const char *f);
+/* YAML source */
+
+void dt_to_yaml(FILE *f, struct dt_info *dti);
+
/* FS trees */
struct dt_info *dt_from_fs(const char *dirname);
diff --git a/scripts/dtc/fdtoverlay.c b/scripts/dtc/fdtoverlay.c
new file mode 100644
index 00000000000..ee1eb8f3ad2
--- /dev/null
+++ b/scripts/dtc/fdtoverlay.c
@@ -0,0 +1,214 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2017 Konsulko Group Inc. All rights reserved.
+ *
+ * Author:
+ * Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include <libfdt.h>
+
+#include "util.h"
+
+#define BUF_INCREMENT 65536
+
+/* Usage related data. */
+static const char usage_synopsis[] =
+ "apply a number of overlays to a base blob\n"
+ " fdtoverlay <options> [<overlay.dtbo> [<overlay.dtbo>]]";
+static const char usage_short_opts[] = "i:o:v" USAGE_COMMON_SHORT_OPTS;
+static struct option const usage_long_opts[] = {
+ {"input", required_argument, NULL, 'i'},
+ {"output", required_argument, NULL, 'o'},
+ {"verbose", no_argument, NULL, 'v'},
+ USAGE_COMMON_LONG_OPTS,
+};
+static const char * const usage_opts_help[] = {
+ "Input base DT blob",
+ "Output DT blob",
+ "Verbose messages",
+ USAGE_COMMON_OPTS_HELP
+};
+
+int verbose = 0;
+
+static void *apply_one(char *base, const char *overlay, size_t *buf_len,
+ const char *name)
+{
+ char *tmp = NULL;
+ char *tmpo;
+ int ret;
+ bool has_symbols;
+
+ /*
+ * We take copies first, because a failed apply can trash
+ * both the base blob and the overlay
+ */
+ tmpo = xmalloc(fdt_totalsize(overlay));
+
+ do {
+ tmp = xrealloc(tmp, *buf_len);
+ ret = fdt_open_into(base, tmp, *buf_len);
+ if (ret) {
+ fprintf(stderr,
+ "\nFailed to make temporary copy: %s\n",
+ fdt_strerror(ret));
+ goto fail;
+ }
+ ret = fdt_path_offset(tmp, "/__symbols__");
+ has_symbols = ret >= 0;
+
+ memcpy(tmpo, overlay, fdt_totalsize(overlay));
+
+ ret = fdt_overlay_apply(tmp, tmpo);
+ if (ret == -FDT_ERR_NOSPACE) {
+ *buf_len += BUF_INCREMENT;
+ }
+ } while (ret == -FDT_ERR_NOSPACE);
+
+ if (ret) {
+ fprintf(stderr, "\nFailed to apply '%s': %s\n",
+ name, fdt_strerror(ret));
+ if (!has_symbols) {
+ fprintf(stderr,
+ "base blob does not have a '/__symbols__' node, "
+ "make sure you have compiled the base blob with '-@' option\n");
+ }
+ goto fail;
+ }
+
+ free(base);
+ free(tmpo);
+ return tmp;
+
+fail:
+ free(tmpo);
+ if (tmp)
+ free(tmp);
+
+ return NULL;
+}
+static int do_fdtoverlay(const char *input_filename,
+ const char *output_filename,
+ int argc, char *argv[])
+{
+ char *blob = NULL;
+ char **ovblob = NULL;
+ size_t buf_len;
+ int i, ret = -1;
+
+ blob = utilfdt_read(input_filename, &buf_len);
+ if (!blob) {
+ fprintf(stderr, "\nFailed to read '%s'\n", input_filename);
+ goto out_err;
+ }
+ if (fdt_totalsize(blob) > buf_len) {
+ fprintf(stderr,
+ "\nBase blob is incomplete (%lu / %" PRIu32 " bytes read)\n",
+ (unsigned long)buf_len, fdt_totalsize(blob));
+ goto out_err;
+ }
+
+ /* allocate blob pointer array */
+ ovblob = xmalloc(sizeof(*ovblob) * argc);
+ memset(ovblob, 0, sizeof(*ovblob) * argc);
+
+ /* read and keep track of the overlay blobs */
+ for (i = 0; i < argc; i++) {
+ size_t ov_len;
+ ovblob[i] = utilfdt_read(argv[i], &ov_len);
+ if (!ovblob[i]) {
+ fprintf(stderr, "\nFailed to read '%s'\n", argv[i]);
+ goto out_err;
+ }
+ if (fdt_totalsize(ovblob[i]) > ov_len) {
+ fprintf(stderr,
+"\nOverlay '%s' is incomplete (%lu / %" PRIu32 " bytes read)\n",
+ argv[i], (unsigned long)ov_len,
+ fdt_totalsize(ovblob[i]));
+ goto out_err;
+ }
+ }
+
+ buf_len = fdt_totalsize(blob);
+
+ /* apply the overlays in sequence */
+ for (i = 0; i < argc; i++) {
+ blob = apply_one(blob, ovblob[i], &buf_len, argv[i]);
+ if (!blob)
+ goto out_err;
+ }
+
+ fdt_pack(blob);
+ ret = utilfdt_write(output_filename, blob);
+ if (ret)
+ fprintf(stderr, "\nFailed to write '%s'\n",
+ output_filename);
+
+out_err:
+ if (ovblob) {
+ for (i = 0; i < argc; i++) {
+ if (ovblob[i])
+ free(ovblob[i]);
+ }
+ free(ovblob);
+ }
+ free(blob);
+
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ int opt, i;
+ char *input_filename = NULL;
+ char *output_filename = NULL;
+
+ while ((opt = util_getopt_long()) != EOF) {
+ switch (opt) {
+ case_USAGE_COMMON_FLAGS
+
+ case 'i':
+ input_filename = optarg;
+ break;
+ case 'o':
+ output_filename = optarg;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ }
+ }
+
+ if (!input_filename)
+ usage("missing input file");
+
+ if (!output_filename)
+ usage("missing output file");
+
+ argv += optind;
+ argc -= optind;
+
+ if (argc <= 0)
+ usage("missing overlay file(s)");
+
+ if (verbose) {
+ printf("input = %s\n", input_filename);
+ printf("output = %s\n", output_filename);
+ for (i = 0; i < argc; i++)
+ printf("overlay[%d] = %s\n", i, argv[i]);
+ }
+
+ if (do_fdtoverlay(input_filename, output_filename, argc, argv))
+ return 1;
+
+ return 0;
+}
diff --git a/scripts/dtc/flattree.c b/scripts/dtc/flattree.c
index 086c5abf10f..ae3f9dec82f 100644
--- a/scripts/dtc/flattree.c
+++ b/scripts/dtc/flattree.c
@@ -1,21 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
- *
- *
- * This program 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 program 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 program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
#include "dtc.h"
@@ -139,7 +124,8 @@ static void asm_emit_cell(void *e, cell_t val)
{
FILE *f = e;
- fprintf(f, "\t.byte 0x%02x; .byte 0x%02x; .byte 0x%02x; .byte 0x%02x\n",
+ fprintf(f, "\t.byte\t0x%02x\n" "\t.byte\t0x%02x\n"
+ "\t.byte\t0x%02x\n" "\t.byte\t0x%02x\n",
(val >> 24) & 0xff, (val >> 16) & 0xff,
(val >> 8) & 0xff, val & 0xff);
}
@@ -149,9 +135,9 @@ static void asm_emit_string(void *e, const char *str, int len)
FILE *f = e;
if (len != 0)
- fprintf(f, "\t.string\t\"%.*s\"\n", len, str);
+ fprintf(f, "\t.asciz\t\"%.*s\"\n", len, str);
else
- fprintf(f, "\t.string\t\"%s\"\n", str);
+ fprintf(f, "\t.asciz\t\"%s\"\n", str);
}
static void asm_emit_align(void *e, int a)
@@ -164,14 +150,14 @@ static void asm_emit_align(void *e, int a)
static void asm_emit_data(void *e, struct data d)
{
FILE *f = e;
- int off = 0;
+ unsigned int off = 0;
struct marker *m = d.markers;
for_each_marker_of_type(m, LABEL)
emit_offset_label(f, m->ref, m->offset);
while ((d.len - off) >= sizeof(uint32_t)) {
- asm_emit_cell(e, fdt32_to_cpu(*((fdt32_t *)(d.val+off))));
+ asm_emit_cell(e, dtb_ld32(d.val + off));
off += sizeof(uint32_t);
}
@@ -234,7 +220,7 @@ static struct emitter asm_emitter = {
static int stringtable_insert(struct data *d, const char *str)
{
- int i;
+ unsigned int i;
/* FIXME: do this more efficiently? */
@@ -310,7 +296,7 @@ static struct data flatten_reserve_list(struct reserve_info *reservelist,
{
struct reserve_info *re;
struct data d = empty_data;
- int j;
+ unsigned int j;
for (re = reservelist; re; re = re->next) {
d = data_append_re(d, re->address, re->size);
@@ -360,7 +346,7 @@ static void make_fdt_header(struct fdt_header *fdt,
void dt_to_blob(FILE *f, struct dt_info *dti, int version)
{
struct version_info *vi = NULL;
- int i;
+ unsigned int i;
struct data blob = empty_data;
struct data reservebuf = empty_data;
struct data dtbuf = empty_data;
@@ -393,7 +379,7 @@ void dt_to_blob(FILE *f, struct dt_info *dti, int version)
padlen = 0;
if (quiet < 1)
fprintf(stderr,
- "Warning: blob size %d >= minimum size %d\n",
+ "Warning: blob size %"PRIu32" >= minimum size %d\n",
fdt32_to_cpu(fdt.totalsize), minsize);
}
}
@@ -453,7 +439,7 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf)
while (p < (strbuf.val + strbuf.len)) {
len = strlen(p);
- fprintf(f, "\t.string \"%s\"\n", p);
+ fprintf(f, "\t.asciz \"%s\"\n", p);
p += len+1;
}
}
@@ -461,7 +447,7 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf)
void dt_to_asm(FILE *f, struct dt_info *dti, int version)
{
struct version_info *vi = NULL;
- int i;
+ unsigned int i;
struct data strbuf = empty_data;
struct reserve_info *re;
const char *symprefix = "dt";
@@ -517,7 +503,7 @@ void dt_to_asm(FILE *f, struct dt_info *dti, int version)
* Reserve map entries.
* Align the reserve map to a doubleword boundary.
* Each entry is an (address, size) pair of u64 values.
- * Always supply a zero-sized temination entry.
+ * Always supply a zero-sized termination entry.
*/
asm_emit_align(f, 8);
emit_label(f, symprefix, "reserve_map");
@@ -525,7 +511,7 @@ void dt_to_asm(FILE *f, struct dt_info *dti, int version)
fprintf(f, "/* Memory reserve map from source file */\n");
/*
- * Use .long on high and low halfs of u64s to avoid .quad
+ * Use .long on high and low halves of u64s to avoid .quad
* as it appears .quad isn't available in some assemblers.
*/
for (re = dti->reservelist; re; re = re->next) {
@@ -618,11 +604,11 @@ static void flat_realign(struct inbuf *inb, int align)
die("Premature end of data parsing flat device tree\n");
}
-static char *flat_read_string(struct inbuf *inb)
+static const char *flat_read_string(struct inbuf *inb)
{
int len = 0;
const char *p = inb->ptr;
- char *str;
+ const char *str;
do {
if (p >= inb->limit)
@@ -630,7 +616,7 @@ static char *flat_read_string(struct inbuf *inb)
len++;
} while ((*p++) != '\0');
- str = xstrdup(inb->ptr);
+ str = inb->ptr;
inb->ptr += len;
@@ -692,7 +678,7 @@ static struct property *flat_read_property(struct inbuf *dtbuf,
val = flat_read_data(dtbuf, proplen);
- return build_property(name, val);
+ return build_property(name, val, NULL);
}
static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
@@ -723,7 +709,8 @@ static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
return reservelist;
}
-static char *nodename_from_path(const char *ppath, const char *cpath)
+
+static const char *nodename_from_path(const char *ppath, const char *cpath)
{
int plen;
@@ -737,7 +724,7 @@ static char *nodename_from_path(const char *ppath, const char *cpath)
if (!streq(ppath, "/"))
plen++;
- return xstrdup(cpath + plen);
+ return cpath + plen;
}
static struct node *unflatten_tree(struct inbuf *dtbuf,
@@ -745,17 +732,18 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
const char *parent_flatname, int flags)
{
struct node *node;
- char *flatname;
+ const char *flatname;
uint32_t val;
- node = build_node(NULL, NULL);
+ node = build_node(NULL, NULL, NULL);
flatname = flat_read_string(dtbuf);
if (flags & FTF_FULLPATH)
- node->name = nodename_from_path(parent_flatname, flatname);
+ node->name = xstrdup(nodename_from_path(parent_flatname,
+ flatname));
else
- node->name = flatname;
+ node->name = xstrdup(flatname);
do {
struct property *prop;
@@ -797,10 +785,6 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
}
} while (val != FDT_END_NODE);
- if (node->name != flatname) {
- free(flatname);
- }
-
return node;
}
diff --git a/scripts/dtc/fstree.c b/scripts/dtc/fstree.c
index ae7d06c3c49..0f9a534bacd 100644
--- a/scripts/dtc/fstree.c
+++ b/scripts/dtc/fstree.c
@@ -1,21 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
- *
- *
- * This program 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 program 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 program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
#include "dtc.h"
@@ -34,7 +19,7 @@ static struct node *read_fstree(const char *dirname)
if (!d)
die("Couldn't opendir() \"%s\": %s\n", dirname, strerror(errno));
- tree = build_node(NULL, NULL);
+ tree = build_node(NULL, NULL, NULL);
while ((de = readdir(d)) != NULL) {
char *tmpname;
@@ -45,7 +30,7 @@ static struct node *read_fstree(const char *dirname)
tmpname = join_path(dirname, de->d_name);
- if (lstat(tmpname, &st) < 0)
+ if (stat(tmpname, &st) < 0)
die("stat(%s): %s\n", tmpname, strerror(errno));
if (S_ISREG(st.st_mode)) {
@@ -58,9 +43,10 @@ static struct node *read_fstree(const char *dirname)
"WARNING: Cannot open %s: %s\n",
tmpname, strerror(errno));
} else {
- prop = build_property(xstrdup(de->d_name),
+ prop = build_property(de->d_name,
data_copy_file(pfile,
- st.st_size));
+ st.st_size),
+ NULL);
add_property(tree, prop);
fclose(pfile);
}
diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c
index 28f4e1a5f15..95f644c31f9 100644
--- a/scripts/dtc/libfdt/fdt.c
+++ b/scripts/dtc/libfdt/fdt.c
@@ -19,9 +19,16 @@ int32_t fdt_ro_probe_(const void *fdt)
{
uint32_t totalsize = fdt_totalsize(fdt);
+ if (can_assume(VALID_DTB))
+ return totalsize;
+
+ /* The device tree must be at an 8-byte aligned address */
+ if ((uintptr_t)fdt & 7)
+ return -FDT_ERR_ALIGNMENT;
+
if (fdt_magic(fdt) == FDT_MAGIC) {
/* Complete tree */
- if (fdt_chk_version()) {
+ if (!can_assume(LATEST)) {
if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
return -FDT_ERR_BADVERSION;
if (fdt_last_comp_version(fdt) >
@@ -30,7 +37,7 @@ int32_t fdt_ro_probe_(const void *fdt)
}
} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
/* Unfinished sequential-write blob */
- if (fdt_size_dt_struct(fdt) == 0)
+ if (!can_assume(VALID_INPUT) && fdt_size_dt_struct(fdt) == 0)
return -FDT_ERR_BADSTATE;
} else {
return -FDT_ERR_BADMAGIC;
@@ -75,17 +82,21 @@ size_t fdt_header_size_(uint32_t version)
size_t fdt_header_size(const void *fdt)
{
- return fdt_chk_version() ? fdt_header_size_(fdt_version(fdt)) :
- FDT_V17_SIZE;
+ return can_assume(LATEST) ? FDT_V17_SIZE :
+ fdt_header_size_(fdt_version(fdt));
}
int fdt_check_header(const void *fdt)
{
size_t hdrsize;
+ /* The device tree must be at an 8-byte aligned address */
+ if ((uintptr_t)fdt & 7)
+ return -FDT_ERR_ALIGNMENT;
+
if (fdt_magic(fdt) != FDT_MAGIC)
return -FDT_ERR_BADMAGIC;
- if (fdt_chk_version()) {
+ if (!can_assume(LATEST)) {
if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
|| (fdt_last_comp_version(fdt) >
FDT_LAST_SUPPORTED_VERSION))
@@ -94,8 +105,7 @@ int fdt_check_header(const void *fdt)
return -FDT_ERR_BADVERSION;
}
hdrsize = fdt_header_size(fdt);
- if (fdt_chk_basic()) {
-
+ if (!can_assume(VALID_DTB)) {
if ((fdt_totalsize(fdt) < hdrsize)
|| (fdt_totalsize(fdt) > INT_MAX))
return -FDT_ERR_TRUNCATED;
@@ -104,11 +114,9 @@ int fdt_check_header(const void *fdt)
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 (!can_assume(LATEST) && fdt_version(fdt) < 17) {
if (!check_off_(hdrsize, fdt_totalsize(fdt),
fdt_off_dt_struct(fdt)))
return -FDT_ERR_TRUNCATED;
@@ -137,13 +145,13 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
if (offset < 0)
return NULL;
- if (fdt_chk_basic())
+ if (!can_assume(VALID_INPUT))
if ((absoffset < uoffset)
|| ((absoffset + len) < absoffset)
|| (absoffset + len) > fdt_totalsize(fdt))
return NULL;
- if (!fdt_chk_version() || fdt_version(fdt) >= 0x11)
+ if (can_assume(LATEST) || fdt_version(fdt) >= 0x11)
if (((uoffset + len) < uoffset)
|| ((offset + len) > fdt_size_dt_struct(fdt)))
return NULL;
@@ -154,13 +162,13 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
{
const fdt32_t *tagp, *lenp;
- uint32_t tag;
+ uint32_t tag, len, sum;
int offset = startoffset;
const char *p;
*nextoffset = -FDT_ERR_TRUNCATED;
tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
- if (fdt_chk_basic() && !tagp)
+ if (!can_assume(VALID_DTB) && !tagp)
return FDT_END; /* premature end */
tag = fdt32_to_cpu(*tagp);
offset += FDT_TAGSIZE;
@@ -172,20 +180,27 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
do {
p = fdt_offset_ptr(fdt, offset++, 1);
} while (p && (*p != '\0'));
- if (fdt_chk_basic() && !p)
+ if (!can_assume(VALID_DTB) && !p)
return FDT_END; /* premature end */
break;
case FDT_PROP:
lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
- if (fdt_chk_basic() && !lenp)
+ if (!can_assume(VALID_DTB) && !lenp)
return FDT_END; /* premature end */
+
+ len = fdt32_to_cpu(*lenp);
+ sum = len + offset;
+ if (!can_assume(VALID_DTB) &&
+ (INT_MAX <= sum || sum < (uint32_t) offset))
+ return FDT_END; /* premature end */
+
/* skip-name offset, length and value */
- offset += sizeof(struct fdt_property) - FDT_TAGSIZE
- + fdt32_to_cpu(*lenp);
- if (fdt_chk_version() &&
- fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 &&
- ((offset - fdt32_to_cpu(*lenp)) % 8) != 0)
+ offset += sizeof(struct fdt_property) - FDT_TAGSIZE + len;
+
+ if (!can_assume(LATEST) &&
+ fdt_version(fdt) < 0x10 && len >= 8 &&
+ ((offset - len) % 8) != 0)
offset += 4;
break;
@@ -198,8 +213,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
return FDT_END;
}
- if (fdt_chk_basic() &&
- !fdt_offset_ptr(fdt, startoffset, offset - startoffset))
+ if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset))
return FDT_END; /* premature end */
*nextoffset = FDT_TAGALIGN(offset);
@@ -208,8 +222,11 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
int fdt_check_node_offset_(const void *fdt, int offset)
{
- if ((offset < 0) || (offset % FDT_TAGSIZE)
- || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
+ if (!can_assume(VALID_INPUT)
+ && ((offset < 0) || (offset % FDT_TAGSIZE)))
+ return -FDT_ERR_BADOFFSET;
+
+ if (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)
return -FDT_ERR_BADOFFSET;
return offset;
@@ -217,8 +234,11 @@ int fdt_check_node_offset_(const void *fdt, int offset)
int fdt_check_prop_offset_(const void *fdt, int offset)
{
- if ((offset < 0) || (offset % FDT_TAGSIZE)
- || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP))
+ if (!can_assume(VALID_INPUT)
+ && ((offset < 0) || (offset % FDT_TAGSIZE)))
+ return -FDT_ERR_BADOFFSET;
+
+ if (fdt_next_tag(fdt, offset, &offset) != FDT_PROP)
return -FDT_ERR_BADOFFSET;
return offset;
@@ -292,21 +312,21 @@ int fdt_next_subnode(const void *fdt, int offset)
return offset;
}
-const char *fdt_find_string_(const char *strtab, int tabsize, const char *s)
+const char *fdt_find_string_len_(const char *strtab, int tabsize, const char *s,
+ int slen)
{
- int len = strlen(s) + 1;
- const char *last = strtab + tabsize - len;
+ const char *last = strtab + tabsize - (slen + 1);
const char *p;
for (p = strtab; p <= last; p++)
- if (memcmp(p, s, len) == 0)
+ if (memcmp(p, s, slen) == 0 && p[slen] == '\0')
return p;
return NULL;
}
int fdt_move(const void *fdt, void *buf, int bufsize)
{
- if (fdt_chk_basic() && bufsize < 0)
+ if (!can_assume(VALID_INPUT) && bufsize < 0)
return -FDT_ERR_NOSPACE;
FDT_RO_PROBE(fdt);
diff --git a/scripts/dtc/libfdt/fdt.h b/scripts/dtc/libfdt/fdt.h
index f2e68807f27..c6e4d7838dc 100644
--- a/scripts/dtc/libfdt/fdt.h
+++ b/scripts/dtc/libfdt/fdt.h
@@ -7,7 +7,7 @@
* Copyright 2012 Kim Phillips, Freescale Semiconductor.
*/
-#ifndef __ASSEMBLY__
+#ifndef __ASSEMBLER__
struct fdt_header {
fdt32_t magic; /* magic word FDT_MAGIC */
@@ -45,7 +45,7 @@ struct fdt_property {
char data[0];
};
-#endif /* !__ASSEMBLY */
+#endif /* !__ASSEMBLER__ */
#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */
#define FDT_TAGSIZE sizeof(fdt32_t)
diff --git a/scripts/dtc/libfdt/fdt_addresses.c b/scripts/dtc/libfdt/fdt_addresses.c
index 9a82cd0ba2f..c40ba094f1f 100644
--- a/scripts/dtc/libfdt/fdt_addresses.c
+++ b/scripts/dtc/libfdt/fdt_addresses.c
@@ -73,7 +73,7 @@ int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
/* check validity of address */
prop = data;
if (addr_cells == 1) {
- if ((addr > UINT32_MAX) || ((UINT32_MAX + 1 - addr) < size))
+ if ((addr > UINT32_MAX) || (((uint64_t) UINT32_MAX + 1 - addr) < size))
return -FDT_ERR_BADVALUE;
fdt32_st(prop, (uint32_t)addr);
diff --git a/scripts/dtc/libfdt/fdt_overlay.c b/scripts/dtc/libfdt/fdt_overlay.c
index 7a65c35af6f..b59b365c189 100644
--- a/scripts/dtc/libfdt/fdt_overlay.c
+++ b/scripts/dtc/libfdt/fdt_overlay.c
@@ -40,37 +40,22 @@ static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
return fdt32_to_cpu(*val);
}
-/**
- * overlay_get_target - retrieves the offset of a fragment's target
- * @fdt: Base device tree blob
- * @fdto: Device tree overlay blob
- * @fragment: node offset of the fragment in the overlay
- * @pathp: pointer which receives the path of the target (or NULL)
- *
- * overlay_get_target() retrieves the target offset in the base
- * device tree of a fragment, no matter how the actual targeting is
- * done (through a phandle or a path)
- *
- * returns:
- * the targeted node offset in the base device tree
- * Negative error code on error
- */
-static int overlay_get_target(const void *fdt, const void *fdto,
- int fragment, char const **pathp)
+int fdt_overlay_target_offset(const void *fdt, const void *fdto,
+ int fragment_offset, char const **pathp)
{
uint32_t phandle;
const char *path = NULL;
int path_len = 0, ret;
/* Try first to do a phandle based lookup */
- phandle = overlay_get_target_phandle(fdto, fragment);
+ phandle = overlay_get_target_phandle(fdto, fragment_offset);
if (phandle == (uint32_t)-1)
return -FDT_ERR_BADPHANDLE;
/* no phandle, try path */
if (!phandle) {
/* And then a path based lookup */
- path = fdt_getprop(fdto, fragment, "target-path", &path_len);
+ path = fdt_getprop(fdto, fragment_offset, "target-path", &path_len);
if (path)
ret = fdt_path_offset(fdt, path);
else
@@ -116,26 +101,22 @@ static int overlay_get_target(const void *fdt, const void *fdto,
static int overlay_phandle_add_offset(void *fdt, int node,
const char *name, uint32_t delta)
{
- const fdt32_t *val;
- uint32_t adj_val;
+ fdt32_t *valp, val;
int len;
- val = fdt_getprop(fdt, node, name, &len);
- if (!val)
+ valp = fdt_getprop_w(fdt, node, name, &len);
+ if (!valp)
return len;
- if (len != sizeof(*val))
+ if (len != sizeof(val))
return -FDT_ERR_BADPHANDLE;
- adj_val = fdt32_to_cpu(*val);
- if ((adj_val + delta) < adj_val)
+ val = fdt32_ld(valp);
+ if (val + delta < val || val + delta == (uint32_t)-1)
return -FDT_ERR_NOPHANDLES;
- adj_val += delta;
- if (adj_val == (uint32_t)-1)
- return -FDT_ERR_NOPHANDLES;
-
- return fdt_setprop_inplace_u32(fdt, node, name, adj_val);
+ fdt32_st(valp, val + delta);
+ return 0;
}
/**
@@ -228,8 +209,8 @@ static int overlay_update_local_node_references(void *fdto,
fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) {
const fdt32_t *fixup_val;
- const char *tree_val;
const char *name;
+ char *tree_val;
int fixup_len;
int tree_len;
int i;
@@ -243,7 +224,7 @@ static int overlay_update_local_node_references(void *fdto,
return -FDT_ERR_BADOVERLAY;
fixup_len /= sizeof(uint32_t);
- tree_val = fdt_getprop(fdto, tree_node, name, &tree_len);
+ tree_val = fdt_getprop_w(fdto, tree_node, name, &tree_len);
if (!tree_val) {
if (tree_len == -FDT_ERR_NOTFOUND)
return -FDT_ERR_BADOVERLAY;
@@ -252,33 +233,15 @@ static int overlay_update_local_node_references(void *fdto,
}
for (i = 0; i < fixup_len; i++) {
- fdt32_t adj_val;
- uint32_t poffset;
+ fdt32_t *refp;
- poffset = fdt32_to_cpu(fixup_val[i]);
+ refp = (fdt32_t *)(tree_val + fdt32_ld_(fixup_val + i));
/*
- * phandles to fixup can be unaligned.
- *
- * Use a memcpy for the architectures that do
- * not support unaligned accesses.
+ * phandles to fixup can be unaligned, so use
+ * fdt32_{ld,st}() to read/write them.
*/
- memcpy(&adj_val, tree_val + poffset, sizeof(adj_val));
-
- adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta);
-
- ret = fdt_setprop_inplace_namelen_partial(fdto,
- tree_node,
- name,
- strlen(name),
- poffset,
- &adj_val,
- sizeof(adj_val));
- if (ret == -FDT_ERR_NOSPACE)
- return -FDT_ERR_BADOVERLAY;
-
- if (ret)
- return ret;
+ fdt32_st(refp, fdt32_ld(refp) + delta);
}
}
@@ -344,7 +307,6 @@ static int overlay_update_local_references(void *fdto, uint32_t delta)
/**
* overlay_fixup_one_phandle - Set an overlay phandle to the base one
- * @fdt: Base Device Tree blob
* @fdto: Device tree overlay blob
* @symbols_off: Node offset of the symbols node in the base device tree
* @path: Path to a node holding a phandle in the overlay
@@ -352,7 +314,7 @@ static int overlay_update_local_references(void *fdto, uint32_t delta)
* @name: Name of the property holding the phandle reference in the overlay
* @name_len: number of name characters to consider
* @poffset: Offset within the overlay property where the phandle is stored
- * @label: Label of the node referenced by the phandle
+ * @phandle: Phandle referencing the node
*
* overlay_fixup_one_phandle() resolves an overlay phandle pointing to
* a node in the base device tree.
@@ -365,34 +327,17 @@ static int overlay_update_local_references(void *fdto, uint32_t delta)
* 0 on success
* Negative error code on failure
*/
-static int overlay_fixup_one_phandle(void *fdt, void *fdto,
- int symbols_off,
+static int overlay_fixup_one_phandle(void *fdto, int symbols_off,
const char *path, uint32_t path_len,
const char *name, uint32_t name_len,
- int poffset, const char *label)
+ int poffset, uint32_t phandle)
{
- const char *symbol_path;
- uint32_t phandle;
fdt32_t phandle_prop;
- int symbol_off, fixup_off;
- int prop_len;
+ int fixup_off;
if (symbols_off < 0)
return symbols_off;
- symbol_path = fdt_getprop(fdt, symbols_off, label,
- &prop_len);
- if (!symbol_path)
- return prop_len;
-
- symbol_off = fdt_path_offset(fdt, symbol_path);
- if (symbol_off < 0)
- return symbol_off;
-
- phandle = fdt_get_phandle(fdt, symbol_off);
- if (!phandle)
- return -FDT_ERR_NOTFOUND;
-
fixup_off = fdt_path_offset_namelen(fdto, path, path_len);
if (fixup_off == -FDT_ERR_NOTFOUND)
return -FDT_ERR_BADOVERLAY;
@@ -404,7 +349,7 @@ static int overlay_fixup_one_phandle(void *fdt, void *fdto,
name, name_len, poffset,
&phandle_prop,
sizeof(phandle_prop));
-};
+}
/**
* overlay_fixup_phandle - Set an overlay phandle to the base one
@@ -431,6 +376,10 @@ static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
const char *value;
const char *label;
int len;
+ const char *symbol_path;
+ int prop_len;
+ int symbol_off;
+ uint32_t phandle;
value = fdt_getprop_by_offset(fdto, property,
&label, &len);
@@ -441,6 +390,18 @@ static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
return len;
}
+ symbol_path = fdt_getprop(fdt, symbols_off, label, &prop_len);
+ if (!symbol_path)
+ return prop_len;
+
+ symbol_off = fdt_path_offset(fdt, symbol_path);
+ if (symbol_off < 0)
+ return symbol_off;
+
+ phandle = fdt_get_phandle(fdt, symbol_off);
+ if (!phandle)
+ return -FDT_ERR_NOTFOUND;
+
do {
const char *path, *name, *fixup_end;
const char *fixup_str = value;
@@ -480,9 +441,9 @@ static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
if ((*endptr != '\0') || (endptr <= (sep + 1)))
return -FDT_ERR_BADOVERLAY;
- ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off,
+ ret = overlay_fixup_one_phandle(fdto, symbols_off,
path, path_len, name, name_len,
- poffset, label);
+ poffset, phandle);
if (ret)
return ret;
} while (len > 0);
@@ -535,6 +496,255 @@ static int overlay_fixup_phandles(void *fdt, void *fdto)
return 0;
}
+/**
+ * overlay_adjust_local_conflicting_phandle: Changes a phandle value
+ * @fdto: Device tree overlay
+ * @node: The node the phandle is set for
+ * @fdt_phandle: The new value for the phandle
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int overlay_adjust_local_conflicting_phandle(void *fdto, int node,
+ uint32_t fdt_phandle)
+{
+ const fdt32_t *php;
+ int len, ret;
+
+ php = fdt_getprop(fdto, node, "phandle", &len);
+ if (php && len == sizeof(*php)) {
+ ret = fdt_setprop_inplace_u32(fdto, node, "phandle", fdt_phandle);
+ if (ret)
+ return ret;
+ }
+
+ php = fdt_getprop(fdto, node, "linux,phandle", &len);
+ if (php && len == sizeof(*php)) {
+ ret = fdt_setprop_inplace_u32(fdto, node, "linux,phandle", fdt_phandle);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * overlay_update_node_conflicting_references - Recursively replace phandle values
+ * @fdto: Device tree overlay blob
+ * @tree_node: Node to recurse into
+ * @fixup_node: Node offset of the matching local fixups node
+ * @fdt_phandle: Value to replace phandles with
+ * @fdto_phandle: Value to be replaced
+ *
+ * Replaces all phandles with value @fdto_phandle by @fdt_phandle.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int overlay_update_node_conflicting_references(void *fdto, int tree_node,
+ int fixup_node,
+ uint32_t fdt_phandle,
+ uint32_t fdto_phandle)
+{
+ int fixup_prop;
+ int fixup_child;
+ int ret;
+
+ fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) {
+ const fdt32_t *fixup_val;
+ const char *name;
+ char *tree_val;
+ int fixup_len;
+ int tree_len;
+ int i;
+
+ fixup_val = fdt_getprop_by_offset(fdto, fixup_prop,
+ &name, &fixup_len);
+ if (!fixup_val)
+ return fixup_len;
+
+ if (fixup_len % sizeof(uint32_t))
+ return -FDT_ERR_BADOVERLAY;
+ fixup_len /= sizeof(uint32_t);
+
+ tree_val = fdt_getprop_w(fdto, tree_node, name, &tree_len);
+ if (!tree_val) {
+ if (tree_len == -FDT_ERR_NOTFOUND)
+ return -FDT_ERR_BADOVERLAY;
+
+ return tree_len;
+ }
+
+ for (i = 0; i < fixup_len; i++) {
+ fdt32_t *refp;
+ uint32_t valp;
+
+ refp = (fdt32_t *)(tree_val + fdt32_ld_(fixup_val + i));
+ valp = fdt32_ld(refp);
+
+ if (valp == fdto_phandle)
+ fdt32_st(refp, fdt_phandle);
+ }
+ }
+
+ fdt_for_each_subnode(fixup_child, fdto, fixup_node) {
+ const char *fixup_child_name = fdt_get_name(fdto, fixup_child, NULL);
+ int tree_child;
+
+ tree_child = fdt_subnode_offset(fdto, tree_node, fixup_child_name);
+
+ if (tree_child == -FDT_ERR_NOTFOUND)
+ return -FDT_ERR_BADOVERLAY;
+ if (tree_child < 0)
+ return tree_child;
+
+ ret = overlay_update_node_conflicting_references(fdto, tree_child,
+ fixup_child,
+ fdt_phandle,
+ fdto_phandle);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * overlay_update_local_conflicting_references - Recursively replace phandle values
+ * @fdto: Device tree overlay blob
+ * @fdt_phandle: Value to replace phandles with
+ * @fdto_phandle: Value to be replaced
+ *
+ * Replaces all phandles with value @fdto_phandle by @fdt_phandle.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int overlay_update_local_conflicting_references(void *fdto,
+ uint32_t fdt_phandle,
+ uint32_t fdto_phandle)
+{
+ int fixups;
+
+ fixups = fdt_path_offset(fdto, "/__local_fixups__");
+ if (fixups == -FDT_ERR_NOTFOUND)
+ return 0;
+ if (fixups < 0)
+ return fixups;
+
+ return overlay_update_node_conflicting_references(fdto, 0, fixups,
+ fdt_phandle,
+ fdto_phandle);
+}
+
+/**
+ * overlay_prevent_phandle_overwrite_node - Helper function for overlay_prevent_phandle_overwrite
+ * @fdt: Base Device tree blob
+ * @fdtnode: Node in fdt that is checked for an overwrite
+ * @fdto: Device tree overlay blob
+ * @fdtonode: Node in fdto matching @fdtnode
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int overlay_prevent_phandle_overwrite_node(void *fdt, int fdtnode,
+ void *fdto, int fdtonode)
+{
+ uint32_t fdt_phandle, fdto_phandle;
+ int fdtochild;
+
+ fdt_phandle = fdt_get_phandle(fdt, fdtnode);
+ fdto_phandle = fdt_get_phandle(fdto, fdtonode);
+
+ if (fdt_phandle && fdto_phandle) {
+ int ret;
+
+ ret = overlay_adjust_local_conflicting_phandle(fdto, fdtonode,
+ fdt_phandle);
+ if (ret)
+ return ret;
+
+ ret = overlay_update_local_conflicting_references(fdto,
+ fdt_phandle,
+ fdto_phandle);
+ if (ret)
+ return ret;
+ }
+
+ fdt_for_each_subnode(fdtochild, fdto, fdtonode) {
+ const char *name = fdt_get_name(fdto, fdtochild, NULL);
+ int fdtchild;
+ int ret;
+
+ fdtchild = fdt_subnode_offset(fdt, fdtnode, name);
+ if (fdtchild == -FDT_ERR_NOTFOUND)
+ /*
+ * no further overwrites possible here as this node is
+ * new
+ */
+ continue;
+
+ ret = overlay_prevent_phandle_overwrite_node(fdt, fdtchild,
+ fdto, fdtochild);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * overlay_prevent_phandle_overwrite - Fixes overlay phandles to not overwrite base phandles
+ * @fdt: Base Device Tree blob
+ * @fdto: Device tree overlay blob
+ *
+ * Checks recursively if applying fdto overwrites phandle values in the base
+ * dtb. When such a phandle is found, the fdto is changed to use the fdt's
+ * phandle value to not break references in the base.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int overlay_prevent_phandle_overwrite(void *fdt, void *fdto)
+{
+ int fragment;
+
+ fdt_for_each_subnode(fragment, fdto, 0) {
+ int overlay;
+ int target;
+ int ret;
+
+ overlay = fdt_subnode_offset(fdto, fragment, "__overlay__");
+ if (overlay == -FDT_ERR_NOTFOUND)
+ continue;
+
+ if (overlay < 0)
+ return overlay;
+
+ target = fdt_overlay_target_offset(fdt, fdto, fragment, NULL);
+ if (target == -FDT_ERR_NOTFOUND)
+ /*
+ * The subtree doesn't exist in the base, so nothing
+ * will be overwritten.
+ */
+ continue;
+ else if (target < 0)
+ return target;
+
+ ret = overlay_prevent_phandle_overwrite_node(fdt, target,
+ fdto, overlay);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
/**
* overlay_apply_node - Merges a node into the base device tree
* @fdt: Base Device Tree blob
@@ -636,7 +846,7 @@ static int overlay_merge(void *fdt, void *fdto)
if (overlay < 0)
return overlay;
- target = overlay_get_target(fdt, fdto, fragment, NULL);
+ target = fdt_overlay_target_offset(fdt, fdto, fragment, NULL);
if (target < 0)
return target;
@@ -779,7 +989,7 @@ static int overlay_symbol_update(void *fdt, void *fdto)
return -FDT_ERR_BADOVERLAY;
/* get the target of the fragment */
- ret = overlay_get_target(fdt, fdto, fragment, &target_path);
+ ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path);
if (ret < 0)
return ret;
target = ret;
@@ -801,7 +1011,7 @@ static int overlay_symbol_update(void *fdt, void *fdto)
if (!target_path) {
/* again in case setprop_placeholder changed it */
- ret = overlay_get_target(fdt, fdto, fragment, &target_path);
+ ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path);
if (ret < 0)
return ret;
target = ret;
@@ -838,18 +1048,26 @@ int fdt_overlay_apply(void *fdt, void *fdto)
if (ret)
goto err;
+ /* Increase all phandles in the fdto by delta */
ret = overlay_adjust_local_phandles(fdto, delta);
if (ret)
goto err;
+ /* Adapt the phandle values in fdto to the above increase */
ret = overlay_update_local_references(fdto, delta);
if (ret)
goto err;
+ /* Update fdto's phandles using symbols from fdt */
ret = overlay_fixup_phandles(fdt, fdto);
if (ret)
goto err;
+ /* Don't overwrite phandles in fdt */
+ ret = overlay_prevent_phandle_overwrite(fdt, fdto);
+ if (ret)
+ goto err;
+
ret = overlay_merge(fdt, fdto);
if (ret)
goto err;
diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c
index d65656aaa8b..3e7e26b4398 100644
--- a/scripts/dtc/libfdt/fdt_ro.c
+++ b/scripts/dtc/libfdt/fdt_ro.c
@@ -16,7 +16,7 @@ static int fdt_nodename_eq_(const void *fdt, int offset,
int olen;
const char *p = fdt_get_name(fdt, offset, &olen);
- if (!p || (fdt_chk_extra() && olen < len))
+ if (!p || olen < len)
/* short match */
return 0;
@@ -39,7 +39,7 @@ const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
int err;
const char *s, *n;
- if (!fdt_chk_extra()) {
+ if (can_assume(VALID_INPUT)) {
s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
if (lenp)
@@ -60,7 +60,7 @@ const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
if (fdt_magic(fdt) == FDT_MAGIC) {
if (stroffset < 0)
goto fail;
- if (!fdt_chk_version() || fdt_version(fdt) >= 17) {
+ if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
if ((unsigned)stroffset >= fdt_size_dt_strings(fdt))
goto fail;
if ((fdt_size_dt_strings(fdt) - stroffset) < len)
@@ -72,7 +72,7 @@ const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
if ((stroffset >= 0) ||
(sw_stroffset > fdt_size_dt_strings(fdt)))
goto fail;
- if ((sw_stroffset) < len)
+ if (sw_stroffset < len)
len = sw_stroffset;
} else {
err = -FDT_ERR_INTERNAL;
@@ -162,7 +162,7 @@ static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
unsigned int offset = n * sizeof(struct fdt_reserve_entry);
unsigned int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
- if (fdt_chk_extra()) {
+ if (!can_assume(VALID_INPUT)) {
if (absoffset < fdt_off_mem_rsvmap(fdt))
return NULL;
if (absoffset > fdt_totalsize(fdt) -
@@ -178,11 +178,11 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
FDT_RO_PROBE(fdt);
re = fdt_mem_rsv(fdt, n);
- if (fdt_chk_extra() && !re)
+ if (!can_assume(VALID_INPUT) && !re)
return -FDT_ERR_BADOFFSET;
- *address = fdt64_to_cpu(re->address);
- *size = fdt64_to_cpu(re->size);
+ *address = fdt64_ld_(&re->address);
+ *size = fdt64_ld_(&re->size);
return 0;
}
@@ -192,7 +192,7 @@ int fdt_num_mem_rsv(const void *fdt)
const struct fdt_reserve_entry *re;
for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
- if (fdt64_to_cpu(re->size) == 0)
+ if (fdt64_ld_(&re->size) == 0)
return i;
}
return -FDT_ERR_TRUNCATED;
@@ -255,6 +255,9 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
FDT_RO_PROBE(fdt);
+ if (!can_assume(VALID_INPUT) && namelen <= 0)
+ return -FDT_ERR_BADPATH;
+
/* see if we have an alias */
if (*path != '/') {
const char *q = memchr(path, '/', end - p);
@@ -303,14 +306,13 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
const char *nameptr;
int err;
- if (fdt_chk_extra() &&
- (((err = fdt_ro_probe_(fdt)) < 0)
- || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)))
- goto fail;
+ if (((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) {
+ if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
/*
* For old FDT versions, match the naming conventions of V16:
* give only the leaf name (after all /). The actual tree
@@ -361,7 +363,8 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
int err;
const struct fdt_property *prop;
- if (fdt_chk_basic() && (err = fdt_check_prop_offset_(fdt, offset)) < 0) {
+ if (!can_assume(VALID_INPUT) &&
+ (err = fdt_check_prop_offset_(fdt, offset)) < 0) {
if (lenp)
*lenp = err;
return NULL;
@@ -370,7 +373,7 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
prop = fdt_offset_ptr_(fdt, offset);
if (lenp)
- *lenp = fdt32_to_cpu(prop->len);
+ *lenp = fdt32_ld_(&prop->len);
return prop;
}
@@ -382,7 +385,7 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
/* Prior to version 16, properties may need realignment
* and this API does not work. fdt_getprop_*() will, however. */
- if (fdt_chk_version() && fdt_version(fdt) < 0x10) {
+ if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
if (lenp)
*lenp = -FDT_ERR_BADVERSION;
return NULL;
@@ -404,11 +407,11 @@ static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
const struct fdt_property *prop;
prop = fdt_get_property_by_offset_(fdt, offset, lenp);
- if (fdt_chk_extra() && !prop) {
+ if (!can_assume(LIBFDT_FLAWLESS) && !prop) {
offset = -FDT_ERR_INTERNAL;
break;
}
- if (fdt_string_eq_(fdt, fdt32_to_cpu(prop->nameoff),
+ if (fdt_string_eq_(fdt, fdt32_ld_(&prop->nameoff),
name, namelen)) {
if (poffset)
*poffset = offset;
@@ -428,7 +431,7 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt,
{
/* Prior to version 16, properties may need realignment
* and this API does not work. fdt_getprop_*() will, however. */
- if (fdt_chk_version() && fdt_version(fdt) < 0x10) {
+ if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
if (lenp)
*lenp = -FDT_ERR_BADVERSION;
return NULL;
@@ -458,8 +461,8 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
return NULL;
/* Handle realignment */
- if (fdt_chk_version() && fdt_version(fdt) < 0x10 &&
- (poffset + sizeof(*prop)) % 8 && fdt32_to_cpu(prop->len) >= 8)
+ if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
+ (poffset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8)
return prop->data + 4;
return prop->data;
}
@@ -476,23 +479,23 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
const char *name;
int namelen;
- if (fdt_chk_extra()) {
- name = fdt_get_string(fdt, fdt32_to_cpu(prop->nameoff),
+ if (!can_assume(VALID_INPUT)) {
+ name = fdt_get_string(fdt, fdt32_ld_(&prop->nameoff),
&namelen);
+ *namep = name;
if (!name) {
if (lenp)
*lenp = namelen;
return NULL;
}
- *namep = name;
} else {
- *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+ *namep = fdt_string(fdt, fdt32_ld_(&prop->nameoff));
}
}
/* Handle realignment */
- if (fdt_chk_version() && fdt_version(fdt) < 0x10 &&
- (offset + sizeof(*prop)) % 8 && fdt32_to_cpu(prop->len) >= 8)
+ if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
+ (offset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8)
return prop->data + 4;
return prop->data;
}
@@ -517,19 +520,34 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
return 0;
}
- return fdt32_to_cpu(*php);
+ return fdt32_ld_(php);
+}
+
+static const void *fdt_path_getprop_namelen(const void *fdt, const char *path,
+ const char *propname, int propnamelen,
+ int *lenp)
+{
+ int offset = fdt_path_offset(fdt, path);
+
+ if (offset < 0)
+ return NULL;
+
+ return fdt_getprop_namelen(fdt, offset, propname, propnamelen, lenp);
}
const char *fdt_get_alias_namelen(const void *fdt,
const char *name, int namelen)
{
- int aliasoffset;
+ int len;
+ const char *alias;
+
+ alias = fdt_path_getprop_namelen(fdt, "/aliases", name, namelen, &len);
- aliasoffset = fdt_path_offset(fdt, "/aliases");
- if (aliasoffset < 0)
+ if (!can_assume(VALID_DTB) &&
+ !(alias && len > 0 && alias[len - 1] == '\0' && *alias == '/'))
return NULL;
- return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
+ return alias;
}
const char *fdt_get_alias(const void *fdt, const char *name)
@@ -537,6 +555,17 @@ const char *fdt_get_alias(const void *fdt, const char *name)
return fdt_get_alias_namelen(fdt, name, strlen(name));
}
+const char *fdt_get_symbol_namelen(const void *fdt,
+ const char *name, int namelen)
+{
+ return fdt_path_getprop_namelen(fdt, "/__symbols__", name, namelen, NULL);
+}
+
+const char *fdt_get_symbol(const void *fdt, const char *name)
+{
+ return fdt_get_symbol_namelen(fdt, name, strlen(name));
+}
+
int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
{
int pdepth = 0, p = 0;
@@ -617,7 +646,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
}
}
- if (fdt_chk_extra()) {
+ if (!can_assume(VALID_INPUT)) {
if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
return -FDT_ERR_BADOFFSET;
else if (offset == -FDT_ERR_BADOFFSET)
@@ -634,7 +663,8 @@ int fdt_node_depth(const void *fdt, int nodeoffset)
err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
if (err)
- return (!fdt_chk_extra() || err < 0) ? err : -FDT_ERR_INTERNAL;
+ return (can_assume(LIBFDT_FLAWLESS) || err < 0) ? err :
+ -FDT_ERR_INTERNAL;
return nodedepth;
}
diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c
index 2eb2b38703b..7475cafce07 100644
--- a/scripts/dtc/libfdt/fdt_rw.c
+++ b/scripts/dtc/libfdt/fdt_rw.c
@@ -13,8 +13,6 @@
static int fdt_blocks_misordered_(const void *fdt,
int mem_rsv_size, int struct_size)
{
- if (!fdt_chk_basic())
- return false;
return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
|| (fdt_off_dt_struct(fdt) <
(fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
@@ -26,16 +24,16 @@ static int fdt_blocks_misordered_(const void *fdt,
static int fdt_rw_probe_(void *fdt)
{
- if (!fdt_chk_basic())
+ if (can_assume(VALID_DTB))
return 0;
FDT_RO_PROBE(fdt);
- if (fdt_chk_version() && fdt_version(fdt) < 17)
+ if (!can_assume(LATEST) && fdt_version(fdt) < 17)
return -FDT_ERR_BADVERSION;
if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry),
fdt_size_dt_struct(fdt)))
return -FDT_ERR_BADLAYOUT;
- if (fdt_chk_version() && fdt_version(fdt) > 17)
+ if (!can_assume(LATEST) && fdt_version(fdt) > 17)
fdt_set_version(fdt, 17);
return 0;
@@ -44,11 +42,11 @@ static int fdt_rw_probe_(void *fdt)
#define FDT_RW_PROBE(fdt) \
{ \
int err_; \
- if (fdt_chk_extra() && (err_ = fdt_rw_probe_(fdt)) != 0) \
+ if ((err_ = fdt_rw_probe_(fdt)) != 0) \
return err_; \
}
-static inline int fdt_data_size_(void *fdt)
+static inline unsigned int fdt_data_size_(void *fdt)
{
return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
}
@@ -56,15 +54,16 @@ static inline int fdt_data_size_(void *fdt)
static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen)
{
char *p = splicepoint;
- char *end = (char *)fdt + fdt_data_size_(fdt);
+ unsigned int dsize = fdt_data_size_(fdt);
+ size_t soff = p - (char *)fdt;
- if (((p + oldlen) < p) || ((p + oldlen) > end))
+ if ((oldlen < 0) || (soff + oldlen < soff) || (soff + oldlen > dsize))
return -FDT_ERR_BADOFFSET;
- if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt))
+ if ((p < (char *)fdt) || (dsize + newlen < (unsigned)oldlen))
return -FDT_ERR_BADOFFSET;
- if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
+ if (dsize - oldlen + newlen > fdt_totalsize(fdt))
return -FDT_ERR_NOSPACE;
- memmove(p + newlen, p + oldlen, end - p - oldlen);
+ memmove(p + newlen, p + oldlen, ((char *)fdt + dsize) - (p + oldlen));
return 0;
}
@@ -122,34 +121,36 @@ static int fdt_splice_string_(void *fdt, int newlen)
* @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)
+ * allocated. Ignored if can_assume(NO_ROLLBACK)
+ * @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)
+static int fdt_find_add_string_(void *fdt, const char *s, int slen,
+ int *allocated)
{
char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
const char *p;
char *new;
- int len = strlen(s) + 1;
int err;
- if (fdt_chk_basic())
+ if (!can_assume(NO_ROLLBACK))
*allocated = 0;
- p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s);
+ p = fdt_find_string_len_(strtab, fdt_size_dt_strings(fdt), s, slen);
if (p)
/* found it */
return (p - strtab);
new = strtab + fdt_size_dt_strings(fdt);
- err = fdt_splice_string_(fdt, len);
+ err = fdt_splice_string_(fdt, slen + 1);
if (err)
return err;
- if (fdt_chk_basic())
+ if (!can_assume(NO_ROLLBACK))
*allocated = 1;
- memcpy(new, s, len);
+ memcpy(new, s, slen);
+ new[slen] = '\0';
+
return (new - strtab);
}
@@ -182,13 +183,15 @@ int fdt_del_mem_rsv(void *fdt, int n)
return fdt_splice_mem_rsv_(fdt, re, 1, 0);
}
-static int fdt_resize_property_(void *fdt, int nodeoffset, const char *name,
+static int fdt_resize_property_(void *fdt, int nodeoffset,
+ const char *name, int namelen,
int len, struct fdt_property **prop)
{
int oldlen;
int err;
- *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
+ *prop = fdt_get_property_namelen_w(fdt, nodeoffset, name, namelen,
+ &oldlen);
if (!*prop)
return oldlen;
@@ -201,7 +204,7 @@ static int fdt_resize_property_(void *fdt, int nodeoffset, const char *name,
}
static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
- int len, struct fdt_property **prop)
+ int namelen, int len, struct fdt_property **prop)
{
int proplen;
int nextoffset;
@@ -212,7 +215,7 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
return nextoffset;
- namestroff = fdt_find_add_string_(fdt, name, &allocated);
+ namestroff = fdt_find_add_string_(fdt, name, namelen, &allocated);
if (namestroff < 0)
return namestroff;
@@ -222,7 +225,7 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
err = fdt_splice_struct_(fdt, *prop, 0, proplen);
if (err) {
/* Delete the string if we failed to add it */
- if (fdt_chk_basic() && allocated)
+ if (!can_assume(NO_ROLLBACK) && allocated)
fdt_del_last_string_(fdt, name);
return err;
}
@@ -256,17 +259,18 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name)
return 0;
}
-int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
- int len, void **prop_data)
+int fdt_setprop_placeholder_namelen(void *fdt, int nodeoffset, const char *name,
+ int namelen, int len, void **prop_data)
{
struct fdt_property *prop;
int err;
FDT_RW_PROBE(fdt);
- err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop);
+ err = fdt_resize_property_(fdt, nodeoffset, name, namelen, len, &prop);
if (err == -FDT_ERR_NOTFOUND)
- err = fdt_add_property_(fdt, nodeoffset, name, len, &prop);
+ err = fdt_add_property_(fdt, nodeoffset, name, namelen, len,
+ &prop);
if (err)
return err;
@@ -274,13 +278,14 @@ int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
return 0;
}
-int fdt_setprop(void *fdt, int nodeoffset, const char *name,
- const void *val, int len)
+int fdt_setprop_namelen(void *fdt, int nodeoffset, const char *name,
+ int namelen, const void *val, int len)
{
void *prop_data;
int err;
- err = fdt_setprop_placeholder(fdt, nodeoffset, name, len, &prop_data);
+ err = fdt_setprop_placeholder_namelen(fdt, nodeoffset, name, namelen,
+ len, &prop_data);
if (err)
return err;
@@ -308,7 +313,8 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
prop->len = cpu_to_fdt32(newlen);
memcpy(prop->data + oldlen, val, len);
} else {
- err = fdt_add_property_(fdt, nodeoffset, name, len, &prop);
+ err = fdt_add_property_(fdt, nodeoffset, name, strlen(name),
+ len, &prop);
if (err)
return err;
memcpy(prop->data, val, len);
@@ -350,7 +356,10 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
return offset;
/* Try to place the new node after the parent's properties */
- fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
+ tag = fdt_next_tag(fdt, parentoffset, &nextoffset);
+ /* the fdt_subnode_offset_namelen() should ensure this never hits */
+ if (!can_assume(LIBFDT_FLAWLESS) && (tag != FDT_BEGIN_NODE))
+ return -FDT_ERR_INTERNAL;
do {
offset = nextoffset;
tag = fdt_next_tag(fdt, offset, &nextoffset);
@@ -392,7 +401,9 @@ int fdt_del_node(void *fdt, int nodeoffset)
}
static void fdt_packblocks_(const char *old, char *new,
- int mem_rsv_size, int struct_size)
+ int mem_rsv_size,
+ int struct_size,
+ int strings_size)
{
int mem_rsv_off, struct_off, strings_off;
@@ -407,8 +418,7 @@ static void fdt_packblocks_(const char *old, char *new,
fdt_set_off_dt_struct(new, struct_off);
fdt_set_size_dt_struct(new, struct_size);
- memmove(new + strings_off, old + fdt_off_dt_strings(old),
- fdt_size_dt_strings(old));
+ memmove(new + strings_off, old + fdt_off_dt_strings(old), strings_size);
fdt_set_off_dt_strings(new, strings_off);
fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
}
@@ -427,17 +437,20 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry);
- if (!fdt_chk_version() || fdt_version(fdt) >= 17) {
+ if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
struct_size = fdt_size_dt_struct(fdt);
- } else {
+ } else if (fdt_version(fdt) == 16) {
struct_size = 0;
while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
;
if (struct_size < 0)
return struct_size;
+ } else {
+ return -FDT_ERR_BADVERSION;
}
- if (!fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) {
+ if (can_assume(LIBFDT_ORDER) ||
+ !fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) {
/* no further work necessary */
err = fdt_move(fdt, buf, bufsize);
if (err)
@@ -465,7 +478,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
return -FDT_ERR_NOSPACE;
}
- fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size);
+ fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size,
+ fdt_size_dt_strings(fdt));
memmove(buf, tmp, newsize);
fdt_set_magic(buf, FDT_MAGIC);
@@ -485,7 +499,8 @@ int fdt_pack(void *fdt)
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry);
- fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
+ fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt),
+ fdt_size_dt_strings(fdt));
fdt_set_totalsize(fdt, fdt_data_size_(fdt));
return 0;
diff --git a/scripts/dtc/libfdt/fdt_strerror.c b/scripts/dtc/libfdt/fdt_strerror.c
index b4356931b06..d852b77e81e 100644
--- a/scripts/dtc/libfdt/fdt_strerror.c
+++ b/scripts/dtc/libfdt/fdt_strerror.c
@@ -39,6 +39,7 @@ static struct fdt_errtabent fdt_errtable[] = {
FDT_ERRTABENT(FDT_ERR_BADOVERLAY),
FDT_ERRTABENT(FDT_ERR_NOPHANDLES),
FDT_ERRTABENT(FDT_ERR_BADFLAGS),
+ FDT_ERRTABENT(FDT_ERR_ALIGNMENT),
};
#define FDT_ERRTABSIZE ((int)(sizeof(fdt_errtable) / sizeof(fdt_errtable[0])))
diff --git a/scripts/dtc/libfdt/fdt_sw.c b/scripts/dtc/libfdt/fdt_sw.c
index d9e67fa2a61..4c569ee7eb0 100644
--- a/scripts/dtc/libfdt/fdt_sw.c
+++ b/scripts/dtc/libfdt/fdt_sw.c
@@ -12,7 +12,7 @@
static int fdt_sw_probe_(void *fdt)
{
- if (fdt_chk_basic()) {
+ if (!can_assume(VALID_INPUT)) {
if (fdt_magic(fdt) == FDT_MAGIC)
return -FDT_ERR_BADSTATE;
else if (fdt_magic(fdt) != FDT_SW_MAGIC)
@@ -25,14 +25,14 @@ static int fdt_sw_probe_(void *fdt)
#define FDT_SW_PROBE(fdt) \
{ \
int err; \
- if (fdt_chk_basic() && (err = fdt_sw_probe_(fdt)) != 0) \
+ if ((err = fdt_sw_probe_(fdt)) != 0) \
return err; \
}
/* 'memrsv' state: Initial state after fdt_create()
*
* Allowed functions:
- * fdt_add_reservmap_entry()
+ * fdt_add_reservemap_entry()
* fdt_finish_reservemap() [moves to 'struct' state]
*/
static int fdt_sw_probe_memrsv_(void *fdt)
@@ -41,7 +41,7 @@ static int fdt_sw_probe_memrsv_(void *fdt)
if (err)
return err;
- if (fdt_chk_extra() && fdt_off_dt_strings(fdt) != 0)
+ if (!can_assume(VALID_INPUT) && fdt_off_dt_strings(fdt) != 0)
return -FDT_ERR_BADSTATE;
return 0;
}
@@ -49,7 +49,7 @@ static int fdt_sw_probe_memrsv_(void *fdt)
#define FDT_SW_PROBE_MEMRSV(fdt) \
{ \
int err; \
- if (fdt_chk_extra() && (err = fdt_sw_probe_memrsv_(fdt)) != 0) \
+ if ((err = fdt_sw_probe_memrsv_(fdt)) != 0) \
return err; \
}
@@ -63,15 +63,12 @@ static int fdt_sw_probe_memrsv_(void *fdt)
*/
static int fdt_sw_probe_struct_(void *fdt)
{
- int err;
-
- if (!fdt_chk_extra())
- return 0;
- err = fdt_sw_probe_(fdt);
+ int err = fdt_sw_probe_(fdt);
if (err)
return err;
- if (fdt_off_dt_strings(fdt) != fdt_totalsize(fdt))
+ if (!can_assume(VALID_INPUT) &&
+ fdt_off_dt_strings(fdt) != fdt_totalsize(fdt))
return -FDT_ERR_BADSTATE;
return 0;
}
@@ -79,7 +76,7 @@ static int fdt_sw_probe_struct_(void *fdt)
#define FDT_SW_PROBE_STRUCT(fdt) \
{ \
int err; \
- if (fdt_chk_extra() && (err = fdt_sw_probe_struct_(fdt)) != 0) \
+ if ((err = fdt_sw_probe_struct_(fdt)) != 0) \
return err; \
}
@@ -161,7 +158,8 @@ int fdt_resize(void *fdt, void *buf, int bufsize)
headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
tailsize = fdt_size_dt_strings(fdt);
- if (fdt_chk_extra() && (headsize + tailsize) > fdt_totalsize(fdt))
+ if (!can_assume(VALID_DTB) &&
+ headsize + tailsize > fdt_totalsize(fdt))
return -FDT_ERR_INTERNAL;
if ((headsize + tailsize) > (unsigned)bufsize)
@@ -379,7 +377,7 @@ int fdt_finish(void *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_last_comp_version(fdt, FDT_LAST_COMPATIBLE_VERSION);
fdt_set_magic(fdt, FDT_MAGIC);
return 0;
diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h
index 16ec53e78b8..d7cf74722b2 100644
--- a/scripts/dtc/libfdt/libfdt.h
+++ b/scripts/dtc/libfdt/libfdt.h
@@ -9,7 +9,12 @@
#include "libfdt_env.h"
#include "fdt.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define FDT_FIRST_SUPPORTED_VERSION 0x02
+#define FDT_LAST_COMPATIBLE_VERSION 0x10
#define FDT_LAST_SUPPORTED_VERSION 0x11
/* Error codes: informative error codes */
@@ -97,7 +102,11 @@
/* 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
+#define FDT_ERR_ALIGNMENT 19
+ /* FDT_ERR_ALIGNMENT: The device tree base address is not 8-byte
+ * aligned. */
+
+#define FDT_ERR_MAX 19
/* constants */
#define FDT_MAX_PHANDLE 0xfffffffe
@@ -117,6 +126,28 @@ 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);
+/*
+ * External helpers to access words from a device tree blob. They're built
+ * to work even with unaligned pointers on platforms (such as ARMv5) that don't
+ * like unaligned loads and stores.
+ */
+static inline uint16_t fdt16_ld(const fdt16_t *p)
+{
+ const uint8_t *bp = (const uint8_t *)p;
+
+ return ((uint16_t)bp[0] << 8) | bp[1];
+}
+
+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;
@@ -127,6 +158,20 @@ static inline void fdt32_st(void *property, uint32_t value)
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;
@@ -149,23 +194,23 @@ int fdt_next_node(const void *fdt, int offset, int *depth);
/**
* fdt_first_subnode() - get offset of first direct subnode
- *
* @fdt: FDT blob
* @offset: Offset of node to check
+ *
* Return: offset of first subnode, or -FDT_ERR_NOTFOUND if there is none
*/
int fdt_first_subnode(const void *fdt, int offset);
/**
* fdt_next_subnode() - get offset of next direct subnode
+ * @fdt: FDT blob
+ * @offset: Offset of previous subnode
*
* After first calling fdt_first_subnode(), call this function repeatedly to
* get direct subnodes of a parent node.
*
- * @fdt: FDT blob
- * @offset: Offset of previous subnode
* Return: offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more
- * subnodes
+ * subnodes
*/
int fdt_next_subnode(const void *fdt, int offset);
@@ -190,7 +235,6 @@ int fdt_next_subnode(const void *fdt, int offset);
* Note that this is implemented as a macro and @node is used as
* iterator in the loop. The parent variable be constant or even a
* literal.
- *
*/
#define fdt_for_each_subnode(node, fdt, parent) \
for (node = fdt_first_subnode(fdt, parent); \
@@ -201,7 +245,7 @@ int fdt_next_subnode(const void *fdt, int offset);
/* General functions */
/**********************************************************************/
#define fdt_get_header(fdt, field) \
- (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
+ (fdt32_ld(&((const struct fdt_header *)(fdt))->field))
#define fdt_magic(fdt) (fdt_get_header(fdt, magic))
#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize))
#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct))
@@ -219,32 +263,36 @@ int fdt_next_subnode(const void *fdt, int offset);
struct fdt_header *fdth = (struct fdt_header *)fdt; \
fdth->name = cpu_to_fdt32(val); \
}
-fdt_set_hdr_(magic);
-fdt_set_hdr_(totalsize);
-fdt_set_hdr_(off_dt_struct);
-fdt_set_hdr_(off_dt_strings);
-fdt_set_hdr_(off_mem_rsvmap);
-fdt_set_hdr_(version);
-fdt_set_hdr_(last_comp_version);
-fdt_set_hdr_(boot_cpuid_phys);
-fdt_set_hdr_(size_dt_strings);
-fdt_set_hdr_(size_dt_struct);
+fdt_set_hdr_(magic)
+fdt_set_hdr_(totalsize)
+fdt_set_hdr_(off_dt_struct)
+fdt_set_hdr_(off_dt_strings)
+fdt_set_hdr_(off_mem_rsvmap)
+fdt_set_hdr_(version)
+fdt_set_hdr_(last_comp_version)
+fdt_set_hdr_(boot_cpuid_phys)
+fdt_set_hdr_(size_dt_strings)
+fdt_set_hdr_(size_dt_struct)
#undef fdt_set_hdr_
/**
* fdt_header_size - return the size of the tree's header
* @fdt: pointer to a flattened device tree
+ *
+ * Return: size of DTB header in bytes
*/
size_t fdt_header_size(const void *fdt);
/**
- * fdt_header_size_ - internal function which takes a version number
+ * fdt_header_size_ - internal function to get header size from a version number
+ * @version: device tree version number
+ *
+ * Return: size of DTB header in bytes
*/
size_t fdt_header_size_(uint32_t version);
/**
* fdt_check_header - sanity check a device tree header
-
* @fdt: pointer to data which might be a flattened device tree
*
* fdt_check_header() checks that the given buffer contains what
@@ -369,8 +417,7 @@ static inline uint32_t fdt_get_max_phandle(const void *fdt)
* highest phandle value in the device tree blob) will be returned in the
* @phandle parameter.
*
- * Returns:
- * 0 on success or a negative error-code on failure
+ * Return: 0 on success or a negative error-code on failure
*/
int fdt_generate_phandle(const void *fdt, uint32_t *phandle);
@@ -390,9 +437,11 @@ int fdt_num_mem_rsv(const void *fdt);
/**
* fdt_get_mem_rsv - retrieve one memory reserve map entry
* @fdt: pointer to the device tree blob
- * @address, @size: pointers to 64-bit variables
+ * @n: index of reserve map entry
+ * @address: pointer to 64-bit variable to hold the start address
+ * @size: pointer to 64-bit variable to hold the size of the entry
*
- * On success, *address and *size will contain the address and size of
+ * On success, @address and @size will contain the address and size of
* the n-th reserve map entry from the device tree blob, in
* native-endian format.
*
@@ -415,6 +464,8 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size);
* namelen characters of name for matching the subnode name. This is
* useful for finding subnodes based on a portion of a larger string,
* such as a full path.
+ *
+ * Return: offset of the subnode or -FDT_ERR_NOTFOUND if name not found.
*/
#ifndef SWIG /* Not available in Python */
int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
@@ -454,6 +505,8 @@ int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name);
*
* Identical to fdt_path_offset(), but only consider the first namelen
* characters of path as the path name.
+ *
+ * Return: offset of the node or negative libfdt error value otherwise
*/
#ifndef SWIG /* Not available in Python */
int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen);
@@ -471,12 +524,37 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen);
* level matching the given component, differentiated only by unit
* address).
*
+ * If the path is not absolute (i.e. does not begin with '/'), the
+ * first component is treated as an alias. That is, the property by
+ * that name is looked up in the /aliases node, and the value of that
+ * property used in place of that first component.
+ *
+ * For example, for this small fragment
+ *
+ * / {
+ * aliases {
+ * i2c2 = &foo; // RHS compiles to "/soc@0/i2c@30a40000/eeprom@52"
+ * };
+ * soc@0 {
+ * foo: i2c@30a40000 {
+ * bar: eeprom@52 {
+ * };
+ * };
+ * };
+ * };
+ *
+ * these would be equivalent:
+ *
+ * /soc@0/i2c@30a40000/eeprom@52
+ * i2c2/eeprom@52
+ *
* returns:
* structure block offset of the node with the requested path (>=0), on
* success
- * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid
+ * -FDT_ERR_BADPATH, given path does not begin with '/' and the first
+ * component is not a valid alias
* -FDT_ERR_NOTFOUND, if the requested node does not exist
- * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
@@ -521,7 +599,7 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp);
* structure block offset of the property (>=0), on success
* -FDT_ERR_NOTFOUND, if the requested node has no properties
* -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag
- * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
@@ -542,7 +620,7 @@ int fdt_first_property_offset(const void *fdt, int nodeoffset);
* structure block offset of the next property (>=0), on success
* -FDT_ERR_NOTFOUND, if the given property is the last in its node
* -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag
- * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
@@ -553,9 +631,9 @@ int fdt_next_property_offset(const void *fdt, int offset);
/**
* fdt_for_each_property_offset - iterate over all properties of a node
*
- * @property_offset: property offset (int, lvalue)
- * @fdt: FDT blob (const void *)
- * @node: node offset (int)
+ * @property: property offset (int, lvalue)
+ * @fdt: FDT blob (const void *)
+ * @node: node offset (int)
*
* This is actually a wrapper around a for loop and would be used like so:
*
@@ -607,6 +685,13 @@ int fdt_next_property_offset(const void *fdt, int offset);
const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
int offset,
int *lenp);
+static inline struct fdt_property *fdt_get_property_by_offset_w(void *fdt,
+ int offset,
+ int *lenp)
+{
+ return (struct fdt_property *)(uintptr_t)
+ fdt_get_property_by_offset(fdt, offset, lenp);
+}
/**
* fdt_get_property_namelen - find a property based on substring
@@ -618,12 +703,22 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
*
* Identical to fdt_get_property(), but only examine the first namelen
* characters of name for matching the property name.
+ *
+ * Return: pointer to the structure representing the property, or NULL
+ * if not found
*/
#ifndef SWIG /* Not available in Python */
const struct fdt_property *fdt_get_property_namelen(const void *fdt,
int nodeoffset,
const char *name,
int namelen, int *lenp);
+static inline struct fdt_property *
+fdt_get_property_namelen_w(void *fdt, int nodeoffset, const char *name,
+ int namelen, int *lenp)
+{
+ return (struct fdt_property *)(uintptr_t)fdt_get_property_namelen(
+ fdt, nodeoffset, name, namelen, lenp);
+}
#endif
/**
@@ -676,7 +771,7 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
* to within the device blob itself, not a copy of the value). If
* lenp is non-NULL, the length of the property value is also
* returned, in the integer pointed to by lenp. If namep is non-NULL,
- * the property's namne will also be returned in the char * pointed to
+ * the property's name will also be returned in the char * pointed to
* by namep (this will be a pointer to within the device tree's string
* block, not a new copy of the name).
*
@@ -684,7 +779,7 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
* pointer to the property's value
* if lenp is non-NULL, *lenp contains the length of the property
* value (>=0)
- * if namep is non-NULL *namep contiains a pointer to the property
+ * if namep is non-NULL *namep contains a pointer to the property
* name.
* NULL, on error
* if lenp is non-NULL, *lenp contains an error code (<0):
@@ -710,6 +805,8 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
*
* Identical to fdt_getprop(), but only examine the first namelen
* characters of name for matching the property name.
+ *
+ * Return: pointer to the property's value or NULL on error
*/
#ifndef SWIG /* Not available in Python */
const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
@@ -731,10 +828,10 @@ static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset,
* @lenp: pointer to an integer variable (will be overwritten) or NULL
*
* fdt_getprop() retrieves a pointer to the value of the property
- * named 'name' of the node at offset nodeoffset (this will be a
+ * named @name of the node at offset @nodeoffset (this will be a
* pointer to within the device blob itself, not a copy of the value).
- * If lenp is non-NULL, the length of the property value is also
- * returned, in the integer pointed to by lenp.
+ * If @lenp is non-NULL, the length of the property value is also
+ * returned, in the integer pointed to by @lenp.
*
* returns:
* pointer to the property's value
@@ -776,11 +873,14 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset);
/**
* fdt_get_alias_namelen - get alias based on substring
* @fdt: pointer to the device tree blob
- * @name: name of the alias th look up
+ * @name: name of the alias to look up
* @namelen: number of characters of name to consider
*
- * Identical to fdt_get_alias(), but only examine the first namelen
- * characters of name for matching the alias name.
+ * Identical to fdt_get_alias(), but only examine the first @namelen
+ * characters of @name for matching the alias name.
+ *
+ * Return: a pointer to the expansion of the alias named @name, if it exists,
+ * NULL otherwise
*/
#ifndef SWIG /* Not available in Python */
const char *fdt_get_alias_namelen(const void *fdt,
@@ -790,10 +890,10 @@ const char *fdt_get_alias_namelen(const void *fdt,
/**
* fdt_get_alias - retrieve the path referenced by a given alias
* @fdt: pointer to the device tree blob
- * @name: name of the alias th look up
+ * @name: name of the alias to look up
*
* fdt_get_alias() retrieves the value of a given alias. That is, the
- * value of the property named 'name' in the node /aliases.
+ * value of the property named @name in the node /aliases.
*
* returns:
* a pointer to the expansion of the alias named 'name', if it exists
@@ -801,6 +901,42 @@ const char *fdt_get_alias_namelen(const void *fdt,
*/
const char *fdt_get_alias(const void *fdt, const char *name);
+/**
+ * fdt_get_symbol_namelen - get symbol based on substring
+ * @fdt: pointer to the device tree blob
+ * @name: name of the symbol to look up
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_get_symbol(), but only examine the first @namelen
+ * characters of @name for matching the symbol name.
+ *
+ * Return: a pointer to the expansion of the symbol named @name, if it exists,
+ * NULL otherwise
+ */
+#ifndef SWIG /* Not available in Python */
+const char *fdt_get_symbol_namelen(const void *fdt,
+ const char *name, int namelen);
+#endif
+
+/**
+ * fdt_get_symbol - retrieve the path referenced by a given symbol
+ * @fdt: pointer to the device tree blob
+ * @name: name of the symbol to look up
+ *
+ * fdt_get_symbol() retrieves the value of a given symbol. That is,
+ * the value of the property named @name in the node
+ * /__symbols__. Such a node exists only for a device tree blob that
+ * has been compiled with the -@ dtc option. Each property corresponds
+ * to a label appearing in the device tree source, with the name of
+ * the property being the label and the value being the full path of
+ * the node it is attached to.
+ *
+ * returns:
+ * a pointer to the expansion of the symbol named 'name', if it exists
+ * NULL, if the given symbol or the /__symbols__ node does not exist
+ */
+const char *fdt_get_symbol(const void *fdt, const char *name);
+
/**
* fdt_get_path - determine the full path of a node
* @fdt: pointer to the device tree blob
@@ -969,14 +1105,13 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle);
/**
- * fdt_node_check_compatible: check a node's compatible property
+ * fdt_node_check_compatible - check a node's compatible property
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of a tree node
* @compatible: string to match against
*
- *
* fdt_node_check_compatible() returns 0 if the given node contains a
- * 'compatible' property with the given string as one of its elements,
+ * @compatible property with the given string as one of its elements,
* it returns non-zero otherwise, or on error.
*
* returns:
@@ -1040,7 +1175,7 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
* one or more strings, each terminated by \0, as is found in a device tree
* "compatible" property.
*
- * @return: 1 if the string is found in the list, 0 not found, or invalid list
+ * Return: 1 if the string is found in the list, 0 not found, or invalid list
*/
int fdt_stringlist_contains(const char *strlist, int listlen, const char *str);
@@ -1049,7 +1184,8 @@ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str);
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of a tree node
* @property: name of the property containing the string list
- * @return:
+ *
+ * Return:
* the number of strings in the given property
* -FDT_ERR_BADVALUE if the property value is not NUL-terminated
* -FDT_ERR_NOTFOUND if the property does not exist
@@ -1069,7 +1205,7 @@ int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property);
* small-valued cell properties, such as #address-cells, when searching for
* the empty string.
*
- * @return:
+ * return:
* the index of the string in the list of strings
* -FDT_ERR_BADVALUE if the property value is not NUL-terminated
* -FDT_ERR_NOTFOUND if the property does not exist or does not contain
@@ -1093,7 +1229,7 @@ int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
* If non-NULL, the length of the string (on success) or a negative error-code
* (on failure) will be stored in the integer pointer to by lenp.
*
- * @return:
+ * Return:
* A pointer to the string at the given index in the string list or NULL on
* failure. On success the length of the string will be stored in the memory
* location pointed to by the lenp parameter, if non-NULL. On failure one of
@@ -1130,8 +1266,8 @@ const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
*
* returns:
* 0 <= n < FDT_MAX_NCELLS, on success
- * 2, if the node has no #address-cells property
- * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
+ * 2, if the node has no #address-cells property
+ * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
* #address-cells property
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
@@ -1151,8 +1287,8 @@ int fdt_address_cells(const void *fdt, int nodeoffset);
*
* returns:
* 0 <= n < FDT_MAX_NCELLS, on success
- * 1, if the node has no #size-cells property
- * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
+ * 1, if the node has no #size-cells property
+ * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
* #size-cells property
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
@@ -1181,6 +1317,8 @@ int fdt_size_cells(const void *fdt, int nodeoffset);
* starting from the given index, and using only the first characters
* of the name. It is useful when you want to manipulate only one value of
* an array and you have a string that doesn't end with \0.
+ *
+ * Return: 0 on success, negative libfdt error value otherwise
*/
#ifndef SWIG /* Not available in Python */
int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
@@ -1294,8 +1432,13 @@ static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset,
/**
* fdt_setprop_inplace_cell - change the value of a single-cell property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node containing the property
+ * @name: name of the property to change the value of
+ * @val: new value of the 32-bit cell
*
* This is an alternative name for fdt_setprop_inplace_u32()
+ * Return: 0 on success, negative libfdt error number otherwise.
*/
static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset,
const char *name, uint32_t val)
@@ -1367,14 +1510,14 @@ int fdt_nop_node(void *fdt, int nodeoffset);
/**
* fdt_create_with_flags - begin creation of a new fdt
- * @fdt: pointer to memory allocated where fdt will be created
+ * @buf: 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.
+ * fdt creation process must end with fdt_finish() to produce a valid fdt.
*
* returns:
* 0, on success
@@ -1385,7 +1528,7 @@ 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
+ * @buf: 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.
@@ -1425,7 +1568,7 @@ static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
* @fdt: pointer to the device tree blob
* @name: name of property to add
* @len: length of property value in bytes
- * @valp: returns a pointer to where where the value should be placed
+ * @valp: returns a pointer to where the value should be placed
*
* returns:
* 0, on success
@@ -1450,7 +1593,8 @@ int fdt_pack(void *fdt);
/**
* fdt_add_mem_rsv - add one memory reserve map entry
* @fdt: pointer to the device tree blob
- * @address, @size: 64-bit values (native endian)
+ * @address: 64-bit start address of the reserve map entry
+ * @size: 64-bit size of the reserved region
*
* Adds a reserve map entry to the given blob reserving a region at
* address address of length size.
@@ -1521,6 +1665,38 @@ int fdt_del_mem_rsv(void *fdt, int n);
*/
int fdt_set_name(void *fdt, int nodeoffset, const char *name);
+/**
+ * fdt_setprop_namelen - create or change a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @namelen: length of the name
+ * @val: pointer to data to set the property value to
+ * @len: length of the property value
+ *
+ * fdt_setprop_namelen() sets the value of the named property in the given
+ * node to the given value and length, creating the property if it
+ * does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop_namelen(void *fdt, int nodeoffset, const char *name,
+ int namelen, const void *val, int len);
+
/**
* fdt_setprop - create or change a property
* @fdt: pointer to the device tree blob
@@ -1549,8 +1725,44 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name);
* -FDT_ERR_BADLAYOUT,
* -FDT_ERR_TRUNCATED, standard meanings
*/
-int fdt_setprop(void *fdt, int nodeoffset, const char *name,
- const void *val, int len);
+static inline int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len)
+{
+ return fdt_setprop_namelen(fdt, nodeoffset, name, strlen(name), val,
+ len);
+}
+
+/**
+ * fdt_setprop_placeholder_namelen - allocate space for a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @namelen: length of the name
+ * @len: length of the property value
+ * @prop_data: return pointer to property data
+ *
+ * fdt_setprop_placeholder_namelen() allocates the named property in the given node.
+ * If the property exists it is resized. In either case a pointer to the
+ * property data is returned.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop_placeholder_namelen(void *fdt, int nodeoffset, const char *name,
+ int namelen, int len, void **prop_data);
/**
* fdt_setprop_placeholder - allocate space for a property
@@ -1560,7 +1772,7 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name,
* @len: length of the property value
* @prop_data: return pointer to property data
*
- * fdt_setprop_placeholer() allocates the named property in the given node.
+ * fdt_setprop_placeholder() allocates the named property in the given node.
* If the property exists it is resized. In either case a pointer to the
* property data is returned.
*
@@ -1580,8 +1792,13 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name,
* -FDT_ERR_BADLAYOUT,
* -FDT_ERR_TRUNCATED, standard meanings
*/
-int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
- int len, void **prop_data);
+static inline int fdt_setprop_placeholder(void *fdt, int nodeoffset,
+ const char *name, int len,
+ void **prop_data)
+{
+ return fdt_setprop_placeholder_namelen(fdt, nodeoffset, name,
+ strlen(name), len, prop_data);
+}
/**
* fdt_setprop_u32 - set a property to a 32-bit integer
@@ -1655,8 +1872,14 @@ static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name,
/**
* fdt_setprop_cell - set a property to a single cell value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value for the property (native endian)
*
* This is an alternative name for fdt_setprop_u32()
+ *
+ * Return: 0 on success, negative libfdt error value otherwise.
*/
static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
uint32_t val)
@@ -1695,6 +1918,39 @@ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
#define fdt_setprop_string(fdt, nodeoffset, name, str) \
fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
+/**
+ * fdt_setprop_namelen_string - set a property to a string value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @namelen: number of characters of name to consider
+ * @str: string value for the property
+ *
+ * fdt_setprop_namelen_string() sets the value of the named property in the
+ * given node to the given string value (using the length of the
+ * string to determine the new length of the property), or creates a
+ * new property with that value if it does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+#define fdt_setprop_namelen_string(fdt, nodeoffset, name, namelen, str) \
+ fdt_setprop_namelen((fdt), (nodeoffset), (name), (namelen), (str), \
+ strlen(str) + 1)
+
/**
* fdt_setprop_empty - set a property to an empty value
* @fdt: pointer to the device tree blob
@@ -1826,8 +2082,14 @@ static inline int fdt_appendprop_u64(void *fdt, int nodeoffset,
/**
* fdt_appendprop_cell - append a single cell value to a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value to append to the property (native endian)
*
* This is an alternative name for fdt_appendprop_u32()
+ *
+ * Return: 0 on success, negative libfdt error value otherwise.
*/
static inline int fdt_appendprop_cell(void *fdt, int nodeoffset,
const char *name, uint32_t val)
@@ -1878,7 +2140,7 @@ static inline int fdt_appendprop_cell(void *fdt, int nodeoffset,
* 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
@@ -1908,7 +2170,7 @@ int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
* @nodeoffset: offset of the node whose property to nop
* @name: name of the property to nop
*
- * fdt_del_property() will delete the given property.
+ * fdt_delprop() will delete the given property.
*
* This function will delete data from the blob, and will therefore
* change the offsets of some existing nodes.
@@ -1930,13 +2192,16 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name);
* fdt_add_subnode_namelen - creates a new node based on substring
* @fdt: pointer to the device tree blob
* @parentoffset: structure block offset of a node
- * @name: name of the subnode to locate
+ * @name: name of the subnode to create
* @namelen: number of characters of name to consider
*
- * Identical to fdt_add_subnode(), but use only the first namelen
- * characters of name as the name of the new node. This is useful for
+ * Identical to fdt_add_subnode(), but use only the first @namelen
+ * characters of @name as the name of the new node. This is useful for
* creating subnodes based on a portion of a larger string, such as a
* full path.
+ *
+ * Return: structure block offset of the created subnode (>=0),
+ * negative libfdt error value otherwise
*/
#ifndef SWIG /* Not available in Python */
int fdt_add_subnode_namelen(void *fdt, int parentoffset,
@@ -1955,10 +2220,9 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
*
* This function will insert data into the blob, and will therefore
* change the offsets of some existing nodes.
-
+ *
* returns:
- * structure block offset of the created nodeequested subnode (>=0), on
- * success
+ * structure block offset of the created subnode (>=0), on success
* -FDT_ERR_NOTFOUND, if the requested subnode does not exist
* -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE
* tag
@@ -1968,7 +2232,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
* blob to contain the new node
* -FDT_ERR_NOSPACE
* -FDT_ERR_BADLAYOUT
- * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
@@ -2013,7 +2277,7 @@ int fdt_del_node(void *fdt, int nodeoffset);
* returns:
* 0, on success
* -FDT_ERR_NOSPACE, there's not enough space in the base device tree
- * -FDT_ERR_NOTFOUND, the overlay points to some inexistant nodes or
+ * -FDT_ERR_NOTFOUND, the overlay points to some nonexistent nodes or
* properties in the base DT
* -FDT_ERR_BADPHANDLE,
* -FDT_ERR_BADOVERLAY,
@@ -2030,6 +2294,24 @@ int fdt_del_node(void *fdt, int nodeoffset);
*/
int fdt_overlay_apply(void *fdt, void *fdto);
+/**
+ * fdt_overlay_target_offset - retrieves the offset of a fragment's target
+ * @fdt: Base device tree blob
+ * @fdto: Device tree overlay blob
+ * @fragment_offset: node offset of the fragment in the overlay
+ * @pathp: pointer which receives the path of the target (or NULL)
+ *
+ * fdt_overlay_target_offset() retrieves the target offset in the base
+ * device tree of a fragment, no matter how the actual targeting is
+ * done (through a phandle or a path)
+ *
+ * returns:
+ * the targeted node offset in the base device tree
+ * Negative error code on error
+ */
+int fdt_overlay_target_offset(const void *fdt, const void *fdto,
+ int fragment_offset, char const **pathp);
+
/**
* fdt_overlay_apply_node - Merges a node into the base device tree
*
@@ -2043,4 +2325,8 @@ int fdt_overlay_apply_node(void *fdt, int target, void *fdto, int node);
const char *fdt_strerror(int errval);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* LIBFDT_H */
diff --git a/scripts/dtc/libfdt/libfdt_internal.h b/scripts/dtc/libfdt/libfdt_internal.h
index 5436e2ceeac..b60b5456f59 100644
--- a/scripts/dtc/libfdt/libfdt_internal.h
+++ b/scripts/dtc/libfdt/libfdt_internal.h
@@ -10,20 +10,25 @@
#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
-int fdt_ro_probe_(const void *fdt);
+int32_t fdt_ro_probe_(const void *fdt);
#define FDT_RO_PROBE(fdt) \
{ \
- int totalsize_; \
- if (fdt_chk_basic()) { \
- totalsize_ = fdt_ro_probe_(fdt); \
- if (totalsize_ < 0) \
- return totalsize_; \
- } \
+ int32_t totalsize_; \
+ if ((totalsize_ = fdt_ro_probe_(fdt)) < 0) \
+ return totalsize_; \
}
int fdt_check_node_offset_(const void *fdt, int offset);
int fdt_check_prop_offset_(const void *fdt, int offset);
-const char *fdt_find_string_(const char *strtab, int tabsize, const char *s);
+
+const char *fdt_find_string_len_(const char *strtab, int tabsize, const char *s,
+ int s_len);
+static inline const char *fdt_find_string_(const char *strtab, int tabsize,
+ const char *s)
+{
+ return fdt_find_string_len_(strtab, tabsize, s, strlen(s));
+}
+
int fdt_node_end_offset_(void *fdt, int nodeoffset);
static inline const void *fdt_offset_ptr_(const void *fdt, int offset)
@@ -49,6 +54,25 @@ static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n)
return (void *)(uintptr_t)fdt_mem_rsv_(fdt, n);
}
+/*
+ * Internal helpers to access structural elements of the device tree
+ * blob (rather than for example reading integers from within property
+ * values). We assume that we are either given a naturally aligned
+ * address for the platform or if we are not, we are on a platform
+ * where unaligned memory reads will be handled in a graceful manner.
+ * If not the external helpers fdtXX_ld() from libfdt.h can be used
+ * instead.
+ */
+static inline uint32_t fdt32_ld_(const fdt32_t *p)
+{
+ return fdt32_to_cpu(*p);
+}
+
+static inline uint64_t fdt64_ld_(const fdt64_t *p)
+{
+ return fdt64_to_cpu(*p);
+}
+
#define FDT_SW_MAGIC (~FDT_MAGIC)
/**********************************************************************/
@@ -61,20 +85,21 @@ static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n)
/*
* Defines assumptions which can be enabled. Each of these can be enabled
- * individually. For maximum saftey, don't enable any assumptions!
+ * individually. For maximum safety, don't enable any assumptions!
*
- * For minimal code size and no safety, use FDT_ASSUME_PERFECT at your own risk.
+ * For minimal code size and no safety, use 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.
+ * ASSUME_SANE.
*/
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.
+ * version is correctly handled. Inconsistencies or errors in the device
+ * tree may cause undefined behaviour or crashes. Invalid parameters
+ * passed to libfdt may do the same.
*
* 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
@@ -85,17 +110,35 @@ enum {
* 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,
+ 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.
+ * With this assumption enabled, 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. Truncated
+ * device trees (e.g. those only partially loaded) can also cause
+ * problems.
+ *
+ * Note: Only checks that relate exclusively to the device tree itself
+ * (not the parameters passed to libfdt) are disabled by this
+ * assumption. This includes checking headers, tags and the like.
+ */
+ ASSUME_VALID_DTB = 1 << 0,
+
+ /*
+ * This builds on ASSUME_VALID_DTB and further assumes that libfdt
+ * functions are called with valid parameters, i.e. not trigger
+ * FDT_ERR_BADOFFSET or offsets that are out of bounds. It disables any
+ * extensive checking of parameters and the device tree, making various
+ * assumptions about correctness.
+ *
+ * It doesn't make sense to enable this assumption unless
+ * ASSUME_VALID_DTB is also enabled.
*/
- FDT_ASSUME_SANE = 1 << 0,
+ ASSUME_VALID_INPUT = 1 << 1,
/*
* This disables checks for device-tree version and removes all code
@@ -104,34 +147,54 @@ enum {
* Only enable this if you know you have a device tree with the latest
* version.
*/
- FDT_ASSUME_LATEST = 1 << 1,
+ ASSUME_LATEST = 1 << 2,
/*
- * 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.
+ * This assumes that it is OK for a failed addition to the device tree,
+ * due to lack of space or some other problem, to skip any rollback
+ * steps (such as dropping the property name from the string table).
+ * This is safe to enable in most circumstances, even though it may
+ * leave the tree in a sub-optimal state.
*/
- FDT_ASSUME_FRIENDLY = 1 << 2,
-};
+ ASSUME_NO_ROLLBACK = 1 << 3,
-/** 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);
-}
+ /*
+ * This assumes that the device tree components appear in a 'convenient'
+ * order, i.e. the memory reservation block first, then the structure
+ * block and finally the string block.
+ *
+ * This order is not specified by the device-tree specification,
+ * but is expected by libfdt. The device-tree compiler always created
+ * device trees with this order.
+ *
+ * This assumption disables a check in fdt_open_into() and removes the
+ * ability to fix the problem there. This is safe if you know that the
+ * device tree is correctly ordered. See fdt_blocks_misordered_().
+ */
+ ASSUME_LIBFDT_ORDER = 1 << 4,
-/** 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);
-}
+ /*
+ * This assumes that libfdt itself does not have any internal bugs. It
+ * drops certain checks that should never be needed unless libfdt has an
+ * undiscovered bug.
+ *
+ * This can generally be considered safe to enable.
+ */
+ ASSUME_LIBFDT_FLAWLESS = 1 << 5,
+};
-/** fdt_chk_extra() - see if extra checking is enabled */
-static inline bool fdt_chk_extra(void)
+/**
+ * can_assume_() - check if a particular assumption is enabled
+ *
+ * @mask: Mask to check (ASSUME_...)
+ * @return true if that assumption is enabled, else false
+ */
+static inline bool can_assume_(int mask)
{
- return !(FDT_ASSUME_MASK & FDT_ASSUME_FRIENDLY);
+ return FDT_ASSUME_MASK & mask;
}
+/** helper macros for checking assumptions */
+#define can_assume(_assume) can_assume_(ASSUME_ ## _assume)
+
#endif /* LIBFDT_INTERNAL_H */
diff --git a/scripts/dtc/livetree.c b/scripts/dtc/livetree.c
index 4cfc2adccdd..1e121d41a89 100644
--- a/scripts/dtc/livetree.c
+++ b/scripts/dtc/livetree.c
@@ -1,24 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
- *
- *
- * This program 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 program 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 program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
#include "dtc.h"
+#include "srcpos.h"
/*
* Tree building functions
@@ -50,25 +36,27 @@ void delete_labels(struct label **labels)
label->deleted = 1;
}
-struct property *build_property(char *name, struct data val)
+struct property *build_property(const char *name, struct data val,
+ struct srcpos *srcpos)
{
struct property *new = xmalloc(sizeof(*new));
memset(new, 0, sizeof(*new));
- new->name = name;
+ new->name = xstrdup(name);
new->val = val;
+ new->srcpos = srcpos_copy(srcpos);
return new;
}
-struct property *build_property_delete(char *name)
+struct property *build_property_delete(const char *name)
{
struct property *new = xmalloc(sizeof(*new));
memset(new, 0, sizeof(*new));
- new->name = name;
+ new->name = xstrdup(name);
new->deleted = 1;
return new;
@@ -97,7 +85,8 @@ struct property *reverse_properties(struct property *first)
return head;
}
-struct node *build_node(struct property *proplist, struct node *children)
+struct node *build_node(struct property *proplist, struct node *children,
+ struct srcpos *srcpos)
{
struct node *new = xmalloc(sizeof(*new));
struct node *child;
@@ -106,6 +95,7 @@ struct node *build_node(struct property *proplist, struct node *children)
new->proplist = reverse_properties(proplist);
new->children = children;
+ new->srcpos = srcpos_copy(srcpos);
for_each_child(new, child) {
child->parent = new;
@@ -114,22 +104,23 @@ struct node *build_node(struct property *proplist, struct node *children)
return new;
}
-struct node *build_node_delete(void)
+struct node *build_node_delete(struct srcpos *srcpos)
{
struct node *new = xmalloc(sizeof(*new));
memset(new, 0, sizeof(*new));
new->deleted = 1;
+ new->srcpos = srcpos_copy(srcpos);
return new;
}
-struct node *name_node(struct node *node, char *name)
+struct node *name_node(struct node *node, const char *name)
{
assert(node->name == NULL);
- node->name = name;
+ node->name = xstrdup(name);
return node;
}
@@ -183,6 +174,8 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
old_prop->val = new_prop->val;
old_prop->deleted = 0;
+ srcpos_free(old_prop->srcpos);
+ old_prop->srcpos = new_prop->srcpos;
free(new_prop);
new_prop = NULL;
break;
@@ -223,6 +216,8 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
add_child(old_node, new_child);
}
+ old_node->srcpos = srcpos_extend(old_node->srcpos, new_node->srcpos);
+
/* The new node contents are now merged into the old node. Free
* the new node. */
free(new_node);
@@ -239,21 +234,23 @@ struct node * add_orphan_node(struct node *dt, struct node *new_node, char *ref)
char *name;
if (ref[0] == '/') {
+ d = data_add_marker(d, TYPE_STRING, ref);
d = data_append_data(d, ref, strlen(ref) + 1);
- p = build_property("target-path", d);
+ p = build_property("target-path", d, NULL);
} else {
d = data_add_marker(d, REF_PHANDLE, ref);
d = data_append_integer(d, 0xffffffff, 32);
- p = build_property("target", d);
+ p = build_property("target", d, NULL);
}
xasprintf(&name, "fragment@%u",
next_orphan_fragment++);
name_node(new_node, "__overlay__");
- node = build_node(p, new_node);
+ node = build_node(p, new_node, NULL);
name_node(node, name);
+ free(name);
add_child(dt, node);
return dt;
@@ -340,18 +337,21 @@ void delete_node(struct node *node)
}
void append_to_property(struct node *node,
- char *name, const void *data, int len)
+ char *name, const void *data, int len,
+ enum markertype type)
{
struct data d;
struct property *p;
p = get_property(node, name);
if (p) {
- d = data_append_data(p->val, data, len);
+ d = data_add_marker(p->val, type, name);
+ d = data_append_data(d, data, len);
p->val = d;
} else {
- d = data_append_data(empty_data, data, len);
- p = build_property(name, d);
+ d = data_add_marker(empty_data, type, name);
+ d = data_append_data(d, data, len);
+ p = build_property(name, d, NULL);
add_property(node, p);
}
}
@@ -439,9 +439,9 @@ cell_t propval_cell(struct property *prop)
return fdt32_to_cpu(*((fdt32_t *)prop->val.val));
}
-cell_t propval_cell_n(struct property *prop, int n)
+cell_t propval_cell_n(struct property *prop, unsigned int n)
{
- assert(prop->val.len / sizeof(cell_t) >= n);
+ assert(prop->val.len / sizeof(cell_t) > n);
return fdt32_to_cpu(*((fdt32_t *)prop->val.val + n));
}
@@ -504,7 +504,7 @@ struct node *get_subnode(struct node *node, const char *nodename)
struct node *child;
for_each_child(node, child)
- if (streq(child->name, nodename))
+ if (streq(child->name, nodename) && !child->deleted)
return child;
return NULL;
@@ -527,8 +527,7 @@ struct node *get_node_by_path(struct node *tree, const char *path)
p = strchr(path, '/');
for_each_child(tree, child) {
- if (p && (strlen(child->name) == p-path) &&
- strprefixeq(path, p - path, child->name))
+ if (p && strprefixeq(path, (size_t)(p - path), child->name))
return get_node_by_path(child, p+1);
else if (!p && streq(path, child->name))
return child;
@@ -561,7 +560,7 @@ struct node *get_node_by_phandle(struct node *tree, cell_t phandle)
{
struct node *child, *node;
- if ((phandle == 0) || (phandle == -1)) {
+ if (!phandle_is_valid(phandle)) {
assert(generate_fixups);
return NULL;
}
@@ -618,11 +617,27 @@ struct node *get_node_by_ref(struct node *tree, const char *ref)
return target;
}
+static void add_phandle_property(struct node *node,
+ const char *name, int format)
+{
+ struct data d;
+
+ if (!(phandle_format & format))
+ return;
+ if (get_property(node, name))
+ return;
+
+ d = data_add_marker(empty_data, TYPE_UINT32, NULL);
+ d = data_append_cell(d, node->phandle);
+
+ add_property(node, build_property(name, d, NULL));
+}
+
cell_t get_node_phandle(struct node *root, struct node *node)
{
static cell_t phandle = 1; /* FIXME: ick, static local */
- if ((node->phandle != 0) && (node->phandle != -1))
+ if (phandle_is_valid(node->phandle))
return node->phandle;
while (get_node_by_phandle(root, phandle))
@@ -630,17 +645,8 @@ cell_t get_node_phandle(struct node *root, struct node *node)
node->phandle = phandle;
- if (!get_property(node, "linux,phandle")
- && (phandle_format & PHANDLE_LEGACY))
- add_property(node,
- build_property("linux,phandle",
- data_append_cell(empty_data, phandle)));
-
- if (!get_property(node, "phandle")
- && (phandle_format & PHANDLE_EPAPR))
- add_property(node,
- build_property("phandle",
- data_append_cell(empty_data, phandle)));
+ add_phandle_property(node, "linux,phandle", PHANDLE_LEGACY);
+ add_phandle_property(node, "phandle", PHANDLE_EPAPR);
/* If the node *does* have a phandle property, we must
* be dealing with a self-referencing phandle, which will be
@@ -809,18 +815,18 @@ void sort_tree(struct dt_info *dti)
}
/* utility helper to avoid code duplication */
-static struct node *build_and_name_child_node(struct node *parent, char *name)
+static struct node *build_and_name_child_node(struct node *parent, const char *name)
{
struct node *node;
- node = build_node(NULL, NULL);
- name_node(node, xstrdup(name));
+ node = build_node(NULL, NULL, NULL);
+ name_node(node, name);
add_child(parent, node);
return node;
}
-static struct node *build_root_node(struct node *dt, char *name)
+static struct node *build_root_node(struct node *dt, const char *name)
{
struct node *an;
@@ -874,8 +880,9 @@ static void generate_label_tree_internal(struct dt_info *dti,
/* insert it */
p = build_property(l->label,
- data_copy_mem(node->fullpath,
- strlen(node->fullpath) + 1));
+ data_copy_escape_string(node->fullpath,
+ strlen(node->fullpath)),
+ NULL);
add_property(an, p);
}
@@ -919,13 +926,19 @@ static void add_fixup_entry(struct dt_info *dti, struct node *fn,
/* m->ref can only be a REF_PHANDLE, but check anyway */
assert(m->type == REF_PHANDLE);
+ /* The format only permits fixups for references to label, not
+ * references to path */
+ if (strchr(m->ref, '/'))
+ die("Can't generate fixup for reference to path &{%s}\n",
+ m->ref);
+
/* there shouldn't be any ':' in the arguments */
if (strchr(node->fullpath, ':') || strchr(prop->name, ':'))
die("arguments should not contain ':'\n");
xasprintf(&entry, "%s:%s:%u",
node->fullpath, prop->name, m->offset);
- append_to_property(fn, m->ref, entry, strlen(entry) + 1);
+ append_to_property(fn, m->ref, entry, strlen(entry) + 1, TYPE_STRING);
free(entry);
}
@@ -985,7 +998,7 @@ static void add_local_fixup_entry(struct dt_info *dti,
char **compp;
int i, depth;
- /* walk back retreiving depth */
+ /* walk back retrieving depth */
depth = 0;
for (wn = node; wn; wn = wn->parent)
depth++;
@@ -1000,15 +1013,13 @@ static void add_local_fixup_entry(struct dt_info *dti,
/* walk the path components creating nodes if they don't exist */
for (wn = lfn, i = 1; i < depth; i++, wn = nwn) {
/* if no node exists, create it */
- nwn = get_subnode(wn, compp[i]);
- if (!nwn)
- nwn = build_and_name_child_node(wn, compp[i]);
+ nwn = build_root_node(wn, compp[i]);
}
free(compp);
value_32 = cpu_to_fdt32(m->offset);
- append_to_property(wn, prop->name, &value_32, sizeof(value_32));
+ append_to_property(wn, prop->name, &value_32, sizeof(value_32), TYPE_UINT32);
}
static void generate_local_fixups_tree_internal(struct dt_info *dti,
@@ -1034,7 +1045,7 @@ static void generate_local_fixups_tree_internal(struct dt_info *dti,
generate_local_fixups_tree_internal(dti, lfn, c);
}
-void generate_label_tree(struct dt_info *dti, char *name, bool allocph)
+void generate_label_tree(struct dt_info *dti, const char *name, bool allocph)
{
if (!any_label_tree(dti, dti->dt))
return;
@@ -1042,18 +1053,31 @@ void generate_label_tree(struct dt_info *dti, char *name, bool allocph)
dti->dt, allocph);
}
-void generate_fixups_tree(struct dt_info *dti, char *name)
+void generate_fixups_tree(struct dt_info *dti, const char *name)
{
+ struct node *n = get_subnode(dti->dt, name);
+
+ /* Start with an empty __fixups__ node to not get duplicates */
+ if (n)
+ n->deleted = true;
+
if (!any_fixup_tree(dti, dti->dt))
return;
- generate_fixups_tree_internal(dti, build_root_node(dti->dt, name),
+ generate_fixups_tree_internal(dti,
+ build_and_name_child_node(dti->dt, name),
dti->dt);
}
-void generate_local_fixups_tree(struct dt_info *dti, char *name)
+void generate_local_fixups_tree(struct dt_info *dti, const char *name)
{
+ struct node *n = get_subnode(dti->dt, name);
+
+ /* Start with an empty __local_fixups__ node to not get duplicates */
+ if (n)
+ n->deleted = true;
if (!any_local_fixup_tree(dti, dti->dt))
return;
- generate_local_fixups_tree_internal(dti, build_root_node(dti->dt, name),
+ generate_local_fixups_tree_internal(dti,
+ build_and_name_child_node(dti->dt, name),
dti->dt);
}
diff --git a/scripts/dtc/srcpos.c b/scripts/dtc/srcpos.c
index 0ad89e2af60..627a0760e6e 100644
--- a/scripts/dtc/srcpos.c
+++ b/scripts/dtc/srcpos.c
@@ -1,23 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc.
- *
- * This program 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 program 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 program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
+#ifndef _GNU_SOURCE
#define _GNU_SOURCE
+#endif
#include <stdio.h>
@@ -33,6 +21,10 @@ struct search_path {
/* This is the list of directories that we search for source files */
static struct search_path *search_path_head, **search_path_tail;
+/* Detect infinite include recursion. */
+#define MAX_SRCFILE_DEPTH (200)
+static int srcfile_depth; /* = 0 */
+
static char *get_dirname(const char *path)
{
const char *slash = strrchr(path, '/');
@@ -50,10 +42,51 @@ static char *get_dirname(const char *path)
FILE *depfile; /* = NULL */
struct srcfile_state *current_srcfile; /* = NULL */
+static char *initial_path; /* = NULL */
+static int initial_pathlen; /* = 0 */
+static bool initial_cpp = true;
-/* Detect infinite include recursion. */
-#define MAX_SRCFILE_DEPTH (100)
-static int srcfile_depth; /* = 0 */
+static void set_initial_path(char *fname)
+{
+ int i, len = strlen(fname);
+
+ xasprintf(&initial_path, "%s", fname);
+ initial_pathlen = 0;
+ for (i = 0; i != len; i++)
+ if (initial_path[i] == '/')
+ initial_pathlen++;
+}
+
+static char *shorten_to_initial_path(char *fname)
+{
+ char *p1, *p2, *prevslash1 = NULL;
+ int slashes = 0;
+
+ for (p1 = fname, p2 = initial_path; *p1 && *p2; p1++, p2++) {
+ if (*p1 != *p2)
+ break;
+ if (*p1 == '/') {
+ prevslash1 = p1;
+ slashes++;
+ }
+ }
+ p1 = prevslash1 + 1;
+ if (prevslash1) {
+ int diff = initial_pathlen - slashes, i, j;
+ int restlen = strlen(fname) - (p1 - fname);
+ char *res;
+
+ res = xmalloc((3 * diff) + restlen + 1);
+ for (i = 0, j = 0; i != diff; i++) {
+ res[j++] = '.';
+ res[j++] = '.';
+ res[j++] = '/';
+ }
+ strcpy(res + j, p1);
+ return res;
+ }
+ return NULL;
+}
/**
* Try to open a file in a given directory.
@@ -127,8 +160,10 @@ FILE *srcfile_relative_open(const char *fname, char **fullnamep)
strerror(errno));
}
- if (depfile)
- fprintf(depfile, " %s", fullname);
+ if (depfile) {
+ fputc(' ', depfile);
+ fprint_path_escaped(depfile, fullname);
+ }
if (fullnamep)
*fullnamep = fullname;
@@ -155,6 +190,9 @@ void srcfile_push(const char *fname)
srcfile->colno = 1;
current_srcfile = srcfile;
+
+ if (srcfile_depth == 1)
+ set_initial_path(srcfile->name);
}
bool srcfile_pop(void)
@@ -195,18 +233,6 @@ void srcfile_add_search_path(const char *dirname)
search_path_tail = &node->next;
}
-/*
- * The empty source position.
- */
-
-struct srcpos srcpos_empty = {
- .first_line = 0,
- .first_column = 0,
- .last_line = 0,
- .last_column = 0,
- .file = NULL,
-};
-
void srcpos_update(struct srcpos *pos, const char *text, int len)
{
int i;
@@ -232,13 +258,46 @@ struct srcpos *
srcpos_copy(struct srcpos *pos)
{
struct srcpos *pos_new;
+ struct srcfile_state *srcfile_state;
+
+ if (!pos)
+ return NULL;
pos_new = xmalloc(sizeof(struct srcpos));
+ assert(pos->next == NULL);
memcpy(pos_new, pos, sizeof(struct srcpos));
+ /* allocate without free */
+ srcfile_state = xmalloc(sizeof(struct srcfile_state));
+ memcpy(srcfile_state, pos->file, sizeof(struct srcfile_state));
+ pos_new->file = srcfile_state;
+
return pos_new;
}
+struct srcpos *srcpos_extend(struct srcpos *pos, struct srcpos *newtail)
+{
+ struct srcpos *p;
+
+ if (!pos)
+ return newtail;
+
+ for (p = pos; p->next != NULL; p = p->next);
+ p->next = newtail;
+ return pos;
+}
+
+void srcpos_free(struct srcpos *pos)
+{
+ struct srcpos *p_next;
+
+ while (pos) {
+ p_next = pos->next;
+ free(pos);
+ pos = p_next;
+ }
+}
+
char *
srcpos_string(struct srcpos *pos)
{
@@ -263,6 +322,68 @@ srcpos_string(struct srcpos *pos)
return pos_str;
}
+static char *
+srcpos_string_comment(struct srcpos *pos, bool first_line, int level)
+{
+ char *pos_str, *fresh_fname = NULL, *first, *rest;
+ const char *fname;
+
+ if (!pos) {
+ if (level > 1) {
+ xasprintf(&pos_str, "<no-file>:<no-line>");
+ return pos_str;
+ } else {
+ return NULL;
+ }
+ }
+
+ if (!pos->file)
+ fname = "<no-file>";
+ else if (!pos->file->name)
+ fname = "<no-filename>";
+ else if (level > 1)
+ fname = pos->file->name;
+ else {
+ fresh_fname = shorten_to_initial_path(pos->file->name);
+ if (fresh_fname)
+ fname = fresh_fname;
+ else
+ fname = pos->file->name;
+ }
+
+ if (level > 1)
+ xasprintf(&first, "%s:%d:%d-%d:%d", fname,
+ pos->first_line, pos->first_column,
+ pos->last_line, pos->last_column);
+ else
+ xasprintf(&first, "%s:%d", fname,
+ first_line ? pos->first_line : pos->last_line);
+
+ if (fresh_fname)
+ free(fresh_fname);
+
+ if (pos->next != NULL) {
+ rest = srcpos_string_comment(pos->next, first_line, level);
+ xasprintf(&pos_str, "%s, %s", first, rest);
+ free(first);
+ free(rest);
+ } else {
+ pos_str = first;
+ }
+
+ return pos_str;
+}
+
+char *srcpos_string_first(struct srcpos *pos, int level)
+{
+ return srcpos_string_comment(pos, true, level);
+}
+
+char *srcpos_string_last(struct srcpos *pos, int level)
+{
+ return srcpos_string_comment(pos, false, level);
+}
+
void srcpos_verror(struct srcpos *pos, const char *prefix,
const char *fmt, va_list va)
{
@@ -291,4 +412,9 @@ void srcpos_set_line(char *f, int l)
{
current_srcfile->name = f;
current_srcfile->lineno = l;
+
+ if (initial_cpp) {
+ initial_cpp = false;
+ set_initial_path(f);
+ }
}
diff --git a/scripts/dtc/srcpos.h b/scripts/dtc/srcpos.h
index fcd9937a911..0b634f212eb 100644
--- a/scripts/dtc/srcpos.h
+++ b/scripts/dtc/srcpos.h
@@ -1,20 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc.
- *
- * This program 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 program 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 program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
#ifndef SRCPOS_H
@@ -74,6 +60,7 @@ struct srcpos {
int last_line;
int last_column;
struct srcfile_state *file;
+ struct srcpos *next;
};
#define YYLTYPE struct srcpos
@@ -93,18 +80,18 @@ struct srcpos {
YYRHSLOC(Rhs, 0).last_column; \
(Current).file = YYRHSLOC (Rhs, 0).file; \
} \
+ (Current).next = NULL; \
} while (0)
-/*
- * Fictional source position used for IR nodes that are
- * created without otherwise knowing a true source position.
- * For example,constant definitions from the command line.
- */
-extern struct srcpos srcpos_empty;
-
extern void srcpos_update(struct srcpos *pos, const char *text, int len);
extern struct srcpos *srcpos_copy(struct srcpos *pos);
+extern struct srcpos *srcpos_extend(struct srcpos *new_srcpos,
+ struct srcpos *old_srcpos);
+extern void srcpos_free(struct srcpos *pos);
extern char *srcpos_string(struct srcpos *pos);
+extern char *srcpos_string_first(struct srcpos *pos, int level);
+extern char *srcpos_string_last(struct srcpos *pos, int level);
+
extern void PRINTF(3, 0) srcpos_verror(struct srcpos *pos, const char *prefix,
const char *fmt, va_list va);
diff --git a/scripts/dtc/treesource.c b/scripts/dtc/treesource.c
index 8c8b914698d..d25f01fc693 100644
--- a/scripts/dtc/treesource.c
+++ b/scripts/dtc/treesource.c
@@ -1,21 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
- *
- *
- * This program 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 program 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 program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
#include "dtc.h"
@@ -61,24 +46,18 @@ static bool isstring(char c)
|| strchr("\a\b\t\n\v\f\r", c));
}
-static void write_propval_string(FILE *f, struct data val)
+static void write_propval_string(FILE *f, const char *s, size_t len)
{
- const char *str = val.val;
- int i;
- struct marker *m = val.markers;
-
- assert(str[val.len-1] == '\0');
+ const char *end = s + len - 1;
- while (m && (m->offset == 0)) {
- if (m->type == LABEL)
- fprintf(f, "%s: ", m->ref);
- m = m->next;
- }
- fprintf(f, "\"");
+ if (!len)
+ return;
- for (i = 0; i < (val.len-1); i++) {
- char c = str[i];
+ assert(*end == '\0');
+ fprintf(f, "\"");
+ while (s < end) {
+ char c = *s++;
switch (c) {
case '\a':
fprintf(f, "\\a");
@@ -108,91 +87,103 @@ static void write_propval_string(FILE *f, struct data val)
fprintf(f, "\\\"");
break;
case '\0':
- fprintf(f, "\", ");
- while (m && (m->offset <= (i + 1))) {
- if (m->type == LABEL) {
- assert(m->offset == (i+1));
- fprintf(f, "%s: ", m->ref);
- }
- m = m->next;
- }
- fprintf(f, "\"");
+ fprintf(f, "\\0");
break;
default:
if (isprint((unsigned char)c))
fprintf(f, "%c", c);
else
- fprintf(f, "\\x%02hhx", c);
+ fprintf(f, "\\x%02"PRIx8, c);
}
}
fprintf(f, "\"");
-
- /* Wrap up any labels at the end of the value */
- for_each_marker_of_type(m, LABEL) {
- assert (m->offset == val.len);
- fprintf(f, " %s:", m->ref);
- }
}
-static void write_propval_cells(FILE *f, struct data val)
+static void write_propval_int(FILE *f, const char *p, size_t len, size_t width)
{
- void *propend = val.val + val.len;
- fdt32_t *cp = (fdt32_t *)val.val;
- struct marker *m = val.markers;
-
- fprintf(f, "<");
- for (;;) {
- while (m && (m->offset <= ((char *)cp - val.val))) {
- if (m->type == LABEL) {
- assert(m->offset == ((char *)cp - val.val));
- fprintf(f, "%s: ", m->ref);
- }
- m = m->next;
- }
+ const char *end = p + len;
+ assert(len % width == 0);
- fprintf(f, "0x%x", fdt32_to_cpu(*cp++));
- if ((void *)cp >= propend)
+ for (; p < end; p += width) {
+ switch (width) {
+ case 1:
+ fprintf(f, "%02"PRIx8, *(const uint8_t*)p);
break;
- fprintf(f, " ");
- }
-
- /* Wrap up any labels at the end of the value */
- for_each_marker_of_type(m, LABEL) {
- assert (m->offset == val.len);
- fprintf(f, " %s:", m->ref);
+ case 2:
+ fprintf(f, "0x%02"PRIx16, dtb_ld16(p));
+ break;
+ case 4:
+ fprintf(f, "0x%02"PRIx32, dtb_ld32(p));
+ break;
+ case 8:
+ fprintf(f, "0x%02"PRIx64, dtb_ld64(p));
+ break;
+ }
+ if (p + width < end)
+ fputc(' ', f);
}
- fprintf(f, ">");
}
-static void write_propval_bytes(FILE *f, struct data val)
+static const char *delim_start[] = {
+ [TYPE_UINT8] = "[",
+ [TYPE_UINT16] = "/bits/ 16 <",
+ [TYPE_UINT32] = "<",
+ [TYPE_UINT64] = "/bits/ 64 <",
+ [TYPE_STRING] = "",
+};
+static const char *delim_end[] = {
+ [TYPE_UINT8] = "]",
+ [TYPE_UINT16] = ">",
+ [TYPE_UINT32] = ">",
+ [TYPE_UINT64] = ">",
+ [TYPE_STRING] = "",
+};
+
+/*
+ * The invariants in the marker list are:
+ * - offsets are non-strictly monotonically increasing
+ * - for a single offset there is at most one type marker
+ * - for a single offset that has both a type marker and non-type markers, the
+ * type marker appears before the others.
+ */
+static struct marker **add_marker(struct marker **mi,
+ enum markertype type, unsigned int offset, char *ref)
{
- void *propend = val.val + val.len;
- const char *bp = val.val;
- struct marker *m = val.markers;
-
- fprintf(f, "[");
- for (;;) {
- while (m && (m->offset == (bp-val.val))) {
- if (m->type == LABEL)
- fprintf(f, "%s: ", m->ref);
- m = m->next;
- }
+ struct marker *nm;
- fprintf(f, "%02hhx", (unsigned char)(*bp++));
- if ((const void *)bp >= propend)
- break;
- fprintf(f, " ");
- }
+ while (*mi && (*mi)->offset < offset)
+ mi = &(*mi)->next;
- /* Wrap up any labels at the end of the value */
- for_each_marker_of_type(m, LABEL) {
- assert (m->offset == val.len);
- fprintf(f, " %s:", m->ref);
+ if (*mi && (*mi)->offset == offset && is_type_marker((*mi)->type)) {
+ if (is_type_marker(type))
+ return mi;
+ mi = &(*mi)->next;
}
- fprintf(f, "]");
+
+ if (*mi && (*mi)->offset == offset && type == (*mi)->type)
+ return mi;
+
+ nm = xmalloc(sizeof(*nm));
+ nm->type = type;
+ nm->offset = offset;
+ nm->ref = ref;
+ nm->next = *mi;
+ *mi = nm;
+
+ return &nm->next;
}
-static void write_propval(FILE *f, struct property *prop)
+static void add_string_markers(struct property *prop)
+{
+ int l, len = prop->val.len;
+ const char *p = prop->val.val;
+ struct marker **mi = &prop->val.markers;
+
+ for (l = strlen(p) + 1; l < len; l += strlen(p + l) + 1)
+ mi = add_marker(mi, TYPE_STRING, l, NULL);
+}
+
+static enum markertype guess_value_type(struct property *prop)
{
int len = prop->val.len;
const char *p = prop->val.val;
@@ -201,11 +192,6 @@ static void write_propval(FILE *f, struct property *prop)
int nnotstringlbl = 0, nnotcelllbl = 0;
int i;
- if (len == 0) {
- fprintf(f, ";\n");
- return;
- }
-
for (i = 0; i < len; i++) {
if (! isstring(p[i]))
nnotstring++;
@@ -220,17 +206,116 @@ static void write_propval(FILE *f, struct property *prop)
nnotcelllbl++;
}
- fprintf(f, " = ");
- if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul < (len-nnul))
+ if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul <= (len-nnul))
&& (nnotstringlbl == 0)) {
- write_propval_string(f, prop->val);
+ if (nnul > 1)
+ add_string_markers(prop);
+ return TYPE_STRING;
} else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) {
- write_propval_cells(f, prop->val);
- } else {
- write_propval_bytes(f, prop->val);
+ return TYPE_UINT32;
}
- fprintf(f, ";\n");
+ return TYPE_UINT8;
+}
+
+static void write_propval(FILE *f, struct property *prop)
+{
+ size_t len = prop->val.len;
+ struct marker *m = prop->val.markers;
+ struct marker dummy_marker;
+ enum markertype emit_type = TYPE_NONE;
+ char *srcstr;
+
+ if (len == 0) {
+ fprintf(f, ";");
+ if (annotate) {
+ srcstr = srcpos_string_first(prop->srcpos, annotate);
+ if (srcstr) {
+ fprintf(f, " /* %s */", srcstr);
+ free(srcstr);
+ }
+ }
+ fprintf(f, "\n");
+ return;
+ }
+
+ fprintf(f, " =");
+
+ if (!next_type_marker(m)) {
+ /* data type information missing, need to guess */
+ dummy_marker.type = guess_value_type(prop);
+ dummy_marker.next = prop->val.markers;
+ dummy_marker.offset = 0;
+ dummy_marker.ref = NULL;
+ m = &dummy_marker;
+ }
+
+ for_each_marker(m) {
+ size_t chunk_len = (m->next ? m->next->offset : len) - m->offset;
+ size_t data_len = type_marker_length(m) ? : len - m->offset;
+ const char *p = &prop->val.val[m->offset];
+ struct marker *m_phandle;
+
+ if (is_type_marker(m->type)) {
+ emit_type = m->type;
+ fprintf(f, " %s", delim_start[emit_type]);
+ } else if (m->type == LABEL)
+ fprintf(f, " %s:", m->ref);
+
+ if (emit_type == TYPE_NONE || chunk_len == 0)
+ continue;
+
+ switch(emit_type) {
+ case TYPE_UINT16:
+ write_propval_int(f, p, chunk_len, 2);
+ break;
+ case TYPE_UINT32:
+ m_phandle = prop->val.markers;
+ for_each_marker_of_type(m_phandle, REF_PHANDLE)
+ if (m->offset == m_phandle->offset)
+ break;
+
+ if (m_phandle) {
+ if (m_phandle->ref[0] == '/')
+ fprintf(f, "&{%s}", m_phandle->ref);
+ else
+ fprintf(f, "&%s", m_phandle->ref);
+ if (chunk_len > 4) {
+ fputc(' ', f);
+ write_propval_int(f, p + 4, chunk_len - 4, 4);
+ }
+ } else {
+ write_propval_int(f, p, chunk_len, 4);
+ }
+ if (data_len > chunk_len)
+ fputc(' ', f);
+ break;
+ case TYPE_UINT64:
+ write_propval_int(f, p, chunk_len, 8);
+ break;
+ case TYPE_STRING:
+ write_propval_string(f, p, chunk_len);
+ break;
+ default:
+ write_propval_int(f, p, chunk_len, 1);
+ }
+
+ if (chunk_len == data_len) {
+ size_t pos = m->offset + chunk_len;
+ fprintf(f, pos == len ? "%s" : "%s,",
+ delim_end[emit_type] ? : "");
+ emit_type = TYPE_NONE;
+ }
+ }
+ fprintf(f, ";");
+ if (annotate) {
+ srcstr = srcpos_string_first(prop->srcpos, annotate);
+ if (srcstr) {
+ fprintf(f, " /* %s */", srcstr);
+ free(srcstr);
+ }
+ }
+ fprintf(f, "\n");
}
static void write_tree_source_node(FILE *f, struct node *tree, int level)
@@ -238,14 +323,24 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level)
struct property *prop;
struct node *child;
struct label *l;
+ char *srcstr;
write_prefix(f, level);
for_each_label(tree->labels, l)
fprintf(f, "%s: ", l->label);
if (tree->name && (*tree->name))
- fprintf(f, "%s {\n", tree->name);
+ fprintf(f, "%s {", tree->name);
else
- fprintf(f, "/ {\n");
+ fprintf(f, "/ {");
+
+ if (annotate) {
+ srcstr = srcpos_string_first(tree->srcpos, annotate);
+ if (srcstr) {
+ fprintf(f, " /* %s */", srcstr);
+ free(srcstr);
+ }
+ }
+ fprintf(f, "\n");
for_each_property(tree, prop) {
write_prefix(f, level+1);
@@ -259,7 +354,15 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level)
write_tree_source_node(f, child, level+1);
}
write_prefix(f, level);
- fprintf(f, "};\n");
+ fprintf(f, "};");
+ if (annotate) {
+ srcstr = srcpos_string_last(tree->srcpos, annotate);
+ if (srcstr) {
+ fprintf(f, " /* %s */", srcstr);
+ free(srcstr);
+ }
+ }
+ fprintf(f, "\n");
}
void dt_to_source(FILE *f, struct dt_info *dti)
diff --git a/scripts/dtc/update-dtc-source.sh b/scripts/dtc/update-dtc-source.sh
index 1a009fd195d..32ff17ffd08 100755
--- a/scripts/dtc/update-dtc-source.sh
+++ b/scripts/dtc/update-dtc-source.sh
@@ -32,11 +32,12 @@ DTC_UPSTREAM_PATH=`pwd`/../dtc
DTC_LINUX_PATH=`pwd`/scripts/dtc
DTC_SOURCE="checks.c data.c dtc.c dtc.h flattree.c fstree.c livetree.c srcpos.c \
- srcpos.h treesource.c util.c util.h version_gen.h Makefile.dtc \
+ srcpos.h treesource.c util.c util.h version_gen.h yamltree.c \
dtc-lexer.l dtc-parser.y"
-LIBFDT_SOURCE="Makefile.libfdt fdt.c fdt.h fdt_addresses.c fdt_empty_tree.c \
+LIBFDT_SOURCE="fdt.c fdt.h fdt_addresses.c fdt_empty_tree.c \
fdt_overlay.c fdt_ro.c fdt_rw.c fdt_strerror.c fdt_sw.c \
fdt_wip.c libfdt.h libfdt_env.h libfdt_internal.h"
+FDTOVERLAY_SOURCE=fdtoverlay.c
get_last_dtc_version() {
git log --oneline scripts/dtc/ | grep 'upstream' | head -1 | sed -e 's/^.* \(.*\)/\1/'
@@ -54,7 +55,7 @@ dtc_log=$(git log --oneline ${last_dtc_ver}..)
# Copy the files into the Linux tree
cd $DTC_LINUX_PATH
-for f in $DTC_SOURCE; do
+for f in $DTC_SOURCE $FDTOVERLAY_SOURCE; do
cp ${DTC_UPSTREAM_PATH}/${f} ${f}
git add ${f}
done
diff --git a/scripts/dtc/util.c b/scripts/dtc/util.c
index 25d4db1e8c2..0e19a9f8acf 100644
--- a/scripts/dtc/util.c
+++ b/scripts/dtc/util.c
@@ -1,24 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright 2011 The Chromium Authors, All Rights Reserved.
* Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
*
* util_is_printable_string contributed by
* Pantelis Antoniou <pantelis.antoniou AT gmail.com>
- *
- * This program 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 program 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 program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
#include <ctype.h>
@@ -27,6 +13,7 @@
#include <stdarg.h>
#include <string.h>
#include <assert.h>
+#include <inttypes.h>
#include <errno.h>
#include <fcntl.h>
@@ -36,6 +23,22 @@
#include "util.h"
#include "version_gen.h"
+void fprint_path_escaped(FILE *fp, const char *path)
+{
+ const char *p = path;
+
+ while (*p) {
+ if (*p == ' ') {
+ fputc('\\', fp);
+ fputc(' ', fp);
+ } else {
+ fputc(*p, fp);
+ }
+
+ p++;
+ }
+}
+
char *xstrdup(const char *s)
{
int len = strlen(s) + 1;
@@ -57,36 +60,54 @@ char *xstrndup(const char *s, size_t n)
return d;
}
-/* based in part from (3) vsnprintf */
-int xasprintf(char **strp, const char *fmt, ...)
+int xavsprintf_append(char **strp, const char *fmt, va_list ap)
{
- int n, size = 128; /* start with 128 bytes */
+ int n, size = 0; /* start with 128 bytes */
char *p;
- va_list ap;
+ va_list ap_copy;
- /* initial pointer is NULL making the fist realloc to be malloc */
- p = NULL;
- while (1) {
- p = xrealloc(p, size);
+ p = *strp;
+ if (p)
+ size = strlen(p);
- /* Try to print in the allocated space. */
- va_start(ap, fmt);
- n = vsnprintf(p, size, fmt, ap);
- va_end(ap);
+ va_copy(ap_copy, ap);
+ n = vsnprintf(NULL, 0, fmt, ap_copy) + 1;
+ va_end(ap_copy);
+
+ p = xrealloc(p, size + n);
+
+ n = vsnprintf(p + size, n, fmt, ap);
- /* If that worked, return the string. */
- if (n > -1 && n < size)
- break;
- /* Else try again with more space. */
- if (n > -1) /* glibc 2.1 */
- size = n + 1; /* precisely what is needed */
- else /* glibc 2.0 */
- size *= 2; /* twice the old size */
- }
*strp = p;
return strlen(p);
}
+int xasprintf_append(char **strp, const char *fmt, ...)
+{
+ int n;
+ va_list ap;
+
+ va_start(ap, fmt);
+ n = xavsprintf_append(strp, fmt, ap);
+ va_end(ap);
+
+ return n;
+}
+
+int xasprintf(char **strp, const char *fmt, ...)
+{
+ int n;
+ va_list ap;
+
+ *strp = NULL;
+
+ va_start(ap, fmt);
+ n = xavsprintf_append(strp, fmt, ap);
+ va_end(ap);
+
+ return n;
+}
+
char *join_path(const char *path, const char *name)
{
int lenp = strlen(path);
@@ -238,11 +259,11 @@ char get_escape_char(const char *s, int *i)
return val;
}
-int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len)
+int utilfdt_read_err(const char *filename, char **buffp, size_t *len)
{
int fd = 0; /* assume stdin */
char *buf = NULL;
- off_t bufsize = 1024, offset = 0;
+ size_t bufsize = 1024, offset = 0;
int ret = 0;
*buffp = NULL;
@@ -275,20 +296,15 @@ int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len)
free(buf);
else
*buffp = buf;
- *len = bufsize;
+ if (len)
+ *len = bufsize;
return ret;
}
-int utilfdt_read_err(const char *filename, char **buffp)
-{
- off_t len;
- return utilfdt_read_err_len(filename, buffp, &len);
-}
-
-char *utilfdt_read_len(const char *filename, off_t *len)
+char *utilfdt_read(const char *filename, size_t *len)
{
char *buff;
- int ret = utilfdt_read_err_len(filename, &buff, len);
+ int ret = utilfdt_read_err(filename, &buff, len);
if (ret) {
fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
@@ -299,12 +315,6 @@ char *utilfdt_read_len(const char *filename, off_t *len)
return buff;
}
-char *utilfdt_read(const char *filename)
-{
- off_t len;
- return utilfdt_read_len(filename, &len);
-}
-
int utilfdt_write_err(const char *filename, const void *blob)
{
int fd = 1; /* assume stdout */
@@ -369,11 +379,11 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size)
}
/* we should now have a type */
- if ((*fmt == '\0') || !strchr("iuxs", *fmt))
+ if ((*fmt == '\0') || !strchr("iuxsr", *fmt))
return -1;
/* convert qualifier (bhL) to byte size */
- if (*fmt != 's')
+ if (*fmt != 's' && *fmt != 'r')
*size = qualifier == 'b' ? 1 :
qualifier == 'h' ? 2 :
qualifier == 'l' ? 4 : -1;
@@ -410,7 +420,7 @@ void utilfdt_print_data(const char *data, int len)
printf(" = <");
for (i = 0, len /= 4; i < len; i++)
- printf("0x%08x%s", fdt32_to_cpu(cell[i]),
+ printf("0x%08" PRIx32 "%s", fdt32_to_cpu(cell[i]),
i < (len - 1) ? " " : "");
printf(">");
} else {
diff --git a/scripts/dtc/util.h b/scripts/dtc/util.h
index 23e32962385..2d63a9a9d8d 100644
--- a/scripts/dtc/util.h
+++ b/scripts/dtc/util.h
@@ -1,6 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef UTIL_H
#define UTIL_H
+#include <stdlib.h>
#include <stdarg.h>
#include <stdbool.h>
#include <getopt.h>
@@ -8,25 +10,16 @@
/*
* Copyright 2011 The Chromium Authors, All Rights Reserved.
* Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
- *
- * This program 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 program 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 program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
#ifdef __GNUC__
+#ifdef __MINGW_PRINTF_FORMAT
+#define PRINTF(i, j) __attribute__((format (__MINGW_PRINTF_FORMAT, i, j)))
+#elif __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)
+#define PRINTF(i, j) __attribute__((format (gnu_printf, i, j)))
+#else
#define PRINTF(i, j) __attribute__((format (printf, i, j)))
+#endif
#define NORETURN __attribute__((noreturn))
#else
#define PRINTF(i, j)
@@ -49,6 +42,11 @@ static inline void NORETURN PRINTF(1, 2) die(const char *str, ...)
exit(1);
}
+/**
+ * Writes path to fp, escaping spaces with a backslash.
+ */
+void fprint_path_escaped(FILE *fp, const char *path);
+
static inline void *xmalloc(size_t len)
{
void *new = malloc(len);
@@ -73,6 +71,8 @@ extern char *xstrdup(const char *s);
extern char *xstrndup(const char *s, size_t len);
extern int PRINTF(2, 3) xasprintf(char **strp, const char *fmt, ...);
+extern int PRINTF(2, 3) xasprintf_append(char **strp, const char *fmt, ...);
+extern int PRINTF(2, 0) xavsprintf_append(char **strp, const char *fmt, va_list ap);
extern char *join_path(const char *path, const char *name);
/**
@@ -99,16 +99,10 @@ char get_escape_char(const char *s, int *i);
* stderr.
*
* @param filename The filename to read, or - for stdin
- * Return: Pointer to allocated buffer containing fdt, or NULL on error
- */
-char *utilfdt_read(const char *filename);
-
-/**
- * Like utilfdt_read(), but also passes back the size of the file read.
- *
* @param len If non-NULL, the amount of data we managed to read
+ * @return Pointer to allocated buffer containing fdt, or NULL on error
*/
-char *utilfdt_read_len(const char *filename, off_t *len);
+char *utilfdt_read(const char *filename, size_t *len);
/**
* Read a device tree file into a buffer. Does not report errors, but only
@@ -117,24 +111,18 @@ char *utilfdt_read_len(const char *filename, off_t *len);
*
* @param filename The filename to read, or - for stdin
* @param buffp Returns pointer to buffer containing fdt
- * Return: 0 if ok, else an errno value representing the error
- */
-int utilfdt_read_err(const char *filename, char **buffp);
-
-/**
- * Like utilfdt_read_err(), but also passes back the size of the file read.
- *
* @param len If non-NULL, the amount of data we managed to read
+ * @return 0 if ok, else an errno value representing the error
*/
-int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len);
+int utilfdt_read_err(const char *filename, char **buffp, size_t *len);
/**
* Write a device tree buffer to a file. This will report any errors on
* stderr.
*
* @param filename The filename to write, or - for stdout
- * @param blob Poiner to buffer containing fdt
- * Return: 0 if ok, -1 on error
+ * @param blob Pointer to buffer containing fdt
+ * @return 0 if ok, -1 on error
*/
int utilfdt_write(const char *filename, const void *blob);
@@ -144,8 +132,8 @@ int utilfdt_write(const char *filename, const void *blob);
* an error message for the user.
*
* @param filename The filename to write, or - for stdout
- * @param blob Poiner to buffer containing fdt
- * Return: 0 if ok, else an errno value representing the error
+ * @param blob Pointer to buffer containing fdt
+ * @return 0 if ok, else an errno value representing the error
*/
int utilfdt_write_err(const char *filename, const void *blob);
@@ -163,6 +151,7 @@ int utilfdt_write_err(const char *filename, const void *blob);
* i signed integer
* u unsigned integer
* x hex
+ * r raw
*
* TODO: Implement ll modifier (8 bytes)
* TODO: Implement o type (octal)
@@ -180,7 +169,7 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size);
*/
#define USAGE_TYPE_MSG \
- "<type>\ts=string, i=int, u=unsigned, x=hex\n" \
+ "<type>\ts=string, i=int, u=unsigned, x=hex, r=raw\n" \
"\tOptional modifier prefix:\n" \
"\t\thh or b=byte, h=2 byte, l=4 byte (default)";
diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h
index b00f14ff7a1..226c48bf75d 100644
--- a/scripts/dtc/version_gen.h
+++ b/scripts/dtc/version_gen.h
@@ -1 +1 @@
-#define DTC_VERSION "DTC 1.4.6-g84e414b0"
+#define DTC_VERSION "DTC 1.7.2-g52f07dcc"
diff --git a/scripts/dtc/yamltree.c b/scripts/dtc/yamltree.c
new file mode 100644
index 00000000000..55908c829c9
--- /dev/null
+++ b/scripts/dtc/yamltree.c
@@ -0,0 +1,235 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright Linaro, Ltd. 2018
+ * (C) Copyright Arm Holdings. 2017
+ * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
+ */
+
+#include <stdlib.h>
+#include <yaml.h>
+#include "dtc.h"
+#include "srcpos.h"
+
+char *yaml_error_name[] = {
+ [YAML_NO_ERROR] = "no error",
+ [YAML_MEMORY_ERROR] = "memory error",
+ [YAML_READER_ERROR] = "reader error",
+ [YAML_SCANNER_ERROR] = "scanner error",
+ [YAML_PARSER_ERROR] = "parser error",
+ [YAML_COMPOSER_ERROR] = "composer error",
+ [YAML_WRITER_ERROR] = "writer error",
+ [YAML_EMITTER_ERROR] = "emitter error",
+};
+
+#define yaml_emitter_emit_or_die(emitter, event) ( \
+{ \
+ if (!yaml_emitter_emit(emitter, event)) \
+ die("yaml '%s': %s in %s, line %i\n", \
+ yaml_error_name[(emitter)->error], \
+ (emitter)->problem, __func__, __LINE__); \
+})
+
+static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers,
+ char *data, unsigned int seq_offset, unsigned int len, int width)
+{
+ yaml_event_t event;
+ void *tag;
+ unsigned int off;
+
+ switch(width) {
+ case 1: tag = "!u8"; break;
+ case 2: tag = "!u16"; break;
+ case 4: tag = "!u32"; break;
+ case 8: tag = "!u64"; break;
+ default:
+ die("Invalid width %i", width);
+ }
+ assert(len % width == 0);
+
+ yaml_sequence_start_event_initialize(&event, NULL,
+ (yaml_char_t *)tag, width == 4, YAML_FLOW_SEQUENCE_STYLE);
+ yaml_emitter_emit_or_die(emitter, &event);
+
+ for (off = 0; off < len; off += width) {
+ char buf[32];
+ struct marker *m;
+ bool is_phandle = false;
+
+ switch(width) {
+ case 1:
+ sprintf(buf, "0x%"PRIx8, *(uint8_t*)(data + off));
+ break;
+ case 2:
+ sprintf(buf, "0x%"PRIx16, dtb_ld16(data + off));
+ break;
+ case 4:
+ sprintf(buf, "0x%"PRIx32, dtb_ld32(data + off));
+ m = markers;
+ is_phandle = false;
+ for_each_marker_of_type(m, REF_PHANDLE) {
+ if (m->offset == (seq_offset + off)) {
+ is_phandle = true;
+ break;
+ }
+ }
+ break;
+ case 8:
+ sprintf(buf, "0x%"PRIx64, dtb_ld64(data + off));
+ break;
+ }
+
+ if (is_phandle)
+ yaml_scalar_event_initialize(&event, NULL,
+ (yaml_char_t*)"!phandle", (yaml_char_t *)buf,
+ strlen(buf), 0, 0, YAML_PLAIN_SCALAR_STYLE);
+ else
+ yaml_scalar_event_initialize(&event, NULL,
+ (yaml_char_t*)YAML_INT_TAG, (yaml_char_t *)buf,
+ strlen(buf), 1, 1, YAML_PLAIN_SCALAR_STYLE);
+ yaml_emitter_emit_or_die(emitter, &event);
+ }
+
+ yaml_sequence_end_event_initialize(&event);
+ yaml_emitter_emit_or_die(emitter, &event);
+}
+
+static void yaml_propval_string(yaml_emitter_t *emitter, char *str, int len)
+{
+ yaml_event_t event;
+ int i;
+
+ assert(str[len-1] == '\0');
+
+ /* Make sure the entire string is in the lower 7-bit ascii range */
+ for (i = 0; i < len; i++)
+ assert(isascii(str[i]));
+
+ yaml_scalar_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)str,
+ len-1, 0, 1, YAML_DOUBLE_QUOTED_SCALAR_STYLE);
+ yaml_emitter_emit_or_die(emitter, &event);
+}
+
+static void yaml_propval(yaml_emitter_t *emitter, struct property *prop)
+{
+ yaml_event_t event;
+ unsigned int len = prop->val.len;
+ struct marker *m = prop->val.markers;
+ struct marker *markers = prop->val.markers;
+
+ /* Emit the property name */
+ yaml_scalar_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)prop->name,
+ strlen(prop->name), 1, 1, YAML_PLAIN_SCALAR_STYLE);
+ yaml_emitter_emit_or_die(emitter, &event);
+
+ /* Boolean properties are easiest to deal with. Length is zero, so just emit 'true' */
+ if (len == 0) {
+ yaml_scalar_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_BOOL_TAG,
+ (yaml_char_t*)"true",
+ strlen("true"), 1, 0, YAML_PLAIN_SCALAR_STYLE);
+ yaml_emitter_emit_or_die(emitter, &event);
+ return;
+ }
+
+ if (!m)
+ die("No markers present in property '%s' value\n", prop->name);
+
+ yaml_sequence_start_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_SEQ_TAG, 1, YAML_FLOW_SEQUENCE_STYLE);
+ yaml_emitter_emit_or_die(emitter, &event);
+
+ for_each_marker(m) {
+ int chunk_len;
+ char *data = &prop->val.val[m->offset];
+
+ if (m->type < TYPE_UINT8)
+ continue;
+
+ chunk_len = type_marker_length(m) ? : len;
+ assert(chunk_len > 0);
+ len -= chunk_len;
+
+ switch(m->type) {
+ case TYPE_UINT16:
+ yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 2);
+ break;
+ case TYPE_UINT32:
+ yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 4);
+ break;
+ case TYPE_UINT64:
+ yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 8);
+ break;
+ case TYPE_STRING:
+ yaml_propval_string(emitter, data, chunk_len);
+ break;
+ default:
+ yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 1);
+ break;
+ }
+ }
+
+ yaml_sequence_end_event_initialize(&event);
+ yaml_emitter_emit_or_die(emitter, &event);
+}
+
+
+static void yaml_tree(struct node *tree, yaml_emitter_t *emitter)
+{
+ struct property *prop;
+ struct node *child;
+ yaml_event_t event;
+
+ if (tree->deleted)
+ return;
+
+ yaml_mapping_start_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_MAP_TAG, 1, YAML_ANY_MAPPING_STYLE);
+ yaml_emitter_emit_or_die(emitter, &event);
+
+ for_each_property(tree, prop)
+ yaml_propval(emitter, prop);
+
+ /* Loop over all the children, emitting them into the map */
+ for_each_child(tree, child) {
+ yaml_scalar_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)child->name,
+ strlen(child->name), 1, 0, YAML_PLAIN_SCALAR_STYLE);
+ yaml_emitter_emit_or_die(emitter, &event);
+ yaml_tree(child, emitter);
+ }
+
+ yaml_mapping_end_event_initialize(&event);
+ yaml_emitter_emit_or_die(emitter, &event);
+}
+
+void dt_to_yaml(FILE *f, struct dt_info *dti)
+{
+ yaml_emitter_t emitter;
+ yaml_event_t event;
+
+ yaml_emitter_initialize(&emitter);
+ yaml_emitter_set_output_file(&emitter, f);
+ yaml_stream_start_event_initialize(&event, YAML_UTF8_ENCODING);
+ yaml_emitter_emit_or_die(&emitter, &event);
+
+ yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
+ yaml_emitter_emit_or_die(&emitter, &event);
+
+ yaml_sequence_start_event_initialize(&event, NULL, (yaml_char_t *)YAML_SEQ_TAG, 1, YAML_ANY_SEQUENCE_STYLE);
+ yaml_emitter_emit_or_die(&emitter, &event);
+
+ yaml_tree(dti->dt, &emitter);
+
+ yaml_sequence_end_event_initialize(&event);
+ yaml_emitter_emit_or_die(&emitter, &event);
+
+ yaml_document_end_event_initialize(&event, 0);
+ yaml_emitter_emit_or_die(&emitter, &event);
+
+ yaml_stream_end_event_initialize(&event);
+ yaml_emitter_emit_or_die(&emitter, &event);
+
+ yaml_emitter_delete(&emitter);
+}
diff --git a/tools/libfdt/fdt_rw.c b/tools/libfdt/fdt_rw.c
index 7189f014295..a3e575bf678 100644
--- a/tools/libfdt/fdt_rw.c
+++ b/tools/libfdt/fdt_rw.c
@@ -26,7 +26,7 @@ int fdt_remove_unused_strings(const void *old, void *new)
new_prop = (struct fdt_property *)(unsigned long)
fdt_get_property_by_offset(new, offset, NULL);
str = fdt_string(old, fdt32_to_cpu(old_prop->nameoff));
- ret = fdt_find_add_string_(new, str, &allocated);
+ ret = fdt_find_add_string_(new, str, strlen(str) + 1, &allocated);
if (ret < 0)
return ret;
new_prop->nameoff = cpu_to_fdt32(ret);
--
2.51.0
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH 3/3] libfdt: Check fdt_offset_ptr() return value unconditionally
2025-11-13 12:21 [PATCH 0/3] Synchronize DTC to 1.7.2 Marek Vasut
2025-11-13 12:21 ` [PATCH 1/3] dm: core: Check ofnode_to_offset() return value Marek Vasut
2025-11-13 12:21 ` [PATCH 2/3] scripts/dtc: Update to upstream version v1.7.2-35-g52f07dcca47c Marek Vasut
@ 2025-11-13 12:21 ` Marek Vasut
2025-11-13 19:33 ` Simon Glass
2025-11-13 17:57 ` [PATCH 0/3] Synchronize DTC to 1.7.2 Tom Rini
3 siblings, 1 reply; 32+ messages in thread
From: Marek Vasut @ 2025-11-13 12:21 UTC (permalink / raw)
To: u-boot
Cc: Marek Vasut, Adriano Cordova, Andrew Goodbody, Christian Marangi,
Heinrich Schuchardt, Ilias Apalodimas, Patrice Chotard,
Sam Edwards, Simon Glass, Tom Rini
The fdt_offset_ptr() may return NULL pointer, check the return
value from fdt_offset_ptr() for NULL unconditionally to prevent
sandbox crashes.
Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
---
Cc: Adriano Cordova <adrianox@gmail.com>
Cc: Andrew Goodbody <andrew.goodbody@linaro.org>
Cc: Christian Marangi <ansuelsmth@gmail.com>
Cc: Heinrich Schuchardt <xypron.glpk@gmx.de>
Cc: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Cc: Patrice Chotard <patrice.chotard@foss.st.com>
Cc: Sam Edwards <cfsworks@gmail.com>
Cc: Simon Glass <sjg@chromium.org>
Cc: Tom Rini <trini@konsulko.com>
Cc: u-boot@lists.denx.de
---
scripts/dtc/libfdt/fdt.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c
index 95f644c31f9..d16cc3d4730 100644
--- a/scripts/dtc/libfdt/fdt.c
+++ b/scripts/dtc/libfdt/fdt.c
@@ -168,7 +168,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
*nextoffset = -FDT_ERR_TRUNCATED;
tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
- if (!can_assume(VALID_DTB) && !tagp)
+ if (!tagp)
return FDT_END; /* premature end */
tag = fdt32_to_cpu(*tagp);
offset += FDT_TAGSIZE;
@@ -186,7 +186,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
case FDT_PROP:
lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
- if (!can_assume(VALID_DTB) && !lenp)
+ if (!lenp)
return FDT_END; /* premature end */
len = fdt32_to_cpu(*lenp);
--
2.51.0
^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [PATCH 0/3] Synchronize DTC to 1.7.2
2025-11-13 12:21 [PATCH 0/3] Synchronize DTC to 1.7.2 Marek Vasut
` (2 preceding siblings ...)
2025-11-13 12:21 ` [PATCH 3/3] libfdt: Check fdt_offset_ptr() return value unconditionally Marek Vasut
@ 2025-11-13 17:57 ` Tom Rini
2025-11-13 18:40 ` Marek Vasut
2025-11-21 19:55 ` Tom Rini
3 siblings, 2 replies; 32+ messages in thread
From: Tom Rini @ 2025-11-13 17:57 UTC (permalink / raw)
To: Marek Vasut
Cc: u-boot, Adriano Cordova, Andrew Goodbody, Christian Marangi,
Heinrich Schuchardt, Ilias Apalodimas, Patrice Chotard,
Sam Edwards, Simon Glass
[-- Attachment #1: Type: text/plain, Size: 3215 bytes --]
On Thu, Nov 13, 2025 at 01:21:07PM +0100, Marek Vasut wrote:
> Synchronize local copy of DTC with Linux 6.17 , using commits picked
> from Linux kernel. This also includes two fix up patches to make the
> DM core work with new 8-byte alignment checking in libfdt and another
> fix for NULL pointer check that is missing in libfdt.
>
> This depends on the following patches sent separately, which fix
> various 8-byte alignment problems in the code base:
>
> - boot: android: Always use 8-byte aligned DT with libfdt
> - test/py: android: Point fdt command to aligned addresses
> - test/py: Use aligned address for overlays in 'extension' test
> - sandbox: Fix DT compiler address warnings in sandbox DTs
> - sandbox: Fix DT compiler pin warnings in sandbox DTs
> - boot: Assure FDT is always at 8-byte aligned address
> - arm: qemu: Eliminate fdt_high and initrd_high misuse
> - efi_loader: Assure fitImage from capsule is used from 8-byte aligned address
> - MIPS: Assure end of U-Boot is at 8-byte aligned offset
So, taking a look at the test branch you pointed me at, my big concern
is size growth. On imx8mp_dhcom_drc02 (where we're already LTO'ing),
with the CI gcc-14.2.0 toolchain full U-Boot grows by more than 6KiB and
SPL by a bit more than 2KiB. This is a bit of a worst-case, imx8mp_navqp
is a bit more than 3KiB / 548 bytes, with the average feeling like
~4KiB/1KiB for aarch64.
I know there are some configuration choices to make libfdt be more
risk-adverse and perform less sanity checks, but I also think we had
fully enabled them.
Frustratingly I think this is why we ended up with:
commit 088bbc1efa8c1efe8e2714b9640055ce984aec93
Author: Patrice Chotard <patrice.chotard@foss.st.com>
Date: Fri Mar 28 17:31:15 2025 +0100
dtc: introduce label relative path references
Since introduction of OF_UPSTREAM flag, U-Boot's dtc must be able
to compile Kernel's device tree.
Since kernel commit 7de129f5389b ("ARM: dts: stm32: stm32mp151a-prtt1l:
Fix QSPI configuration"), label relative path references has been
introduced. These label relative path references is not supported
by current U-Boot dtc version 1.5.0: (see mailing list discussion [1]).
In order to support such label relative patch references
adds following commit from upstream DTC tree:
commit 651410e54cb9 ("util: introduce xstrndup helper")
commit ec7986e682cf ("dtc: introduce label relative path references")
[1] https://lore.kernel.org/all/20250115144428.GZ3476@bill-the-cat/T/
Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
Cc: Tom Rini <trini@konsulko.com>
Cc: Simon Glass <sjg@chromium.org>
Reviewed-by: Tom Rini <trini@konsulko.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Rather than a full-resync for the last time we needed a feature found
upstream.
There are things we *need* like to be 8-byte aligned and also the
phandle resolution thing I believe inspired your investigations here,
but I don't know if we can take the whole sync. Or maybe needing to work
with upstream to shrink down some parts, I'm unsure.
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 0/3] Synchronize DTC to 1.7.2
2025-11-13 17:57 ` [PATCH 0/3] Synchronize DTC to 1.7.2 Tom Rini
@ 2025-11-13 18:40 ` Marek Vasut
2025-11-13 18:49 ` Tom Rini
2025-11-21 19:55 ` Tom Rini
1 sibling, 1 reply; 32+ messages in thread
From: Marek Vasut @ 2025-11-13 18:40 UTC (permalink / raw)
To: Tom Rini
Cc: u-boot, Adriano Cordova, Andrew Goodbody, Christian Marangi,
Heinrich Schuchardt, Ilias Apalodimas, Patrice Chotard,
Sam Edwards, Simon Glass
On 11/13/25 6:57 PM, Tom Rini wrote:
Hello Tom,
> So, taking a look at the test branch you pointed me at, my big concern
> is size growth. On imx8mp_dhcom_drc02 (where we're already LTO'ing),
> with the CI gcc-14.2.0 toolchain full U-Boot grows by more than 6KiB and
> SPL by a bit more than 2KiB. This is a bit of a worst-case, imx8mp_navqp
> is a bit more than 3KiB / 548 bytes, with the average feeling like
> ~4KiB/1KiB for aarch64.
Do you know why this growth happened ? Is that in libfdt ? How did you
find it ?
[...]
> Rather than a full-resync for the last time we needed a feature found
> upstream.
I really don't want to do partial resync, it will only make it harder to
maintain obsolete code base going forward. Even this resync was hard due
to that exact current divergence.
> There are things we *need* like to be 8-byte aligned and also the
> phandle resolution thing I believe inspired your investigations here,
> but I don't know if we can take the whole sync. Or maybe needing to work
> with upstream to shrink down some parts, I'm unsure.
CI does show that no boards went oversize . If there is some growth on
existing devices, maybe we can shrink that, but maintaining obsolete DTC
code base going forward and picking random updates into it, that will
only lead to increasing maintenance pain, so I don't want to do that.
--
Best regards,
Marek Vasut
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 0/3] Synchronize DTC to 1.7.2
2025-11-13 18:40 ` Marek Vasut
@ 2025-11-13 18:49 ` Tom Rini
2025-11-13 19:32 ` Simon Glass
2025-11-15 23:23 ` Marek Vasut
0 siblings, 2 replies; 32+ messages in thread
From: Tom Rini @ 2025-11-13 18:49 UTC (permalink / raw)
To: Marek Vasut
Cc: u-boot, Adriano Cordova, Andrew Goodbody, Christian Marangi,
Heinrich Schuchardt, Ilias Apalodimas, Patrice Chotard,
Sam Edwards, Simon Glass
[-- Attachment #1: Type: text/plain, Size: 2195 bytes --]
On Thu, Nov 13, 2025 at 07:40:29PM +0100, Marek Vasut wrote:
> On 11/13/25 6:57 PM, Tom Rini wrote:
>
> Hello Tom,
>
> > So, taking a look at the test branch you pointed me at, my big concern
> > is size growth. On imx8mp_dhcom_drc02 (where we're already LTO'ing),
> > with the CI gcc-14.2.0 toolchain full U-Boot grows by more than 6KiB and
> > SPL by a bit more than 2KiB. This is a bit of a worst-case, imx8mp_navqp
> > is a bit more than 3KiB / 548 bytes, with the average feeling like
> > ~4KiB/1KiB for aarch64.
>
> Do you know why this growth happened ? Is that in libfdt ? How did you find
> it ?
Using buildman. To make it easier I put my wrapper around it at:
https://source.denx.de/u-boot/u-boot-extras/-/blob/master/contrib/trini/u-boot-size-test.sh?ref_type=heads
a while ago. I can also send you off-list the world build comparison
(it's 446KiB gzip'd).
> [...]
>
> > Rather than a full-resync for the last time we needed a feature found
> > upstream.
>
> I really don't want to do partial resync, it will only make it harder to
> maintain obsolete code base going forward. Even this resync was hard due to
> that exact current divergence.
>
> > There are things we *need* like to be 8-byte aligned and also the
> > phandle resolution thing I believe inspired your investigations here,
> > but I don't know if we can take the whole sync. Or maybe needing to work
> > with upstream to shrink down some parts, I'm unsure.
>
> CI does show that no boards went oversize . If there is some growth on
> existing devices, maybe we can shrink that, but maintaining obsolete DTC
> code base going forward and picking random updates into it, that will only
> lead to increasing maintenance pain, so I don't want to do that.
Yeah, it's not an easy spot. But I'm really not happy with growing main
U-Boot almost everywhere by 2KiB - 4KiB, and SPL by ~512 bytes or more
just to keep up. I do see that integratorcp_cm1136 barely grows at all,
so maybe there's something that can be done more widely and just wasn't
clear at first. m68k only grows an average of 500 bytes and MIPS is
~1KiB. PowerPC grows a lot. RISC-V a little.
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 0/3] Synchronize DTC to 1.7.2
2025-11-13 18:49 ` Tom Rini
@ 2025-11-13 19:32 ` Simon Glass
2025-11-15 23:23 ` Marek Vasut
1 sibling, 0 replies; 32+ messages in thread
From: Simon Glass @ 2025-11-13 19:32 UTC (permalink / raw)
To: Tom Rini
Cc: Marek Vasut, u-boot, Adriano Cordova, Andrew Goodbody,
Christian Marangi, Heinrich Schuchardt, Ilias Apalodimas,
Patrice Chotard, Sam Edwards
Hi Tom, Marek,
On Thu, 13 Nov 2025 at 11:49, Tom Rini <trini@konsulko.com> wrote:
>
> On Thu, Nov 13, 2025 at 07:40:29PM +0100, Marek Vasut wrote:
> > On 11/13/25 6:57 PM, Tom Rini wrote:
> >
> > Hello Tom,
> >
> > > So, taking a look at the test branch you pointed me at, my big concern
> > > is size growth. On imx8mp_dhcom_drc02 (where we're already LTO'ing),
> > > with the CI gcc-14.2.0 toolchain full U-Boot grows by more than 6KiB and
> > > SPL by a bit more than 2KiB. This is a bit of a worst-case, imx8mp_navqp
> > > is a bit more than 3KiB / 548 bytes, with the average feeling like
> > > ~4KiB/1KiB for aarch64.
> >
> > Do you know why this growth happened ? Is that in libfdt ? How did you find
> > it ?
>
> Using buildman. To make it easier I put my wrapper around it at:
> https://source.denx.de/u-boot/u-boot-extras/-/blob/master/contrib/trini/u-boot-size-test.sh?ref_type=heads
> a while ago. I can also send you off-list the world build comparison
> (it's 446KiB gzip'd).
>
> > [...]
> >
> > > Rather than a full-resync for the last time we needed a feature found
> > > upstream.
> >
> > I really don't want to do partial resync, it will only make it harder to
> > maintain obsolete code base going forward. Even this resync was hard due to
> > that exact current divergence.
> >
> > > There are things we *need* like to be 8-byte aligned and also the
> > > phandle resolution thing I believe inspired your investigations here,
> > > but I don't know if we can take the whole sync. Or maybe needing to work
> > > with upstream to shrink down some parts, I'm unsure.
> >
> > CI does show that no boards went oversize . If there is some growth on
> > existing devices, maybe we can shrink that, but maintaining obsolete DTC
> > code base going forward and picking random updates into it, that will only
> > lead to increasing maintenance pain, so I don't want to do that.
>
> Yeah, it's not an easy spot. But I'm really not happy with growing main
> U-Boot almost everywhere by 2KiB - 4KiB, and SPL by ~512 bytes or more
> just to keep up. I do see that integratorcp_cm1136 barely grows at all,
> so maybe there's something that can be done more widely and just wasn't
> clear at first. m68k only grows an average of 500 bytes and MIPS is
> ~1KiB. PowerPC grows a lot. RISC-V a little.
FDT_ASSUME_MASK was my attempt to handle this upstream. It is likely
that people have not been using that very much upstream and some more
of the code needs to check fdt_chk_extra() before address/value
checks, etc.
Regards,
Simon
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 1/3] dm: core: Check ofnode_to_offset() return value
2025-11-13 12:21 ` [PATCH 1/3] dm: core: Check ofnode_to_offset() return value Marek Vasut
@ 2025-11-13 19:33 ` Simon Glass
2025-11-13 21:51 ` Marek Vasut
0 siblings, 1 reply; 32+ messages in thread
From: Simon Glass @ 2025-11-13 19:33 UTC (permalink / raw)
To: Marek Vasut
Cc: u-boot, Adriano Cordova, Andrew Goodbody, Christian Marangi,
Heinrich Schuchardt, Ilias Apalodimas, Patrice Chotard,
Sam Edwards, Tom Rini
Hi Marek,
On Thu, 13 Nov 2025 at 05:21, Marek Vasut
<marek.vasut+renesas@mailbox.org> wrote:
>
> The ofnode_to_offset() may return -1 , which is not a valid value
> and is not accepted by modern libfdt 1.7.2. Check the return value
> from ofnode_to_offset() and exit early in case it is not a valid
> offset.
>
> Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
> ---
> Cc: Adriano Cordova <adrianox@gmail.com>
> Cc: Andrew Goodbody <andrew.goodbody@linaro.org>
> Cc: Christian Marangi <ansuelsmth@gmail.com>
> Cc: Heinrich Schuchardt <xypron.glpk@gmx.de>
> Cc: Ilias Apalodimas <ilias.apalodimas@linaro.org>
> Cc: Patrice Chotard <patrice.chotard@foss.st.com>
> Cc: Sam Edwards <cfsworks@gmail.com>
> Cc: Simon Glass <sjg@chromium.org>
> Cc: Tom Rini <trini@konsulko.com>
> Cc: u-boot@lists.denx.de
> ---
> drivers/core/ofnode.c | 384 +++++++++++++++++++++++++++++++-----------
> 1 file changed, 284 insertions(+), 100 deletions(-)
>
> diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
> index 071d998a0a5..55c2b3a10bb 100644
> --- a/drivers/core/ofnode.c
> +++ b/drivers/core/ofnode.c
> @@ -335,7 +335,7 @@ bool ofnode_name_eq_unit(ofnode node, const char *name)
> int ofnode_read_u8(ofnode node, const char *propname, u8 *outp)
> {
> const u8 *cell;
> - int len;
> + int len, off;
>
> assert(ofnode_valid(node));
> log_debug("%s: %s: ", __func__, propname);
> @@ -343,8 +343,13 @@ int ofnode_read_u8(ofnode node, const char *propname, u8 *outp)
> if (ofnode_is_np(node))
> return of_read_u8(ofnode_to_np(node), propname, outp);
>
> - cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
> - &len);
> + off = ofnode_to_offset(node);
> + if (off < 0) {
> + log_debug("(not valid)\n");
> + return -EINVAL;
> + }
Ugh this is really horrible, sorry :-)
Better to put a wrapper around it than add all these checks, extra
code size, etc. Also in many cases the ofnode is known to be valid(TM)
so it might just be a waste.
Regards,
Simon
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 3/3] libfdt: Check fdt_offset_ptr() return value unconditionally
2025-11-13 12:21 ` [PATCH 3/3] libfdt: Check fdt_offset_ptr() return value unconditionally Marek Vasut
@ 2025-11-13 19:33 ` Simon Glass
2025-11-13 21:48 ` Marek Vasut
0 siblings, 1 reply; 32+ messages in thread
From: Simon Glass @ 2025-11-13 19:33 UTC (permalink / raw)
To: Marek Vasut
Cc: u-boot, Adriano Cordova, Andrew Goodbody, Christian Marangi,
Heinrich Schuchardt, Ilias Apalodimas, Patrice Chotard,
Sam Edwards, Tom Rini
Hi Marek,
On Thu, 13 Nov 2025 at 05:22, Marek Vasut
<marek.vasut+renesas@mailbox.org> wrote:
>
> The fdt_offset_ptr() may return NULL pointer, check the return
> value from fdt_offset_ptr() for NULL unconditionally to prevent
> sandbox crashes.
>
> Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
> ---
> Cc: Adriano Cordova <adrianox@gmail.com>
> Cc: Andrew Goodbody <andrew.goodbody@linaro.org>
> Cc: Christian Marangi <ansuelsmth@gmail.com>
> Cc: Heinrich Schuchardt <xypron.glpk@gmx.de>
> Cc: Ilias Apalodimas <ilias.apalodimas@linaro.org>
> Cc: Patrice Chotard <patrice.chotard@foss.st.com>
> Cc: Sam Edwards <cfsworks@gmail.com>
> Cc: Simon Glass <sjg@chromium.org>
> Cc: Tom Rini <trini@konsulko.com>
> Cc: u-boot@lists.denx.de
> ---
> scripts/dtc/libfdt/fdt.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c
> index 95f644c31f9..d16cc3d4730 100644
> --- a/scripts/dtc/libfdt/fdt.c
> +++ b/scripts/dtc/libfdt/fdt.c
> @@ -168,7 +168,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
>
> *nextoffset = -FDT_ERR_TRUNCATED;
> tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
> - if (!can_assume(VALID_DTB) && !tagp)
> + if (!tagp)
> return FDT_END; /* premature end */
> tag = fdt32_to_cpu(*tagp);
> offset += FDT_TAGSIZE;
> @@ -186,7 +186,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
>
> case FDT_PROP:
> lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
> - if (!can_assume(VALID_DTB) && !lenp)
> + if (!lenp)
> return FDT_END; /* premature end */
>
> len = fdt32_to_cpu(*lenp);
> --
> 2.51.0
>
The can_assume() is there to be respected and helps to reduce code
size. What problem are you actually seeing?
Regards,
Simon
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 3/3] libfdt: Check fdt_offset_ptr() return value unconditionally
2025-11-13 19:33 ` Simon Glass
@ 2025-11-13 21:48 ` Marek Vasut
2025-11-13 23:34 ` Simon Glass
0 siblings, 1 reply; 32+ messages in thread
From: Marek Vasut @ 2025-11-13 21:48 UTC (permalink / raw)
To: Simon Glass, Marek Vasut
Cc: u-boot, Adriano Cordova, Andrew Goodbody, Christian Marangi,
Heinrich Schuchardt, Ilias Apalodimas, Patrice Chotard,
Sam Edwards, Tom Rini
On 11/13/25 8:33 PM, Simon Glass wrote:
Hello Simon,
>> The fdt_offset_ptr() may return NULL pointer, check the return
>> value from fdt_offset_ptr() for NULL unconditionally to prevent
>> sandbox crashes.
>>
>> Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
>> ---
>> Cc: Adriano Cordova <adrianox@gmail.com>
>> Cc: Andrew Goodbody <andrew.goodbody@linaro.org>
>> Cc: Christian Marangi <ansuelsmth@gmail.com>
>> Cc: Heinrich Schuchardt <xypron.glpk@gmx.de>
>> Cc: Ilias Apalodimas <ilias.apalodimas@linaro.org>
>> Cc: Patrice Chotard <patrice.chotard@foss.st.com>
>> Cc: Sam Edwards <cfsworks@gmail.com>
>> Cc: Simon Glass <sjg@chromium.org>
>> Cc: Tom Rini <trini@konsulko.com>
>> Cc: u-boot@lists.denx.de
>> ---
>> scripts/dtc/libfdt/fdt.c | 4 ++--
>> 1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c
>> index 95f644c31f9..d16cc3d4730 100644
>> --- a/scripts/dtc/libfdt/fdt.c
>> +++ b/scripts/dtc/libfdt/fdt.c
>> @@ -168,7 +168,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
>>
>> *nextoffset = -FDT_ERR_TRUNCATED;
>> tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
>> - if (!can_assume(VALID_DTB) && !tagp)
>> + if (!tagp)
>> return FDT_END; /* premature end */
>> tag = fdt32_to_cpu(*tagp);
>> offset += FDT_TAGSIZE;
>> @@ -186,7 +186,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
>>
>> case FDT_PROP:
>> lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
>> - if (!can_assume(VALID_DTB) && !lenp)
>> + if (!lenp)
>> return FDT_END; /* premature end */
>>
>> len = fdt32_to_cpu(*lenp);
>> --
>> 2.51.0
>>
>
> The can_assume() is there to be respected and helps to reduce code
> size. What problem are you actually seeing?
fdt_offset_ptr() can return NULL, and it does in test_spl on sandbox if
I recall it right, because the U-Boot code passes in offsets which can
not be resolved properly and that makes fdt_offset_ptr() return NULL and
trigger SIGSEGV when it is dereferenced here.
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 1/3] dm: core: Check ofnode_to_offset() return value
2025-11-13 19:33 ` Simon Glass
@ 2025-11-13 21:51 ` Marek Vasut
2025-11-13 22:46 ` Simon Glass
0 siblings, 1 reply; 32+ messages in thread
From: Marek Vasut @ 2025-11-13 21:51 UTC (permalink / raw)
To: Simon Glass, Marek Vasut
Cc: u-boot, Adriano Cordova, Andrew Goodbody, Christian Marangi,
Heinrich Schuchardt, Ilias Apalodimas, Patrice Chotard,
Sam Edwards, Tom Rini
On 11/13/25 8:33 PM, Simon Glass wrote:
Hello Simon,
>> diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
>> index 071d998a0a5..55c2b3a10bb 100644
>> --- a/drivers/core/ofnode.c
>> +++ b/drivers/core/ofnode.c
>> @@ -335,7 +335,7 @@ bool ofnode_name_eq_unit(ofnode node, const char *name)
>> int ofnode_read_u8(ofnode node, const char *propname, u8 *outp)
>> {
>> const u8 *cell;
>> - int len;
>> + int len, off;
>>
>> assert(ofnode_valid(node));
>> log_debug("%s: %s: ", __func__, propname);
>> @@ -343,8 +343,13 @@ int ofnode_read_u8(ofnode node, const char *propname, u8 *outp)
>> if (ofnode_is_np(node))
>> return of_read_u8(ofnode_to_np(node), propname, outp);
>>
>> - cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
>> - &len);
>> + off = ofnode_to_offset(node);
>> + if (off < 0) {
>> + log_debug("(not valid)\n");
>> + return -EINVAL;
>> + }
>
> Ugh this is really horrible, sorry :-)
>
> Better to put a wrapper around it than add all these checks, extra
> code size, etc. Also in many cases the ofnode is known to be valid(TM)
> so it might just be a waste.
How would you propose the wrapper should look like ?
Keep in mind, not everything is fdt_getprop( ... ofnode_to_offset() ...)
in this patch.
--
Best regards,
Marek Vasut
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 1/3] dm: core: Check ofnode_to_offset() return value
2025-11-13 21:51 ` Marek Vasut
@ 2025-11-13 22:46 ` Simon Glass
2025-11-14 5:17 ` Marek Vasut
0 siblings, 1 reply; 32+ messages in thread
From: Simon Glass @ 2025-11-13 22:46 UTC (permalink / raw)
To: Marek Vasut
Cc: Marek Vasut, u-boot, Adriano Cordova, Andrew Goodbody,
Christian Marangi, Heinrich Schuchardt, Ilias Apalodimas,
Patrice Chotard, Sam Edwards, Tom Rini
Hi Marek,
On Thu, 13 Nov 2025 at 14:57, Marek Vasut <marek.vasut@mailbox.org> wrote:
>
> On 11/13/25 8:33 PM, Simon Glass wrote:
>
> Hello Simon,
>
> >> diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
> >> index 071d998a0a5..55c2b3a10bb 100644
> >> --- a/drivers/core/ofnode.c
> >> +++ b/drivers/core/ofnode.c
> >> @@ -335,7 +335,7 @@ bool ofnode_name_eq_unit(ofnode node, const char *name)
> >> int ofnode_read_u8(ofnode node, const char *propname, u8 *outp)
> >> {
> >> const u8 *cell;
> >> - int len;
> >> + int len, off;
> >>
> >> assert(ofnode_valid(node));
> >> log_debug("%s: %s: ", __func__, propname);
> >> @@ -343,8 +343,13 @@ int ofnode_read_u8(ofnode node, const char *propname, u8 *outp)
> >> if (ofnode_is_np(node))
> >> return of_read_u8(ofnode_to_np(node), propname, outp);
> >>
> >> - cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
> >> - &len);
> >> + off = ofnode_to_offset(node);
> >> + if (off < 0) {
> >> + log_debug("(not valid)\n");
> >> + return -EINVAL;
> >> + }
> >
> > Ugh this is really horrible, sorry :-)
> >
> > Better to put a wrapper around it than add all these checks, extra
> > code size, etc. Also in many cases the ofnode is known to be valid(TM)
> > so it might just be a waste.
>
> How would you propose the wrapper should look like ?
>
> Keep in mind, not everything is fdt_getprop( ... ofnode_to_offset() ...)
> in this patch.
I was thinking of
my_fdt_getprop(fdt, node, propname, lenp)
{
if (node is not valid)
return NULL;
return fdt_getprop();
}
What does fdt_getprop() return when the offset is -1 ?
Regards,
Simon
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 3/3] libfdt: Check fdt_offset_ptr() return value unconditionally
2025-11-13 21:48 ` Marek Vasut
@ 2025-11-13 23:34 ` Simon Glass
2025-11-20 4:20 ` Marek Vasut
0 siblings, 1 reply; 32+ messages in thread
From: Simon Glass @ 2025-11-13 23:34 UTC (permalink / raw)
To: Marek Vasut
Cc: Marek Vasut, u-boot, Adriano Cordova, Andrew Goodbody,
Christian Marangi, Heinrich Schuchardt, Ilias Apalodimas,
Patrice Chotard, Sam Edwards, Tom Rini
Hi Marke,
On Thu, 13 Nov 2025 at 14:57, Marek Vasut <marek.vasut@mailbox.org> wrote:
>
> On 11/13/25 8:33 PM, Simon Glass wrote:
>
> Hello Simon,
>
> >> The fdt_offset_ptr() may return NULL pointer, check the return
> >> value from fdt_offset_ptr() for NULL unconditionally to prevent
> >> sandbox crashes.
> >>
> >> Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
> >> ---
> >> Cc: Adriano Cordova <adrianox@gmail.com>
> >> Cc: Andrew Goodbody <andrew.goodbody@linaro.org>
> >> Cc: Christian Marangi <ansuelsmth@gmail.com>
> >> Cc: Heinrich Schuchardt <xypron.glpk@gmx.de>
> >> Cc: Ilias Apalodimas <ilias.apalodimas@linaro.org>
> >> Cc: Patrice Chotard <patrice.chotard@foss.st.com>
> >> Cc: Sam Edwards <cfsworks@gmail.com>
> >> Cc: Simon Glass <sjg@chromium.org>
> >> Cc: Tom Rini <trini@konsulko.com>
> >> Cc: u-boot@lists.denx.de
> >> ---
> >> scripts/dtc/libfdt/fdt.c | 4 ++--
> >> 1 file changed, 2 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c
> >> index 95f644c31f9..d16cc3d4730 100644
> >> --- a/scripts/dtc/libfdt/fdt.c
> >> +++ b/scripts/dtc/libfdt/fdt.c
> >> @@ -168,7 +168,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
> >>
> >> *nextoffset = -FDT_ERR_TRUNCATED;
> >> tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
> >> - if (!can_assume(VALID_DTB) && !tagp)
> >> + if (!tagp)
> >> return FDT_END; /* premature end */
> >> tag = fdt32_to_cpu(*tagp);
> >> offset += FDT_TAGSIZE;
> >> @@ -186,7 +186,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
> >>
> >> case FDT_PROP:
> >> lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
> >> - if (!can_assume(VALID_DTB) && !lenp)
> >> + if (!lenp)
> >> return FDT_END; /* premature end */
> >>
> >> len = fdt32_to_cpu(*lenp);
> >> --
> >> 2.51.0
> >>
> >
> > The can_assume() is there to be respected and helps to reduce code
> > size. What problem are you actually seeing?
> fdt_offset_ptr() can return NULL, and it does in test_spl on sandbox if
> I recall it right, because the U-Boot code passes in offsets which can
> not be resolved properly and that makes fdt_offset_ptr() return NULL and
> trigger SIGSEGV when it is dereferenced here.
That sounds like the FDT is corrupt? Here we are parsing through tags,
so we should really figure out why it is corrupt.
But if note, then we should not be passing bad offsets...so what is
the root cause of that?
Regards,
Simon
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 1/3] dm: core: Check ofnode_to_offset() return value
2025-11-13 22:46 ` Simon Glass
@ 2025-11-14 5:17 ` Marek Vasut
2025-11-14 14:36 ` Tom Rini
0 siblings, 1 reply; 32+ messages in thread
From: Marek Vasut @ 2025-11-14 5:17 UTC (permalink / raw)
To: Simon Glass
Cc: Marek Vasut, u-boot, Adriano Cordova, Andrew Goodbody,
Christian Marangi, Heinrich Schuchardt, Ilias Apalodimas,
Patrice Chotard, Sam Edwards, Tom Rini
On 11/13/25 11:46 PM, Simon Glass wrote:
Hello Simon,
>>>> diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
>>>> index 071d998a0a5..55c2b3a10bb 100644
>>>> --- a/drivers/core/ofnode.c
>>>> +++ b/drivers/core/ofnode.c
>>>> @@ -335,7 +335,7 @@ bool ofnode_name_eq_unit(ofnode node, const char *name)
>>>> int ofnode_read_u8(ofnode node, const char *propname, u8 *outp)
>>>> {
>>>> const u8 *cell;
>>>> - int len;
>>>> + int len, off;
>>>>
>>>> assert(ofnode_valid(node));
>>>> log_debug("%s: %s: ", __func__, propname);
>>>> @@ -343,8 +343,13 @@ int ofnode_read_u8(ofnode node, const char *propname, u8 *outp)
>>>> if (ofnode_is_np(node))
>>>> return of_read_u8(ofnode_to_np(node), propname, outp);
>>>>
>>>> - cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
>>>> - &len);
>>>> + off = ofnode_to_offset(node);
>>>> + if (off < 0) {
>>>> + log_debug("(not valid)\n");
>>>> + return -EINVAL;
>>>> + }
>>>
>>> Ugh this is really horrible, sorry :-)
>>>
>>> Better to put a wrapper around it than add all these checks, extra
>>> code size, etc. Also in many cases the ofnode is known to be valid(TM)
>>> so it might just be a waste.
>>
>> How would you propose the wrapper should look like ?
>>
>> Keep in mind, not everything is fdt_getprop( ... ofnode_to_offset() ...)
>> in this patch.
>
> I was thinking of
>
> my_fdt_getprop(fdt, node, propname, lenp)
> {
> if (node is not valid)
> return NULL;
> return fdt_getprop();
> }
We would need a wrapper for almost every libfdt call, which isn't really
better.
> What does fdt_getprop() return when the offset is -1 ?
If can_assume(VALID_DTB) , then crash on NULL pointer dereference .
If not, I think FDT_END (premature end) or an error code.
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 1/3] dm: core: Check ofnode_to_offset() return value
2025-11-14 5:17 ` Marek Vasut
@ 2025-11-14 14:36 ` Tom Rini
2025-11-16 0:16 ` Marek Vasut
0 siblings, 1 reply; 32+ messages in thread
From: Tom Rini @ 2025-11-14 14:36 UTC (permalink / raw)
To: Marek Vasut
Cc: Simon Glass, Marek Vasut, u-boot, Adriano Cordova,
Andrew Goodbody, Christian Marangi, Heinrich Schuchardt,
Ilias Apalodimas, Patrice Chotard, Sam Edwards
[-- Attachment #1: Type: text/plain, Size: 2340 bytes --]
On Fri, Nov 14, 2025 at 06:17:27AM +0100, Marek Vasut wrote:
> On 11/13/25 11:46 PM, Simon Glass wrote:
>
> Hello Simon,
>
> > > > > diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
> > > > > index 071d998a0a5..55c2b3a10bb 100644
> > > > > --- a/drivers/core/ofnode.c
> > > > > +++ b/drivers/core/ofnode.c
> > > > > @@ -335,7 +335,7 @@ bool ofnode_name_eq_unit(ofnode node, const char *name)
> > > > > int ofnode_read_u8(ofnode node, const char *propname, u8 *outp)
> > > > > {
> > > > > const u8 *cell;
> > > > > - int len;
> > > > > + int len, off;
> > > > >
> > > > > assert(ofnode_valid(node));
> > > > > log_debug("%s: %s: ", __func__, propname);
> > > > > @@ -343,8 +343,13 @@ int ofnode_read_u8(ofnode node, const char *propname, u8 *outp)
> > > > > if (ofnode_is_np(node))
> > > > > return of_read_u8(ofnode_to_np(node), propname, outp);
> > > > >
> > > > > - cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
> > > > > - &len);
> > > > > + off = ofnode_to_offset(node);
> > > > > + if (off < 0) {
> > > > > + log_debug("(not valid)\n");
> > > > > + return -EINVAL;
> > > > > + }
> > > >
> > > > Ugh this is really horrible, sorry :-)
> > > >
> > > > Better to put a wrapper around it than add all these checks, extra
> > > > code size, etc. Also in many cases the ofnode is known to be valid(TM)
> > > > so it might just be a waste.
> > >
> > > How would you propose the wrapper should look like ?
> > >
> > > Keep in mind, not everything is fdt_getprop( ... ofnode_to_offset() ...)
> > > in this patch.
> >
> > I was thinking of
> >
> > my_fdt_getprop(fdt, node, propname, lenp)
> > {
> > if (node is not valid)
> > return NULL;
> > return fdt_getprop();
> > }
>
> We would need a wrapper for almost every libfdt call, which isn't really
> better.
>
> > What does fdt_getprop() return when the offset is -1 ?
> If can_assume(VALID_DTB) , then crash on NULL pointer dereference .
> If not, I think FDT_END (premature end) or an error code.
How are we now getting in this state is a question. Are we being passed
an unaligned DT and trying to work around/with it?
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 0/3] Synchronize DTC to 1.7.2
2025-11-13 18:49 ` Tom Rini
2025-11-13 19:32 ` Simon Glass
@ 2025-11-15 23:23 ` Marek Vasut
2025-11-16 14:11 ` Tom Rini
1 sibling, 1 reply; 32+ messages in thread
From: Marek Vasut @ 2025-11-15 23:23 UTC (permalink / raw)
To: Tom Rini
Cc: u-boot, Adriano Cordova, Andrew Goodbody, Christian Marangi,
Heinrich Schuchardt, Ilias Apalodimas, Patrice Chotard,
Sam Edwards, Simon Glass
On 11/13/25 7:49 PM, Tom Rini wrote:
Hello Tom,
>> CI does show that no boards went oversize . If there is some growth on
>> existing devices, maybe we can shrink that, but maintaining obsolete DTC
>> code base going forward and picking random updates into it, that will only
>> lead to increasing maintenance pain, so I don't want to do that.
>
> Yeah, it's not an easy spot. But I'm really not happy with growing main
> U-Boot almost everywhere by 2KiB - 4KiB, and SPL by ~512 bytes or more
> just to keep up. I do see that integratorcp_cm1136 barely grows at all,
> so maybe there's something that can be done more widely and just wasn't
> clear at first. m68k only grows an average of 500 bytes and MIPS is
> ~1KiB. PowerPC grows a lot. RISC-V a little.
I suspect this might have to do with DTO support. The imx8mp_dhcom do
use DTOs and the fdt_overlay.c code grew a lot.
I also found out that if I patch out can_assume() and replace it with
plain 1 , then the size drops by 1-2 kiB, but that's probably not what
we want to do.
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 1/3] dm: core: Check ofnode_to_offset() return value
2025-11-14 14:36 ` Tom Rini
@ 2025-11-16 0:16 ` Marek Vasut
2025-11-16 14:13 ` Tom Rini
0 siblings, 1 reply; 32+ messages in thread
From: Marek Vasut @ 2025-11-16 0:16 UTC (permalink / raw)
To: Tom Rini
Cc: Simon Glass, Marek Vasut, u-boot, Adriano Cordova,
Andrew Goodbody, Christian Marangi, Heinrich Schuchardt,
Ilias Apalodimas, Patrice Chotard, Sam Edwards
On 11/14/25 3:36 PM, Tom Rini wrote:
Hello Tom,
>> We would need a wrapper for almost every libfdt call, which isn't really
>> better.
>>
>>> What does fdt_getprop() return when the offset is -1 ?
>> If can_assume(VALID_DTB) , then crash on NULL pointer dereference .
>> If not, I think FDT_END (premature end) or an error code.
>
> How are we now getting in this state is a question. Are we being passed
> an unaligned DT and trying to work around/with it?
This is superseded by:
[PATCH] xtensa: Assure end of U-Boot is at 8-byte aligned offset
It turns out the problem was yet another unaligned appended DT, on
xtensa this time.
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 0/3] Synchronize DTC to 1.7.2
2025-11-15 23:23 ` Marek Vasut
@ 2025-11-16 14:11 ` Tom Rini
2025-11-16 21:48 ` Marek Vasut
0 siblings, 1 reply; 32+ messages in thread
From: Tom Rini @ 2025-11-16 14:11 UTC (permalink / raw)
To: Marek Vasut
Cc: u-boot, Adriano Cordova, Andrew Goodbody, Christian Marangi,
Heinrich Schuchardt, Ilias Apalodimas, Patrice Chotard,
Sam Edwards, Simon Glass
[-- Attachment #1: Type: text/plain, Size: 1620 bytes --]
On Sun, Nov 16, 2025 at 12:23:30AM +0100, Marek Vasut wrote:
> On 11/13/25 7:49 PM, Tom Rini wrote:
>
> Hello Tom,
>
> > > CI does show that no boards went oversize . If there is some growth on
> > > existing devices, maybe we can shrink that, but maintaining obsolete DTC
> > > code base going forward and picking random updates into it, that will only
> > > lead to increasing maintenance pain, so I don't want to do that.
> >
> > Yeah, it's not an easy spot. But I'm really not happy with growing main
> > U-Boot almost everywhere by 2KiB - 4KiB, and SPL by ~512 bytes or more
> > just to keep up. I do see that integratorcp_cm1136 barely grows at all,
> > so maybe there's something that can be done more widely and just wasn't
> > clear at first. m68k only grows an average of 500 bytes and MIPS is
> > ~1KiB. PowerPC grows a lot. RISC-V a little.
> I suspect this might have to do with DTO support. The imx8mp_dhcom do use
> DTOs and the fdt_overlay.c code grew a lot.
>
> I also found out that if I patch out can_assume() and replace it with plain
> 1 , then the size drops by 1-2 kiB, but that's probably not what we want to
> do.
I'm not sure, maybe we do? Or maybe we need to look and have *one* place
that confirms correct alignment and either fixes/complains, and then
every follow-up location doesn't need to perform that (or possibly many
other as well) validation checks. My impression from when I looked at
the code last, a few year ago, was that it was designed with "validate
with most? every? function" and we would be happy enough with "validate
once".
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 1/3] dm: core: Check ofnode_to_offset() return value
2025-11-16 0:16 ` Marek Vasut
@ 2025-11-16 14:13 ` Tom Rini
2025-11-16 21:28 ` Marek Vasut
0 siblings, 1 reply; 32+ messages in thread
From: Tom Rini @ 2025-11-16 14:13 UTC (permalink / raw)
To: Marek Vasut
Cc: Simon Glass, Marek Vasut, u-boot, Adriano Cordova,
Andrew Goodbody, Christian Marangi, Heinrich Schuchardt,
Ilias Apalodimas, Patrice Chotard, Sam Edwards
[-- Attachment #1: Type: text/plain, Size: 1039 bytes --]
On Sun, Nov 16, 2025 at 01:16:53AM +0100, Marek Vasut wrote:
> On 11/14/25 3:36 PM, Tom Rini wrote:
>
> Hello Tom,
>
> > > We would need a wrapper for almost every libfdt call, which isn't really
> > > better.
> > >
> > > > What does fdt_getprop() return when the offset is -1 ?
> > > If can_assume(VALID_DTB) , then crash on NULL pointer dereference .
> > > If not, I think FDT_END (premature end) or an error code.
> >
> > How are we now getting in this state is a question. Are we being passed
> > an unaligned DT and trying to work around/with it?
> This is superseded by:
>
> [PATCH] xtensa: Assure end of U-Boot is at 8-byte aligned offset
>
> It turns out the problem was yet another unaligned appended DT, on xtensa
> this time.
I wonder if we have still more places. I've seen patches in your series
for many but not all of
https://lore.kernel.org/all/20221215115825.827111-1-eugen.hristev@microchip.com/
and I don't recall how many of those were done individually instead
afterwards.
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 1/3] dm: core: Check ofnode_to_offset() return value
2025-11-16 14:13 ` Tom Rini
@ 2025-11-16 21:28 ` Marek Vasut
2025-11-17 14:14 ` Tom Rini
0 siblings, 1 reply; 32+ messages in thread
From: Marek Vasut @ 2025-11-16 21:28 UTC (permalink / raw)
To: Tom Rini
Cc: Simon Glass, Marek Vasut, u-boot, Adriano Cordova,
Andrew Goodbody, Christian Marangi, Heinrich Schuchardt,
Ilias Apalodimas, Patrice Chotard, Sam Edwards
On 11/16/25 3:13 PM, Tom Rini wrote:
> On Sun, Nov 16, 2025 at 01:16:53AM +0100, Marek Vasut wrote:
>> On 11/14/25 3:36 PM, Tom Rini wrote:
>>
>> Hello Tom,
>>
>>>> We would need a wrapper for almost every libfdt call, which isn't really
>>>> better.
>>>>
>>>>> What does fdt_getprop() return when the offset is -1 ?
>>>> If can_assume(VALID_DTB) , then crash on NULL pointer dereference .
>>>> If not, I think FDT_END (premature end) or an error code.
>>>
>>> How are we now getting in this state is a question. Are we being passed
>>> an unaligned DT and trying to work around/with it?
>> This is superseded by:
>>
>> [PATCH] xtensa: Assure end of U-Boot is at 8-byte aligned offset
>>
>> It turns out the problem was yet another unaligned appended DT, on xtensa
>> this time.
>
> I wonder if we have still more places. I've seen patches in your series
> for many but not all of
> https://lore.kernel.org/all/20221215115825.827111-1-eugen.hristev@microchip.com/
> and I don't recall how many of those were done individually instead
> afterwards.
Was there any reason why that patch (or subset of) was not picked up ?
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 0/3] Synchronize DTC to 1.7.2
2025-11-16 14:11 ` Tom Rini
@ 2025-11-16 21:48 ` Marek Vasut
2025-11-17 18:40 ` Tom Rini
0 siblings, 1 reply; 32+ messages in thread
From: Marek Vasut @ 2025-11-16 21:48 UTC (permalink / raw)
To: Tom Rini
Cc: u-boot, Adriano Cordova, Andrew Goodbody, Christian Marangi,
Heinrich Schuchardt, Ilias Apalodimas, Patrice Chotard,
Sam Edwards, Simon Glass
On 11/16/25 3:11 PM, Tom Rini wrote:
> On Sun, Nov 16, 2025 at 12:23:30AM +0100, Marek Vasut wrote:
>> On 11/13/25 7:49 PM, Tom Rini wrote:
>>
>> Hello Tom,
>>
>>>> CI does show that no boards went oversize . If there is some growth on
>>>> existing devices, maybe we can shrink that, but maintaining obsolete DTC
>>>> code base going forward and picking random updates into it, that will only
>>>> lead to increasing maintenance pain, so I don't want to do that.
>>>
>>> Yeah, it's not an easy spot. But I'm really not happy with growing main
>>> U-Boot almost everywhere by 2KiB - 4KiB, and SPL by ~512 bytes or more
>>> just to keep up. I do see that integratorcp_cm1136 barely grows at all,
>>> so maybe there's something that can be done more widely and just wasn't
>>> clear at first. m68k only grows an average of 500 bytes and MIPS is
>>> ~1KiB. PowerPC grows a lot. RISC-V a little.
>> I suspect this might have to do with DTO support. The imx8mp_dhcom do use
>> DTOs and the fdt_overlay.c code grew a lot.
>>
>> I also found out that if I patch out can_assume() and replace it with plain
>> 1 , then the size drops by 1-2 kiB, but that's probably not what we want to
>> do.
>
> I'm not sure, maybe we do? Or maybe we need to look and have *one* place
> that confirms correct alignment and either fixes/complains
That's already part of new libfdt, that is also what triggered the
various fixes I posted recently:
scripts/dtc/libfdt/fdt.c: if ((uintptr_t)fdt & 7)
scripts/dtc/libfdt/fdt.c: if ((uintptr_t)fdt & 7)
> , and then
> every follow-up location doesn't need to perform that (or possibly many
> other as well) validation checks. My impression from when I looked at
> the code last, a few year ago, was that it was designed with "validate
> with most? every? function" and we would be happy enough with "validate
> once".
If you can make that assumption -- that whatever we feed into libfdt is
valid -- then we can simply patch out can_assume() .
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 1/3] dm: core: Check ofnode_to_offset() return value
2025-11-16 21:28 ` Marek Vasut
@ 2025-11-17 14:14 ` Tom Rini
0 siblings, 0 replies; 32+ messages in thread
From: Tom Rini @ 2025-11-17 14:14 UTC (permalink / raw)
To: Marek Vasut
Cc: Simon Glass, Marek Vasut, u-boot, Adriano Cordova,
Andrew Goodbody, Christian Marangi, Heinrich Schuchardt,
Ilias Apalodimas, Patrice Chotard, Sam Edwards
[-- Attachment #1: Type: text/plain, Size: 1470 bytes --]
On Sun, Nov 16, 2025 at 10:28:28PM +0100, Marek Vasut wrote:
> On 11/16/25 3:13 PM, Tom Rini wrote:
> > On Sun, Nov 16, 2025 at 01:16:53AM +0100, Marek Vasut wrote:
> > > On 11/14/25 3:36 PM, Tom Rini wrote:
> > >
> > > Hello Tom,
> > >
> > > > > We would need a wrapper for almost every libfdt call, which isn't really
> > > > > better.
> > > > >
> > > > > > What does fdt_getprop() return when the offset is -1 ?
> > > > > If can_assume(VALID_DTB) , then crash on NULL pointer dereference .
> > > > > If not, I think FDT_END (premature end) or an error code.
> > > >
> > > > How are we now getting in this state is a question. Are we being passed
> > > > an unaligned DT and trying to work around/with it?
> > > This is superseded by:
> > >
> > > [PATCH] xtensa: Assure end of U-Boot is at 8-byte aligned offset
> > >
> > > It turns out the problem was yet another unaligned appended DT, on xtensa
> > > this time.
> >
> > I wonder if we have still more places. I've seen patches in your series
> > for many but not all of
> > https://lore.kernel.org/all/20221215115825.827111-1-eugen.hristev@microchip.com/
> > and I don't recall how many of those were done individually instead
> > afterwards.
> Was there any reason why that patch (or subset of) was not picked up ?
It didn't get split up, and truncate isn't portable but later in the
thread we confirmed how to use dd in a way that is and does what's
required.
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 0/3] Synchronize DTC to 1.7.2
2025-11-16 21:48 ` Marek Vasut
@ 2025-11-17 18:40 ` Tom Rini
2025-11-19 21:31 ` Marek Vasut
0 siblings, 1 reply; 32+ messages in thread
From: Tom Rini @ 2025-11-17 18:40 UTC (permalink / raw)
To: Marek Vasut
Cc: u-boot, Adriano Cordova, Andrew Goodbody, Christian Marangi,
Heinrich Schuchardt, Ilias Apalodimas, Patrice Chotard,
Sam Edwards, Simon Glass
[-- Attachment #1: Type: text/plain, Size: 2463 bytes --]
On Sun, Nov 16, 2025 at 10:48:45PM +0100, Marek Vasut wrote:
> On 11/16/25 3:11 PM, Tom Rini wrote:
> > On Sun, Nov 16, 2025 at 12:23:30AM +0100, Marek Vasut wrote:
> > > On 11/13/25 7:49 PM, Tom Rini wrote:
> > >
> > > Hello Tom,
> > >
> > > > > CI does show that no boards went oversize . If there is some growth on
> > > > > existing devices, maybe we can shrink that, but maintaining obsolete DTC
> > > > > code base going forward and picking random updates into it, that will only
> > > > > lead to increasing maintenance pain, so I don't want to do that.
> > > >
> > > > Yeah, it's not an easy spot. But I'm really not happy with growing main
> > > > U-Boot almost everywhere by 2KiB - 4KiB, and SPL by ~512 bytes or more
> > > > just to keep up. I do see that integratorcp_cm1136 barely grows at all,
> > > > so maybe there's something that can be done more widely and just wasn't
> > > > clear at first. m68k only grows an average of 500 bytes and MIPS is
> > > > ~1KiB. PowerPC grows a lot. RISC-V a little.
> > > I suspect this might have to do with DTO support. The imx8mp_dhcom do use
> > > DTOs and the fdt_overlay.c code grew a lot.
> > >
> > > I also found out that if I patch out can_assume() and replace it with plain
> > > 1 , then the size drops by 1-2 kiB, but that's probably not what we want to
> > > do.
> >
> > I'm not sure, maybe we do? Or maybe we need to look and have *one* place
> > that confirms correct alignment and either fixes/complains
>
> That's already part of new libfdt, that is also what triggered the various
> fixes I posted recently:
>
> scripts/dtc/libfdt/fdt.c: if ((uintptr_t)fdt & 7)
> scripts/dtc/libfdt/fdt.c: if ((uintptr_t)fdt & 7)
>
> > , and then
> > every follow-up location doesn't need to perform that (or possibly many
> > other as well) validation checks. My impression from when I looked at
> > the code last, a few year ago, was that it was designed with "validate
> > with most? every? function" and we would be happy enough with "validate
> > once".
>
> If you can make that assumption -- that whatever we feed into libfdt is
> valid -- then we can simply patch out can_assume() .
Maybe the question I have then is, why isn't can_assume being optimized
out at compile time, if we set the mask right. Makes me wonder if
there's not something to fix upstream too. Or maybe we need to change
the default to higher than 0?
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 0/3] Synchronize DTC to 1.7.2
2025-11-17 18:40 ` Tom Rini
@ 2025-11-19 21:31 ` Marek Vasut
2025-11-20 15:54 ` Tom Rini
0 siblings, 1 reply; 32+ messages in thread
From: Marek Vasut @ 2025-11-19 21:31 UTC (permalink / raw)
To: Tom Rini
Cc: u-boot, Adriano Cordova, Andrew Goodbody, Christian Marangi,
Heinrich Schuchardt, Ilias Apalodimas, Patrice Chotard,
Sam Edwards, Simon Glass
On 11/17/25 7:40 PM, Tom Rini wrote:
Hello Tom,
>>> , and then
>>> every follow-up location doesn't need to perform that (or possibly many
>>> other as well) validation checks. My impression from when I looked at
>>> the code last, a few year ago, was that it was designed with "validate
>>> with most? every? function" and we would be happy enough with "validate
>>> once".
>>
>> If you can make that assumption -- that whatever we feed into libfdt is
>> valid -- then we can simply patch out can_assume() .
>
> Maybe the question I have then is, why isn't can_assume being optimized
> out at compile time, if we set the mask right. Makes me wonder if
> there's not something to fix upstream too. Or maybe we need to change
> the default to higher than 0?
Maybe because the mask is set differently for U-Boot and SPL , see:
CONFIG_SPL_OF_LIBFDT_ASSUME_MASK=0xff
CONFIG_OF_LIBFDT_ASSUME_MASK=0x0
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 3/3] libfdt: Check fdt_offset_ptr() return value unconditionally
2025-11-13 23:34 ` Simon Glass
@ 2025-11-20 4:20 ` Marek Vasut
0 siblings, 0 replies; 32+ messages in thread
From: Marek Vasut @ 2025-11-20 4:20 UTC (permalink / raw)
To: Simon Glass
Cc: Marek Vasut, u-boot, Adriano Cordova, Andrew Goodbody,
Christian Marangi, Heinrich Schuchardt, Ilias Apalodimas,
Patrice Chotard, Sam Edwards, Tom Rini
On 11/14/25 12:34 AM, Simon Glass wrote:
Hello Simon,
>>>> diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c
>>>> index 95f644c31f9..d16cc3d4730 100644
>>>> --- a/scripts/dtc/libfdt/fdt.c
>>>> +++ b/scripts/dtc/libfdt/fdt.c
>>>> @@ -168,7 +168,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
>>>>
>>>> *nextoffset = -FDT_ERR_TRUNCATED;
>>>> tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
>>>> - if (!can_assume(VALID_DTB) && !tagp)
>>>> + if (!tagp)
>>>> return FDT_END; /* premature end */
>>>> tag = fdt32_to_cpu(*tagp);
>>>> offset += FDT_TAGSIZE;
>>>> @@ -186,7 +186,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
>>>>
>>>> case FDT_PROP:
>>>> lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
>>>> - if (!can_assume(VALID_DTB) && !lenp)
>>>> + if (!lenp)
>>>> return FDT_END; /* premature end */
>>>>
>>>> len = fdt32_to_cpu(*lenp);
>>>> --
>>>> 2.51.0
>>>>
>>>
>>> The can_assume() is there to be respected and helps to reduce code
>>> size. What problem are you actually seeing?
>> fdt_offset_ptr() can return NULL, and it does in test_spl on sandbox if
>> I recall it right, because the U-Boot code passes in offsets which can
>> not be resolved properly and that makes fdt_offset_ptr() return NULL and
>> trigger SIGSEGV when it is dereferenced here.
>
> That sounds like the FDT is corrupt? Here we are parsing through tags,
> so we should really figure out why it is corrupt.
>
> But if note, then we should not be passing bad offsets...so what is
> the root cause of that?
These four [1] [2] [3] [4] supersede this patch.
[1]
https://lore.kernel.org/u-boot/20251120041439.817233-1-marek.vasut+renesas@mailbox.org/
[2]
https://lore.kernel.org/u-boot/20251120041504.817264-1-marek.vasut+renesas@mailbox.org/
[3]
https://lore.kernel.org/u-boot/20251120041526.817288-1-marek.vasut+renesas@mailbox.org/
[4]
https://lore.kernel.org/u-boot/20251120041613.817311-1-marek.vasut+renesas@mailbox.org/
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 0/3] Synchronize DTC to 1.7.2
2025-11-19 21:31 ` Marek Vasut
@ 2025-11-20 15:54 ` Tom Rini
2025-11-20 20:14 ` Marek Vasut
0 siblings, 1 reply; 32+ messages in thread
From: Tom Rini @ 2025-11-20 15:54 UTC (permalink / raw)
To: Marek Vasut
Cc: u-boot, Adriano Cordova, Andrew Goodbody, Christian Marangi,
Heinrich Schuchardt, Ilias Apalodimas, Patrice Chotard,
Sam Edwards, Simon Glass
[-- Attachment #1: Type: text/plain, Size: 1454 bytes --]
On Wed, Nov 19, 2025 at 10:31:24PM +0100, Marek Vasut wrote:
> On 11/17/25 7:40 PM, Tom Rini wrote:
>
> Hello Tom,
>
> > > > , and then
> > > > every follow-up location doesn't need to perform that (or possibly many
> > > > other as well) validation checks. My impression from when I looked at
> > > > the code last, a few year ago, was that it was designed with "validate
> > > > with most? every? function" and we would be happy enough with "validate
> > > > once".
> > >
> > > If you can make that assumption -- that whatever we feed into libfdt is
> > > valid -- then we can simply patch out can_assume() .
> >
> > Maybe the question I have then is, why isn't can_assume being optimized
> > out at compile time, if we set the mask right. Makes me wonder if
> > there's not something to fix upstream too. Or maybe we need to change
> > the default to higher than 0?
>
> Maybe because the mask is set differently for U-Boot and SPL , see:
>
> CONFIG_SPL_OF_LIBFDT_ASSUME_MASK=0xff
> CONFIG_OF_LIBFDT_ASSUME_MASK=0x0
Right. We might want a different default for full U-Boot at this point
(not assume perfect, but also not assume nothing). But still, I would
have hoped SPL growth was smaller, but perhaps I just need to
re-evaluate things. Let me know when you have a next iteration of
everything branch somewhere and I'll run the size growth build before
you post if you like and we can iterate on it.
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 0/3] Synchronize DTC to 1.7.2
2025-11-20 15:54 ` Tom Rini
@ 2025-11-20 20:14 ` Marek Vasut
0 siblings, 0 replies; 32+ messages in thread
From: Marek Vasut @ 2025-11-20 20:14 UTC (permalink / raw)
To: Tom Rini
Cc: u-boot, Adriano Cordova, Andrew Goodbody, Christian Marangi,
Heinrich Schuchardt, Ilias Apalodimas, Patrice Chotard,
Sam Edwards, Simon Glass
On 11/20/25 4:54 PM, Tom Rini wrote:
Hello Tom,
>>>>> , and then
>>>>> every follow-up location doesn't need to perform that (or possibly many
>>>>> other as well) validation checks. My impression from when I looked at
>>>>> the code last, a few year ago, was that it was designed with "validate
>>>>> with most? every? function" and we would be happy enough with "validate
>>>>> once".
>>>>
>>>> If you can make that assumption -- that whatever we feed into libfdt is
>>>> valid -- then we can simply patch out can_assume() .
>>>
>>> Maybe the question I have then is, why isn't can_assume being optimized
>>> out at compile time, if we set the mask right. Makes me wonder if
>>> there's not something to fix upstream too. Or maybe we need to change
>>> the default to higher than 0?
>>
>> Maybe because the mask is set differently for U-Boot and SPL , see:
>>
>> CONFIG_SPL_OF_LIBFDT_ASSUME_MASK=0xff
>> CONFIG_OF_LIBFDT_ASSUME_MASK=0x0
>
> Right. We might want a different default for full U-Boot at this point
> (not assume perfect, but also not assume nothing).
For SPL, we assume perfect. For U-Boot, we assume not valid at all.
I think this configuration is actually what we want, keep SPL size
small, perform validation of DT in U-Boot because it might come from a
command line.
> But still, I would
> have hoped SPL growth was smaller, but perhaps I just need to
> re-evaluate things. Let me know when you have a next iteration of
> everything branch somewhere and I'll run the size growth build before
> you post if you like and we can iterate on it.
The latest is always in u-boot-sh / test-dtc branch.
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 0/3] Synchronize DTC to 1.7.2
2025-11-13 17:57 ` [PATCH 0/3] Synchronize DTC to 1.7.2 Tom Rini
2025-11-13 18:40 ` Marek Vasut
@ 2025-11-21 19:55 ` Tom Rini
2025-12-02 17:46 ` Marek Vasut
1 sibling, 1 reply; 32+ messages in thread
From: Tom Rini @ 2025-11-21 19:55 UTC (permalink / raw)
To: Marek Vasut
Cc: u-boot, Adriano Cordova, Andrew Goodbody, Christian Marangi,
Heinrich Schuchardt, Ilias Apalodimas, Patrice Chotard,
Sam Edwards, Simon Glass
[-- Attachment #1: Type: text/plain, Size: 2829 bytes --]
On Thu, Nov 13, 2025 at 11:57:00AM -0600, Tom Rini wrote:
> On Thu, Nov 13, 2025 at 01:21:07PM +0100, Marek Vasut wrote:
>
> > Synchronize local copy of DTC with Linux 6.17 , using commits picked
> > from Linux kernel. This also includes two fix up patches to make the
> > DM core work with new 8-byte alignment checking in libfdt and another
> > fix for NULL pointer check that is missing in libfdt.
> >
> > This depends on the following patches sent separately, which fix
> > various 8-byte alignment problems in the code base:
> >
> > - boot: android: Always use 8-byte aligned DT with libfdt
> > - test/py: android: Point fdt command to aligned addresses
> > - test/py: Use aligned address for overlays in 'extension' test
> > - sandbox: Fix DT compiler address warnings in sandbox DTs
> > - sandbox: Fix DT compiler pin warnings in sandbox DTs
> > - boot: Assure FDT is always at 8-byte aligned address
> > - arm: qemu: Eliminate fdt_high and initrd_high misuse
> > - efi_loader: Assure fitImage from capsule is used from 8-byte aligned address
> > - MIPS: Assure end of U-Boot is at 8-byte aligned offset
>
> So, taking a look at the test branch you pointed me at, my big concern
> is size growth. On imx8mp_dhcom_drc02 (where we're already LTO'ing),
> with the CI gcc-14.2.0 toolchain full U-Boot grows by more than 6KiB and
> SPL by a bit more than 2KiB. This is a bit of a worst-case, imx8mp_navqp
> is a bit more than 3KiB / 548 bytes, with the average feeling like
> ~4KiB/1KiB for aarch64.
I'm coming back to this to try and better understand things. And one
problem here is that upstream dtc changes really trip up LTO. I made as
a local hack, a change for imx8mp_dhcom_pdk2 to NOT use LTO (and so SPL
fails to link, but it's about the same growth, given the change in
overflows sram by numbers). This brought the size change down from ~6KiB
to ~4KiB. Since this was already a hack just for investigation, I then
started out with giving full U-Boot the "assume perfect dtb" mask. This
reduces growth by 900 bytes.
A better test case is pinephone because it's aarch64 but not LTO. And
with a full mask in U-Boot hack, the size growth for full U-Boot is
around 1000 bytes and 300 bytes in SPL.
And so to me, there's a few questions. The first of which is, how is
what's being done so terrible for LTO. It's not good for normal
optimizations either, but it's really bad with LTO. The second of which
is, is there something being done with how the sanity checks are
performed that can be re-examined? Take fdt_get_string for example,
which grows by 120 bytes without changing the mask at all, and the code
changes are trivial switches to the new FDT_ASSUME mechanic and dropping
extra parens. That shouldn't have size growth, I would expect.
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 0/3] Synchronize DTC to 1.7.2
2025-11-21 19:55 ` Tom Rini
@ 2025-12-02 17:46 ` Marek Vasut
2025-12-02 18:06 ` Tom Rini
0 siblings, 1 reply; 32+ messages in thread
From: Marek Vasut @ 2025-12-02 17:46 UTC (permalink / raw)
To: Tom Rini
Cc: u-boot, Adriano Cordova, Andrew Goodbody, Christian Marangi,
Heinrich Schuchardt, Ilias Apalodimas, Patrice Chotard,
Sam Edwards, Simon Glass
[-- Attachment #1: Type: text/plain, Size: 8821 bytes --]
On 11/21/25 8:55 PM, Tom Rini wrote:
Hello Tom,
>>> Synchronize local copy of DTC with Linux 6.17 , using commits picked
>>> from Linux kernel. This also includes two fix up patches to make the
>>> DM core work with new 8-byte alignment checking in libfdt and another
>>> fix for NULL pointer check that is missing in libfdt.
>>>
>>> This depends on the following patches sent separately, which fix
>>> various 8-byte alignment problems in the code base:
>>>
>>> - boot: android: Always use 8-byte aligned DT with libfdt
>>> - test/py: android: Point fdt command to aligned addresses
>>> - test/py: Use aligned address for overlays in 'extension' test
>>> - sandbox: Fix DT compiler address warnings in sandbox DTs
>>> - sandbox: Fix DT compiler pin warnings in sandbox DTs
>>> - boot: Assure FDT is always at 8-byte aligned address
>>> - arm: qemu: Eliminate fdt_high and initrd_high misuse
>>> - efi_loader: Assure fitImage from capsule is used from 8-byte aligned address
>>> - MIPS: Assure end of U-Boot is at 8-byte aligned offset
>>
>> So, taking a look at the test branch you pointed me at, my big concern
>> is size growth. On imx8mp_dhcom_drc02 (where we're already LTO'ing),
>> with the CI gcc-14.2.0 toolchain full U-Boot grows by more than 6KiB and
>> SPL by a bit more than 2KiB. This is a bit of a worst-case, imx8mp_navqp
>> is a bit more than 3KiB / 548 bytes, with the average feeling like
>> ~4KiB/1KiB for aarch64.
>
> I'm coming back to this to try and better understand things. And one
> problem here is that upstream dtc changes really trip up LTO. I made as
> a local hack, a change for imx8mp_dhcom_pdk2 to NOT use LTO (and so SPL
> fails to link, but it's about the same growth, given the change in
> overflows sram by numbers). This brought the size change down from ~6KiB
> to ~4KiB. Since this was already a hack just for investigation, I then
> started out with giving full U-Boot the "assume perfect dtb" mask. This
> reduces growth by 900 bytes.
>
> A better test case is pinephone because it's aarch64 but not LTO. And
> with a full mask in U-Boot hack, the size growth for full U-Boot is
> around 1000 bytes and 300 bytes in SPL.
>
> And so to me, there's a few questions. The first of which is, how is
> what's being done so terrible for LTO. It's not good for normal
> optimizations either, but it's really bad with LTO. The second of which
> is, is there something being done with how the sanity checks are
> performed that can be re-examined? Take fdt_get_string for example,
> which grows by 120 bytes without changing the mask at all, and the code
> changes are trivial switches to the new FDT_ASSUME mechanic and dropping
> extra parens. That shouldn't have size growth, I would expect.
Does this patch below make your size problem go away ?
"
diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h
index d7cf74722b2..7f8bb05c545 100644
--- a/scripts/dtc/libfdt/libfdt.h
+++ b/scripts/dtc/libfdt/libfdt.h
@@ -140,12 +140,7 @@ static inline uint16_t fdt16_ld(const fdt16_t *p)
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];
+ return fdt32_to_cpu(*p);
}
static inline void fdt32_st(void *property, uint32_t value)
@@ -160,16 +155,7 @@ static inline void fdt32_st(void *property,
uint32_t value)
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];
+ return fdt64_to_cpu(*p);
}
static inline void fdt64_st(void *property, uint64_t value)
"
You can see the difference caused by these new unaligned-access
functions in the disassembly (objdump -lSD) of u-boot with (top) and
without (bottom) the DTC 1.7.2 patch:
"
00000000402984e0 <fdt_get_string>:
fdt_get_string():
/tmp/dtc-yes/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:35
{
402984e0: a9be7bfd stp x29, x30, [sp, #-32]!
402984e4: aa0003e3 mov x3, x0
402984e8: 2a0103e4 mov w4, w1
402984ec: 910003fd mov x29, sp
402984f0: a90153f3 stp x19, x20, [sp, #16]
402984f4: aa0203f4 mov x20, x2
/tmp/dtc-yes/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:49
totalsize = fdt_ro_probe_(fdt);
402984f8: 97fffe4b bl 40297e24 <fdt_ro_probe_>
/tmp/dtc-yes/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:51
if (totalsize < 0)
402984fc: 37f80a40 tbnz w0, #31, 40298644
<fdt_get_string+0x164>
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv #1
/tmp/dtc-yes/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:55
absoffset = stroffset + fdt_off_dt_strings(fdt);
40298500: 39403061 ldrb w1, [x3, #12]
40298504: 39403462 ldrb w2, [x3, #13]
40298508: 39403c73 ldrb w19, [x3, #15]
4029850c: aa022022 orr x2, x1, x2, lsl #8
40298510: 39403861 ldrb w1, [x3, #14]
40298514: aa014041 orr x1, x2, x1, lsl #16
40298518: aa136033 orr x19, x1, x19, lsl #24
4029851c: 5ac00a73 rev w19, w19
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #1
/tmp/dtc-yes/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:55
(discriminator 1)
40298520: 0b130093 add w19, w4, w19
/tmp/dtc-yes/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:56
if (absoffset >= (unsigned)totalsize)
40298524: 6b13001f cmp w0, w19
40298528: 54000969 b.ls 40298654 <fdt_get_string+0x174>
// b.plast
/tmp/dtc-yes/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:58
len = totalsize - absoffset;
4029852c: 39400062 ldrb w2, [x3]
40298530: 4b130000 sub w0, w0, w19
/tmp/dtc-yes/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:60
if (fdt_magic(fdt) == FDT_MAGIC) {
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv #2
40298534: 39400461 ldrb w1, [x3, #1]
40298538: aa012041 orr x1, x2, x1, lsl #8
4029853c: 39400862 ldrb w2, [x3, #2]
40298540: aa024022 orr x2, x1, x2, lsl #16
40298544: 39400c61 ldrb w1, [x3, #3]
40298548: aa016041 orr x1, x2, x1, lsl #24
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #2
"
"
0000000040297804 <fdt_get_string>:
fdt_get_string():
/tmp/dtc-no/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:35
{
40297804: a9bd7bfd stp x29, x30, [sp, #-48]!
40297808: 910003fd mov x29, sp
4029780c: a90153f3 stp x19, x20, [sp, #16]
40297810: 2a0103f4 mov w20, w1
40297814: a9025bf5 stp x21, x22, [sp, #32]
40297818: aa0003f6 mov x22, x0
4029781c: aa0203f5 mov x21, x2
/tmp/dtc-no/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:49
totalsize = fdt_ro_probe_(fdt);
40297820: 97fff833 bl 402958ec <fdt_ro_probe_>
/tmp/dtc-no/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:51
if (totalsize < 0)
40297824: 37f806a0 tbnz w0, #31, 402978f8
<fdt_get_string+0xf4>
/tmp/dtc-no/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:55
absoffset = stroffset + fdt_off_dt_strings(fdt);
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv #1
40297828: b9400ed3 ldr w19, [x22, #12]
4029782c: 5ac00a73 rev w19, w19
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #1
/tmp/dtc-no/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:55
(discriminator 6)
40297830: 0b130293 add w19, w20, w19
/tmp/dtc-no/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:56
if (absoffset >= (unsigned)totalsize)
40297834: 6b13001f cmp w0, w19
40297838: 54000689 b.ls 40297908 <fdt_get_string+0x104>
// b.plast
/tmp/dtc-no/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:58
len = totalsize - absoffset;
4029783c: b94002c1 ldr w1, [x22]
/tmp/dtc-no/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:60
(discriminator 6)
if (fdt_magic(fdt) == FDT_MAGIC) {
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv #2
40297840: 5281ba02 mov w2, #0xdd0
// #3536
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #2
"
But the question now is, how should we handle this ? These unaligned
access functions are there for a reason.
[-- Attachment #2: fdt.diff --]
[-- Type: text/x-patch, Size: 1035 bytes --]
diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h
index d7cf74722b2..7f8bb05c545 100644
--- a/scripts/dtc/libfdt/libfdt.h
+++ b/scripts/dtc/libfdt/libfdt.h
@@ -140,12 +140,7 @@ static inline uint16_t fdt16_ld(const fdt16_t *p)
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];
+ return fdt32_to_cpu(*p);
}
static inline void fdt32_st(void *property, uint32_t value)
@@ -160,16 +155,7 @@ static inline void fdt32_st(void *property, uint32_t value)
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];
+ return fdt64_to_cpu(*p);
}
static inline void fdt64_st(void *property, uint64_t value)
^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [PATCH 0/3] Synchronize DTC to 1.7.2
2025-12-02 17:46 ` Marek Vasut
@ 2025-12-02 18:06 ` Tom Rini
2025-12-02 18:35 ` Marek Vasut
0 siblings, 1 reply; 32+ messages in thread
From: Tom Rini @ 2025-12-02 18:06 UTC (permalink / raw)
To: Marek Vasut
Cc: u-boot, Adriano Cordova, Andrew Goodbody, Christian Marangi,
Heinrich Schuchardt, Ilias Apalodimas, Patrice Chotard,
Sam Edwards, Simon Glass
[-- Attachment #1: Type: text/plain, Size: 10056 bytes --]
On Tue, Dec 02, 2025 at 06:46:07PM +0100, Marek Vasut wrote:
> On 11/21/25 8:55 PM, Tom Rini wrote:
>
> Hello Tom,
>
> > > > Synchronize local copy of DTC with Linux 6.17 , using commits picked
> > > > from Linux kernel. This also includes two fix up patches to make the
> > > > DM core work with new 8-byte alignment checking in libfdt and another
> > > > fix for NULL pointer check that is missing in libfdt.
> > > >
> > > > This depends on the following patches sent separately, which fix
> > > > various 8-byte alignment problems in the code base:
> > > >
> > > > - boot: android: Always use 8-byte aligned DT with libfdt
> > > > - test/py: android: Point fdt command to aligned addresses
> > > > - test/py: Use aligned address for overlays in 'extension' test
> > > > - sandbox: Fix DT compiler address warnings in sandbox DTs
> > > > - sandbox: Fix DT compiler pin warnings in sandbox DTs
> > > > - boot: Assure FDT is always at 8-byte aligned address
> > > > - arm: qemu: Eliminate fdt_high and initrd_high misuse
> > > > - efi_loader: Assure fitImage from capsule is used from 8-byte aligned address
> > > > - MIPS: Assure end of U-Boot is at 8-byte aligned offset
> > >
> > > So, taking a look at the test branch you pointed me at, my big concern
> > > is size growth. On imx8mp_dhcom_drc02 (where we're already LTO'ing),
> > > with the CI gcc-14.2.0 toolchain full U-Boot grows by more than 6KiB and
> > > SPL by a bit more than 2KiB. This is a bit of a worst-case, imx8mp_navqp
> > > is a bit more than 3KiB / 548 bytes, with the average feeling like
> > > ~4KiB/1KiB for aarch64.
> >
> > I'm coming back to this to try and better understand things. And one
> > problem here is that upstream dtc changes really trip up LTO. I made as
> > a local hack, a change for imx8mp_dhcom_pdk2 to NOT use LTO (and so SPL
> > fails to link, but it's about the same growth, given the change in
> > overflows sram by numbers). This brought the size change down from ~6KiB
> > to ~4KiB. Since this was already a hack just for investigation, I then
> > started out with giving full U-Boot the "assume perfect dtb" mask. This
> > reduces growth by 900 bytes.
> >
> > A better test case is pinephone because it's aarch64 but not LTO. And
> > with a full mask in U-Boot hack, the size growth for full U-Boot is
> > around 1000 bytes and 300 bytes in SPL.
> >
> > And so to me, there's a few questions. The first of which is, how is
> > what's being done so terrible for LTO. It's not good for normal
> > optimizations either, but it's really bad with LTO. The second of which
> > is, is there something being done with how the sanity checks are
> > performed that can be re-examined? Take fdt_get_string for example,
> > which grows by 120 bytes without changing the mask at all, and the code
> > changes are trivial switches to the new FDT_ASSUME mechanic and dropping
> > extra parens. That shouldn't have size growth, I would expect.
>
> Does this patch below make your size problem go away ?
>
> "
> diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h
> index d7cf74722b2..7f8bb05c545 100644
> --- a/scripts/dtc/libfdt/libfdt.h
> +++ b/scripts/dtc/libfdt/libfdt.h
> @@ -140,12 +140,7 @@ static inline uint16_t fdt16_ld(const fdt16_t *p)
>
> 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];
> + return fdt32_to_cpu(*p);
> }
>
> static inline void fdt32_st(void *property, uint32_t value)
> @@ -160,16 +155,7 @@ static inline void fdt32_st(void *property, uint32_t
> value)
>
> 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];
> + return fdt64_to_cpu(*p);
> }
>
> static inline void fdt64_st(void *property, uint64_t value)
> "
>
> You can see the difference caused by these new unaligned-access functions in
> the disassembly (objdump -lSD) of u-boot with (top) and without (bottom) the
> DTC 1.7.2 patch:
I bet it does, yes. I had forgotten that we explicitly revert that
change from upstream.
> "
> 00000000402984e0 <fdt_get_string>:
> fdt_get_string():
> /tmp/dtc-yes/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:35
> {
> 402984e0: a9be7bfd stp x29, x30, [sp, #-32]!
> 402984e4: aa0003e3 mov x3, x0
> 402984e8: 2a0103e4 mov w4, w1
> 402984ec: 910003fd mov x29, sp
> 402984f0: a90153f3 stp x19, x20, [sp, #16]
> 402984f4: aa0203f4 mov x20, x2
> /tmp/dtc-yes/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:49
> totalsize = fdt_ro_probe_(fdt);
> 402984f8: 97fffe4b bl 40297e24 <fdt_ro_probe_>
> /tmp/dtc-yes/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:51
> if (totalsize < 0)
> 402984fc: 37f80a40 tbnz w0, #31, 40298644
> <fdt_get_string+0x164>
> vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv #1
> /tmp/dtc-yes/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:55
> absoffset = stroffset + fdt_off_dt_strings(fdt);
> 40298500: 39403061 ldrb w1, [x3, #12]
> 40298504: 39403462 ldrb w2, [x3, #13]
> 40298508: 39403c73 ldrb w19, [x3, #15]
> 4029850c: aa022022 orr x2, x1, x2, lsl #8
> 40298510: 39403861 ldrb w1, [x3, #14]
> 40298514: aa014041 orr x1, x2, x1, lsl #16
> 40298518: aa136033 orr x19, x1, x19, lsl #24
> 4029851c: 5ac00a73 rev w19, w19
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #1
> /tmp/dtc-yes/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:55 (discriminator
> 1)
> 40298520: 0b130093 add w19, w4, w19
> /tmp/dtc-yes/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:56
> if (absoffset >= (unsigned)totalsize)
> 40298524: 6b13001f cmp w0, w19
> 40298528: 54000969 b.ls 40298654 <fdt_get_string+0x174> //
> b.plast
> /tmp/dtc-yes/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:58
> len = totalsize - absoffset;
> 4029852c: 39400062 ldrb w2, [x3]
> 40298530: 4b130000 sub w0, w0, w19
> /tmp/dtc-yes/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:60
> if (fdt_magic(fdt) == FDT_MAGIC) {
> vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv #2
> 40298534: 39400461 ldrb w1, [x3, #1]
> 40298538: aa012041 orr x1, x2, x1, lsl #8
> 4029853c: 39400862 ldrb w2, [x3, #2]
> 40298540: aa024022 orr x2, x1, x2, lsl #16
> 40298544: 39400c61 ldrb w1, [x3, #3]
> 40298548: aa016041 orr x1, x2, x1, lsl #24
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #2
> "
>
> "
> 0000000040297804 <fdt_get_string>:
> fdt_get_string():
> /tmp/dtc-no/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:35
> {
> 40297804: a9bd7bfd stp x29, x30, [sp, #-48]!
> 40297808: 910003fd mov x29, sp
> 4029780c: a90153f3 stp x19, x20, [sp, #16]
> 40297810: 2a0103f4 mov w20, w1
> 40297814: a9025bf5 stp x21, x22, [sp, #32]
> 40297818: aa0003f6 mov x22, x0
> 4029781c: aa0203f5 mov x21, x2
> /tmp/dtc-no/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:49
> totalsize = fdt_ro_probe_(fdt);
> 40297820: 97fff833 bl 402958ec <fdt_ro_probe_>
> /tmp/dtc-no/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:51
> if (totalsize < 0)
> 40297824: 37f806a0 tbnz w0, #31, 402978f8
> <fdt_get_string+0xf4>
> /tmp/dtc-no/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:55
> absoffset = stroffset + fdt_off_dt_strings(fdt);
> vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv #1
> 40297828: b9400ed3 ldr w19, [x22, #12]
> 4029782c: 5ac00a73 rev w19, w19
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #1
> /tmp/dtc-no/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:55 (discriminator
> 6)
> 40297830: 0b130293 add w19, w20, w19
> /tmp/dtc-no/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:56
> if (absoffset >= (unsigned)totalsize)
> 40297834: 6b13001f cmp w0, w19
> 40297838: 54000689 b.ls 40297908 <fdt_get_string+0x104> //
> b.plast
> /tmp/dtc-no/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:58
> len = totalsize - absoffset;
> 4029783c: b94002c1 ldr w1, [x22]
> /tmp/dtc-no/lib/libfdt/../../scripts/dtc/libfdt/fdt_ro.c:60 (discriminator
> 6)
> if (fdt_magic(fdt) == FDT_MAGIC) {
> vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv #2
> 40297840: 5281ba02 mov w2, #0xdd0 // #3536
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #2
> "
>
> But the question now is, how should we handle this ? These unaligned access
> functions are there for a reason.
The historical and short version of why they are there is that a
platform was passing the kernel a misaligned device tree and the
assumption was that it was intentional and not a bug, and so dtc put a
bunch of effort in to working around that. After discussion (in 2019 or
so) the conclusion from dtc was that they still wanted to keep these
changes, despite it being a bug that a misaligned tree was passed. I did
not further press the issue further. So doing a revert, again, is what
we need to do.
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 0/3] Synchronize DTC to 1.7.2
2025-12-02 18:06 ` Tom Rini
@ 2025-12-02 18:35 ` Marek Vasut
0 siblings, 0 replies; 32+ messages in thread
From: Marek Vasut @ 2025-12-02 18:35 UTC (permalink / raw)
To: Tom Rini
Cc: u-boot, Adriano Cordova, Andrew Goodbody, Christian Marangi,
Heinrich Schuchardt, Ilias Apalodimas, Patrice Chotard,
Sam Edwards, Simon Glass
On 12/2/25 7:06 PM, Tom Rini wrote:
Hello Tom,
>> But the question now is, how should we handle this ? These unaligned access
>> functions are there for a reason.
>
> The historical and short version of why they are there is that a
> platform was passing the kernel a misaligned device tree and the
> assumption was that it was intentional and not a bug, and so dtc put a
> bunch of effort in to working around that. After discussion (in 2019 or
> so) the conclusion from dtc was that they still wanted to keep these
> changes, despite it being a bug that a misaligned tree was passed. I did
> not further press the issue further. So doing a revert, again, is what
> we need to do.
All right, let me wrap this into V2 and send V2 once CI passes.
--
Best regards,
Marek Vasut
^ permalink raw reply [flat|nested] 32+ messages in thread
end of thread, other threads:[~2025-12-02 18:35 UTC | newest]
Thread overview: 32+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-13 12:21 [PATCH 0/3] Synchronize DTC to 1.7.2 Marek Vasut
2025-11-13 12:21 ` [PATCH 1/3] dm: core: Check ofnode_to_offset() return value Marek Vasut
2025-11-13 19:33 ` Simon Glass
2025-11-13 21:51 ` Marek Vasut
2025-11-13 22:46 ` Simon Glass
2025-11-14 5:17 ` Marek Vasut
2025-11-14 14:36 ` Tom Rini
2025-11-16 0:16 ` Marek Vasut
2025-11-16 14:13 ` Tom Rini
2025-11-16 21:28 ` Marek Vasut
2025-11-17 14:14 ` Tom Rini
2025-11-13 12:21 ` [PATCH 2/3] scripts/dtc: Update to upstream version v1.7.2-35-g52f07dcca47c Marek Vasut
2025-11-13 12:21 ` [PATCH 3/3] libfdt: Check fdt_offset_ptr() return value unconditionally Marek Vasut
2025-11-13 19:33 ` Simon Glass
2025-11-13 21:48 ` Marek Vasut
2025-11-13 23:34 ` Simon Glass
2025-11-20 4:20 ` Marek Vasut
2025-11-13 17:57 ` [PATCH 0/3] Synchronize DTC to 1.7.2 Tom Rini
2025-11-13 18:40 ` Marek Vasut
2025-11-13 18:49 ` Tom Rini
2025-11-13 19:32 ` Simon Glass
2025-11-15 23:23 ` Marek Vasut
2025-11-16 14:11 ` Tom Rini
2025-11-16 21:48 ` Marek Vasut
2025-11-17 18:40 ` Tom Rini
2025-11-19 21:31 ` Marek Vasut
2025-11-20 15:54 ` Tom Rini
2025-11-20 20:14 ` Marek Vasut
2025-11-21 19:55 ` Tom Rini
2025-12-02 17:46 ` Marek Vasut
2025-12-02 18:06 ` Tom Rini
2025-12-02 18:35 ` Marek Vasut
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox