aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSzuWei Lin <szuweilin@google.com>2017-11-09 15:04:16 +0800
committerSzuWei Lin <szuweilin@google.com>2017-11-09 15:04:16 +0800
commita058df1cffd5fb5d24cad1555841ec1e6fbd3104 (patch)
tree2e477e1e127ed0e920282e66ec7dfd729be3f1cf
parent3281c3abb9f0d29d1ef11b0b2994f5f440c346d6 (diff)
parent0016f8c2aa32423f680ec6e94a00f1095b81b5fc (diff)
downloaddtc-a058df1cffd5fb5d24cad1555841ec1e6fbd3104.tar.gz
Update dtc to the version of 20170713 of upstreamandroid-o-mr1-iot-preview-6o-mr1-iot-preview-6
For pylibfdt, merge dtc to upstream 0016f8c2aa32423f680ec6e94a00f1095b81b5fc and merge history Bug: 64424046 Test: Build dtc, use output dtc to build dts, can output correct dtb. Change-Id: I4304259e1245bc4a45d0b8f8e3ae8119e509042c
-rw-r--r--.travis.yml25
-rw-r--r--Documentation/manual.txt20
-rw-r--r--Makefile70
-rw-r--r--Makefile.utils6
-rw-r--r--README66
-rw-r--r--checks.c231
-rw-r--r--dtc.c2
-rw-r--r--dtc.h6
-rw-r--r--fdtdump.c7
-rw-r--r--fdtoverlay.c168
-rw-r--r--libfdt/fdt_empty_tree.c1
-rw-r--r--libfdt/fdt_ro.c4
-rw-r--r--libfdt/fdt_rw.c4
-rw-r--r--libfdt/fdt_sw.c16
-rw-r--r--libfdt/fdt_wip.c4
-rw-r--r--libfdt/libfdt.h37
-rw-r--r--livetree.c3
-rw-r--r--pylibfdt/.gitignore3
-rw-r--r--pylibfdt/Makefile.pylibfdt24
-rw-r--r--pylibfdt/libfdt.i433
-rwxr-xr-xpylibfdt/setup.py121
-rw-r--r--tests/Makefile.tests6
-rw-r--r--tests/fdtoverlay-runtest.sh40
-rw-r--r--tests/include7.dts1
-rw-r--r--tests/path-references.c12
-rw-r--r--tests/path-references.dts13
-rw-r--r--tests/pylibfdt_tests.py288
-rwxr-xr-xtests/run_tests.sh61
-rw-r--r--tests/sw_tree1.c5
-rw-r--r--tests/test_tree1.dts1
-rw-r--r--tests/test_tree1_label_noderef.dts1
-rw-r--r--tests/tests.sh1
-rw-r--r--tests/trees.S2
-rw-r--r--tests/unit-addr-leading-0s.dts12
-rw-r--r--tests/unit-addr-leading-0x.dts12
35 files changed, 1677 insertions, 29 deletions
diff --git a/.travis.yml b/.travis.yml
index f2336d8..a07c989 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,30 @@
language: c
+# Coverity Scan uploads
+env:
+ global:
+ # COVERITY_SCAN_TOKEN (dgibson/dtc)
+ - secure: "vlHvXe618//IM9LQaKzqsrUbjs7ng0L9UCST4kJbJnFQDXvVe5JiSmJGd4ef7mm0NUv5bMRl2W3xCiu6BYAu/NvU3tMNHoLG+JgCJs0+wLJXbWOwji/NmH7olqgJG+CmpaCMXjARF6+nrTnBYHJL6cYyf4KVoV4B0I/hLUW91+s="
+
+matrix:
+ include:
+ - addons:
+ apt:
+ packages:
+ - swig
+ - python-dev
+ coverity_scan:
+ project:
+ name: dtc
+ description: Device Tree Compiler
+ notification_email: david@gibson.dropbear.id.au
+ build_command: make
+ branch_pattern: coverity_scan
+
+ - addons:
+ apt:
+ packages:
+
script:
- make
- make check
diff --git a/Documentation/manual.txt b/Documentation/manual.txt
index 2f07350..72403ac 100644
--- a/Documentation/manual.txt
+++ b/Documentation/manual.txt
@@ -674,4 +674,22 @@ The fdtdump program prints a readable version of a flat device tree file.
The syntax of the fdtdump command line is:
- fdtdump <DTB-file-name>
+ fdtdump [options] <DTB-file-name>
+
+Where options are:
+ -d,--debug Dump debug information while decoding the file
+ -s,--scan Scan for an embedded fdt in given file
+
+3) fdtoverlay -- Flat Device Tree overlay applicator
+
+The fdtoverlay applies an arbitrary number of FDT overlays to a base FDT blob
+to a given output file.
+
+The syntax of the fdtoverlay command line is:
+
+ fdtoverlay -i <base-blob> -o <output-blob> <overlay-blob0> [<overlay-blob1> ...]
+
+Where options are:
+ -i, --input Input base DT blob
+ -o, --output Output DT blob
+ -v, --verbose Verbose message output
diff --git a/Makefile b/Makefile
index c3f72e0..fe482b9 100644
--- a/Makefile
+++ b/Makefile
@@ -18,10 +18,12 @@ CONFIG_LOCALVERSION =
CPPFLAGS = -I libfdt -I .
WARNINGS = -Wall -Wpointer-arith -Wcast-qual -Wnested-externs \
-Wstrict-prototypes -Wmissing-prototypes -Wredundant-decls -Wshadow
-CFLAGS = -g -Os -fPIC -Werror $(WARNINGS)
+CFLAGS = -g -Os $(SHAREDLIB_CFLAGS) -Werror $(WARNINGS)
BISON = bison
LEX = flex
+SWIG = swig
+PKG_CONFIG ?= pkg-config
INSTALL = /usr/bin/install
DESTDIR =
@@ -31,14 +33,20 @@ LIBDIR = $(PREFIX)/lib
INCLUDEDIR = $(PREFIX)/include
HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
- sed -e 's/\(cygwin\).*/cygwin/')
+ sed -e 's/\(cygwin\|msys\).*/\1/')
ifeq ($(HOSTOS),darwin)
-SHAREDLIB_EXT=dylib
-SHAREDLIB_LINK_OPTIONS=-dynamiclib -Wl,-install_name -Wl,
+SHAREDLIB_EXT = dylib
+SHAREDLIB_CFLAGS = -fPIC
+SHAREDLIB_LDFLAGS = -fPIC -dynamiclib -Wl,-install_name -Wl,
+else ifeq ($(HOSTOS),$(filter $(HOSTOS),msys cygwin))
+SHAREDLIB_EXT = so
+SHAREDLIB_CFLAGS =
+SHAREDLIB_LDFLAGS = -shared -Wl,--version-script=$(LIBFDT_version) -Wl,-soname,
else
-SHAREDLIB_EXT=so
-SHAREDLIB_LINK_OPTIONS=-shared -Wl,--version-script=$(LIBFDT_version) -Wl,-soname,
+SHAREDLIB_EXT = so
+SHAREDLIB_CFLAGS = -fPIC
+SHAREDLIB_LDFLAGS = -fPIC -shared -Wl,--version-script=$(LIBFDT_version) -Wl,-soname,
endif
#
@@ -112,11 +120,30 @@ BIN += dtc
BIN += fdtdump
BIN += fdtget
BIN += fdtput
+BIN += fdtoverlay
SCRIPTS = dtdiff
all: $(BIN) libfdt
+# We need both Python and swig to build pylibfdt.
+.PHONY: maybe_pylibfdt
+maybe_pylibfdt: FORCE
+ if $(PKG_CONFIG) --cflags python >/dev/null 2>&1; then \
+ if which swig >/dev/null 2>&1; then \
+ can_build=yes; \
+ fi; \
+ fi; \
+ if [ "$$can_build" = "yes" ]; then \
+ $(MAKE) pylibfdt; \
+ else \
+ echo "## Skipping pylibfdt (install python dev and swig to build)"; \
+ fi
+
+ifeq ($(NO_PYTHON),)
+all: maybe_pylibfdt
+endif
+
ifneq ($(DEPTARGETS),)
-include $(DTC_OBJS:%.o=%.d)
@@ -124,6 +151,7 @@ ifneq ($(DEPTARGETS),)
-include $(FDTDUMP_OBJS:%.o=%.d)
-include $(FDTGET_OBJS:%.o=%.d)
-include $(FDTPUT_OBJS:%.o=%.d)
+-include $(FDTOVERLAY_OBJS:%.o=%.d)
endif
@@ -180,6 +208,10 @@ install-includes:
install: install-bin install-lib install-includes
+ifeq ($(NO_PYTHON),)
+install: install_pylibfdt
+endif
+
$(VERSION_FILE): Makefile FORCE
$(call filechk,version)
@@ -196,12 +228,30 @@ fdtget: $(FDTGET_OBJS) $(LIBFDT_archive)
fdtput: $(FDTPUT_OBJS) $(LIBFDT_archive)
+fdtoverlay: $(FDTOVERLAY_OBJS) $(LIBFDT_archive)
+
dist:
git archive --format=tar --prefix=dtc-$(dtc_version)/ HEAD \
> ../dtc-$(dtc_version).tar
cat ../dtc-$(dtc_version).tar | \
gzip -9 > ../dtc-$(dtc_version).tar.gz
+
+#
+# Rules for pylibfdt
+#
+PYLIBFDT_srcdir = pylibfdt
+PYLIBFDT_objdir = pylibfdt
+
+include $(PYLIBFDT_srcdir)/Makefile.pylibfdt
+
+.PHONY: pylibfdt
+pylibfdt: $(PYLIBFDT_objdir)/_libfdt.so
+
+pylibfdt_clean:
+ @$(VECHO) CLEAN "(pylibfdt)"
+ rm -f $(addprefix $(PYLIBFDT_objdir)/,$(PYLIBFDT_cleanfiles))
+
#
# Release signing and uploading
# This is for maintainer convenience, don't try this at home.
@@ -234,6 +284,10 @@ TESTS_BIN += convert-dtsv0
TESTS_BIN += fdtput
TESTS_BIN += fdtget
TESTS_BIN += fdtdump
+TESTS_BIN += fdtoverlay
+ifeq ($(NO_PYTHON),)
+TESTS_PYLIBFDT += maybe_pylibfdt
+endif
include tests/Makefile.tests
@@ -243,7 +297,7 @@ include tests/Makefile.tests
STD_CLEANFILES = *~ *.o *.$(SHAREDLIB_EXT) *.d *.a *.i *.s core a.out vgcore.* \
*.tab.[ch] *.lex.c *.output
-clean: libfdt_clean tests_clean
+clean: libfdt_clean pylibfdt_clean tests_clean
@$(VECHO) CLEAN
rm -f $(STD_CLEANFILES)
rm -f $(VERSION_FILE)
@@ -287,7 +341,7 @@ clean: libfdt_clean tests_clean
$(LIBFDT_lib):
@$(VECHO) LD $@
- $(CC) $(LDFLAGS) -fPIC $(SHAREDLIB_LINK_OPTIONS)$(LIBFDT_soname) -o $(LIBFDT_lib) $^
+ $(CC) $(LDFLAGS) $(SHAREDLIB_LDFLAGS)$(LIBFDT_soname) -o $(LIBFDT_lib) $^
%.lex.c: %.l
@$(VECHO) LEX $@
diff --git a/Makefile.utils b/Makefile.utils
index 48ece49..e028922 100644
--- a/Makefile.utils
+++ b/Makefile.utils
@@ -22,3 +22,9 @@ FDTPUT_SRCS = \
util.c
FDTPUT_OBJS = $(FDTPUT_SRCS:%.c=%.o)
+
+FDTOVERLAY_SRCS = \
+ fdtoverlay.c \
+ util.c
+
+FDTOVERLAY_OBJS = $(FDTOVERLAY_SRCS:%.c=%.o)
diff --git a/README b/README
index f92008f..17dc845 100644
--- a/README
+++ b/README
@@ -7,6 +7,72 @@ DTC and LIBFDT are maintained by:
David Gibson <david@gibson.dropbear.id.au>
Jon Loeliger <jdl@jdl.com>
+
+Python library
+--------------
+
+A Python library is also available. To build this you will need to install
+swig and Python development files. On Debian distributions:
+
+ sudo apt-get install swig python-dev
+
+The library provides an Fdt class which you can use like this:
+
+$ PYTHONPATH=../pylibfdt python
+>>> import libfdt
+>>> fdt = libfdt.Fdt(open('test_tree1.dtb').read())
+>>> node = fdt.path_offset('/subnode@1')
+>>> print node
+124
+>>> prop_offset = fdt.first_property_offset(node)
+>>> prop = fdt.get_property_by_offset(prop_offset)
+>>> print '%s=%r' % (prop.name, prop.value)
+compatible=bytearray(b'subnode1\x00')
+>>> print '%s=%s' % (prop.name, prop.value)
+compatible=subnode1
+>>> node2 = fdt.path_offset('/')
+>>> print fdt.getprop(node2, 'compatible')
+test_tree1
+
+You will find tests in tests/pylibfdt_tests.py showing how to use each
+method. Help is available using the Python help command, e.g.:
+
+ $ cd pylibfdt
+ $ python -c "import libfdt; help(libfdt)"
+
+If you add new features, please check code coverage:
+
+ $ sudo apt-get install python-pip python-pytest
+ $ sudo pip install coverage
+ $ cd tests
+ $ coverage run pylibfdt_tests.py
+ $ coverage html
+ # Open 'htmlcov/index.html' in your browser
+
+
+To install the library via the normal setup.py method, use:
+
+ ./pylibfdt/setup.py [--prefix=/path/to/install_dir]
+
+If --prefix is not provided, the default prefix is used, typically '/usr'
+or '/usr/local'. See Python's distutils documentation for details. You can
+also install via the Makefile if you like, but the above is more common.
+
+To install both libfdt and pylibfdt you can use:
+
+ make install [SETUP_PREFIX=/path/to/install_dir] \
+ [PREFIX=/path/to/install_dir]
+
+To disable building the python library, even if swig and Python are available,
+use:
+
+ make NO_PYTHON=1
+
+
+More work remains to support all of libfdt, including access to numeric
+values.
+
+
Mailing list
------------
The following list is for discussion about dtc and libfdt implementation
diff --git a/checks.c b/checks.c
index 38f548e..afabf64 100644
--- a/checks.c
+++ b/checks.c
@@ -681,6 +681,229 @@ static void check_ranges_format(struct check *c, struct dt_info *dti,
}
WARNING(ranges_format, check_ranges_format, NULL, &addr_size_cells);
+static const struct bus_type pci_bus = {
+ .name = "PCI",
+};
+
+static void check_pci_bridge(struct check *c, struct dt_info *dti, struct node *node)
+{
+ struct property *prop;
+ cell_t *cells;
+
+ prop = get_property(node, "device_type");
+ if (!prop || !streq(prop->val.val, "pci"))
+ return;
+
+ node->bus = &pci_bus;
+
+ if (!strneq(node->name, "pci", node->basenamelen) &&
+ !strneq(node->name, "pcie", node->basenamelen))
+ FAIL(c, dti, "Node %s node name is not \"pci\" or \"pcie\"",
+ node->fullpath);
+
+ prop = get_property(node, "ranges");
+ if (!prop)
+ FAIL(c, dti, "Node %s missing ranges for PCI bridge (or not a bridge)",
+ node->fullpath);
+
+ if (node_addr_cells(node) != 3)
+ FAIL(c, dti, "Node %s incorrect #address-cells for PCI bridge",
+ node->fullpath);
+ if (node_size_cells(node) != 2)
+ FAIL(c, dti, "Node %s incorrect #size-cells for PCI bridge",
+ node->fullpath);
+
+ prop = get_property(node, "bus-range");
+ if (!prop) {
+ FAIL(c, dti, "Node %s missing bus-range for PCI bridge",
+ node->fullpath);
+ return;
+ }
+ if (prop->val.len != (sizeof(cell_t) * 2)) {
+ FAIL(c, dti, "Node %s bus-range must be 2 cells",
+ node->fullpath);
+ return;
+ }
+ cells = (cell_t *)prop->val.val;
+ if (fdt32_to_cpu(cells[0]) > fdt32_to_cpu(cells[1]))
+ FAIL(c, dti, "Node %s bus-range 1st cell must be less than or equal to 2nd cell",
+ node->fullpath);
+ if (fdt32_to_cpu(cells[1]) > 0xff)
+ FAIL(c, dti, "Node %s bus-range maximum bus number must be less than 256",
+ node->fullpath);
+}
+WARNING(pci_bridge, check_pci_bridge, NULL,
+ &device_type_is_string, &addr_size_cells);
+
+static void check_pci_device_bus_num(struct check *c, struct dt_info *dti, struct node *node)
+{
+ struct property *prop;
+ unsigned int bus_num, min_bus, max_bus;
+ cell_t *cells;
+
+ if (!node->parent || (node->parent->bus != &pci_bus))
+ return;
+
+ prop = get_property(node, "reg");
+ if (!prop)
+ return;
+
+ cells = (cell_t *)prop->val.val;
+ bus_num = (fdt32_to_cpu(cells[0]) & 0x00ff0000) >> 16;
+
+ prop = get_property(node->parent, "bus-range");
+ if (!prop) {
+ min_bus = max_bus = 0;
+ } else {
+ cells = (cell_t *)prop->val.val;
+ min_bus = fdt32_to_cpu(cells[0]);
+ max_bus = fdt32_to_cpu(cells[0]);
+ }
+ if ((bus_num < min_bus) || (bus_num > max_bus))
+ FAIL(c, dti, "Node %s PCI bus number %d out of range, expected (%d - %d)",
+ node->fullpath, bus_num, min_bus, max_bus);
+}
+WARNING(pci_device_bus_num, check_pci_device_bus_num, NULL, &reg_format, &pci_bridge);
+
+static void check_pci_device_reg(struct check *c, struct dt_info *dti, struct node *node)
+{
+ struct property *prop;
+ const char *unitname = get_unitname(node);
+ char unit_addr[5];
+ unsigned int dev, func, reg;
+ cell_t *cells;
+
+ if (!node->parent || (node->parent->bus != &pci_bus))
+ return;
+
+ prop = get_property(node, "reg");
+ if (!prop) {
+ FAIL(c, dti, "Node %s missing PCI reg property", node->fullpath);
+ return;
+ }
+
+ cells = (cell_t *)prop->val.val;
+ if (cells[1] || cells[2])
+ FAIL(c, dti, "Node %s PCI reg config space address cells 2 and 3 must be 0",
+ node->fullpath);
+
+ reg = fdt32_to_cpu(cells[0]);
+ dev = (reg & 0xf800) >> 11;
+ func = (reg & 0x700) >> 8;
+
+ if (reg & 0xff000000)
+ FAIL(c, dti, "Node %s PCI reg address is not configuration space",
+ node->fullpath);
+ if (reg & 0x000000ff)
+ FAIL(c, dti, "Node %s PCI reg config space address register number must be 0",
+ node->fullpath);
+
+ if (func == 0) {
+ snprintf(unit_addr, sizeof(unit_addr), "%x", dev);
+ if (streq(unitname, unit_addr))
+ return;
+ }
+
+ snprintf(unit_addr, sizeof(unit_addr), "%x,%x", dev, func);
+ if (streq(unitname, unit_addr))
+ return;
+
+ FAIL(c, dti, "Node %s PCI unit address format error, expected \"%s\"",
+ node->fullpath, unit_addr);
+}
+WARNING(pci_device_reg, check_pci_device_reg, NULL, &reg_format, &pci_bridge);
+
+static const struct bus_type simple_bus = {
+ .name = "simple-bus",
+};
+
+static bool node_is_compatible(struct node *node, const char *compat)
+{
+ struct property *prop;
+ const char *str, *end;
+
+ prop = get_property(node, "compatible");
+ if (!prop)
+ return false;
+
+ for (str = prop->val.val, end = str + prop->val.len; str < end;
+ str += strnlen(str, end - str) + 1) {
+ if (strneq(str, compat, end - str))
+ return true;
+ }
+ return false;
+}
+
+static void check_simple_bus_bridge(struct check *c, struct dt_info *dti, struct node *node)
+{
+ if (node_is_compatible(node, "simple-bus"))
+ node->bus = &simple_bus;
+}
+WARNING(simple_bus_bridge, check_simple_bus_bridge, NULL, &addr_size_cells);
+
+static void check_simple_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];
+ unsigned int size;
+ uint64_t reg = 0;
+ cell_t *cells = NULL;
+
+ if (!node->parent || (node->parent->bus != &simple_bus))
+ return;
+
+ prop = get_property(node, "reg");
+ if (prop)
+ cells = (cell_t *)prop->val.val;
+ else {
+ prop = get_property(node, "ranges");
+ if (prop && prop->val.len)
+ /* skip of child address */
+ cells = ((cell_t *)prop->val.val) + node_addr_cells(node);
+ }
+
+ if (!cells) {
+ if (node->parent->parent && !(node->bus == &simple_bus))
+ FAIL(c, dti, "Node %s missing or empty reg/ranges property", node->fullpath);
+ return;
+ }
+
+ size = node_addr_cells(node->parent);
+ while (size--)
+ reg = (reg << 32) | fdt32_to_cpu(*(cells++));
+
+ snprintf(unit_addr, sizeof(unit_addr), "%"PRIx64, reg);
+ if (!streq(unitname, unit_addr))
+ FAIL(c, dti, "Node %s simple-bus unit address format error, expected \"%s\"",
+ node->fullpath, unit_addr);
+}
+WARNING(simple_bus_reg, check_simple_bus_reg, NULL, &reg_format, &simple_bus_bridge);
+
+static void check_unit_address_format(struct check *c, struct dt_info *dti,
+ struct node *node)
+{
+ const char *unitname = get_unitname(node);
+
+ if (node->parent && node->parent->bus)
+ return;
+
+ if (!unitname[0])
+ return;
+
+ if (!strncmp(unitname, "0x", 2)) {
+ FAIL(c, dti, "Node %s unit name should not have leading \"0x\"",
+ node->fullpath);
+ /* skip over 0x for next test */
+ unitname += 2;
+ }
+ if (unitname[0] == '0' && isxdigit(unitname[1]))
+ FAIL(c, dti, "Node %s unit name should not have leading 0s",
+ node->fullpath);
+}
+WARNING(unit_address_format, check_unit_address_format, NULL,
+ &node_name_format, &pci_bridge, &simple_bus_bridge);
+
/*
* Style checks
*/
@@ -752,6 +975,14 @@ static struct check *check_table[] = {
&addr_size_cells, &reg_format, &ranges_format,
&unit_address_vs_reg,
+ &unit_address_format,
+
+ &pci_bridge,
+ &pci_device_reg,
+ &pci_device_bus_num,
+
+ &simple_bus_bridge,
+ &simple_bus_reg,
&avoid_default_addr_size,
&obsolete_chosen_interrupt_controller,
diff --git a/dtc.c b/dtc.c
index f5eed9d..5ed873c 100644
--- a/dtc.c
+++ b/dtc.c
@@ -31,7 +31,7 @@ int reservenum; /* Number of memory reservation slots */
int minsize; /* Minimum blob size */
int padsize; /* Additional padding to blob */
int alignsize; /* Additional padding to blob accroding to the alignsize */
-int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */
+int phandle_format = PHANDLE_EPAPR; /* Use linux,phandle or phandle properties */
int generate_symbols; /* enable symbols & fixup support */
int generate_fixups; /* suppress generation of fixups on symbol support */
int auto_label_aliases; /* auto generate labels -> aliases */
diff --git a/dtc.h b/dtc.h
index e031a5a..07e3ddb 100644
--- a/dtc.h
+++ b/dtc.h
@@ -31,6 +31,7 @@
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
+#include <inttypes.h>
#include <libfdt_env.h>
#include <fdt.h>
@@ -135,6 +136,10 @@ struct label {
struct label *next;
};
+struct bus_type {
+ const char *name;
+};
+
struct property {
bool deleted;
char *name;
@@ -161,6 +166,7 @@ struct node {
int addr_cells, size_cells;
struct label *labels;
+ const struct bus_type *bus;
};
#define for_each_label_withdel(l0, l) \
diff --git a/fdtdump.c b/fdtdump.c
index 4eaade9..fa3b561 100644
--- a/fdtdump.c
+++ b/fdtdump.c
@@ -165,7 +165,7 @@ static bool valid_header(char *p, off_t len)
if (len < sizeof(struct fdt_header) ||
fdt_magic(p) != FDT_MAGIC ||
fdt_version(p) > MAX_VERSION ||
- fdt_last_comp_version(p) >= MAX_VERSION ||
+ fdt_last_comp_version(p) > MAX_VERSION ||
fdt_totalsize(p) >= len ||
fdt_off_dt_struct(p) >= len ||
fdt_off_dt_strings(p) >= len)
@@ -183,6 +183,11 @@ int main(int argc, char *argv[])
bool scan = false;
off_t len;
+ fprintf(stderr, "\n"
+"**** fdtdump is a low-level debugging tool, not meant for general use.\n"
+"**** If you want to decompile a dtb, you probably want\n"
+"**** dtc -I dtb -O dts <filename>\n\n"
+ );
while ((opt = util_getopt_long()) != EOF) {
switch (opt) {
case_USAGE_COMMON_FLAGS
diff --git a/fdtoverlay.c b/fdtoverlay.c
new file mode 100644
index 0000000..9c5618c
--- /dev/null
+++ b/fdtoverlay.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2017 Konsulko Group Inc. All rights reserved.
+ *
+ * Author:
+ * Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <alloca.h>
+
+#include <libfdt.h>
+
+#include "util.h"
+
+/* 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 int do_fdtoverlay(const char *input_filename,
+ const char *output_filename,
+ int argc, char *argv[])
+{
+ char *blob = NULL;
+ char **ovblob = NULL;
+ off_t blob_len, ov_len, total_len;
+ int i, ret = -1;
+
+ blob = utilfdt_read_len(input_filename, &blob_len);
+ if (!blob) {
+ fprintf(stderr, "\nFailed to read base blob %s\n",
+ input_filename);
+ goto out_err;
+ }
+ ret = 0;
+
+ /* allocate blob pointer array */
+ ovblob = alloca(sizeof(*ovblob) * argc);
+ memset(ovblob, 0, sizeof(*ovblob) * argc);
+
+ /* read and keep track of the overlay blobs */
+ total_len = 0;
+ for (i = 0; i < argc; i++) {
+ ovblob[i] = utilfdt_read_len(argv[i], &ov_len);
+ if (!ovblob[i]) {
+ fprintf(stderr, "\nFailed to read overlay %s\n",
+ argv[i]);
+ goto out_err;
+ }
+ total_len += ov_len;
+ }
+
+ /* grow the blob to worst case */
+ blob_len = fdt_totalsize(blob) + total_len;
+ blob = xrealloc(blob, blob_len);
+ fdt_open_into(blob, blob, blob_len);
+
+ /* apply the overlays in sequence */
+ for (i = 0; i < argc; i++) {
+ ret = fdt_overlay_apply(blob, ovblob[i]);
+ if (ret) {
+ fprintf(stderr, "\nFailed to apply %s (%d)\n",
+ argv[i], ret);
+ goto out_err;
+ }
+ }
+
+ fdt_pack(blob);
+ ret = utilfdt_write(output_filename, blob);
+ if (ret)
+ fprintf(stderr, "\nFailed to write output blob %s\n",
+ output_filename);
+
+out_err:
+ if (ovblob) {
+ for (i = 0; i < argc; i++) {
+ if (ovblob[i])
+ free(ovblob[i]);
+ }
+ }
+ 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/libfdt/fdt_empty_tree.c b/libfdt/fdt_empty_tree.c
index f72d13b..f2ae9b7 100644
--- a/libfdt/fdt_empty_tree.c
+++ b/libfdt/fdt_empty_tree.c
@@ -81,4 +81,3 @@ int fdt_create_empty_tree(void *buf, int bufsize)
return fdt_open_into(buf, buf, bufsize);
}
-
diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c
index 3d00d2e..08de2cc 100644
--- a/libfdt/fdt_ro.c
+++ b/libfdt/fdt_ro.c
@@ -60,7 +60,7 @@ static int _fdt_nodename_eq(const void *fdt, int offset,
{
const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
- if (! p)
+ if (!p)
/* short match */
return 0;
@@ -327,7 +327,7 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
const struct fdt_property *prop;
prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
- if (! prop)
+ if (!prop)
return NULL;
return prop->data;
diff --git a/libfdt/fdt_rw.c b/libfdt/fdt_rw.c
index 3fd5847..8b487f6 100644
--- a/libfdt/fdt_rw.c
+++ b/libfdt/fdt_rw.c
@@ -207,7 +207,7 @@ static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
int err;
*prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
- if (! (*prop))
+ if (!*prop)
return oldlen;
if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
@@ -323,7 +323,7 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name)
FDT_RW_CHECK_HEADER(fdt);
prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
- if (! prop)
+ if (!prop)
return len;
proplen = sizeof(*prop) + FDT_TAGALIGN(len);
diff --git a/libfdt/fdt_sw.c b/libfdt/fdt_sw.c
index 6a80485..2bd15e7 100644
--- a/libfdt/fdt_sw.c
+++ b/libfdt/fdt_sw.c
@@ -220,7 +220,7 @@ static int _fdt_find_add_string(void *fdt, const char *s)
return offset;
}
-int fdt_property(void *fdt, const char *name, const void *val, int len)
+int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)
{
struct fdt_property *prop;
int nameoff;
@@ -238,7 +238,19 @@ int fdt_property(void *fdt, const char *name, const void *val, int len)
prop->tag = cpu_to_fdt32(FDT_PROP);
prop->nameoff = cpu_to_fdt32(nameoff);
prop->len = cpu_to_fdt32(len);
- memcpy(prop->data, val, len);
+ *valp = prop->data;
+ return 0;
+}
+
+int fdt_property(void *fdt, const char *name, const void *val, int len)
+{
+ void *ptr;
+ int ret;
+
+ ret = fdt_property_placeholder(fdt, name, len, &ptr);
+ if (ret)
+ return ret;
+ memcpy(ptr, val, len);
return 0;
}
diff --git a/libfdt/fdt_wip.c b/libfdt/fdt_wip.c
index 6aaab39..5e85919 100644
--- a/libfdt/fdt_wip.c
+++ b/libfdt/fdt_wip.c
@@ -82,7 +82,7 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
int proplen;
propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
- if (! propval)
+ if (!propval)
return proplen;
if (proplen != len)
@@ -107,7 +107,7 @@ int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
int len;
prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
- if (! prop)
+ if (!prop)
return len;
_fdt_nop_region(prop, len + sizeof(*prop));
diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h
index ac42e04..a248b1b 100644
--- a/libfdt/libfdt.h
+++ b/libfdt/libfdt.h
@@ -143,7 +143,9 @@
/* Low-level functions (you probably don't need these) */
/**********************************************************************/
+#ifndef SWIG /* This function is not useful in Python */
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen);
+#endif
static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
{
return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen);
@@ -210,7 +212,6 @@ int fdt_next_subnode(const void *fdt, int offset);
/**********************************************************************/
/* General functions */
/**********************************************************************/
-
#define fdt_get_header(fdt, field) \
(fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
#define fdt_magic(fdt) (fdt_get_header(fdt, magic))
@@ -354,8 +355,10 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size);
* useful for finding subnodes based on a portion of a larger string,
* such as a full path.
*/
+#ifndef SWIG /* Not available in Python */
int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
const char *name, int namelen);
+#endif
/**
* fdt_subnode_offset - find a subnode of a given node
* @fdt: pointer to the device tree blob
@@ -391,7 +394,9 @@ 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.
*/
+#ifndef SWIG /* Not available in Python */
int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen);
+#endif
/**
* fdt_path_offset - find a tree node by its full path
@@ -550,10 +555,12 @@ 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.
*/
+#ifndef SWIG /* Not available in Python */
const struct fdt_property *fdt_get_property_namelen(const void *fdt,
int nodeoffset,
const char *name,
int namelen, int *lenp);
+#endif
/**
* fdt_get_property - find a given property in a given node
@@ -624,8 +631,10 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_TRUNCATED, standard meanings
*/
+#ifndef SWIG /* This function is not useful in Python */
const void *fdt_getprop_by_offset(const void *fdt, int offset,
const char **namep, int *lenp);
+#endif
/**
* fdt_getprop_namelen - get property value based on substring
@@ -638,6 +647,7 @@ 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.
*/
+#ifndef SWIG /* Not available in Python */
const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
const char *name, int namelen, int *lenp);
static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset,
@@ -647,6 +657,7 @@ static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset,
return (void *)(uintptr_t)fdt_getprop_namelen(fdt, nodeoffset, name,
namelen, lenp);
}
+#endif
/**
* fdt_getprop - retrieve the value of a given property
@@ -707,8 +718,10 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset);
* Identical to fdt_get_alias(), but only examine the first namelen
* characters of name for matching the alias name.
*/
+#ifndef SWIG /* Not available in Python */
const char *fdt_get_alias_namelen(const void *fdt,
const char *name, int namelen);
+#endif
/**
* fdt_get_alias - retrieve the path referenced by a given alias
@@ -1106,10 +1119,12 @@ int fdt_size_cells(const void *fdt, int nodeoffset);
* 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.
*/
+#ifndef SWIG /* Not available in Python */
int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
const char *name, int namelen,
uint32_t idx, const void *val,
int len);
+#endif
/**
* fdt_setprop_inplace - change a property's value, but not its size
@@ -1139,8 +1154,10 @@ int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_TRUNCATED, standard meanings
*/
+#ifndef SWIG /* Not available in Python */
int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
const void *val, int len);
+#endif
/**
* fdt_setprop_inplace_u32 - change the value of a 32-bit integer property
@@ -1297,6 +1314,22 @@ static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
{
return fdt_property_u32(fdt, name, val);
}
+
+/**
+ * fdt_property_placeholder - add a new property and return a ptr to its value
+ *
+ * @fdt: pointer to the device tree blob
+ * @name: name of property to add
+ * @len: length of property value in bytes
+ * @valp: returns a pointer to where where the value should be placed
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_NOSPACE, standard meanings
+ */
+int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp);
+
#define fdt_property_string(fdt, name, str) \
fdt_property(fdt, name, str, strlen(str)+1)
int fdt_end_node(void *fdt);
@@ -1734,8 +1767,10 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name);
* creating subnodes based on a portion of a larger string, such as a
* full path.
*/
+#ifndef SWIG /* Not available in Python */
int fdt_add_subnode_namelen(void *fdt, int parentoffset,
const char *name, int namelen);
+#endif
/**
* fdt_add_subnode - creates a new node
diff --git a/livetree.c b/livetree.c
index 90580be..a5d5676 100644
--- a/livetree.c
+++ b/livetree.c
@@ -500,7 +500,8 @@ struct node *get_node_by_path(struct node *tree, const char *path)
p = strchr(path, '/');
for_each_child(tree, child) {
- if (p && strneq(path, child->name, p-path))
+ if (p && (strlen(child->name) == p-path) &&
+ strneq(path, child->name, p-path))
return get_node_by_path(child, p+1);
else if (!p && streq(path, child->name))
return child;
diff --git a/pylibfdt/.gitignore b/pylibfdt/.gitignore
new file mode 100644
index 0000000..5e8c5e3
--- /dev/null
+++ b/pylibfdt/.gitignore
@@ -0,0 +1,3 @@
+libfdt.py
+libfdt.pyc
+libfdt_wrap.c
diff --git a/pylibfdt/Makefile.pylibfdt b/pylibfdt/Makefile.pylibfdt
new file mode 100644
index 0000000..9507d3d
--- /dev/null
+++ b/pylibfdt/Makefile.pylibfdt
@@ -0,0 +1,24 @@
+# Makefile.pylibfdt
+#
+
+PYLIBFDT_srcs = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_SRCS)) \
+ $(PYLIBFDT_srcdir)/libfdt.i
+PYMODULE = $(PYLIBFDT_objdir)/_libfdt.so
+
+define run_setup
+ SOURCES="$(1)" CPPFLAGS="$(CPPFLAGS)" OBJDIR="$(PYLIBFDT_objdir)"
+ VERSION="$(dtc_version)"
+ $(PYLIBFDT_objdir)/setup.py --quiet $(2)
+endef
+
+$(PYMODULE): $(PYLIBFDT_srcs)
+ @$(VECHO) PYMOD $@
+ $(call run_setup, $^, build_ext --inplace)
+ mv _libfdt.so $@
+
+install_pylibfdt: $(PYMODULE)
+ $(VECHO) INSTALL-PYLIB; \
+ $(call run_setup, $(PYLIBFDT_srcs), \
+ install $(if $(SETUP_PREFIX),--prefix=$(SETUP_PREFIX)))
+
+PYLIBFDT_cleanfiles = libfdt_wrap.c libfdt.py libfdt.pyc _libfdt.so
diff --git a/pylibfdt/libfdt.i b/pylibfdt/libfdt.i
new file mode 100644
index 0000000..cd1c6a9
--- /dev/null
+++ b/pylibfdt/libfdt.i
@@ -0,0 +1,433 @@
+/*
+ * pylibfdt - Flat Device Tree manipulation in Python
+ * Copyright (C) 2017 Google, Inc.
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+%module libfdt
+
+%{
+#define SWIG_FILE_WITH_INIT
+#include "libfdt.h"
+%}
+
+%pythoncode %{
+
+import struct
+
+# Error codes, corresponding to FDT_ERR_... in libfdt.h
+(NOTFOUND,
+ EXISTS,
+ NOSPACE,
+ BADOFFSET,
+ BADPATH,
+ BADPHANDLE,
+ BADSTATE,
+ TRUNCATED,
+ BADMAGIC,
+ BADVERSION,
+ BADSTRUCTURE,
+ BADLAYOUT,
+ INTERNAL,
+ BADNCELLS,
+ BADVALUE,
+ BADOVERLAY,
+ NOPHANDLES) = QUIET_ALL = range(1, 18)
+# QUIET_ALL can be passed as the 'quiet' parameter to avoid exceptions
+# altogether. All # functions passed this value will return an error instead
+# of raising an exception.
+
+# Pass this as the 'quiet' parameter to return -ENOTFOUND on NOTFOUND errors,
+# instead of raising an exception.
+QUIET_NOTFOUND = (NOTFOUND,)
+
+
+class FdtException(Exception):
+ """An exception caused by an error such as one of the codes above"""
+ def __init__(self, err):
+ self.err = err
+
+ def __str__(self):
+ return 'pylibfdt error %d: %s' % (self.err, fdt_strerror(self.err))
+
+def strerror(fdt_err):
+ """Get the string for an error number
+
+ Args:
+ fdt_err: Error number (-ve)
+
+ Returns:
+ String containing the associated error
+ """
+ return fdt_strerror(fdt_err)
+
+def check_err(val, quiet=()):
+ """Raise an error if the return value is -ve
+
+ This is used to check for errors returned by libfdt C functions.
+
+ Args:
+ val: Return value from a libfdt function
+ quiet: Errors to ignore (empty to raise on all errors)
+
+ Returns:
+ val if val >= 0
+
+ Raises
+ FdtException if val < 0
+ """
+ if val < 0:
+ if -val not in quiet:
+ raise FdtException(val)
+ return val
+
+def check_err_null(val, quiet=()):
+ """Raise an error if the return value is NULL
+
+ This is used to check for a NULL return value from certain libfdt C
+ functions
+
+ Args:
+ val: Return value from a libfdt function
+ quiet: Errors to ignore (empty to raise on all errors)
+
+ Returns:
+ val if val is a list, None if not
+
+ Raises
+ FdtException if val indicates an error was reported and the error
+ is not in @quiet.
+ """
+ # Normally a list is returned which contains the data and its length.
+ # If we get just an integer error code, it means the function failed.
+ if not isinstance(val, list):
+ if -val not in quiet:
+ raise FdtException(val)
+ return val
+
+class Fdt:
+ """Device tree class, supporting all operations
+
+ The Fdt object is created is created from a device tree binary file,
+ e.g. with something like:
+
+ fdt = Fdt(open("filename.dtb").read())
+
+ Operations can then be performed using the methods in this class. Each
+ method xxx(args...) corresponds to a libfdt function fdt_xxx(fdt, args...).
+
+ All methods raise an FdtException if an error occurs. To avoid this
+ behaviour a 'quiet' parameter is provided for some functions. This
+ defaults to empty, but you can pass a list of errors that you expect.
+ If one of these errors occurs, the function will return an error number
+ (e.g. -NOTFOUND).
+ """
+ def __init__(self, data):
+ self._fdt = bytearray(data)
+ check_err(fdt_check_header(self._fdt));
+
+ def path_offset(self, path, quiet=()):
+ """Get the offset for a given path
+
+ Args:
+ path: Path to the required node, e.g. '/node@3/subnode@1'
+ quiet: Errors to ignore (empty to raise on all errors)
+
+ Returns:
+ Node offset
+
+ Raises
+ FdtException if the path is not valid or not found
+ """
+ return check_err(fdt_path_offset(self._fdt, path), quiet)
+
+ def first_property_offset(self, nodeoffset, quiet=()):
+ """Get the offset of the first property in a node offset
+
+ Args:
+ nodeoffset: Offset to the node to check
+ quiet: Errors to ignore (empty to raise on all errors)
+
+ Returns:
+ Offset of the first property
+
+ Raises
+ FdtException if the associated node has no properties, or some
+ other error occurred
+ """
+ return check_err(fdt_first_property_offset(self._fdt, nodeoffset),
+ quiet)
+
+ def next_property_offset(self, prop_offset, quiet=()):
+ """Get the next property in a node
+
+ Args:
+ prop_offset: Offset of the previous property
+ quiet: Errors to ignore (empty to raise on all errors)
+
+ Returns:
+ Offset of the next property
+
+ Raises:
+ FdtException if the associated node has no more properties, or
+ some other error occurred
+ """
+ return check_err(fdt_next_property_offset(self._fdt, prop_offset),
+ quiet)
+
+ def get_name(self, nodeoffset):
+ """Get the name of a node
+
+ Args:
+ nodeoffset: Offset of node to check
+
+ Returns:
+ Node name
+
+ Raises:
+ FdtException on error (e.g. nodeoffset is invalid)
+ """
+ return check_err_null(fdt_get_name(self._fdt, nodeoffset))[0]
+
+ def get_property_by_offset(self, prop_offset, quiet=()):
+ """Obtains a property that can be examined
+
+ Args:
+ prop_offset: Offset of property (e.g. from first_property_offset())
+ quiet: Errors to ignore (empty to raise on all errors)
+
+ Returns:
+ Property object, or None if not found
+
+ Raises:
+ FdtException on error (e.g. invalid prop_offset or device
+ tree format)
+ """
+ pdata = check_err_null(
+ fdt_get_property_by_offset(self._fdt, prop_offset), quiet)
+ if isinstance(pdata, (int)):
+ return pdata
+ return Property(pdata[0], pdata[1])
+
+ def first_subnode(self, nodeoffset, quiet=()):
+ """Find the first subnode of a parent node
+
+ Args:
+ nodeoffset: Node offset of parent node
+ quiet: Errors to ignore (empty to raise on all errors)
+
+ Returns:
+ The offset of the first subnode, if any
+
+ Raises:
+ FdtException if no subnode found or other error occurs
+ """
+ return check_err(fdt_first_subnode(self._fdt, nodeoffset), quiet)
+
+ def next_subnode(self, nodeoffset, quiet=()):
+ """Find the next subnode
+
+ Args:
+ nodeoffset: Node offset of previous subnode
+ quiet: Errors to ignore (empty to raise on all errors)
+
+ Returns:
+ The offset of the next subnode, if any
+
+ Raises:
+ FdtException if no more subnode found or other error occurs
+ """
+ return check_err(fdt_next_subnode(self._fdt, nodeoffset), quiet)
+
+ def totalsize(self):
+ """Return the total size of the device tree
+
+ Returns:
+ Total tree size in bytes
+ """
+ return check_err(fdt_totalsize(self._fdt))
+
+ def off_dt_struct(self):
+ """Return the start of the device tree struct area
+
+ Returns:
+ Start offset of struct area
+ """
+ return check_err(fdt_off_dt_struct(self._fdt))
+
+ def pack(self, quiet=()):
+ """Pack the device tree to remove unused space
+
+ This adjusts the tree in place.
+
+ Args:
+ quiet: Errors to ignore (empty to raise on all errors)
+
+ Raises:
+ FdtException if any error occurs
+ """
+ return check_err(fdt_pack(self._fdt), quiet)
+
+ def delprop(self, nodeoffset, prop_name):
+ """Delete a property from a node
+
+ Args:
+ nodeoffset: Node offset containing property to delete
+ prop_name: Name of property to delete
+
+ Raises:
+ FdtError if the property does not exist, or another error occurs
+ """
+ return check_err(fdt_delprop(self._fdt, nodeoffset, prop_name))
+
+ def getprop(self, nodeoffset, prop_name, quiet=()):
+ """Get a property from a node
+
+ Args:
+ nodeoffset: Node offset containing property to get
+ prop_name: Name of property to get
+ quiet: Errors to ignore (empty to raise on all errors)
+
+ Returns:
+ Value of property as a bytearray, or -ve error number
+
+ Raises:
+ FdtError if any error occurs (e.g. the property is not found)
+ """
+ pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name),
+ quiet)
+ if isinstance(pdata, (int)):
+ return pdata
+ return bytearray(pdata[0])
+
+
+class Property:
+ """Holds a device tree property name and value.
+
+ This holds a copy of a property taken from the device tree. It does not
+ reference the device tree, so if anything changes in the device tree,
+ a Property object will remain valid.
+
+ Properties:
+ name: Property name
+ value: Proper value as a bytearray
+ """
+ def __init__(self, name, value):
+ self.name = name
+ self.value = value
+%}
+
+%rename(fdt_property) fdt_property_func;
+
+typedef int fdt32_t;
+
+%include "libfdt/fdt.h"
+
+%include "typemaps.i"
+
+/* Most functions don't change the device tree, so use a const void * */
+%typemap(in) (const void *)(const void *fdt) {
+ if (!PyByteArray_Check($input)) {
+ SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
+ "', argument " "$argnum"" of type '" "$type""'");
+ }
+ $1 = (void *)PyByteArray_AsString($input);
+ fdt = $1;
+ fdt = fdt; /* avoid unused variable warning */
+}
+
+/* Some functions do change the device tree, so use void * */
+%typemap(in) (void *)(const void *fdt) {
+ if (!PyByteArray_Check($input)) {
+ SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
+ "', argument " "$argnum"" of type '" "$type""'");
+ }
+ $1 = PyByteArray_AsString($input);
+ fdt = $1;
+ fdt = fdt; /* avoid unused variable warning */
+}
+
+%typemap(out) (struct fdt_property *) {
+ PyObject *buff;
+
+ if ($1) {
+ resultobj = PyString_FromString(
+ fdt_string(fdt1, fdt32_to_cpu($1->nameoff)));
+ buff = PyByteArray_FromStringAndSize(
+ (const char *)($1 + 1), fdt32_to_cpu($1->len));
+ resultobj = SWIG_Python_AppendOutput(resultobj, buff);
+ }
+}
+
+%apply int *OUTPUT { int *lenp };
+
+/* typemap used for fdt_getprop() */
+%typemap(out) (const void *) {
+ if (!$1)
+ $result = Py_None;
+ else
+ $result = Py_BuildValue("s#", $1, *arg4);
+}
+
+/* We have both struct fdt_property and a function fdt_property() */
+%warnfilter(302) fdt_property;
+
+/* These are macros in the header so have to be redefined here */
+int fdt_magic(const void *fdt);
+int fdt_totalsize(const void *fdt);
+int fdt_off_dt_struct(const void *fdt);
+int fdt_off_dt_strings(const void *fdt);
+int fdt_off_mem_rsvmap(const void *fdt);
+int fdt_version(const void *fdt);
+int fdt_last_comp_version(const void *fdt);
+int fdt_boot_cpuid_phys(const void *fdt);
+int fdt_size_dt_strings(const void *fdt);
+int fdt_size_dt_struct(const void *fdt);
+
+%include <../libfdt/libfdt.h>
diff --git a/pylibfdt/setup.py b/pylibfdt/setup.py
new file mode 100755
index 0000000..90e80f3
--- /dev/null
+++ b/pylibfdt/setup.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+
+"""
+setup.py file for SWIG libfdt
+Copyright (C) 2017 Google, Inc.
+Written by Simon Glass <sjg@chromium.org>
+
+Files to be built into the extension are provided in SOURCES
+C flags to use are provided in CPPFLAGS
+Object file directory is provided in OBJDIR
+Version is provided in VERSION
+
+If these variables are not given they are parsed from the Makefiles. This
+allows this script to be run stand-alone, e.g.:
+
+ ./pylibfdt/setup.py install [--prefix=...]
+"""
+
+from distutils.core import setup, Extension
+import os
+import re
+import sys
+
+# Decodes a Makefile assignment line into key and value (and plus for +=)
+RE_KEY_VALUE = re.compile('(?P<key>\w+) *(?P<plus>[+])?= *(?P<value>.*)$')
+
+
+def ParseMakefile(fname):
+ """Parse a Makefile to obtain its variables.
+
+ This collects variable assigments of the form:
+
+ VAR = value
+ VAR += more
+
+ It does not pick out := assignments, as these are not needed here. It does
+ handle line continuation.
+
+ Returns a dict:
+ key: Variable name (e.g. 'VAR')
+ value: Variable value (e.g. 'value more')
+ """
+ makevars = {}
+ with open(fname) as fd:
+ prev_text = '' # Continuation text from previous line(s)
+ for line in fd.read().splitlines():
+ if line and line[-1] == '\\': # Deal with line continuation
+ prev_text += line[:-1]
+ continue
+ elif prev_text:
+ line = prev_text + line
+ prev_text = '' # Continuation is now used up
+ m = RE_KEY_VALUE.match(line)
+ if m:
+ value = m.group('value') or ''
+ key = m.group('key')
+
+ # Appending to a variable inserts a space beforehand
+ if 'plus' in m.groupdict() and key in makevars:
+ makevars[key] += ' ' + value
+ else:
+ makevars[key] = value
+ return makevars
+
+def GetEnvFromMakefiles():
+ """Scan the Makefiles to obtain the settings we need.
+
+ This assumes that this script is being run from the top-level directory,
+ not the pylibfdt directory.
+
+ Returns:
+ Tuple with:
+ List of swig options
+ Version string
+ List of files to build
+ List of extra C preprocessor flags needed
+ Object directory to use (always '')
+ """
+ basedir = os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0])))
+ swig_opts = ['-I%s' % basedir]
+ makevars = ParseMakefile(os.path.join(basedir, 'Makefile'))
+ version = '%s.%s.%s' % (makevars['VERSION'], makevars['PATCHLEVEL'],
+ makevars['SUBLEVEL'])
+ makevars = ParseMakefile(os.path.join(basedir, 'libfdt', 'Makefile.libfdt'))
+ files = makevars['LIBFDT_SRCS'].split()
+ files = [os.path.join(basedir, 'libfdt', fname) for fname in files]
+ files.append('pylibfdt/libfdt.i')
+ cflags = ['-I%s' % basedir, '-I%s/libfdt' % basedir]
+ objdir = ''
+ return swig_opts, version, files, cflags, objdir
+
+
+progname = sys.argv[0]
+files = os.environ.get('SOURCES', '').split()
+cflags = os.environ.get('CPPFLAGS', '').split()
+objdir = os.environ.get('OBJDIR')
+version = os.environ.get('VERSION')
+swig_opts = []
+
+# If we were called directly rather than through our Makefile (which is often
+# the case with Python module installation), read the settings from the
+# Makefile.
+if not all((version, files, cflags, objdir)):
+ swig_opts, version, files, cflags, objdir = GetEnvFromMakefiles()
+
+libfdt_module = Extension(
+ '_libfdt',
+ sources = files,
+ extra_compile_args = cflags,
+ swig_opts = swig_opts,
+)
+
+setup(
+ name='libfdt',
+ version= version,
+ author='Simon Glass <sjg@chromium.org>',
+ description='Python binding for libfdt',
+ ext_modules=[libfdt_module],
+ package_dir={'': objdir},
+ py_modules=['pylibfdt/libfdt'],
+)
diff --git a/tests/Makefile.tests b/tests/Makefile.tests
index 3d7a4f8..2258135 100644
--- a/tests/Makefile.tests
+++ b/tests/Makefile.tests
@@ -72,13 +72,13 @@ tests_clean:
rm -f $(STD_CLEANFILES:%=$(TESTS_PREFIX)%)
rm -f $(TESTS_CLEANFILES)
-check: tests ${TESTS_BIN}
+check: tests ${TESTS_BIN} $(TESTS_PYLIBFDT)
cd $(TESTS_PREFIX); ./run_tests.sh
-checkm: tests ${TESTS_BIN}
+checkm: tests ${TESTS_BIN} $(TESTS_PYLIBFDT)
cd $(TESTS_PREFIX); ./run_tests.sh -m 2>&1 | tee vglog.$$$$
-checkv: tests ${TESTS_BIN}
+checkv: tests ${TESTS_BIN} $(TESTS_PYLIBFDT)
cd $(TESTS_PREFIX); ./run_tests.sh -v
ifneq ($(DEPTARGETS),)
diff --git a/tests/fdtoverlay-runtest.sh b/tests/fdtoverlay-runtest.sh
new file mode 100644
index 0000000..06c1169
--- /dev/null
+++ b/tests/fdtoverlay-runtest.sh
@@ -0,0 +1,40 @@
+#! /bin/sh
+
+# Run script for fdtoverlay tests
+# We run fdtoverlay to generate a target device tree, thn fdtget to check it
+
+# Usage
+# fdtoverlay-runtest.sh name expected_output dtb_file node property flags value
+
+. ./tests.sh
+
+LOG=tmp.log.$$
+EXPECT=tmp.expect.$$
+rm -f $LOG $EXPECT
+trap "rm -f $LOG $EXPECT" 0
+
+expect="$1"
+echo $expect >$EXPECT
+node="$2"
+property="$3"
+flags="$4"
+basedtb="$5"
+targetdtb="$6"
+shift 6
+overlays="$@"
+
+# First run fdtoverlay
+verbose_run_check $VALGRIND "$FDTOVERLAY" -i "$basedtb" -o "$targetdtb" $overlays
+
+# Now fdtget to read the value
+verbose_run_log_check "$LOG" $VALGRIND "$DTGET" "$targetdtb" "$node" "$property" $flags
+
+if cmp $EXPECT $LOG >/dev/null; then
+ PASS
+else
+ if [ -z "$QUIET_TEST" ]; then
+ echo "EXPECTED :-:"
+ cat $EXPECT
+ fi
+ FAIL "Results differ from expected"
+fi
diff --git a/tests/include7.dts b/tests/include7.dts
index 2f6eb89..ab2c948 100644
--- a/tests/include7.dts
+++ b/tests/include7.dts
@@ -5,6 +5,7 @@
subsubnode {
compatible = "subsubnode1", "subsubnode";
+ placeholder = "this is a placeholder string", "string2";
prop-int = <0xdeadbeef>;
};
diff --git a/tests/path-references.c b/tests/path-references.c
index c8d25fb..5e332e8 100644
--- a/tests/path-references.c
+++ b/tests/path-references.c
@@ -66,7 +66,7 @@ int main(int argc, char *argv[])
void *fdt;
const char *p;
int len, multilen;
- int n1, n2;
+ int n1, n2, n3, n4;
test_init(argc, argv);
fdt = load_blob_arg(argc, argv);
@@ -92,6 +92,16 @@ int main(int argc, char *argv[])
if ((!streq(p, "/node1") || !streq(p + strlen("/node1") + 1, "/node2")))
FAIL("multiref has wrong value");
+ /* Check reference to nested nodes with common prefix */
+ n3 = fdt_path_offset(fdt, "/foo/baz");
+ if (n3 < 0)
+ FAIL("fdt_path_offset(/foo/baz): %s", fdt_strerror(n3));
+ n4 = fdt_path_offset(fdt, "/foobar/baz");
+ if (n4 < 0)
+ FAIL("fdt_path_offset(/foobar/baz): %s", fdt_strerror(n4));
+ check_ref(fdt, n3, "/foobar/baz");
+ check_ref(fdt, n4, "/foo/baz");
+
check_rref(fdt);
PASS();
diff --git a/tests/path-references.dts b/tests/path-references.dts
index b00fd79..8c66d80 100644
--- a/tests/path-references.dts
+++ b/tests/path-references.dts
@@ -12,4 +12,17 @@
ref = &{/node1}; /* reference after target */
lref = &n1;
};
+ /* Check references to nested nodes with common prefix */
+ foobar {
+ n3: baz {
+ ref = &{/foo/baz};
+ lref = &n4;
+ };
+ };
+ foo {
+ n4: baz {
+ ref = &{/foobar/baz};
+ lref = &n3;
+ };
+ };
};
diff --git a/tests/pylibfdt_tests.py b/tests/pylibfdt_tests.py
new file mode 100644
index 0000000..ae392bb
--- /dev/null
+++ b/tests/pylibfdt_tests.py
@@ -0,0 +1,288 @@
+# pylibfdt - Tests for Flat Device Tree manipulation in Python
+# Copyright (C) 2017 Google, Inc.
+# Written by Simon Glass <sjg@chromium.org>
+#
+# libfdt is dual licensed: you can use it either under the terms of
+# the GPL, or the BSD license, at your option.
+#
+# a) This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with this library; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+# MA 02110-1301 USA
+#
+# Alternatively,
+#
+# b) Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+# 1. Redistributions of source code must retain the above
+# copyright notice, this list of conditions and the following
+# disclaimer.
+# 2. Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials
+# provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+import sys
+import types
+import unittest
+
+sys.path.append('../pylibfdt')
+import libfdt
+from libfdt import FdtException, QUIET_NOTFOUND, QUIET_ALL
+
+def get_err(err_code):
+ """Convert an error code into an error message
+
+ Args:
+ err_code: Error code value (FDT_ERR_...)
+
+ Returns:
+ String error code
+ """
+ return 'pylibfdt error %d: %s' % (-err_code, libfdt.fdt_strerror(-err_code))
+
+def _ReadFdt(fname):
+ """Read a device tree file into an Fdt object, ready for use
+
+ Args:
+ fname: Filename to read from
+
+ Returns:
+ Fdt bytearray suitable for passing to libfdt functions
+ """
+ return libfdt.Fdt(open(fname).read())
+
+class PyLibfdtTests(unittest.TestCase):
+ """Test class for pylibfdt
+
+ Properties:
+ fdt: Device tree file used for testing
+ """
+
+ def setUp(self):
+ """Read in the device tree we use for testing"""
+ self.fdt = _ReadFdt('test_tree1.dtb')
+
+ def GetPropList(self, node_path):
+ """Read a list of properties from a node
+
+ Args:
+ node_path: Full path to node, e.g. '/subnode@1/subsubnode'
+
+ Returns:
+ List of property names for that node, e.g. ['compatible', 'reg']
+ """
+ prop_list = []
+ node = self.fdt.path_offset(node_path)
+ poffset = self.fdt.first_property_offset(node, QUIET_NOTFOUND)
+ while poffset > 0:
+ prop = self.fdt.get_property_by_offset(poffset)
+ prop_list.append(prop.name)
+ poffset = self.fdt.next_property_offset(poffset, QUIET_NOTFOUND)
+ return prop_list
+
+ def testImport(self):
+ """Check that we can import the library correctly"""
+ self.assertEquals(type(libfdt), types.ModuleType)
+
+ def testBadFdt(self):
+ """Check that a filename provided accidentally is not accepted"""
+ with self.assertRaises(FdtException) as e:
+ fdt = libfdt.Fdt('a string')
+ self.assertEquals(e.exception.err, -libfdt.BADMAGIC)
+
+ def testPathOffset(self):
+ """Check that we can find the offset of a node"""
+ self.assertEquals(self.fdt.path_offset('/'), 0)
+ self.assertTrue(self.fdt.path_offset('/subnode@1') > 0)
+ with self.assertRaises(FdtException) as e:
+ self.fdt.path_offset('/wibble')
+ self.assertEquals(e.exception.err, -libfdt.NOTFOUND)
+ self.assertEquals(self.fdt.path_offset('/wibble', QUIET_NOTFOUND),
+ -libfdt.NOTFOUND)
+
+ def testPropertyOffset(self):
+ """Walk through all the properties in the root node"""
+ offset = self.fdt.first_property_offset(0)
+ self.assertTrue(offset > 0)
+ for i in range(5):
+ next_offset = self.fdt.next_property_offset(offset)
+ self.assertTrue(next_offset > offset)
+ offset = next_offset
+ self.assertEquals(self.fdt.next_property_offset(offset, QUIET_NOTFOUND),
+ -libfdt.NOTFOUND)
+
+ def testPropertyOffsetExceptions(self):
+ """Check that exceptions are raised as expected"""
+ with self.assertRaises(FdtException) as e:
+ self.fdt.first_property_offset(107)
+ self.assertEquals(e.exception.err, -libfdt.BADOFFSET)
+
+ # Quieten the NOTFOUND exception and check that a BADOFFSET
+ # exception is still raised.
+ with self.assertRaises(FdtException) as e:
+ self.fdt.first_property_offset(107, QUIET_NOTFOUND)
+ self.assertEquals(e.exception.err, -libfdt.BADOFFSET)
+ with self.assertRaises(FdtException) as e:
+ self.fdt.next_property_offset(107, QUIET_NOTFOUND)
+ self.assertEquals(e.exception.err, -libfdt.BADOFFSET)
+
+ # Check that NOTFOUND can be quietened.
+ node = self.fdt.path_offset('/subnode@1/ss1')
+ self.assertEquals(self.fdt.first_property_offset(node, QUIET_NOTFOUND),
+ -libfdt.NOTFOUND)
+ with self.assertRaises(FdtException) as e:
+ self.fdt.first_property_offset(node)
+ self.assertEquals(e.exception.err, -libfdt.NOTFOUND)
+
+ def testGetName(self):
+ """Check that we can get the name of a node"""
+ self.assertEquals(self.fdt.get_name(0), '')
+ node = self.fdt.path_offset('/subnode@1/subsubnode')
+ self.assertEquals(self.fdt.get_name(node), 'subsubnode')
+
+ with self.assertRaises(FdtException) as e:
+ self.fdt.get_name(-2)
+ self.assertEquals(e.exception.err, -libfdt.BADOFFSET)
+
+ def testGetPropertyByOffset(self):
+ """Check that we can read the name and contents of a property"""
+ root = 0
+ poffset = self.fdt.first_property_offset(root)
+ prop = self.fdt.get_property_by_offset(poffset)
+ self.assertEquals(prop.name, 'compatible')
+ self.assertEquals(prop.value, 'test_tree1\0')
+
+ with self.assertRaises(FdtException) as e:
+ self.fdt.get_property_by_offset(-2)
+ self.assertEquals(e.exception.err, -libfdt.BADOFFSET)
+ self.assertEquals(
+ -libfdt.BADOFFSET,
+ self.fdt.get_property_by_offset(-2, [libfdt.BADOFFSET]))
+
+ def testGetProp(self):
+ """Check that we can read the contents of a property by name"""
+ root = self.fdt.path_offset('/')
+ value = self.fdt.getprop(root, "compatible")
+ self.assertEquals(value, 'test_tree1\0')
+ self.assertEquals(-libfdt.NOTFOUND, self.fdt.getprop(root, 'missing',
+ QUIET_NOTFOUND))
+
+ with self.assertRaises(FdtException) as e:
+ self.fdt.getprop(root, 'missing')
+ self.assertEquals(e.exception.err, -libfdt.NOTFOUND)
+
+ node = self.fdt.path_offset('/subnode@1/subsubnode')
+ value = self.fdt.getprop(node, "compatible")
+ self.assertEquals(value, 'subsubnode1\0subsubnode\0')
+
+ def testStrError(self):
+ """Check that we can get an error string"""
+ self.assertEquals(libfdt.strerror(-libfdt.NOTFOUND),
+ 'FDT_ERR_NOTFOUND')
+
+ def testFirstNextSubnodeOffset(self):
+ """Check that we can walk through subnodes"""
+ node_list = []
+ node = self.fdt.first_subnode(0, QUIET_NOTFOUND)
+ while node >= 0:
+ node_list.append(self.fdt.get_name(node))
+ node = self.fdt.next_subnode(node, QUIET_NOTFOUND)
+ self.assertEquals(node_list, ['subnode@1', 'subnode@2'])
+
+ def testFirstNextSubnodeOffsetExceptions(self):
+ """Check except handling for first/next subnode functions"""
+ node = self.fdt.path_offset('/subnode@1/subsubnode', QUIET_NOTFOUND)
+ self.assertEquals(self.fdt.first_subnode(node, QUIET_NOTFOUND),
+ -libfdt.NOTFOUND)
+ with self.assertRaises(FdtException) as e:
+ self.fdt.first_subnode(node)
+ self.assertEquals(e.exception.err, -libfdt.NOTFOUND)
+
+ node = self.fdt.path_offset('/subnode@1/ss1', QUIET_NOTFOUND)
+ self.assertEquals(self.fdt.next_subnode(node, QUIET_NOTFOUND),
+ -libfdt.NOTFOUND)
+ with self.assertRaises(FdtException) as e:
+ self.fdt.next_subnode(node)
+ self.assertEquals(e.exception.err, -libfdt.NOTFOUND)
+
+ def testDeleteProperty(self):
+ """Test that we can delete a property"""
+ node_name = '/subnode@1'
+ self.assertEquals(self.GetPropList(node_name),
+ ['compatible', 'reg', 'prop-int'])
+ node = self.fdt.path_offset('/%s' % node_name)
+ self.assertEquals(self.fdt.delprop(node, 'reg'), 0)
+ self.assertEquals(self.GetPropList(node_name),
+ ['compatible', 'prop-int'])
+
+ def testHeader(self):
+ """Test that we can access the header values"""
+ self.assertEquals(self.fdt.totalsize(), len(self.fdt._fdt))
+ self.assertEquals(self.fdt.off_dt_struct(), 88)
+
+ def testPack(self):
+ """Test that we can pack the tree after deleting something"""
+ orig_size = self.fdt.totalsize()
+ node = self.fdt.path_offset('/subnode@2', QUIET_NOTFOUND)
+ self.assertEquals(self.fdt.delprop(node, 'prop-int'), 0)
+ self.assertEquals(orig_size, self.fdt.totalsize())
+ self.assertEquals(self.fdt.pack(), 0)
+ self.assertTrue(self.fdt.totalsize() < orig_size)
+
+ def testBadPropertyOffset(self):
+ """Test that bad property offsets are detected"""
+ with self.assertRaises(FdtException) as e:
+ self.fdt.get_property_by_offset(13)
+ self.assertEquals(e.exception.err, -libfdt.BADOFFSET)
+ with self.assertRaises(FdtException) as e:
+ self.fdt.first_property_offset(3)
+ self.assertEquals(e.exception.err, -libfdt.BADOFFSET)
+ with self.assertRaises(FdtException) as e:
+ self.fdt.next_property_offset(3)
+ self.assertEquals(e.exception.err, -libfdt.BADOFFSET)
+
+ def testBadPathOffset(self):
+ """Test that bad path names are detected"""
+ with self.assertRaisesRegexp(FdtException, get_err(libfdt.BADPATH)):
+ self.fdt.path_offset('not-present')
+
+ def testQuietAll(self):
+ """Check that exceptions can be masked by QUIET_ALL"""
+ self.assertEquals(-libfdt.NOTFOUND,
+ self.fdt.path_offset('/missing', QUIET_ALL))
+ self.assertEquals(-libfdt.BADOFFSET,
+ self.fdt.get_property_by_offset(13, QUIET_ALL))
+ self.assertEquals(-libfdt.BADPATH,
+ self.fdt.path_offset('missing', QUIET_ALL))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index ed489db..b8a2825 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -157,7 +157,15 @@ run_fdtdump_test() {
file="$1"
shorten_echo fdtdump-runtest.sh "$file"
printf ": "
- base_run_test sh fdtdump-runtest.sh "$file"
+ base_run_test sh fdtdump-runtest.sh "$file" 2>/dev/null
+}
+
+run_fdtoverlay_test() {
+ expect="$1"
+ shift
+ shorten_echo fdtoverlay-runtest.sh "$expect" "$@"
+ printf ": "
+ base_run_test sh fdtoverlay-runtest.sh "$expect" "$@"
}
BAD_FIXUP_TREES="bad_index \
@@ -420,7 +428,7 @@ dtc_tests () {
run_dtc_test -I dts -O dtb -o dtc_path-references.test.dtb path-references.dts
run_test path-references dtc_path-references.test.dtb
- run_test phandle_format dtc_references.test.dtb both
+ run_test phandle_format dtc_references.test.dtb epapr
for f in legacy epapr both; do
run_dtc_test -I dts -O dtb -H $f -o dtc_references.test.$f.dtb references.dts
run_test phandle_format dtc_references.test.$f.dtb $f
@@ -540,6 +548,8 @@ dtc_tests () {
check_tests obsolete-chosen-interrupt-controller.dts obsolete_chosen_interrupt_controller
check_tests reg-without-unit-addr.dts unit_address_vs_reg
check_tests unit-addr-without-reg.dts unit_address_vs_reg
+ check_tests unit-addr-leading-0x.dts unit_address_format
+ check_tests unit-addr-leading-0s.dts unit_address_format
run_sh_test dtc-checkfails.sh node_name_chars -- -I dtb -O dtb bad_node_char.dtb
run_sh_test dtc-checkfails.sh node_name_format -- -I dtb -O dtb bad_node_format.dtb
run_sh_test dtc-checkfails.sh prop_name_chars -- -I dtb -O dtb bad_prop_char.dtb
@@ -769,6 +779,40 @@ fdtdump_tests () {
run_fdtdump_test fdtdump.dts
}
+fdtoverlay_tests() {
+ base=overlay_base.dts
+ basedtb=overlay_base.fdoverlay.test.dtb
+ overlay=overlay_overlay_manual_fixups.dts
+ overlaydtb=overlay_overlay_manual_fixups.fdoverlay.test.dtb
+ targetdtb=target.fdoverlay.test.dtb
+
+ run_dtc_test -@ -I dts -O dtb -o $basedtb $base
+ run_dtc_test -@ -I dts -O dtb -o $overlaydtb $overlay
+
+ # test that the new property is installed
+ run_fdtoverlay_test foobar "/test-node" "test-str-property" "-ts" ${basedtb} ${targetdtb} ${overlaydtb}
+}
+
+pylibfdt_tests () {
+ TMP=/tmp/tests.stderr.$$
+ python pylibfdt_tests.py -v 2> $TMP
+
+ # Use the 'ok' message meaning the test passed, 'ERROR' meaning it failed
+ # and the summary line for total tests (e.g. 'Ran 17 tests in 0.002s').
+ # We could add pass + fail to get total tests, but this provides a useful
+ # sanity check.
+ pass_count=$(grep "\.\.\. ok$" $TMP | wc -l)
+ fail_count=$(grep "^ERROR: " $TMP | wc -l)
+ total_tests=$(sed -n 's/^Ran \([0-9]*\) tests.*$/\1/p' $TMP)
+ cat $TMP
+ rm $TMP
+
+ # Extract the test results and add them to our totals
+ tot_fail=$((tot_fail + $fail_count))
+ tot_pass=$((tot_pass + $pass_count))
+ tot_tests=$((tot_tests + $total_tests))
+}
+
while getopts "vt:me" ARG ; do
case $ARG in
"v")
@@ -787,7 +831,12 @@ while getopts "vt:me" ARG ; do
done
if [ -z "$TESTSETS" ]; then
- TESTSETS="libfdt utilfdt dtc dtbs_equal fdtget fdtput fdtdump"
+ TESTSETS="libfdt utilfdt dtc dtbs_equal fdtget fdtput fdtdump fdtoverlay"
+
+ # Test pylibfdt if the libfdt Python module is available.
+ if [ -f ../pylibfdt/_libfdt.so ]; then
+ TESTSETS="$TESTSETS pylibfdt"
+ fi
fi
# Make sure we don't have stale blobs lying around
@@ -816,6 +865,12 @@ for set in $TESTSETS; do
"fdtdump")
fdtdump_tests
;;
+ "pylibfdt")
+ pylibfdt_tests
+ ;;
+ "fdtoverlay")
+ fdtoverlay_tests
+ ;;
esac
done
diff --git a/tests/sw_tree1.c b/tests/sw_tree1.c
index 4887dc3..6a338fc 100644
--- a/tests/sw_tree1.c
+++ b/tests/sw_tree1.c
@@ -85,6 +85,9 @@ int main(int argc, char *argv[])
size_t size;
int err;
bool created = false;
+ void *place;
+ const char place_str[] = "this is a placeholder string\0string2";
+ int place_len = sizeof(place_str);
test_init(argc, argv);
@@ -135,6 +138,8 @@ int main(int argc, char *argv[])
CHECK(fdt_begin_node(fdt, "subsubnode"));
CHECK(fdt_property(fdt, "compatible", "subsubnode1\0subsubnode",
23));
+ CHECK(fdt_property_placeholder(fdt, "placeholder", place_len, &place));
+ memcpy(place, place_str, place_len);
CHECK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_1));
CHECK(fdt_end_node(fdt));
CHECK(fdt_begin_node(fdt, "ss1"));
diff --git a/tests/test_tree1.dts b/tests/test_tree1.dts
index 67ecfd0..77ea325 100644
--- a/tests/test_tree1.dts
+++ b/tests/test_tree1.dts
@@ -18,6 +18,7 @@
subsubnode {
compatible = "subsubnode1", "subsubnode";
+ placeholder = "this is a placeholder string", "string2";
prop-int = <0xdeadbeef>;
};
diff --git a/tests/test_tree1_label_noderef.dts b/tests/test_tree1_label_noderef.dts
index b2b194c..cfe5946 100644
--- a/tests/test_tree1_label_noderef.dts
+++ b/tests/test_tree1_label_noderef.dts
@@ -18,6 +18,7 @@
subsubnode {
compatible = "subsubnode1", "subsubnode";
+ placeholder = "this is a placeholder string", "string2";
prop-int = <0xdeadbeef>;
};
diff --git a/tests/tests.sh b/tests/tests.sh
index 818fd09..8dda6e1 100644
--- a/tests/tests.sh
+++ b/tests/tests.sh
@@ -22,6 +22,7 @@ DTC=../dtc
DTGET=../fdtget
DTPUT=../fdtput
FDTDUMP=../fdtdump
+FDTOVERLAY=../fdtoverlay
verbose_run () {
if [ -z "$QUIET_TEST" ]; then
diff --git a/tests/trees.S b/tests/trees.S
index 3d24aa2..9854d1d 100644
--- a/tests/trees.S
+++ b/tests/trees.S
@@ -102,6 +102,7 @@ test_tree1_struct:
BEGIN_NODE("subsubnode")
PROP_STR(test_tree1, compatible, "subsubnode1\0subsubnode")
+ PROP_STR(test_tree1, placeholder, "this is a placeholder string\0string2")
PROP_INT(test_tree1, prop_int, TEST_VALUE_1)
END_NODE
@@ -141,6 +142,7 @@ test_tree1_strings:
STRING(test_tree1, linux_phandle, "linux,phandle")
STRING(test_tree1, phandle, "phandle")
STRING(test_tree1, reg, "reg")
+ STRING(test_tree1, placeholder, "placeholder")
STRING(test_tree1, address_cells, "#address-cells")
STRING(test_tree1, size_cells, "#size-cells")
test_tree1_strings_end:
diff --git a/tests/unit-addr-leading-0s.dts b/tests/unit-addr-leading-0s.dts
new file mode 100644
index 0000000..cc017e9
--- /dev/null
+++ b/tests/unit-addr-leading-0s.dts
@@ -0,0 +1,12 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ bus {
+ node@001 {
+ reg = <1 0>;
+ };
+ };
+};
diff --git a/tests/unit-addr-leading-0x.dts b/tests/unit-addr-leading-0x.dts
new file mode 100644
index 0000000..74f1967
--- /dev/null
+++ b/tests/unit-addr-leading-0x.dts
@@ -0,0 +1,12 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ bus {
+ node@0x1 {
+ reg = <1 0>;
+ };
+ };
+};