summaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorRob Herring <robh@kernel.org>2018-09-13 08:59:25 -0500
committerRob Herring <robh@kernel.org>2018-09-20 11:31:10 -0700
commitf858927fd6ce394a7f431153d44ad0a09e8f49a1 (patch)
tree6e6f1c2551a12796fedac46caa69a6dea69b25d1 /scripts
parentc36d5a6c74e7f1529f1af0cf39d3ecaa46c52e83 (diff)
scripts/dtc: Update to upstream version v1.4.7-14-gc86da84d30e4
Major changes are I2C and SPI bus checks, YAML output format (for future validation), some new libfdt functions, and more libfdt validation of dtbs. The YAML addition adds an optional dependency on libyaml. pkg-config is used to test for it and pkg-config became a kconfig dependency in 4.18. This adds the following commits from upstream: c86da84d30e4 Add support for YAML encoded output 361b5e7d8067 Make type_marker_length helper public bfbfab047e45 pylibfdt: Add a means to add and delete notes 9005f4108e7c pylibfdt: Allow delprop() to return errors b94c056b137e Make valgrind optional fd06c54d4711 tests: Better testing of dtc -I fs mode c3f50c9a86d9 tests: Allow dtbs_equal_unordered to ignore mem reserves 0ac9fdee37c7 dtc: trivial '-I fs -O dts' test 0fd1c8c783f3 pylibfdt: fdt_get_mem_rsv returns 2 uint64_t values 04853cad18f4 pylibfdt: Don't incorrectly / unnecessarily override uint64_t typemap 9619c8619c37 Kill bogus TYPE_BLOB marker type ac68ff92ae20 parser: add TYPE_STRING marker to path references 90a190eb04d9 checks: add SPI bus checks 53a1bd546905 checks: add I2C bus checks 88f18909db73 dtc: Bump version to v1.4.7 85bce8b2f06d tests: Correction to vg_prepare_blob() 57f7f9e7bc7c tests: Don't call memcmp() with NULL arguments c12b2b0c20eb libfdt: fdt_address_cells() and fdt_size_cells() 3fe0eeda0b7f livetree: Set phandle properties type to uint32 853649acceba pylibfdt: Support the sequential-write interface 9b0e4fe26093 tests: Improve fdt_resize() tests 1087504bb3e8 libfdt: Add necessary header padding in fdt_create() c72fa777e613 libfdt: Copy the struct region in fdt_resize() 32b9c6130762 Preserve datatype markers when emitting dts format 6dcb8ba408ec libfdt: Add helpers for accessing unaligned words 42607f21d43e tests: Fix incorrect check name 'prop_name_chars' 9d78c33bf8a1 tests: fix grep for checks error messages b770f3d1c13f pylibfdt: Support setting the name of a node 2f0d07e678e0 pylibfdt: Add functions to set and get properties as strings 354d3dc55939 pylibfdt: Update the bytearray size with pack() 3c374d46acce pylibfdt: Allow reading integer values from properties 49d32ce40bb4 pylibfdt: Use an unsigned type for fdt32_t 481246a0c13a pylibfdt: Avoid accessing the internal _fdt member in tests 9aafa33d99ed pylibfdt: Add functions to update properties 5a598671fdbf pylibfdt: Support device-tree creation/expansion 483e170625e1 pylibfdt: Add support for reading the memory reserve map 29bb05aa4200 pylibfdt: Add support for the rest of the header functions 582a7159a5d0 pylibfdt: Add support for fdt_next_node() f0f8c9169819 pylibfdt: Reorder functions to match libfdt.h 64a69d123935 pylibfdt: Return string instead of bytearray from getprop() 4d09a83420df fdtput: Add documentation e617cbe1bd67 fdtget: Add documentation 180a93924014 Use <inttypes.h> format specifiers in a bunch of places we should b9af3b396576 scripts/dtc: Fixed format mismatch in fprintf 4b8fcc3d015c libfdt: Add fdt_check_full() function c14223fb2292 tests: Use valgrind client requests for better checking 5b67d2b955a3 tests: Better handling of valgrind errors saving blobs e2556aaeb506 tests: Remove unused #define fb9c6abddaa8 Use size_t for blob lengths in utilfdt_read* 0112fda03bf6 libfdt: Add fdt_header_size() 6473a21d8bfe Consolidate utilfdt_read_len() variants d5db5382c5e5 libfdt: Safer access to memory reservations 719d582e98ec libfdt: Propagate name errors in fdt_getprop_by_offset() 70166d62a27f libfdt: Safer access to strings section eb890c0f77dc libfdt: Make fdt_check_header() more thorough 899d6fad93f3 libfdt: Improve sequential write state checking 04b5b4062ccd libfdt: Clean up header checking functions 44d3efedc816 Preserve datatype information when parsing dts f0be81bd8de0 Make Property a subclass of bytearray 24b1f3f064d4 pylibfdt: Add a method to access the device tree directly Signed-off-by: Rob Herring <robh@kernel.org>
Diffstat (limited to 'scripts')
-rw-r--r--scripts/dtc/Makefile7
-rw-r--r--scripts/dtc/Makefile.dtc4
-rw-r--r--scripts/dtc/checks.c143
-rw-r--r--scripts/dtc/data.c4
-rw-r--r--scripts/dtc/dtc-parser.y16
-rw-r--r--scripts/dtc/dtc.c11
-rw-r--r--scripts/dtc/dtc.h13
-rw-r--r--scripts/dtc/flattree.c2
-rw-r--r--scripts/dtc/libfdt/fdt.c81
-rw-r--r--scripts/dtc/libfdt/fdt_addresses.c35
-rw-r--r--scripts/dtc/libfdt/fdt_overlay.c6
-rw-r--r--scripts/dtc/libfdt/fdt_ro.c199
-rw-r--r--scripts/dtc/libfdt/fdt_rw.c28
-rw-r--r--scripts/dtc/libfdt/fdt_sw.c109
-rw-r--r--scripts/dtc/libfdt/libfdt.h76
-rw-r--r--scripts/dtc/libfdt/libfdt_env.h1
-rw-r--r--scripts/dtc/libfdt/libfdt_internal.h5
-rw-r--r--scripts/dtc/livetree.c12
-rw-r--r--scripts/dtc/treesource.c225
-rw-r--r--scripts/dtc/util.c23
-rw-r--r--scripts/dtc/util.h20
-rw-r--r--scripts/dtc/version_gen.h2
-rw-r--r--scripts/dtc/yamltree.c247
23 files changed, 1033 insertions, 236 deletions
diff --git a/scripts/dtc/Makefile b/scripts/dtc/Makefile
index 1c943e03eaf2..81c6f5132f12 100644
--- a/scripts/dtc/Makefile
+++ b/scripts/dtc/Makefile
@@ -11,6 +11,13 @@ 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$(src)/libfdt
+ifeq ($(wildcard /usr/include/yaml.h),)
+HOST_EXTRACFLAGS += -DNO_YAML
+else
+dtc-objs += yamltree.o
+HOSTLDLIBS_dtc := -lyaml
+endif
+
# Generated files need one more search path to include headers in source tree
HOSTCFLAGS_dtc-lexer.lex.o := -I$(src)
HOSTCFLAGS_dtc-parser.tab.o := -I$(src)
diff --git a/scripts/dtc/Makefile.dtc b/scripts/dtc/Makefile.dtc
index bece49b35535..d4375630a7f7 100644
--- a/scripts/dtc/Makefile.dtc
+++ b/scripts/dtc/Makefile.dtc
@@ -14,5 +14,9 @@ DTC_SRCS = \
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 a2cc1036c915..9c9b0c328af6 100644
--- a/scripts/dtc/checks.c
+++ b/scripts/dtc/checks.c
@@ -962,6 +962,143 @@ static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct no
}
WARNING(simple_bus_reg, check_simple_bus_reg, NULL, &reg_format, &simple_bus_bridge);
+static const struct bus_type i2c_bus = {
+ .name = "i2c-bus",
+};
+
+static void check_i2c_bus_bridge(struct check *c, struct dt_info *dti, struct node *node)
+{
+ if (strprefixeq(node->name, node->basenamelen, "i2c-bus") ||
+ strprefixeq(node->name, node->basenamelen, "i2c-arb")) {
+ node->bus = &i2c_bus;
+ } else if (strprefixeq(node->name, node->basenamelen, "i2c")) {
+ struct node *child;
+ for_each_child(node, child) {
+ if (strprefixeq(child->name, node->basenamelen, "i2c-bus"))
+ return;
+ }
+ node->bus = &i2c_bus;
+ } else
+ return;
+
+ if (!node->children)
+ return;
+
+ if (node_addr_cells(node) != 1)
+ FAIL(c, dti, node, "incorrect #address-cells for I2C bus");
+ if (node_size_cells(node) != 0)
+ FAIL(c, dti, node, "incorrect #size-cells for I2C bus");
+
+}
+WARNING(i2c_bus_bridge, check_i2c_bus_bridge, NULL, &addr_size_cells);
+
+static void check_i2c_bus_reg(struct check *c, struct dt_info *dti, struct node *node)
+{
+ struct property *prop;
+ const char *unitname = get_unitname(node);
+ char unit_addr[17];
+ uint32_t reg = 0;
+ int len;
+ cell_t *cells = NULL;
+
+ if (!node->parent || (node->parent->bus != &i2c_bus))
+ return;
+
+ prop = get_property(node, "reg");
+ if (prop)
+ cells = (cell_t *)prop->val.val;
+
+ if (!cells) {
+ FAIL(c, dti, node, "missing or empty reg property");
+ return;
+ }
+
+ reg = fdt32_to_cpu(*cells);
+ snprintf(unit_addr, sizeof(unit_addr), "%x", reg);
+ if (!streq(unitname, unit_addr))
+ FAIL(c, dti, node, "I2C bus unit address format error, expected \"%s\"",
+ unit_addr);
+
+ for (len = prop->val.len; len > 0; len -= 4) {
+ reg = fdt32_to_cpu(*(cells++));
+ if (reg > 0x3ff)
+ FAIL_PROP(c, dti, node, prop, "I2C address must be less than 10-bits, got \"0x%x\"",
+ reg);
+
+ }
+}
+WARNING(i2c_bus_reg, check_i2c_bus_reg, NULL, &reg_format, &i2c_bus_bridge);
+
+static const struct bus_type spi_bus = {
+ .name = "spi-bus",
+};
+
+static void check_spi_bus_bridge(struct check *c, struct dt_info *dti, struct node *node)
+{
+
+ if (strprefixeq(node->name, node->basenamelen, "spi")) {
+ node->bus = &spi_bus;
+ } else {
+ /* Try to detect SPI buses which don't have proper node name */
+ struct node *child;
+
+ if (node_addr_cells(node) != 1 || node_size_cells(node) != 0)
+ return;
+
+ for_each_child(node, child) {
+ struct property *prop;
+ for_each_property(child, prop) {
+ if (strprefixeq(prop->name, 4, "spi-")) {
+ node->bus = &spi_bus;
+ break;
+ }
+ }
+ if (node->bus == &spi_bus)
+ break;
+ }
+
+ if (node->bus == &spi_bus && get_property(node, "reg"))
+ FAIL(c, dti, node, "node name for SPI buses should be 'spi'");
+ }
+ if (node->bus != &spi_bus || !node->children)
+ return;
+
+ if (node_addr_cells(node) != 1)
+ FAIL(c, dti, node, "incorrect #address-cells for SPI bus");
+ if (node_size_cells(node) != 0)
+ FAIL(c, dti, node, "incorrect #size-cells for SPI bus");
+
+}
+WARNING(spi_bus_bridge, check_spi_bus_bridge, NULL, &addr_size_cells);
+
+static void check_spi_bus_reg(struct check *c, struct dt_info *dti, struct node *node)
+{
+ struct property *prop;
+ const char *unitname = get_unitname(node);
+ char unit_addr[9];
+ uint32_t reg = 0;
+ cell_t *cells = NULL;
+
+ if (!node->parent || (node->parent->bus != &spi_bus))
+ return;
+
+ prop = get_property(node, "reg");
+ if (prop)
+ cells = (cell_t *)prop->val.val;
+
+ if (!cells) {
+ FAIL(c, dti, node, "missing or empty reg property");
+ return;
+ }
+
+ reg = fdt32_to_cpu(*cells);
+ snprintf(unit_addr, sizeof(unit_addr), "%x", reg);
+ if (!streq(unitname, unit_addr))
+ FAIL(c, dti, node, "SPI bus unit address format error, expected \"%s\"",
+ unit_addr);
+}
+WARNING(spi_bus_reg, check_spi_bus_reg, NULL, &reg_format, &spi_bus_bridge);
+
static void check_unit_address_format(struct check *c, struct dt_info *dti,
struct node *node)
{
@@ -1582,6 +1719,12 @@ static struct check *check_table[] = {
&simple_bus_bridge,
&simple_bus_reg,
+ &i2c_bus_bridge,
+ &i2c_bus_reg,
+
+ &spi_bus_bridge,
+ &spi_bus_reg,
+
&avoid_default_addr_size,
&avoid_unnecessary_addr_size,
&unique_unit_address,
diff --git a/scripts/dtc/data.c b/scripts/dtc/data.c
index aa37a16c8891..4a204145cc7b 100644
--- a/scripts/dtc/data.c
+++ b/scripts/dtc/data.c
@@ -74,7 +74,8 @@ struct data data_copy_escape_string(const char *s, int len)
struct data d;
char *q;
- d = data_grow_for(empty_data, len + 1);
+ d = data_add_marker(empty_data, TYPE_STRING, NULL);
+ d = data_grow_for(d, len + 1);
q = d.val;
while (i < len) {
@@ -94,6 +95,7 @@ struct data data_copy_file(FILE *f, size_t maxlen)
{
struct data d = empty_data;
+ d = data_add_marker(d, TYPE_NONE, NULL);
while (!feof(f) && (d.len < maxlen)) {
size_t chunksize, ret;
diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y
index 011a5b25539a..dd70ebf386f4 100644
--- a/scripts/dtc/dtc-parser.y
+++ b/scripts/dtc/dtc-parser.y
@@ -287,6 +287,7 @@ propdata:
}
| propdataprefix DT_REF
{
+ $1 = data_add_marker($1, TYPE_STRING, $2);
$$ = data_add_marker($1, REF_PATH, $2);
}
| propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
@@ -340,22 +341,27 @@ arrayprefix:
DT_BITS DT_LITERAL '<'
{
unsigned long long bits;
+ enum markertype type = TYPE_UINT32;
bits = $2;
- if ((bits != 8) && (bits != 16) &&
- (bits != 32) && (bits != 64)) {
+ switch (bits) {
+ case 8: type = TYPE_UINT8; break;
+ case 16: type = TYPE_UINT16; break;
+ case 32: type = TYPE_UINT32; break;
+ case 64: type = TYPE_UINT64; break;
+ default:
ERROR(&@2, "Array elements must be"
" 8, 16, 32 or 64-bits");
bits = 32;
}
- $$.data = empty_data;
+ $$.data = data_add_marker(empty_data, type, NULL);
$$.bits = bits;
}
| '<'
{
- $$.data = empty_data;
+ $$.data = data_add_marker(empty_data, TYPE_UINT32, NULL);
$$.bits = 32;
}
| arrayprefix integer_prim
@@ -499,7 +505,7 @@ integer_unary:
bytestring:
/* empty */
{
- $$ = empty_data;
+ $$ = data_add_marker(empty_data, TYPE_UINT8, NULL);
}
| bytestring DT_BYTE
{
diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c
index c36994e6eac5..64134aadb997 100644
--- a/scripts/dtc/dtc.c
+++ b/scripts/dtc/dtc.c
@@ -95,6 +95,9 @@ static const char * const usage_opts_help[] = {
"\n\tOutput formats are:\n"
"\t\tdts - device tree source text\n"
"\t\tdtb - device tree blob\n"
+#ifndef NO_YAML
+ "\t\tyaml - device tree encoded as YAML\n"
+#endif
"\t\tasm - assembler source",
"\n\tBlob version to produce, defaults to "stringify(DEFAULT_FDT_VERSION)" (for dtb and asm output)",
"\n\tOutput dependency file",
@@ -128,6 +131,8 @@ static const char *guess_type_by_name(const char *fname, const char *fallback)
return fallback;
if (!strcasecmp(s, ".dts"))
return "dts";
+ if (!strcasecmp(s, ".yaml"))
+ return "yaml";
if (!strcasecmp(s, ".dtb"))
return "dtb";
return fallback;
@@ -350,6 +355,12 @@ int main(int argc, char *argv[])
if (streq(outform, "dts")) {
dt_to_source(outf, dti);
+#ifndef NO_YAML
+ } else if (streq(outform, "yaml")) {
+ if (!streq(inform, "dts"))
+ die("YAML output format requires dts input format\n");
+ dt_to_yaml(outf, dti);
+#endif
} else if (streq(outform, "dtb")) {
dt_to_blob(outf, dti, outversion);
} else if (streq(outform, "asm")) {
diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h
index 6d667701ab6a..cbe541525c2c 100644
--- a/scripts/dtc/dtc.h
+++ b/scripts/dtc/dtc.h
@@ -74,10 +74,17 @@ typedef uint32_t cell_t;
/* Data blobs */
enum markertype {
+ TYPE_NONE,
REF_PHANDLE,
REF_PATH,
LABEL,
+ TYPE_UINT8,
+ TYPE_UINT16,
+ TYPE_UINT32,
+ TYPE_UINT64,
+ TYPE_STRING,
};
+extern const char *markername(enum markertype markertype);
struct marker {
enum markertype type;
@@ -101,6 +108,8 @@ struct data {
for_each_marker(m) \
if ((m)->type == (t))
+size_t type_marker_length(struct marker *m);
+
void data_free(struct data d);
struct data data_grow_for(struct data d, int xlen);
@@ -290,6 +299,10 @@ struct dt_info *dt_from_blob(const char *fname);
void dt_to_source(FILE *f, struct dt_info *dti);
struct dt_info *dt_from_source(const char *f);
+/* YAML source */
+
+void dt_to_yaml(FILE *f, struct dt_info *dti);
+
/* FS trees */
struct dt_info *dt_from_fs(const char *dirname);
diff --git a/scripts/dtc/flattree.c b/scripts/dtc/flattree.c
index 8d268fb785db..851ea87dbc0f 100644
--- a/scripts/dtc/flattree.c
+++ b/scripts/dtc/flattree.c
@@ -393,7 +393,7 @@ void dt_to_blob(FILE *f, struct dt_info *dti, int version)
padlen = 0;
if (quiet < 1)
fprintf(stderr,
- "Warning: blob size %d >= minimum size %d\n",
+ "Warning: blob size %"PRIu32" >= minimum size %d\n",
fdt32_to_cpu(fdt.totalsize), minsize);
}
}
diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c
index 7855a1787763..ae03b1112961 100644
--- a/scripts/dtc/libfdt/fdt.c
+++ b/scripts/dtc/libfdt/fdt.c
@@ -55,7 +55,12 @@
#include "libfdt_internal.h"
-int fdt_check_header(const void *fdt)
+/*
+ * Minimal sanity check for a read-only tree. fdt_ro_probe_() checks
+ * that the given buffer contains what appears to be a flattened
+ * device tree with sane information in its header.
+ */
+int fdt_ro_probe_(const void *fdt)
{
if (fdt_magic(fdt) == FDT_MAGIC) {
/* Complete tree */
@@ -74,6 +79,78 @@ int fdt_check_header(const void *fdt)
return 0;
}
+static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off)
+{
+ return (off >= hdrsize) && (off <= totalsize);
+}
+
+static int check_block_(uint32_t hdrsize, uint32_t totalsize,
+ uint32_t base, uint32_t size)
+{
+ if (!check_off_(hdrsize, totalsize, base))
+ return 0; /* block start out of bounds */
+ if ((base + size) < base)
+ return 0; /* overflow */
+ if (!check_off_(hdrsize, totalsize, base + size))
+ return 0; /* block end out of bounds */
+ return 1;
+}
+
+size_t fdt_header_size_(uint32_t version)
+{
+ if (version <= 1)
+ return FDT_V1_SIZE;
+ else if (version <= 2)
+ return FDT_V2_SIZE;
+ else if (version <= 3)
+ return FDT_V3_SIZE;
+ else if (version <= 16)
+ return FDT_V16_SIZE;
+ else
+ return FDT_V17_SIZE;
+}
+
+int fdt_check_header(const void *fdt)
+{
+ size_t hdrsize;
+
+ if (fdt_magic(fdt) != FDT_MAGIC)
+ return -FDT_ERR_BADMAGIC;
+ 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;
+
+ /* Bounds check memrsv block */
+ if (!check_off_(hdrsize, fdt_totalsize(fdt), fdt_off_mem_rsvmap(fdt)))
+ return -FDT_ERR_TRUNCATED;
+
+ /* Bounds check structure block */
+ if (fdt_version(fdt) < 17) {
+ if (!check_off_(hdrsize, fdt_totalsize(fdt),
+ fdt_off_dt_struct(fdt)))
+ return -FDT_ERR_TRUNCATED;
+ } else {
+ if (!check_block_(hdrsize, fdt_totalsize(fdt),
+ fdt_off_dt_struct(fdt),
+ fdt_size_dt_struct(fdt)))
+ return -FDT_ERR_TRUNCATED;
+ }
+
+ /* Bounds check strings block */
+ if (!check_block_(hdrsize, fdt_totalsize(fdt),
+ fdt_off_dt_strings(fdt), fdt_size_dt_strings(fdt)))
+ return -FDT_ERR_TRUNCATED;
+
+ return 0;
+}
+
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
{
unsigned absoffset = offset + fdt_off_dt_struct(fdt);
@@ -244,7 +321,7 @@ const char *fdt_find_string_(const char *strtab, int tabsize, const char *s)
int fdt_move(const void *fdt, void *buf, int bufsize)
{
- FDT_CHECK_HEADER(fdt);
+ FDT_RO_PROBE(fdt);
if (fdt_totalsize(fdt) > bufsize)
return -FDT_ERR_NOSPACE;
diff --git a/scripts/dtc/libfdt/fdt_addresses.c b/scripts/dtc/libfdt/fdt_addresses.c
index eff4dbcc729d..49537b578d03 100644
--- a/scripts/dtc/libfdt/fdt_addresses.c
+++ b/scripts/dtc/libfdt/fdt_addresses.c
@@ -1,6 +1,7 @@
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au>
+ * Copyright (C) 2018 embedded brains GmbH
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
@@ -55,42 +56,32 @@
#include "libfdt_internal.h"
-int fdt_address_cells(const void *fdt, int nodeoffset)
+static int fdt_cells(const void *fdt, int nodeoffset, const char *name)
{
- const fdt32_t *ac;
+ const fdt32_t *c;
int val;
int len;
- ac = fdt_getprop(fdt, nodeoffset, "#address-cells", &len);
- if (!ac)
+ c = fdt_getprop(fdt, nodeoffset, name, &len);
+ if (!c)
return 2;
- if (len != sizeof(*ac))
+ if (len != sizeof(*c))
return -FDT_ERR_BADNCELLS;
- val = fdt32_to_cpu(*ac);
+ val = fdt32_to_cpu(*c);
if ((val <= 0) || (val > FDT_MAX_NCELLS))
return -FDT_ERR_BADNCELLS;
return val;
}
-int fdt_size_cells(const void *fdt, int nodeoffset)
+int fdt_address_cells(const void *fdt, int nodeoffset)
{
- const fdt32_t *sc;
- int val;
- int len;
-
- sc = fdt_getprop(fdt, nodeoffset, "#size-cells", &len);
- if (!sc)
- return 2;
-
- if (len != sizeof(*sc))
- return -FDT_ERR_BADNCELLS;
-
- val = fdt32_to_cpu(*sc);
- if ((val < 0) || (val > FDT_MAX_NCELLS))
- return -FDT_ERR_BADNCELLS;
+ return fdt_cells(fdt, nodeoffset, "#address-cells");
+}
- return val;
+int fdt_size_cells(const void *fdt, int nodeoffset)
+{
+ return fdt_cells(fdt, nodeoffset, "#size-cells");
}
diff --git a/scripts/dtc/libfdt/fdt_overlay.c b/scripts/dtc/libfdt/fdt_overlay.c
index bf75388ec9a2..5fdab6c6371d 100644
--- a/scripts/dtc/libfdt/fdt_overlay.c
+++ b/scripts/dtc/libfdt/fdt_overlay.c
@@ -697,7 +697,7 @@ static int get_path_len(const void *fdt, int nodeoffset)
int len = 0, namelen;
const char *name;
- FDT_CHECK_HEADER(fdt);
+ FDT_RO_PROBE(fdt);
for (;;) {
name = fdt_get_name(fdt, nodeoffset, &namelen);
@@ -866,8 +866,8 @@ int fdt_overlay_apply(void *fdt, void *fdto)
uint32_t delta = fdt_get_max_phandle(fdt);
int ret;
- FDT_CHECK_HEADER(fdt);
- FDT_CHECK_HEADER(fdto);
+ FDT_RO_PROBE(fdt);
+ FDT_RO_PROBE(fdto);
ret = overlay_adjust_local_phandles(fdto, delta);
if (ret)
diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c
index dfb3236da388..eafc14282892 100644
--- a/scripts/dtc/libfdt/fdt_ro.c
+++ b/scripts/dtc/libfdt/fdt_ro.c
@@ -76,17 +76,72 @@ static int fdt_nodename_eq_(const void *fdt, int offset,
return 0;
}
+const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
+{
+ uint32_t absoffset = stroffset + fdt_off_dt_strings(fdt);
+ size_t len;
+ int err;
+ const char *s, *n;
+
+ err = fdt_ro_probe_(fdt);
+ if (err != 0)
+ goto fail;
+
+ err = -FDT_ERR_BADOFFSET;
+ if (absoffset >= fdt_totalsize(fdt))
+ goto fail;
+ len = fdt_totalsize(fdt) - absoffset;
+
+ if (fdt_magic(fdt) == FDT_MAGIC) {
+ if (stroffset < 0)
+ goto fail;
+ if (fdt_version(fdt) >= 17) {
+ if (stroffset >= fdt_size_dt_strings(fdt))
+ goto fail;
+ if ((fdt_size_dt_strings(fdt) - stroffset) < len)
+ len = fdt_size_dt_strings(fdt) - stroffset;
+ }
+ } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
+ if ((stroffset >= 0)
+ || (stroffset < -fdt_size_dt_strings(fdt)))
+ goto fail;
+ if ((-stroffset) < len)
+ len = -stroffset;
+ } else {
+ err = -FDT_ERR_INTERNAL;
+ goto fail;
+ }
+
+ s = (const char *)fdt + absoffset;
+ n = memchr(s, '\0', len);
+ if (!n) {
+ /* missing terminating NULL */
+ err = -FDT_ERR_TRUNCATED;
+ goto fail;
+ }
+
+ if (lenp)
+ *lenp = n - s;
+ return s;
+
+fail:
+ if (lenp)
+ *lenp = err;
+ return NULL;
+}
+
const char *fdt_string(const void *fdt, int stroffset)
{
- return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
+ return fdt_get_string(fdt, stroffset, NULL);
}
static int fdt_string_eq_(const void *fdt, int stroffset,
const char *s, int len)
{
- const char *p = fdt_string(fdt, stroffset);
+ int slen;
+ const char *p = fdt_get_string(fdt, stroffset, &slen);
- return (strlen(p) == len) && (memcmp(p, s, len) == 0);
+ return p && (slen == len) && (memcmp(p, s, len) == 0);
}
uint32_t fdt_get_max_phandle(const void *fdt)
@@ -115,21 +170,42 @@ uint32_t fdt_get_max_phandle(const void *fdt)
return 0;
}
+static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
+{
+ int offset = n * sizeof(struct fdt_reserve_entry);
+ int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
+
+ if (absoffset < fdt_off_mem_rsvmap(fdt))
+ return NULL;
+ if (absoffset > fdt_totalsize(fdt) - sizeof(struct fdt_reserve_entry))
+ return NULL;
+ return fdt_mem_rsv_(fdt, n);
+}
+
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
{
- FDT_CHECK_HEADER(fdt);
- *address = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->address);
- *size = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->size);
+ const struct fdt_reserve_entry *re;
+
+ FDT_RO_PROBE(fdt);
+ re = fdt_mem_rsv(fdt, n);
+ if (!re)
+ return -FDT_ERR_BADOFFSET;
+
+ *address = fdt64_ld(&re->address);
+ *size = fdt64_ld(&re->size);
return 0;
}
int fdt_num_mem_rsv(const void *fdt)
{
- int i = 0;
+ int i;
+ const struct fdt_reserve_entry *re;
- while (fdt64_to_cpu(fdt_mem_rsv_(fdt, i)->size) != 0)
- i++;
- return i;
+ for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
+ if (fdt64_ld(&re->size) == 0)
+ return i;
+ }
+ return -FDT_ERR_TRUNCATED;
}
static int nextprop_(const void *fdt, int offset)
@@ -161,7 +237,7 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset,
{
int depth;
- FDT_CHECK_HEADER(fdt);
+ FDT_RO_PROBE(fdt);
for (depth = 0;
(offset >= 0) && (depth >= 0);
@@ -187,7 +263,7 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
const char *p = path;
int offset = 0;
- FDT_CHECK_HEADER(fdt);
+ FDT_RO_PROBE(fdt);
/* see if we have an alias */
if (*path != '/') {
@@ -237,7 +313,7 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
const char *nameptr;
int err;
- if (((err = fdt_check_header(fdt)) != 0)
+ if (((err = fdt_ro_probe_(fdt)) != 0)
|| ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
goto fail;
@@ -303,7 +379,7 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
prop = fdt_offset_ptr_(fdt, offset);
if (lenp)
- *lenp = fdt32_to_cpu(prop->len);
+ *lenp = fdt32_ld(&prop->len);
return prop;
}
@@ -340,7 +416,7 @@ static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
offset = -FDT_ERR_INTERNAL;
break;
}
- if (fdt_string_eq_(fdt, fdt32_to_cpu(prop->nameoff),
+ if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff),
name, namelen)) {
if (poffset)
*poffset = offset;
@@ -393,7 +469,7 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
/* Handle realignment */
if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 &&
- fdt32_to_cpu(prop->len) >= 8)
+ fdt32_ld(&prop->len) >= 8)
return prop->data + 4;
return prop->data;
}
@@ -406,12 +482,22 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
prop = fdt_get_property_by_offset_(fdt, offset, lenp);
if (!prop)
return NULL;
- if (namep)
- *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+ if (namep) {
+ const char *name;
+ int namelen;
+ name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff),
+ &namelen);
+ if (!name) {
+ if (lenp)
+ *lenp = namelen;
+ return NULL;
+ }
+ *namep = name;
+ }
/* Handle realignment */
if (fdt_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 &&
- fdt32_to_cpu(prop->len) >= 8)
+ fdt32_ld(&prop->len) >= 8)
return prop->data + 4;
return prop->data;
}
@@ -436,7 +522,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
return 0;
}
- return fdt32_to_cpu(*php);
+ return fdt32_ld(php);
}
const char *fdt_get_alias_namelen(const void *fdt,
@@ -462,7 +548,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
int offset, depth, namelen;
const char *name;
- FDT_CHECK_HEADER(fdt);
+ FDT_RO_PROBE(fdt);
if (buflen < 2)
return -FDT_ERR_NOSPACE;
@@ -514,7 +600,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
int offset, depth;
int supernodeoffset = -FDT_ERR_INTERNAL;
- FDT_CHECK_HEADER(fdt);
+ FDT_RO_PROBE(fdt);
if (supernodedepth < 0)
return -FDT_ERR_NOTFOUND;
@@ -573,7 +659,7 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
const void *val;
int len;
- FDT_CHECK_HEADER(fdt);
+ FDT_RO_PROBE(fdt);
/* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_getprop(), then if that didn't
@@ -599,7 +685,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
if ((phandle == 0) || (phandle == -1))
return -FDT_ERR_BADPHANDLE;
- FDT_CHECK_HEADER(fdt);
+ FDT_RO_PROBE(fdt);
/* FIXME: The algorithm here is pretty horrible: we
* potentially scan each property of a node in
@@ -752,7 +838,7 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
{
int offset, err;
- FDT_CHECK_HEADER(fdt);
+ FDT_RO_PROBE(fdt);
/* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_node_check_compatible(), then if
@@ -771,3 +857,66 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
re