Snap for 4453288 from 65effc285b9fc120e167a49b13ea9d4a91138676 to pi-release

Change-Id: I0cc8d7061c58db1751f1e1bb262e58bd006c0217
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 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 @@
 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 @@
 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 += 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 @@
 -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: install-bin install-lib install-includes
 
+ifeq ($(NO_PYTHON),)
+install: install_pylibfdt
+endif
+
 $(VERSION_FILE): Makefile FORCE
 	$(call filechk,version)
 
@@ -196,12 +228,30 @@
 
 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 += 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 @@
 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 @@
 
 $(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 @@
 	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 @@
 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 @@
 }
 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 @@
 	&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 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 *next;
 };
 
+struct bus_type {
+	const char *name;
+};
+
 struct property {
 	bool deleted;
 	char *name;
@@ -161,6 +166,7 @@
 	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 @@
 	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 @@
 	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 @@
 
 	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 @@
 {
 	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 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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 proplen;
 
 	propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
-	if (! propval)
+	if (!propval)
 		return proplen;
 
 	if (proplen != len)
@@ -107,7 +107,7 @@
 	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 @@
 /**********************************************************************/
 /* 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 @@
  * 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 @@
  * 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 @@
  * 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 @@
  *		-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 @@
  * 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 @@
 	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 @@
  * 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 @@
  * 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 @@
  *	-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 @@
 {
 	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 @@
  * 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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
     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 @@
     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 @@
     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 @@
     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 @@
 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 @@
 	"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 @@
 	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 @@
 	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 @@
 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 @@
 
 	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 @@
 	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>;
+		};
+	};
+};