aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/dtc
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/dtc')
-rw-r--r--scripts/dtc/.gitignore4
-rw-r--r--scripts/dtc/Makefile23
-rw-r--r--scripts/dtc/Makefile.dtc23
-rw-r--r--scripts/dtc/checks.c274
-rw-r--r--scripts/dtc/data.c6
-rwxr-xr-xscripts/dtc/dt-extract-compatibles69
-rw-r--r--scripts/dtc/dtc-lexer.l3
-rw-r--r--scripts/dtc/dtc-parser.y4
-rw-r--r--scripts/dtc/dtc.c6
-rw-r--r--scripts/dtc/dtc.h79
-rwxr-xr-xscripts/dtc/dtx_diff11
-rw-r--r--scripts/dtc/fdtdump.c163
-rw-r--r--scripts/dtc/fdtoverlay.c208
-rw-r--r--scripts/dtc/flattree.c21
l---------scripts/dtc/include-prefixes/c6x1
l---------scripts/dtc/include-prefixes/h83001
-rw-r--r--scripts/dtc/libfdt/Makefile.libfdt18
-rw-r--r--scripts/dtc/libfdt/fdt.c130
-rw-r--r--scripts/dtc/libfdt/fdt.h4
-rw-r--r--scripts/dtc/libfdt/fdt_overlay.c3
-rw-r--r--scripts/dtc/libfdt/fdt_ro.c175
-rw-r--r--scripts/dtc/libfdt/fdt_rw.c64
-rw-r--r--scripts/dtc/libfdt/fdt_strerror.c5
-rw-r--r--scripts/dtc/libfdt/fdt_sw.c50
-rw-r--r--scripts/dtc/libfdt/fdt_wip.c2
-rw-r--r--scripts/dtc/libfdt/libfdt.h146
-rw-r--r--scripts/dtc/libfdt/libfdt_internal.h141
-rw-r--r--scripts/dtc/livetree.c8
-rwxr-xr-xscripts/dtc/of_unittest_expect408
-rw-r--r--scripts/dtc/srcpos.c2
-rw-r--r--scripts/dtc/treesource.c56
-rwxr-xr-xscripts/dtc/update-dtc-source.sh7
-rw-r--r--scripts/dtc/util.h7
-rw-r--r--scripts/dtc/version_gen.h2
-rw-r--r--scripts/dtc/yamltree.c24
35 files changed, 1537 insertions, 611 deletions
diff --git a/scripts/dtc/.gitignore b/scripts/dtc/.gitignore
index 2e6e60d64ede..e0b5c1d2464a 100644
--- a/scripts/dtc/.gitignore
+++ b/scripts/dtc/.gitignore
@@ -1 +1,3 @@
-dtc
+# SPDX-License-Identifier: GPL-2.0-only
+/dtc
+/fdtoverlay
diff --git a/scripts/dtc/Makefile b/scripts/dtc/Makefile
index 3acbb410904c..4d32b9497da9 100644
--- a/scripts/dtc/Makefile
+++ b/scripts/dtc/Makefile
@@ -1,26 +1,23 @@
# SPDX-License-Identifier: GPL-2.0
# scripts/dtc makefile
-hostprogs := dtc
-always-$(CONFIG_DTC) := $(hostprogs)
+# *** Also keep .gitignore in sync when changing ***
+hostprogs-always-$(CONFIG_DTC) += dtc fdtoverlay
+hostprogs-always-$(CHECK_DT_BINDING) += 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
-# Source files need to get at the userspace version of libfdt_env.h to compile
-HOST_EXTRACFLAGS := -I $(srctree)/$(src)/libfdt
+# 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
-ifeq ($(shell pkg-config --exists yaml-0.1 2>/dev/null && echo yes),)
-ifneq ($(CHECK_DTBS),)
-$(error dtc needs libyaml for DT schema validation support. \
- Install the necessary libyaml development package.)
-endif
+# Source files need to get at the userspace version of libfdt_env.h to compile
+HOST_EXTRACFLAGS += -I $(srctree)/$(src)/libfdt
HOST_EXTRACFLAGS += -DNO_YAML
-else
-dtc-objs += yamltree.o
-HOSTLDLIBS_dtc := $(shell pkg-config yaml-0.1 --libs)
-endif
# Generated files need one more search path to include headers in source tree
HOSTCFLAGS_dtc-lexer.lex.o := -I $(srctree)/$(src)
diff --git a/scripts/dtc/Makefile.dtc b/scripts/dtc/Makefile.dtc
deleted file mode 100644
index 9c467b096f03..000000000000
--- a/scripts/dtc/Makefile.dtc
+++ /dev/null
@@ -1,23 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-or-later
-# 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
-
-ifneq ($(NO_YAML),1)
-DTC_SRCS += yamltree.c
-endif
-
-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 756f0fa9203f..781ba1129a8e 100644
--- a/scripts/dtc/checks.c
+++ b/scripts/dtc/checks.c
@@ -143,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;
@@ -297,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)
@@ -330,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)
{
@@ -352,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);
@@ -363,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,
@@ -380,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;
@@ -497,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;
@@ -556,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);
@@ -657,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");
@@ -672,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;
@@ -753,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);
@@ -765,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;
}
@@ -783,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",
@@ -868,7 +892,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)",
@@ -888,10 +912,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])
@@ -1019,6 +1041,9 @@ static void check_i2c_bus_bridge(struct check *c, struct dt_info *dti, struct no
}
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;
@@ -1041,6 +1066,8 @@ static void check_i2c_bus_reg(struct check *c, struct dt_info *dti, struct node
}
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\"",
@@ -1048,10 +1075,15 @@ static void check_i2c_bus_reg(struct check *c, struct dt_info *dti, struct node
for (len = prop->val.len; len > 0; len -= 4) {
reg = fdt32_to_cpu(*(cells++));
- if (reg > 0x3ff)
+ /* Ignore I2C_OWN_SLAVE_ADDRESS */
+ reg &= ~I2C_OWN_SLAVE_ADDRESS;
+
+ if ((reg & I2C_TEN_BIT_ADDRESS) && ((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, &reg_format, &i2c_bus_bridge);
@@ -1356,9 +1388,9 @@ static void check_property_phandle_args(struct check *c,
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));
@@ -1368,14 +1400,14 @@ 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;
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;
@@ -1441,7 +1473,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");
@@ -1462,24 +1495,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,
@@ -1514,13 +1540,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,
@@ -1544,6 +1567,113 @@ 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);
+
+ cell += 1 + parent_cellsize;
+ }
+}
+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)
@@ -1551,13 +1681,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));
@@ -1570,7 +1700,7 @@ static void check_interrupts_property(struct check *c,
prop = get_property(parent, "interrupt-parent");
if (prop) {
phandle = propval_cell(prop);
- 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)
@@ -1601,12 +1731,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)));
@@ -1717,7 +1847,7 @@ 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;
@@ -1727,7 +1857,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);
@@ -1763,7 +1893,7 @@ WARNING(graph_endpoint, check_graph_endpoint, NULL, &graph_nodes);
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,
@@ -1771,7 +1901,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,
@@ -1780,7 +1910,7 @@ static struct check *check_table[] = {
&property_name_chars_strict,
&node_name_chars_strict,
- &addr_size_cells, &reg_format, &ranges_format,
+ &addr_size_cells, &reg_format, &ranges_format, &dma_ranges_format,
&unit_address_vs_reg,
&unit_address_format,
@@ -1806,25 +1936,43 @@ static struct check *check_table[] = {
&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,
@@ -1848,7 +1996,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 */
@@ -1869,7 +2017,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;
@@ -1896,7 +2044,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 0a43b6de3264..14734233ad8b 100644
--- a/scripts/dtc/data.c
+++ b/scripts/dtc/data.c
@@ -21,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;
@@ -84,7 +84,7 @@ struct data data_copy_file(FILE *f, size_t maxlen)
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;
diff --git a/scripts/dtc/dt-extract-compatibles b/scripts/dtc/dt-extract-compatibles
new file mode 100755
index 000000000000..a1119762ed08
--- /dev/null
+++ b/scripts/dtc/dt-extract-compatibles
@@ -0,0 +1,69 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-only
+
+import os
+import glob
+import re
+import argparse
+
+
+def parse_of_declare_macros(data):
+ """ Find all compatible strings in OF_DECLARE() style macros """
+ compat_list = []
+ # CPU_METHOD_OF_DECLARE does not have a compatible string
+ for m in re.finditer(r'(?<!CPU_METHOD_)(IRQCHIP|OF)_(DECLARE|MATCH)(_DRIVER)?\(.*?\)', data):
+ try:
+ compat = re.search(r'"(.*?)"', m[0])[1]
+ except:
+ # Fails on compatible strings in #define, so just skip
+ continue
+ compat_list += [compat]
+
+ return compat_list
+
+
+def parse_of_device_id(data):
+ """ Find all compatible strings in of_device_id structs """
+ compat_list = []
+ for m in re.finditer(r'of_device_id\s+[a-zA-Z0-9_]+\[\]\s*=\s*({.*?);', data):
+ compat_list += re.findall(r'\.compatible\s+=\s+"([a-zA-Z0-9_\-,]+)"', m[1])
+
+ return compat_list
+
+
+def parse_compatibles(file):
+ with open(file, 'r', encoding='utf-8') as f:
+ data = f.read().replace('\n', '')
+
+ compat_list = parse_of_declare_macros(data)
+ compat_list += parse_of_device_id(data)
+
+ return compat_list
+
+def print_compat(filename, compatibles):
+ if not compatibles:
+ return
+ if show_filename:
+ compat_str = ' '.join(compatibles)
+ print(filename + ": compatible(s): " + compat_str)
+ else:
+ print(*compatibles, sep='\n')
+
+show_filename = False
+
+if __name__ == "__main__":
+ ap = argparse.ArgumentParser()
+ ap.add_argument("cfile", type=str, nargs='*', help="C source files or directories to parse")
+ ap.add_argument('-H', '--with-filename', help="Print filename with compatibles", action="store_true")
+ args = ap.parse_args()
+
+ show_filename = args.with_filename
+
+ for f in args.cfile:
+ if os.path.isdir(f):
+ for filename in glob.iglob(f + "/**/*.c", recursive=True):
+ compat_list = parse_compatibles(filename)
+ print_compat(filename, compat_list)
+ else:
+ compat_list = parse_compatibles(f)
+ print_compat(f, compat_list)
diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l
index 5c6c3fd557d7..5568b4ae84cf 100644
--- a/scripts/dtc/dtc-lexer.l
+++ b/scripts/dtc/dtc-lexer.l
@@ -23,7 +23,6 @@ LINECOMMENT "//".*\n
#include "srcpos.h"
#include "dtc-parser.tab.h"
-YYLTYPE yylloc;
extern bool treesource_error;
/* CAUTION: this will stop working if we ever use yyless() or yyunput() */
@@ -58,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 # */
diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y
index 40dcf4f149da..a0316a3cc309 100644
--- a/scripts/dtc/dtc-parser.y
+++ b/scripts/dtc/dtc-parser.y
@@ -476,8 +476,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
;
diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c
index bdb3f5945699..bc786c543b7e 100644
--- a/scripts/dtc/dtc.c
+++ b/scripts/dtc/dtc.c
@@ -12,7 +12,7 @@
* 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 */
@@ -122,6 +122,8 @@ static const char *guess_type_by_name(const char *fname, const char *fallback)
return "dts";
if (!strcasecmp(s, ".yaml"))
return "yaml";
+ if (!strcasecmp(s, ".dtbo"))
+ return "dtb";
if (!strcasecmp(s, ".dtb"))
return "dtb";
return fallback;
@@ -195,7 +197,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);
diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h
index 6e74ecea55a3..0a1f54991026 100644
--- a/scripts/dtc/dtc.h
+++ b/scripts/dtc/dtc.h
@@ -35,7 +35,7 @@
* 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 */
@@ -51,10 +51,56 @@ extern int annotate; /* annotate .dts with input source location */
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))
@@ -70,17 +116,23 @@ enum markertype {
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;
};
@@ -94,11 +146,26 @@ struct data {
for_each_marker(m) \
if ((m)->type == (t))
-size_t type_marker_length(struct marker *m);
+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);
@@ -222,7 +289,7 @@ void append_to_property(struct node *node,
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,
diff --git a/scripts/dtc/dtx_diff b/scripts/dtc/dtx_diff
index 541c432e7d19..f2bbde4bba86 100755
--- a/scripts/dtc/dtx_diff
+++ b/scripts/dtc/dtx_diff
@@ -29,7 +29,8 @@ Usage:
-s SRCTREE linux kernel source tree is at path SRCTREE
(default is current directory)
-S linux kernel source tree is at root of current git repo
- -T Annotate output .dts with input source file and line (-T -T for more details)
+ -T annotate output .dts with input source file and line
+ (-T -T for more details)
-u unsorted, do not sort DTx
@@ -58,12 +59,8 @@ Otherwise DTx is treated as a dts source file (aka .dts).
or '/include/' to be processed.
If DTx_1 and DTx_2 are in different architectures, then this script
- may not work since \${ARCH} is part of the include path. Two possible
- workarounds:
-
- `basename $0` \\
- <(ARCH=arch_of_dtx_1 `basename $0` DTx_1) \\
- <(ARCH=arch_of_dtx_2 `basename $0` DTx_2)
+ may not work since \${ARCH} is part of the include path. The following
+ workaround can be used:
`basename $0` ARCH=arch_of_dtx_1 DTx_1 >tmp_dtx_1.dts
`basename $0` ARCH=arch_of_dtx_2 DTx_2 >tmp_dtx_2.dts
diff --git a/scripts/dtc/fdtdump.c b/scripts/dtc/fdtdump.c
deleted file mode 100644
index 7d460a50b513..000000000000
--- a/scripts/dtc/fdtdump.c
+++ /dev/null
@@ -1,163 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * fdtdump.c - Contributed by Pantelis Antoniou <pantelis.antoniou AT gmail.com>
- */
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-
-#include <fdt.h>
-#include <libfdt_env.h>
-
-#include "util.h"
-
-#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
-#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a))))
-#define GET_CELL(p) (p += 4, *((const uint32_t *)(p-4)))
-
-static void print_data(const char *data, int len)
-{
- int i;
- const char *p = data;
-
- /* no data, don't print */
- if (len == 0)
- return;
-
- if (util_is_printable_string(data, len)) {
- printf(" = \"%s\"", (const char *)data);
- } else if ((len % 4) == 0) {
- printf(" = <");
- for (i = 0; i < len; i += 4)
- printf("0x%08x%s", fdt32_to_cpu(GET_CELL(p)),
- i < (len - 4) ? " " : "");
- printf(">");
- } else {
- printf(" = [");
- for (i = 0; i < len; i++)
- printf("%02x%s", *p++, i < len - 1 ? " " : "");
- printf("]");
- }
-}
-
-static void dump_blob(void *blob)
-{
- struct fdt_header *bph = blob;
- uint32_t off_mem_rsvmap = fdt32_to_cpu(bph->off_mem_rsvmap);
- uint32_t off_dt = fdt32_to_cpu(bph->off_dt_struct);
- uint32_t off_str = fdt32_to_cpu(bph->off_dt_strings);
- struct fdt_reserve_entry *p_rsvmap =
- (struct fdt_reserve_entry *)((char *)blob + off_mem_rsvmap);
- const char *p_struct = (const char *)blob + off_dt;
- const char *p_strings = (const char *)blob + off_str;
- uint32_t version = fdt32_to_cpu(bph->version);
- uint32_t totalsize = fdt32_to_cpu(bph->totalsize);
- uint32_t tag;
- const char *p, *s, *t;
- int depth, sz, shift;
- int i;
- uint64_t addr, size;
-
- depth = 0;
- shift = 4;
-
- printf("/dts-v1/;\n");
- printf("// magic:\t\t0x%x\n", fdt32_to_cpu(bph->magic));
- printf("// totalsize:\t\t0x%x (%d)\n", totalsize, totalsize);
- printf("// off_dt_struct:\t0x%x\n", off_dt);
- printf("// off_dt_strings:\t0x%x\n", off_str);
- printf("// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap);
- printf("// version:\t\t%d\n", version);
- printf("// last_comp_version:\t%d\n",
- fdt32_to_cpu(bph->last_comp_version));
- if (version >= 2)
- printf("// boot_cpuid_phys:\t0x%x\n",
- fdt32_to_cpu(bph->boot_cpuid_phys));
-
- if (version >= 3)
- printf("// size_dt_strings:\t0x%x\n",
- fdt32_to_cpu(bph->size_dt_strings));
- if (version >= 17)
- printf("// size_dt_struct:\t0x%x\n",
- fdt32_to_cpu(bph->size_dt_struct));
- printf("\n");
-
- for (i = 0; ; i++) {
- addr = fdt64_to_cpu(p_rsvmap[i].address);
- size = fdt64_to_cpu(p_rsvmap[i].size);
- if (addr == 0 && size == 0)
- break;
-
- printf("/memreserve/ %llx %llx;\n",
- (unsigned long long)addr, (unsigned long long)size);
- }
-
- p = p_struct;
- while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) {
-
- /* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */
-
- if (tag == FDT_BEGIN_NODE) {
- s = p;
- p = PALIGN(p + strlen(s) + 1, 4);
-
- if (*s == '\0')
- s = "/";
-
- printf("%*s%s {\n", depth * shift, "", s);
-
- depth++;
- continue;
- }
-
- if (tag == FDT_END_NODE) {
- depth--;
-
- printf("%*s};\n", depth * shift, "");
- continue;
- }
-
- if (tag == FDT_NOP) {
- printf("%*s// [NOP]\n", depth * shift, "");
- continue;
- }
-
- if (tag != FDT_PROP) {
- fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", depth * shift, "", tag);
- break;
- }
- sz = fdt32_to_cpu(GET_CELL(p));
- s = p_strings + fdt32_to_cpu(GET_CELL(p));
- if (version < 16 && sz >= 8)
- p = PALIGN(p, 8);
- t = p;
-
- p = PALIGN(p + sz, 4);
-
- printf("%*s%s", depth * shift, "", s);
- print_data(t, sz);
- printf(";\n");
- }
-}
-
-
-int main(int argc, char *argv[])
-{
- char *buf;
-
- if (argc < 2) {
- fprintf(stderr, "supply input filename\n");
- return 5;
- }
-
- buf = utilfdt_read(argv[1]);
- if (buf)
- dump_blob(buf);
- else
- return 10;
-
- return 0;
-}
diff --git a/scripts/dtc/fdtoverlay.c b/scripts/dtc/fdtoverlay.c
new file mode 100644
index 000000000000..5350af65679f
--- /dev/null
+++ b/scripts/dtc/fdtoverlay.c
@@ -0,0 +1,208 @@
+// 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>]]\n"
+ "\n"
+ USAGE_TYPE_MSG;
+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;
+
+ /*
+ * We take a copies first, because a 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;
+ }
+
+ 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));
+ 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 bd6977eedcb8..95e43d32c3e6 100644
--- a/scripts/dtc/flattree.c
+++ b/scripts/dtc/flattree.c
@@ -124,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);
}
@@ -134,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)
@@ -149,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);
}
@@ -219,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? */
@@ -295,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);
@@ -345,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;
@@ -438,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;
}
}
@@ -446,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";
diff --git a/scripts/dtc/include-prefixes/c6x b/scripts/dtc/include-prefixes/c6x
deleted file mode 120000
index 49ded4cae2be..000000000000
--- a/scripts/dtc/include-prefixes/c6x
+++ /dev/null
@@ -1 +0,0 @@
-../../../arch/c6x/boot/dts \ No newline at end of file
diff --git a/scripts/dtc/include-prefixes/h8300 b/scripts/dtc/include-prefixes/h8300
deleted file mode 120000
index 3bdaa332c54c..000000000000
--- a/scripts/dtc/include-prefixes/h8300
+++ /dev/null
@@ -1 +0,0 @@
-../../../arch/h8300/boot/dts \ No newline at end of file
diff --git a/scripts/dtc/libfdt/Makefile.libfdt b/scripts/dtc/libfdt/Makefile.libfdt
deleted file mode 100644
index e54639738c8e..000000000000
--- a/scripts/dtc/libfdt/Makefile.libfdt
+++ /dev/null
@@ -1,18 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
-# Makefile.libfdt
-#
-# This is not a complete Makefile of itself. Instead, it is designed to
-# be easily embeddable into other systems of Makefiles.
-#
-LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1
-LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h
-LIBFDT_VERSION = version.lds
-LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c \
- fdt_addresses.c fdt_overlay.c
-LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
-LIBFDT_LIB = libfdt-$(DTC_VERSION).$(SHAREDLIB_EXT)
-
-libfdt_clean:
- @$(VECHO) CLEAN "(libfdt)"
- rm -f $(STD_CLEANFILES:%=$(LIBFDT_dir)/%)
- rm -f $(LIBFDT_dir)/$(LIBFDT_soname)
diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c
index d6ce7c052dc8..9fe7cf4b747d 100644
--- a/scripts/dtc/libfdt/fdt.c
+++ b/scripts/dtc/libfdt/fdt.c
@@ -19,15 +19,25 @@ 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_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
- return -FDT_ERR_BADVERSION;
- if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
- return -FDT_ERR_BADVERSION;
+ if (!can_assume(LATEST)) {
+ if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
+ return -FDT_ERR_BADVERSION;
+ if (fdt_last_comp_version(fdt) >
+ FDT_LAST_SUPPORTED_VERSION)
+ return -FDT_ERR_BADVERSION;
+ }
} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
/* Unfinished sequential-write blob */
- if (fdt_size_dt_struct(fdt) == 0)
+ if (!can_assume(VALID_INPUT) && fdt_size_dt_struct(fdt) == 0)
return -FDT_ERR_BADSTATE;
} else {
return -FDT_ERR_BADMAGIC;
@@ -70,58 +80,82 @@ size_t fdt_header_size_(uint32_t version)
return FDT_V17_SIZE;
}
+size_t fdt_header_size(const void *fdt)
+{
+ 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 (!can_assume(LATEST)) {
+ if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
+ || (fdt_last_comp_version(fdt) >
+ FDT_LAST_SUPPORTED_VERSION))
+ return -FDT_ERR_BADVERSION;
+ if (fdt_version(fdt) < fdt_last_comp_version(fdt))
+ return -FDT_ERR_BADVERSION;
+ }
hdrsize = fdt_header_size(fdt);
- if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
- || (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION))
- return -FDT_ERR_BADVERSION;
- if (fdt_version(fdt) < fdt_last_comp_version(fdt))
- return -FDT_ERR_BADVERSION;
-
- if ((fdt_totalsize(fdt) < hdrsize)
- || (fdt_totalsize(fdt) > INT_MAX))
- return -FDT_ERR_TRUNCATED;
+ if (!can_assume(VALID_DTB)) {
- /* Bounds check memrsv block */
- if (!check_off_(hdrsize, fdt_totalsize(fdt), fdt_off_mem_rsvmap(fdt)))
- return -FDT_ERR_TRUNCATED;
+ if ((fdt_totalsize(fdt) < hdrsize)
+ || (fdt_totalsize(fdt) > INT_MAX))
+ return -FDT_ERR_TRUNCATED;
- /* Bounds check structure block */
- if (fdt_version(fdt) < 17) {
+ /* Bounds check memrsv block */
if (!check_off_(hdrsize, fdt_totalsize(fdt),
- fdt_off_dt_struct(fdt)))
+ fdt_off_mem_rsvmap(fdt)))
return -FDT_ERR_TRUNCATED;
- } else {
+ }
+
+ if (!can_assume(VALID_DTB)) {
+ /* Bounds check structure block */
+ if (!can_assume(LATEST) && fdt_version(fdt) < 17) {
+ if (!check_off_(hdrsize, fdt_totalsize(fdt),
+ fdt_off_dt_struct(fdt)))
+ return -FDT_ERR_TRUNCATED;
+ } else {
+ if (!check_block_(hdrsize, fdt_totalsize(fdt),
+ fdt_off_dt_struct(fdt),
+ fdt_size_dt_struct(fdt)))
+ return -FDT_ERR_TRUNCATED;
+ }
+
+ /* Bounds check strings block */
if (!check_block_(hdrsize, fdt_totalsize(fdt),
- fdt_off_dt_struct(fdt),
- fdt_size_dt_struct(fdt)))
+ fdt_off_dt_strings(fdt),
+ fdt_size_dt_strings(fdt)))
return -FDT_ERR_TRUNCATED;
}
- /* Bounds check strings block */
- if (!check_block_(hdrsize, fdt_totalsize(fdt),
- fdt_off_dt_strings(fdt), fdt_size_dt_strings(fdt)))
- return -FDT_ERR_TRUNCATED;
-
return 0;
}
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
{
- unsigned absoffset = offset + fdt_off_dt_struct(fdt);
+ unsigned int uoffset = offset;
+ unsigned int absoffset = offset + fdt_off_dt_struct(fdt);
- if ((absoffset < offset)
- || ((absoffset + len) < absoffset)
- || (absoffset + len) > fdt_totalsize(fdt))
+ if (offset < 0)
return NULL;
- if (fdt_version(fdt) >= 0x11)
- if (((offset + len) < offset)
+ if (!can_assume(VALID_INPUT))
+ if ((absoffset < uoffset)
+ || ((absoffset + len) < absoffset)
+ || (absoffset + len) > fdt_totalsize(fdt))
+ return NULL;
+
+ if (can_assume(LATEST) || fdt_version(fdt) >= 0x11)
+ if (((uoffset + len) < uoffset)
|| ((offset + len) > fdt_size_dt_struct(fdt)))
return NULL;
@@ -137,7 +171,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
*nextoffset = -FDT_ERR_TRUNCATED;
tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
- if (!tagp)
+ if (!can_assume(VALID_DTB) && !tagp)
return FDT_END; /* premature end */
tag = fdt32_to_cpu(*tagp);
offset += FDT_TAGSIZE;
@@ -149,18 +183,19 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
do {
p = fdt_offset_ptr(fdt, offset++, 1);
} while (p && (*p != '\0'));
- if (!p)
+ if (!can_assume(VALID_DTB) && !p)
return FDT_END; /* premature end */
break;
case FDT_PROP:
lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
- if (!lenp)
+ if (!can_assume(VALID_DTB) && !lenp)
return FDT_END; /* premature end */
/* skip-name offset, length and value */
offset += sizeof(struct fdt_property) - FDT_TAGSIZE
+ fdt32_to_cpu(*lenp);
- if (fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 &&
+ if (!can_assume(LATEST) &&
+ fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 &&
((offset - fdt32_to_cpu(*lenp)) % 8) != 0)
offset += 4;
break;
@@ -183,8 +218,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;
@@ -192,8 +230,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;
@@ -281,9 +322,12 @@ const char *fdt_find_string_(const char *strtab, int tabsize, const char *s)
int fdt_move(const void *fdt, void *buf, int bufsize)
{
+ if (!can_assume(VALID_INPUT) && bufsize < 0)
+ return -FDT_ERR_NOSPACE;
+
FDT_RO_PROBE(fdt);
- if (fdt_totalsize(fdt) > bufsize)
+ if (fdt_totalsize(fdt) > (unsigned int)bufsize)
return -FDT_ERR_NOSPACE;
memmove(buf, fdt, fdt_totalsize(fdt));
diff --git a/scripts/dtc/libfdt/fdt.h b/scripts/dtc/libfdt/fdt.h
index f2e68807f277..0c91aa7f67b5 100644
--- a/scripts/dtc/libfdt/fdt.h
+++ b/scripts/dtc/libfdt/fdt.h
@@ -35,14 +35,14 @@ struct fdt_reserve_entry {
struct fdt_node_header {
fdt32_t tag;
- char name[0];
+ char name[];
};
struct fdt_property {
fdt32_t tag;
fdt32_t len;
fdt32_t nameoff;
- char data[0];
+ char data[];
};
#endif /* !__ASSEMBLY */
diff --git a/scripts/dtc/libfdt/fdt_overlay.c b/scripts/dtc/libfdt/fdt_overlay.c
index b310e49a698e..d217e79b6722 100644
--- a/scripts/dtc/libfdt/fdt_overlay.c
+++ b/scripts/dtc/libfdt/fdt_overlay.c
@@ -241,6 +241,7 @@ static int overlay_update_local_node_references(void *fdto,
if (fixup_len % sizeof(uint32_t))
return -FDT_ERR_BADOVERLAY;
+ fixup_len /= sizeof(uint32_t);
tree_val = fdt_getprop(fdto, tree_node, name, &tree_len);
if (!tree_val) {
@@ -250,7 +251,7 @@ static int overlay_update_local_node_references(void *fdto,
return tree_len;
}
- for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) {
+ for (i = 0; i < fixup_len; i++) {
fdt32_t adj_val;
uint32_t poffset;
diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c
index a5c2797cde65..17584da25760 100644
--- a/scripts/dtc/libfdt/fdt_ro.c
+++ b/scripts/dtc/libfdt/fdt_ro.c
@@ -33,36 +33,47 @@ static int fdt_nodename_eq_(const void *fdt, int offset,
const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
{
- int32_t totalsize = fdt_ro_probe_(fdt);
- uint32_t absoffset = stroffset + fdt_off_dt_strings(fdt);
+ int32_t totalsize;
+ uint32_t absoffset;
size_t len;
int err;
const char *s, *n;
+ if (can_assume(VALID_INPUT)) {
+ s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
+
+ if (lenp)
+ *lenp = strlen(s);
+ return s;
+ }
+ totalsize = fdt_ro_probe_(fdt);
err = totalsize;
if (totalsize < 0)
goto fail;
err = -FDT_ERR_BADOFFSET;
- if (absoffset >= totalsize)
+ absoffset = stroffset + fdt_off_dt_strings(fdt);
+ if (absoffset >= (unsigned)totalsize)
goto fail;
len = totalsize - absoffset;
if (fdt_magic(fdt) == FDT_MAGIC) {
if (stroffset < 0)
goto fail;
- if (fdt_version(fdt) >= 17) {
- if (stroffset >= fdt_size_dt_strings(fdt))
+ 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)
len = fdt_size_dt_strings(fdt) - stroffset;
}
} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
- if ((stroffset >= 0)
- || (stroffset < -fdt_size_dt_strings(fdt)))
+ unsigned int sw_stroffset = -stroffset;
+
+ if ((stroffset >= 0) ||
+ (sw_stroffset > fdt_size_dt_strings(fdt)))
goto fail;
- if ((-stroffset) < len)
- len = -stroffset;
+ if (sw_stroffset < len)
+ len = sw_stroffset;
} else {
err = -FDT_ERR_INTERNAL;
goto fail;
@@ -148,13 +159,16 @@ int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
{
- int offset = n * sizeof(struct fdt_reserve_entry);
- int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
+ unsigned int offset = n * sizeof(struct fdt_reserve_entry);
+ unsigned int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
- if (absoffset < fdt_off_mem_rsvmap(fdt))
- return NULL;
- if (absoffset > fdt_totalsize(fdt) - sizeof(struct fdt_reserve_entry))
- return NULL;
+ if (!can_assume(VALID_INPUT)) {
+ if (absoffset < fdt_off_mem_rsvmap(fdt))
+ return NULL;
+ if (absoffset > fdt_totalsize(fdt) -
+ sizeof(struct fdt_reserve_entry))
+ return NULL;
+ }
return fdt_mem_rsv_(fdt, n);
}
@@ -164,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 (!re)
+ if (!can_assume(VALID_INPUT) && !re)
return -FDT_ERR_BADOFFSET;
- *address = fdt64_ld(&re->address);
- *size = fdt64_ld(&re->size);
+ *address = fdt64_ld_(&re->address);
+ *size = fdt64_ld_(&re->size);
return 0;
}
@@ -178,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_ld(&re->size) == 0)
+ if (fdt64_ld_(&re->size) == 0)
return i;
}
return -FDT_ERR_TRUNCATED;
@@ -295,7 +309,7 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
nameptr = nh->name;
- if (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
@@ -346,7 +360,8 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
int err;
const struct fdt_property *prop;
- if ((err = fdt_check_prop_offset_(fdt, offset)) < 0) {
+ if (!can_assume(VALID_INPUT) &&
+ (err = fdt_check_prop_offset_(fdt, offset)) < 0) {
if (lenp)
*lenp = err;
return NULL;
@@ -355,7 +370,7 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
prop = fdt_offset_ptr_(fdt, offset);
if (lenp)
- *lenp = fdt32_ld(&prop->len);
+ *lenp = fdt32_ld_(&prop->len);
return prop;
}
@@ -367,7 +382,7 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
/* Prior to version 16, properties may need realignment
* and this API does not work. fdt_getprop_*() will, however. */
- if (fdt_version(fdt) < 0x10) {
+ if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
if (lenp)
*lenp = -FDT_ERR_BADVERSION;
return NULL;
@@ -388,11 +403,12 @@ static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
(offset = fdt_next_property_offset(fdt, offset))) {
const struct fdt_property *prop;
- if (!(prop = fdt_get_property_by_offset_(fdt, offset, lenp))) {
+ prop = fdt_get_property_by_offset_(fdt, offset, lenp);
+ if (!can_assume(LIBFDT_FLAWLESS) && !prop) {
offset = -FDT_ERR_INTERNAL;
break;
}
- if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff),
+ if (fdt_string_eq_(fdt, fdt32_ld_(&prop->nameoff),
name, namelen)) {
if (poffset)
*poffset = offset;
@@ -413,7 +429,7 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt,
{
/* Prior to version 16, properties may need realignment
* and this API does not work. fdt_getprop_*() will, however. */
- if (fdt_version(fdt) < 0x10) {
+ if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
if (lenp)
*lenp = -FDT_ERR_BADVERSION;
return NULL;
@@ -444,8 +460,8 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
return NULL;
/* Handle realignment */
- if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 &&
- fdt32_ld(&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;
}
@@ -461,19 +477,24 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
if (namep) {
const char *name;
int namelen;
- name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff),
- &namelen);
- if (!name) {
- if (lenp)
- *lenp = namelen;
- return NULL;
+
+ if (!can_assume(VALID_INPUT)) {
+ name = fdt_get_string(fdt, fdt32_ld_(&prop->nameoff),
+ &namelen);
+ if (!name) {
+ if (lenp)
+ *lenp = namelen;
+ return NULL;
+ }
+ *namep = name;
+ } else {
+ *namep = fdt_string(fdt, fdt32_ld_(&prop->nameoff));
}
- *namep = name;
}
/* Handle realignment */
- if (fdt_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 &&
- fdt32_ld(&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;
}
@@ -498,7 +519,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
return 0;
}
- return fdt32_ld(php);
+ return fdt32_ld_(php);
}
const char *fdt_get_alias_namelen(const void *fdt,
@@ -598,10 +619,12 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
}
}
- if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
- return -FDT_ERR_BADOFFSET;
- else if (offset == -FDT_ERR_BADOFFSET)
- return -FDT_ERR_BADSTRUCTURE;
+ if (!can_assume(VALID_INPUT)) {
+ if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+ return -FDT_ERR_BADOFFSET;
+ else if (offset == -FDT_ERR_BADOFFSET)
+ return -FDT_ERR_BADSTRUCTURE;
+ }
return offset; /* error from fdt_next_node() */
}
@@ -613,7 +636,8 @@ int fdt_node_depth(const void *fdt, int nodeoffset)
err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
if (err)
- return (err < 0) ? err : -FDT_ERR_INTERNAL;
+ return (can_assume(LIBFDT_FLAWLESS) || err < 0) ? err :
+ -FDT_ERR_INTERNAL;
return nodedepth;
}
@@ -658,7 +682,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
{
int offset;
- if ((phandle == 0) || (phandle == -1))
+ if ((phandle == 0) || (phandle == ~0U))
return -FDT_ERR_BADPHANDLE;
FDT_RO_PROBE(fdt);
@@ -833,66 +857,3 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
return offset; /* error from fdt_next_node() */
}
-
-int fdt_check_full(const void *fdt, size_t bufsize)
-{
- int err;
- int num_memrsv;
- int offset, nextoffset = 0;
- uint32_t tag;
- unsigned depth = 0;
- const void *prop;
- const char *propname;
-
- if (bufsize < FDT_V1_SIZE)
- return -FDT_ERR_TRUNCATED;
- err = fdt_check_header(fdt);
- if (err != 0)
- return err;
- if (bufsize < fdt_totalsize(fdt))
- return -FDT_ERR_TRUNCATED;
-
- num_memrsv = fdt_num_mem_rsv(fdt);
- if (num_memrsv < 0)
- return num_memrsv;
-
- while (1) {
- offset = nextoffset;
- tag = fdt_next_tag(fdt, offset, &nextoffset);
-
- if (nextoffset < 0)
- return nextoffset;
-
- switch (tag) {
- case FDT_NOP:
- break;
-
- case FDT_END:
- if (depth != 0)
- return -FDT_ERR_BADSTRUCTURE;
- return 0;
-
- case FDT_BEGIN_NODE:
- depth++;
- if (depth > INT_MAX)
- return -FDT_ERR_BADSTRUCTURE;
- break;
-
- case FDT_END_NODE:
- if (depth == 0)
- return -FDT_ERR_BADSTRUCTURE;
- depth--;
- break;
-
- case FDT_PROP:
- prop = fdt_getprop_by_offset(fdt, offset, &propname,
- &err);
- if (!prop)
- return err;
- break;
-
- default:
- return -FDT_ERR_INTERNAL;
- }
- }
-}
diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c
index 8795947c00dd..3621d3651d3f 100644
--- a/scripts/dtc/libfdt/fdt_rw.c
+++ b/scripts/dtc/libfdt/fdt_rw.c
@@ -24,14 +24,16 @@ static int fdt_blocks_misordered_(const void *fdt,
static int fdt_rw_probe_(void *fdt)
{
+ if (can_assume(VALID_DTB))
+ return 0;
FDT_RO_PROBE(fdt);
- if (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_version(fdt) > 17)
+ if (!can_assume(LATEST) && fdt_version(fdt) > 17)
fdt_set_version(fdt, 17);
return 0;
@@ -44,7 +46,7 @@ static int fdt_rw_probe_(void *fdt)
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);
}
@@ -52,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;
}
@@ -112,6 +115,15 @@ static int fdt_splice_string_(void *fdt, int newlen)
return 0;
}
+/**
+ * fdt_find_add_string_() - Find or allocate a string
+ *
+ * @fdt: pointer to the device tree to check/adjust
+ * @s: string to find/add
+ * @allocated: Set to 0 if the string was found, 1 if not found and so
+ * allocated. Ignored if 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)
{
char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
@@ -120,7 +132,8 @@ static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
int len = strlen(s) + 1;
int err;
- *allocated = 0;
+ if (!can_assume(NO_ROLLBACK))
+ *allocated = 0;
p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s);
if (p)
@@ -132,7 +145,8 @@ static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
if (err)
return err;
- *allocated = 1;
+ if (!can_assume(NO_ROLLBACK))
+ *allocated = 1;
memcpy(new, s, len);
return (new - strtab);
@@ -206,7 +220,8 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
err = fdt_splice_struct_(fdt, *prop, 0, proplen);
if (err) {
- if (allocated)
+ /* Delete the string if we failed to add it */
+ if (!can_assume(NO_ROLLBACK) && allocated)
fdt_del_last_string_(fdt, name);
return err;
}
@@ -334,7 +349,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);
@@ -376,7 +394,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;
@@ -391,8 +411,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));
}
@@ -411,17 +430,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_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)
@@ -449,7 +471,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);
@@ -469,7 +492,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 768db66eada5..d852b77e81e7 100644
--- a/scripts/dtc/libfdt/fdt_strerror.c
+++ b/scripts/dtc/libfdt/fdt_strerror.c
@@ -39,8 +39,9 @@ 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 (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
+#define FDT_ERRTABSIZE ((int)(sizeof(fdt_errtable) / sizeof(fdt_errtable[0])))
const char *fdt_strerror(int errval)
{
@@ -48,7 +49,7 @@ const char *fdt_strerror(int errval)
return "<valid offset/length>";
else if (errval == 0)
return "<no error>";
- else if (errval > -FDT_ERRTABSIZE) {
+ else if (-errval < FDT_ERRTABSIZE) {
const char *s = fdt_errtable[-errval].str;
if (s)
diff --git a/scripts/dtc/libfdt/fdt_sw.c b/scripts/dtc/libfdt/fdt_sw.c
index 76bea22f734f..4c569ee7eb0d 100644
--- a/scripts/dtc/libfdt/fdt_sw.c
+++ b/scripts/dtc/libfdt/fdt_sw.c
@@ -12,10 +12,13 @@
static int fdt_sw_probe_(void *fdt)
{
- if (fdt_magic(fdt) == FDT_MAGIC)
- return -FDT_ERR_BADSTATE;
- else if (fdt_magic(fdt) != FDT_SW_MAGIC)
- return -FDT_ERR_BADMAGIC;
+ if (!can_assume(VALID_INPUT)) {
+ if (fdt_magic(fdt) == FDT_MAGIC)
+ return -FDT_ERR_BADSTATE;
+ else if (fdt_magic(fdt) != FDT_SW_MAGIC)
+ return -FDT_ERR_BADMAGIC;
+ }
+
return 0;
}
@@ -29,7 +32,7 @@ static int fdt_sw_probe_(void *fdt)
/* '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)
@@ -38,7 +41,7 @@ static int fdt_sw_probe_memrsv_(void *fdt)
if (err)
return err;
- if (fdt_off_dt_strings(fdt) != 0)
+ if (!can_assume(VALID_INPUT) && fdt_off_dt_strings(fdt) != 0)
return -FDT_ERR_BADSTATE;
return 0;
}
@@ -64,7 +67,8 @@ static int fdt_sw_probe_struct_(void *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;
}
@@ -89,8 +93,8 @@ static inline uint32_t sw_flags(void *fdt)
static void *fdt_grab_space_(void *fdt, size_t len)
{
- int offset = fdt_size_dt_struct(fdt);
- int spaceleft;
+ unsigned int offset = fdt_size_dt_struct(fdt);
+ unsigned int spaceleft;
spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
- fdt_size_dt_strings(fdt);
@@ -104,8 +108,8 @@ static void *fdt_grab_space_(void *fdt, size_t len)
int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags)
{
- const size_t hdrsize = FDT_ALIGN(sizeof(struct fdt_header),
- sizeof(struct fdt_reserve_entry));
+ const int hdrsize = FDT_ALIGN(sizeof(struct fdt_header),
+ sizeof(struct fdt_reserve_entry));
void *fdt = buf;
if (bufsize < hdrsize)
@@ -148,13 +152,17 @@ int fdt_resize(void *fdt, void *buf, int bufsize)
FDT_SW_PROBE(fdt);
+ if (bufsize < 0)
+ return -FDT_ERR_NOSPACE;
+
headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
tailsize = fdt_size_dt_strings(fdt);
- if ((headsize + tailsize) > fdt_totalsize(fdt))
+ if (!can_assume(VALID_DTB) &&
+ headsize + tailsize > fdt_totalsize(fdt))
return -FDT_ERR_INTERNAL;
- if ((headsize + tailsize) > bufsize)
+ if ((headsize + tailsize) > (unsigned)bufsize)
return -FDT_ERR_NOSPACE;
oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize;
@@ -242,18 +250,18 @@ int fdt_end_node(void *fdt)
static int fdt_add_string_(void *fdt, const char *s)
{
char *strtab = (char *)fdt + fdt_totalsize(fdt);
- int strtabsize = fdt_size_dt_strings(fdt);
- int len = strlen(s) + 1;
- int struct_top, offset;
+ unsigned int strtabsize = fdt_size_dt_strings(fdt);
+ unsigned int len = strlen(s) + 1;
+ unsigned int struct_top, offset;
- offset = -strtabsize - len;
+ offset = strtabsize + len;
struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
- if (fdt_totalsize(fdt) + offset < struct_top)
+ if (fdt_totalsize(fdt) - offset < struct_top)
return 0; /* no more room :( */
- memcpy(strtab + offset, s, len);
+ memcpy(strtab - offset, s, len);
fdt_set_size_dt_strings(fdt, strtabsize + len);
- return offset;
+ return -offset;
}
/* Must only be used to roll back in case of error */
@@ -369,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/fdt_wip.c b/scripts/dtc/libfdt/fdt_wip.c
index f64139e0b3dc..c2d7566a67dc 100644
--- a/scripts/dtc/libfdt/fdt_wip.c
+++ b/scripts/dtc/libfdt/fdt_wip.c
@@ -23,7 +23,7 @@ int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
if (!propval)
return proplen;
- if (proplen < (len + idx))
+ if ((unsigned)proplen < (len + idx))
return -FDT_ERR_NOSPACE;
memcpy((char *)propval + idx, val, len);
diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h
index 8907b09b86cc..ce31e844856a 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
@@ -118,11 +127,16 @@ static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
/*
- * Alignment helpers:
- * These helpers access words from a device tree blob. They're
- * built to work even with unaligned pointers on platforms (ike
- * ARM) that don't like unaligned loads and stores
+ * 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)
{
@@ -180,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
+ *
+ * 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
+ * Return: offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more
+ * subnodes
*/
int fdt_next_subnode(const void *fdt, int offset);
@@ -221,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); \
@@ -265,16 +278,21 @@ fdt_set_hdr_(size_dt_struct);
/**
* 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 to get header size from a version number
+ * @version: devicetree version number
+ *
+ * Return: size of DTB header in bytes
*/
size_t fdt_header_size_(uint32_t version);
-static inline size_t fdt_header_size(const void *fdt)
-{
- return fdt_header_size_(fdt_version(fdt));
-}
/**
* 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
@@ -399,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);
@@ -420,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.
*
@@ -445,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,
@@ -484,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);
@@ -583,9 +606,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:
*
@@ -648,6 +671,9 @@ 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,
@@ -740,6 +766,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,
@@ -761,10 +789,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
@@ -809,8 +837,11 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset);
* @name: name of the alias th look up
* @namelen: number of characters of name to consider
*
- * Identical to fdt_get_alias(), but only examine the first namelen
- * 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,
@@ -823,7 +854,7 @@ const char *fdt_get_alias_namelen(const void *fdt,
* @name: name of the alias th 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
@@ -999,14 +1030,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:
@@ -1070,7 +1100,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);
@@ -1079,7 +1109,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
@@ -1099,7 +1130,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
@@ -1123,7 +1154,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
@@ -1212,6 +1243,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,
@@ -1325,8 +1358,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)
@@ -1398,7 +1436,7 @@ 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.
*
@@ -1416,7 +1454,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.
@@ -1481,7 +1519,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.
@@ -1686,8 +1725,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)
@@ -1858,8 +1903,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)
@@ -1962,13 +2013,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,
@@ -1987,7 +2041,7 @@ 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
@@ -2068,4 +2122,8 @@ int fdt_overlay_apply(void *fdt, void *fdto);
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 058c7358d441..16bda1906a7b 100644
--- a/scripts/dtc/libfdt/libfdt_internal.h
+++ b/scripts/dtc/libfdt/libfdt_internal.h
@@ -46,6 +46,147 @@ 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 tructural elements of the device tree
+ * blob (rather than for exaple 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)
+/**********************************************************************/
+/* Checking controls */
+/**********************************************************************/
+
+#ifndef FDT_ASSUME_MASK
+#define FDT_ASSUME_MASK 0
+#endif
+
+/*
+ * Defines assumptions which can be enabled. Each of these can be enabled
+ * individually. For maximum safety, don't enable any assumptions!
+ *
+ * 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
+ * ASSUME_SANE.
+ */
+enum {
+ /*
+ * This does essentially no checks. Only the latest device-tree
+ * 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
+ * where there is insufficient space may result in the property name
+ * being added to the string table even though the property itself is
+ * not added to the struct section.
+ *
+ * Only use this if you have a fully validated device tree with
+ * the latest supported version and wish to minimise code size.
+ */
+ ASSUME_PERFECT = 0xff,
+
+ /*
+ * This assumes that the device tree is sane. i.e. header metadata
+ * and basic hierarchy are correct.
+ *
+ * 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.
+ */
+ ASSUME_VALID_INPUT = 1 << 1,
+
+ /*
+ * This disables checks for device-tree version and removes all code
+ * which handles older versions.
+ *
+ * Only enable this if you know you have a device tree with the latest
+ * version.
+ */
+ ASSUME_LATEST = 1 << 2,
+
+ /*
+ * 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.
+ */
+ ASSUME_NO_ROLLBACK = 1 << 3,
+
+ /*
+ * 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,
+
+ /*
+ * 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,
+};
+
+/**
+ * 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 & 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 032df5878ccc..cc612370ec61 100644
--- a/scripts/dtc/livetree.c
+++ b/scripts/dtc/livetree.c
@@ -438,7 +438,7 @@ 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);
return fdt32_to_cpu(*((fdt32_t *)prop->val.val + n));
@@ -526,7 +526,7 @@ struct node *get_node_by_path(struct node *tree, const char *path)
p = strchr(path, '/');
for_each_child(tree, child) {
- if (p && 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;
@@ -559,7 +559,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;
}
@@ -594,7 +594,7 @@ cell_t get_node_phandle(struct node *root, struct node *node)
static cell_t phandle = 1; /* FIXME: ick, static local */
struct data d = empty_data;
- if ((node->phandle != 0) && (node->phandle != -1))
+ if (phandle_is_valid(node->phandle))
return node->phandle;
while (get_node_by_phandle(root, phandle))
diff --git a/scripts/dtc/of_unittest_expect b/scripts/dtc/of_unittest_expect
new file mode 100755
index 000000000000..96b12d9ea606
--- /dev/null
+++ b/scripts/dtc/of_unittest_expect
@@ -0,0 +1,408 @@
+#!/usr/bin/perl
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright 2020, 2022 Sony Corporation
+#
+# Author: Frank Rowand
+
+# This program is meant to be an aid to reading the verbose output of
+# on the console log that results from executing the Linux kernel
+# devicetree unittest (drivers/of/unitest.c).
+
+$VUFX = "220201a";
+
+use strict 'refs';
+use strict subs;
+
+use Getopt::Long;
+use Text::Wrap;
+
+# strip off everything before final "/"
+(undef, $script_name) = split(/^.*\//, $0);
+
+# following /usr/include/sysexits.h
+$EX_OK=0;
+$EX_USAGE=64;
+
+
+#______________________________________________________________________________
+sub compare {
+ my ($expect, $got) = @_;
+ my $expect_next;
+ my $expect_next_lit;
+ my $got_next;
+ my $type;
+
+ while ($expect) {
+
+ ($expect_next, $type) = split(/<</, $expect);
+ ($type) = split(/>>/, $type);
+ $expect =~ s/^.*?>>//; # '?' is non-greedy, minimal match
+
+ # literal, ignore all metacharacters when used in a regex
+ $expect_next_lit = quotemeta($expect_next);
+
+ $got_next = $got;
+ $got_next =~ s/^($expect_next_lit).*/\1/;
+ $got =~ s/^$expect_next_lit//;
+
+ if ($expect_next ne $got_next) {
+ return 0;
+ }
+
+ if ($type eq "int") {
+ if ($got =~ /^[+-]*[0-9]+/) {
+ $got =~ s/^[+-]*[0-9]+//;
+ } else {
+ return 0;
+ }
+ } elsif ($type eq "hex") {
+ if ($got =~ /^(0x)*[0-9a-f]+/) {
+ $got =~ s/^(0x)*[0-9a-f]+//;
+ } else {
+ return 0;
+ }
+ } elsif ($type eq "") {
+ if ($expect_next ne $got_next) {
+ return 0;
+ } else {
+ return 1;
+ }
+ } else {
+ $internal_err++;
+ print "** ERROR: special pattern not recognized: <<$type>>, CONSOLE_LOG line: $.\n";
+ return 0;
+ }
+
+ }
+
+ # should not get here
+ $internal_err++;
+ print "** ERROR: $script_name internal error, at end of compare(), CONSOLE_LOG line: $.\n";
+
+ return 0;
+}
+
+
+#______________________________________________________________________________
+sub usage {
+
+# ***** when editing, be careful to not put tabs in the string printed:
+
+ print STDERR
+"
+usage:
+
+ $script_name CONSOLE_LOG
+
+ -h print program usage
+ --help print program usage
+ --hide-expect suppress output of EXPECTed lines
+ --line-num report line number of CONSOLE_LOG
+ --no-expect-stats do not report EXPECT statistics
+ --no-strip-ts do not strip leading console timestamps
+ --verbose do not suppress EXPECT begin and end lines
+ --version print program version and exit
+
+
+ Process a console log for EXPECTed test related messages to either
+ highlight expected devicetree unittest related messages or suppress
+ the messages. Leading console timestamps will be stripped.
+
+ Various unittests may trigger kernel messages from outside the
+ unittest code. The unittest annotates that it expects the message
+ to occur with an 'EXPECT \\ : text' (begin) before triggering the
+ message, and an 'EXPECT / : text' (end) after triggering the message.
+
+ If an expected message does not occur, that will be reported.
+
+ For each expected message, the 'EXPECT \\ : text' (begin) and
+ 'EXPECT / : text' (end), 'text' will contain the message text.
+
+ If 'EXPECT \\' (begin) and 'EXPECT /' (end) lines do not contain
+ matching 'text', that will be reported.
+
+ If EXPECT lines are nested, 'EXPECT /' (end) lines must be in the
+ reverse order of the corresponding 'EXPECT \\' (begin) lines.
+
+ 'EXPECT \\ : text' (begin) and 'EXPECT / : text' (end) lines can
+ contain special patterns in 'text':
+
+ <<int>> matches: [+-]*[0-9]+
+ <<hex>> matches: (0x)*[0-9a-f]+
+
+ 'EXPECT \\' (begin) and 'EXPECT /' (end) lines are suppressed.
+
+ A prefix is added to every line of output:
+
+ 'ok ' Line matches an enclosing EXPECT begin/end pair
+
+ '** ' Line reports $script_name warning or error
+
+ '-> ' Line reports start or end of the unittests
+
+ '>> ' Line reports a unittest test FAIL
+
+ ' ' Lines that are not otherwise prefixed
+
+ Issues detected in CONSOLE_LOG are reported to STDOUT, not to STDERR.
+
+ Known Issues:
+
+ --line-num causes the CONSOLE_LOG line number to be printed in 4 columns.
+ If CONSOLE_LOG contains more than 9999 lines then more columns will be
+ used to report the line number for lines greater than 9999 (eg for
+ lines 10000 - 99999, 5 columns will be used).
+";
+
+ return {};
+}
+
+#______________________________________________________________________________
+#______________________________________________________________________________
+
+if (!GetOptions(
+ "h" => \$help,
+ "help" => \$help,
+ "hide-expect" => \$hide_expect,
+ "line-num" => \$print_line_num,
+ "no-expect-stats" => \$no_expect_stats,
+ "no-strip-ts" => \$no_strip_ts,
+ "verbose" => \$verbose,
+ "version" => \$version,
+ )) {
+ print STDERR "\n";
+ print STDERR "ERROR processing command line options\n";
+ print STDERR "\n";
+ print STDERR "For help, type '$script_name --help'\n";
+ print STDERR "\n";
+
+ exit $EX_OK;
+}
+
+
+if ($no_strip_ts) {
+ $strip_ts = 1;
+ $no_strip_ts = 0;
+} else {
+ $strip_ts = 0;
+ $no_strip_ts = 1;
+}
+
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+if ($help){
+
+ &usage;
+
+ exit $EX_OK;
+}
+
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+if ($version) {
+ print STDERR "\n$script_name $VUFX\n\n";
+ print STDERR "\n";
+
+ exit $EX_OK;
+}
+
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+if ($#ARGV != 0) {
+
+ # Limit input files to exactly one.
+ #
+ # 'while ($line = <ARGV>) {' in the code below supports multiple file
+ # names on the command line, but the EXPECT statistics are reported
+ # once for all input - it is not an expected use case to generate one
+ # set of statistics for multiple input files.
+
+ print STDERR "\n";
+ print STDERR "Required arguments: CONSOLE_LOG\n";
+ print STDERR "\n";
+
+ exit $EX_USAGE;
+}
+
+
+#______________________________________________________________________________
+
+# Patterns to match 'EXPECT \ : ' (begin) and 'EXPECT / : ' (end)
+#
+# $exp_* are used as regex match patterns,
+# so '\\\\' in $exp_begin matches a single '\'
+# quotemeta() does not do the right thing in this case
+#
+# $pr_fmt is the prefix that unittest prints for every message
+
+$pr_fmt = "### dt-test ### ";
+$exp_begin = "${pr_fmt}EXPECT \\\\ : ";
+$exp_end = "${pr_fmt}EXPECT / : ";
+
+
+$line_num = "";
+$timestamp = "";
+
+LINE:
+while ($line = <ARGV>) {
+
+ chomp $line;
+
+ $prefix = " "; ## 2 characters
+
+
+ if ($strip_ts) {
+
+ $timestamp = $line;
+
+ if ($timestamp =~ /^\[\s*[0-9]+\.[0-9]*\] /) {
+ ($timestamp, $null) = split(/]/, $line);
+ $timestamp = $timestamp . "] ";
+
+ } else {
+ $timestamp = "";
+ }
+ }
+
+ $line =~ s/^\[\s*[0-9]+\.[0-9]*\] //;
+
+
+ # ----- find EXPECT begin
+
+ if ($line =~ /^\s*$exp_begin/) {
+ $data = $line;
+ $data =~ s/^\s*$exp_begin//;
+ push @begin, $data;
+
+ if ($verbose) {
+ if ($print_line_num) {
+ $line_num = sprintf("%4s ", $.);
+ }
+ printf "%s %s%s%s\n", $prefix, $line_num, $timestamp, $line;
+ }
+
+ next LINE;
+ }
+
+
+ # ----- find EXPECT end
+
+ if ($line =~ /^\s*$exp_end/) {
+ $data = $line;
+ $data =~ s/^\s*$exp_end//;
+
+ if ($verbose) {
+ if ($print_line_num) {
+ $line_num = sprintf("%4s ", $.);
+ }
+ printf "%s %s%s%s\n", $prefix, $line_num, $timestamp, $line;
+ }
+
+ $found = 0;
+ $no_begin = 0;
+ if (@found_or_begin > 0) {
+ $begin = pop @found_or_begin;
+ if (compare($data, $begin)) {
+ $found = 1;
+ }
+ } elsif (@begin > 0) {
+ $begin = pop @begin;
+ } else {
+ $no_begin = 1;
+ }
+
+ if ($no_begin) {
+
+ $expect_missing_begin++;
+ print "** ERROR: EXPECT end without any EXPECT begin:\n";
+ print " end ---> $line\n";
+
+ } elsif (! $found) {
+
+ if ($print_line_num) {
+ $line_num = sprintf("%4s ", $.);
+ }
+
+ $expect_not_found++;
+ printf "** %s%s$script_name WARNING - not found ---> %s\n",
+ $line_num, $timestamp, $data;
+
+ } elsif (! compare($data, $begin)) {
+
+ $expect_missing_end++;
+ print "** ERROR: EXPECT end does not match EXPECT begin:\n";
+ print " begin -> $begin\n";
+ print " end ---> $line\n";
+
+ } else {
+
+ $expect_found++;
+
+ }
+
+ next LINE;
+ }
+
+
+ # ----- not an EXPECT line
+
+ if (($line =~ /^${pr_fmt}start of unittest - you will see error messages$/) ||
+ ($line =~ /^${pr_fmt}end of unittest - [0-9]+ passed, [0-9]+ failed$/ ) ) {
+ $prefix = "->"; # 2 characters
+ } elsif ($line =~ /^${pr_fmt}FAIL /) {
+ $unittest_fail++;
+ $prefix = ">>"; # 2 characters
+ }
+
+ $found = 0;
+ foreach $begin (@begin) {
+ if (compare($begin, $line)) {
+ $found = 1;
+ last;
+ }
+ }
+
+ if ($found) {
+ $begin = shift @begin;
+ while (! compare($begin, $line)) {
+ push @found_or_begin, $begin;
+ $begin = shift @begin;
+ }
+ push @found_or_begin, $line;
+
+ if ($hide_expect) {
+ $suppress_line = 1;
+ next LINE;
+ }
+ $prefix = "ok"; # 2 characters
+ }
+
+
+ if ($print_line_num) {
+ $line_num = sprintf("%4s ", $.);
+ }
+
+ printf "%s %s%s%s\n", $prefix, $line_num, $timestamp, $line;
+}
+
+if (! $no_expect_stats) {
+ print "\n";
+ print "** EXPECT statistics:\n";
+ print "**\n";
+ printf "** EXPECT found : %4i\n", $expect_found;
+ printf "** EXPECT not found : %4i\n", $expect_not_found;
+ printf "** missing EXPECT begin : %4i\n", $expect_missing_begin;
+ printf "** missing EXPECT end : %4i\n", $expect_missing_end;
+ printf "** unittest FAIL : %4i\n", $unittest_fail;
+ printf "** internal error : %4i\n", $internal_err;
+}
+
+if (@begin) {
+ print "** ERROR: EXPECT begin without any EXPECT end:\n";
+ print " This list may be misleading.\n";
+ foreach $begin (@begin) {
+ print " begin ---> $begin\n";
+ }
+}
diff --git a/scripts/dtc/srcpos.c b/scripts/dtc/srcpos.c
index f5205fb9c1ff..4fdb22a019bd 100644
--- a/scripts/dtc/srcpos.c
+++ b/scripts/dtc/srcpos.c
@@ -20,7 +20,7 @@ struct search_path {
static struct search_path *search_path_head, **search_path_tail;
/* Detect infinite include recursion. */
-#define MAX_SRCFILE_DEPTH (100)
+#define MAX_SRCFILE_DEPTH (200)
static int srcfile_depth; /* = 0 */
static char *get_dirname(const char *path)
diff --git a/scripts/dtc/treesource.c b/scripts/dtc/treesource.c
index c9d980c8abfc..33fedee82d58 100644
--- a/scripts/dtc/treesource.c
+++ b/scripts/dtc/treesource.c
@@ -110,13 +110,13 @@ static void write_propval_int(FILE *f, const char *p, size_t len, size_t width)
fprintf(f, "%02"PRIx8, *(const uint8_t*)p);
break;
case 2:
- fprintf(f, "0x%02"PRIx16, fdt16_to_cpu(*(const fdt16_t*)p));
+ fprintf(f, "0x%02"PRIx16, dtb_ld16(p));
break;
case 4:
- fprintf(f, "0x%02"PRIx32, fdt32_to_cpu(*(const fdt32_t*)p));
+ fprintf(f, "0x%02"PRIx32, dtb_ld32(p));
break;
case 8:
- fprintf(f, "0x%02"PRIx64, fdt64_to_cpu(*(const fdt64_t*)p));
+ fprintf(f, "0x%02"PRIx64, dtb_ld64(p));
break;
}
if (p + width < end)
@@ -124,27 +124,6 @@ static void write_propval_int(FILE *f, const char *p, size_t len, size_t width)
}
}
-static bool has_data_type_information(struct marker *m)
-{
- return m->type >= TYPE_UINT8;
-}
-
-static struct marker *next_type_marker(struct marker *m)
-{
- while (m && !has_data_type_information(m))
- m = m->next;
- return m;
-}
-
-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;
-}
-
static const char *delim_start[] = {
[TYPE_UINT8] = "[",
[TYPE_UINT16] = "/bits/ 16 <",
@@ -183,7 +162,7 @@ static enum markertype guess_value_type(struct property *prop)
nnotcelllbl++;
}
- if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul < (len-nnul))
+ if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul <= (len-nnul))
&& (nnotstringlbl == 0)) {
return TYPE_STRING;
} else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) {
@@ -229,26 +208,39 @@ static void write_propval(FILE *f, struct property *prop)
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 (has_data_type_information(m)) {
+ 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);
- else if (m->offset)
- fputc(' ', f);
- if (emit_type == TYPE_NONE) {
- assert(chunk_len == 0);
+ 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:
- write_propval_int(f, p, chunk_len, 4);
+ 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);
+ }
break;
case TYPE_UINT64:
write_propval_int(f, p, chunk_len, 8);
diff --git a/scripts/dtc/update-dtc-source.sh b/scripts/dtc/update-dtc-source.sh
index 7dd29a0362b8..94627541533e 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 yamltree.c Makefile.dtc \
+ srcpos.h treesource.c util.c util.h version_gen.h \
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.h b/scripts/dtc/util.h
index 5a4172dd0f84..c45b2c295aa5 100644
--- a/scripts/dtc/util.h
+++ b/scripts/dtc/util.h
@@ -2,6 +2,7 @@
#ifndef UTIL_H
#define UTIL_H
+#include <stdlib.h>
#include <stdarg.h>
#include <stdbool.h>
#include <getopt.h>
@@ -12,10 +13,10 @@
*/
#ifdef __GNUC__
-#ifdef __clang__
-#define PRINTF(i, j) __attribute__((format (printf, i, j)))
-#else
+#if __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
diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h
index 6dba95d23207..785cc4c57326 100644
--- a/scripts/dtc/version_gen.h
+++ b/scripts/dtc/version_gen.h
@@ -1 +1 @@
-#define DTC_VERSION "DTC 1.5.0-gc40aeb60"
+#define DTC_VERSION "DTC 1.6.1-g0a3a9d34"
diff --git a/scripts/dtc/yamltree.c b/scripts/dtc/yamltree.c
index 5b6ea8ea862f..55908c829c98 100644
--- a/scripts/dtc/yamltree.c
+++ b/scripts/dtc/yamltree.c
@@ -29,11 +29,12 @@ char *yaml_error_name[] = {
(emitter)->problem, __func__, __LINE__); \
})
-static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, char *data, int len, int width)
+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;
- int off, start_offset = markers->offset;
+ unsigned int off;
switch(width) {
case 1: tag = "!u8"; break;
@@ -59,21 +60,21 @@ static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, ch
sprintf(buf, "0x%"PRIx8, *(uint8_t*)(data + off));
break;
case 2:
- sprintf(buf, "0x%"PRIx16, fdt16_to_cpu(*(fdt16_t*)(data + off)));
+ sprintf(buf, "0x%"PRIx16, dtb_ld16(data + off));
break;
case 4:
- sprintf(buf, "0x%"PRIx32, fdt32_to_cpu(*(fdt32_t*)(data + off)));
+ sprintf(buf, "0x%"PRIx32, dtb_ld32(data + off));
m = markers;
is_phandle = false;
for_each_marker_of_type(m, REF_PHANDLE) {
- if (m->offset == (start_offset + off)) {
+ if (m->offset == (seq_offset + off)) {
is_phandle = true;
break;
}
}
break;
case 8:
- sprintf(buf, "0x%"PRIx64, fdt64_to_cpu(*(fdt64_t*)(data + off)));
+ sprintf(buf, "0x%"PRIx64, dtb_ld64(data + off));
break;
}
@@ -112,8 +113,9 @@ static void yaml_propval_string(yaml_emitter_t *emitter, char *str, int len)
static void yaml_propval(yaml_emitter_t *emitter, struct property *prop)
{
yaml_event_t event;
- int len = prop->val.len;
+ 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,
@@ -151,19 +153,19 @@ static void yaml_propval(yaml_emitter_t *emitter, struct property *prop)
switch(m->type) {
case TYPE_UINT16:
- yaml_propval_int(emitter, m, data, chunk_len, 2);
+ yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 2);
break;
case TYPE_UINT32:
- yaml_propval_int(emitter, m, data, chunk_len, 4);
+ yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 4);
break;
case TYPE_UINT64:
- yaml_propval_int(emitter, m, data, chunk_len, 8);
+ 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, m, data, chunk_len, 1);
+ yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 1);
break;
}
}