Update dtc to 1.6.0

Upstream commit 9d7888cbf19c.

Bug: 160825200
Change-Id: I1f8c79f09190af4025b186166a25b745710f2871
diff --git a/.cirrus.yml b/.cirrus.yml
new file mode 100644
index 0000000..c270a09
--- /dev/null
+++ b/.cirrus.yml
@@ -0,0 +1,23 @@
+env:
+  CIRRUS_CLONE_DEPTH: 1
+
+freebsd_12_task:
+  freebsd_instance:
+    image: freebsd-12-1-release-amd64
+  install_script:
+    pkg install -y bison gmake pkgconf
+  build_script:
+    gmake
+  test_script:
+    gmake check
+
+linux_gcc_task:
+  container:
+    image: gcc:latest
+  install_script:
+    - apt-get update
+    - apt-get -y install bison flex
+  build_script:
+    - make
+  test_script:
+    - make check
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..d7e68fb
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,30 @@
+# EditorConfig is a file format and collection of text editor plugins
+# for maintaining consistent coding styles between different editors
+# and IDEs. Most popular editors support this either natively or via
+# plugin.
+#
+# Check https://editorconfig.org for details.
+
+root = true
+
+[*]
+end_of_line = lf
+insert_final_newline = true
+charset = utf-8
+indent_style = space
+
+[Makefile*]
+indent_style = tab
+indent_size = 8
+file_type_emacs = makefile
+
+[*.[ch]]
+indent_style = tab
+indent_size = 8
+
+[*.py]
+indent_size = 4
+
+[meson.build]
+indent_style = space
+indent_size = 2
diff --git a/.gitignore b/.gitignore
index 545b899..1f2a0f2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
 *.patch
 *.so
 *~
+*.bak
 *.tab.[ch]
 lex.yy.c
 *.lex.c
@@ -13,5 +14,6 @@
 /version_gen.h
 /fdtget
 /fdtput
+/fdtoverlay
 /patches
 /.pc
diff --git a/.travis.yml b/.travis.yml
index a07c989..a5163de 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,6 +13,8 @@
           packages:
             - swig
             - python-dev
+            - valgrind
+            - libyaml-0-2
         coverity_scan:
           project:
             name: dtc
@@ -20,11 +22,44 @@
           notification_email: david@gibson.dropbear.id.au
           build_command: make
           branch_pattern: coverity_scan
+      script:
+        - make
+        - make check && make checkm
 
-    - addons:
-        apt:
-          packages:
-
-script:
+    # Check it builds properly without optional packages:
+    #     python, valgrind, libyaml
+    - script:
         - make
         - make check
+
+    - arch: arm64
+      addons:
+        apt_packages:
+          - swig
+          - python-dev
+          - valgrind
+          - libyaml-0-2
+      script:
+        - make
+        - make check checkm
+
+    - arch: ppc64le
+      addons:
+        apt_packages:
+          - swig
+          - python-dev
+          - libyaml-0-2
+      script:
+        - make
+        - make check
+
+    - arch: s390x
+      addons:
+        apt_packages:
+          - swig
+          - python-dev
+          - valgrind
+          - libyaml-0-2
+      script:
+        - make
+        - make check checkm
diff --git a/Android.bp b/Android.bp
index d52d98c..712bc4d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -7,6 +7,7 @@
         "-Wno-sign-compare",
         "-Wno-missing-field-initializers",
         "-Wno-unused-parameter",
+        "-DNO_YAML"
     ],
 
     static_libs: ["libfdt"],
diff --git a/BSD-2-Clause b/BSD-2-Clause
new file mode 100644
index 0000000..da366e2
--- /dev/null
+++ b/BSD-2-Clause
@@ -0,0 +1,32 @@
+Valid-License-Identifier: BSD-2-Clause
+SPDX-URL: https://spdx.org/licenses/BSD-2-Clause.html
+Usage-Guide:
+  To use the BSD 2-clause "Simplified" License put the following SPDX
+  tag/value pair into a comment according to the placement guidelines in
+  the licensing rules documentation:
+    SPDX-License-Identifier: BSD-2-Clause
+License-Text:
+
+Copyright (c) <year> <owner> . All rights reserved.
+
+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 HOLDER 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.
diff --git a/Documentation/manual.txt b/Documentation/manual.txt
index 72403ac..adf5ccb 100644
--- a/Documentation/manual.txt
+++ b/Documentation/manual.txt
@@ -37,7 +37,7 @@
     git://git.kernel.org/pub/scm/utils/dtc/dtc.git
     https://git.kernel.org/pub/scm/utils/dtc/dtc.git
 
-The gitweb interface for the upstream respository is:
+The gitweb interface for the upstream repository is:
 
     https://git.kernel.org/cgit/utils/dtc/dtc.git/
 
@@ -78,6 +78,9 @@
         then simply be added to your Makefile.  Additionally, the
         assembly file exports some symbols that can be used.
 
+     - "yaml": DT encoded in YAML format. This representation is an
+       intermediate format used for validation tools.
+
 
 3) Command Line
 
@@ -231,7 +234,7 @@
       "childnode at address".  It in turn has a string property
       called "childprop".
 
-	childnode@addresss {
+	childnode@address {
 	    childprop = "hello\n";
 	};
 
@@ -250,7 +253,7 @@
 before a node name, and are referenced using an ampersand: &label.
 Absolute node path names are also allowed in node references.
 
-In this exmaple, a node is labled "mpic" and then referenced:
+In this example, a node is labeled "mpic" and then referenced:
 
     mpic:  interrupt-controller@40000 {
 	...
@@ -261,7 +264,7 @@
 	...
     };
 
-And used in properties, lables may appear before or after any value:
+And used in properties, labels may appear before or after any value:
 
     randomnode {
 	prop: string = data: "mystring\n" data_end: ;
@@ -415,7 +418,7 @@
      among others, by kexec. If you are on an SMP system, this value
      should match the content of the "reg" property of the CPU node in
      the device-tree corresponding to the CPU calling the kernel entry
-     point (see further chapters for more informations on the required
+     point (see further chapters for more information on the required
      device-tree contents)
 
    - size_dt_strings
@@ -581,7 +584,7 @@
 
 This tree is almost a minimal tree. It pretty much contains the
 minimal set of required nodes and properties to boot a linux kernel;
-that is, some basic model informations at the root, the CPUs, and the
+that is, some basic model information at the root, the CPUs, and the
 physical memory layout.  It also includes misc information passed
 through /chosen, like in this example, the platform type (mandatory)
 and the kernel command line arguments (optional).
@@ -693,3 +696,67 @@
     -i, --input         Input base DT blob
     -o, --output        Output DT blob
     -v, --verbose       Verbose message output
+
+4 ) fdtget -- Read properties from device tree
+
+This command can be used to obtain individual values from the device tree in a
+nicely formatted way. You can specify multiple nodes to display (when using -p)
+or multiple node/property pairs (when not using -p). For the latter, each
+property is displayed on its own line, with a space between each cell within
+the property.
+
+The syntax of the fdtget command is:
+
+    fdtget <options> <dt file> [<node> <property>]...
+    fdtget -p <options> <dt file> [<node> ]...
+
+where options are:
+
+    <type>    s=string, i=int, u=unsigned, x=hex
+        Optional modifier prefix:
+            hh or b=byte, h=2 byte, l=4 byte (default)
+
+    Options: -[t:pld:hV]
+    -t, --type <arg>    Type of data
+    -p, --properties    List properties for each node
+    -l, --list          List subnodes for each node
+    -d, --default <arg> Default value to display when the property is missing
+    -h, --help          Print this help and exit
+    -V, --version       Print version and exit
+
+If -t is not provided, fdtget will try to figure out the type, trying to detect
+strings, string lists and the size of each value in the property. This is
+similar to how fdtdump works, and uses the same heuristics.
+
+
+5 ) fdtput - Write properties to a device tree
+
+The syntax of the fdtput command is:
+
+    fdtput <options> <dt file> <node> <property> [<value>...]
+    fdtput -c <options> <dt file> [<node>...]
+    fdtput -r <options> <dt file> [<node>...]
+    fdtput -d <options> <dt file> <node> [<property>...]
+
+Options are:
+
+    <type>    s=string, i=int, u=unsigned, x=hex
+        Optional modifier prefix:
+            hh or b=byte, h=2 byte, l=4 byte (default)
+
+    -c, --create     Create nodes if they don't already exist
+    -r, --remove     Delete nodes (and any subnodes) if they already exist
+    -d, --delete     Delete properties if they already exist
+    -p, --auto-path  Automatically create nodes as needed for the node path
+    -t, --type <arg> Type of data
+    -v, --verbose    Display each value decoded from command line
+    -h, --help       Print this help and exit
+    -V, --version    Print version and exit
+
+The option determines which usage is selected and therefore the operation that
+is performed. The first usage adds or updates properties; the rest are used to
+create/delete nodes and delete properties.
+
+For the first usage, the command line arguments are joined together into a
+single value which is written to the property. The -t option is required so
+that fdtput knows how to decode its arguments.
diff --git a/GPL b/GPL
index d60c31a..d159169 100644
--- a/GPL
+++ b/GPL
@@ -1,12 +1,12 @@
-		    GNU GENERAL PUBLIC LICENSE
-		       Version 2, June 1991
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
 
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  Everyone is permitted to copy and distribute verbatim copies
  of this license document, but changing it is not allowed.
 
-			    Preamble
+                            Preamble
 
   The licenses for most software are designed to take away your
 freedom to share and change it.  By contrast, the GNU General Public
@@ -15,7 +15,7 @@
 General Public License applies to most of the Free Software
 Foundation's software and to any other program whose authors commit to
 using it.  (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.)  You can apply it to
+the GNU Lesser General Public License instead.)  You can apply it to
 your programs, too.
 
   When we speak of free software, we are referring to freedom, not
@@ -55,8 +55,8 @@
 
   The precise terms and conditions for copying, distribution and
 modification follow.
-
-		    GNU GENERAL PUBLIC LICENSE
+
+                    GNU GENERAL PUBLIC LICENSE
    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 
   0. This License applies to any program or other work which contains
@@ -110,7 +110,7 @@
     License.  (Exception: if the Program itself is interactive but
     does not normally print such an announcement, your work based on
     the Program is not required to print an announcement.)
-
+
 These requirements apply to the modified work as a whole.  If
 identifiable sections of that work are not derived from the Program,
 and can be reasonably considered independent and separate works in
@@ -168,7 +168,7 @@
 access to copy the source code from the same place counts as
 distribution of the source code, even though third parties are not
 compelled to copy the source along with the object code.
-
+
   4. You may not copy, modify, sublicense, or distribute the Program
 except as expressly provided under this License.  Any attempt
 otherwise to copy, modify, sublicense or distribute the Program is
@@ -225,7 +225,7 @@
 
 This section is intended to make thoroughly clear what is believed to
 be a consequence of the rest of this License.
-
+
   8. If the distribution and/or use of the Program is restricted in
 certain countries either by patents or by copyrighted interfaces, the
 original copyright holder who places the Program under this License
@@ -255,7 +255,7 @@
 of preserving the free status of all derivatives of our free software and
 of promoting the sharing and reuse of software generally.
 
-			    NO WARRANTY
+                            NO WARRANTY
 
   11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
 FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
@@ -277,9 +277,9 @@
 PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGES.
 
-		     END OF TERMS AND CONDITIONS
-
-	    How to Apply These Terms to Your New Programs
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
 
   If you develop a new program, and you want it to be of the greatest
 possible use to the public, the best way to achieve this is to make it
@@ -303,17 +303,16 @@
     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
-
+    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.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
 Also add information on how to contact you by electronic and paper mail.
 
 If the program is interactive, make it output a short notice like this
 when it starts in an interactive mode:
 
-    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision version 69, Copyright (C) year name of author
     Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
     This is free software, and you are welcome to redistribute it
     under certain conditions; type `show c' for details.
@@ -336,5 +335,5 @@
 This General Public License does not permit incorporating your program into
 proprietary programs.  If your program is a subroutine library, you may
 consider it more useful to permit linking proprietary applications with the
-library.  If this is what you want to do, use the GNU Library General
+library.  If this is what you want to do, use the GNU Lesser General
 Public License instead of this License.
diff --git a/Makefile b/Makefile
index fe482b9..cb256e8 100644
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Device Tree Compiler
 #
@@ -9,23 +10,32 @@
 # CONFIG_LOCALVERSION from some future config system.
 #
 VERSION = 1
-PATCHLEVEL = 4
-SUBLEVEL = 4
+PATCHLEVEL = 6
+SUBLEVEL = 0
 EXTRAVERSION =
 LOCAL_VERSION =
 CONFIG_LOCALVERSION =
 
-CPPFLAGS = -I libfdt -I .
+# Control the assumptions made (e.g. risking security issues) in the code.
+# See libfdt_internal.h for details
+ASSUME_MASK ?= 0
+
+CPPFLAGS = -I libfdt -I . -DFDT_ASSUME_MASK=$(ASSUME_MASK)
 WARNINGS = -Wall -Wpointer-arith -Wcast-qual -Wnested-externs \
 	-Wstrict-prototypes -Wmissing-prototypes -Wredundant-decls -Wshadow
-CFLAGS = -g -Os $(SHAREDLIB_CFLAGS) -Werror $(WARNINGS)
+CFLAGS = -g -Os $(SHAREDLIB_CFLAGS) -Werror $(WARNINGS) $(EXTRA_CFLAGS)
 
 BISON = bison
 LEX = flex
 SWIG = swig
 PKG_CONFIG ?= pkg-config
+PYTHON ?= python3
 
 INSTALL = /usr/bin/install
+INSTALL_PROGRAM = $(INSTALL)
+INSTALL_LIB = $(INSTALL)
+INSTALL_DATA = $(INSTALL) -m 644
+INSTALL_SCRIPT = $(INSTALL)
 DESTDIR =
 PREFIX = $(HOME)
 BINDIR = $(PREFIX)/bin
@@ -35,6 +45,22 @@
 HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
 	    sed -e 's/\(cygwin\|msys\).*/\1/')
 
+NO_PYTHON ?= 0
+
+NO_VALGRIND := $(shell $(PKG_CONFIG) --exists valgrind; echo $$?)
+ifeq ($(NO_VALGRIND),1)
+	CPPFLAGS += -DNO_VALGRIND
+else
+	CFLAGS += $(shell $(PKG_CONFIG) --cflags valgrind)
+endif
+
+NO_YAML := $(shell $(PKG_CONFIG) --exists yaml-0.1; echo $$?)
+ifeq ($(NO_YAML),1)
+	CFLAGS += -DNO_YAML
+else
+	LDLIBS_dtc += $(shell $(PKG_CONFIG) --libs yaml-0.1)
+endif
+
 ifeq ($(HOSTOS),darwin)
 SHAREDLIB_EXT     = dylib
 SHAREDLIB_CFLAGS  = -fPIC
@@ -126,26 +152,31 @@
 
 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 \
+# We need both Python and swig to build/install pylibfdt.
+# This builds the given make ${target} if those deps are found.
+check_python_deps = \
+	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; \
+	if [ "$${can_build}" = "yes" ]; then \
+		$(MAKE) $${target}; \
 	else \
-		echo "## Skipping pylibfdt (install python dev and swig to build)"; \
-	fi
+		echo "\#\# Skipping pylibfdt (install python dev and swig to build)"; \
+	fi ;
 
-ifeq ($(NO_PYTHON),)
+.PHONY: maybe_pylibfdt
+maybe_pylibfdt: FORCE
+	target=pylibfdt; $(check_python_deps)
+
+ifeq ($(NO_PYTHON),0)
 all: maybe_pylibfdt
 endif
 
 
 ifneq ($(DEPTARGETS),)
+ifneq ($(MAKECMDGOALS),libfdt)
 -include $(DTC_OBJS:%.o=%.d)
 -include $(CONVERT_OBJS:%.o=%.d)
 -include $(FDTDUMP_OBJS:%.o=%.d)
@@ -153,34 +184,34 @@
 -include $(FDTPUT_OBJS:%.o=%.d)
 -include $(FDTOVERLAY_OBJS:%.o=%.d)
 endif
+endif
 
 
 
 #
 # Rules for libfdt
 #
-LIBFDT_objdir = libfdt
-LIBFDT_srcdir = libfdt
-LIBFDT_archive = $(LIBFDT_objdir)/libfdt.a
-LIBFDT_lib = $(LIBFDT_objdir)/libfdt-$(DTC_VERSION).$(SHAREDLIB_EXT)
-LIBFDT_include = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_INCLUDES))
-LIBFDT_version = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_VERSION))
+LIBFDT_dir = libfdt
+LIBFDT_archive = $(LIBFDT_dir)/libfdt.a
+LIBFDT_lib = $(LIBFDT_dir)/$(LIBFDT_LIB)
+LIBFDT_include = $(addprefix $(LIBFDT_dir)/,$(LIBFDT_INCLUDES))
+LIBFDT_version = $(addprefix $(LIBFDT_dir)/,$(LIBFDT_VERSION))
 
-include $(LIBFDT_srcdir)/Makefile.libfdt
+include $(LIBFDT_dir)/Makefile.libfdt
 
 .PHONY: libfdt
 libfdt: $(LIBFDT_archive) $(LIBFDT_lib)
 
-$(LIBFDT_archive): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS))
-$(LIBFDT_lib): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS))
+$(LIBFDT_archive): $(addprefix $(LIBFDT_dir)/,$(LIBFDT_OBJS))
 
-libfdt_clean:
-	@$(VECHO) CLEAN "(libfdt)"
-	rm -f $(addprefix $(LIBFDT_objdir)/,$(STD_CLEANFILES))
-	rm -f $(LIBFDT_objdir)/*.so
+$(LIBFDT_lib): $(addprefix $(LIBFDT_dir)/,$(LIBFDT_OBJS)) $(LIBFDT_version)
+	@$(VECHO) LD $@
+	$(CC) $(LDFLAGS) $(SHAREDLIB_LDFLAGS)$(LIBFDT_soname) -o $(LIBFDT_lib) \
+		$(addprefix $(LIBFDT_dir)/,$(LIBFDT_OBJS))
+	ln -sf $(LIBFDT_LIB) $(LIBFDT_dir)/$(LIBFDT_soname)
 
 ifneq ($(DEPTARGETS),)
--include $(LIBFDT_OBJS:%.o=$(LIBFDT_objdir)/%.d)
+-include $(LIBFDT_OBJS:%.o=$(LIBFDT_dir)/%.d)
 endif
 
 # This stops make from generating the lex and bison output during
@@ -191,25 +222,30 @@
 install-bin: all $(SCRIPTS)
 	@$(VECHO) INSTALL-BIN
 	$(INSTALL) -d $(DESTDIR)$(BINDIR)
-	$(INSTALL) $(BIN) $(SCRIPTS) $(DESTDIR)$(BINDIR)
+	$(INSTALL_PROGRAM) $(BIN) $(DESTDIR)$(BINDIR)
+	$(INSTALL_SCRIPT) $(SCRIPTS) $(DESTDIR)$(BINDIR)
 
 install-lib: all
 	@$(VECHO) INSTALL-LIB
 	$(INSTALL) -d $(DESTDIR)$(LIBDIR)
-	$(INSTALL) $(LIBFDT_lib) $(DESTDIR)$(LIBDIR)
+	$(INSTALL_LIB) $(LIBFDT_lib) $(DESTDIR)$(LIBDIR)
 	ln -sf $(notdir $(LIBFDT_lib)) $(DESTDIR)$(LIBDIR)/$(LIBFDT_soname)
 	ln -sf $(LIBFDT_soname) $(DESTDIR)$(LIBDIR)/libfdt.$(SHAREDLIB_EXT)
-	$(INSTALL) -m 644 $(LIBFDT_archive) $(DESTDIR)$(LIBDIR)
+	$(INSTALL_DATA) $(LIBFDT_archive) $(DESTDIR)$(LIBDIR)
 
 install-includes:
 	@$(VECHO) INSTALL-INC
 	$(INSTALL) -d $(DESTDIR)$(INCLUDEDIR)
-	$(INSTALL) -m 644 $(LIBFDT_include) $(DESTDIR)$(INCLUDEDIR)
+	$(INSTALL_DATA) $(LIBFDT_include) $(DESTDIR)$(INCLUDEDIR)
 
 install: install-bin install-lib install-includes
 
-ifeq ($(NO_PYTHON),)
-install: install_pylibfdt
+.PHONY: maybe_install_pylibfdt
+maybe_install_pylibfdt: FORCE
+	target=install_pylibfdt; $(check_python_deps)
+
+ifeq ($(NO_PYTHON),0)
+install: maybe_install_pylibfdt
 endif
 
 $(VERSION_FILE): Makefile FORCE
@@ -224,11 +260,11 @@
 
 fdtdump:	$(FDTDUMP_OBJS)
 
-fdtget:	$(FDTGET_OBJS) $(LIBFDT_archive)
+fdtget:	$(FDTGET_OBJS) $(LIBFDT_lib)
 
-fdtput:	$(FDTPUT_OBJS) $(LIBFDT_archive)
+fdtput:	$(FDTPUT_OBJS) $(LIBFDT_lib)
 
-fdtoverlay: $(FDTOVERLAY_OBJS) $(LIBFDT_archive)
+fdtoverlay: $(FDTOVERLAY_OBJS) $(LIBFDT_lib)
 
 dist:
 	git archive --format=tar --prefix=dtc-$(dtc_version)/ HEAD \
@@ -240,17 +276,12 @@
 #
 # Rules for pylibfdt
 #
-PYLIBFDT_srcdir = pylibfdt
-PYLIBFDT_objdir = pylibfdt
+PYLIBFDT_dir = pylibfdt
 
-include $(PYLIBFDT_srcdir)/Makefile.pylibfdt
+include $(PYLIBFDT_dir)/Makefile.pylibfdt
 
 .PHONY: pylibfdt
-pylibfdt: $(PYLIBFDT_objdir)/_libfdt.so
-
-pylibfdt_clean:
-	@$(VECHO) CLEAN "(pylibfdt)"
-	rm -f $(addprefix $(PYLIBFDT_objdir)/,$(PYLIBFDT_cleanfiles))
+pylibfdt: $(PYLIBFDT_dir)/_libfdt.so
 
 #
 # Release signing and uploading
@@ -285,11 +316,13 @@
 TESTS_BIN += fdtget
 TESTS_BIN += fdtdump
 TESTS_BIN += fdtoverlay
-ifeq ($(NO_PYTHON),)
+ifeq ($(NO_PYTHON),0)
 TESTS_PYLIBFDT += maybe_pylibfdt
 endif
 
+ifneq ($(MAKECMDGOALS),libfdt)
 include tests/Makefile.tests
+endif
 
 #
 # Clean rules
@@ -309,7 +342,7 @@
 #
 %: %.o
 	@$(VECHO) LD $@
-	$(LINK.c) -o $@ $^
+	$(LINK.c) -o $@ $^ $(LDLIBS_$*)
 
 %.o: %.c
 	@$(VECHO) CC $@
@@ -321,7 +354,7 @@
 
 %.d: %.c
 	@$(VECHO) DEP $<
-	$(CC) $(CPPFLAGS) -MM -MG -MT "$*.o $@" $< > $@
+	$(CC) $(CPPFLAGS) $(CFLAGS) -MM -MG -MT "$*.o $@" $< > $@
 
 %.d: %.S
 	@$(VECHO) DEP $<
@@ -339,16 +372,12 @@
 	@$(VECHO) AR $@
 	$(AR) $(ARFLAGS) $@ $^
 
-$(LIBFDT_lib):
-	@$(VECHO) LD $@
-	$(CC) $(LDFLAGS) $(SHAREDLIB_LDFLAGS)$(LIBFDT_soname) -o $(LIBFDT_lib) $^
-
 %.lex.c: %.l
 	@$(VECHO) LEX $@
 	$(LEX) -o$@ $<
 
 %.tab.c %.tab.h %.output: %.y
 	@$(VECHO) BISON $@
-	$(BISON) -d $<
+	$(BISON) -b $(basename $(basename $@)) -d $<
 
 FORCE:
diff --git a/Makefile.convert-dtsv0 b/Makefile.convert-dtsv0
index 08ea40a..c12ed40 100644
--- a/Makefile.convert-dtsv0
+++ b/Makefile.convert-dtsv0
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # This is not a complete Makefile of itself.
 # Instead, it is designed to be easily embeddable
diff --git a/Makefile.dtc b/Makefile.dtc
index bece49b..9c467b0 100644
--- a/Makefile.dtc
+++ b/Makefile.dtc
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
 # Makefile.dtc
 #
 # This is not a complete Makefile of itself.  Instead, it is designed to
@@ -14,5 +15,9 @@
 	treesource.c \
 	util.c
 
+ifneq ($(NO_YAML),1)
+DTC_SRCS += yamltree.c
+endif
+
 DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c
 DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o)
diff --git a/Makefile.utils b/Makefile.utils
index e028922..9436b34 100644
--- a/Makefile.utils
+++ b/Makefile.utils
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # This is not a complete Makefile of itself.  Instead, it is designed to
 # be easily embeddable into other systems of Makefiles.
diff --git a/README b/README
index 17dc845..9465ee5 100644
--- a/README
+++ b/README
@@ -14,45 +14,43 @@
 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
+   sudo apt-get install swig python3-dev
 
 The library provides an Fdt class which you can use like this:
 
-$ PYTHONPATH=../pylibfdt python
+$ PYTHONPATH=../pylibfdt python3
 >>> import libfdt
->>> fdt = libfdt.Fdt(open('test_tree1.dtb').read())
+>>> fdt = libfdt.Fdt(open('test_tree1.dtb', mode='rb').read())
 >>> node = fdt.path_offset('/subnode@1')
->>> print node
+>>> 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)
+>>> print('%s=%s' % (prop.name, prop.as_str()))
 compatible=subnode1
 >>> node2 = fdt.path_offset('/')
->>> print fdt.getprop(node2, 'compatible')
+>>> print(fdt.getprop(node2, 'compatible').as_str())
 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)"
+    $ python3 -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
+    $ sudo apt-get install python3-coverage
     $ cd tests
-    $ coverage run pylibfdt_tests.py
-    $ coverage html
+    # It's just 'coverage' on most other distributions
+    $ python3-coverage run pylibfdt_tests.py
+    $ python3-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]
+    ./pylibfdt/setup.py install [--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
@@ -73,6 +71,17 @@
 values.
 
 
+Tests
+-----
+
+Test files are kept in the tests/ directory. Use 'make check' to build and run
+all tests.
+
+If you want to adjust a test file, be aware that tree_tree1.dts is compiled
+and checked against a binary tree from assembler macros in trees.S. So
+if you change that file you must change tree.S also.
+
+
 Mailing list
 ------------
 The following list is for discussion about dtc and libfdt implementation
diff --git a/README.license b/README.license
index d56c88f..102b004 100644
--- a/README.license
+++ b/README.license
@@ -4,11 +4,11 @@
 This dtc package contains two pieces of software: dtc itself, and
 libfdt which comprises the files in the libfdt/ subdirectory.  These
 two pieces of software, although closely related, are quite distinct.
-dtc does not incoporate or rely on libfdt for its operation, nor vice
+dtc does not incorporate or rely on libfdt for its operation, nor vice
 versa.  It is important that these two pieces of software have
 different license conditions.
 
-As the copyright banners in each source file attest, dtc is licensed
+As SPDX license tags in each source file attest, dtc is licensed
 under the GNU GPL.  The full text of the GPL can be found in the file
 entitled 'GPL' which should be included in this package.  dtc code,
 therefore, may not be incorporated into works which do not have a GPL
@@ -16,10 +16,10 @@
 
 libfdt, however, is GPL/BSD dual-licensed.  That is, it may be used
 either under the terms of the GPL, or under the terms of the 2-clause
-BSD license (aka the ISC license).  The full terms of that license are
-given in the copyright banners of each of the libfdt source files.
-This is, in practice, equivalent to being BSD licensed, since the
-terms of the BSD license are strictly more permissive than the GPL.
+BSD license (aka the ISC license).  The full terms of that license can
+be found are in the file entitled 'BSD-2-Clause'. This is, in
+practice, equivalent to being BSD licensed, since the terms of the BSD
+license are strictly more permissive than the GPL.
 
 I made the decision to license libfdt in this way because I want to
 encourage widespread and correct usage of flattened device trees,
@@ -33,7 +33,7 @@
 believe the goal of allowing libfdt to be widely used is more
 important than avoiding that.  libfdt is quite small, and hardly
 rocket science; so the incentive for such impolite behaviour is small,
-and the inconvenience caused therby is not dire.
+and the inconvenience caused thereby is not dire.
 
 Licenses such as the LGPL which would allow code to be used in non-GPL
 software, but also require contributions to be returned were
diff --git a/checks.c b/checks.c
index afabf64..b7955db 100644
--- a/checks.c
+++ b/checks.c
@@ -1,24 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2007.
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
- *                                                                   USA
  */
 
 #include "dtc.h"
+#include "srcpos.h"
 
 #ifdef TRACE_CHECKS
 #define TRACE(c, ...) \
@@ -53,49 +39,98 @@
 	struct check **prereq;
 };
 
-#define CHECK_ENTRY(_nm, _fn, _d, _w, _e, ...)	       \
-	static struct check *_nm##_prereqs[] = { __VA_ARGS__ }; \
-	static struct check _nm = { \
-		.name = #_nm, \
-		.fn = (_fn), \
-		.data = (_d), \
-		.warn = (_w), \
-		.error = (_e), \
+#define CHECK_ENTRY(nm_, fn_, d_, w_, e_, ...)	       \
+	static struct check *nm_##_prereqs[] = { __VA_ARGS__ }; \
+	static struct check nm_ = { \
+		.name = #nm_, \
+		.fn = (fn_), \
+		.data = (d_), \
+		.warn = (w_), \
+		.error = (e_), \
 		.status = UNCHECKED, \
-		.num_prereqs = ARRAY_SIZE(_nm##_prereqs), \
-		.prereq = _nm##_prereqs, \
+		.num_prereqs = ARRAY_SIZE(nm_##_prereqs), \
+		.prereq = nm_##_prereqs, \
 	};
-#define WARNING(_nm, _fn, _d, ...) \
-	CHECK_ENTRY(_nm, _fn, _d, true, false, __VA_ARGS__)
-#define ERROR(_nm, _fn, _d, ...) \
-	CHECK_ENTRY(_nm, _fn, _d, false, true, __VA_ARGS__)
-#define CHECK(_nm, _fn, _d, ...) \
-	CHECK_ENTRY(_nm, _fn, _d, false, false, __VA_ARGS__)
+#define WARNING(nm_, fn_, d_, ...) \
+	CHECK_ENTRY(nm_, fn_, d_, true, false, __VA_ARGS__)
+#define ERROR(nm_, fn_, d_, ...) \
+	CHECK_ENTRY(nm_, fn_, d_, false, true, __VA_ARGS__)
+#define CHECK(nm_, fn_, d_, ...) \
+	CHECK_ENTRY(nm_, fn_, d_, false, false, __VA_ARGS__)
 
-static inline void  PRINTF(3, 4) check_msg(struct check *c, struct dt_info *dti,
+static inline void  PRINTF(5, 6) check_msg(struct check *c, struct dt_info *dti,
+					   struct node *node,
+					   struct property *prop,
 					   const char *fmt, ...)
 {
 	va_list ap;
-	va_start(ap, fmt);
+	char *str = NULL;
+	struct srcpos *pos = NULL;
+	char *file_str;
 
-	if ((c->warn && (quiet < 1))
-	    || (c->error && (quiet < 2))) {
-		fprintf(stderr, "%s: %s (%s): ",
-			strcmp(dti->outname, "-") ? dti->outname : "<stdout>",
-			(c->error) ? "ERROR" : "Warning", c->name);
-		vfprintf(stderr, fmt, ap);
-		fprintf(stderr, "\n");
+	if (!(c->warn && (quiet < 1)) && !(c->error && (quiet < 2)))
+		return;
+
+	if (prop && prop->srcpos)
+		pos = prop->srcpos;
+	else if (node && node->srcpos)
+		pos = node->srcpos;
+
+	if (pos) {
+		file_str = srcpos_string(pos);
+		xasprintf(&str, "%s", file_str);
+		free(file_str);
+	} else if (streq(dti->outname, "-")) {
+		xasprintf(&str, "<stdout>");
+	} else {
+		xasprintf(&str, "%s", dti->outname);
 	}
+
+	xasprintf_append(&str, ": %s (%s): ",
+			(c->error) ? "ERROR" : "Warning", c->name);
+
+	if (node) {
+		if (prop)
+			xasprintf_append(&str, "%s:%s: ", node->fullpath, prop->name);
+		else
+			xasprintf_append(&str, "%s: ", node->fullpath);
+	}
+
+	va_start(ap, fmt);
+	xavsprintf_append(&str, fmt, ap);
 	va_end(ap);
+
+	xasprintf_append(&str, "\n");
+
+	if (!prop && pos) {
+		pos = node->srcpos;
+		while (pos->next) {
+			pos = pos->next;
+
+			file_str = srcpos_string(pos);
+			xasprintf_append(&str, "  also defined at %s\n", file_str);
+			free(file_str);
+		}
+	}
+
+	fputs(str, stderr);
 }
 
-#define FAIL(c, dti, ...)						\
+#define FAIL(c, dti, node, ...)						\
 	do {								\
 		TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__);	\
 		(c)->status = FAILED;					\
-		check_msg((c), dti, __VA_ARGS__);			\
+		check_msg((c), dti, node, NULL, __VA_ARGS__);		\
 	} while (0)
 
+#define FAIL_PROP(c, dti, node, prop, ...)				\
+	do {								\
+		TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__);	\
+		(c)->status = FAILED;					\
+		check_msg((c), dti, node, prop, __VA_ARGS__);		\
+	} while (0)
+
+
 static void check_nodes_props(struct check *c, struct dt_info *dti, struct node *node)
 {
 	struct node *child;
@@ -126,7 +161,7 @@
 		error = error || run_check(prq, dti);
 		if (prq->status != PASSED) {
 			c->status = PREREQ;
-			check_msg(c, dti, "Failed prerequisite '%s'",
+			check_msg(c, dti, NULL, NULL, "Failed prerequisite '%s'",
 				  c->prereq[i]->name);
 		}
 	}
@@ -156,7 +191,7 @@
 static inline void check_always_fail(struct check *c, struct dt_info *dti,
 				     struct node *node)
 {
-	FAIL(c, dti, "always_fail check");
+	FAIL(c, dti, node, "always_fail check");
 }
 CHECK(always_fail, check_always_fail, NULL);
 
@@ -171,14 +206,42 @@
 		return; /* Not present, assumed ok */
 
 	if (!data_is_one_string(prop->val))
-		FAIL(c, dti, "\"%s\" property in %s is not a string",
-		     propname, node->fullpath);
+		FAIL_PROP(c, dti, node, prop, "property is not a string");
 }
 #define WARNING_IF_NOT_STRING(nm, propname) \
 	WARNING(nm, check_is_string, (propname))
 #define ERROR_IF_NOT_STRING(nm, propname) \
 	ERROR(nm, check_is_string, (propname))
 
+static void check_is_string_list(struct check *c, struct dt_info *dti,
+				 struct node *node)
+{
+	int rem, l;
+	struct property *prop;
+	char *propname = c->data;
+	char *str;
+
+	prop = get_property(node, propname);
+	if (!prop)
+		return; /* Not present, assumed ok */
+
+	str = prop->val.val;
+	rem = prop->val.len;
+	while (rem > 0) {
+		l = strnlen(str, rem);
+		if (l == rem) {
+			FAIL_PROP(c, dti, node, prop, "property is not a string list");
+			break;
+		}
+		rem -= l + 1;
+		str += l + 1;
+	}
+}
+#define WARNING_IF_NOT_STRING_LIST(nm, propname) \
+	WARNING(nm, check_is_string_list, (propname))
+#define ERROR_IF_NOT_STRING_LIST(nm, propname) \
+	ERROR(nm, check_is_string_list, (propname))
+
 static void check_is_cell(struct check *c, struct dt_info *dti,
 			  struct node *node)
 {
@@ -190,8 +253,7 @@
 		return; /* Not present, assumed ok */
 
 	if (prop->val.len != sizeof(cell_t))
-		FAIL(c, dti, "\"%s\" property in %s is not a single cell",
-		     propname, node->fullpath);
+		FAIL_PROP(c, dti, node, prop, "property is not a single cell");
 }
 #define WARNING_IF_NOT_CELL(nm, propname) \
 	WARNING(nm, check_is_cell, (propname))
@@ -212,8 +274,7 @@
 		     child2;
 		     child2 = child2->next_sibling)
 			if (streq(child->name, child2->name))
-				FAIL(c, dti, "Duplicate node name %s",
-				     child->fullpath);
+				FAIL(c, dti, child2, "Duplicate node name");
 }
 ERROR(duplicate_node_names, check_duplicate_node_names, NULL);
 
@@ -227,8 +288,7 @@
 			if (prop2->deleted)
 				continue;
 			if (streq(prop->name, prop2->name))
-				FAIL(c, dti, "Duplicate property name %s in %s",
-				     prop->name, node->fullpath);
+				FAIL_PROP(c, dti, node, prop, "Duplicate property name");
 		}
 	}
 }
@@ -246,8 +306,8 @@
 	int n = strspn(node->name, c->data);
 
 	if (n < strlen(node->name))
-		FAIL(c, dti, "Bad character '%c' in node %s",
-		     node->name[n], node->fullpath);
+		FAIL(c, dti, node, "Bad character '%c' in node name",
+		     node->name[n]);
 }
 ERROR(node_name_chars, check_node_name_chars, PROPNODECHARS "@");
 
@@ -257,8 +317,8 @@
 	int n = strspn(node->name, c->data);
 
 	if (n < node->basenamelen)
-		FAIL(c, dti, "Character '%c' not recommended in node %s",
-		     node->name[n], node->fullpath);
+		FAIL(c, dti, node, "Character '%c' not recommended in node name",
+		     node->name[n]);
 }
 CHECK(node_name_chars_strict, check_node_name_chars_strict, PROPNODECHARSSTRICT);
 
@@ -266,8 +326,7 @@
 				   struct node *node)
 {
 	if (strchr(get_unitname(node), '@'))
-		FAIL(c, dti, "Node %s has multiple '@' characters in name",
-		     node->fullpath);
+		FAIL(c, dti, node, "multiple '@' characters in node name");
 }
 ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars);
 
@@ -277,6 +336,11 @@
 	const char *unitname = get_unitname(node);
 	struct property *prop = get_property(node, "reg");
 
+	if (get_subnode(node, "__overlay__")) {
+		/* HACK: Overlay fragments are a special case */
+		return;
+	}
+
 	if (!prop) {
 		prop = get_property(node, "ranges");
 		if (prop && !prop->val.len)
@@ -285,12 +349,10 @@
 
 	if (prop) {
 		if (!unitname[0])
-			FAIL(c, dti, "Node %s has a reg or ranges property, but no unit name",
-			    node->fullpath);
+			FAIL(c, dti, node, "node has a reg or ranges property, but no unit name");
 	} else {
 		if (unitname[0])
-			FAIL(c, dti, "Node %s has a unit name, but no reg property",
-			    node->fullpath);
+			FAIL(c, dti, node, "node has a unit name, but no reg or ranges property");
 	}
 }
 WARNING(unit_address_vs_reg, check_unit_address_vs_reg, NULL);
@@ -304,8 +366,8 @@
 		int n = strspn(prop->name, c->data);
 
 		if (n < strlen(prop->name))
-			FAIL(c, dti, "Bad character '%c' in property name \"%s\", node %s",
-			     prop->name[n], prop->name, node->fullpath);
+			FAIL_PROP(c, dti, node, prop, "Bad character '%c' in property name",
+				  prop->name[n]);
 	}
 }
 ERROR(property_name_chars, check_property_name_chars, PROPNODECHARS);
@@ -336,8 +398,8 @@
 			n = strspn(name, c->data);
 		}
 		if (n < strlen(name))
-			FAIL(c, dti, "Character '%c' not recommended in property name \"%s\", node %s",
-			     name[n], prop->name, node->fullpath);
+			FAIL_PROP(c, dti, node, prop, "Character '%c' not recommended in property name",
+				  name[n]);
 	}
 }
 CHECK(property_name_chars_strict, check_property_name_chars_strict, PROPNODECHARSSTRICT);
@@ -370,7 +432,7 @@
 		return;
 
 	if ((othernode != node) || (otherprop != prop) || (othermark != mark))
-		FAIL(c, dti, "Duplicate label '%s' on " DESCLABEL_FMT
+		FAIL(c, dti, node, "Duplicate label '%s' on " DESCLABEL_FMT
 		     " and " DESCLABEL_FMT,
 		     label, DESCLABEL_ARGS(node, prop, mark),
 		     DESCLABEL_ARGS(othernode, otherprop, othermark));
@@ -410,8 +472,8 @@
 		return 0;
 
 	if (prop->val.len != sizeof(cell_t)) {
-		FAIL(c, dti, "%s has bad length (%d) %s property",
-		     node->fullpath, prop->val.len, prop->name);
+		FAIL_PROP(c, dti, node, prop, "bad length (%d) %s property",
+			  prop->val.len, prop->name);
 		return 0;
 	}
 
@@ -422,8 +484,8 @@
 			/* "Set this node's phandle equal to some
 			 * other node's phandle".  That's nonsensical
 			 * by construction. */ {
-			FAIL(c, dti, "%s in %s is a reference to another node",
-			     prop->name, node->fullpath);
+			FAIL(c, dti, node, "%s is a reference to another node",
+			     prop->name);
 		}
 		/* But setting this node's phandle equal to its own
 		 * phandle is allowed - that means allocate a unique
@@ -436,8 +498,8 @@
 	phandle = propval_cell(prop);
 
 	if ((phandle == 0) || (phandle == -1)) {
-		FAIL(c, dti, "%s has bad value (0x%x) in %s property",
-		     node->fullpath, phandle, prop->name);
+		FAIL_PROP(c, dti, node, prop, "bad value (0x%x) in %s property",
+		     phandle, prop->name);
 		return 0;
 	}
 
@@ -463,16 +525,16 @@
 		return;
 
 	if (linux_phandle && phandle && (phandle != linux_phandle))
-		FAIL(c, dti, "%s has mismatching 'phandle' and 'linux,phandle'"
-		     " properties", node->fullpath);
+		FAIL(c, dti, node, "mismatching 'phandle' and 'linux,phandle'"
+		     " properties");
 
 	if (linux_phandle && !phandle)
 		phandle = linux_phandle;
 
 	other = get_node_by_phandle(root, phandle);
 	if (other && (other != node)) {
-		FAIL(c, dti, "%s has duplicated phandle 0x%x (seen before at %s)",
-		     node->fullpath, phandle, other->fullpath);
+		FAIL(c, dti, node, "duplicated phandle 0x%x (seen before at %s)",
+		     phandle, other->fullpath);
 		return;
 	}
 
@@ -496,8 +558,8 @@
 
 	if ((prop->val.len != node->basenamelen+1)
 	    || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) {
-		FAIL(c, dti, "\"name\" property in %s is incorrect (\"%s\" instead"
-		     " of base node name)", node->fullpath, prop->val.val);
+		FAIL(c, dti, node, "\"name\" property is incorrect (\"%s\" instead"
+		     " of base node name)", prop->val.val);
 	} else {
 		/* The name property is correct, and therefore redundant.
 		 * Delete it */
@@ -531,7 +593,7 @@
 			refnode = get_node_by_ref(dt, m->ref);
 			if (! refnode) {
 				if (!(dti->dtsflags & DTSF_PLUGIN))
-					FAIL(c, dti, "Reference to non-existent node or "
+					FAIL(c, dti, node, "Reference to non-existent node or "
 							"label \"%s\"\n", m->ref);
 				else /* mark the entry as unresolved */
 					*((fdt32_t *)(prop->val.val + m->offset)) =
@@ -541,6 +603,8 @@
 
 			phandle = get_node_phandle(dt, refnode);
 			*((fdt32_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
+
+			reference_node(refnode);
 		}
 	}
 }
@@ -563,7 +627,7 @@
 
 			refnode = get_node_by_ref(dt, m->ref);
 			if (!refnode) {
-				FAIL(c, dti, "Reference to non-existent node or label \"%s\"\n",
+				FAIL(c, dti, node, "Reference to non-existent node or label \"%s\"\n",
 				     m->ref);
 				continue;
 			}
@@ -571,11 +635,23 @@
 			path = refnode->fullpath;
 			prop->val = data_insert_at_marker(prop->val, m, path,
 							  strlen(path) + 1);
+
+			reference_node(refnode);
 		}
 	}
 }
 ERROR(path_references, fixup_path_references, NULL, &duplicate_node_names);
 
+static void fixup_omit_unused_nodes(struct check *c, struct dt_info *dti,
+				    struct node *node)
+{
+	if (generate_symbols && node->labels)
+		return;
+	if (node->omit_if_unused && !node->is_referenced)
+		delete_node(node);
+}
+ERROR(omit_unused_nodes, fixup_omit_unused_nodes, NULL, &phandle_references, &path_references);
+
 /*
  * Semantic checks
  */
@@ -586,6 +662,50 @@
 WARNING_IF_NOT_STRING(device_type_is_string, "device_type");
 WARNING_IF_NOT_STRING(model_is_string, "model");
 WARNING_IF_NOT_STRING(status_is_string, "status");
+WARNING_IF_NOT_STRING(label_is_string, "label");
+
+WARNING_IF_NOT_STRING_LIST(compatible_is_string_list, "compatible");
+
+static void check_names_is_string_list(struct check *c, struct dt_info *dti,
+				       struct node *node)
+{
+	struct property *prop;
+
+	for_each_property(node, prop) {
+		const char *s = strrchr(prop->name, '-');
+		if (!s || !streq(s, "-names"))
+			continue;
+
+		c->data = prop->name;
+		check_is_string_list(c, dti, node);
+	}
+}
+WARNING(names_is_string_list, check_names_is_string_list, NULL);
+
+static void check_alias_paths(struct check *c, struct dt_info *dti,
+				    struct node *node)
+{
+	struct property *prop;
+
+	if (!streq(node->name, "aliases"))
+		return;
+
+	for_each_property(node, prop) {
+		if (streq(prop->name, "phandle")
+		    || streq(prop->name, "linux,phandle")) {
+			continue;
+		}
+
+		if (!prop->val.val || !get_node_by_path(dti->dt, prop->val.val)) {
+			FAIL_PROP(c, dti, node, prop, "aliases property is not a valid node (%s)",
+				  prop->val.val);
+			continue;
+		}
+		if (strspn(prop->name, LOWERCASE DIGITS "-") != strlen(prop->name))
+			FAIL(c, dti, node, "aliases property name must include only lowercase and '-'");
+	}
+}
+WARNING(alias_paths, check_alias_paths, NULL);
 
 static void fixup_addr_size_cells(struct check *c, struct dt_info *dti,
 				  struct node *node)
@@ -622,21 +742,21 @@
 		return; /* No "reg", that's fine */
 
 	if (!node->parent) {
-		FAIL(c, dti, "Root node has a \"reg\" property");
+		FAIL(c, dti, node, "Root node has a \"reg\" property");
 		return;
 	}
 
 	if (prop->val.len == 0)
-		FAIL(c, dti, "\"reg\" property in %s is empty", node->fullpath);
+		FAIL_PROP(c, dti, node, prop, "property is empty");
 
 	addr_cells = node_addr_cells(node->parent);
 	size_cells = node_size_cells(node->parent);
 	entrylen = (addr_cells + size_cells) * sizeof(cell_t);
 
 	if (!entrylen || (prop->val.len % entrylen) != 0)
-		FAIL(c, dti, "\"reg\" property in %s has invalid length (%d bytes) "
-		     "(#address-cells == %d, #size-cells == %d)",
-		     node->fullpath, prop->val.len, addr_cells, size_cells);
+		FAIL_PROP(c, dti, node, prop, "property has invalid length (%d bytes) "
+			  "(#address-cells == %d, #size-cells == %d)",
+			  prop->val.len, addr_cells, size_cells);
 }
 WARNING(reg_format, check_reg_format, NULL, &addr_size_cells);
 
@@ -645,13 +765,15 @@
 {
 	struct property *prop;
 	int c_addr_cells, p_addr_cells, c_size_cells, p_size_cells, entrylen;
+	const char *ranges = c->data;
 
-	prop = get_property(node, "ranges");
+	prop = get_property(node, ranges);
 	if (!prop)
 		return;
 
 	if (!node->parent) {
-		FAIL(c, dti, "Root node has a \"ranges\" property");
+		FAIL_PROP(c, dti, node, prop, "Root node has a \"%s\" property",
+			  ranges);
 		return;
 	}
 
@@ -663,23 +785,24 @@
 
 	if (prop->val.len == 0) {
 		if (p_addr_cells != c_addr_cells)
-			FAIL(c, dti, "%s has empty \"ranges\" property but its "
-			     "#address-cells (%d) differs from %s (%d)",
-			     node->fullpath, c_addr_cells, node->parent->fullpath,
-			     p_addr_cells);
+			FAIL_PROP(c, dti, node, prop, "empty \"%s\" property but its "
+				  "#address-cells (%d) differs from %s (%d)",
+				  ranges, c_addr_cells, node->parent->fullpath,
+				  p_addr_cells);
 		if (p_size_cells != c_size_cells)
-			FAIL(c, dti, "%s has empty \"ranges\" property but its "
-			     "#size-cells (%d) differs from %s (%d)",
-			     node->fullpath, c_size_cells, node->parent->fullpath,
-			     p_size_cells);
+			FAIL_PROP(c, dti, node, prop, "empty \"%s\" property but its "
+				  "#size-cells (%d) differs from %s (%d)",
+				  ranges, c_size_cells, node->parent->fullpath,
+				  p_size_cells);
 	} else if ((prop->val.len % entrylen) != 0) {
-		FAIL(c, dti, "\"ranges\" property in %s has invalid length (%d bytes) "
-		     "(parent #address-cells == %d, child #address-cells == %d, "
-		     "#size-cells == %d)", node->fullpath, prop->val.len,
-		     p_addr_cells, c_addr_cells, c_size_cells);
+		FAIL_PROP(c, dti, node, prop, "\"%s\" property has invalid length (%d bytes) "
+			  "(parent #address-cells == %d, child #address-cells == %d, "
+			  "#size-cells == %d)", ranges, prop->val.len,
+			  p_addr_cells, c_addr_cells, c_size_cells);
 	}
 }
-WARNING(ranges_format, check_ranges_format, NULL, &addr_size_cells);
+WARNING(ranges_format, check_ranges_format, "ranges", &addr_size_cells);
+WARNING(dma_ranges_format, check_ranges_format, "dma-ranges", &addr_size_cells);
 
 static const struct bus_type pci_bus = {
 	.name = "PCI",
@@ -696,41 +819,32 @@
 
 	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);
+	if (!strprefixeq(node->name, node->basenamelen, "pci") &&
+	    !strprefixeq(node->name, node->basenamelen, "pcie"))
+		FAIL(c, dti, node, "node name is not \"pci\" or \"pcie\"");
 
 	prop = get_property(node, "ranges");
 	if (!prop)
-		FAIL(c, dti, "Node %s missing ranges for PCI bridge (or not a bridge)",
-			     node->fullpath);
+		FAIL(c, dti, node, "missing ranges for PCI bridge (or not a bridge)");
 
 	if (node_addr_cells(node) != 3)
-		FAIL(c, dti, "Node %s incorrect #address-cells for PCI bridge",
-			     node->fullpath);
+		FAIL(c, dti, node, "incorrect #address-cells for PCI bridge");
 	if (node_size_cells(node) != 2)
-		FAIL(c, dti, "Node %s incorrect #size-cells for PCI bridge",
-			     node->fullpath);
+		FAIL(c, dti, node, "incorrect #size-cells for PCI bridge");
 
 	prop = get_property(node, "bus-range");
-	if (!prop) {
-		FAIL(c, dti, "Node %s missing bus-range for PCI bridge",
-			     node->fullpath);
+	if (!prop)
 		return;
-	}
+
 	if (prop->val.len != (sizeof(cell_t) * 2)) {
-		FAIL(c, dti, "Node %s bus-range must be 2 cells",
-			     node->fullpath);
+		FAIL_PROP(c, dti, node, prop, "value must be 2 cells");
 		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);
+		FAIL_PROP(c, dti, node, prop, "1st cell must be less than or equal to 2nd cell");
 	if (fdt32_to_cpu(cells[1]) > 0xff)
-		FAIL(c, dti, "Node %s bus-range maximum bus number must be less than 256",
-			     node->fullpath);
+		FAIL_PROP(c, dti, node, prop, "maximum bus number must be less than 256");
 }
 WARNING(pci_bridge, check_pci_bridge, NULL,
 	&device_type_is_string, &addr_size_cells);
@@ -760,8 +874,8 @@
 		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);
+		FAIL_PROP(c, dti, node, prop, "PCI bus number %d out of range, expected (%d - %d)",
+			  bus_num, min_bus, max_bus);
 }
 WARNING(pci_device_bus_num, check_pci_device_bus_num, NULL, &reg_format, &pci_bridge);
 
@@ -778,25 +892,22 @@
 
 	prop = get_property(node, "reg");
 	if (!prop) {
-		FAIL(c, dti, "Node %s missing PCI reg property", node->fullpath);
+		FAIL(c, dti, node, "missing PCI reg property");
 		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);
+		FAIL_PROP(c, dti, node, prop, "PCI reg config space address cells 2 and 3 must be 0");
 
 	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);
+		FAIL_PROP(c, dti, node, prop, "PCI reg address is not configuration space");
 	if (reg & 0x000000ff)
-		FAIL(c, dti, "Node %s PCI reg config space address register number must be 0",
-			     node->fullpath);
+		FAIL_PROP(c, dti, node, prop, "PCI reg config space address register number must be 0");
 
 	if (func == 0) {
 		snprintf(unit_addr, sizeof(unit_addr), "%x", dev);
@@ -808,8 +919,8 @@
 	if (streq(unitname, unit_addr))
 		return;
 
-	FAIL(c, dti, "Node %s PCI unit address format error, expected \"%s\"",
-	     node->fullpath, unit_addr);
+	FAIL(c, dti, node, "PCI unit address format error, expected \"%s\"",
+	     unit_addr);
 }
 WARNING(pci_device_reg, check_pci_device_reg, NULL, &reg_format, &pci_bridge);
 
@@ -828,7 +939,7 @@
 
 	for (str = prop->val.val, end = str + prop->val.len; str < end;
 	     str += strnlen(str, end - str) + 1) {
-		if (strneq(str, compat, end - str))
+		if (streq(str, compat))
 			return true;
 	}
 	return false;
@@ -839,7 +950,8 @@
 	if (node_is_compatible(node, "simple-bus"))
 		node->bus = &simple_bus;
 }
-WARNING(simple_bus_bridge, check_simple_bus_bridge, NULL, &addr_size_cells);
+WARNING(simple_bus_bridge, check_simple_bus_bridge, NULL,
+	&addr_size_cells, &compatible_is_string_list);
 
 static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct node *node)
 {
@@ -865,7 +977,7 @@
 
 	if (!cells) {
 		if (node->parent->parent && !(node->bus == &simple_bus))
-			FAIL(c, dti, "Node %s missing or empty reg/ranges property", node->fullpath);
+			FAIL(c, dti, node, "missing or empty reg/ranges property");
 		return;
 	}
 
@@ -875,11 +987,164 @@
 
 	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);
+		FAIL(c, dti, node, "simple-bus unit address format error, expected \"%s\"",
+		     unit_addr);
 }
 WARNING(simple_bus_reg, check_simple_bus_reg, NULL, &reg_format, &simple_bus_bridge);
 
+static const struct bus_type i2c_bus = {
+	.name = "i2c-bus",
+};
+
+static void check_i2c_bus_bridge(struct check *c, struct dt_info *dti, struct node *node)
+{
+	if (strprefixeq(node->name, node->basenamelen, "i2c-bus") ||
+	    strprefixeq(node->name, node->basenamelen, "i2c-arb")) {
+		node->bus = &i2c_bus;
+	} else if (strprefixeq(node->name, node->basenamelen, "i2c")) {
+		struct node *child;
+		for_each_child(node, child) {
+			if (strprefixeq(child->name, node->basenamelen, "i2c-bus"))
+				return;
+		}
+		node->bus = &i2c_bus;
+	} else
+		return;
+
+	if (!node->children)
+		return;
+
+	if (node_addr_cells(node) != 1)
+		FAIL(c, dti, node, "incorrect #address-cells for I2C bus");
+	if (node_size_cells(node) != 0)
+		FAIL(c, dti, node, "incorrect #size-cells for I2C bus");
+
+}
+WARNING(i2c_bus_bridge, check_i2c_bus_bridge, NULL, &addr_size_cells);
+
+#define I2C_OWN_SLAVE_ADDRESS	(1U << 30)
+#define I2C_TEN_BIT_ADDRESS	(1U << 31)
+
+static void check_i2c_bus_reg(struct check *c, struct dt_info *dti, struct node *node)
+{
+	struct property *prop;
+	const char *unitname = get_unitname(node);
+	char unit_addr[17];
+	uint32_t reg = 0;
+	int len;
+	cell_t *cells = NULL;
+
+	if (!node->parent || (node->parent->bus != &i2c_bus))
+		return;
+
+	prop = get_property(node, "reg");
+	if (prop)
+		cells = (cell_t *)prop->val.val;
+
+	if (!cells) {
+		FAIL(c, dti, node, "missing or empty reg property");
+		return;
+	}
+
+	reg = fdt32_to_cpu(*cells);
+	/* Ignore I2C_OWN_SLAVE_ADDRESS */
+	reg &= ~I2C_OWN_SLAVE_ADDRESS;
+	snprintf(unit_addr, sizeof(unit_addr), "%x", reg);
+	if (!streq(unitname, unit_addr))
+		FAIL(c, dti, node, "I2C bus unit address format error, expected \"%s\"",
+		     unit_addr);
+
+	for (len = prop->val.len; len > 0; len -= 4) {
+		reg = fdt32_to_cpu(*(cells++));
+		/* Ignore I2C_OWN_SLAVE_ADDRESS */
+		reg &= ~I2C_OWN_SLAVE_ADDRESS;
+
+		if ((reg & I2C_TEN_BIT_ADDRESS) && ((reg & ~I2C_TEN_BIT_ADDRESS) > 0x3ff))
+			FAIL_PROP(c, dti, node, prop, "I2C address must be less than 10-bits, got \"0x%x\"",
+				  reg);
+		else if (reg > 0x7f)
+			FAIL_PROP(c, dti, node, prop, "I2C address must be less than 7-bits, got \"0x%x\". Set I2C_TEN_BIT_ADDRESS for 10 bit addresses or fix the property",
+				  reg);
+	}
+}
+WARNING(i2c_bus_reg, check_i2c_bus_reg, NULL, &reg_format, &i2c_bus_bridge);
+
+static const struct bus_type spi_bus = {
+	.name = "spi-bus",
+};
+
+static void check_spi_bus_bridge(struct check *c, struct dt_info *dti, struct node *node)
+{
+	int spi_addr_cells = 1;
+
+	if (strprefixeq(node->name, node->basenamelen, "spi")) {
+		node->bus = &spi_bus;
+	} else {
+		/* Try to detect SPI buses which don't have proper node name */
+		struct node *child;
+
+		if (node_addr_cells(node) != 1 || node_size_cells(node) != 0)
+			return;
+
+		for_each_child(node, child) {
+			struct property *prop;
+			for_each_property(child, prop) {
+				if (strprefixeq(prop->name, 4, "spi-")) {
+					node->bus = &spi_bus;
+					break;
+				}
+			}
+			if (node->bus == &spi_bus)
+				break;
+		}
+
+		if (node->bus == &spi_bus && get_property(node, "reg"))
+			FAIL(c, dti, node, "node name for SPI buses should be 'spi'");
+	}
+	if (node->bus != &spi_bus || !node->children)
+		return;
+
+	if (get_property(node, "spi-slave"))
+		spi_addr_cells = 0;
+	if (node_addr_cells(node) != spi_addr_cells)
+		FAIL(c, dti, node, "incorrect #address-cells for SPI bus");
+	if (node_size_cells(node) != 0)
+		FAIL(c, dti, node, "incorrect #size-cells for SPI bus");
+
+}
+WARNING(spi_bus_bridge, check_spi_bus_bridge, NULL, &addr_size_cells);
+
+static void check_spi_bus_reg(struct check *c, struct dt_info *dti, struct node *node)
+{
+	struct property *prop;
+	const char *unitname = get_unitname(node);
+	char unit_addr[9];
+	uint32_t reg = 0;
+	cell_t *cells = NULL;
+
+	if (!node->parent || (node->parent->bus != &spi_bus))
+		return;
+
+	if (get_property(node->parent, "spi-slave"))
+		return;
+
+	prop = get_property(node, "reg");
+	if (prop)
+		cells = (cell_t *)prop->val.val;
+
+	if (!cells) {
+		FAIL(c, dti, node, "missing or empty reg property");
+		return;
+	}
+
+	reg = fdt32_to_cpu(*cells);
+	snprintf(unit_addr, sizeof(unit_addr), "%x", reg);
+	if (!streq(unitname, unit_addr))
+		FAIL(c, dti, node, "SPI bus unit address format error, expected \"%s\"",
+		     unit_addr);
+}
+WARNING(spi_bus_reg, check_spi_bus_reg, NULL, &reg_format, &spi_bus_bridge);
+
 static void check_unit_address_format(struct check *c, struct dt_info *dti,
 				      struct node *node)
 {
@@ -892,14 +1157,12 @@
 		return;
 
 	if (!strncmp(unitname, "0x", 2)) {
-		FAIL(c, dti, "Node %s unit name should not have leading \"0x\"",
-		    node->fullpath);
+		FAIL(c, dti, node, "unit name should not have leading \"0x\"");
 		/* 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);
+		FAIL(c, dti, node, "unit name should not have leading 0s");
 }
 WARNING(unit_address_format, check_unit_address_format, NULL,
 	&node_name_format, &pci_bridge, &simple_bus_bridge);
@@ -922,16 +1185,104 @@
 		return;
 
 	if (node->parent->addr_cells == -1)
-		FAIL(c, dti, "Relying on default #address-cells value for %s",
-		     node->fullpath);
+		FAIL(c, dti, node, "Relying on default #address-cells value");
 
 	if (node->parent->size_cells == -1)
-		FAIL(c, dti, "Relying on default #size-cells value for %s",
-		     node->fullpath);
+		FAIL(c, dti, node, "Relying on default #size-cells value");
 }
 WARNING(avoid_default_addr_size, check_avoid_default_addr_size, NULL,
 	&addr_size_cells);
 
+static void check_avoid_unnecessary_addr_size(struct check *c, struct dt_info *dti,
+					      struct node *node)
+{
+	struct property *prop;
+	struct node *child;
+	bool has_reg = false;
+
+	if (!node->parent || node->addr_cells < 0 || node->size_cells < 0)
+		return;
+
+	if (get_property(node, "ranges") || !node->children)
+		return;
+
+	for_each_child(node, child) {
+		prop = get_property(child, "reg");
+		if (prop)
+			has_reg = true;
+	}
+
+	if (!has_reg)
+		FAIL(c, dti, node, "unnecessary #address-cells/#size-cells without \"ranges\" or child \"reg\" property");
+}
+WARNING(avoid_unnecessary_addr_size, check_avoid_unnecessary_addr_size, NULL, &avoid_default_addr_size);
+
+static bool node_is_disabled(struct node *node)
+{
+	struct property *prop;
+
+	prop = get_property(node, "status");
+	if (prop) {
+		char *str = prop->val.val;
+		if (streq("disabled", str))
+			return true;
+	}
+
+	return false;
+}
+
+static void check_unique_unit_address_common(struct check *c,
+						struct dt_info *dti,
+						struct node *node,
+						bool disable_check)
+{
+	struct node *childa;
+
+	if (node->addr_cells < 0 || node->size_cells < 0)
+		return;
+
+	if (!node->children)
+		return;
+
+	for_each_child(node, childa) {
+		struct node *childb;
+		const char *addr_a = get_unitname(childa);
+
+		if (!strlen(addr_a))
+			continue;
+
+		if (disable_check && node_is_disabled(childa))
+			continue;
+
+		for_each_child(node, childb) {
+			const char *addr_b = get_unitname(childb);
+			if (childa == childb)
+				break;
+
+			if (disable_check && node_is_disabled(childb))
+				continue;
+
+			if (streq(addr_a, addr_b))
+				FAIL(c, dti, childb, "duplicate unit-address (also used in node %s)", childa->fullpath);
+		}
+	}
+}
+
+static void check_unique_unit_address(struct check *c, struct dt_info *dti,
+					      struct node *node)
+{
+	check_unique_unit_address_common(c, dti, node, false);
+}
+WARNING(unique_unit_address, check_unique_unit_address, NULL, &avoid_default_addr_size);
+
+static void check_unique_unit_address_if_enabled(struct check *c, struct dt_info *dti,
+					      struct node *node)
+{
+	check_unique_unit_address_common(c, dti, node, true);
+}
+CHECK_ENTRY(unique_unit_address_if_enabled, check_unique_unit_address_if_enabled,
+	    NULL, false, false, &avoid_default_addr_size);
+
 static void check_obsolete_chosen_interrupt_controller(struct check *c,
 						       struct dt_info *dti,
 						       struct node *node)
@@ -950,12 +1301,500 @@
 
 	prop = get_property(chosen, "interrupt-controller");
 	if (prop)
-		FAIL(c, dti, "/chosen has obsolete \"interrupt-controller\" "
-		     "property");
+		FAIL_PROP(c, dti, node, prop,
+			  "/chosen has obsolete \"interrupt-controller\" property");
 }
 WARNING(obsolete_chosen_interrupt_controller,
 	check_obsolete_chosen_interrupt_controller, NULL);
 
+static void check_chosen_node_is_root(struct check *c, struct dt_info *dti,
+				      struct node *node)
+{
+	if (!streq(node->name, "chosen"))
+		return;
+
+	if (node->parent != dti->dt)
+		FAIL(c, dti, node, "chosen node must be at root node");
+}
+WARNING(chosen_node_is_root, check_chosen_node_is_root, NULL);
+
+static void check_chosen_node_bootargs(struct check *c, struct dt_info *dti,
+				       struct node *node)
+{
+	struct property *prop;
+
+	if (!streq(node->name, "chosen"))
+		return;
+
+	prop = get_property(node, "bootargs");
+	if (!prop)
+		return;
+
+	c->data = prop->name;
+	check_is_string(c, dti, node);
+}
+WARNING(chosen_node_bootargs, check_chosen_node_bootargs, NULL);
+
+static void check_chosen_node_stdout_path(struct check *c, struct dt_info *dti,
+					  struct node *node)
+{
+	struct property *prop;
+
+	if (!streq(node->name, "chosen"))
+		return;
+
+	prop = get_property(node, "stdout-path");
+	if (!prop) {
+		prop = get_property(node, "linux,stdout-path");
+		if (!prop)
+			return;
+		FAIL_PROP(c, dti, node, prop, "Use 'stdout-path' instead");
+	}
+
+	c->data = prop->name;
+	check_is_string(c, dti, node);
+}
+WARNING(chosen_node_stdout_path, check_chosen_node_stdout_path, NULL);
+
+struct provider {
+	const char *prop_name;
+	const char *cell_name;
+	bool optional;
+};
+
+static void check_property_phandle_args(struct check *c,
+					  struct dt_info *dti,
+				          struct node *node,
+				          struct property *prop,
+				          const struct provider *provider)
+{
+	struct node *root = dti->dt;
+	int cell, cellsize = 0;
+
+	if (prop->val.len % sizeof(cell_t)) {
+		FAIL_PROP(c, dti, node, prop,
+			  "property size (%d) is invalid, expected multiple of %zu",
+			  prop->val.len, sizeof(cell_t));
+		return;
+	}
+
+	for (cell = 0; cell < prop->val.len / sizeof(cell_t); cell += cellsize + 1) {
+		struct node *provider_node;
+		struct property *cellprop;
+		int phandle;
+
+		phandle = propval_cell_n(prop, cell);
+		/*
+		 * Some bindings use a cell value 0 or -1 to skip over optional
+		 * entries when each index position has a specific definition.
+		 */
+		if (phandle == 0 || phandle == -1) {
+			/* Give up if this is an overlay with external references */
+			if (dti->dtsflags & DTSF_PLUGIN)
+				break;
+
+			cellsize = 0;
+			continue;
+		}
+
+		/* If we have markers, verify the current cell is a phandle */
+		if (prop->val.markers) {
+			struct marker *m = prop->val.markers;
+			for_each_marker_of_type(m, REF_PHANDLE) {
+				if (m->offset == (cell * sizeof(cell_t)))
+					break;
+			}
+			if (!m)
+				FAIL_PROP(c, dti, node, prop,
+					  "cell %d is not a phandle reference",
+					  cell);
+		}
+
+		provider_node = get_node_by_phandle(root, phandle);
+		if (!provider_node) {
+			FAIL_PROP(c, dti, node, prop,
+				  "Could not get phandle node for (cell %d)",
+				  cell);
+			break;
+		}
+
+		cellprop = get_property(provider_node, provider->cell_name);
+		if (cellprop) {
+			cellsize = propval_cell(cellprop);
+		} else if (provider->optional) {
+			cellsize = 0;
+		} else {
+			FAIL(c, dti, node, "Missing property '%s' in node %s or bad phandle (referred from %s[%d])",
+			     provider->cell_name,
+			     provider_node->fullpath,
+			     prop->name, cell);
+			break;
+		}
+
+		if (prop->val.len < ((cell + cellsize + 1) * sizeof(cell_t))) {
+			FAIL_PROP(c, dti, node, prop,
+				  "property size (%d) too small for cell size %d",
+				  prop->val.len, cellsize);
+		}
+	}
+}
+
+static void check_provider_cells_property(struct check *c,
+					  struct dt_info *dti,
+				          struct node *node)
+{
+	struct provider *provider = c->data;
+	struct property *prop;
+
+	prop = get_property(node, provider->prop_name);
+	if (!prop)
+		return;
+
+	check_property_phandle_args(c, dti, node, prop, provider);
+}
+#define WARNING_PROPERTY_PHANDLE_CELLS(nm, propname, cells_name, ...) \
+	static struct provider nm##_provider = { (propname), (cells_name), __VA_ARGS__ }; \
+	WARNING(nm##_property, check_provider_cells_property, &nm##_provider, &phandle_references);
+
+WARNING_PROPERTY_PHANDLE_CELLS(clocks, "clocks", "#clock-cells");
+WARNING_PROPERTY_PHANDLE_CELLS(cooling_device, "cooling-device", "#cooling-cells");
+WARNING_PROPERTY_PHANDLE_CELLS(dmas, "dmas", "#dma-cells");
+WARNING_PROPERTY_PHANDLE_CELLS(hwlocks, "hwlocks", "#hwlock-cells");
+WARNING_PROPERTY_PHANDLE_CELLS(interrupts_extended, "interrupts-extended", "#interrupt-cells");
+WARNING_PROPERTY_PHANDLE_CELLS(io_channels, "io-channels", "#io-channel-cells");
+WARNING_PROPERTY_PHANDLE_CELLS(iommus, "iommus", "#iommu-cells");
+WARNING_PROPERTY_PHANDLE_CELLS(mboxes, "mboxes", "#mbox-cells");
+WARNING_PROPERTY_PHANDLE_CELLS(msi_parent, "msi-parent", "#msi-cells", true);
+WARNING_PROPERTY_PHANDLE_CELLS(mux_controls, "mux-controls", "#mux-control-cells");
+WARNING_PROPERTY_PHANDLE_CELLS(phys, "phys", "#phy-cells");
+WARNING_PROPERTY_PHANDLE_CELLS(power_domains, "power-domains", "#power-domain-cells");
+WARNING_PROPERTY_PHANDLE_CELLS(pwms, "pwms", "#pwm-cells");
+WARNING_PROPERTY_PHANDLE_CELLS(resets, "resets", "#reset-cells");
+WARNING_PROPERTY_PHANDLE_CELLS(sound_dai, "sound-dai", "#sound-dai-cells");
+WARNING_PROPERTY_PHANDLE_CELLS(thermal_sensors, "thermal-sensors", "#thermal-sensor-cells");
+
+static bool prop_is_gpio(struct property *prop)
+{
+	char *str;
+
+	/*
+	 * *-gpios and *-gpio can appear in property names,
+	 * so skip over any false matches (only one known ATM)
+	 */
+	if (strstr(prop->name, "nr-gpio"))
+		return false;
+
+	str = strrchr(prop->name, '-');
+	if (str)
+		str++;
+	else
+		str = prop->name;
+	if (!(streq(str, "gpios") || streq(str, "gpio")))
+		return false;
+
+	return true;
+}
+
+static void check_gpios_property(struct check *c,
+					  struct dt_info *dti,
+				          struct node *node)
+{
+	struct property *prop;
+
+	/* Skip GPIO hog nodes which have 'gpios' property */
+	if (get_property(node, "gpio-hog"))
+		return;
+
+	for_each_property(node, prop) {
+		struct provider provider;
+
+		if (!prop_is_gpio(prop))
+			continue;
+
+		provider.prop_name = prop->name;
+		provider.cell_name = "#gpio-cells";
+		provider.optional = false;
+		check_property_phandle_args(c, dti, node, prop, &provider);
+	}
+
+}
+WARNING(gpios_property, check_gpios_property, NULL, &phandle_references);
+
+static void check_deprecated_gpio_property(struct check *c,
+					   struct dt_info *dti,
+				           struct node *node)
+{
+	struct property *prop;
+
+	for_each_property(node, prop) {
+		char *str;
+
+		if (!prop_is_gpio(prop))
+			continue;
+
+		str = strstr(prop->name, "gpio");
+		if (!streq(str, "gpio"))
+			continue;
+
+		FAIL_PROP(c, dti, node, prop,
+			  "'[*-]gpio' is deprecated, use '[*-]gpios' instead");
+	}
+
+}
+CHECK(deprecated_gpio_property, check_deprecated_gpio_property, NULL);
+
+static bool node_is_interrupt_provider(struct node *node)
+{
+	struct property *prop;
+
+	prop = get_property(node, "interrupt-controller");
+	if (prop)
+		return true;
+
+	prop = get_property(node, "interrupt-map");
+	if (prop)
+		return true;
+
+	return false;
+}
+
+static void check_interrupt_provider(struct check *c,
+				     struct dt_info *dti,
+				     struct node *node)
+{
+	struct property *prop;
+
+	if (!node_is_interrupt_provider(node))
+		return;
+
+	prop = get_property(node, "#interrupt-cells");
+	if (!prop)
+		FAIL(c, dti, node,
+		     "Missing #interrupt-cells in interrupt provider");
+
+	prop = get_property(node, "#address-cells");
+	if (!prop)
+		FAIL(c, dti, node,
+		     "Missing #address-cells in interrupt provider");
+}
+WARNING(interrupt_provider, check_interrupt_provider, NULL);
+
+static void check_interrupts_property(struct check *c,
+				      struct dt_info *dti,
+				      struct node *node)
+{
+	struct node *root = dti->dt;
+	struct node *irq_node = NULL, *parent = node;
+	struct property *irq_prop, *prop = NULL;
+	int irq_cells, phandle;
+
+	irq_prop = get_property(node, "interrupts");
+	if (!irq_prop)
+		return;
+
+	if (irq_prop->val.len % sizeof(cell_t))
+		FAIL_PROP(c, dti, node, irq_prop, "size (%d) is invalid, expected multiple of %zu",
+		     irq_prop->val.len, sizeof(cell_t));
+
+	while (parent && !prop) {
+		if (parent != node && node_is_interrupt_provider(parent)) {
+			irq_node = parent;
+			break;
+		}
+
+		prop = get_property(parent, "interrupt-parent");
+		if (prop) {
+			phandle = propval_cell(prop);
+			if ((phandle == 0) || (phandle == -1)) {
+				/* Give up if this is an overlay with
+				 * external references */
+				if (dti->dtsflags & DTSF_PLUGIN)
+					return;
+				FAIL_PROP(c, dti, parent, prop, "Invalid phandle");
+				continue;
+			}
+
+			irq_node = get_node_by_phandle(root, phandle);
+			if (!irq_node) {
+				FAIL_PROP(c, dti, parent, prop, "Bad phandle");
+				return;
+			}
+			if (!node_is_interrupt_provider(irq_node))
+				FAIL(c, dti, irq_node,
+				     "Missing interrupt-controller or interrupt-map property");
+
+			break;
+		}
+
+		parent = parent->parent;
+	}
+
+	if (!irq_node) {
+		FAIL(c, dti, node, "Missing interrupt-parent");
+		return;
+	}
+
+	prop = get_property(irq_node, "#interrupt-cells");
+	if (!prop) {
+		/* We warn about that already in another test. */
+		return;
+	}
+
+	irq_cells = propval_cell(prop);
+	if (irq_prop->val.len % (irq_cells * sizeof(cell_t))) {
+		FAIL_PROP(c, dti, node, prop,
+			  "size is (%d), expected multiple of %d",
+			  irq_prop->val.len, (int)(irq_cells * sizeof(cell_t)));
+	}
+}
+WARNING(interrupts_property, check_interrupts_property, &phandle_references);
+
+static const struct bus_type graph_port_bus = {
+	.name = "graph-port",
+};
+
+static const struct bus_type graph_ports_bus = {
+	.name = "graph-ports",
+};
+
+static void check_graph_nodes(struct check *c, struct dt_info *dti,
+			      struct node *node)
+{
+	struct node *child;
+
+	for_each_child(node, child) {
+		if (!(strprefixeq(child->name, child->basenamelen, "endpoint") ||
+		      get_property(child, "remote-endpoint")))
+			continue;
+
+		node->bus = &graph_port_bus;
+
+		/* The parent of 'port' nodes can be either 'ports' or a device */
+		if (!node->parent->bus &&
+		    (streq(node->parent->name, "ports") || get_property(node, "reg")))
+			node->parent->bus = &graph_ports_bus;
+
+		break;
+	}
+
+}
+WARNING(graph_nodes, check_graph_nodes, NULL);
+
+static void check_graph_child_address(struct check *c, struct dt_info *dti,
+				      struct node *node)
+{
+	int cnt = 0;
+	struct node *child;
+
+	if (node->bus != &graph_ports_bus && node->bus != &graph_port_bus)
+		return;
+
+	for_each_child(node, child) {
+		struct property *prop = get_property(child, "reg");
+
+		/* No error if we have any non-zero unit address */
+		if (prop && propval_cell(prop) != 0)
+			return;
+
+		cnt++;
+	}
+
+	if (cnt == 1 && node->addr_cells != -1)
+		FAIL(c, dti, node, "graph node has single child node '%s', #address-cells/#size-cells are not necessary",
+		     node->children->name);
+}
+WARNING(graph_child_address, check_graph_child_address, NULL, &graph_nodes);
+
+static void check_graph_reg(struct check *c, struct dt_info *dti,
+			    struct node *node)
+{
+	char unit_addr[9];
+	const char *unitname = get_unitname(node);
+	struct property *prop;
+
+	prop = get_property(node, "reg");
+	if (!prop || !unitname)
+		return;
+
+	if (!(prop->val.val && prop->val.len == sizeof(cell_t))) {
+		FAIL(c, dti, node, "graph node malformed 'reg' property");
+		return;
+	}
+
+	snprintf(unit_addr, sizeof(unit_addr), "%x", propval_cell(prop));
+	if (!streq(unitname, unit_addr))
+		FAIL(c, dti, node, "graph node unit address error, expected \"%s\"",
+		     unit_addr);
+
+	if (node->parent->addr_cells != 1)
+		FAIL_PROP(c, dti, node, get_property(node, "#address-cells"),
+			  "graph node '#address-cells' is %d, must be 1",
+			  node->parent->addr_cells);
+	if (node->parent->size_cells != 0)
+		FAIL_PROP(c, dti, node, get_property(node, "#size-cells"),
+			  "graph node '#size-cells' is %d, must be 0",
+			  node->parent->size_cells);
+}
+
+static void check_graph_port(struct check *c, struct dt_info *dti,
+			     struct node *node)
+{
+	if (node->bus != &graph_port_bus)
+		return;
+
+	if (!strprefixeq(node->name, node->basenamelen, "port"))
+		FAIL(c, dti, node, "graph port node name should be 'port'");
+
+	check_graph_reg(c, dti, node);
+}
+WARNING(graph_port, check_graph_port, NULL, &graph_nodes);
+
+static struct node *get_remote_endpoint(struct check *c, struct dt_info *dti,
+					struct node *endpoint)
+{
+	int phandle;
+	struct node *node;
+	struct property *prop;
+
+	prop = get_property(endpoint, "remote-endpoint");
+	if (!prop)
+		return NULL;
+
+	phandle = propval_cell(prop);
+	/* Give up if this is an overlay with external references */
+	if (phandle == 0 || phandle == -1)
+		return NULL;
+
+	node = get_node_by_phandle(dti->dt, phandle);
+	if (!node)
+		FAIL_PROP(c, dti, endpoint, prop, "graph phandle is not valid");
+
+	return node;
+}
+
+static void check_graph_endpoint(struct check *c, struct dt_info *dti,
+				 struct node *node)
+{
+	struct node *remote_node;
+
+	if (!node->parent || node->parent->bus != &graph_port_bus)
+		return;
+
+	if (!strprefixeq(node->name, node->basenamelen, "endpoint"))
+		FAIL(c, dti, node, "graph endpoint node name should be 'endpoint'");
+
+	check_graph_reg(c, dti, node);
+
+	remote_node = get_remote_endpoint(c, dti, node);
+	if (!remote_node)
+		return;
+
+	if (get_remote_endpoint(c, dti, remote_node) != node)
+		FAIL(c, dti, node, "graph connection to node '%s' is not bidirectional",
+		     remote_node->fullpath);
+}
+WARNING(graph_endpoint, check_graph_endpoint, NULL, &graph_nodes);
+
 static struct check *check_table[] = {
 	&duplicate_node_names, &duplicate_property_names,
 	&node_name_chars, &node_name_format, &property_name_chars,
@@ -965,14 +1804,18 @@
 
 	&explicit_phandles,
 	&phandle_references, &path_references,
+	&omit_unused_nodes,
 
 	&address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell,
 	&device_type_is_string, &model_is_string, &status_is_string,
+	&label_is_string,
+
+	&compatible_is_string_list, &names_is_string_list,
 
 	&property_name_chars_strict,
 	&node_name_chars_strict,
 
-	&addr_size_cells, &reg_format, &ranges_format,
+	&addr_size_cells, &reg_format, &ranges_format, &dma_ranges_format,
 
 	&unit_address_vs_reg,
 	&unit_address_format,
@@ -984,8 +1827,44 @@
 	&simple_bus_bridge,
 	&simple_bus_reg,
 
+	&i2c_bus_bridge,
+	&i2c_bus_reg,
+
+	&spi_bus_bridge,
+	&spi_bus_reg,
+
 	&avoid_default_addr_size,
+	&avoid_unnecessary_addr_size,
+	&unique_unit_address,
+	&unique_unit_address_if_enabled,
 	&obsolete_chosen_interrupt_controller,
+	&chosen_node_is_root, &chosen_node_bootargs, &chosen_node_stdout_path,
+
+	&clocks_property,
+	&cooling_device_property,
+	&dmas_property,
+	&hwlocks_property,
+	&interrupts_extended_property,
+	&io_channels_property,
+	&iommus_property,
+	&mboxes_property,
+	&msi_parent_property,
+	&mux_controls_property,
+	&phys_property,
+	&power_domains_property,
+	&pwms_property,
+	&resets_property,
+	&sound_dai_property,
+	&thermal_sensors_property,
+
+	&deprecated_gpio_property,
+	&gpios_property,
+	&interrupts_property,
+	&interrupt_provider,
+
+	&alias_paths,
+
+	&graph_nodes, &graph_child_address, &graph_port, &graph_endpoint,
 
 	&always_fail,
 };
diff --git a/convert-dtsv0-lexer.l b/convert-dtsv0-lexer.l
index d6d68cd..f52e8a1 100644
--- a/convert-dtsv0-lexer.l
+++ b/convert-dtsv0-lexer.l
@@ -1,20 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 /*
  * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005, 2008.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
- *                                                                   USA
  */
 
 %option noyywrap nounput noinput never-interactive
diff --git a/data.c b/data.c
index aa37a16..0a43b6d 100644
--- a/data.c
+++ b/data.c
@@ -1,21 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
- *                                                                   USA
  */
 
 #include "dtc.h"
@@ -74,7 +59,8 @@
 	struct data d;
 	char *q;
 
-	d = data_grow_for(empty_data, len + 1);
+	d = data_add_marker(empty_data, TYPE_STRING, NULL);
+	d = data_grow_for(d, len + 1);
 
 	q = d.val;
 	while (i < len) {
@@ -94,6 +80,7 @@
 {
 	struct data d = empty_data;
 
+	d = data_add_marker(d, TYPE_NONE, NULL);
 	while (!feof(f) && (d.len < maxlen)) {
 		size_t chunksize, ret;
 
diff --git a/dtc-lexer.l b/dtc-lexer.l
index 13f4b06..f0faa28 100644
--- a/dtc-lexer.l
+++ b/dtc-lexer.l
@@ -1,21 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 /*
  * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
- *                                                                   USA
  */
 
 %option noyywrap nounput noinput never-interactive
@@ -38,7 +23,6 @@
 #include "srcpos.h"
 #include "dtc-parser.h"
 
-YYLTYPE yylloc;
 extern bool treesource_error;
 
 /* CAUTION: this will stop working if we ever use yyless() or yyunput() */
@@ -153,6 +137,13 @@
 			return DT_DEL_NODE;
 		}
 
+<*>"/omit-if-no-ref/"	{
+			DPRINT("Keyword: /omit-if-no-ref/\n");
+			DPRINT("<PROPNODENAME>\n");
+			BEGIN(PROPNODENAME);
+			return DT_OMIT_NO_REF;
+		}
+
 <*>{LABEL}:	{
 			DPRINT("Label: %s\n", yytext);
 			yylval.labelref = xstrdup(yytext);
@@ -206,14 +197,14 @@
 <*>\&{LABEL}	{	/* label reference */
 			DPRINT("Ref: %s\n", yytext+1);
 			yylval.labelref = xstrdup(yytext+1);
-			return DT_REF;
+			return DT_LABEL_REF;
 		}
 
 <*>"&{/"{PATHCHAR}*\}	{	/* new-style path reference */
 			yytext[yyleng-1] = '\0';
 			DPRINT("Ref: %s\n", yytext+2);
 			yylval.labelref = xstrdup(yytext+2);
-			return DT_REF;
+			return DT_PATH_REF;
 		}
 
 <BYTESTRING>[0-9a-fA-F]{2} {
diff --git a/dtc-parser.y b/dtc-parser.y
index affc81a..cf0e361 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -1,22 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
- *                                                                   USA
  */
+%locations
+
 %{
 #include <stdio.h>
 #include <inttypes.h>
@@ -32,6 +19,8 @@
 		treesource_error = true; \
 	} while (0)
 
+#define YYERROR_CALL(msg) yyerror(msg)
+
 extern struct dt_info *parser_output;
 extern bool treesource_error;
 %}
@@ -63,13 +52,15 @@
 %token DT_BITS
 %token DT_DEL_PROP
 %token DT_DEL_NODE
+%token DT_OMIT_NO_REF
 %token <propnodename> DT_PROPNODENAME
 %token <integer> DT_LITERAL
 %token <integer> DT_CHAR_LITERAL
 %token <byte> DT_BYTE
 %token <data> DT_STRING
 %token <labelref> DT_LABEL
-%token <labelref> DT_REF
+%token <labelref> DT_LABEL_REF
+%token <labelref> DT_PATH_REF
 %token DT_INCBIN
 
 %type <data> propdata
@@ -82,6 +73,7 @@
 %type <data> bytestring
 %type <prop> propdef
 %type <proplist> proplist
+%type <labelref> dt_ref
 
 %type <node> devicetree
 %type <node> nodedef
@@ -157,6 +149,8 @@
 		}
 	;
 
+dt_ref: DT_LABEL_REF | DT_PATH_REF;
+
 devicetree:
 	  '/' nodedef
 		{
@@ -166,8 +160,21 @@
 		{
 			$$ = merge_nodes($1, $3);
 		}
-
-	| devicetree DT_LABEL DT_REF nodedef
+	| dt_ref nodedef
+		{
+			/*
+			 * We rely on the rule being always:
+			 *   versioninfo plugindecl memreserves devicetree
+			 * so $-1 is what we want (plugindecl)
+			 */
+			if (!($<flags>-1 & DTSF_PLUGIN))
+				ERROR(&@2, "Label or path %s not found", $1);
+			$$ = add_orphan_node(
+					name_node(build_node(NULL, NULL, NULL),
+						  ""),
+					$2, $1);
+		}
+	| devicetree DT_LABEL dt_ref nodedef
 		{
 			struct node *target = get_node_by_ref($1, $3);
 
@@ -178,7 +185,26 @@
 				ERROR(&@3, "Label or path %s not found", $3);
 			$$ = $1;
 		}
-	| devicetree DT_REF nodedef
+	| devicetree DT_PATH_REF nodedef
+		{
+			/*
+			 * We rely on the rule being always:
+			 *   versioninfo plugindecl memreserves devicetree
+			 * so $-1 is what we want (plugindecl)
+			 */
+			if ($<flags>-1 & DTSF_PLUGIN) {
+				add_orphan_node($1, $3, $2);
+			} else {
+				struct node *target = get_node_by_ref($1, $2);
+
+				if (target)
+					merge_nodes(target, $3);
+				else
+					ERROR(&@2, "Label or path %s not found", $2);
+			}
+			$$ = $1;
+		}
+	| devicetree DT_LABEL_REF nodedef
 		{
 			struct node *target = get_node_by_ref($1, $2);
 
@@ -197,7 +223,7 @@
 			}
 			$$ = $1;
 		}
-	| devicetree DT_DEL_NODE DT_REF ';'
+	| devicetree DT_DEL_NODE dt_ref ';'
 		{
 			struct node *target = get_node_by_ref($1, $3);
 
@@ -209,17 +235,29 @@
 
 			$$ = $1;
 		}
+	| devicetree DT_OMIT_NO_REF dt_ref ';'
+		{
+			struct node *target = get_node_by_ref($1, $3);
+
+			if (target)
+				omit_node_if_unused(target);
+			else
+				ERROR(&@3, "Label or path %s not found", $3);
+
+
+			$$ = $1;
+		}
 	| /* empty */
 		{
 			/* build empty node */
-			$$ = name_node(build_node(NULL, NULL), "");
+			$$ = name_node(build_node(NULL, NULL, NULL), "");
 		}
 	;
 
 nodedef:
 	  '{' proplist subnodes '}' ';'
 		{
-			$$ = build_node($2, $3);
+			$$ = build_node($2, $3, &@$);
 		}
 	;
 
@@ -237,11 +275,11 @@
 propdef:
 	  DT_PROPNODENAME '=' propdata ';'
 		{
-			$$ = build_property($1, $3);
+			$$ = build_property($1, $3, &@$);
 		}
 	| DT_PROPNODENAME ';'
 		{
-			$$ = build_property($1, empty_data);
+			$$ = build_property($1, empty_data, &@$);
 		}
 	| DT_DEL_PROP DT_PROPNODENAME ';'
 		{
@@ -267,8 +305,9 @@
 		{
 			$$ = data_merge($1, $3);
 		}
-	| propdataprefix DT_REF
+	| propdataprefix dt_ref
 		{
+			$1 = data_add_marker($1, TYPE_STRING, $2);
 			$$ = data_add_marker($1, REF_PATH, $2);
 		}
 	| propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
@@ -322,22 +361,27 @@
 	DT_BITS DT_LITERAL '<'
 		{
 			unsigned long long bits;
+			enum markertype type = TYPE_UINT32;
 
 			bits = $2;
 
-			if ((bits !=  8) && (bits != 16) &&
-			    (bits != 32) && (bits != 64)) {
+			switch (bits) {
+			case 8: type = TYPE_UINT8; break;
+			case 16: type = TYPE_UINT16; break;
+			case 32: type = TYPE_UINT32; break;
+			case 64: type = TYPE_UINT64; break;
+			default:
 				ERROR(&@2, "Array elements must be"
 				      " 8, 16, 32 or 64-bits");
 				bits = 32;
 			}
 
-			$$.data = empty_data;
+			$$.data = data_add_marker(empty_data, type, NULL);
 			$$.bits = bits;
 		}
 	| '<'
 		{
-			$$.data = empty_data;
+			$$.data = data_add_marker(empty_data, TYPE_UINT32, NULL);
 			$$.bits = 32;
 		}
 	| arrayprefix integer_prim
@@ -359,7 +403,7 @@
 
 			$$.data = data_append_integer($1.data, $2, $1.bits);
 		}
-	| arrayprefix DT_REF
+	| arrayprefix dt_ref
 		{
 			uint64_t val = ~0ULL >> (64 - $1.bits);
 
@@ -481,7 +525,7 @@
 bytestring:
 	  /* empty */
 		{
-			$$ = empty_data;
+			$$ = data_add_marker(empty_data, TYPE_UINT8, NULL);
 		}
 	| bytestring DT_BYTE
 		{
@@ -516,7 +560,11 @@
 		}
 	| DT_DEL_NODE DT_PROPNODENAME ';'
 		{
-			$$ = name_node(build_node_delete(), $2);
+			$$ = name_node(build_node_delete(&@$), $2);
+		}
+	| DT_OMIT_NO_REF subnode
+		{
+			$$ = omit_node_if_unused($2);
 		}
 	| DT_LABEL subnode
 		{
diff --git a/dtc.c b/dtc.c
index 5ed873c..bdb3f59 100644
--- a/dtc.c
+++ b/dtc.c
@@ -1,21 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
- *                                                                   USA
  */
 
 #include <sys/stat.h>
@@ -35,6 +20,8 @@
 int generate_symbols;	/* enable symbols & fixup support */
 int generate_fixups;		/* suppress generation of fixups on symbol support */
 int auto_label_aliases;		/* auto generate labels -> aliases */
+int annotate;		/* Level of annotation: 1 for input source location
+			   >1 for full input source location. */
 
 static int is_power_of_2(int x)
 {
@@ -59,10 +46,8 @@
 }
 
 /* Usage related data. */
-#define FDT_VERSION(version)	_FDT_VERSION(version)
-#define _FDT_VERSION(version)	#version
 static const char usage_synopsis[] = "dtc [options] <input file>";
-static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@Ahv";
+static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@AThv";
 static struct option const usage_long_opts[] = {
 	{"quiet",            no_argument, NULL, 'q'},
 	{"in-format",         a_argument, NULL, 'I'},
@@ -83,6 +68,7 @@
 	{"error",             a_argument, NULL, 'E'},
 	{"symbols",	     no_argument, NULL, '@'},
 	{"auto-alias",       no_argument, NULL, 'A'},
+	{"annotate",         no_argument, NULL, 'T'},
 	{"help",             no_argument, NULL, 'h'},
 	{"version",          no_argument, NULL, 'v'},
 	{NULL,               no_argument, NULL, 0x0},
@@ -97,8 +83,11 @@
 	"\n\tOutput formats are:\n"
 	 "\t\tdts - device tree source text\n"
 	 "\t\tdtb - device tree blob\n"
+#ifndef NO_YAML
+	 "\t\tyaml - device tree encoded as YAML\n"
+#endif
 	 "\t\tasm - assembler source",
-	"\n\tBlob version to produce, defaults to "FDT_VERSION(DEFAULT_FDT_VERSION)" (for dtb and asm output)",
+	"\n\tBlob version to produce, defaults to "stringify(DEFAULT_FDT_VERSION)" (for dtb and asm output)",
 	"\n\tOutput dependency file",
 	"\n\tMake space for <number> reserve map entries (for dtb and asm output)",
 	"\n\tMake the blob at least <bytes> long (extra space)",
@@ -116,6 +105,7 @@
 	"\n\tEnable/disable errors (prefix with \"no-\")",
 	"\n\tEnable generation of symbols",
 	"\n\tEnable auto-alias of labels",
+	"\n\tAnnotate output .dts with input source file and line (-T -T for more details)",
 	"\n\tPrint this help and exit",
 	"\n\tPrint version and exit",
 	NULL,
@@ -130,6 +120,8 @@
 		return fallback;
 	if (!strcasecmp(s, ".dts"))
 		return "dts";
+	if (!strcasecmp(s, ".yaml"))
+		return "yaml";
 	if (!strcasecmp(s, ".dtb"))
 		return "dtb";
 	return fallback;
@@ -261,6 +253,9 @@
 		case 'A':
 			auto_label_aliases = 1;
 			break;
+		case 'T':
+			annotate++;
+			break;
 
 		case 'h':
 			usage(NULL);
@@ -299,6 +294,8 @@
 				outform = "dts";
 		}
 	}
+	if (annotate && (!streq(inform, "dts") || !streq(outform, "dts")))
+		die("--annotate requires -I dts -O dts\n");
 	if (streq(inform, "dts"))
 		dti = dt_from_source(arg);
 	else if (streq(inform, "fs"))
@@ -319,13 +316,14 @@
 		dti->boot_cpuid_phys = cmdline_boot_cpuid;
 
 	fill_fullpaths(dti->dt, "");
-	process_checks(force, dti);
 
 	/* on a plugin, generate by default */
 	if (dti->dtsflags & DTSF_PLUGIN) {
 		generate_fixups = 1;
 	}
 
+	process_checks(force, dti);
+
 	if (auto_label_aliases)
 		generate_label_tree(dti, "aliases", false);
 
@@ -351,6 +349,12 @@
 
 	if (streq(outform, "dts")) {
 		dt_to_source(outf, dti);
+#ifndef NO_YAML
+	} else if (streq(outform, "yaml")) {
+		if (!streq(inform, "dts"))
+			die("YAML output format requires dts input format\n");
+		dt_to_yaml(outf, dti);
+#endif
 	} else if (streq(outform, "dtb")) {
 		dt_to_blob(outf, dti, outversion);
 	} else if (streq(outform, "asm")) {
diff --git a/dtc.h b/dtc.h
index 07e3ddb..a08f415 100644
--- a/dtc.h
+++ b/dtc.h
@@ -1,24 +1,9 @@
-#ifndef _DTC_H
-#define _DTC_H
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef DTC_H
+#define DTC_H
 
 /*
  * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
- *                                                                   USA
  */
 
 #include <stdio.h>
@@ -58,6 +43,7 @@
 extern int generate_symbols;	/* generate symbols for nodes with labels */
 extern int generate_fixups;	/* generate fixups */
 extern int auto_label_aliases;	/* auto generate labels -> aliases */
+extern int annotate;		/* annotate .dts with input source location */
 
 #define PHANDLE_LEGACY	0x1
 #define PHANDLE_EPAPR	0x2
@@ -65,18 +51,57 @@
 
 typedef uint32_t cell_t;
 
+static inline uint16_t dtb_ld16(const void *p)
+{
+	const uint8_t *bp = (const uint8_t *)p;
+
+	return ((uint16_t)bp[0] << 8)
+		| bp[1];
+}
+
+static inline uint32_t dtb_ld32(const void *p)
+{
+	const uint8_t *bp = (const uint8_t *)p;
+
+	return ((uint32_t)bp[0] << 24)
+		| ((uint32_t)bp[1] << 16)
+		| ((uint32_t)bp[2] << 8)
+		| bp[3];
+}
+
+static inline uint64_t dtb_ld64(const void *p)
+{
+	const uint8_t *bp = (const uint8_t *)p;
+
+	return ((uint64_t)bp[0] << 56)
+		| ((uint64_t)bp[1] << 48)
+		| ((uint64_t)bp[2] << 40)
+		| ((uint64_t)bp[3] << 32)
+		| ((uint64_t)bp[4] << 24)
+		| ((uint64_t)bp[5] << 16)
+		| ((uint64_t)bp[6] << 8)
+		| bp[7];
+}
 
 #define streq(a, b)	(strcmp((a), (b)) == 0)
-#define strneq(a, b, n)	(strncmp((a), (b), (n)) == 0)
+#define strstarts(s, prefix)	(strncmp((s), (prefix), strlen(prefix)) == 0)
+#define strprefixeq(a, n, b)	(strlen(b) == (n) && (memcmp(a, b, n) == 0))
 
 #define ALIGN(x, a)	(((x) + (a) - 1) & ~((a) - 1))
 
 /* Data blobs */
 enum markertype {
+	TYPE_NONE,
 	REF_PHANDLE,
 	REF_PATH,
 	LABEL,
+	TYPE_UINT8,
+	TYPE_UINT16,
+	TYPE_UINT32,
+	TYPE_UINT64,
+	TYPE_STRING,
 };
+extern const char *markername(enum markertype markertype);
 
 struct  marker {
 	enum markertype type;
@@ -100,6 +125,8 @@
 	for_each_marker(m) \
 		if ((m)->type == (t))
 
+size_t type_marker_length(struct marker *m);
+
 void data_free(struct data d);
 
 struct data data_grow_for(struct data d, int xlen);
@@ -148,6 +175,7 @@
 	struct property *next;
 
 	struct label *labels;
+	struct srcpos *srcpos;
 };
 
 struct node {
@@ -167,6 +195,9 @@
 
 	struct label *labels;
 	const struct bus_type *bus;
+	struct srcpos *srcpos;
+
+	bool omit_if_unused, is_referenced;
 };
 
 #define for_each_label_withdel(l0, l) \
@@ -193,17 +224,21 @@
 void add_label(struct label **labels, char *label);
 void delete_labels(struct label **labels);
 
-struct property *build_property(char *name, struct data val);
+struct property *build_property(char *name, struct data val,
+				struct srcpos *srcpos);
 struct property *build_property_delete(char *name);
 struct property *chain_property(struct property *first, struct property *list);
 struct property *reverse_properties(struct property *first);
 
-struct node *build_node(struct property *proplist, struct node *children);
-struct node *build_node_delete(void);
+struct node *build_node(struct property *proplist, struct node *children,
+			struct srcpos *srcpos);
+struct node *build_node_delete(struct srcpos *srcpos);
 struct node *name_node(struct node *node, char *name);
+struct node *omit_node_if_unused(struct node *node);
+struct node *reference_node(struct node *node);
 struct node *chain_node(struct node *first, struct node *list);
 struct node *merge_nodes(struct node *old_node, struct node *new_node);
-void add_orphan_node(struct node *old_node, struct node *new_node, char *ref);
+struct node *add_orphan_node(struct node *old_node, struct node *new_node, char *ref);
 
 void add_property(struct node *node, struct property *prop);
 void delete_property_by_name(struct node *node, char *name);
@@ -212,11 +247,13 @@
 void delete_node_by_name(struct node *parent, char *name);
 void delete_node(struct node *node);
 void append_to_property(struct node *node,
-			char *name, const void *data, int len);
+			char *name, const void *data, int len,
+			enum markertype type);
 
 const char *get_unitname(struct node *node);
 struct property *get_property(struct node *node, const char *propname);
 cell_t propval_cell(struct property *prop);
+cell_t propval_cell_n(struct property *prop, int n);
 struct property *get_property_by_label(struct node *tree, const char *label,
 				       struct node **node);
 struct marker *get_marker_label(struct node *tree, const char *label,
@@ -284,8 +321,12 @@
 void dt_to_source(FILE *f, struct dt_info *dti);
 struct dt_info *dt_from_source(const char *f);
 
+/* YAML source */
+
+void dt_to_yaml(FILE *f, struct dt_info *dti);
+
 /* FS trees */
 
 struct dt_info *dt_from_fs(const char *dirname);
 
-#endif /* _DTC_H */
+#endif /* DTC_H */
diff --git a/dtdiff b/dtdiff
index 5fa772b..cdbf079 100644
--- a/dtdiff
+++ b/dtdiff
@@ -1,4 +1,5 @@
 #! /bin/bash
+# SPDX-License-Identifier: GPL-2.0-or-later
 
 # This script uses the bash <(...) extension.
 # If you want to change this to work with a generic /bin/sh, make sure
diff --git a/fdtdump.c b/fdtdump.c
index fa3b561..9613bef 100644
--- a/fdtdump.c
+++ b/fdtdump.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * fdtdump.c - Contributed by Pantelis Antoniou <pantelis.antoniou AT gmail.com>
  */
@@ -8,6 +9,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
+#include <inttypes.h>
 
 #include <libfdt.h>
 #include <libfdt_env.h>
@@ -65,23 +67,24 @@
 	shift = 4;
 
 	printf("/dts-v1/;\n");
-	printf("// magic:\t\t0x%x\n", fdt32_to_cpu(bph->magic));
-	printf("// totalsize:\t\t0x%x (%d)\n", totalsize, totalsize);
-	printf("// off_dt_struct:\t0x%x\n", off_dt);
-	printf("// off_dt_strings:\t0x%x\n", off_str);
-	printf("// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap);
-	printf("// version:\t\t%d\n", version);
-	printf("// last_comp_version:\t%d\n",
+	printf("// magic:\t\t0x%"PRIx32"\n", fdt32_to_cpu(bph->magic));
+	printf("// totalsize:\t\t0x%"PRIx32" (%"PRIu32")\n",
+	       totalsize, totalsize);
+	printf("// off_dt_struct:\t0x%"PRIx32"\n", off_dt);
+	printf("// off_dt_strings:\t0x%"PRIx32"\n", off_str);
+	printf("// off_mem_rsvmap:\t0x%"PRIx32"\n", off_mem_rsvmap);
+	printf("// version:\t\t%"PRIu32"\n", version);
+	printf("// last_comp_version:\t%"PRIu32"\n",
 	       fdt32_to_cpu(bph->last_comp_version));
 	if (version >= 2)
-		printf("// boot_cpuid_phys:\t0x%x\n",
+		printf("// boot_cpuid_phys:\t0x%"PRIx32"\n",
 		       fdt32_to_cpu(bph->boot_cpuid_phys));
 
 	if (version >= 3)
-		printf("// size_dt_strings:\t0x%x\n",
+		printf("// size_dt_strings:\t0x%"PRIx32"\n",
 		       fdt32_to_cpu(bph->size_dt_strings));
 	if (version >= 17)
-		printf("// size_dt_struct:\t0x%x\n",
+		printf("// size_dt_struct:\t0x%"PRIx32"\n",
 		       fdt32_to_cpu(bph->size_dt_struct));
 	printf("\n");
 
@@ -91,14 +94,14 @@
 		if (addr == 0 && size == 0)
 			break;
 
-		printf("/memreserve/ %#llx %#llx;\n",
-		       (unsigned long long)addr, (unsigned long long)size);
+		printf("/memreserve/ %#"PRIx64" %#"PRIx64";\n",
+		       addr, size);
 	}
 
 	p = p_struct;
 	while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) {
 
-		dumpf("%04zx: tag: 0x%08x (%s)\n",
+		dumpf("%04"PRIxPTR": tag: 0x%08"PRIx32" (%s)\n",
 		        (uintptr_t)p - blob_off - 4, tag, tagname(tag));
 
 		if (tag == FDT_BEGIN_NODE) {
@@ -127,7 +130,7 @@
 		}
 
 		if (tag != FDT_PROP) {
-			fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", depth * shift, "", tag);
+			fprintf(stderr, "%*s ** Unknown tag 0x%08"PRIx32"\n", depth * shift, "", tag);
 			break;
 		}
 		sz = fdt32_to_cpu(GET_CELL(p));
@@ -138,8 +141,8 @@
 
 		p = PALIGN(p + sz, 4);
 
-		dumpf("%04zx: string: %s\n", (uintptr_t)s - blob_off, s);
-		dumpf("%04zx: value\n", (uintptr_t)t - blob_off);
+		dumpf("%04"PRIxPTR": string: %s\n", (uintptr_t)s - blob_off, s);
+		dumpf("%04"PRIxPTR": value\n", (uintptr_t)t - blob_off);
 		printf("%*s%s", depth * shift, "", s);
 		utilfdt_print_data(t, sz);
 		printf(";\n");
@@ -181,7 +184,7 @@
 	char *buf;
 	bool debug = false;
 	bool scan = false;
-	off_t len;
+	size_t len;
 
 	fprintf(stderr, "\n"
 "**** fdtdump is a low-level debugging tool, not meant for general use.\n"
@@ -204,7 +207,7 @@
 		usage("missing input filename");
 	file = argv[optind];
 
-	buf = utilfdt_read_len(file, &len);
+	buf = utilfdt_read(file, &len);
 	if (!buf)
 		die("could not read: %s\n", file);
 
@@ -227,14 +230,14 @@
 				if (valid_header(p, this_len))
 					break;
 				if (debug)
-					printf("%s: skipping fdt magic at offset %#zx\n",
+					printf("%s: skipping fdt magic at offset %#tx\n",
 						file, p - buf);
 			}
 			++p;
 		}
 		if (!p || endp - p < sizeof(struct fdt_header))
 			die("%s: could not locate fdt magic\n", file);
-		printf("%s: found fdt at offset %#zx\n", file, p - buf);
+		printf("%s: found fdt at offset %#tx\n", file, p - buf);
 		buf = p;
 	} else if (!valid_header(buf, len))
 		die("%s: header is not valid\n", file);
diff --git a/fdtget.c b/fdtget.c
index 39f1742..777582e 100644
--- a/fdtget.c
+++ b/fdtget.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
  *
@@ -6,21 +7,6 @@
  * Based on code written by:
  *   Pantelis Antoniou <pantelis.antoniou@gmail.com> and
  *   Matthew McClintock <msm@freescale.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>
@@ -54,6 +40,37 @@
 }
 
 /**
+ * Shows a list of cells in the requested format
+ *
+ * @param disp		Display information / options
+ * @param data		Data to display
+ * @param len		Maximum length of buffer
+ * @param size		Data size to use for display (e.g. 4 for 32-bit)
+ * @return 0 if ok, -1 on error
+ */
+static int show_cell_list(struct display_info *disp, const char *data, int len,
+			  int size)
+{
+	const uint8_t *p = (const uint8_t *)data;
+	char fmt[3];
+	int value;
+	int i;
+
+	fmt[0] = '%';
+	fmt[1] = disp->type ? disp->type : 'd';
+	fmt[2] = '\0';
+	for (i = 0; i < len; i += size, p += size) {
+		if (i)
+			printf(" ");
+		value = size == 4 ? fdt32_ld((const fdt32_t *)p) :
+			size == 2 ? (*p << 8) | p[1] : *p;
+		printf(fmt, value);
+	}
+
+	return 0;
+}
+
+/**
  * Displays data of a given length according to selected options
  *
  * If a specific data type is provided in disp, then this is used. Otherwise
@@ -66,12 +83,9 @@
  */
 static int show_data(struct display_info *disp, const char *data, int len)
 {
-	int i, size;
-	const uint8_t *p = (const uint8_t *)data;
+	int size;
 	const char *s;
-	int value;
 	int is_string;
-	char fmt[3];
 
 	/* no data, don't print */
 	if (len == 0)
@@ -99,17 +113,8 @@
 				"selected data size\n");
 		return -1;
 	}
-	fmt[0] = '%';
-	fmt[1] = disp->type ? disp->type : 'd';
-	fmt[2] = '\0';
-	for (i = 0; i < len; i += size, p += size) {
-		if (i)
-			printf(" ");
-		value = size == 4 ? fdt32_to_cpu(*(const fdt32_t *)p) :
-			size == 2 ? (*p << 8) | p[1] : *p;
-		printf(fmt, value);
-	}
-	return 0;
+
+	return show_cell_list(disp, data, len, size);
 }
 
 /**
@@ -121,7 +126,6 @@
  */
 static int list_properties(const void *blob, int node)
 {
-	const struct fdt_property *data;
 	const char *name;
 	int prop;
 
@@ -130,8 +134,7 @@
 		/* Stop silently when there are no more properties */
 		if (prop < 0)
 			return prop == -FDT_ERR_NOTFOUND ? 0 : prop;
-		data = fdt_get_property_by_offset(blob, prop, NULL);
-		name = fdt_string(blob, fdt32_to_cpu(data->nameoff));
+		fdt_getprop_by_offset(blob, prop, &name, NULL);
 		if (name)
 			puts(name);
 		prop = fdt_next_property_offset(blob, prop);
@@ -254,7 +257,7 @@
 	const char *prop;
 	int i, node;
 
-	blob = utilfdt_read(filename);
+	blob = utilfdt_read(filename, NULL);
 	if (!blob)
 		return -1;
 
diff --git a/fdtoverlay.c b/fdtoverlay.c
index 9c5618c..5350af6 100644
--- a/fdtoverlay.c
+++ b/fdtoverlay.c
@@ -1,23 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * 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>
@@ -26,12 +12,14 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <alloca.h>
+#include <inttypes.h>
 
 #include <libfdt.h>
 
 #include "util.h"
 
+#define BUF_INCREMENT	65536
+
 /* Usage related data. */
 static const char usage_synopsis[] =
 	"apply a number of overlays to a base blob\n"
@@ -54,59 +42,110 @@
 
 int verbose = 0;
 
+static void *apply_one(char *base, const char *overlay, size_t *buf_len,
+		       const char *name)
+{
+	char *tmp = NULL;
+	char *tmpo;
+	int ret;
+
+	/*
+	 * We take a copies first, because a a failed apply can trash
+	 * both the base blob and the overlay
+	 */
+	tmpo = xmalloc(fdt_totalsize(overlay));
+
+	do {
+		tmp = xrealloc(tmp, *buf_len);
+		ret = fdt_open_into(base, tmp, *buf_len);
+		if (ret) {
+			fprintf(stderr,
+				"\nFailed to make temporary copy: %s\n",
+				fdt_strerror(ret));
+			goto fail;
+		}
+
+		memcpy(tmpo, overlay, fdt_totalsize(overlay));
+
+		ret = fdt_overlay_apply(tmp, tmpo);
+		if (ret == -FDT_ERR_NOSPACE) {
+			*buf_len += BUF_INCREMENT;
+		}
+	} while (ret == -FDT_ERR_NOSPACE);
+
+	if (ret) {
+		fprintf(stderr, "\nFailed to apply '%s': %s\n",
+			name, fdt_strerror(ret));
+		goto fail;
+	}
+
+	free(base);
+	free(tmpo);
+	return tmp;
+
+fail:
+	free(tmpo);
+	if (tmp)
+		free(tmp);
+
+	return NULL;
+}
 static int do_fdtoverlay(const char *input_filename,
 			 const char *output_filename,
 			 int argc, char *argv[])
 {
 	char *blob = NULL;
 	char **ovblob = NULL;
-	off_t blob_len, ov_len, total_len;
+	size_t buf_len;
 	int i, ret = -1;
 
-	blob = utilfdt_read_len(input_filename, &blob_len);
+	blob = utilfdt_read(input_filename, &buf_len);
 	if (!blob) {
-		fprintf(stderr, "\nFailed to read base blob %s\n",
-				input_filename);
+		fprintf(stderr, "\nFailed to read '%s'\n", input_filename);
 		goto out_err;
 	}
-	ret = 0;
+	if (fdt_totalsize(blob) > buf_len) {
+		fprintf(stderr,
+ "\nBase blob is incomplete (%lu / %" PRIu32 " bytes read)\n",
+			(unsigned long)buf_len, fdt_totalsize(blob));
+		goto out_err;
+	}
 
 	/* allocate blob pointer array */
-	ovblob = alloca(sizeof(*ovblob) * argc);
+	ovblob = xmalloc(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);
+		size_t ov_len;
+		ovblob[i] = utilfdt_read(argv[i], &ov_len);
 		if (!ovblob[i]) {
-			fprintf(stderr, "\nFailed to read overlay %s\n",
-					argv[i]);
+			fprintf(stderr, "\nFailed to read '%s'\n", argv[i]);
 			goto out_err;
 		}
-		total_len += ov_len;
+		if (fdt_totalsize(ovblob[i]) > ov_len) {
+			fprintf(stderr,
+"\nOverlay '%s' is incomplete (%lu / %" PRIu32 " bytes read)\n",
+				argv[i], (unsigned long)ov_len,
+				fdt_totalsize(ovblob[i]));
+			goto out_err;
+		}
 	}
 
-	/* 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);
+	buf_len = fdt_totalsize(blob);
 
 	/* 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);
+		blob = apply_one(blob, ovblob[i], &buf_len, argv[i]);
+		if (!blob)
 			goto out_err;
-		}
 	}
 
 	fdt_pack(blob);
 	ret = utilfdt_write(output_filename, blob);
 	if (ret)
-		fprintf(stderr, "\nFailed to write output blob %s\n",
-				output_filename);
+		fprintf(stderr, "\nFailed to write '%s'\n",
+			output_filename);
 
 out_err:
 	if (ovblob) {
@@ -114,6 +153,7 @@
 			if (ovblob[i])
 				free(ovblob[i]);
 		}
+		free(ovblob);
 	}
 	free(blob);
 
diff --git a/fdtput.c b/fdtput.c
index 8d8e934..428745a 100644
--- a/fdtput.c
+++ b/fdtput.c
@@ -1,20 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
- *
- * 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>
@@ -130,7 +116,7 @@
 
 #define ALIGN(x)		(((x) + (FDT_TAGSIZE) - 1) & ~((FDT_TAGSIZE) - 1))
 
-static char *_realloc_fdt(char *fdt, int delta)
+static char *realloc_fdt(char *fdt, int delta)
 {
 	int new_sz = fdt_totalsize(fdt) + delta;
 	fdt = xrealloc(fdt, new_sz);
@@ -144,7 +130,7 @@
 	/* FDT_BEGIN_NODE, node name in off_struct and FDT_END_NODE */
 	delta = sizeof(struct fdt_node_header) + ALIGN(strlen(name) + 1)
 			+ FDT_TAGSIZE;
-	return _realloc_fdt(fdt, delta);
+	return realloc_fdt(fdt, delta);
 }
 
 static char *realloc_property(char *fdt, int nodeoffset,
@@ -161,7 +147,7 @@
 		/* actual value in off_struct */
 		delta += ALIGN(newlen) - ALIGN(oldlen);
 
-	return _realloc_fdt(fdt, delta);
+	return realloc_fdt(fdt, delta);
 }
 
 static int store_key_value(char **blob, const char *node_name,
@@ -333,7 +319,7 @@
 	char *node;
 	int len, ret = 0;
 
-	blob = utilfdt_read(filename);
+	blob = utilfdt_read(filename, NULL);
 	if (!blob)
 		return -1;
 
diff --git a/flattree.c b/flattree.c
index fcf7154..07f10d2 100644
--- a/flattree.c
+++ b/flattree.c
@@ -1,21 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
- *                                                                   USA
  */
 
 #include "dtc.h"
@@ -171,7 +156,7 @@
 		emit_offset_label(f, m->ref, m->offset);
 
 	while ((d.len - off) >= sizeof(uint32_t)) {
-		asm_emit_cell(e, fdt32_to_cpu(*((fdt32_t *)(d.val+off))));
+		asm_emit_cell(e, dtb_ld32(d.val + off));
 		off += sizeof(uint32_t);
 	}
 
@@ -393,7 +378,7 @@
 			padlen = 0;
 			if (quiet < 1)
 				fprintf(stderr,
-					"Warning: blob size %d >= minimum size %d\n",
+					"Warning: blob size %"PRIu32" >= minimum size %d\n",
 					fdt32_to_cpu(fdt.totalsize), minsize);
 		}
 	}
@@ -525,7 +510,7 @@
 	fprintf(f, "/* Memory reserve map from source file */\n");
 
 	/*
-	 * Use .long on high and low halfs of u64s to avoid .quad
+	 * Use .long on high and low halves of u64s to avoid .quad
 	 * as it appears .quad isn't available in some assemblers.
 	 */
 	for (re = dti->reservelist; re; re = re->next) {
@@ -692,7 +677,7 @@
 
 	val = flat_read_data(dtbuf, proplen);
 
-	return build_property(name, val);
+	return build_property(name, val, NULL);
 }
 
 
@@ -731,7 +716,7 @@
 
 	plen = strlen(ppath);
 
-	if (!strneq(ppath, cpath, plen))
+	if (!strstarts(cpath, ppath))
 		die("Path \"%s\" is not valid as a child of \"%s\"\n",
 		    cpath, ppath);
 
@@ -750,7 +735,7 @@
 	char *flatname;
 	uint32_t val;
 
-	node = build_node(NULL, NULL);
+	node = build_node(NULL, NULL, NULL);
 
 	flatname = flat_read_string(dtbuf);
 
diff --git a/fstree.c b/fstree.c
index ae7d06c..5e59594 100644
--- a/fstree.c
+++ b/fstree.c
@@ -1,21 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
- *                                                                   USA
  */
 
 #include "dtc.h"
@@ -34,7 +19,7 @@
 	if (!d)
 		die("Couldn't opendir() \"%s\": %s\n", dirname, strerror(errno));
 
-	tree = build_node(NULL, NULL);
+	tree = build_node(NULL, NULL, NULL);
 
 	while ((de = readdir(d)) != NULL) {
 		char *tmpname;
@@ -45,7 +30,7 @@
 
 		tmpname = join_path(dirname, de->d_name);
 
-		if (lstat(tmpname, &st) < 0)
+		if (stat(tmpname, &st) < 0)
 			die("stat(%s): %s\n", tmpname, strerror(errno));
 
 		if (S_ISREG(st.st_mode)) {
@@ -60,7 +45,8 @@
 			} else {
 				prop = build_property(xstrdup(de->d_name),
 						      data_copy_file(pfile,
-								     st.st_size));
+								     st.st_size),
+						      NULL);
 				add_property(tree, prop);
 				fclose(pfile);
 			}
diff --git a/libfdt/.gitignore b/libfdt/.gitignore
new file mode 100644
index 0000000..fed4603
--- /dev/null
+++ b/libfdt/.gitignore
@@ -0,0 +1 @@
+libfdt.so.1
diff --git a/libfdt/Android.bp b/libfdt/Android.bp
index 320d4fc..16c6cf4 100644
--- a/libfdt/Android.bp
+++ b/libfdt/Android.bp
@@ -9,6 +9,7 @@
     ],
     srcs: [
         "fdt.c",
+        "fdt_check.c",
         "fdt_ro.c",
         "fdt_wip.c",
         "fdt_sw.c",
diff --git a/libfdt/Makefile.libfdt b/libfdt/Makefile.libfdt
index efe1537..3e70abf 100644
--- a/libfdt/Makefile.libfdt
+++ b/libfdt/Makefile.libfdt
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 # Makefile.libfdt
 #
 # This is not a complete Makefile of itself.  Instead, it is designed to
@@ -7,5 +8,11 @@
 LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h
 LIBFDT_VERSION = version.lds
 LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c \
-	fdt_addresses.c fdt_overlay.c acpi.c
+	fdt_addresses.c fdt_overlay.c fdt_check.c acpi.c
 LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
+LIBFDT_LIB = libfdt-$(DTC_VERSION).$(SHAREDLIB_EXT)
+
+libfdt_clean:
+	@$(VECHO) CLEAN "(libfdt)"
+	rm -f $(STD_CLEANFILES:%=$(LIBFDT_dir)/%)
+	rm -f $(LIBFDT_dir)/$(LIBFDT_soname)
diff --git a/libfdt/fdt.c b/libfdt/fdt.c
index 22286a1..c28fcc1 100644
--- a/libfdt/fdt.c
+++ b/libfdt/fdt.c
@@ -1,52 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * 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.
  */
 #include "libfdt_env.h"
 
@@ -55,22 +10,125 @@
 
 #include "libfdt_internal.h"
 
-int fdt_check_header(const void *fdt)
+/*
+ * Minimal sanity check for a read-only tree. fdt_ro_probe_() checks
+ * that the given buffer contains what appears to be a flattened
+ * device tree with sane information in its header.
+ */
+int32_t fdt_ro_probe_(const void *fdt)
 {
+	uint32_t totalsize = fdt_totalsize(fdt);
+
+	if (can_assume(VALID_DTB))
+		return totalsize;
+
 	if (fdt_magic(fdt) == FDT_MAGIC) {
 		/* Complete tree */
-		if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
-			return -FDT_ERR_BADVERSION;
-		if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
-			return -FDT_ERR_BADVERSION;
+		if (!can_assume(LATEST)) {
+			if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
+				return -FDT_ERR_BADVERSION;
+			if (fdt_last_comp_version(fdt) >
+					FDT_LAST_SUPPORTED_VERSION)
+				return -FDT_ERR_BADVERSION;
+		}
 	} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
 		/* Unfinished sequential-write blob */
-		if (fdt_size_dt_struct(fdt) == 0)
+		if (!can_assume(VALID_INPUT) && fdt_size_dt_struct(fdt) == 0)
 			return -FDT_ERR_BADSTATE;
 	} else {
 		return -FDT_ERR_BADMAGIC;
 	}
 
+	if (totalsize < INT32_MAX)
+		return totalsize;
+	else
+		return -FDT_ERR_TRUNCATED;
+}
+
+static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off)
+{
+	return (off >= hdrsize) && (off <= totalsize);
+}
+
+static int check_block_(uint32_t hdrsize, uint32_t totalsize,
+			uint32_t base, uint32_t size)
+{
+	if (!check_off_(hdrsize, totalsize, base))
+		return 0; /* block start out of bounds */
+	if ((base + size) < base)
+		return 0; /* overflow */
+	if (!check_off_(hdrsize, totalsize, base + size))
+		return 0; /* block end out of bounds */
+	return 1;
+}
+
+size_t fdt_header_size_(uint32_t version)
+{
+	if (version <= 1)
+		return FDT_V1_SIZE;
+	else if (version <= 2)
+		return FDT_V2_SIZE;
+	else if (version <= 3)
+		return FDT_V3_SIZE;
+	else if (version <= 16)
+		return FDT_V16_SIZE;
+	else
+		return FDT_V17_SIZE;
+}
+
+size_t fdt_header_size(const void *fdt)
+{
+	return can_assume(LATEST) ? FDT_V17_SIZE :
+		fdt_header_size_(fdt_version(fdt));
+}
+
+int fdt_check_header(const void *fdt)
+{
+	size_t hdrsize;
+
+	if (fdt_magic(fdt) != FDT_MAGIC)
+		return -FDT_ERR_BADMAGIC;
+	if (!can_assume(LATEST)) {
+		if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
+		    || (fdt_last_comp_version(fdt) >
+			FDT_LAST_SUPPORTED_VERSION))
+			return -FDT_ERR_BADVERSION;
+		if (fdt_version(fdt) < fdt_last_comp_version(fdt))
+			return -FDT_ERR_BADVERSION;
+	}
+	hdrsize = fdt_header_size(fdt);
+	if (!can_assume(VALID_DTB)) {
+
+		if ((fdt_totalsize(fdt) < hdrsize)
+		    || (fdt_totalsize(fdt) > INT_MAX))
+			return -FDT_ERR_TRUNCATED;
+
+		/* Bounds check memrsv block */
+		if (!check_off_(hdrsize, fdt_totalsize(fdt),
+				fdt_off_mem_rsvmap(fdt)))
+			return -FDT_ERR_TRUNCATED;
+	}
+
+	if (!can_assume(VALID_DTB)) {
+		/* Bounds check structure block */
+		if (!can_assume(LATEST) && fdt_version(fdt) < 17) {
+			if (!check_off_(hdrsize, fdt_totalsize(fdt),
+					fdt_off_dt_struct(fdt)))
+				return -FDT_ERR_TRUNCATED;
+		} else {
+			if (!check_block_(hdrsize, fdt_totalsize(fdt),
+					  fdt_off_dt_struct(fdt),
+					  fdt_size_dt_struct(fdt)))
+				return -FDT_ERR_TRUNCATED;
+		}
+
+		/* Bounds check strings block */
+		if (!check_block_(hdrsize, fdt_totalsize(fdt),
+				  fdt_off_dt_strings(fdt),
+				  fdt_size_dt_strings(fdt)))
+			return -FDT_ERR_TRUNCATED;
+	}
+
 	return 0;
 }
 
@@ -78,17 +136,18 @@
 {
 	unsigned absoffset = offset + fdt_off_dt_struct(fdt);
 
-	if ((absoffset < offset)
-	    || ((absoffset + len) < absoffset)
-	    || (absoffset + len) > fdt_totalsize(fdt))
-		return NULL;
+	if (!can_assume(VALID_INPUT))
+		if ((absoffset < offset)
+		    || ((absoffset + len) < absoffset)
+		    || (absoffset + len) > fdt_totalsize(fdt))
+			return NULL;
 
-	if (fdt_version(fdt) >= 0x11)
+	if (can_assume(LATEST) || fdt_version(fdt) >= 0x11)
 		if (((offset + len) < offset)
 		    || ((offset + len) > fdt_size_dt_struct(fdt)))
 			return NULL;
 
-	return _fdt_offset_ptr(fdt, offset);
+	return fdt_offset_ptr_(fdt, offset);
 }
 
 uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
@@ -100,7 +159,7 @@
 
 	*nextoffset = -FDT_ERR_TRUNCATED;
 	tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
-	if (!tagp)
+	if (!can_assume(VALID_DTB) && !tagp)
 		return FDT_END; /* premature end */
 	tag = fdt32_to_cpu(*tagp);
 	offset += FDT_TAGSIZE;
@@ -112,17 +171,21 @@
 		do {
 			p = fdt_offset_ptr(fdt, offset++, 1);
 		} while (p && (*p != '\0'));
-		if (!p)
+		if (!can_assume(VALID_DTB) && !p)
 			return FDT_END; /* premature end */
 		break;
 
 	case FDT_PROP:
 		lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
-		if (!lenp)
+		if (!can_assume(VALID_DTB) && !lenp)
 			return FDT_END; /* premature end */
 		/* skip-name offset, length and value */
 		offset += sizeof(struct fdt_property) - FDT_TAGSIZE
 			+ fdt32_to_cpu(*lenp);
+		if (!can_assume(LATEST) &&
+		    fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 &&
+		    ((offset - fdt32_to_cpu(*lenp)) % 8) != 0)
+			offset += 4;
 		break;
 
 	case FDT_END:
@@ -141,8 +204,10 @@
 	return tag;
 }
 
-int _fdt_check_node_offset(const void *fdt, int offset)
+int fdt_check_node_offset_(const void *fdt, int offset)
 {
+	if (can_assume(VALID_INPUT))
+		return offset;
 	if ((offset < 0) || (offset % FDT_TAGSIZE)
 	    || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
 		return -FDT_ERR_BADOFFSET;
@@ -150,7 +215,7 @@
 	return offset;
 }
 
-int _fdt_check_prop_offset(const void *fdt, int offset)
+int fdt_check_prop_offset_(const void *fdt, int offset)
 {
 	if ((offset < 0) || (offset % FDT_TAGSIZE)
 	    || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP))
@@ -165,7 +230,7 @@
 	uint32_t tag;
 
 	if (offset >= 0)
-		if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0)
+		if ((nextoffset = fdt_check_node_offset_(fdt, offset)) < 0)
 			return nextoffset;
 
 	do {
@@ -227,7 +292,7 @@
 	return offset;
 }
 
-const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
+const char *fdt_find_string_(const char *strtab, int tabsize, const char *s)
 {
 	int len = strlen(s) + 1;
 	const char *last = strtab + tabsize - len;
@@ -241,7 +306,7 @@
 
 int fdt_move(const void *fdt, void *buf, int bufsize)
 {
-	FDT_CHECK_HEADER(fdt);
+	FDT_RO_PROBE(fdt);
 
 	if (fdt_totalsize(fdt) > bufsize)
 		return -FDT_ERR_NOSPACE;
diff --git a/libfdt/fdt.h b/libfdt/fdt.h
index 526aedb..f2e6880 100644
--- a/libfdt/fdt.h
+++ b/libfdt/fdt.h
@@ -1,55 +1,10 @@
-#ifndef _FDT_H
-#define _FDT_H
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
+#ifndef FDT_H
+#define FDT_H
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
  * Copyright 2012 Kim Phillips, Freescale Semiconductor.
- *
- * 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.
  */
 
 #ifndef __ASSEMBLY__
@@ -108,4 +63,4 @@
 #define FDT_V16_SIZE	FDT_V3_SIZE
 #define FDT_V17_SIZE	(FDT_V16_SIZE + sizeof(fdt32_t))
 
-#endif /* _FDT_H */
+#endif /* FDT_H */
diff --git a/libfdt/fdt_addresses.c b/libfdt/fdt_addresses.c
index eff4dbc..9a82cd0 100644
--- a/libfdt/fdt_addresses.c
+++ b/libfdt/fdt_addresses.c
@@ -1,52 +1,8 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au>
- *
- * 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.
+ * Copyright (C) 2018 embedded brains GmbH
  */
 #include "libfdt_env.h"
 
@@ -55,42 +11,91 @@
 
 #include "libfdt_internal.h"
 
-int fdt_address_cells(const void *fdt, int nodeoffset)
+static int fdt_cells(const void *fdt, int nodeoffset, const char *name)
 {
-	const fdt32_t *ac;
-	int val;
+	const fdt32_t *c;
+	uint32_t val;
 	int len;
 
-	ac = fdt_getprop(fdt, nodeoffset, "#address-cells", &len);
-	if (!ac)
+	c = fdt_getprop(fdt, nodeoffset, name, &len);
+	if (!c)
+		return len;
+
+	if (len != sizeof(*c))
+		return -FDT_ERR_BADNCELLS;
+
+	val = fdt32_to_cpu(*c);
+	if (val > FDT_MAX_NCELLS)
+		return -FDT_ERR_BADNCELLS;
+
+	return (int)val;
+}
+
+int fdt_address_cells(const void *fdt, int nodeoffset)
+{
+	int val;
+
+	val = fdt_cells(fdt, nodeoffset, "#address-cells");
+	if (val == 0)
+		return -FDT_ERR_BADNCELLS;
+	if (val == -FDT_ERR_NOTFOUND)
 		return 2;
-
-	if (len != sizeof(*ac))
-		return -FDT_ERR_BADNCELLS;
-
-	val = fdt32_to_cpu(*ac);
-	if ((val <= 0) || (val > FDT_MAX_NCELLS))
-		return -FDT_ERR_BADNCELLS;
-
 	return val;
 }
 
 int fdt_size_cells(const void *fdt, int nodeoffset)
 {
-	const fdt32_t *sc;
 	int val;
-	int len;
 
-	sc = fdt_getprop(fdt, nodeoffset, "#size-cells", &len);
-	if (!sc)
-		return 2;
-
-	if (len != sizeof(*sc))
-		return -FDT_ERR_BADNCELLS;
-
-	val = fdt32_to_cpu(*sc);
-	if ((val < 0) || (val > FDT_MAX_NCELLS))
-		return -FDT_ERR_BADNCELLS;
-
+	val = fdt_cells(fdt, nodeoffset, "#size-cells");
+	if (val == -FDT_ERR_NOTFOUND)
+		return 1;
 	return val;
 }
+
+/* This function assumes that [address|size]_cells is 1 or 2 */
+int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
+			     const char *name, uint64_t addr, uint64_t size)
+{
+	int addr_cells, size_cells, ret;
+	uint8_t data[sizeof(fdt64_t) * 2], *prop;
+
+	ret = fdt_address_cells(fdt, parent);
+	if (ret < 0)
+		return ret;
+	addr_cells = ret;
+
+	ret = fdt_size_cells(fdt, parent);
+	if (ret < 0)
+		return ret;
+	size_cells = ret;
+
+	/* check validity of address */
+	prop = data;
+	if (addr_cells == 1) {
+		if ((addr > UINT32_MAX) || ((UINT32_MAX + 1 - addr) < size))
+			return -FDT_ERR_BADVALUE;
+
+		fdt32_st(prop, (uint32_t)addr);
+	} else if (addr_cells == 2) {
+		fdt64_st(prop, addr);
+	} else {
+		return -FDT_ERR_BADNCELLS;
+	}
+
+	/* check validity of size */
+	prop += addr_cells * sizeof(fdt32_t);
+	if (size_cells == 1) {
+		if (size > UINT32_MAX)
+			return -FDT_ERR_BADVALUE;
+
+		fdt32_st(prop, (uint32_t)size);
+	} else if (size_cells == 2) {
+		fdt64_st(prop, size);
+	} else {
+		return -FDT_ERR_BADNCELLS;
+	}
+
+	return fdt_appendprop(fdt, nodeoffset, name, data,
+			      (addr_cells + size_cells) * sizeof(fdt32_t));
+}
diff --git a/libfdt/fdt_check.c b/libfdt/fdt_check.c
new file mode 100644
index 0000000..7f6a96c
--- /dev/null
+++ b/libfdt/fdt_check.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+int fdt_check_full(const void *fdt, size_t bufsize)
+{
+	int err;
+	int num_memrsv;
+	int offset, nextoffset = 0;
+	uint32_t tag;
+	unsigned int depth = 0;
+	const void *prop;
+	const char *propname;
+
+	if (bufsize < FDT_V1_SIZE)
+		return -FDT_ERR_TRUNCATED;
+	err = fdt_check_header(fdt);
+	if (err != 0)
+		return err;
+	if (bufsize < fdt_totalsize(fdt))
+		return -FDT_ERR_TRUNCATED;
+
+	num_memrsv = fdt_num_mem_rsv(fdt);
+	if (num_memrsv < 0)
+		return num_memrsv;
+
+	while (1) {
+		offset = nextoffset;
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+		if (nextoffset < 0)
+			return nextoffset;
+
+		switch (tag) {
+		case FDT_NOP:
+			break;
+
+		case FDT_END:
+			if (depth != 0)
+				return -FDT_ERR_BADSTRUCTURE;
+			return 0;
+
+		case FDT_BEGIN_NODE:
+			depth++;
+			if (depth > INT_MAX)
+				return -FDT_ERR_BADSTRUCTURE;
+			break;
+
+		case FDT_END_NODE:
+			if (depth == 0)
+				return -FDT_ERR_BADSTRUCTURE;
+			depth--;
+			break;
+
+		case FDT_PROP:
+			prop = fdt_getprop_by_offset(fdt, offset, &propname,
+						     &err);
+			if (!prop)
+				return err;
+			break;
+
+		default:
+			return -FDT_ERR_INTERNAL;
+		}
+	}
+}
diff --git a/libfdt/fdt_empty_tree.c b/libfdt/fdt_empty_tree.c
index f2ae9b7..49d54d4 100644
--- a/libfdt/fdt_empty_tree.c
+++ b/libfdt/fdt_empty_tree.c
@@ -1,52 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2012 David Gibson, IBM Corporation.
- *
- * 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.
  */
 #include "libfdt_env.h"
 
diff --git a/libfdt/fdt_overlay.c b/libfdt/fdt_overlay.c
index ceb9687..b310e49 100644
--- a/libfdt/fdt_overlay.c
+++ b/libfdt/fdt_overlay.c
@@ -1,3 +1,9 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2016 Free Electrons
+ * Copyright (C) 2016 NextThing Co.
+ */
 #include "libfdt_env.h"
 
 #include <fdt.h>
@@ -39,47 +45,58 @@
  * @fdt: Base device tree blob
  * @fdto: Device tree overlay blob
  * @fragment: node offset of the fragment in the overlay
+ * @pathp: pointer which receives the path of the target (or NULL)
  *
  * overlay_get_target() retrieves the target offset in the base
- * device tree of a fragment, no matter how the actual targetting is
+ * device tree of a fragment, no matter how the actual targeting is
  * done (through a phandle or a path)
  *
  * returns:
- *      the targetted node offset in the base device tree
+ *      the targeted node offset in the base device tree
  *      Negative error code on error
  */
 static int overlay_get_target(const void *fdt, const void *fdto,
-			      int fragment)
+			      int fragment, char const **pathp)
 {
 	uint32_t phandle;
-	const char *path;
-	int path_len;
+	const char *path = NULL;
+	int path_len = 0, ret;
 
 	/* Try first to do a phandle based lookup */
 	phandle = overlay_get_target_phandle(fdto, fragment);
 	if (phandle == (uint32_t)-1)
 		return -FDT_ERR_BADPHANDLE;
 
-	if (phandle)
-		return fdt_node_offset_by_phandle(fdt, phandle);
+	/* no phandle, try path */
+	if (!phandle) {
+		/* And then a path based lookup */
+		path = fdt_getprop(fdto, fragment, "target-path", &path_len);
+		if (path)
+			ret = fdt_path_offset(fdt, path);
+		else
+			ret = path_len;
+	} else
+		ret = fdt_node_offset_by_phandle(fdt, phandle);
 
-	/* And then a path based lookup */
-	path = fdt_getprop(fdto, fragment, "target-path", &path_len);
-	if (!path) {
-		/*
-		 * If we haven't found either a target or a
-		 * target-path property in a node that contains a
-		 * __overlay__ subnode (we wouldn't be called
-		 * otherwise), consider it a improperly written
-		 * overlay
-		 */
-		if (path_len == -FDT_ERR_NOTFOUND)
-			return -FDT_ERR_BADOVERLAY;
+	/*
+	* If we haven't found either a target or a
+	* target-path property in a node that contains a
+	* __overlay__ subnode (we wouldn't be called
+	* otherwise), consider it a improperly written
+	* overlay
+	*/
+	if (ret < 0 && path_len == -FDT_ERR_NOTFOUND)
+		ret = -FDT_ERR_BADOVERLAY;
 
-		return path_len;
-	}
+	/* return on error */
+	if (ret < 0)
+		return ret;
 
-	return fdt_path_offset(fdt, path);
+	/* return pointer to path (if available) */
+	if (pathp)
+		*pathp = path ? path : NULL;
+
+	return ret;
 }
 
 /**
@@ -590,7 +607,7 @@
  *
  * overlay_merge() merges an overlay into its base device tree.
  *
- * This is the final step in the device tree overlay application
+ * This is the next to last step in the device tree overlay application
  * process, when all the phandles have been adjusted and resolved and
  * you just have to merge overlay into the base device tree.
  *
@@ -618,7 +635,7 @@
 		if (overlay < 0)
 			return overlay;
 
-		target = overlay_get_target(fdt, fdto, fragment);
+		target = overlay_get_target(fdt, fdto, fragment, NULL);
 		if (target < 0)
 			return target;
 
@@ -630,13 +647,196 @@
 	return 0;
 }
 
+static int get_path_len(const void *fdt, int nodeoffset)
+{
+	int len = 0, namelen;
+	const char *name;
+
+	FDT_RO_PROBE(fdt);
+
+	for (;;) {
+		name = fdt_get_name(fdt, nodeoffset, &namelen);
+		if (!name)
+			return namelen;
+
+		/* root? we're done */
+		if (namelen == 0)
+			break;
+
+		nodeoffset = fdt_parent_offset(fdt, nodeoffset);
+		if (nodeoffset < 0)
+			return nodeoffset;
+		len += namelen + 1;
+	}
+
+	/* in case of root pretend it's "/" */
+	if (len == 0)
+		len++;
+	return len;
+}
+
+/**
+ * overlay_symbol_update - Update the symbols of base tree after a merge
+ * @fdt: Base Device Tree blob
+ * @fdto: Device tree overlay blob
+ *
+ * overlay_symbol_update() updates the symbols of the base tree with the
+ * symbols of the applied overlay
+ *
+ * This is the last step in the device tree overlay application
+ * process, allowing the reference of overlay symbols by subsequent
+ * overlay operations.
+ *
+ * returns:
+ *      0 on success
+ *      Negative error code on failure
+ */
+static int overlay_symbol_update(void *fdt, void *fdto)
+{
+	int root_sym, ov_sym, prop, path_len, fragment, target;
+	int len, frag_name_len, ret, rel_path_len;
+	const char *s, *e;
+	const char *path;
+	const char *name;
+	const char *frag_name;
+	const char *rel_path;
+	const char *target_path;
+	char *buf;
+	void *p;
+
+	ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__");
+
+	/* if no overlay symbols exist no problem */
+	if (ov_sym < 0)
+		return 0;
+
+	root_sym = fdt_subnode_offset(fdt, 0, "__symbols__");
+
+	/* it no root symbols exist we should create them */
+	if (root_sym == -FDT_ERR_NOTFOUND)
+		root_sym = fdt_add_subnode(fdt, 0, "__symbols__");
+
+	/* any error is fatal now */
+	if (root_sym < 0)
+		return root_sym;
+
+	/* iterate over each overlay symbol */
+	fdt_for_each_property_offset(prop, fdto, ov_sym) {
+		path = fdt_getprop_by_offset(fdto, prop, &name, &path_len);
+		if (!path)
+			return path_len;
+
+		/* verify it's a string property (terminated by a single \0) */
+		if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1])
+			return -FDT_ERR_BADVALUE;
+
+		/* keep end marker to avoid strlen() */
+		e = path + path_len;
+
+		if (*path != '/')
+			return -FDT_ERR_BADVALUE;
+
+		/* get fragment name first */
+		s = strchr(path + 1, '/');
+		if (!s) {
+			/* Symbol refers to something that won't end
+			 * up in the target tree */
+			continue;
+		}
+
+		frag_name = path + 1;
+		frag_name_len = s - path - 1;
+
+		/* verify format; safe since "s" lies in \0 terminated prop */
+		len = sizeof("/__overlay__/") - 1;
+		if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) {
+			/* /<fragment-name>/__overlay__/<relative-subnode-path> */
+			rel_path = s + len;
+			rel_path_len = e - rel_path - 1;
+		} else if ((e - s) == len
+			   && (memcmp(s, "/__overlay__", len - 1) == 0)) {
+			/* /<fragment-name>/__overlay__ */
+			rel_path = "";
+			rel_path_len = 0;
+		} else {
+			/* Symbol refers to something that won't end
+			 * up in the target tree */
+			continue;
+		}
+
+		/* find the fragment index in which the symbol lies */
+		ret = fdt_subnode_offset_namelen(fdto, 0, frag_name,
+					       frag_name_len);
+		/* not found? */
+		if (ret < 0)
+			return -FDT_ERR_BADOVERLAY;
+		fragment = ret;
+
+		/* an __overlay__ subnode must exist */
+		ret = fdt_subnode_offset(fdto, fragment, "__overlay__");
+		if (ret < 0)
+			return -FDT_ERR_BADOVERLAY;
+
+		/* get the target of the fragment */
+		ret = overlay_get_target(fdt, fdto, fragment, &target_path);
+		if (ret < 0)
+			return ret;
+		target = ret;
+
+		/* if we have a target path use */
+		if (!target_path) {
+			ret = get_path_len(fdt, target);
+			if (ret < 0)
+				return ret;
+			len = ret;
+		} else {
+			len = strlen(target_path);
+		}
+
+		ret = fdt_setprop_placeholder(fdt, root_sym, name,
+				len + (len > 1) + rel_path_len + 1, &p);
+		if (ret < 0)
+			return ret;
+
+		if (!target_path) {
+			/* again in case setprop_placeholder changed it */
+			ret = overlay_get_target(fdt, fdto, fragment, &target_path);
+			if (ret < 0)
+				return ret;
+			target = ret;
+		}
+
+		buf = p;
+		if (len > 1) { /* target is not root */
+			if (!target_path) {
+				ret = fdt_get_path(fdt, target, buf, len + 1);
+				if (ret < 0)
+					return ret;
+			} else
+				memcpy(buf, target_path, len + 1);
+
+		} else
+			len--;
+
+		buf[len] = '/';
+		memcpy(buf + len + 1, rel_path, rel_path_len);
+		buf[len + 1 + rel_path_len] = '\0';
+	}
+
+	return 0;
+}
+
 int fdt_overlay_apply(void *fdt, void *fdto)
 {
-	uint32_t delta = fdt_get_max_phandle(fdt);
+	uint32_t delta;
 	int ret;
 
-	FDT_CHECK_HEADER(fdt);
-	FDT_CHECK_HEADER(fdto);
+	FDT_RO_PROBE(fdt);
+	FDT_RO_PROBE(fdto);
+
+	ret = fdt_find_max_phandle(fdt, &delta);
+	if (ret)
+		goto err;
 
 	ret = overlay_adjust_local_phandles(fdto, delta);
 	if (ret)
@@ -654,6 +854,10 @@
 	if (ret)
 		goto err;
 
+	ret = overlay_symbol_update(fdt, fdto);
+	if (ret)
+		goto err;
+
 	/*
 	 * The overlay has been damaged, erase its magic.
 	 */
diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c
index 08de2cc..e03570a 100644
--- a/libfdt/fdt_ro.c
+++ b/libfdt/fdt_ro.c
@@ -1,52 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * 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.
  */
 #include "libfdt_env.h"
 
@@ -55,12 +10,13 @@
 
 #include "libfdt_internal.h"
 
-static int _fdt_nodename_eq(const void *fdt, int offset,
+static int fdt_nodename_eq_(const void *fdt, int offset,
 			    const char *s, int len)
 {
-	const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
+	int olen;
+	const char *p = fdt_get_name(fdt, offset, &olen);
 
-	if (!p)
+	if (!p || olen < len)
 		/* short match */
 		return 0;
 
@@ -75,63 +31,172 @@
 		return 0;
 }
 
+const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
+{
+	int32_t totalsize;
+	uint32_t absoffset;
+	size_t len;
+	int err;
+	const char *s, *n;
+
+	if (can_assume(VALID_INPUT)) {
+		s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
+
+		if (lenp)
+			*lenp = strlen(s);
+		return s;
+	}
+	totalsize = fdt_ro_probe_(fdt);
+	err = totalsize;
+	if (totalsize < 0)
+		goto fail;
+
+	err = -FDT_ERR_BADOFFSET;
+	absoffset = stroffset + fdt_off_dt_strings(fdt);
+	if (absoffset >= totalsize)
+		goto fail;
+	len = totalsize - absoffset;
+
+	if (fdt_magic(fdt) == FDT_MAGIC) {
+		if (stroffset < 0)
+			goto fail;
+		if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
+			if (stroffset >= fdt_size_dt_strings(fdt))
+				goto fail;
+			if ((fdt_size_dt_strings(fdt) - stroffset) < len)
+				len = fdt_size_dt_strings(fdt) - stroffset;
+		}
+	} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
+		if ((stroffset >= 0)
+		    || (stroffset < -fdt_size_dt_strings(fdt)))
+			goto fail;
+		if ((-stroffset) < len)
+			len = -stroffset;
+	} else {
+		err = -FDT_ERR_INTERNAL;
+		goto fail;
+	}
+
+	s = (const char *)fdt + absoffset;
+	n = memchr(s, '\0', len);
+	if (!n) {
+		/* missing terminating NULL */
+		err = -FDT_ERR_TRUNCATED;
+		goto fail;
+	}
+
+	if (lenp)
+		*lenp = n - s;
+	return s;
+
+fail:
+	if (lenp)
+		*lenp = err;
+	return NULL;
+}
+
 const char *fdt_string(const void *fdt, int stroffset)
 {
-	return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
+	return fdt_get_string(fdt, stroffset, NULL);
 }
 
-static int _fdt_string_eq(const void *fdt, int stroffset,
+static int fdt_string_eq_(const void *fdt, int stroffset,
 			  const char *s, int len)
 {
-	const char *p = fdt_string(fdt, stroffset);
+	int slen;
+	const char *p = fdt_get_string(fdt, stroffset, &slen);
 
-	return (strlen(p) == len) && (memcmp(p, s, len) == 0);
+	return p && (slen == len) && (memcmp(p, s, len) == 0);
 }
 
-uint32_t fdt_get_max_phandle(const void *fdt)
+int fdt_find_max_phandle(const void *fdt, uint32_t *phandle)
 {
-	uint32_t max_phandle = 0;
-	int offset;
+	uint32_t max = 0;
+	int offset = -1;
 
-	for (offset = fdt_next_node(fdt, -1, NULL);;
-	     offset = fdt_next_node(fdt, offset, NULL)) {
-		uint32_t phandle;
+	while (true) {
+		uint32_t value;
 
-		if (offset == -FDT_ERR_NOTFOUND)
-			return max_phandle;
+		offset = fdt_next_node(fdt, offset, NULL);
+		if (offset < 0) {
+			if (offset == -FDT_ERR_NOTFOUND)
+				break;
 
-		if (offset < 0)
-			return (uint32_t)-1;
+			return offset;
+		}
 
-		phandle = fdt_get_phandle(fdt, offset);
-		if (phandle == (uint32_t)-1)
-			continue;
+		value = fdt_get_phandle(fdt, offset);
 
-		if (phandle > max_phandle)
-			max_phandle = phandle;
+		if (value > max)
+			max = value;
 	}
 
+	if (phandle)
+		*phandle = max;
+
 	return 0;
 }
 
+int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
+{
+	uint32_t max;
+	int err;
+
+	err = fdt_find_max_phandle(fdt, &max);
+	if (err < 0)
+		return err;
+
+	if (max == FDT_MAX_PHANDLE)
+		return -FDT_ERR_NOPHANDLES;
+
+	if (phandle)
+		*phandle = max + 1;
+
+	return 0;
+}
+
+static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
+{
+	int offset = n * sizeof(struct fdt_reserve_entry);
+	int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
+
+	if (!can_assume(VALID_INPUT)) {
+		if (absoffset < fdt_off_mem_rsvmap(fdt))
+			return NULL;
+		if (absoffset > fdt_totalsize(fdt) -
+		    sizeof(struct fdt_reserve_entry))
+			return NULL;
+	}
+	return fdt_mem_rsv_(fdt, n);
+}
+
 int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
 {
-	FDT_CHECK_HEADER(fdt);
-	*address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
-	*size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
+	const struct fdt_reserve_entry *re;
+
+	FDT_RO_PROBE(fdt);
+	re = fdt_mem_rsv(fdt, n);
+	if (!can_assume(VALID_INPUT) && !re)
+		return -FDT_ERR_BADOFFSET;
+
+	*address = fdt64_ld(&re->address);
+	*size = fdt64_ld(&re->size);
 	return 0;
 }
 
 int fdt_num_mem_rsv(const void *fdt)
 {
-	int i = 0;
+	int i;
+	const struct fdt_reserve_entry *re;
 
-	while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
-		i++;
-	return i;
+	for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
+		if (fdt64_ld(&re->size) == 0)
+			return i;
+	}
+	return -FDT_ERR_TRUNCATED;
 }
 
-static int _nextprop(const void *fdt, int offset)
+static int nextprop_(const void *fdt, int offset)
 {
 	uint32_t tag;
 	int nextoffset;
@@ -160,13 +225,13 @@
 {
 	int depth;
 
-	FDT_CHECK_HEADER(fdt);
+	FDT_RO_PROBE(fdt);
 
 	for (depth = 0;
 	     (offset >= 0) && (depth >= 0);
 	     offset = fdt_next_node(fdt, offset, &depth))
 		if ((depth == 1)
-		    && _fdt_nodename_eq(fdt, offset, name, namelen))
+		    && fdt_nodename_eq_(fdt, offset, name, namelen))
 			return offset;
 
 	if (depth < 0)
@@ -186,7 +251,7 @@
 	const char *p = path;
 	int offset = 0;
 
-	FDT_CHECK_HEADER(fdt);
+	FDT_RO_PROBE(fdt);
 
 	/* see if we have an alias */
 	if (*path != '/') {
@@ -232,17 +297,35 @@
 
 const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
 {
-	const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
+	const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset);
+	const char *nameptr;
 	int err;
 
-	if (((err = fdt_check_header(fdt)) != 0)
-	    || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
+	if (((err = fdt_ro_probe_(fdt)) < 0)
+	    || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
 			goto fail;
 
-	if (len)
-		*len = strlen(nh->name);
+	nameptr = nh->name;
 
-	return nh->name;
+	if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
+		/*
+		 * For old FDT versions, match the naming conventions of V16:
+		 * give only the leaf name (after all /). The actual tree
+		 * contents are loosely checked.
+		 */
+		const char *leaf;
+		leaf = strrchr(nameptr, '/');
+		if (leaf == NULL) {
+			err = -FDT_ERR_BADSTRUCTURE;
+			goto fail;
+		}
+		nameptr = leaf+1;
+	}
+
+	if (len)
+		*len = strlen(nameptr);
+
+	return nameptr;
 
  fail:
 	if (len)
@@ -254,58 +337,81 @@
 {
 	int offset;
 
-	if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
+	if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
 		return offset;
 
-	return _nextprop(fdt, offset);
+	return nextprop_(fdt, offset);
 }
 
 int fdt_next_property_offset(const void *fdt, int offset)
 {
-	if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0)
+	if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0)
 		return offset;
 
-	return _nextprop(fdt, offset);
+	return nextprop_(fdt, offset);
+}
+
+static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
+						              int offset,
+						              int *lenp)
+{
+	int err;
+	const struct fdt_property *prop;
+
+	if (!can_assume(VALID_INPUT) &&
+	    (err = fdt_check_prop_offset_(fdt, offset)) < 0) {
+		if (lenp)
+			*lenp = err;
+		return NULL;
+	}
+
+	prop = fdt_offset_ptr_(fdt, offset);
+
+	if (lenp)
+		*lenp = fdt32_ld(&prop->len);
+
+	return prop;
 }
 
 const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
 						      int offset,
 						      int *lenp)
 {
-	int err;
-	const struct fdt_property *prop;
+	/* Prior to version 16, properties may need realignment
+	 * and this API does not work. fdt_getprop_*() will, however. */
 
-	if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) {
+	if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
 		if (lenp)
-			*lenp = err;
+			*lenp = -FDT_ERR_BADVERSION;
 		return NULL;
 	}
 
-	prop = _fdt_offset_ptr(fdt, offset);
-
-	if (lenp)
-		*lenp = fdt32_to_cpu(prop->len);
-
-	return prop;
+	return fdt_get_property_by_offset_(fdt, offset, lenp);
 }
 
-const struct fdt_property *fdt_get_property_namelen(const void *fdt,
-						    int offset,
-						    const char *name,
-						    int namelen, int *lenp)
+static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
+						            int offset,
+						            const char *name,
+						            int namelen,
+							    int *lenp,
+							    int *poffset)
 {
 	for (offset = fdt_first_property_offset(fdt, offset);
 	     (offset >= 0);
 	     (offset = fdt_next_property_offset(fdt, offset))) {
 		const struct fdt_property *prop;
 
-		if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) {
+		prop = fdt_get_property_by_offset_(fdt, offset, lenp);
+		if (!can_assume(LIBFDT_FLAWLESS) && !prop) {
 			offset = -FDT_ERR_INTERNAL;
 			break;
 		}
-		if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),
-				   name, namelen))
+		if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff),
+				   name, namelen)) {
+			if (poffset)
+				*poffset = offset;
 			return prop;
+		}
 	}
 
 	if (lenp)
@@ -313,6 +419,25 @@
 	return NULL;
 }
 
+
+const struct fdt_property *fdt_get_property_namelen(const void *fdt,
+						    int offset,
+						    const char *name,
+						    int namelen, int *lenp)
+{
+	/* Prior to version 16, properties may need realignment
+	 * and this API does not work. fdt_getprop_*() will, however. */
+	if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
+		if (lenp)
+			*lenp = -FDT_ERR_BADVERSION;
+		return NULL;
+	}
+
+	return fdt_get_property_namelen_(fdt, offset, name, namelen, lenp,
+					 NULL);
+}
+
+
 const struct fdt_property *fdt_get_property(const void *fdt,
 					    int nodeoffset,
 					    const char *name, int *lenp)
@@ -324,12 +449,18 @@
 const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
 				const char *name, int namelen, int *lenp)
 {
+	int poffset;
 	const struct fdt_property *prop;
 
-	prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
+	prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp,
+					 &poffset);
 	if (!prop)
 		return NULL;
 
+	/* Handle realignment */
+	if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
+	    (poffset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
+		return prop->data + 4;
 	return prop->data;
 }
 
@@ -338,11 +469,31 @@
 {
 	const struct fdt_property *prop;
 
-	prop = fdt_get_property_by_offset(fdt, offset, lenp);
+	prop = fdt_get_property_by_offset_(fdt, offset, lenp);
 	if (!prop)
 		return NULL;
-	if (namep)
-		*namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+	if (namep) {
+		const char *name;
+		int namelen;
+
+		if (!can_assume(VALID_INPUT)) {
+			name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff),
+					      &namelen);
+			if (!name) {
+				if (lenp)
+					*lenp = namelen;
+				return NULL;
+			}
+			*namep = name;
+		} else {
+			*namep = fdt_string(fdt, fdt32_ld(&prop->nameoff));
+		}
+	}
+
+	/* Handle realignment */
+	if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
+	    (offset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
+		return prop->data + 4;
 	return prop->data;
 }
 
@@ -366,7 +517,7 @@
 			return 0;
 	}
 
-	return fdt32_to_cpu(*php);
+	return fdt32_ld(php);
 }
 
 const char *fdt_get_alias_namelen(const void *fdt,
@@ -392,7 +543,7 @@
 	int offset, depth, namelen;
 	const char *name;
 
-	FDT_CHECK_HEADER(fdt);
+	FDT_RO_PROBE(fdt);
 
 	if (buflen < 2)
 		return -FDT_ERR_NOSPACE;
@@ -444,7 +595,7 @@
 	int offset, depth;
 	int supernodeoffset = -FDT_ERR_INTERNAL;
 
-	FDT_CHECK_HEADER(fdt);
+	FDT_RO_PROBE(fdt);
 
 	if (supernodedepth < 0)
 		return -FDT_ERR_NOTFOUND;
@@ -466,10 +617,12 @@
 		}
 	}
 
-	if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
-		return -FDT_ERR_BADOFFSET;
-	else if (offset == -FDT_ERR_BADOFFSET)
-		return -FDT_ERR_BADSTRUCTURE;
+	if (!can_assume(VALID_INPUT)) {
+		if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+			return -FDT_ERR_BADOFFSET;
+		else if (offset == -FDT_ERR_BADOFFSET)
+			return -FDT_ERR_BADSTRUCTURE;
+	}
 
 	return offset; /* error from fdt_next_node() */
 }
@@ -481,7 +634,8 @@
 
 	err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
 	if (err)
-		return (err < 0) ? err : -FDT_ERR_INTERNAL;
+		return (can_assume(LIBFDT_FLAWLESS) || err < 0) ? err :
+			-FDT_ERR_INTERNAL;
 	return nodedepth;
 }
 
@@ -503,7 +657,7 @@
 	const void *val;
 	int len;
 
-	FDT_CHECK_HEADER(fdt);
+	FDT_RO_PROBE(fdt);
 
 	/* FIXME: The algorithm here is pretty horrible: we scan each
 	 * property of a node in fdt_getprop(), then if that didn't
@@ -529,7 +683,7 @@
 	if ((phandle == 0) || (phandle == -1))
 		return -FDT_ERR_BADPHANDLE;
 
-	FDT_CHECK_HEADER(fdt);
+	FDT_RO_PROBE(fdt);
 
 	/* FIXME: The algorithm here is pretty horrible: we
 	 * potentially scan each property of a node in
@@ -682,7 +836,7 @@
 {
 	int offset, err;
 
-	FDT_CHECK_HEADER(fdt);
+	FDT_RO_PROBE(fdt);
 
 	/* FIXME: The algorithm here is pretty horrible: we scan each
 	 * property of a node in fdt_node_check_compatible(), then if
diff --git a/libfdt/fdt_rw.c b/libfdt/fdt_rw.c
index 8b487f6..93e4a2b 100644
--- a/libfdt/fdt_rw.c
+++ b/libfdt/fdt_rw.c
@@ -1,52 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * 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.
  */
 #include "libfdt_env.h"
 
@@ -55,8 +10,8 @@
 
 #include "libfdt_internal.h"
 
-static int _fdt_blocks_misordered(const void *fdt,
-			      int mem_rsv_size, int struct_size)
+static int fdt_blocks_misordered_(const void *fdt,
+				  int mem_rsv_size, int struct_size)
 {
 	return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
 		|| (fdt_off_dt_struct(fdt) <
@@ -67,54 +22,57 @@
 		    (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
 }
 
-static int _fdt_rw_check_header(void *fdt)
+static int fdt_rw_probe_(void *fdt)
 {
-	FDT_CHECK_HEADER(fdt);
+	if (can_assume(VALID_DTB))
+		return 0;
+	FDT_RO_PROBE(fdt);
 
-	if (fdt_version(fdt) < 17)
+	if (!can_assume(LATEST) && fdt_version(fdt) < 17)
 		return -FDT_ERR_BADVERSION;
-	if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
+	if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry),
 				   fdt_size_dt_struct(fdt)))
 		return -FDT_ERR_BADLAYOUT;
-	if (fdt_version(fdt) > 17)
+	if (!can_assume(LATEST) && fdt_version(fdt) > 17)
 		fdt_set_version(fdt, 17);
 
 	return 0;
 }
 
-#define FDT_RW_CHECK_HEADER(fdt) \
+#define FDT_RW_PROBE(fdt) \
 	{ \
-		int __err; \
-		if ((__err = _fdt_rw_check_header(fdt)) != 0) \
-			return __err; \
+		int err_; \
+		if ((err_ = fdt_rw_probe_(fdt)) != 0) \
+			return err_; \
 	}
 
-static inline int _fdt_data_size(void *fdt)
+static inline unsigned int fdt_data_size_(void *fdt)
 {
 	return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
 }
 
-static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen)
+static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen)
 {
 	char *p = splicepoint;
-	char *end = (char *)fdt + _fdt_data_size(fdt);
+	unsigned int dsize = fdt_data_size_(fdt);
+	size_t soff = p - (char *)fdt;
 
-	if (((p + oldlen) < p) || ((p + oldlen) > end))
+	if ((oldlen < 0) || (soff + oldlen < soff) || (soff + oldlen > dsize))
 		return -FDT_ERR_BADOFFSET;
-	if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt))
+	if ((p < (char *)fdt) || (dsize + newlen < oldlen))
 		return -FDT_ERR_BADOFFSET;
-	if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
+	if (dsize - oldlen + newlen > fdt_totalsize(fdt))
 		return -FDT_ERR_NOSPACE;
-	memmove(p + newlen, p + oldlen, end - p - oldlen);
+	memmove(p + newlen, p + oldlen, ((char *)fdt + dsize) - (p + oldlen));
 	return 0;
 }
 
-static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
+static int fdt_splice_mem_rsv_(void *fdt, struct fdt_reserve_entry *p,
 			       int oldn, int newn)
 {
 	int delta = (newn - oldn) * sizeof(*p);
 	int err;
-	err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
+	err = fdt_splice_(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
 	if (err)
 		return err;
 	fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
@@ -122,13 +80,13 @@
 	return 0;
 }
 
-static int _fdt_splice_struct(void *fdt, void *p,
+static int fdt_splice_struct_(void *fdt, void *p,
 			      int oldlen, int newlen)
 {
 	int delta = newlen - oldlen;
 	int err;
 
-	if ((err = _fdt_splice(fdt, p, oldlen, newlen)))
+	if ((err = fdt_splice_(fdt, p, oldlen, newlen)))
 		return err;
 
 	fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
@@ -136,20 +94,37 @@
 	return 0;
 }
 
-static int _fdt_splice_string(void *fdt, int newlen)
+/* Must only be used to roll back in case of error */
+static void fdt_del_last_string_(void *fdt, const char *s)
+{
+	int newlen = strlen(s) + 1;
+
+	fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) - newlen);
+}
+
+static int fdt_splice_string_(void *fdt, int newlen)
 {
 	void *p = (char *)fdt
 		+ fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
 	int err;
 
-	if ((err = _fdt_splice(fdt, p, 0, newlen)))
+	if ((err = fdt_splice_(fdt, p, 0, newlen)))
 		return err;
 
 	fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
 	return 0;
 }
 
-static int _fdt_find_add_string(void *fdt, const char *s)
+/**
+ * fdt_find_add_string_() - Find or allocate a string
+ *
+ * @fdt: pointer to the device tree to check/adjust
+ * @s: string to find/add
+ * @allocated: Set to 0 if the string was found, 1 if not found and so
+ *	allocated. Ignored if can_assume(NO_ROLLBACK)
+ * @return offset of string in the string table (whether found or added)
+ */
+static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
 {
 	char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
 	const char *p;
@@ -157,16 +132,22 @@
 	int len = strlen(s) + 1;
 	int err;
 
-	p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s);
+	if (!can_assume(NO_ROLLBACK))
+		*allocated = 0;
+
+	p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s);
 	if (p)
 		/* found it */
 		return (p - strtab);
 
 	new = strtab + fdt_size_dt_strings(fdt);
-	err = _fdt_splice_string(fdt, len);
+	err = fdt_splice_string_(fdt, len);
 	if (err)
 		return err;
 
+	if (!can_assume(NO_ROLLBACK))
+		*allocated = 1;
+
 	memcpy(new, s, len);
 	return (new - strtab);
 }
@@ -176,10 +157,10 @@
 	struct fdt_reserve_entry *re;
 	int err;
 
-	FDT_RW_CHECK_HEADER(fdt);
+	FDT_RW_PROBE(fdt);
 
-	re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
-	err = _fdt_splice_mem_rsv(fdt, re, 0, 1);
+	re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt));
+	err = fdt_splice_mem_rsv_(fdt, re, 0, 1);
 	if (err)
 		return err;
 
@@ -190,17 +171,17 @@
 
 int fdt_del_mem_rsv(void *fdt, int n)
 {
-	struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
+	struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n);
 
-	FDT_RW_CHECK_HEADER(fdt);
+	FDT_RW_PROBE(fdt);
 
 	if (n >= fdt_num_mem_rsv(fdt))
 		return -FDT_ERR_NOTFOUND;
 
-	return _fdt_splice_mem_rsv(fdt, re, 1, 0);
+	return fdt_splice_mem_rsv_(fdt, re, 1, 0);
 }
 
-static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
+static int fdt_resize_property_(void *fdt, int nodeoffset, const char *name,
 				int len, struct fdt_property **prop)
 {
 	int oldlen;
@@ -210,7 +191,7 @@
 	if (!*prop)
 		return oldlen;
 
-	if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
+	if ((err = fdt_splice_struct_(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
 				      FDT_TAGALIGN(len))))
 		return err;
 
@@ -218,27 +199,32 @@
 	return 0;
 }
 
-static int _fdt_add_property(void *fdt, int nodeoffset, const char *name,
+static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
 			     int len, struct fdt_property **prop)
 {
 	int proplen;
 	int nextoffset;
 	int namestroff;
 	int err;
+	int allocated;
 
-	if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
+	if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
 		return nextoffset;
 
-	namestroff = _fdt_find_add_string(fdt, name);
+	namestroff = fdt_find_add_string_(fdt, name, &allocated);
 	if (namestroff < 0)
 		return namestroff;
 
-	*prop = _fdt_offset_ptr_w(fdt, nextoffset);
+	*prop = fdt_offset_ptr_w_(fdt, nextoffset);
 	proplen = sizeof(**prop) + FDT_TAGALIGN(len);
 
-	err = _fdt_splice_struct(fdt, *prop, 0, proplen);
-	if (err)
+	err = fdt_splice_struct_(fdt, *prop, 0, proplen);
+	if (err) {
+		/* Delete the string if we failed to add it */
+		if (!can_assume(NO_ROLLBACK) && allocated)
+			fdt_del_last_string_(fdt, name);
 		return err;
+	}
 
 	(*prop)->tag = cpu_to_fdt32(FDT_PROP);
 	(*prop)->nameoff = cpu_to_fdt32(namestroff);
@@ -252,7 +238,7 @@
 	int oldlen, newlen;
 	int err;
 
-	FDT_RW_CHECK_HEADER(fdt);
+	FDT_RW_PROBE(fdt);
 
 	namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
 	if (!namep)
@@ -260,7 +246,7 @@
 
 	newlen = strlen(name);
 
-	err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1),
+	err = fdt_splice_struct_(fdt, namep, FDT_TAGALIGN(oldlen+1),
 				 FDT_TAGALIGN(newlen+1));
 	if (err)
 		return err;
@@ -269,22 +255,36 @@
 	return 0;
 }
 
-int fdt_setprop(void *fdt, int nodeoffset, const char *name,
-		const void *val, int len)
+int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
+			    int len, void **prop_data)
 {
 	struct fdt_property *prop;
 	int err;
 
-	FDT_RW_CHECK_HEADER(fdt);
+	FDT_RW_PROBE(fdt);
 
-	err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop);
+	err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop);
 	if (err == -FDT_ERR_NOTFOUND)
-		err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
+		err = fdt_add_property_(fdt, nodeoffset, name, len, &prop);
+	if (err)
+		return err;
+
+	*prop_data = prop->data;
+	return 0;
+}
+
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+		const void *val, int len)
+{
+	void *prop_data;
+	int err;
+
+	err = fdt_setprop_placeholder(fdt, nodeoffset, name, len, &prop_data);
 	if (err)
 		return err;
 
 	if (len)
-		memcpy(prop->data, val, len);
+		memcpy(prop_data, val, len);
 	return 0;
 }
 
@@ -294,12 +294,12 @@
 	struct fdt_property *prop;
 	int err, oldlen, newlen;
 
-	FDT_RW_CHECK_HEADER(fdt);
+	FDT_RW_PROBE(fdt);
 
 	prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
 	if (prop) {
 		newlen = len + oldlen;
-		err = _fdt_splice_struct(fdt, prop->data,
+		err = fdt_splice_struct_(fdt, prop->data,
 					 FDT_TAGALIGN(oldlen),
 					 FDT_TAGALIGN(newlen));
 		if (err)
@@ -307,7 +307,7 @@
 		prop->len = cpu_to_fdt32(newlen);
 		memcpy(prop->data + oldlen, val, len);
 	} else {
-		err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
+		err = fdt_add_property_(fdt, nodeoffset, name, len, &prop);
 		if (err)
 			return err;
 		memcpy(prop->data, val, len);
@@ -320,14 +320,14 @@
 	struct fdt_property *prop;
 	int len, proplen;
 
-	FDT_RW_CHECK_HEADER(fdt);
+	FDT_RW_PROBE(fdt);
 
 	prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
 	if (!prop)
 		return len;
 
 	proplen = sizeof(*prop) + FDT_TAGALIGN(len);
-	return _fdt_splice_struct(fdt, prop, proplen, 0);
+	return fdt_splice_struct_(fdt, prop, proplen, 0);
 }
 
 int fdt_add_subnode_namelen(void *fdt, int parentoffset,
@@ -340,7 +340,7 @@
 	uint32_t tag;
 	fdt32_t *endtag;
 
-	FDT_RW_CHECK_HEADER(fdt);
+	FDT_RW_PROBE(fdt);
 
 	offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
 	if (offset >= 0)
@@ -355,10 +355,10 @@
 		tag = fdt_next_tag(fdt, offset, &nextoffset);
 	} while ((tag == FDT_PROP) || (tag == FDT_NOP));
 
-	nh = _fdt_offset_ptr_w(fdt, offset);
+	nh = fdt_offset_ptr_w_(fdt, offset);
 	nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;
 
-	err = _fdt_splice_struct(fdt, nh, 0, nodelen);
+	err = fdt_splice_struct_(fdt, nh, 0, nodelen);
 	if (err)
 		return err;
 
@@ -380,17 +380,17 @@
 {
 	int endoffset;
 
-	FDT_RW_CHECK_HEADER(fdt);
+	FDT_RW_PROBE(fdt);
 
-	endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+	endoffset = fdt_node_end_offset_(fdt, nodeoffset);
 	if (endoffset < 0)
 		return endoffset;
 
-	return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
+	return fdt_splice_struct_(fdt, fdt_offset_ptr_w_(fdt, nodeoffset),
 				  endoffset - nodeoffset, 0);
 }
 
-static void _fdt_packblocks(const char *old, char *new,
+static void fdt_packblocks_(const char *old, char *new,
 			    int mem_rsv_size, int struct_size)
 {
 	int mem_rsv_off, struct_off, strings_off;
@@ -421,12 +421,12 @@
 	const char *fdtend = fdtstart + fdt_totalsize(fdt);
 	char *tmp;
 
-	FDT_CHECK_HEADER(fdt);
+	FDT_RO_PROBE(fdt);
 
 	mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
 		* sizeof(struct fdt_reserve_entry);
 
-	if (fdt_version(fdt) >= 17) {
+	if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
 		struct_size = fdt_size_dt_struct(fdt);
 	} else {
 		struct_size = 0;
@@ -436,7 +436,8 @@
 			return struct_size;
 	}
 
-	if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
+	if (can_assume(LIBFDT_ORDER) ||
+	    !fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) {
 		/* no further work necessary */
 		err = fdt_move(fdt, buf, bufsize);
 		if (err)
@@ -464,7 +465,7 @@
 			return -FDT_ERR_NOSPACE;
 	}
 
-	_fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size);
+	fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size);
 	memmove(buf, tmp, newsize);
 
 	fdt_set_magic(buf, FDT_MAGIC);
@@ -480,12 +481,12 @@
 {
 	int mem_rsv_size;
 
-	FDT_RW_CHECK_HEADER(fdt);
+	FDT_RW_PROBE(fdt);
 
 	mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
 		* sizeof(struct fdt_reserve_entry);
-	_fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
-	fdt_set_totalsize(fdt, _fdt_data_size(fdt));
+	fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
+	fdt_set_totalsize(fdt, fdt_data_size_(fdt));
 
 	return 0;
 }
diff --git a/libfdt/fdt_strerror.c b/libfdt/fdt_strerror.c
index 9677a18..768db66 100644
--- a/libfdt/fdt_strerror.c
+++ b/libfdt/fdt_strerror.c
@@ -1,51 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * 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.
  */
 #include "libfdt_env.h"
@@ -82,6 +38,7 @@
 	FDT_ERRTABENT(FDT_ERR_BADVALUE),
 	FDT_ERRTABENT(FDT_ERR_BADOVERLAY),
 	FDT_ERRTABENT(FDT_ERR_NOPHANDLES),
+	FDT_ERRTABENT(FDT_ERR_BADFLAGS),
 };
 #define FDT_ERRTABSIZE	(sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
 
diff --git a/libfdt/fdt_sw.c b/libfdt/fdt_sw.c
index 2bd15e7..94ce4bb 100644
--- a/libfdt/fdt_sw.c
+++ b/libfdt/fdt_sw.c
@@ -1,52 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * 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.
  */
 #include "libfdt_env.h"
 
@@ -55,22 +10,88 @@
 
 #include "libfdt_internal.h"
 
-static int _fdt_sw_check_header(void *fdt)
+static int fdt_sw_probe_(void *fdt)
 {
-	if (fdt_magic(fdt) != FDT_SW_MAGIC)
-		return -FDT_ERR_BADMAGIC;
-	/* FIXME: should check more details about the header state */
+	if (!can_assume(VALID_INPUT)) {
+		if (fdt_magic(fdt) == FDT_MAGIC)
+			return -FDT_ERR_BADSTATE;
+		else if (fdt_magic(fdt) != FDT_SW_MAGIC)
+			return -FDT_ERR_BADMAGIC;
+	}
+
 	return 0;
 }
 
-#define FDT_SW_CHECK_HEADER(fdt) \
+#define FDT_SW_PROBE(fdt) \
 	{ \
 		int err; \
-		if ((err = _fdt_sw_check_header(fdt)) != 0) \
+		if ((err = fdt_sw_probe_(fdt)) != 0) \
 			return err; \
 	}
 
-static void *_fdt_grab_space(void *fdt, size_t len)
+/* 'memrsv' state:	Initial state after fdt_create()
+ *
+ * Allowed functions:
+ *	fdt_add_reservemap_entry()
+ *	fdt_finish_reservemap()		[moves to 'struct' state]
+ */
+static int fdt_sw_probe_memrsv_(void *fdt)
+{
+	int err = fdt_sw_probe_(fdt);
+	if (err)
+		return err;
+
+	if (!can_assume(VALID_INPUT) && fdt_off_dt_strings(fdt) != 0)
+		return -FDT_ERR_BADSTATE;
+	return 0;
+}
+
+#define FDT_SW_PROBE_MEMRSV(fdt) \
+	{ \
+		int err; \
+		if ((err = fdt_sw_probe_memrsv_(fdt)) != 0) \
+			return err; \
+	}
+
+/* 'struct' state:	Enter this state after fdt_finish_reservemap()
+ *
+ * Allowed functions:
+ *	fdt_begin_node()
+ *	fdt_end_node()
+ *	fdt_property*()
+ *	fdt_finish()			[moves to 'complete' state]
+ */
+static int fdt_sw_probe_struct_(void *fdt)
+{
+	int err = fdt_sw_probe_(fdt);
+	if (err)
+		return err;
+
+	if (!can_assume(VALID_INPUT) &&
+	    fdt_off_dt_strings(fdt) != fdt_totalsize(fdt))
+		return -FDT_ERR_BADSTATE;
+	return 0;
+}
+
+#define FDT_SW_PROBE_STRUCT(fdt) \
+	{ \
+		int err; \
+		if ((err = fdt_sw_probe_struct_(fdt)) != 0) \
+			return err; \
+	}
+
+static inline uint32_t sw_flags(void *fdt)
+{
+	/* assert: (fdt_magic(fdt) == FDT_SW_MAGIC) */
+	return fdt_last_comp_version(fdt);
+}
+
+/* 'complete' state:	Enter this state after fdt_finish()
+ *
+ * Allowed functions: none
+ */
+
+static void *fdt_grab_space_(void *fdt, size_t len)
 {
 	int offset = fdt_size_dt_struct(fdt);
 	int spaceleft;
@@ -82,29 +103,46 @@
 		return NULL;
 
 	fdt_set_size_dt_struct(fdt, offset + len);
-	return _fdt_offset_ptr_w(fdt, offset);
+	return fdt_offset_ptr_w_(fdt, offset);
+}
+
+int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags)
+{
+	const size_t hdrsize = FDT_ALIGN(sizeof(struct fdt_header),
+					 sizeof(struct fdt_reserve_entry));
+	void *fdt = buf;
+
+	if (bufsize < hdrsize)
+		return -FDT_ERR_NOSPACE;
+
+	if (flags & ~FDT_CREATE_FLAGS_ALL)
+		return -FDT_ERR_BADFLAGS;
+
+	memset(buf, 0, bufsize);
+
+	/*
+	 * magic and last_comp_version keep intermediate state during the fdt
+	 * creation process, which is replaced with the proper FDT format by
+	 * fdt_finish().
+	 *
+	 * flags should be accessed with sw_flags().
+	 */
+	fdt_set_magic(fdt, FDT_SW_MAGIC);
+	fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
+	fdt_set_last_comp_version(fdt, flags);
+
+	fdt_set_totalsize(fdt,  bufsize);
+
+	fdt_set_off_mem_rsvmap(fdt, hdrsize);
+	fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
+	fdt_set_off_dt_strings(fdt, 0);
+
+	return 0;
 }
 
 int fdt_create(void *buf, int bufsize)
 {
-	void *fdt = buf;
-
-	if (bufsize < sizeof(struct fdt_header))
-		return -FDT_ERR_NOSPACE;
-
-	memset(buf, 0, bufsize);
-
-	fdt_set_magic(fdt, FDT_SW_MAGIC);
-	fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
-	fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
-	fdt_set_totalsize(fdt,  bufsize);
-
-	fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header),
-					      sizeof(struct fdt_reserve_entry)));
-	fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
-	fdt_set_off_dt_strings(fdt, bufsize);
-
-	return 0;
+	return fdt_create_with_flags(buf, bufsize, 0);
 }
 
 int fdt_resize(void *fdt, void *buf, int bufsize)
@@ -112,11 +150,15 @@
 	size_t headsize, tailsize;
 	char *oldtail, *newtail;
 
-	FDT_SW_CHECK_HEADER(fdt);
+	FDT_SW_PROBE(fdt);
 
-	headsize = fdt_off_dt_struct(fdt);
+	headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
 	tailsize = fdt_size_dt_strings(fdt);
 
+	if (!can_assume(VALID_DTB) &&
+	    headsize + tailsize > fdt_totalsize(fdt))
+		return -FDT_ERR_INTERNAL;
+
 	if ((headsize + tailsize) > bufsize)
 		return -FDT_ERR_NOSPACE;
 
@@ -133,8 +175,9 @@
 		memmove(buf, fdt, headsize);
 	}
 
-	fdt_set_off_dt_strings(buf, bufsize);
 	fdt_set_totalsize(buf, bufsize);
+	if (fdt_off_dt_strings(buf))
+		fdt_set_off_dt_strings(buf, bufsize);
 
 	return 0;
 }
@@ -144,10 +187,7 @@
 	struct fdt_reserve_entry *re;
 	int offset;
 
-	FDT_SW_CHECK_HEADER(fdt);
-
-	if (fdt_size_dt_struct(fdt))
-		return -FDT_ERR_BADSTATE;
+	FDT_SW_PROBE_MEMRSV(fdt);
 
 	offset = fdt_off_dt_struct(fdt);
 	if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
@@ -164,17 +204,24 @@
 
 int fdt_finish_reservemap(void *fdt)
 {
-	return fdt_add_reservemap_entry(fdt, 0, 0);
+	int err = fdt_add_reservemap_entry(fdt, 0, 0);
+
+	if (err)
+		return err;
+
+	fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt));
+	return 0;
 }
 
 int fdt_begin_node(void *fdt, const char *name)
 {
 	struct fdt_node_header *nh;
-	int namelen = strlen(name) + 1;
+	int namelen;
 
-	FDT_SW_CHECK_HEADER(fdt);
+	FDT_SW_PROBE_STRUCT(fdt);
 
-	nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
+	namelen = strlen(name) + 1;
+	nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
 	if (! nh)
 		return -FDT_ERR_NOSPACE;
 
@@ -187,9 +234,9 @@
 {
 	fdt32_t *en;
 
-	FDT_SW_CHECK_HEADER(fdt);
+	FDT_SW_PROBE_STRUCT(fdt);
 
-	en = _fdt_grab_space(fdt, FDT_TAGSIZE);
+	en = fdt_grab_space_(fdt, FDT_TAGSIZE);
 	if (! en)
 		return -FDT_ERR_NOSPACE;
 
@@ -197,19 +244,13 @@
 	return 0;
 }
 
-static int _fdt_find_add_string(void *fdt, const char *s)
+static int fdt_add_string_(void *fdt, const char *s)
 {
 	char *strtab = (char *)fdt + fdt_totalsize(fdt);
-	const char *p;
 	int strtabsize = fdt_size_dt_strings(fdt);
 	int len = strlen(s) + 1;
 	int struct_top, offset;
 
-	p = _fdt_find_string(strtab - strtabsize, strtabsize, s);
-	if (p)
-		return p - strtab;
-
-	/* Add it */
 	offset = -strtabsize - len;
 	struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
 	if (fdt_totalsize(fdt) + offset < struct_top)
@@ -220,20 +261,56 @@
 	return offset;
 }
 
+/* Must only be used to roll back in case of error */
+static void fdt_del_last_string_(void *fdt, const char *s)
+{
+	int strtabsize = fdt_size_dt_strings(fdt);
+	int len = strlen(s) + 1;
+
+	fdt_set_size_dt_strings(fdt, strtabsize - len);
+}
+
+static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
+{
+	char *strtab = (char *)fdt + fdt_totalsize(fdt);
+	int strtabsize = fdt_size_dt_strings(fdt);
+	const char *p;
+
+	*allocated = 0;
+
+	p = fdt_find_string_(strtab - strtabsize, strtabsize, s);
+	if (p)
+		return p - strtab;
+
+	*allocated = 1;
+
+	return fdt_add_string_(fdt, s);
+}
+
 int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)
 {
 	struct fdt_property *prop;
 	int nameoff;
+	int allocated;
 
-	FDT_SW_CHECK_HEADER(fdt);
+	FDT_SW_PROBE_STRUCT(fdt);
 
-	nameoff = _fdt_find_add_string(fdt, name);
+	/* String de-duplication can be slow, _NO_NAME_DEDUP skips it */
+	if (sw_flags(fdt) & FDT_CREATE_FLAG_NO_NAME_DEDUP) {
+		allocated = 1;
+		nameoff = fdt_add_string_(fdt, name);
+	} else {
+		nameoff = fdt_find_add_string_(fdt, name, &allocated);
+	}
 	if (nameoff == 0)
 		return -FDT_ERR_NOSPACE;
 
-	prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
-	if (! prop)
+	prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
+	if (! prop) {
+		if (allocated)
+			fdt_del_last_string_(fdt, name);
 		return -FDT_ERR_NOSPACE;
+	}
 
 	prop->tag = cpu_to_fdt32(FDT_PROP);
 	prop->nameoff = cpu_to_fdt32(nameoff);
@@ -262,10 +339,10 @@
 	uint32_t tag;
 	int offset, nextoffset;
 
-	FDT_SW_CHECK_HEADER(fdt);
+	FDT_SW_PROBE_STRUCT(fdt);
 
 	/* Add terminator */
-	end = _fdt_grab_space(fdt, sizeof(*end));
+	end = fdt_grab_space_(fdt, sizeof(*end));
 	if (! end)
 		return -FDT_ERR_NOSPACE;
 	*end = cpu_to_fdt32(FDT_END);
@@ -281,7 +358,7 @@
 	while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
 		if (tag == FDT_PROP) {
 			struct fdt_property *prop =
-				_fdt_offset_ptr_w(fdt, offset);
+				fdt_offset_ptr_w_(fdt, offset);
 			int nameoff;
 
 			nameoff = fdt32_to_cpu(prop->nameoff);
@@ -295,6 +372,10 @@
 
 	/* Finally, adjust the header */
 	fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
+
+	/* And fix up fields that were keeping intermediate state. */
+	fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
 	fdt_set_magic(fdt, FDT_MAGIC);
+
 	return 0;
 }
diff --git a/libfdt/fdt_wip.c b/libfdt/fdt_wip.c
index 5e85919..f64139e 100644
--- a/libfdt/fdt_wip.c
+++ b/libfdt/fdt_wip.c
@@ -1,52 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * 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.
  */
 #include "libfdt_env.h"
 
@@ -93,7 +48,7 @@
 						   val, len);
 }
 
-static void _fdt_nop_region(void *start, int len)
+static void fdt_nop_region_(void *start, int len)
 {
 	fdt32_t *p;
 
@@ -110,12 +65,12 @@
 	if (!prop)
 		return len;
 
-	_fdt_nop_region(prop, len + sizeof(*prop));
+	fdt_nop_region_(prop, len + sizeof(*prop));
 
 	return 0;
 }
 
-int _fdt_node_end_offset(void *fdt, int offset)
+int fdt_node_end_offset_(void *fdt, int offset)
 {
 	int depth = 0;
 
@@ -129,11 +84,11 @@
 {
 	int endoffset;
 
-	endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+	endoffset = fdt_node_end_offset_(fdt, nodeoffset);
 	if (endoffset < 0)
 		return endoffset;
 
-	_fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0),
+	fdt_nop_region_(fdt_offset_ptr_w(fdt, nodeoffset, 0),
 			endoffset - nodeoffset);
 	return 0;
 }
diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h
index a248b1b..544d3ef 100644
--- a/libfdt/libfdt.h
+++ b/libfdt/libfdt.h
@@ -1,60 +1,19 @@
-#ifndef _LIBFDT_H
-#define _LIBFDT_H
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
+#ifndef LIBFDT_H
+#define LIBFDT_H
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * 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.
  */
 
 #include <libfdt_env.h>
 #include <fdt.h>
 
-#define FDT_FIRST_SUPPORTED_VERSION	0x10
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define FDT_FIRST_SUPPORTED_VERSION	0x02
 #define FDT_LAST_SUPPORTED_VERSION	0x11
 
 /* Error codes: informative error codes */
@@ -90,8 +49,9 @@
 
 /* Error codes: codes for bad device tree blobs */
 #define FDT_ERR_TRUNCATED	8
-	/* FDT_ERR_TRUNCATED: Structure block of the given device tree
-	 * ends without an FDT_END tag. */
+	/* FDT_ERR_TRUNCATED: FDT or a sub-block is improperly
+	 * terminated (overflows, goes outside allowed bounds, or
+	 * isn't properly terminated).  */
 #define FDT_ERR_BADMAGIC	9
 	/* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
 	 * device tree at all - it is missing the flattened device
@@ -137,7 +97,15 @@
 	/* FDT_ERR_NOPHANDLES: The device tree doesn't have any
 	 * phandle available anymore without causing an overflow */
 
-#define FDT_ERR_MAX		17
+#define FDT_ERR_BADFLAGS	18
+	/* FDT_ERR_BADFLAGS: The function was passed a flags field that
+	 * contains invalid flags or an invalid combination of flags. */
+
+#define FDT_ERR_MAX		18
+
+/* constants */
+#define FDT_MAX_PHANDLE 0xfffffffe
+	/* Valid values for phandles range from 1 to 2^32-2. */
 
 /**********************************************************************/
 /* Low-level functions (you probably don't need these)                */
@@ -153,6 +121,61 @@
 
 uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
 
+/*
+ * Alignment helpers:
+ *     These helpers access words from a device tree blob.  They're
+ *     built to work even with unaligned pointers on platforms (ike
+ *     ARM) that don't like unaligned loads and stores
+ */
+
+static inline uint32_t fdt32_ld(const fdt32_t *p)
+{
+	const uint8_t *bp = (const uint8_t *)p;
+
+	return ((uint32_t)bp[0] << 24)
+		| ((uint32_t)bp[1] << 16)
+		| ((uint32_t)bp[2] << 8)
+		| bp[3];
+}
+
+static inline void fdt32_st(void *property, uint32_t value)
+{
+	uint8_t *bp = (uint8_t *)property;
+
+	bp[0] = value >> 24;
+	bp[1] = (value >> 16) & 0xff;
+	bp[2] = (value >> 8) & 0xff;
+	bp[3] = value & 0xff;
+}
+
+static inline uint64_t fdt64_ld(const fdt64_t *p)
+{
+	const uint8_t *bp = (const uint8_t *)p;
+
+	return ((uint64_t)bp[0] << 56)
+		| ((uint64_t)bp[1] << 48)
+		| ((uint64_t)bp[2] << 40)
+		| ((uint64_t)bp[3] << 32)
+		| ((uint64_t)bp[4] << 24)
+		| ((uint64_t)bp[5] << 16)
+		| ((uint64_t)bp[6] << 8)
+		| bp[7];
+}
+
+static inline void fdt64_st(void *property, uint64_t value)
+{
+	uint8_t *bp = (uint8_t *)property;
+
+	bp[0] = value >> 56;
+	bp[1] = (value >> 48) & 0xff;
+	bp[2] = (value >> 40) & 0xff;
+	bp[3] = (value >> 32) & 0xff;
+	bp[4] = (value >> 24) & 0xff;
+	bp[5] = (value >> 16) & 0xff;
+	bp[6] = (value >> 8) & 0xff;
+	bp[7] = value & 0xff;
+}
+
 /**********************************************************************/
 /* Traversal functions                                                */
 /**********************************************************************/
@@ -195,7 +218,7 @@
  *		...
  *	}
  *
- *	if ((node < 0) && (node != -FDT_ERR_NOT_FOUND)) {
+ *	if ((node < 0) && (node != -FDT_ERR_NOTFOUND)) {
  *		Error handling
  *	}
  *
@@ -213,7 +236,7 @@
 /* General functions                                                  */
 /**********************************************************************/
 #define fdt_get_header(fdt, field) \
-	(fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
+	(fdt32_ld(&((const struct fdt_header *)(fdt))->field))
 #define fdt_magic(fdt)			(fdt_get_header(fdt, magic))
 #define fdt_totalsize(fdt)		(fdt_get_header(fdt, totalsize))
 #define fdt_off_dt_struct(fdt)		(fdt_get_header(fdt, off_dt_struct))
@@ -225,37 +248,51 @@
 #define fdt_size_dt_strings(fdt)	(fdt_get_header(fdt, size_dt_strings))
 #define fdt_size_dt_struct(fdt)		(fdt_get_header(fdt, size_dt_struct))
 
-#define __fdt_set_hdr(name) \
+#define fdt_set_hdr_(name) \
 	static inline void fdt_set_##name(void *fdt, uint32_t val) \
 	{ \
 		struct fdt_header *fdth = (struct fdt_header *)fdt; \
 		fdth->name = cpu_to_fdt32(val); \
 	}
-__fdt_set_hdr(magic);
-__fdt_set_hdr(totalsize);
-__fdt_set_hdr(off_dt_struct);
-__fdt_set_hdr(off_dt_strings);
-__fdt_set_hdr(off_mem_rsvmap);
-__fdt_set_hdr(version);
-__fdt_set_hdr(last_comp_version);
-__fdt_set_hdr(boot_cpuid_phys);
-__fdt_set_hdr(size_dt_strings);
-__fdt_set_hdr(size_dt_struct);
-#undef __fdt_set_hdr
+fdt_set_hdr_(magic);
+fdt_set_hdr_(totalsize);
+fdt_set_hdr_(off_dt_struct);
+fdt_set_hdr_(off_dt_strings);
+fdt_set_hdr_(off_mem_rsvmap);
+fdt_set_hdr_(version);
+fdt_set_hdr_(last_comp_version);
+fdt_set_hdr_(boot_cpuid_phys);
+fdt_set_hdr_(size_dt_strings);
+fdt_set_hdr_(size_dt_struct);
+#undef fdt_set_hdr_
 
 /**
- * fdt_check_header - sanity check a device tree or possible device tree
+ * fdt_header_size - return the size of the tree's header
+ * @fdt: pointer to a flattened device tree
+ */
+size_t fdt_header_size(const void *fdt);
+
+/**
+ * fdt_header_size_ - internal function which takes a version number
+ */
+size_t fdt_header_size_(uint32_t version);
+
+/**
+ * fdt_check_header - sanity check a device tree header
+
  * @fdt: pointer to data which might be a flattened device tree
  *
  * fdt_check_header() checks that the given buffer contains what
- * appears to be a flattened device tree with sane information in its
- * header.
+ * appears to be a flattened device tree, and that the header contains
+ * valid information (to the extent that can be determined from the
+ * header alone).
  *
  * returns:
  *     0, if the buffer appears to contain a valid device tree
  *     -FDT_ERR_BADMAGIC,
  *     -FDT_ERR_BADVERSION,
- *     -FDT_ERR_BADSTATE, standard meanings, as above
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_TRUNCATED, standard meanings, as above
  */
 int fdt_check_header(const void *fdt);
 
@@ -284,6 +321,24 @@
 /* Read-only functions                                                */
 /**********************************************************************/
 
+int fdt_check_full(const void *fdt, size_t bufsize);
+
+/**
+ * fdt_get_string - retrieve a string from the strings block of a device tree
+ * @fdt: pointer to the device tree blob
+ * @stroffset: offset of the string within the strings block (native endian)
+ * @lenp: optional pointer to return the string's length
+ *
+ * fdt_get_string() retrieves a pointer to a single string from the
+ * strings block of the device tree blob at fdt, and optionally also
+ * returns the string's length in *lenp.
+ *
+ * returns:
+ *     a pointer to the string, on success
+ *     NULL, if stroffset is out of bounds, or doesn't point to a valid string
+ */
+const char *fdt_get_string(const void *fdt, int stroffset, int *lenp);
+
 /**
  * fdt_string - retrieve a string from the strings block of a device tree
  * @fdt: pointer to the device tree blob
@@ -294,11 +349,25 @@
  *
  * returns:
  *     a pointer to the string, on success
- *     NULL, if stroffset is out of bounds
+ *     NULL, if stroffset is out of bounds, or doesn't point to a valid string
  */
 const char *fdt_string(const void *fdt, int stroffset);
 
 /**
+ * fdt_find_max_phandle - find and return the highest phandle in a tree
+ * @fdt: pointer to the device tree blob
+ * @phandle: return location for the highest phandle value found in the tree
+ *
+ * fdt_find_max_phandle() finds the highest phandle value in the given device
+ * tree. The value returned in @phandle is only valid if the function returns
+ * success.
+ *
+ * returns:
+ *     0 on success or a negative error code on failure
+ */
+int fdt_find_max_phandle(const void *fdt, uint32_t *phandle);
+
+/**
  * fdt_get_max_phandle - retrieves the highest phandle in a tree
  * @fdt: pointer to the device tree blob
  *
@@ -306,12 +375,39 @@
  * device tree. This will ignore badly formatted phandles, or phandles
  * with a value of 0 or -1.
  *
+ * This function is deprecated in favour of fdt_find_max_phandle().
+ *
  * returns:
  *      the highest phandle on success
  *      0, if no phandle was found in the device tree
  *      -1, if an error occurred
  */
-uint32_t fdt_get_max_phandle(const void *fdt);
+static inline uint32_t fdt_get_max_phandle(const void *fdt)
+{
+	uint32_t phandle;
+	int err;
+
+	err = fdt_find_max_phandle(fdt, &phandle);
+	if (err < 0)
+		return (uint32_t)-1;
+
+	return phandle;
+}
+
+/**
+ * fdt_generate_phandle - return a new, unused phandle for a device tree blob
+ * @fdt: pointer to the device tree blob
+ * @phandle: return location for the new phandle
+ *
+ * Walks the device tree blob and looks for the highest phandle value. On
+ * success, the new, unused phandle value (one higher than the previously
+ * highest phandle value in the device tree blob) will be returned in the
+ * @phandle parameter.
+ *
+ * Returns:
+ *   0 on success or a negative error-code on failure
+ */
+int fdt_generate_phandle(const void *fdt, uint32_t *phandle);
 
 /**
  * fdt_num_mem_rsv - retrieve the number of memory reserve map entries
@@ -503,7 +599,7 @@
  *		...
  *	}
  *
- *	if ((property < 0) && (property != -FDT_ERR_NOT_FOUND)) {
+ *	if ((property < 0) && (property != -FDT_ERR_NOTFOUND)) {
  *		Error handling
  *	}
  *
@@ -527,6 +623,9 @@
  * offset.  If lenp is non-NULL, the length of the property value is
  * also returned, in the integer pointed to by lenp.
  *
+ * Note that this code only works on device tree versions >= 16. fdt_getprop()
+ * works on all versions.
+ *
  * returns:
  *	pointer to the structure representing the property
  *		if lenp is non-NULL, *lenp contains the length of the property
@@ -603,7 +702,7 @@
 /**
  * fdt_getprop_by_offset - retrieve the value of a property at a given offset
  * @fdt: pointer to the device tree blob
- * @ffset: offset of the property to read
+ * @offset: offset of the property to read
  * @namep: pointer to a string variable (will be overwritten) or NULL
  * @lenp: pointer to an integer variable (will be overwritten) or NULL
  *
@@ -1087,7 +1186,7 @@
  *
  * returns:
  *	0 <= n < FDT_MAX_NCELLS, on success
- *      2, if the node has no #address-cells property
+ *      1, if the node has no #size-cells property
  *      -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
  *		#size-cells property
  *	-FDT_ERR_BADMAGIC,
@@ -1294,7 +1393,45 @@
 /* Sequential write functions                                         */
 /**********************************************************************/
 
+/* fdt_create_with_flags flags */
+#define FDT_CREATE_FLAG_NO_NAME_DEDUP 0x1
+	/* FDT_CREATE_FLAG_NO_NAME_DEDUP: Do not try to de-duplicate property
+	 * names in the fdt. This can result in faster creation times, but
+	 * a larger fdt. */
+
+#define FDT_CREATE_FLAGS_ALL	(FDT_CREATE_FLAG_NO_NAME_DEDUP)
+
+/**
+ * fdt_create_with_flags - begin creation of a new fdt
+ * @fdt: pointer to memory allocated where fdt will be created
+ * @bufsize: size of the memory space at fdt
+ * @flags: a valid combination of FDT_CREATE_FLAG_ flags, or 0.
+ *
+ * fdt_create_with_flags() begins the process of creating a new fdt with
+ * the sequential write interface.
+ *
+ * fdt creation process must end with fdt_finished() to produce a valid fdt.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, bufsize is insufficient for a minimal fdt
+ *	-FDT_ERR_BADFLAGS, flags is not valid
+ */
+int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags);
+
+/**
+ * fdt_create - begin creation of a new fdt
+ * @fdt: pointer to memory allocated where fdt will be created
+ * @bufsize: size of the memory space at fdt
+ *
+ * fdt_create() is equivalent to fdt_create_with_flags() with flags=0.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, bufsize is insufficient for a minimal fdt
+ */
 int fdt_create(void *buf, int bufsize);
+
 int fdt_resize(void *fdt, void *buf, int bufsize);
 int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
 int fdt_finish_reservemap(void *fdt);
@@ -1310,10 +1447,13 @@
 	fdt64_t tmp = cpu_to_fdt64(val);
 	return fdt_property(fdt, name, &tmp, sizeof(tmp));
 }
+
+#ifndef SWIG /* Not available in Python */
 static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
 {
 	return fdt_property_u32(fdt, name, val);
 }
+#endif
 
 /**
  * fdt_property_placeholder - add a new property and return a ptr to its value
@@ -1449,6 +1589,37 @@
 		const void *val, int len);
 
 /**
+ * fdt_setprop_placeholder - allocate space for a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @len: length of the property value
+ * @prop_data: return pointer to property data
+ *
+ * fdt_setprop_placeholer() allocates the named property in the given node.
+ * If the property exists it is resized. In either case a pointer to the
+ * property data is returned.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
+			    int len, void **prop_data);
+
+/**
  * fdt_setprop_u32 - set a property to a 32-bit integer
  * @fdt: pointer to the device tree blob
  * @nodeoffset: offset of the node whose property to change
@@ -1732,6 +1903,43 @@
 	fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
 
 /**
+ * fdt_appendprop_addrrange - append a address range property
+ * @fdt: pointer to the device tree blob
+ * @parent: offset of the parent node
+ * @nodeoffset: offset of the node to add a property at
+ * @name: name of property
+ * @addr: start address of a given range
+ * @size: size of a given range
+ *
+ * fdt_appendprop_addrrange() appends an address range value (start
+ * address and size) to the value of the named property in the given
+ * node, or creates a new property with that value if it does not
+ * already exist.
+ * If "name" is not specified, a default "reg" is used.
+ * Cell sizes are determined by parent's #address-cells and #size-cells.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
+ *		#address-cells property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADVALUE, addr or size doesn't fit to respective cells size
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain a new property
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
+			     const char *name, uint64_t addr, uint64_t size);
+
+/**
  * fdt_delprop - delete a property
  * @fdt: pointer to the device tree blob
  * @nodeoffset: offset of the node whose property to nop
@@ -1865,4 +2073,8 @@
 
 const char *fdt_strerror(int errval);
 
-#endif /* _LIBFDT_H */
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBFDT_H */
diff --git a/libfdt/libfdt_env.h b/libfdt/libfdt_env.h
index 952056c..73b6d40 100644
--- a/libfdt/libfdt_env.h
+++ b/libfdt/libfdt_env.h
@@ -1,61 +1,18 @@
-#ifndef _LIBFDT_ENV_H
-#define _LIBFDT_ENV_H
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
+#ifndef LIBFDT_ENV_H
+#define LIBFDT_ENV_H
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
  * Copyright 2012 Kim Phillips, Freescale Semiconductor.
- *
- * 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.
  */
 
+#include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
+#include <limits.h>
 
 #ifdef __CHECKER__
 #define FDT_FORCE __attribute__((force))
@@ -109,4 +66,31 @@
 #undef CPU_TO_FDT16
 #undef EXTRACT_BYTE
 
-#endif /* _LIBFDT_ENV_H */
+#ifdef __APPLE__
+#include <AvailabilityMacros.h>
+
+/* strnlen() is not available on Mac OS < 10.7 */
+# if !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED < \
+                                         MAC_OS_X_VERSION_10_7)
+
+#define strnlen fdt_strnlen
+
+/*
+ * fdt_strnlen: returns the length of a string or max_count - which ever is
+ * smallest.
+ * Input 1 string: the string whose size is to be determined
+ * Input 2 max_count: the maximum value returned by this function
+ * Output: length of the string or max_count (the smallest of the two)
+ */
+static inline size_t fdt_strnlen(const char *string, size_t max_count)
+{
+    const char *p = memchr(string, 0, max_count);
+    return p ? p - string : max_count;
+}
+
+#endif /* !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED <
+          MAC_OS_X_VERSION_10_7) */
+
+#endif /* __APPLE__ */
+
+#endif /* LIBFDT_ENV_H */
diff --git a/libfdt/libfdt_internal.h b/libfdt/libfdt_internal.h
index 02cfa6f..d4e0bd4 100644
--- a/libfdt/libfdt_internal.h
+++ b/libfdt/libfdt_internal.h
@@ -1,83 +1,39 @@
-#ifndef _LIBFDT_INTERNAL_H
-#define _LIBFDT_INTERNAL_H
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
+#ifndef LIBFDT_INTERNAL_H
+#define LIBFDT_INTERNAL_H
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * 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.
  */
 #include <fdt.h>
 
 #define FDT_ALIGN(x, a)		(((x) + (a) - 1) & ~((a) - 1))
 #define FDT_TAGALIGN(x)		(FDT_ALIGN((x), FDT_TAGSIZE))
 
-#define FDT_CHECK_HEADER(fdt) \
-	{ \
-		int __err; \
-		if ((__err = fdt_check_header(fdt)) != 0) \
-			return __err; \
+int32_t fdt_ro_probe_(const void *fdt);
+#define FDT_RO_PROBE(fdt)					\
+	{							\
+		int32_t totalsize_;				\
+		if ((totalsize_ = fdt_ro_probe_(fdt)) < 0)	\
+			return totalsize_;			\
 	}
 
-int _fdt_check_node_offset(const void *fdt, int offset);
-int _fdt_check_prop_offset(const void *fdt, int offset);
-const char *_fdt_find_string(const char *strtab, int tabsize, const char *s);
-int _fdt_node_end_offset(void *fdt, int nodeoffset);
+int fdt_check_node_offset_(const void *fdt, int offset);
+int fdt_check_prop_offset_(const void *fdt, int offset);
+const char *fdt_find_string_(const char *strtab, int tabsize, const char *s);
+int fdt_node_end_offset_(void *fdt, int nodeoffset);
 
-static inline const void *_fdt_offset_ptr(const void *fdt, int offset)
+static inline const void *fdt_offset_ptr_(const void *fdt, int offset)
 {
 	return (const char *)fdt + fdt_off_dt_struct(fdt) + offset;
 }
 
-static inline void *_fdt_offset_ptr_w(void *fdt, int offset)
+static inline void *fdt_offset_ptr_w_(void *fdt, int offset)
 {
-	return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset);
+	return (void *)(uintptr_t)fdt_offset_ptr_(fdt, offset);
 }
 
-static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n)
+static inline const struct fdt_reserve_entry *fdt_mem_rsv_(const void *fdt, int n)
 {
 	const struct fdt_reserve_entry *rsv_table =
 		(const struct fdt_reserve_entry *)
@@ -85,11 +41,133 @@
 
 	return rsv_table + n;
 }
-static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n)
+static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n)
 {
-	return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n);
+	return (void *)(uintptr_t)fdt_mem_rsv_(fdt, n);
 }
 
 #define FDT_SW_MAGIC		(~FDT_MAGIC)
 
-#endif /* _LIBFDT_INTERNAL_H */
+/**********************************************************************/
+/* Checking controls                                                  */
+/**********************************************************************/
+
+#ifndef FDT_ASSUME_MASK
+#define FDT_ASSUME_MASK 0
+#endif
+
+/*
+ * Defines assumptions which can be enabled. Each of these can be enabled
+ * individually. For maximum safety, don't enable any assumptions!
+ *
+ * For minimal code size and no safety, use ASSUME_PERFECT at your own risk.
+ * You should have another method of validating the device tree, such as a
+ * signature or hash check before using libfdt.
+ *
+ * For situations where security is not a concern it may be safe to enable
+ * ASSUME_SANE.
+ */
+enum {
+	/*
+	 * This does essentially no checks. Only the latest device-tree
+	 * version is correctly handled. Inconsistencies or errors in the device
+	 * tree may cause undefined behaviour or crashes. Invalid parameters
+	 * passed to libfdt may do the same.
+	 *
+	 * If an error occurs when modifying the tree it may leave the tree in
+	 * an intermediate (but valid) state. As an example, adding a property
+	 * where there is insufficient space may result in the property name
+	 * being added to the string table even though the property itself is
+	 * not added to the struct section.
+	 *
+	 * Only use this if you have a fully validated device tree with
+	 * the latest supported version and wish to minimise code size.
+	 */
+	ASSUME_PERFECT		= 0xff,
+
+	/*
+	 * This assumes that the device tree is sane. i.e. header metadata
+	 * and basic hierarchy are correct.
+	 *
+	 * With this assumption enabled, normal device trees produced by libfdt
+	 * and the compiler should be handled safely. Malicious device trees and
+	 * complete garbage may cause libfdt to behave badly or crash. Truncated
+	 * device trees (e.g. those only partially loaded) can also cause
+	 * problems.
+	 *
+	 * Note: Only checks that relate exclusively to the device tree itself
+	 * (not the parameters passed to libfdt) are disabled by this
+	 * assumption. This includes checking headers, tags and the like.
+	 */
+	ASSUME_VALID_DTB	= 1 << 0,
+
+	/*
+	 * This builds on ASSUME_VALID_DTB and further assumes that libfdt
+	 * functions are called with valid parameters, i.e. not trigger
+	 * FDT_ERR_BADOFFSET or offsets that are out of bounds. It disables any
+	 * extensive checking of parameters and the device tree, making various
+	 * assumptions about correctness.
+	 *
+	 * It doesn't make sense to enable this assumption unless
+	 * ASSUME_VALID_DTB is also enabled.
+	 */
+	ASSUME_VALID_INPUT	= 1 << 1,
+
+	/*
+	 * This disables checks for device-tree version and removes all code
+	 * which handles older versions.
+	 *
+	 * Only enable this if you know you have a device tree with the latest
+	 * version.
+	 */
+	ASSUME_LATEST		= 1 << 2,
+
+	/*
+	 * This assumes that it is OK for a failed addition to the device tree,
+	 * due to lack of space or some other problem, to skip any rollback
+	 * steps (such as dropping the property name from the string table).
+	 * This is safe to enable in most circumstances, even though it may
+	 * leave the tree in a sub-optimal state.
+	 */
+	ASSUME_NO_ROLLBACK	= 1 << 3,
+
+	/*
+	 * This assumes that the device tree components appear in a 'convenient'
+	 * order, i.e. the memory reservation block first, then the structure
+	 * block and finally the string block.
+	 *
+	 * This order is not specified by the device-tree specification,
+	 * but is expected by libfdt. The device-tree compiler always created
+	 * device trees with this order.
+	 *
+	 * This assumption disables a check in fdt_open_into() and removes the
+	 * ability to fix the problem there. This is safe if you know that the
+	 * device tree is correctly ordered. See fdt_blocks_misordered_().
+	 */
+	ASSUME_LIBFDT_ORDER	= 1 << 4,
+
+	/*
+	 * This assumes that libfdt itself does not have any internal bugs. It
+	 * drops certain checks that should never be needed unless libfdt has an
+	 * undiscovered bug.
+	 *
+	 * This can generally be considered safe to enable.
+	 */
+	ASSUME_LIBFDT_FLAWLESS	= 1 << 5,
+};
+
+/**
+ * can_assume_() - check if a particular assumption is enabled
+ *
+ * @mask: Mask to check (ASSUME_...)
+ * @return true if that assumption is enabled, else false
+ */
+static inline bool can_assume_(int mask)
+{
+	return FDT_ASSUME_MASK & mask;
+}
+
+/** helper macros for checking assumptions */
+#define can_assume(_assume)	can_assume_(ASSUME_ ## _assume)
+
+#endif /* LIBFDT_INTERNAL_H */
diff --git a/libfdt/version.lds b/libfdt/version.lds
index cff0358..7ab85f1 100644
--- a/libfdt/version.lds
+++ b/libfdt/version.lds
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
 LIBFDT_1.2 {
 	global:
 		fdt_next_node;
@@ -19,6 +20,7 @@
 		fdt_get_alias_namelen;
 		fdt_get_alias;
 		fdt_get_path;
+                fdt_header_size;
 		fdt_supernode_atdepth_offset;
 		fdt_node_depth;
 		fdt_parent_offset;
@@ -60,9 +62,21 @@
 		fdt_address_cells;
 		fdt_size_cells;
 		fdt_stringlist_contains;
+		fdt_stringlist_count;
+		fdt_stringlist_search;
+		fdt_stringlist_get;
 		fdt_resize;
 		fdt_overlay_apply;
-
+		fdt_get_string;
+		fdt_find_max_phandle;
+		fdt_generate_phandle;
+		fdt_check_full;
+		fdt_setprop_placeholder;
+		fdt_property_placeholder;
+		fdt_header_size_;
+		fdt_appendprop_addrrange;
+		fdt_setprop_inplace_namelen_partial;
+		fdt_create_with_flags;
 	local:
 		*;
 };
diff --git a/livetree.c b/livetree.c
index a5d5676..032df58 100644
--- a/livetree.c
+++ b/livetree.c
@@ -1,24 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
- *                                                                   USA
  */
 
 #include "dtc.h"
+#include "srcpos.h"
 
 /*
  * Tree building functions
@@ -50,7 +36,8 @@
 		label->deleted = 1;
 }
 
-struct property *build_property(char *name, struct data val)
+struct property *build_property(char *name, struct data val,
+				struct srcpos *srcpos)
 {
 	struct property *new = xmalloc(sizeof(*new));
 
@@ -58,6 +45,7 @@
 
 	new->name = name;
 	new->val = val;
+	new->srcpos = srcpos_copy(srcpos);
 
 	return new;
 }
@@ -97,7 +85,8 @@
 	return head;
 }
 
-struct node *build_node(struct property *proplist, struct node *children)
+struct node *build_node(struct property *proplist, struct node *children,
+			struct srcpos *srcpos)
 {
 	struct node *new = xmalloc(sizeof(*new));
 	struct node *child;
@@ -106,6 +95,7 @@
 
 	new->proplist = reverse_properties(proplist);
 	new->children = children;
+	new->srcpos = srcpos_copy(srcpos);
 
 	for_each_child(new, child) {
 		child->parent = new;
@@ -114,13 +104,14 @@
 	return new;
 }
 
-struct node *build_node_delete(void)
+struct node *build_node_delete(struct srcpos *srcpos)
 {
 	struct node *new = xmalloc(sizeof(*new));
 
 	memset(new, 0, sizeof(*new));
 
 	new->deleted = 1;
+	new->srcpos = srcpos_copy(srcpos);
 
 	return new;
 }
@@ -134,6 +125,20 @@
 	return node;
 }
 
+struct node *omit_node_if_unused(struct node *node)
+{
+	node->omit_if_unused = 1;
+
+	return node;
+}
+
+struct node *reference_node(struct node *node)
+{
+	node->is_referenced = 1;
+
+	return node;
+}
+
 struct node *merge_nodes(struct node *old_node, struct node *new_node)
 {
 	struct property *new_prop, *old_prop;
@@ -169,6 +174,8 @@
 
 				old_prop->val = new_prop->val;
 				old_prop->deleted = 0;
+				free(old_prop->srcpos);
+				old_prop->srcpos = new_prop->srcpos;
 				free(new_prop);
 				new_prop = NULL;
 				break;
@@ -209,6 +216,8 @@
 			add_child(old_node, new_child);
 	}
 
+	old_node->srcpos = srcpos_extend(old_node->srcpos, new_node->srcpos);
+
 	/* The new node contents are now merged into the old node.  Free
 	 * the new node. */
 	free(new_node);
@@ -216,7 +225,7 @@
 	return old_node;
 }
 
-void add_orphan_node(struct node *dt, struct node *new_node, char *ref)
+struct node * add_orphan_node(struct node *dt, struct node *new_node, char *ref)
 {
 	static unsigned int next_orphan_fragment = 0;
 	struct node *node;
@@ -224,18 +233,26 @@
 	struct data d = empty_data;
 	char *name;
 
-	d = data_add_marker(d, REF_PHANDLE, ref);
-	d = data_append_integer(d, 0xffffffff, 32);
+	if (ref[0] == '/') {
+		d = data_add_marker(d, TYPE_STRING, ref);
+		d = data_append_data(d, ref, strlen(ref) + 1);
 
-	p = build_property("target", d);
+		p = build_property("target-path", d, NULL);
+	} else {
+		d = data_add_marker(d, REF_PHANDLE, ref);
+		d = data_append_integer(d, 0xffffffff, 32);
+
+		p = build_property("target", d, NULL);
+	}
 
 	xasprintf(&name, "fragment@%u",
 			next_orphan_fragment++);
 	name_node(new_node, "__overlay__");
-	node = build_node(p, new_node);
+	node = build_node(p, new_node, NULL);
 	name_node(node, name);
 
 	add_child(dt, node);
+	return dt;
 }
 
 struct node *chain_node(struct node *first, struct node *list)
@@ -319,18 +336,21 @@
 }
 
 void append_to_property(struct node *node,
-				    char *name, const void *data, int len)
+			char *name, const void *data, int len,
+			enum markertype type)
 {
 	struct data d;
 	struct property *p;
 
 	p = get_property(node, name);
 	if (p) {
-		d = data_append_data(p->val, data, len);
+		d = data_add_marker(p->val, type, name);
+		d = data_append_data(d, data, len);
 		p->val = d;
 	} else {
-		d = data_append_data(empty_data, data, len);
-		p = build_property(name, d);
+		d = data_add_marker(empty_data, type, name);
+		d = data_append_data(d, data, len);
+		p = build_property(name, d, NULL);
 		add_property(node, p);
 	}
 }
@@ -418,6 +438,12 @@
 	return fdt32_to_cpu(*((fdt32_t *)prop->val.val));
 }
 
+cell_t propval_cell_n(struct property *prop, int n)
+{
+	assert(prop->val.len / sizeof(cell_t) >= n);
+	return fdt32_to_cpu(*((fdt32_t *)prop->val.val + n));
+}
+
 struct property *get_property_by_label(struct node *tree, const char *label,
 				       struct node **node)
 {
@@ -500,8 +526,7 @@
 	p = strchr(path, '/');
 
 	for_each_child(tree, child) {
-		if (p && (strlen(child->name) == p-path) &&
-				strneq(path, child->name, p-path))
+		if (p && strprefixeq(path, p - path, child->name))
 			return get_node_by_path(child, p+1);
 		else if (!p && streq(path, child->name))
 			return child;
@@ -534,7 +559,10 @@
 {
 	struct node *child, *node;
 
-	assert((phandle != 0) && (phandle != -1));
+	if ((phandle == 0) || (phandle == -1)) {
+		assert(generate_fixups);
+		return NULL;
+	}
 
 	if (tree->phandle == phandle) {
 		if (tree->deleted)
@@ -564,6 +592,7 @@
 cell_t get_node_phandle(struct node *root, struct node *node)
 {
 	static cell_t phandle = 1; /* FIXME: ick, static local */
+	struct data d = empty_data;
 
 	if ((node->phandle != 0) && (node->phandle != -1))
 		return node->phandle;
@@ -573,17 +602,16 @@
 
 	node->phandle = phandle;
 
+	d = data_add_marker(d, TYPE_UINT32, NULL);
+	d = data_append_cell(d, phandle);
+
 	if (!get_property(node, "linux,phandle")
 	    && (phandle_format & PHANDLE_LEGACY))
-		add_property(node,
-			     build_property("linux,phandle",
-					    data_append_cell(empty_data, phandle)));
+		add_property(node, build_property("linux,phandle", d, NULL));
 
 	if (!get_property(node, "phandle")
 	    && (phandle_format & PHANDLE_EPAPR))
-		add_property(node,
-			     build_property("phandle",
-					    data_append_cell(empty_data, phandle)));
+		add_property(node, build_property("phandle", d, NULL));
 
 	/* If the node *does* have a phandle property, we must
 	 * be dealing with a self-referencing phandle, which will be
@@ -757,7 +785,7 @@
 {
 	struct node *node;
 
-	node = build_node(NULL, NULL);
+	node = build_node(NULL, NULL, NULL);
 	name_node(node, xstrdup(name));
 	add_child(parent, node);
 
@@ -818,8 +846,9 @@
 
 			/* insert it */
 			p = build_property(l->label,
-				data_copy_mem(node->fullpath,
-						strlen(node->fullpath) + 1));
+				data_copy_escape_string(node->fullpath,
+						strlen(node->fullpath)),
+				NULL);
 			add_property(an, p);
 		}
 
@@ -869,7 +898,7 @@
 
 	xasprintf(&entry, "%s:%s:%u",
 			node->fullpath, prop->name, m->offset);
-	append_to_property(fn, m->ref, entry, strlen(entry) + 1);
+	append_to_property(fn, m->ref, entry, strlen(entry) + 1, TYPE_STRING);
 
 	free(entry);
 }
@@ -929,7 +958,7 @@
 	char **compp;
 	int i, depth;
 
-	/* walk back retreiving depth */
+	/* walk back retrieving depth */
 	depth = 0;
 	for (wn = node; wn; wn = wn->parent)
 		depth++;
@@ -952,7 +981,7 @@
 	free(compp);
 
 	value_32 = cpu_to_fdt32(m->offset);
-	append_to_property(wn, prop->name, &value_32, sizeof(value_32));
+	append_to_property(wn, prop->name, &value_32, sizeof(value_32), TYPE_UINT32);
 }
 
 static void generate_local_fixups_tree_internal(struct dt_info *dti,
diff --git a/pylibfdt/.gitignore b/pylibfdt/.gitignore
index 5e8c5e3..f63a8f1 100644
--- a/pylibfdt/.gitignore
+++ b/pylibfdt/.gitignore
@@ -1,3 +1,3 @@
 libfdt.py
-libfdt.pyc
+*.pyc
 libfdt_wrap.c
diff --git a/pylibfdt/Makefile.pylibfdt b/pylibfdt/Makefile.pylibfdt
index 9507d3d..6866a0b 100644
--- a/pylibfdt/Makefile.pylibfdt
+++ b/pylibfdt/Makefile.pylibfdt
@@ -1,24 +1,30 @@
+# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 # Makefile.pylibfdt
 #
 
-PYLIBFDT_srcs = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_SRCS)) \
-		$(PYLIBFDT_srcdir)/libfdt.i
-PYMODULE = $(PYLIBFDT_objdir)/_libfdt.so
+PYLIBFDT_srcs = $(PYLIBFDT_dir)/libfdt.i
+PYMODULE = $(PYLIBFDT_dir)/_libfdt.so
+PYLIBFDT_CLEANFILES_L = libfdt_wrap.c libfdt.py *.pyc *.so
+PYLIBFDT_CLEANFILES = $(PYLIBFDT_CLEANFILES_L:%=$(PYLIBFDT_dir)/%)
+PYLIBFDT_CLEANDIRS_L = build __pycache__
+PYLIBFDT_CLEANDIRS = $(PYLIBFDT_CLEANDIRS_L:%=$(PYLIBFDT_dir)/%)
 
-define run_setup
-	SOURCES="$(1)" CPPFLAGS="$(CPPFLAGS)" OBJDIR="$(PYLIBFDT_objdir)"
-	VERSION="$(dtc_version)"
-	$(PYLIBFDT_objdir)/setup.py --quiet $(2)
-endef
+SETUP = $(PYLIBFDT_dir)/setup.py
+SETUPFLAGS =
 
-$(PYMODULE): $(PYLIBFDT_srcs)
+ifndef V
+SETUPFLAGS += --quiet
+endif
+
+$(PYMODULE): $(PYLIBFDT_srcs) $(LIBFDT_archive) $(SETUP) $(VERSION_FILE)
 	@$(VECHO) PYMOD $@
-	$(call run_setup, $^, build_ext --inplace)
-	mv _libfdt.so $@
+	$(PYTHON) $(SETUP) $(SETUPFLAGS) build_ext --build-lib=../$(PYLIBFDT_dir)
 
 install_pylibfdt: $(PYMODULE)
-	$(VECHO) INSTALL-PYLIB; \
-	$(call run_setup, $(PYLIBFDT_srcs), \
-		install $(if $(SETUP_PREFIX),--prefix=$(SETUP_PREFIX)))
+	@$(VECHO) INSTALL-PYLIB
+	$(PYTHON) $(SETUP) $(SETUPFLAGS) install --prefix=$(PREFIX)
 
-PYLIBFDT_cleanfiles = libfdt_wrap.c libfdt.py libfdt.pyc _libfdt.so
+pylibfdt_clean:
+	@$(VECHO) CLEAN "(pylibfdt)"
+	rm -f $(PYLIBFDT_CLEANFILES)
+	rm -rf $(PYLIBFDT_CLEANDIRS)
diff --git a/pylibfdt/libfdt.i b/pylibfdt/libfdt.i
index cd1c6a9..3e09d3a 100644
--- a/pylibfdt/libfdt.i
+++ b/pylibfdt/libfdt.i
@@ -1,60 +1,29 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * 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
 
+%include <stdint.i>
+
 %{
 #define SWIG_FILE_WITH_INIT
 #include "libfdt.h"
+
+/*
+ * We rename this function here to avoid problems with swig, since we also have
+ * a struct called fdt_property. That struct causes swig to create a class in
+ * libfdt.py called fdt_property(), which confuses things.
+ */
+static int fdt_property_stub(void *fdt, const char *name, const void *val,
+                             int len)
+{
+    return fdt_property(fdt, name, val, len);
+}
+
 %}
 
 %pythoncode %{
@@ -86,6 +55,7 @@
 # Pass this as the 'quiet' parameter to return -ENOTFOUND on NOTFOUND errors,
 # instead of raising an exception.
 QUIET_NOTFOUND = (NOTFOUND,)
+QUIET_NOSPACE = (NOSPACE,)
 
 
 class FdtException(Exception):
@@ -122,7 +92,7 @@
     Raises
         FdtException if val < 0
     """
-    if val < 0:
+    if isinstance(val, int) and val < 0:
         if -val not in quiet:
             raise FdtException(val)
     return val
@@ -151,27 +121,199 @@
             raise FdtException(val)
     return val
 
-class Fdt:
-    """Device tree class, supporting all operations
+class FdtRo(object):
+    """Class for a read-only device-tree
 
-    The Fdt object is created is created from a device tree binary file,
-    e.g. with something like:
+    This is a base class used by FdtRw (read-write access) and FdtSw
+    (sequential-write access). It implements read-only access to the
+    device tree.
 
-       fdt = Fdt(open("filename.dtb").read())
+    Here are the three classes and when you should use them:
 
-    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).
+        FdtRo - read-only access to an existing FDT
+        FdtRw - read-write access to an existing FDT (most common case)
+        FdtSw - for creating a new FDT, as well as allowing read-only access
     """
     def __init__(self, data):
         self._fdt = bytearray(data)
         check_err(fdt_check_header(self._fdt));
 
+    def as_bytearray(self):
+        """Get the device tree contents as a bytearray
+
+        This can be passed directly to libfdt functions that access a
+        const void * for the device tree.
+
+        Returns:
+            bytearray containing the device tree
+        """
+        return bytearray(self._fdt)
+
+    def next_node(self, nodeoffset, depth, quiet=()):
+        """Find the next subnode
+
+        Args:
+            nodeoffset: Node offset of previous node
+            depth: The depth of the node at nodeoffset. This is used to
+                calculate the depth of the returned node
+            quiet: Errors to ignore (empty to raise on all errors)
+
+        Returns:
+            Typle:
+                Offset of the next node, if any, else a -ve error
+                Depth of the returned node, if any, else undefined
+
+        Raises:
+            FdtException if no more nodes found or other error occurs
+        """
+        return check_err(fdt_next_node(self._fdt, nodeoffset, depth), quiet)
+
+    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 subnodes 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 subnodes found or other error occurs
+        """
+        return check_err(fdt_next_subnode(self._fdt, nodeoffset), quiet)
+
+    def magic(self):
+        """Return the magic word from the header
+
+        Returns:
+            Magic word
+        """
+        return fdt_magic(self._fdt)
+
+    def totalsize(self):
+        """Return the total size of the device tree
+
+        Returns:
+            Total tree size in bytes
+        """
+        return 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 fdt_off_dt_struct(self._fdt)
+
+    def off_dt_strings(self):
+        """Return the start of the device-tree string area
+
+        Returns:
+            Start offset of string area
+        """
+        return fdt_off_dt_strings(self._fdt)
+
+    def off_mem_rsvmap(self):
+        """Return the start of the memory reserve map
+
+        Returns:
+            Start offset of memory reserve map
+        """
+        return fdt_off_mem_rsvmap(self._fdt)
+
+    def version(self):
+        """Return the version of the device tree
+
+        Returns:
+            Version number of the device tree
+        """
+        return fdt_version(self._fdt)
+
+    def last_comp_version(self):
+        """Return the last compatible version of the device tree
+
+        Returns:
+            Last compatible version number of the device tree
+        """
+        return fdt_last_comp_version(self._fdt)
+
+    def boot_cpuid_phys(self):
+        """Return the physical boot CPU ID
+
+        Returns:
+            Physical boot CPU ID
+        """
+        return fdt_boot_cpuid_phys(self._fdt)
+
+    def size_dt_strings(self):
+        """Return the start of the device-tree string area
+
+        Returns:
+            Start offset of string area
+        """
+        return fdt_size_dt_strings(self._fdt)
+
+    def size_dt_struct(self):
+        """Return the start of the device-tree struct area
+
+        Returns:
+            Start offset of struct area
+        """
+        return fdt_size_dt_struct(self._fdt)
+
+    def num_mem_rsv(self, quiet=()):
+        """Return the number of memory reserve-map records
+
+        Returns:
+            Number of memory reserve-map records
+        """
+        return check_err(fdt_num_mem_rsv(self._fdt), quiet)
+
+    def get_mem_rsv(self, index, quiet=()):
+        """Return the indexed memory reserve-map record
+
+        Args:
+            index: Record to return (0=first)
+
+        Returns:
+            Number of memory reserve-map records
+        """
+        return check_err(fdt_get_mem_rsv(self._fdt, index), quiet)
+
+    def subnode_offset(self, parentoffset, name, quiet=()):
+        """Get the offset of a named subnode
+
+        Args:
+            parentoffset: Offset of the parent node to check
+            name: Name of the required subnode, e.g. 'subnode@1'
+            quiet: Errors to ignore (empty to raise on all errors)
+
+        Returns:
+            The node offset of the found node, if any
+
+        Raises
+            FdtException if there is no node with that name, or other error
+        """
+        return check_err(fdt_subnode_offset(self._fdt, parentoffset, name),
+                         quiet)
+
     def path_offset(self, path, quiet=()):
         """Get the offset for a given path
 
@@ -187,6 +329,20 @@
         """
         return check_err(fdt_path_offset(self._fdt, path), 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 first_property_offset(self, nodeoffset, quiet=()):
         """Get the offset of the first property in a node offset
 
@@ -221,20 +377,6 @@
         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
 
@@ -255,77 +397,6 @@
             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
 
@@ -335,7 +406,9 @@
             quiet: Errors to ignore (empty to raise on all errors)
 
         Returns:
-            Value of property as a bytearray, or -ve error number
+            Value of property as a Property object (which can be used as a
+               bytearray/string), or -ve error number. On failure, returns an
+               integer error
 
         Raises:
             FdtError if any error occurs (e.g. the property is not found)
@@ -344,10 +417,276 @@
                                quiet)
         if isinstance(pdata, (int)):
             return pdata
-        return bytearray(pdata[0])
+        return Property(prop_name, bytearray(pdata[0]))
+
+    def get_phandle(self, nodeoffset):
+        """Get the phandle of a node
+
+        Args:
+            nodeoffset: Node offset to check
+
+        Returns:
+            phandle of node, or 0 if the node has no phandle or another error
+            occurs
+        """
+        return fdt_get_phandle(self._fdt, nodeoffset)
+
+    def get_alias(self, name):
+        """Get the full path referenced by a given alias
+
+        Args:
+            name: name of the alias to lookup
+
+        Returns:
+            Full path to the node for the alias named 'name', if it exists
+            None, if the given alias or the /aliases node does not exist
+        """
+        return fdt_get_alias(self._fdt, name)
+
+    def parent_offset(self, nodeoffset, quiet=()):
+        """Get the offset of a node's parent
+
+        Args:
+            nodeoffset: Node offset to check
+            quiet: Errors to ignore (empty to raise on all errors)
+
+        Returns:
+            The offset of the parent node, if any
+
+        Raises:
+            FdtException if no parent found or other error occurs
+        """
+        return check_err(fdt_parent_offset(self._fdt, nodeoffset), quiet)
+
+    def node_offset_by_phandle(self, phandle, quiet=()):
+        """Get the offset of a node with the given phandle
+
+        Args:
+            phandle: Phandle to search for
+            quiet: Errors to ignore (empty to raise on all errors)
+
+        Returns:
+            The offset of node with that phandle, if any
+
+        Raises:
+            FdtException if no node found or other error occurs
+        """
+        return check_err(fdt_node_offset_by_phandle(self._fdt, phandle), quiet)
 
 
-class Property:
+class Fdt(FdtRo):
+    """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):
+        FdtRo.__init__(self, data)
+
+    @staticmethod
+    def create_empty_tree(size, quiet=()):
+        """Create an empty device tree ready for use
+
+        Args:
+            size: Size of device tree in bytes
+
+        Returns:
+            Fdt object containing the device tree
+        """
+        data = bytearray(size)
+        err = check_err(fdt_create_empty_tree(data, size), quiet)
+        if err:
+            return err
+        return Fdt(data)
+
+    def resize(self, size, quiet=()):
+        """Move the device tree into a larger or smaller space
+
+        This creates a new device tree of size @size and moves the existing
+        device tree contents over to that. It can be used to create more space
+        in a device tree. Note that the Fdt object remains the same, but it
+        now has a new bytearray holding the contents.
+
+        Args:
+            size: Required new size of device tree in bytes
+        """
+        fdt = bytearray(size)
+        err = check_err(fdt_open_into(self._fdt, fdt, size), quiet)
+        if err:
+            return err
+        self._fdt = 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)
+
+        Returns:
+            Error code, or 0 if OK
+
+        Raises:
+            FdtException if any error occurs
+        """
+        err = check_err(fdt_pack(self._fdt), quiet)
+        if err:
+            return err
+        del self._fdt[self.totalsize():]
+        return err
+
+    def set_name(self, nodeoffset, name, quiet=()):
+        """Set the name of a node
+
+        Args:
+            nodeoffset: Node offset of node to update
+            name: New node name (string without \0)
+
+        Returns:
+            Error code, or 0 if OK
+
+        Raises:
+            FdtException if no parent found or other error occurs
+        """
+        if chr(0) in name:
+            raise ValueError('Property contains embedded nul characters')
+        return check_err(fdt_set_name(self._fdt, nodeoffset, name), quiet)
+
+    def setprop(self, nodeoffset, prop_name, val, quiet=()):
+        """Set the value of a property
+
+        Args:
+            nodeoffset: Node offset containing the property to create/update
+            prop_name: Name of property
+            val: Value to write (string or bytearray)
+            quiet: Errors to ignore (empty to raise on all errors)
+
+        Returns:
+            Error code, or 0 if OK
+
+        Raises:
+            FdtException if no parent found or other error occurs
+        """
+        return check_err(fdt_setprop(self._fdt, nodeoffset, prop_name, val,
+                                     len(val)), quiet)
+
+    def setprop_u32(self, nodeoffset, prop_name, val, quiet=()):
+        """Set the value of a property
+
+        Args:
+            nodeoffset: Node offset containing the property to create/update
+            prop_name: Name of property
+            val: Value to write (integer)
+            quiet: Errors to ignore (empty to raise on all errors)
+
+        Returns:
+            Error code, or 0 if OK
+
+        Raises:
+            FdtException if no parent found or other error occurs
+        """
+        return check_err(fdt_setprop_u32(self._fdt, nodeoffset, prop_name, val),
+                         quiet)
+
+    def setprop_u64(self, nodeoffset, prop_name, val, quiet=()):
+        """Set the value of a property
+
+        Args:
+            nodeoffset: Node offset containing the property to create/update
+            prop_name: Name of property
+            val: Value to write (integer)
+            quiet: Errors to ignore (empty to raise on all errors)
+
+        Returns:
+            Error code, or 0 if OK
+
+        Raises:
+            FdtException if no parent found or other error occurs
+        """
+        return check_err(fdt_setprop_u64(self._fdt, nodeoffset, prop_name, val),
+                         quiet)
+
+    def setprop_str(self, nodeoffset, prop_name, val, quiet=()):
+        """Set the string value of a property
+
+        The property is set to the string, with a nul terminator added
+
+        Args:
+            nodeoffset: Node offset containing the property to create/update
+            prop_name: Name of property
+            val: Value to write (string without nul terminator). Unicode is
+                supposed by encoding to UTF-8
+            quiet: Errors to ignore (empty to raise on all errors)
+
+        Returns:
+            Error code, or 0 if OK
+
+        Raises:
+            FdtException if no parent found or other error occurs
+        """
+        val = val.encode('utf-8') + b'\0'
+        return check_err(fdt_setprop(self._fdt, nodeoffset, prop_name,
+                                     val, len(val)), quiet)
+
+    def delprop(self, nodeoffset, prop_name, quiet=()):
+        """Delete a property from a node
+
+        Args:
+            nodeoffset: Node offset containing property to delete
+            prop_name: Name of property to delete
+            quiet: Errors to ignore (empty to raise on all errors)
+
+        Returns:
+            Error code, or 0 if OK
+
+        Raises:
+            FdtError if the property does not exist, or another error occurs
+        """
+        return check_err(fdt_delprop(self._fdt, nodeoffset, prop_name), quiet)
+
+    def add_subnode(self, parentoffset, name, quiet=()):
+        """Add a new subnode to a node
+
+        Args:
+            parentoffset: Parent offset to add the subnode to
+            name: Name of node to add
+
+        Returns:
+            offset of the node created, or negative error code on failure
+
+        Raises:
+            FdtError if there is not enough space, or another error occurs
+        """
+        return check_err(fdt_add_subnode(self._fdt, parentoffset, name), quiet)
+
+    def del_node(self, nodeoffset, quiet=()):
+        """Delete a node
+
+        Args:
+            nodeoffset: Offset of node to delete
+
+        Returns:
+            Error code, or 0 if OK
+
+        Raises:
+            FdtError if an error occurs
+        """
+        return check_err(fdt_del_node(self._fdt, nodeoffset), quiet)
+
+
+class Property(bytearray):
     """Holds a device tree property name and value.
 
     This holds a copy of a property taken from the device tree. It does not
@@ -356,18 +695,309 @@
 
     Properties:
         name: Property name
-        value: Proper value as a bytearray
+        value: Property value as a bytearray
     """
     def __init__(self, name, value):
+        bytearray.__init__(self, value)
         self.name = name
-        self.value = value
+
+    def as_cell(self, fmt):
+        return struct.unpack('>' + fmt, self)[0]
+
+    def as_uint32(self):
+        return self.as_cell('L')
+
+    def as_int32(self):
+        return self.as_cell('l')
+
+    def as_uint64(self):
+        return self.as_cell('Q')
+
+    def as_int64(self):
+        return self.as_cell('q')
+
+    def as_str(self):
+        """Unicode is supported by decoding from UTF-8"""
+        if self[-1] != 0:
+            raise ValueError('Property lacks nul termination')
+        if 0 in self[:-1]:
+            raise ValueError('Property contains embedded nul characters')
+        return self[:-1].decode('utf-8')
+
+
+class FdtSw(FdtRo):
+    """Software interface to create a device tree from scratch
+
+    The methods in this class work by adding to an existing 'partial' device
+    tree buffer of a fixed size created by instantiating this class. When the
+    tree is complete, call as_fdt() to obtain a device tree ready to be used.
+
+    Similarly with nodes, a new node is started with begin_node() and finished
+    with end_node().
+
+    The context manager functions can be used to make this a bit easier:
+
+    # First create the device tree with a node and property:
+    sw = FdtSw()
+    sw.finish_reservemap()
+    with sw.add_node(''):
+        with sw.add_node('node'):
+            sw.property_u32('reg', 2)
+    fdt = sw.as_fdt()
+
+    # Now we can use it as a real device tree
+    fdt.setprop_u32(0, 'reg', 3)
+
+    The size hint provides a starting size for the space to be used by the
+    device tree. This will be increased automatically as needed as new items
+    are added to the tree.
+    """
+    INC_SIZE = 1024  # Expand size by this much when out of space
+
+    def __init__(self, size_hint=None):
+        """Create a new FdtSw object
+
+        Args:
+            size_hint: A hint as to the initial size to use
+
+        Raises:
+            ValueError if size_hint is negative
+
+        Returns:
+            FdtSw object on success, else integer error code (if not raising)
+        """
+        if not size_hint:
+            size_hint = self.INC_SIZE
+        fdtsw = bytearray(size_hint)
+        err = check_err(fdt_create(fdtsw, size_hint))
+        if err:
+            return err
+        self._fdt = fdtsw
+
+    def as_fdt(self):
+        """Convert a FdtSw into an Fdt so it can be accessed as normal
+
+        Creates a new Fdt object from the work-in-progress device tree. This
+        does not call fdt_finish() on the current object, so it is possible to
+        add more nodes/properties and call as_fdt() again to get an updated
+        tree.
+
+        Returns:
+            Fdt object allowing access to the newly created device tree
+        """
+        fdtsw = bytearray(self._fdt)
+        check_err(fdt_finish(fdtsw))
+        return Fdt(fdtsw)
+
+    def check_space(self, val):
+        """Check if we need to add more space to the FDT
+
+        This should be called with the error code from an operation. If this is
+        -NOSPACE then the FDT will be expanded to have more space, and True will
+        be returned, indicating that the operation needs to be tried again.
+
+        Args:
+            val: Return value from the operation that was attempted
+
+        Returns:
+            True if the operation must be retried, else False
+        """
+        if check_err(val, QUIET_NOSPACE) < 0:
+            self.resize(len(self._fdt) + self.INC_SIZE)
+            return True
+        return False
+
+    def resize(self, size):
+        """Resize the buffer to accommodate a larger tree
+
+        Args:
+            size: New size of tree
+
+        Raises:
+            FdtException on any error
+        """
+        fdt = bytearray(size)
+        err = check_err(fdt_resize(self._fdt, fdt, size))
+        self._fdt = fdt
+
+    def add_reservemap_entry(self, addr, size):
+        """Add a new memory reserve map entry
+
+        Once finished adding, you must call finish_reservemap().
+
+        Args:
+            addr: 64-bit start address
+            size: 64-bit size
+
+        Raises:
+            FdtException on any error
+        """
+        while self.check_space(fdt_add_reservemap_entry(self._fdt, addr,
+                                                        size)):
+            pass
+
+    def finish_reservemap(self):
+        """Indicate that there are no more reserve map entries to add
+
+        Raises:
+            FdtException on any error
+        """
+        while self.check_space(fdt_finish_reservemap(self._fdt)):
+            pass
+
+    def begin_node(self, name):
+        """Begin a new node
+
+        Use this before adding properties to the node. Then call end_node() to
+        finish it. You can also use the context manager as shown in the FdtSw
+        class comment.
+
+        Args:
+            name: Name of node to begin
+
+        Raises:
+            FdtException on any error
+        """
+        while self.check_space(fdt_begin_node(self._fdt, name)):
+            pass
+
+    def property_string(self, name, string):
+        """Add a property with a string value
+
+        The string will be nul-terminated when written to the device tree
+
+        Args:
+            name: Name of property to add
+            string: String value of property
+
+        Raises:
+            FdtException on any error
+        """
+        while self.check_space(fdt_property_string(self._fdt, name, string)):
+            pass
+
+    def property_u32(self, name, val):
+        """Add a property with a 32-bit value
+
+        Write a single-cell value to the device tree
+
+        Args:
+            name: Name of property to add
+            val: Value of property
+
+        Raises:
+            FdtException on any error
+        """
+        while self.check_space(fdt_property_u32(self._fdt, name, val)):
+            pass
+
+    def property_u64(self, name, val):
+        """Add a property with a 64-bit value
+
+        Write a double-cell value to the device tree in big-endian format
+
+        Args:
+            name: Name of property to add
+            val: Value of property
+
+        Raises:
+            FdtException on any error
+        """
+        while self.check_space(fdt_property_u64(self._fdt, name, val)):
+            pass
+
+    def property_cell(self, name, val):
+        """Add a property with a single-cell value
+
+        Write a single-cell value to the device tree
+
+        Args:
+            name: Name of property to add
+            val: Value of property
+            quiet: Errors to ignore (empty to raise on all errors)
+
+        Raises:
+            FdtException on any error
+        """
+        while self.check_space(fdt_property_cell(self._fdt, name, val)):
+            pass
+
+    def property(self, name, val):
+        """Add a property
+
+        Write a new property with the given value to the device tree. The value
+        is taken as is and is not nul-terminated
+
+        Args:
+            name: Name of property to add
+            val: Value of property (bytes)
+            quiet: Errors to ignore (empty to raise on all errors)
+
+        Raises:
+            FdtException on any error
+        """
+        while self.check_space(fdt_property_stub(self._fdt, name, val,
+                                                 len(val))):
+            pass
+
+    def end_node(self):
+        """End a node
+
+        Use this after adding properties to a node to close it off. You can also
+        use the context manager as shown in the FdtSw class comment.
+
+        Args:
+            quiet: Errors to ignore (empty to raise on all errors)
+
+        Raises:
+            FdtException on any error
+        """
+        while self.check_space(fdt_end_node(self._fdt)):
+            pass
+
+    def add_node(self, name):
+        """Create a new context for adding a node
+
+        When used in a 'with' clause this starts a new node and finishes it
+        afterward.
+
+        Args:
+            name: Name of node to add
+        """
+        return NodeAdder(self, name)
+
+
+class NodeAdder():
+    """Class to provide a node context
+
+    This allows you to add nodes in a more natural way:
+
+        with fdtsw.add_node('name'):
+            fdtsw.property_string('test', 'value')
+
+    The node is automatically completed with a call to end_node() when the
+    context exits.
+    """
+    def __init__(self, fdtsw, name):
+        self._fdt = fdtsw
+        self._name = name
+
+    def __enter__(self):
+        self._fdt.begin_node(self._name)
+
+    def __exit__(self, type, value, traceback):
+        self._fdt.end_node()
 %}
 
 %rename(fdt_property) fdt_property_func;
 
-typedef int fdt32_t;
+/*
+ * fdt32_t is a big-endian 32-bit value defined to uint32_t in libfdt_env.h
+ * so use the same type here.
+ */
+typedef uint32_t fdt32_t;
 
-%include "libfdt/fdt.h"
+%include "fdt.h"
 
 %include "typemaps.i"
 
@@ -393,6 +1023,7 @@
         fdt = fdt; /* avoid unused variable warning */
 }
 
+/* typemap used for fdt_get_property_by_offset() */
 %typemap(out) (struct fdt_property *) {
 	PyObject *buff;
 
@@ -412,22 +1043,76 @@
 	if (!$1)
 		$result = Py_None;
 	else
-		$result = Py_BuildValue("s#", $1, *arg4);
+        %#if PY_VERSION_HEX >= 0x03000000
+            $result = Py_BuildValue("y#", $1, *arg4);
+        %#else
+            $result = Py_BuildValue("s#", $1, *arg4);
+        %#endif
+}
+
+/* typemap used for fdt_setprop() */
+%typemap(in) (const void *val) {
+    %#if PY_VERSION_HEX >= 0x03000000
+        if (!PyBytes_Check($input)) {
+            SWIG_exception_fail(SWIG_TypeError, "bytes expected in method '" "$symname"
+                "', argument " "$argnum"" of type '" "$type""'");
+        }
+        $1 = PyBytes_AsString($input);
+    %#else
+        $1 = PyString_AsString($input);   /* char *str */
+    %#endif
+}
+
+/* typemaps used for fdt_next_node() */
+%typemap(in, numinputs=1) int *depth (int depth) {
+   depth = (int) PyInt_AsLong($input);
+   $1 = &depth;
+}
+
+%typemap(argout) int *depth {
+        PyObject *val = Py_BuildValue("i", *arg$argnum);
+        resultobj = SWIG_Python_AppendOutput(resultobj, val);
+}
+
+%apply int *depth { int *depth };
+
+/* typemaps for fdt_get_mem_rsv */
+%typemap(in, numinputs=0) uint64_t * (uint64_t temp) {
+   $1 = &temp;
+}
+
+%typemap(argout) uint64_t * {
+        PyObject *val = PyLong_FromUnsignedLongLong(*arg$argnum);
+        if (!result) {
+           if (PyTuple_GET_SIZE(resultobj) == 0)
+              resultobj = val;
+           else
+              resultobj = SWIG_Python_AppendOutput(resultobj, val);
+        }
 }
 
 /* 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);
+uint32_t fdt_magic(const void *fdt);
+uint32_t fdt_totalsize(const void *fdt);
+uint32_t fdt_off_dt_struct(const void *fdt);
+uint32_t fdt_off_dt_strings(const void *fdt);
+uint32_t fdt_off_mem_rsvmap(const void *fdt);
+uint32_t fdt_version(const void *fdt);
+uint32_t fdt_last_comp_version(const void *fdt);
+uint32_t fdt_boot_cpuid_phys(const void *fdt);
+uint32_t fdt_size_dt_strings(const void *fdt);
+uint32_t fdt_size_dt_struct(const void *fdt);
 
-%include <../libfdt/libfdt.h>
+int fdt_property_string(void *fdt, const char *name, const char *val);
+int fdt_property_cell(void *fdt, const char *name, uint32_t val);
+
+/*
+ * This function has a stub since the name fdt_property is used for both a
+  * function and a struct, which confuses SWIG.
+ */
+int fdt_property_stub(void *fdt, const char *name, const void *val, int len);
+
+%include <libfdt.h>
diff --git a/pylibfdt/setup.py b/pylibfdt/setup.py
index 90e80f3..53f2bef 100755
--- a/pylibfdt/setup.py
+++ b/pylibfdt/setup.py
@@ -1,19 +1,13 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
+# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+
+# While Python 3 is the default, it's also possible to invoke
+# this setup.py script with Python 2.
 
 """
 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
@@ -21,101 +15,34 @@
 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>.*)$')
+
+VERSION_PATTERN = '^#define DTC_VERSION "DTC ([^"]*)"$'
 
 
-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
+def get_version():
+    version_file = "../version_gen.h"
+    f = open(version_file, 'rt')
+    m = re.match(VERSION_PATTERN, f.readline())
+    return m.group(1)
 
 
-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()
+setupdir = os.path.dirname(os.path.abspath(sys.argv[0]))
+os.chdir(setupdir)
 
 libfdt_module = Extension(
     '_libfdt',
-    sources = files,
-    extra_compile_args = cflags,
-    swig_opts = swig_opts,
+    sources=['libfdt.i'],
+    include_dirs=['../libfdt'],
+    libraries=['fdt'],
+    library_dirs=['../libfdt'],
+    swig_opts=['-I../libfdt'],
 )
 
 setup(
     name='libfdt',
-    version= version,
+    version=get_version(),
     author='Simon Glass <sjg@chromium.org>',
     description='Python binding for libfdt',
     ext_modules=[libfdt_module],
-    package_dir={'': objdir},
-    py_modules=['pylibfdt/libfdt'],
+    py_modules=['libfdt'],
 )
diff --git a/scripts/kup-dtc b/scripts/kup-dtc
index e18abbb..3c3376c 100755
--- a/scripts/kup-dtc
+++ b/scripts/kup-dtc
@@ -1,4 +1,5 @@
 #! /bin/sh
+# SPDX-License-Identifier: GPL-2.0-or-later
 
 REMOTE_GIT=/pub/scm/utils/dtc/dtc.git
 REMOTE_PATH=/pub/software/utils/dtc
diff --git a/scripts/setlocalversion b/scripts/setlocalversion
index 82e4993..ea333e7 100755
--- a/scripts/setlocalversion
+++ b/scripts/setlocalversion
@@ -1,4 +1,5 @@
 #!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-or-later
 # Print additional version information for non-release trees.
 
 usage() {
diff --git a/srcpos.c b/srcpos.c
index 9d38459..f5205fb 100644
--- a/srcpos.c
+++ b/srcpos.c
@@ -1,20 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
- *                                                                   USA
  */
 
 #define _GNU_SOURCE
@@ -33,6 +19,9 @@
 /* This is the list of directories that we search for source files */
 static struct search_path *search_path_head, **search_path_tail;
 
+/* Detect infinite include recursion. */
+#define MAX_SRCFILE_DEPTH     (100)
+static int srcfile_depth; /* = 0 */
 
 static char *get_dirname(const char *path)
 {
@@ -51,11 +40,51 @@
 
 FILE *depfile; /* = NULL */
 struct srcfile_state *current_srcfile; /* = NULL */
+static char *initial_path; /* = NULL */
+static int initial_pathlen; /* = 0 */
+static bool initial_cpp = true;
 
-/* Detect infinite include recursion. */
-#define MAX_SRCFILE_DEPTH     (100)
-static int srcfile_depth; /* = 0 */
+static void set_initial_path(char *fname)
+{
+	int i, len = strlen(fname);
 
+	xasprintf(&initial_path, "%s", fname);
+	initial_pathlen = 0;
+	for (i = 0; i != len; i++)
+		if (initial_path[i] == '/')
+			initial_pathlen++;
+}
+
+static char *shorten_to_initial_path(char *fname)
+{
+	char *p1, *p2, *prevslash1 = NULL;
+	int slashes = 0;
+
+	for (p1 = fname, p2 = initial_path; *p1 && *p2; p1++, p2++) {
+		if (*p1 != *p2)
+			break;
+		if (*p1 == '/') {
+			prevslash1 = p1;
+			slashes++;
+		}
+	}
+	p1 = prevslash1 + 1;
+	if (prevslash1) {
+		int diff = initial_pathlen - slashes, i, j;
+		int restlen = strlen(fname) - (p1 - fname);
+		char *res;
+
+		res = xmalloc((3 * diff) + restlen + 1);
+		for (i = 0, j = 0; i != diff; i++) {
+			res[j++] = '.';
+			res[j++] = '.';
+			res[j++] = '/';
+		}
+		strcpy(res + j, p1);
+		return res;
+	}
+	return NULL;
+}
 
 /**
  * Try to open a file in a given directory.
@@ -157,6 +186,9 @@
 	srcfile->colno = 1;
 
 	current_srcfile = srcfile;
+
+	if (srcfile_depth == 1)
+		set_initial_path(srcfile->name);
 }
 
 bool srcfile_pop(void)
@@ -197,20 +229,6 @@
 	search_path_tail = &node->next;
 }
 
-/*
- * The empty source position.
- */
-
-struct srcpos srcpos_empty = {
-	.first_line = 0,
-	.first_column = 0,
-	.last_line = 0,
-	.last_column = 0,
-	.file = NULL,
-};
-
-#define TAB_SIZE      8
-
 void srcpos_update(struct srcpos *pos, const char *text, int len)
 {
 	int i;
@@ -224,9 +242,6 @@
 		if (text[i] == '\n') {
 			current_srcfile->lineno++;
 			current_srcfile->colno = 1;
-		} else if (text[i] == '\t') {
-			current_srcfile->colno =
-				ALIGN(current_srcfile->colno, TAB_SIZE);
 		} else {
 			current_srcfile->colno++;
 		}
@@ -239,13 +254,35 @@
 srcpos_copy(struct srcpos *pos)
 {
 	struct srcpos *pos_new;
+	struct srcfile_state *srcfile_state;
+
+	if (!pos)
+		return NULL;
 
 	pos_new = xmalloc(sizeof(struct srcpos));
+	assert(pos->next == NULL);
 	memcpy(pos_new, pos, sizeof(struct srcpos));
 
+	/* allocate without free */
+	srcfile_state = xmalloc(sizeof(struct srcfile_state));
+	memcpy(srcfile_state, pos->file, sizeof(struct srcfile_state));
+	pos_new->file = srcfile_state;
+
 	return pos_new;
 }
 
+struct srcpos *srcpos_extend(struct srcpos *pos, struct srcpos *newtail)
+{
+	struct srcpos *p;
+
+	if (!pos)
+		return newtail;
+
+	for (p = pos; p->next != NULL; p = p->next);
+	p->next = newtail;
+	return pos;
+}
+
 char *
 srcpos_string(struct srcpos *pos)
 {
@@ -271,6 +308,68 @@
 	return pos_str;
 }
 
+static char *
+srcpos_string_comment(struct srcpos *pos, bool first_line, int level)
+{
+	char *pos_str, *fname, *first, *rest;
+	bool fresh_fname = false;
+
+	if (!pos) {
+		if (level > 1) {
+			xasprintf(&pos_str, "<no-file>:<no-line>");
+			return pos_str;
+		} else {
+			return NULL;
+		}
+	}
+
+	if (!pos->file)
+		fname = "<no-file>";
+	else if (!pos->file->name)
+		fname = "<no-filename>";
+	else if (level > 1)
+		fname = pos->file->name;
+	else {
+		fname = shorten_to_initial_path(pos->file->name);
+		if (fname)
+			fresh_fname = true;
+		else
+			fname = pos->file->name;
+	}
+
+	if (level > 1)
+		xasprintf(&first, "%s:%d:%d-%d:%d", fname,
+			  pos->first_line, pos->first_column,
+			  pos->last_line, pos->last_column);
+	else
+		xasprintf(&first, "%s:%d", fname,
+			  first_line ? pos->first_line : pos->last_line);
+
+	if (fresh_fname)
+		free(fname);
+
+	if (pos->next != NULL) {
+		rest = srcpos_string_comment(pos->next, first_line, level);
+		xasprintf(&pos_str, "%s, %s", first, rest);
+		free(first);
+		free(rest);
+	} else {
+		pos_str = first;
+	}
+
+	return pos_str;
+}
+
+char *srcpos_string_first(struct srcpos *pos, int level)
+{
+	return srcpos_string_comment(pos, true, level);
+}
+
+char *srcpos_string_last(struct srcpos *pos, int level)
+{
+	return srcpos_string_comment(pos, false, level);
+}
+
 void srcpos_verror(struct srcpos *pos, const char *prefix,
 		   const char *fmt, va_list va)
 {
@@ -299,4 +398,9 @@
 {
 	current_srcfile->name = f;
 	current_srcfile->lineno = l;
+
+	if (initial_cpp) {
+		initial_cpp = false;
+		set_initial_path(f);
+	}
 }
diff --git a/srcpos.h b/srcpos.h
index 7caca82..4318d7a 100644
--- a/srcpos.h
+++ b/srcpos.h
@@ -1,24 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 /*
  * Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
- *                                                                   USA
  */
 
-#ifndef _SRCPOS_H_
-#define _SRCPOS_H_
+#ifndef SRCPOS_H
+#define SRCPOS_H
 
 #include <stdio.h>
 #include <stdbool.h>
@@ -74,6 +60,7 @@
     int last_line;
     int last_column;
     struct srcfile_state *file;
+    struct srcpos *next;
 };
 
 #define YYLTYPE struct srcpos
@@ -93,19 +80,18 @@
 				YYRHSLOC(Rhs, 0).last_column;			\
 			(Current).file = YYRHSLOC (Rhs, 0).file;		\
 		}								\
+		(Current).next = NULL;						\
 	} while (0)
 
 
-/*
- * Fictional source position used for IR nodes that are
- * created without otherwise knowing a true source position.
- * For example,constant definitions from the command line.
- */
-extern struct srcpos srcpos_empty;
-
 extern void srcpos_update(struct srcpos *pos, const char *text, int len);
 extern struct srcpos *srcpos_copy(struct srcpos *pos);
+extern struct srcpos *srcpos_extend(struct srcpos *new_srcpos,
+				    struct srcpos *old_srcpos);
 extern char *srcpos_string(struct srcpos *pos);
+extern char *srcpos_string_first(struct srcpos *pos, int level);
+extern char *srcpos_string_last(struct srcpos *pos, int level);
+
 
 extern void PRINTF(3, 0) srcpos_verror(struct srcpos *pos, const char *prefix,
 					const char *fmt, va_list va);
@@ -114,4 +100,4 @@
 
 extern void srcpos_set_line(char *f, int l);
 
-#endif /* _SRCPOS_H_ */
+#endif /* SRCPOS_H */
diff --git a/tests/.gitignore b/tests/.gitignore
index 9e209d5..d3f1434 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -1,13 +1,19 @@
 *.dtb
 *.dts.test.s
 *.test.dts
+*.test.dt.yaml
 tmp.*
+/fs/
 /add_subnode_with_nops
 /addr_size_cells
+/addr_size_cells2
 /appendprop[12]
+/appendprop_addrrange
 /asm_tree_dump
 /boot-cpuid
 /char_literal
+/check_full
+/check_header
 /check_path
 /del_node
 /del_property
@@ -23,8 +29,10 @@
 /get_path
 /get_phandle
 /getprop
+/get_prop_offset
 /incbin
 /integer-expressions
+/fs_tree1
 /mangle-layout
 /move_and_save
 /node_check_compatible
@@ -48,6 +56,7 @@
 /references
 /root_node
 /rw_tree1
+/rw_oom
 /set_name
 /setprop
 /setprop_inplace
@@ -58,6 +67,9 @@
 /subnode_offset
 /supernode_atdepth_offset
 /sw_tree1
+/sw_states
 /truncated_property
+/truncated_string
+/truncated_memrsv
 /utilfdt_test
 /value-labels
diff --git a/tests/Makefile.tests b/tests/Makefile.tests
index 2258135..cb66c9f 100644
--- a/tests/Makefile.tests
+++ b/tests/Makefile.tests
@@ -1,6 +1,6 @@
 LIB_TESTS_L = get_mem_rsv \
 	root_node find_property subnode_offset path_offset \
-	get_name getprop get_phandle \
+	get_name getprop get_prop_offset get_phandle \
 	get_path supernode_atdepth_offset parent_offset \
 	node_offset_by_prop_value node_offset_by_phandle \
 	node_check_compatible node_offset_by_compatible \
@@ -9,11 +9,13 @@
 	sized_cells \
 	notfound \
 	addr_size_cells \
+	addr_size_cells2 \
+	appendprop_addrrange \
 	stringlist \
 	setprop_inplace nop_property nop_node \
-	sw_tree1 \
+	sw_tree1 sw_states \
 	move_and_save mangle-layout nopulate \
-	open_pack rw_tree1 set_name setprop del_property del_node \
+	open_pack rw_tree1 rw_oom set_name setprop del_property del_node \
 	appendprop1 appendprop2 propname_escapes \
 	string_escapes references path-references phandle_format \
 	boot-cpuid incbin \
@@ -26,10 +28,11 @@
 	property_iterate \
 	subnode_iterate \
 	overlay overlay_bad_fixup \
-	check_path
+	check_path check_header check_full \
+	fs_tree1
 LIB_TESTS = $(LIB_TESTS_L:%=$(TESTS_PREFIX)%)
 
-LIBTREE_TESTS_L = truncated_property
+LIBTREE_TESTS_L = truncated_property truncated_string truncated_memrsv
 LIBTREE_TESTS = $(LIBTREE_TESTS_L:%=$(TESTS_PREFIX)%)
 
 DL_LIB_TESTS_L = asm_tree_dump value-labels
@@ -45,38 +48,49 @@
 TESTS_DEPFILES = $(TESTS:%=%.d) \
 	$(addprefix $(TESTS_PREFIX),testutils.d trees.d dumptrees.d)
 
-TESTS_CLEANFILES_L =  *.output vglog.* vgcore.* *.dtb *.test.dts *.dtsv1 tmp.*
-TESTS_CLEANFILES_L += dumptrees
+TESTS_CLEANFILES_L = $(STD_CLEANFILES) \
+	*.dtb *.test.dts *.test.dt.yaml *.dtsv1 tmp.* *.bak \
+	dumptrees
 TESTS_CLEANFILES = $(TESTS) $(TESTS_CLEANFILES_L:%=$(TESTS_PREFIX)%)
+TESTS_CLEANDIRS_L = fs
+TESTS_CLEANDIRS = $(TESTS_CLEANDIRS_L:%=$(TESTS_PREFIX)%)
 
 .PHONY: tests
 tests:	$(TESTS) $(TESTS_TREES)
 
-$(LIB_TESTS): %: $(TESTS_PREFIX)testutils.o util.o $(LIBFDT_archive)
+$(LIB_TESTS): %: $(TESTS_PREFIX)testutils.o util.o $(LIBFDT_lib)
 
-$(DL_LIB_TESTS): %: %.o $(TESTS_PREFIX)testutils.o util.o $(LIBFDT_archive)
+# Not necessary on all platforms; allow -ldl to be excluded instead of forcing
+# other platforms to patch it out.
+LIBDL = -ldl
+$(DL_LIB_TESTS): %: %.o $(TESTS_PREFIX)testutils.o util.o $(LIBFDT_lib)
 	@$(VECHO) LD [libdl] $@
-	$(LINK.c) -o $@ $^ -ldl
+	$(LINK.c) -o $@ $^ $(LIBDL)
 
 $(LIBTREE_TESTS): %: $(TESTS_PREFIX)testutils.o $(TESTS_PREFIX)trees.o \
-		util.o $(LIBFDT_archive)
+		util.o $(LIBFDT_lib)
 
 $(TESTS_PREFIX)dumptrees: $(TESTS_PREFIX)trees.o
 
 $(TESTS_TREES): $(TESTS_PREFIX)dumptrees
 	@$(VECHO) DUMPTREES
-	cd $(TESTS_PREFIX); ./dumptrees >/dev/null
+	cd $(TESTS_PREFIX); ./dumptrees . >/dev/null
 
 tests_clean:
 	@$(VECHO) CLEAN "(tests)"
-	rm -f $(STD_CLEANFILES:%=$(TESTS_PREFIX)%)
 	rm -f $(TESTS_CLEANFILES)
+	rm -rf $(TESTS_CLEANDIRS)
 
 check:	tests ${TESTS_BIN} $(TESTS_PYLIBFDT)
 	cd $(TESTS_PREFIX); ./run_tests.sh
 
+ifeq ($(NO_VALGRIND),1)
+checkm:
+	@echo "make checkm requires valgrind, but NO_VALGRIND=1"
+else
 checkm: tests ${TESTS_BIN} $(TESTS_PYLIBFDT)
-	cd $(TESTS_PREFIX); ./run_tests.sh -m 2>&1 | tee vglog.$$$$
+	cd $(TESTS_PREFIX); ./run_tests.sh -m
+endif
 
 checkv:	tests ${TESTS_BIN} $(TESTS_PYLIBFDT)
 	cd $(TESTS_PREFIX); ./run_tests.sh -v
@@ -84,4 +98,3 @@
 ifneq ($(DEPTARGETS),)
 -include $(TESTS_DEPFILES)
 endif
-
diff --git a/tests/add_subnode_with_nops.c b/tests/add_subnode_with_nops.c
index 95ddf6a..29bd34b 100644
--- a/tests/add_subnode_with_nops.c
+++ b/tests/add_subnode_with_nops.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_nop_node()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
diff --git a/tests/addr_size_cells.c b/tests/addr_size_cells.c
index 6090d93..783574d 100644
--- a/tests/addr_size_cells.c
+++ b/tests/addr_size_cells.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for #address-cells and #size-cells handling
  * Copyright (C) 2014 David Gibson, <david@gibson.dropbear.id.au>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 #include <stdlib.h>
 #include <stdio.h>
@@ -58,7 +45,12 @@
 	fdt = load_blob(argv[1]);
 
 	check_node(fdt, "/", 2, 2);
-	check_node(fdt, "/identity-bus@0", 2, 2);
+	check_node(fdt, "/identity-bus@0", 2, 1);
 	check_node(fdt, "/simple-bus@1000000", 2, 1);
+	check_node(fdt, "/discrete-bus@2000000", 1, 0);
+	check_node(fdt, "/c0", -FDT_ERR_BADNCELLS, -FDT_ERR_BADNCELLS);
+	check_node(fdt, "/c1", -FDT_ERR_BADNCELLS, -FDT_ERR_BADNCELLS);
+	check_node(fdt, "/c2", -FDT_ERR_BADNCELLS, -FDT_ERR_BADNCELLS);
+	check_node(fdt, "/c3", -FDT_ERR_BADNCELLS, 0);
 	PASS();
 }
diff --git a/tests/addr_size_cells2.c b/tests/addr_size_cells2.c
new file mode 100644
index 0000000..d97541b
--- /dev/null
+++ b/tests/addr_size_cells2.c
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ * libfdt - Flat Device Tree manipulation
+ *	Testcase for #address-cells and #size-cells handling
+ * Copyright (C) 2014 David Gibson, <david@gibson.dropbear.id.au>
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+static void check_node(const void *fdt, const char *path, int ac, int sc)
+{
+	int offset;
+	int xac, xsc;
+
+	offset = fdt_path_offset(fdt, path);
+	if (offset < 0)
+		FAIL("Couldn't find path %s", path);
+
+	xac = fdt_address_cells(fdt, offset);
+	xsc = fdt_size_cells(fdt, offset);
+
+	if (xac != ac)
+		FAIL("Address cells for %s is %d instead of %d\n",
+		     path, xac, ac);
+	if (xsc != sc)
+		FAIL("Size cells for %s is %d instead of %d\n",
+		     path, xsc, sc);
+}
+
+int main(int argc, char *argv[])
+{
+	void *fdt;
+
+	if (argc != 2)
+		CONFIG("Usage: %s <dtb file>\n", argv[0]);
+
+	test_init(argc, argv);
+	fdt = load_blob(argv[1]);
+
+	check_node(fdt, "/", 2, 1);
+	PASS();
+}
diff --git a/tests/addresses.dts b/tests/addresses.dts
index a2faaf5..1b307ab 100644
--- a/tests/addresses.dts
+++ b/tests/addresses.dts
@@ -12,4 +12,29 @@
 		#address-cells = <2>;
 		#size-cells = <1>;
 	};
+
+	discrete-bus@2000000 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
+
+	c0@0 {
+		#address-cells = <1 1>;
+		#size-cells = <1 1>;
+	};
+
+	c1@0 {
+		#address-cells = <0x80000000>;
+		#size-cells = <0x80000000>;
+	};
+
+	c2@0 {
+		#address-cells = <5>;
+		#size-cells = <5>;
+	};
+
+	c3@0 {
+		#address-cells = <0>;
+		#size-cells = <0>;
+	};
 };
diff --git a/tests/appendprop1.c b/tests/appendprop1.c
index 9d6b3ad..a7b502a 100644
--- a/tests/appendprop1.c
+++ b/tests/appendprop1.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_appendprop()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
diff --git a/tests/appendprop2.c b/tests/appendprop2.c
index ca1446c..a0c1f6f 100644
--- a/tests/appendprop2.c
+++ b/tests/appendprop2.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_appendprop()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
diff --git a/tests/appendprop_addrrange.c b/tests/appendprop_addrrange.c
new file mode 100644
index 0000000..538afcf
--- /dev/null
+++ b/tests/appendprop_addrrange.c
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ * libfdt - Flat Device Tree manipulation
+ *	Testcase for fdt_appendprop_addrrange()
+ * Copyright (C) 2018 AKASHI Takahiro, Linaro Limited
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+int main(int argc, char *argv[])
+{
+	void *fdt, *buf;
+	int offset, xac, xsc, num, i, err;
+	uint64_t addr, size;
+
+	if (argc != 5)
+		CONFIG("Usage: %s <dtb file> <address-cells> <size-cells> <num>\n",
+		       argv[0]);
+
+	test_init(argc, argv);
+	fdt = load_blob(argv[1]);
+	xac = strtol(argv[2], NULL, 10);
+	xsc = strtol(argv[3], NULL, 10);
+	num = strtol(argv[4], NULL, 10);
+
+	buf = xmalloc(0x1000);
+	if (!buf)
+		FAIL("Couldn't allocate temporary buffer");
+	err = fdt_open_into(fdt, buf, 0x1000);
+	if (err)
+		FAIL("fdt_open_into(): %s", fdt_strerror(err));
+
+	fdt = buf;
+
+	/* Set up */
+	err = fdt_setprop_cell(fdt, 0, "#address-cells", xac);
+	if (err)
+		FAIL("fdt_setprop_cell(\"#address-cells\"): %s",
+		     fdt_strerror(err));
+	err = fdt_setprop_cell(fdt, 0, "#size-cells", xsc);
+	if (err)
+		FAIL("fdt_setprop_cell(\"#size-cells\"): %s",
+		     fdt_strerror(err));
+
+	offset = fdt_path_offset(fdt, "/node@1");
+	if (offset < 0)
+		FAIL("Couldn't find path %s", "/node@1");
+
+	addr = TEST_MEMREGION_ADDR;
+	if (xac > 1)
+		addr += TEST_MEMREGION_ADDR_HI;
+	size = TEST_MEMREGION_SIZE;
+	if (xsc > 1)
+		size += TEST_MEMREGION_SIZE_HI;
+
+	/*
+	 * Do test
+	 */
+	/* 1. repeat append's */
+	for (i = 0; i < num; i++) {
+		err = fdt_appendprop_addrrange(fdt, 0, offset,
+					       "prop-memregion", addr, size);
+		if (err)
+			FAIL("Failed to append[%d] \"prop-memregion\": %s",
+			     i, fdt_strerror(err));
+
+		check_getprop_addrrange(fdt, 0, offset, "prop-memregion",
+					i + 1);
+
+		addr += size;
+		size += TEST_MEMREGION_SIZE_INC;
+	}
+
+	/* 2. default property name */
+	addr = TEST_MEMREGION_ADDR;
+	if (xac > 1)
+		addr += TEST_MEMREGION_ADDR_HI;
+	size = TEST_MEMREGION_SIZE;
+	if (xsc > 1)
+		size += TEST_MEMREGION_SIZE_HI;
+
+	err = fdt_appendprop_addrrange(fdt, 0, offset, "reg", addr, size);
+	if (err)
+		FAIL("Failed to set \"reg\": %s", fdt_strerror(err));
+	check_getprop_addrrange(fdt, 0, offset, "reg", 1);
+
+	PASS();
+}
diff --git a/tests/asm_tree_dump.c b/tests/asm_tree_dump.c
index bd12eda..8236172 100644
--- a/tests/asm_tree_dump.c
+++ b/tests/asm_tree_dump.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Tests if an asm tree built into a shared object matches a given dtb
  * Copyright (C) 2008 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
diff --git a/tests/bad-chosen.dts b/tests/bad-chosen.dts
new file mode 100644
index 0000000..d6f53c6
--- /dev/null
+++ b/tests/bad-chosen.dts
@@ -0,0 +1,10 @@
+/dts-v1/;
+
+/ {
+	node2 {
+		chosen {
+			bootargs = <0xdeadbeef>;
+			stdout-path = <1>;
+		};
+	};
+};
diff --git a/tests/bad-dma-ranges.dts b/tests/bad-dma-ranges.dts
new file mode 100644
index 0000000..fbe7ab8
--- /dev/null
+++ b/tests/bad-dma-ranges.dts
@@ -0,0 +1,12 @@
+/dts-v1/;
+
+/ {
+	#address-cells = <2>;
+	#size-cells = <2>;
+	node {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		dma-ranges = <0 0 0 0 0>;
+	};
+};
diff --git a/tests/bad-gpio.dts b/tests/bad-gpio.dts
new file mode 100644
index 0000000..6b77be4
--- /dev/null
+++ b/tests/bad-gpio.dts
@@ -0,0 +1,13 @@
+/dts-v1/;
+
+/ {
+	gpio: gpio-controller {
+		#gpio-cells = <3>;
+	};
+
+	node {
+		nr-gpios = <1>;
+		foo-gpios = <&gpio>;
+		bar-gpio = <&gpio 1 2 3>;
+	};
+};
diff --git a/tests/bad-graph.dts b/tests/bad-graph.dts
new file mode 100644
index 0000000..522da0e
--- /dev/null
+++ b/tests/bad-graph.dts
@@ -0,0 +1,24 @@
+/dts-v1/;
+
+/ {
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		bad_endpoint: port-a@0 {
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			endpoint@d0 {
+				reg = <0>;
+				remote-endpoint = <0xdeadbeef>;
+			};
+
+		};
+
+		port@1 {
+			reg = <0>;
+		};
+	};
+};
diff --git a/tests/bad-interrupt-cells.dts b/tests/bad-interrupt-cells.dts
new file mode 100644
index 0000000..39fc78f
--- /dev/null
+++ b/tests/bad-interrupt-cells.dts
@@ -0,0 +1,12 @@
+/dts-v1/;
+
+/ {
+	interrupt-parent = <&intc>;
+	intc: interrupt-controller {
+		#interrupt-cells = <3>;
+	};
+
+	node {
+		interrupts = <1>;
+	};
+};
diff --git a/tests/bad-interrupt-controller.dts b/tests/bad-interrupt-controller.dts
new file mode 100644
index 0000000..62fa118
--- /dev/null
+++ b/tests/bad-interrupt-controller.dts
@@ -0,0 +1,7 @@
+/dts-v1/;
+
+/ {
+	intc: interrupt-controller {
+		interrupt-controller;
+	};
+};
diff --git a/tests/bad-phandle-cells.dts b/tests/bad-phandle-cells.dts
new file mode 100644
index 0000000..7f7c6a2
--- /dev/null
+++ b/tests/bad-phandle-cells.dts
@@ -0,0 +1,11 @@
+/dts-v1/;
+
+/ {
+	intc: interrupt-controller {
+		#interrupt-cells = <3>;
+	};
+
+	node {
+		interrupts-extended = <&intc>;
+	};
+};
diff --git a/tests/bad-string-props.dts b/tests/bad-string-props.dts
index 396f820..6694704 100644
--- a/tests/bad-string-props.dts
+++ b/tests/bad-string-props.dts
@@ -4,4 +4,11 @@
 	device_type = <0xdeadbeef>;
 	model = <0xdeadbeef>;
 	status = <0xdeadbeef>;
+	label = <0xdeadbeef>;
+
+	foobar-names = "foo", <1>;
+
+	node {
+		compatible = "good", <0xdeadbeef>;
+	};
 };
diff --git a/tests/boot-cpuid.c b/tests/boot-cpuid.c
index ca39f4b..5ed4f9a 100644
--- a/tests/boot-cpuid.c
+++ b/tests/boot-cpuid.c
@@ -1,19 +1,6 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * Copyright (C) 2008 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
diff --git a/tests/char_literal.c b/tests/char_literal.c
index da1f964..3a69e28 100644
--- a/tests/char_literal.c
+++ b/tests/char_literal.c
@@ -1,22 +1,9 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for character literals in dtc
  * Copyright (C) 2006 David Gibson, IBM Corporation.
  * Copyright (C) 2011 The Chromium Authors. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 #include <stdlib.h>
 #include <stdio.h>
diff --git a/tests/check_full.c b/tests/check_full.c
new file mode 100644
index 0000000..b6d5fc3
--- /dev/null
+++ b/tests/check_full.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ * libfdt - Flat Device Tree manipulation
+ *	Tests if two given dtbs are structurally equal (including order)
+ * Copyright (C) 2007 David Gibson, IBM Corporation.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+static int expect_bad; /* = 0 */
+
+int main(int argc, char *argv[])
+{
+	const char *filename;
+	char *fdt;
+	size_t len;
+	int err;
+
+	test_init(argc, argv);
+	if ((argc != 2)
+	    && ((argc != 3) || !streq(argv[1], "-n")))
+		CONFIG("Usage: %s [-n] <dtb file>", argv[0]);
+	if (argc == 3)
+		expect_bad = 1;
+
+	filename = argv[argc-1];
+	err = utilfdt_read_err(filename, &fdt, &len);
+	if (err)
+		CONFIG("Couldn't open blob from \"%s\": %s",
+		       filename, strerror(err));
+
+	vg_prepare_blob(fdt, len);
+
+	err = fdt_check_full(fdt, len);
+
+	if (expect_bad && (err == 0))
+		FAIL("fdt_check_full() succeeded unexpectedly");
+	else if (!expect_bad && (err != 0))
+		FAIL("fdt_check_full() failed: %s", fdt_strerror(err));
+
+	PASS();
+}
diff --git a/tests/check_header.c b/tests/check_header.c
new file mode 100644
index 0000000..ca26ec1
--- /dev/null
+++ b/tests/check_header.c
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ * libfdt - Flat Device Tree manipulation
+ *	Testcase for fdt_check_header
+ * Copyright (C) 2018 David Gibson
+ */
+
+#include <stdio.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+
+static void *dtdup(void *dt)
+{
+	size_t bufsize = fdt_totalsize(dt);
+	void *buf = xmalloc(bufsize);
+	fdt_move(dt, buf, bufsize);
+	return buf;
+}
+
+#define CHECK_MANGLE(exerr, code)					\
+	do {								\
+		void *fdt = dtdup(template);				\
+		{ code }						\
+		err = fdt_check_header(fdt);				\
+		verbose_printf("\"%s\" => %s\n", #code, fdt_strerror(err)); \
+		if (err != (exerr))					\
+			FAIL("fdt_check_header() didn't catch mangle %s", \
+			     #code);					\
+		free(fdt);						\
+	} while (0)
+
+int main(int argc, char *argv[])
+{
+	void *template;
+	int err;
+
+	test_init(argc, argv);
+	template = load_blob(argv[1]);
+
+	/* Check that the base dt is valid before mangling it */
+	err = fdt_check_header(template);
+	if (err != 0)
+		FAIL("Base tree fails: %s", fdt_strerror(err));
+
+	/* Check a no-op mangle doesn't break things */
+	CHECK_MANGLE(0, ; );
+
+	/* Mess up the magic number */
+	CHECK_MANGLE(-FDT_ERR_BADMAGIC,
+		fdt_set_magic(fdt, fdt_magic(fdt) ^ 0x1);
+	);
+	CHECK_MANGLE(-FDT_ERR_BADMAGIC,
+		fdt_set_magic(fdt, fdt_magic(fdt) ^ 0x80000000);
+	);
+
+	/* Mess up the version */
+	CHECK_MANGLE(-FDT_ERR_BADVERSION,
+		fdt_set_version(fdt, FDT_FIRST_SUPPORTED_VERSION - 1);
+		fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION - 1);
+	);
+	CHECK_MANGLE(-FDT_ERR_BADVERSION,
+		fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION + 1);
+		fdt_set_last_comp_version(fdt, FDT_LAST_SUPPORTED_VERSION + 1);
+	);
+	CHECK_MANGLE(-FDT_ERR_BADVERSION,
+		fdt_set_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
+		fdt_set_last_comp_version(fdt, FDT_LAST_SUPPORTED_VERSION);
+	);
+
+	/* Out of bounds sizes */
+	CHECK_MANGLE(-FDT_ERR_TRUNCATED,
+		fdt_set_totalsize(fdt, FDT_V1_SIZE - 1);
+	);
+	CHECK_MANGLE(-FDT_ERR_TRUNCATED,
+		     fdt_set_totalsize(fdt, (uint32_t)INT_MAX + 1);
+	);
+
+	/* Truncate within various blocks */
+	CHECK_MANGLE(-FDT_ERR_TRUNCATED,
+		fdt_set_totalsize(fdt, fdt_off_dt_struct(fdt) - 1);
+	);
+	CHECK_MANGLE(-FDT_ERR_TRUNCATED,
+		fdt_set_totalsize(fdt, fdt_off_dt_strings(fdt) - 1);
+	);
+	CHECK_MANGLE(-FDT_ERR_TRUNCATED,
+		fdt_set_totalsize(fdt, fdt_off_mem_rsvmap(fdt) - 1);
+	);
+	CHECK_MANGLE(-FDT_ERR_TRUNCATED,
+		fdt_set_totalsize(fdt, fdt_off_dt_struct(fdt) + 1);
+	);
+	CHECK_MANGLE(-FDT_ERR_TRUNCATED,
+		fdt_set_totalsize(fdt, fdt_off_dt_strings(fdt) + 1);
+	);
+	CHECK_MANGLE(-FDT_ERR_TRUNCATED,
+		fdt_set_totalsize(fdt, fdt_off_mem_rsvmap(fdt) + 1);
+	);
+
+	/* Negative block sizes */
+	CHECK_MANGLE(-FDT_ERR_TRUNCATED,
+		fdt_set_size_dt_struct(fdt, (uint32_t)-1);
+	);
+	CHECK_MANGLE(-FDT_ERR_TRUNCATED,
+		fdt_set_size_dt_strings(fdt, (uint32_t)-1);
+	);
+	CHECK_MANGLE(-FDT_ERR_TRUNCATED,
+		     fdt_set_size_dt_struct(fdt, (uint32_t)INT_MIN);
+	);
+	CHECK_MANGLE(-FDT_ERR_TRUNCATED,
+		fdt_set_size_dt_strings(fdt, (uint32_t)INT_MIN);
+	);
+
+	PASS();
+}
diff --git a/tests/check_path.c b/tests/check_path.c
index f12f950..cc9757a 100644
--- a/tests/check_path.c
+++ b/tests/check_path.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for node existence
  * Copyright (C) 2016 Konsulko Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdio.h>
diff --git a/tests/del_node.c b/tests/del_node.c
index 45cb060..10846df 100644
--- a/tests/del_node.c
+++ b/tests/del_node.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_nop_node()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
diff --git a/tests/del_property.c b/tests/del_property.c
index 42fd7cb..37e8303 100644
--- a/tests/del_property.c
+++ b/tests/del_property.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_delprop()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
diff --git a/tests/dtb_reverse.c b/tests/dtb_reverse.c
index 527fd71..95b6c1c 100644
--- a/tests/dtb_reverse.c
+++ b/tests/dtb_reverse.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Tests if two given dtbs are structurally equal (including order)
  * Copyright (C) 2010 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
diff --git a/tests/dtbs_equal_ordered.c b/tests/dtbs_equal_ordered.c
index 98bf0e7..90c7344 100644
--- a/tests/dtbs_equal_ordered.c
+++ b/tests/dtbs_equal_ordered.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Tests if two given dtbs are structurally equal (including order)
  * Copyright (C) 2007 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
diff --git a/tests/dtbs_equal_unordered.c b/tests/dtbs_equal_unordered.c
index baf2ae7..e5ff9e8 100644
--- a/tests/dtbs_equal_unordered.c
+++ b/tests/dtbs_equal_unordered.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Tests if two given dtbs are structurally equal (including order)
  * Copyright (C) 2007 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
@@ -30,6 +17,7 @@
 #include "testdata.h"
 
 static int notequal; /* = 0 */
+static int ignore_memrsv; /* = 0 */
 
 #define MISMATCH(fmt, ...)			\
 	do { \
@@ -195,22 +183,41 @@
 	compare_subnodes(fdt2, offset2, fdt1, offset1, 0);
 }
 
+static void badargs(char **argv)
+{
+	CONFIG("Usage: %s [-n] [-m] <dtb file> <dtb file>", argv[0]);
+}
+
 int main(int argc, char *argv[])
 {
 	void *fdt1, *fdt2;
 	uint32_t cpuid1, cpuid2;
+	char **args;
+	int argsleft;
 
 	test_init(argc, argv);
-	if ((argc != 3)
-	    && ((argc != 4) || !streq(argv[1], "-n")))
-		CONFIG("Usage: %s [-n] <dtb file> <dtb file>", argv[0]);
-	if (argc == 4)
-		notequal = 1;
 
-	fdt1 = load_blob(argv[argc-2]);
-	fdt2 = load_blob(argv[argc-1]);
+	args = &argv[1];
+	argsleft = argc - 1;
 
-	compare_mem_rsv(fdt1, fdt2);
+	while (argsleft > 2) {
+		if (streq(args[0], "-n"))
+			notequal = 1;
+		else if (streq(args[0], "-m"))
+			ignore_memrsv = 1;
+		else
+			badargs(argv);
+		args++;
+		argsleft--;
+	}
+	if (argsleft != 2)
+		badargs(argv);
+
+	fdt1 = load_blob(args[0]);
+	fdt2 = load_blob(args[1]);
+
+	if (!ignore_memrsv)
+		compare_mem_rsv(fdt1, fdt2);
 	compare_node(fdt1, 0, fdt2, 0);
 
 	cpuid1 = fdt_boot_cpuid_phys(fdt1);
diff --git a/tests/dtc-checkfails.sh b/tests/dtc-checkfails.sh
index 76ded15..4fd9691 100755
--- a/tests/dtc-checkfails.sh
+++ b/tests/dtc-checkfails.sh
@@ -1,6 +1,7 @@
 #! /bin/sh
 
-. ./tests.sh
+SRCDIR=`dirname "$0"`
+. "$SRCDIR/testutils.sh"
 
 for x; do
     shift
@@ -30,13 +31,13 @@
 FAIL_IF_SIGNAL $ret
 
 for c in $YESCHECKS; do
-    if ! grep -E "^(ERROR)|(Warning) \($c\):" $LOG > /dev/null; then
+    if ! grep -E "(ERROR|Warning) \($c\):" $LOG > /dev/null; then
 	FAIL "Failed to trigger check \"$c\""
     fi
 done
 
 for c in $NOCHECKS; do
-    if grep -E "^(ERROR)|(Warning) \($c\):" $LOG > /dev/null; then
+    if grep -E "(ERROR|Warning) \($c\):" $LOG > /dev/null; then
 	FAIL "Incorrectly triggered check \"$c\""
     fi
 done
diff --git a/tests/dtc-fails.sh b/tests/dtc-fails.sh
index 4ddcb27..855b623 100755
--- a/tests/dtc-fails.sh
+++ b/tests/dtc-fails.sh
@@ -1,6 +1,7 @@
 #! /bin/sh
 
-. ./tests.sh
+SRCDIR=`dirname "$0"`
+. "$SRCDIR/testutils.sh"
 
 if [ "$1" = "-n" ]; then
     NEG="$1"
diff --git a/tests/dtc-fatal.sh b/tests/dtc-fatal.sh
old mode 100644
new mode 100755
index 6781ced..08a4d29
--- a/tests/dtc-fatal.sh
+++ b/tests/dtc-fatal.sh
@@ -1,6 +1,7 @@
 #! /bin/sh
 
-. ./tests.sh
+SRCDIR=`dirname "$0"`
+. "$SRCDIR/testutils.sh"
 
 verbose_run $VALGRIND "$DTC" -o/dev/null "$@"
 ret="$?"
diff --git a/tests/dumptrees.c b/tests/dumptrees.c
index 0728811..aecb326 100644
--- a/tests/dumptrees.c
+++ b/tests/dumptrees.c
@@ -1,23 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * dumptrees - utility for libfdt testing
  *
  * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2006.
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
- *                                                                   USA
  */
 #include <stdio.h>
 #include <stdlib.h>
@@ -33,10 +18,12 @@
 	void *blob;
 	const char *filename;
 } trees[] = {
-#define TREE(name)	{ &_##name, #name ".dtb" }
+#define TREE(name)	{ &name, #name ".dtb" }
 	TREE(test_tree1),
 	TREE(bad_node_char), TREE(bad_node_format), TREE(bad_prop_char),
 	TREE(ovf_size_strings),
+	TREE(truncated_property), TREE(truncated_string),
+	TREE(truncated_memrsv),
 };
 
 #define NUM_TREES	(sizeof(trees) / sizeof(trees[0]))
@@ -45,6 +32,16 @@
 {
 	int i;
 
+	if (argc != 2) {
+	    fprintf(stderr, "Missing output directory argument\n");
+	    return 1;
+	}
+
+	if (chdir(argv[1]) != 0) {
+	    perror("chdir()");
+	    return 1;
+	}
+
 	for (i = 0; i < NUM_TREES; i++) {
 		void *blob = trees[i].blob;
 		const char *filename = trees[i].filename;
diff --git a/tests/extra-terminating-null.c b/tests/extra-terminating-null.c
index dc1fe89..0fa2ca8 100644
--- a/tests/extra-terminating-null.c
+++ b/tests/extra-terminating-null.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for properties with more than one terminating null
  * Copyright (C) 2009 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 #include <stdlib.h>
 #include <stdio.h>
diff --git a/tests/fdtdump-runtest.sh b/tests/fdtdump-runtest.sh
old mode 100644
new mode 100755
index 77593cf..71ac861
--- a/tests/fdtdump-runtest.sh
+++ b/tests/fdtdump-runtest.sh
@@ -4,7 +4,8 @@
 #   $1 - source file to compile and compare with fdtdump output of the
 #	  compiled file.
 
-. ./tests.sh
+SRCDIR=`dirname "$0"`
+. "$SRCDIR/testutils.sh"
 
 dts="$1"
 dtb="${dts}.dtb"
diff --git a/tests/fdtget-runtest.sh b/tests/fdtget-runtest.sh
index 8d8b058..18b7404 100755
--- a/tests/fdtget-runtest.sh
+++ b/tests/fdtget-runtest.sh
@@ -1,6 +1,7 @@
 #! /bin/sh
 
-. ./tests.sh
+SRCDIR=`dirname "$0"`
+. "$SRCDIR/testutils.sh"
 
 LOG=tmp.log.$$
 EXPECT=tmp.expect.$$
diff --git a/tests/fdtoverlay-runtest.sh b/tests/fdtoverlay-runtest.sh
old mode 100644
new mode 100755
index 06c1169..0c648f4
--- a/tests/fdtoverlay-runtest.sh
+++ b/tests/fdtoverlay-runtest.sh
@@ -1,12 +1,13 @@
 #! /bin/sh
 
 # Run script for fdtoverlay tests
-# We run fdtoverlay to generate a target device tree, thn fdtget to check it
+# We run fdtoverlay to generate a target device tree, then fdtget to check it
 
 # Usage
 #    fdtoverlay-runtest.sh name expected_output dtb_file node property flags value
 
-. ./tests.sh
+SRCDIR=`dirname "$0"`
+. "$SRCDIR/testutils.sh"
 
 LOG=tmp.log.$$
 EXPECT=tmp.expect.$$
diff --git a/tests/fdtput-runtest.sh b/tests/fdtput-runtest.sh
old mode 100644
new mode 100755
index 527a968..1210eab
--- a/tests/fdtput-runtest.sh
+++ b/tests/fdtput-runtest.sh
@@ -1,12 +1,13 @@
 #! /bin/sh
 
 # Run script for fdtput tests
-# We run fdtput to update the device tree, thn fdtget to check it
+# We run fdtput to update the device tree, then fdtget to check it
 
 # Usage
 #    fdtput-runtest.sh name expected_output dtb_file node property flags value
 
-. ./tests.sh
+SRCDIR=`dirname "$0"`
+. "$SRCDIR/testutils.sh"
 
 LOG=tmp.log.$$
 EXPECT=tmp.expect.$$
diff --git a/tests/find_property.c b/tests/find_property.c
index 4dc3030..0404ea0 100644
--- a/tests/find_property.c
+++ b/tests/find_property.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_property_offset()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 #include <stdlib.h>
 #include <stdio.h>
diff --git a/tests/fs_tree1.c b/tests/fs_tree1.c
new file mode 100644
index 0000000..dff3880
--- /dev/null
+++ b/tests/fs_tree1.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ * libfdt - Flat Device Tree manipulation
+ *	Testcase/tool constructing an fs tree for further test
+ * Copyright (C) 2018 David Gibson, Red Hat Inc.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+static void start_dir(const char *name)
+{
+	int rc;
+
+	rc = mkdir(name, 0777);
+	if (rc != 0)
+		FAIL("mkdir(\"%s\"): %s", name, strerror(errno));
+
+	rc = chdir(name);
+	if (rc != 0)
+		FAIL("chdir(\"%s\"): %s", name, strerror(errno));
+}
+
+static void end_dir(void)
+{
+	int rc;
+
+	rc = chdir("..");
+	if (rc != 0)
+		FAIL("chdir(..): %s", strerror(errno));
+}
+	
+static void mkfile(const char *name, void *data, size_t len)
+{
+	int fd;
+	int rc;
+
+	fd = open(name, O_WRONLY|O_CREAT, 0666);
+	if (fd < 0)
+		FAIL("open(\"%s\"): %s", name, strerror(errno));
+
+	rc = write(fd, data, len);
+	if (rc < 0)
+		FAIL("write(\"%s\"): %s", name, strerror(errno));
+	if (rc != len)
+		FAIL("write(\"%s\"): short write", name);
+	
+	rc = close(fd);
+	if (rc != 0)
+		FAIL("close(\"%s\"): %s", name, strerror(errno));
+}
+
+#define mkfile_str(name, s)			  \
+	do {					  \
+		char str[] = s;			  \
+		mkfile((name), str, sizeof(str)); \
+	} while (0)
+
+static void mkfile_u32(const char *name, uint32_t val)
+{
+	val = cpu_to_fdt32(val);
+	mkfile(name, &val, sizeof(val));
+}
+
+static void mkfile_u64(const char *name, uint64_t val)
+{
+	val = cpu_to_fdt64(val);
+	mkfile(name, &val, sizeof(val));
+}
+
+int main(int argc, char *argv[])
+{
+	const char *base;
+
+	test_init(argc, argv);
+	if (argc != 2)
+		CONFIG("Usage: %s <path>", argv[0]);
+
+	base = argv[1];
+
+	start_dir(base);
+	mkfile_str("compatible", "test_tree1");
+	mkfile_u32("prop-int", TEST_VALUE_1);
+	mkfile_u64("prop-int64", 0xdeadbeef01abcdefULL);
+	mkfile_str("prop-str", "hello world");
+	mkfile_u32("#address-cells", 1);
+	mkfile_u32("#size-cells", 0);
+
+	{
+		start_dir("subnode@1");
+
+		mkfile_str("compatible", "subnode1");
+		mkfile_u32("reg", 1);
+		mkfile_u32("prop-int", TEST_VALUE_1);
+
+		{
+			start_dir("subsubnode");
+
+			mkfile_str("compatible", "subsubnode1\0subsubnode");
+			mkfile_str("placeholder", "this is a placeholder string\0string2");
+			mkfile_u32("prop-int", TEST_VALUE_1);
+			
+			end_dir();
+		}
+
+		{
+			start_dir("ss1");
+			end_dir();
+		}
+		
+		end_dir();
+	}
+
+	{
+		start_dir("subnode@2");
+
+		mkfile_u32("reg", 2);
+		mkfile_u32("linux,phandle", 0x2000);
+		mkfile_u32("prop-int", TEST_VALUE_2);
+		mkfile_u32("#address-cells", 1);
+		mkfile_u32("#size-cells", 0);
+
+		{
+			start_dir("subsubnode@0");
+
+			mkfile_u32("reg", 0);
+			mkfile_u32("phandle", 0x2001);
+			mkfile_str("compatible", "subsubnode2\0subsubnode");
+			mkfile_u32("prop-int", TEST_VALUE_2);
+			
+			end_dir();
+		}
+
+		{
+			start_dir("ss2");
+			end_dir();
+		}
+		
+		end_dir();
+	}
+
+	PASS();
+}
diff --git a/tests/get_alias.c b/tests/get_alias.c
index 5060795..fb2c38c 100644
--- a/tests/get_alias.c
+++ b/tests/get_alias.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_get_alias()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
diff --git a/tests/get_mem_rsv.c b/tests/get_mem_rsv.c
index 1812639..f977d19 100644
--- a/tests/get_mem_rsv.c
+++ b/tests/get_mem_rsv.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_get_mem_rsv() and fdt_num_mem_rsv()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
diff --git a/tests/get_name.c b/tests/get_name.c
index c6ca9f9..5a35103 100644
--- a/tests/get_name.c
+++ b/tests/get_name.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_get_name()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 #include <stdlib.h>
 #include <stdio.h>
diff --git a/tests/get_path.c b/tests/get_path.c
index 7352976..7349898 100644
--- a/tests/get_path.c
+++ b/tests/get_path.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_get_path()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 #include <stdlib.h>
 #include <stdio.h>
@@ -42,7 +29,8 @@
 	memset(buf, POISON, sizeof(buf)); /* poison the buffer */
 
 	len = fdt_get_path(fdt, offset, buf, buflen);
-	verbose_printf("get_path() %s -> %d -> %s\n", path, offset, buf);
+	verbose_printf("get_path() %s -> %d -> %s\n", path, offset,
+		       len >= 0 ? buf : "<error>");
 
 	if (buflen <= pathlen) {
 		if (len != -FDT_ERR_NOSPACE)
diff --git a/tests/get_phandle.c b/tests/get_phandle.c
index 22bd7b8..157b522 100644
--- a/tests/get_phandle.c
+++ b/tests/get_phandle.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_get_phandle()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
+#include <stdbool.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -42,10 +30,32 @@
 		     path, phandle, checkhandle);
 }
 
+static void check_phandle_unique(const void *fdt, uint32_t checkhandle)
+{
+	uint32_t phandle;
+	int offset = -1;
+
+	while (true) {
+		offset = fdt_next_node(fdt, offset, NULL);
+		if (offset < 0) {
+			if (offset == -FDT_ERR_NOTFOUND)
+				break;
+
+			FAIL("error looking for phandle %#x", checkhandle);
+		}
+
+		phandle = fdt_get_phandle(fdt, offset);
+
+		if (phandle == checkhandle)
+			FAIL("generated phandle already exists");
+	}
+}
+
 int main(int argc, char *argv[])
 {
-	uint32_t max;
+	uint32_t max, phandle;
 	void *fdt;
+	int err;
 
 	test_init(argc, argv);
 	fdt = load_blob_arg(argc, argv);
@@ -54,10 +64,24 @@
 	check_phandle(fdt, "/subnode@2", PHANDLE_1);
 	check_phandle(fdt, "/subnode@2/subsubnode@0", PHANDLE_2);
 
+	err = fdt_find_max_phandle(fdt, &max);
+	if (err < 0)
+		FAIL("fdt_find_max_phandle returned %d instead of 0\n", err);
+
+	if (max != PHANDLE_2)
+		FAIL("fdt_find_max_phandle found 0x%x instead of 0x%x", max,
+		     PHANDLE_2);
+
 	max = fdt_get_max_phandle(fdt);
 	if (max != PHANDLE_2)
 		FAIL("fdt_get_max_phandle returned 0x%x instead of 0x%x\n",
 		     max, PHANDLE_2);
 
+	err = fdt_generate_phandle(fdt, &phandle);
+	if (err < 0)
+		FAIL("failed to generate phandle: %d", err);
+
+	check_phandle_unique(fdt, phandle);
+
 	PASS();
 }
diff --git a/tests/get_prop_offset.c b/tests/get_prop_offset.c
new file mode 100644
index 0000000..cff3c18
--- /dev/null
+++ b/tests/get_prop_offset.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ * libfdt - Flat Device Tree manipulation
+ *	Testcase for fdt_getprop_by_offset()
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+int main(int argc, char *argv[])
+{
+	bool found_prop_int = false;
+	bool found_prop_str = false;
+	int poffset;
+	void *fdt;
+
+	test_init(argc, argv);
+	fdt = load_blob_arg(argc, argv);
+
+	fdt_for_each_property_offset(poffset, fdt, 0) {
+		if (check_get_prop_offset_cell(fdt, poffset, "prop-int",
+					       TEST_VALUE_1))
+			found_prop_int = true;
+		if (check_get_prop_offset(fdt, poffset, "prop-str",
+					  strlen(TEST_STRING_1) + 1,
+					  TEST_STRING_1))
+			found_prop_str = true;
+	}
+	if (!found_prop_int)
+		FAIL("Property 'prop-int' not found");
+	if (!found_prop_str)
+		FAIL("Property 'prop-str' not found");
+
+	PASS();
+}
diff --git a/tests/getprop.c b/tests/getprop.c
index 6255bad..cccc8e2 100644
--- a/tests/getprop.c
+++ b/tests/getprop.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_getprop()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
diff --git a/tests/incbin.c b/tests/incbin.c
index 4100ba0..36ff669 100644
--- a/tests/incbin.c
+++ b/tests/incbin.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for string escapes in dtc
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 #include <stdlib.h>
 #include <stdio.h>
@@ -65,8 +52,11 @@
 
 	test_init(argc, argv);
 
-	incbin = load_file("incbin.bin", &len);
-	fdt = load_blob_arg(argc, argv);
+	if (argc != 3)
+		CONFIG("Usage: %s <incbin file> <dtb file>", argv[0]);
+
+	incbin = load_file(argv[1], &len);
+	fdt = load_blob(argv[2]);
 
 	check_getprop(fdt, 0, "incbin", len, incbin);
 	check_getprop(fdt, 0, "incbin-partial", 17, incbin + 13);
diff --git a/tests/integer-expressions.c b/tests/integer-expressions.c
index ed1f967..6f33d81 100644
--- a/tests/integer-expressions.c
+++ b/tests/integer-expressions.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * Testcase for dtc expression support
  *
  * Copyright (C) 2008 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
@@ -97,7 +84,7 @@
 		res = fdt_getprop(fdt, 0, "expressions", &reslen);
 
 		if (!res)
-			FAIL("Error retreiving expression results: %s\n",
+			FAIL("Error retrieving expression results: %s\n",
 		     fdt_strerror(reslen));
 
 		if (reslen != (ARRAY_SIZE(expr_table) * sizeof(uint32_t)))
diff --git a/tests/mangle-layout.c b/tests/mangle-layout.c
index a76e51e..59b1604 100644
--- a/tests/mangle-layout.c
+++ b/tests/mangle-layout.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase/tool for rearranging blocks of a dtb
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
@@ -44,13 +31,9 @@
 
 static void new_header(struct bufstate *buf, int version, const void *fdt)
 {
-	int hdrsize;
+	int hdrsize = fdt_header_size_(version);
 
-	if (version == 16)
-		hdrsize = FDT_V16_SIZE;
-	else if (version == 17)
-		hdrsize = FDT_V17_SIZE;
-	else
+	if ((version != 16) && (version != 17))
 		CONFIG("Bad version %d", version);
 
 	expand_buf(buf, hdrsize);
diff --git a/tests/mangle-layout.supp b/tests/mangle-layout.supp
deleted file mode 100644
index 2890420..0000000
--- a/tests/mangle-layout.supp
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-   uninitialized alignment gaps can be dumped to output
-   Memcheck:Param
-   write(buf)
-   obj:/lib/ld-*.so
-   fun:main
-}
diff --git a/tests/move_and_save.c b/tests/move_and_save.c
index 393b60a..a89f8de 100644
--- a/tests/move_and_save.c
+++ b/tests/move_and_save.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Basic testcase for read-only access
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
diff --git a/tests/multilabel.dts b/tests/multilabel.dts
index 77da06c..d80ebe1 100644
--- a/tests/multilabel.dts
+++ b/tests/multilabel.dts
@@ -41,4 +41,9 @@
 		n2 = &n2;
 		n3 = &n3;
 	};
+
+	node6 {
+		linux,phandle = <0xfffffffe>;
+		phandle = <0xfffffffe>;
+	};
 };
diff --git a/tests/multilabel_merge.dts b/tests/multilabel_merge.dts
index 3e80298..a27d856 100644
--- a/tests/multilabel_merge.dts
+++ b/tests/multilabel_merge.dts
@@ -39,6 +39,11 @@
 		n2 = &n2;
 		n3 = &n3;
 	};
+
+	node6 {
+		linux,phandle = <0xfffffffe>;
+		phandle = <0xfffffffe>;
+	};
 };
 
 / {
diff --git a/tests/node_check_compatible.c b/tests/node_check_compatible.c
index 4bdf091..81efe62 100644
--- a/tests/node_check_compatible.c
+++ b/tests/node_check_compatible.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_node_check_compatible()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
@@ -45,6 +32,23 @@
 		FAIL("%s is not compatible with \"%s\"", path, compat);
 }
 
+static void check_not_compatible(const void *fdt, const char *path,
+				 const char *compat)
+{
+	int offset, err;
+
+	offset = fdt_path_offset(fdt, path);
+	if (offset < 0)
+		FAIL("fdt_path_offset(%s): %s", path, fdt_strerror(offset));
+
+	err = fdt_node_check_compatible(fdt, offset, compat);
+	if (err < 0)
+		FAIL("fdt_node_check_compatible(%s): %s", path,
+		     fdt_strerror(err));
+	if (err == 0)
+		FAIL("%s is incorrectly compatible with \"%s\"", path, compat);
+}
+
 int main(int argc, char *argv[])
 {
 	void *fdt;
@@ -55,8 +59,10 @@
 	check_compatible(fdt, "/", "test_tree1");
 	check_compatible(fdt, "/subnode@1/subsubnode", "subsubnode1");
 	check_compatible(fdt, "/subnode@1/subsubnode", "subsubnode");
+	check_not_compatible(fdt, "/subnode@1/subsubnode", "subsubnode2");
 	check_compatible(fdt, "/subnode@2/subsubnode", "subsubnode2");
 	check_compatible(fdt, "/subnode@2/subsubnode", "subsubnode");
+	check_not_compatible(fdt, "/subnode@2/subsubnode", "subsubnode1");
 
 	PASS();
 }
diff --git a/tests/node_offset_by_compatible.c b/tests/node_offset_by_compatible.c
index f62b591..a9e6783 100644
--- a/tests/node_offset_by_compatible.c
+++ b/tests/node_offset_by_compatible.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_node_offset_by_compatible()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 #include <stdlib.h>
 #include <stdio.h>
diff --git a/tests/node_offset_by_phandle.c b/tests/node_offset_by_phandle.c
index becff0f..60af78a 100644
--- a/tests/node_offset_by_phandle.c
+++ b/tests/node_offset_by_phandle.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_node_offset_by_phandle()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 #include <stdlib.h>
 #include <stdio.h>
diff --git a/tests/node_offset_by_prop_value.c b/tests/node_offset_by_prop_value.c
index 286f1e7..48ab1d9 100644
--- a/tests/node_offset_by_prop_value.c
+++ b/tests/node_offset_by_prop_value.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_path_offset()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 #include <stdlib.h>
 #include <stdio.h>
diff --git a/tests/nop_node.c b/tests/nop_node.c
index c316444..ee972d2 100644
--- a/tests/nop_node.c
+++ b/tests/nop_node.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_nop_node()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
diff --git a/tests/nop_property.c b/tests/nop_property.c
index 644b0a6..6593828 100644
--- a/tests/nop_property.c
+++ b/tests/nop_property.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_nop_property()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
diff --git a/tests/nopulate.c b/tests/nopulate.c
index 94ce8ad..2ae1753 100644
--- a/tests/nopulate.c
+++ b/tests/nopulate.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase/tool for rearranging blocks of a dtb
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
diff --git a/tests/notfound.c b/tests/notfound.c
index dc623d6..70acbcd 100644
--- a/tests/notfound.c
+++ b/tests/notfound.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for behaviour on searching for a non-existent node
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 #include <stdlib.h>
 #include <stdio.h>
diff --git a/tests/omit-no-ref.dts b/tests/omit-no-ref.dts
new file mode 100644
index 0000000..8ace232
--- /dev/null
+++ b/tests/omit-no-ref.dts
@@ -0,0 +1,26 @@
+/dts-v1/;
+
+/ {
+	test-phandle = <&node3>;
+	test-path = &node4;
+
+	/omit-if-no-ref/ node1: node1 {
+		bar = <0xdeadbeef>;
+	};
+
+	node2: node2 {
+		foo = <0x42>;
+	};
+
+	node3: node3 {
+		test = "test";
+	};
+
+	node4: node4 {
+		test;
+	};
+};
+
+/omit-if-no-ref/ &node2;
+/omit-if-no-ref/ &node3;
+/omit-if-no-ref/ &node4;
diff --git a/tests/open_pack.c b/tests/open_pack.c
index 407ef6c..6ed4df7 100644
--- a/tests/open_pack.c
+++ b/tests/open_pack.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Basic testcase for read-only access
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
diff --git a/tests/open_pack.supp b/tests/open_pack.supp
deleted file mode 100644
index c954fe7..0000000
--- a/tests/open_pack.supp
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-   opened blob dumps uninitialized data
-   Memcheck:Param
-   write(buf)
-   obj:/lib/ld-*.so
-   fun:main
-}
diff --git a/tests/overlay.c b/tests/overlay.c
index 3093eec..91afa72 100644
--- a/tests/overlay.c
+++ b/tests/overlay.c
@@ -1,22 +1,9 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for DT overlays()
  * Copyright (C) 2016 Free Electrons
  * Copyright (C) 2016 NextThing Co.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdio.h>
diff --git a/tests/overlay_bad_fixup.c b/tests/overlay_bad_fixup.c
index 5014f5e..029bc79 100644
--- a/tests/overlay_bad_fixup.c
+++ b/tests/overlay_bad_fixup.c
@@ -1,22 +1,9 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for DT overlays()
  * Copyright (C) 2016 Free Electrons
  * Copyright (C) 2016 NextThing Co.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdio.h>
diff --git a/tests/overlay_base.dts b/tests/overlay_base.dts
index 2603adb..a5e55b2 100644
--- a/tests/overlay_base.dts
+++ b/tests/overlay_base.dts
@@ -14,6 +14,10 @@
 
 		subtest: sub-test-node {
 			sub-test-property;
+
+			subtest_with_long_path: sub-test-node-with-very-long-target-path {
+				long-test-path-property;
+			};
 		};
 	};
 };
diff --git a/tests/overlay_overlay.dts b/tests/overlay_overlay.dts
index b6d841b..c4ef1d4 100644
--- a/tests/overlay_overlay.dts
+++ b/tests/overlay_overlay.dts
@@ -9,78 +9,44 @@
 /dts-v1/;
 /plugin/;
 
-/ {
-	/* Test that we can change an int by another */
-	fragment@0 {
-		target = <&test>;
+/* Test that we can change an int by another */
+&test {
+	test-int-property = <43>;
+};
 
-		__overlay__ {
-			test-int-property = <43>;
-		};
+/* Test that we can replace a string by a longer one */
+&test {
+	test-str-property = "foobar";
+};
+
+/* Test that we add a new property */
+&test {
+	test-str-property-2 = "foobar2";
+};
+
+/* Test that we add a new node (by phandle) */
+&test {
+	new-node {
+		new-property;
 	};
+};
 
-	/* Test that we can replace a string by a longer one */
-	fragment@1 {
-		target = <&test>;
-
-		__overlay__ {
-			test-str-property = "foobar";
-		};
+&test {
+	local: new-local-node {
+		new-property;
 	};
+};
 
-	/* Test that we add a new property */
-	fragment@2 {
-		target = <&test>;
+&test {
+	test-phandle = <&test>, <&local>;
+};
 
-		__overlay__ {
-			test-str-property-2 = "foobar2";
-		};
-	};
+&test {
+	test-several-phandle = <&local>, <&local>;
+};
 
-	/* Test that we add a new node (by phandle) */
-	fragment@3 {
-		target = <&test>;
-
-		__overlay__ {
-			new-node {
-				new-property;
-			};
-		};
-	};
-
-	fragment@5 {
-		target = <&test>;
-
-		__overlay__ {
-			local: new-local-node {
-				new-property;
-			};
-		};
-	};
-
-	fragment@6 {
-		target = <&test>;
-
-		__overlay__ {
-			test-phandle = <&test>, <&local>;
-		};
-	};
-
-	fragment@7 {
-		target = <&test>;
-
-		__overlay__ {
-			test-several-phandle = <&local>, <&local>;
-		};
-	};
-
-	fragment@8 {
-		target = <&test>;
-
-		__overlay__ {
-			sub-test-node {
-				new-sub-test-property;
-			};
-		};
+&test {
+	sub-test-node {
+		new-sub-test-property;
 	};
 };
diff --git a/tests/overlay_overlay_bypath.dts b/tests/overlay_overlay_bypath.dts
new file mode 100644
index 0000000..f23e7b6
--- /dev/null
+++ b/tests/overlay_overlay_bypath.dts
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016 NextThing Co
+ * Copyright (c) 2016 Free Electrons
+ * Copyright (c) 2016 Konsulko Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/dts-v1/;
+/plugin/;
+
+/* Test that we can change an int by another */
+&{/test-node} {
+	test-int-property = <43>;
+};
+
+/* Test that we can replace a string by a longer one */
+&{/test-node} {
+	test-str-property = "foobar";
+};
+
+/* Test that we add a new property */
+&{/test-node} {
+	test-str-property-2 = "foobar2";
+};
+
+/* Test that we add a new node (by phandle) */
+&{/test-node} {
+	new-node {
+		new-property;
+	};
+};
+
+&{/} {
+	local: new-local-node {
+		new-property;
+	};
+};
+
+&{/} {
+	test-several-phandle = <&local>, <&local>;
+};
+
+&{/test-node} {
+	sub-test-node {
+		new-sub-test-property;
+	};
+};
diff --git a/tests/overlay_overlay_local_merge.dts b/tests/overlay_overlay_local_merge.dts
new file mode 100644
index 0000000..3ee622d
--- /dev/null
+++ b/tests/overlay_overlay_local_merge.dts
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2016 NextThing Co
+ * Copyright (c) 2016 Free Electrons
+ * Copyright (c) 2016 Konsulko Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/dts-v1/;
+/plugin/;
+
+&test {
+	parent: new-node {
+		parent-property;
+	};
+};
+
+&parent {
+	new-merged-property;
+	new-merged-node {
+		new-property;
+	};
+};
+
+&{/} {
+	new-root-node {
+		new-root-node-property;
+	};
+};
diff --git a/tests/overlay_overlay_long_path.dts b/tests/overlay_overlay_long_path.dts
new file mode 100644
index 0000000..4f0d40b
--- /dev/null
+++ b/tests/overlay_overlay_long_path.dts
@@ -0,0 +1,32 @@
+/dts-v1/;
+/plugin/;
+
+&subtest_with_long_path {
+	lpath_0: test-0 {
+		prop = "lpath";
+	};
+
+	lpath_1: test-1 {
+		prop = "lpath";
+	};
+
+	lpath_2: test-2 {
+		prop = "lpath";
+	};
+
+	lpath_3: test-3 {
+		prop = "lpath";
+	};
+
+	lpath_4: test-4 {
+		prop = "lpath";
+	};
+
+	lpath_5: test-5 {
+		prop = "lpath";
+	};
+
+	lpath_6: test-6 {
+		prop = "lpath";
+	};
+};
diff --git a/tests/overlay_overlay_manual_fixups.dts b/tests/overlay_overlay_manual_fixups.dts
index e34c4fc..a5715b6 100644
--- a/tests/overlay_overlay_manual_fixups.dts
+++ b/tests/overlay_overlay_manual_fixups.dts
@@ -50,7 +50,7 @@
 		};
 	};
 
-	fragment@5 {
+	fragment@4 {
 		target = <0xffffffff /*&test*/>;
 
 		__overlay__ {
@@ -60,7 +60,7 @@
 		};
 	};
 
-	fragment@6 {
+	fragment@5 {
 		target = <0xffffffff /*&test*/>;
 
 		__overlay__ {
@@ -68,7 +68,7 @@
 		};
 	};
 
-	fragment@7 {
+	fragment@6 {
 		target = <0xffffffff /*&test*/>;
 
 		__overlay__ {
@@ -76,7 +76,7 @@
 		};
 	};
 
-	fragment@8 {
+	fragment@7 {
 		target = <0xffffffff /*&test*/>;
 
 		__overlay__ {
@@ -86,27 +86,27 @@
 		};
 	};
 
-	__local_fixups__ {
-		fragment@6 {
-			__overlay__ {
-				test-phandle = <4>;
-			};
-		};
-		fragment@7 {
-			__overlay__ {
-				test-several-phandle = <0 4>;
-			};
-		};
-	};
 	__fixups__ {
 		test = "/fragment@0:target:0",
 		       "/fragment@1:target:0",
 		       "/fragment@2:target:0",
 		       "/fragment@3:target:0",
+		       "/fragment@4:target:0",
 		       "/fragment@5:target:0",
+		       "/fragment@5/__overlay__:test-phandle:0",
 		       "/fragment@6:target:0",
-		       "/fragment@6/__overlay__:test-phandle:0",
-		       "/fragment@7:target:0",
-		       "/fragment@8:target:0";
+		       "/fragment@7:target:0";
+	};
+	__local_fixups__ {
+		fragment@5 {
+			__overlay__ {
+				test-phandle = <4>;
+			};
+		};
+		fragment@6 {
+			__overlay__ {
+				test-several-phandle = <0 4>;
+			};
+		};
 	};
 };
diff --git a/tests/overlay_overlay_nosugar.dts b/tests/overlay_overlay_nosugar.dts
new file mode 100644
index 0000000..b6d841b
--- /dev/null
+++ b/tests/overlay_overlay_nosugar.dts
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2016 NextThing Co
+ * Copyright (c) 2016 Free Electrons
+ * Copyright (c) 2016 Konsulko Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	/* Test that we can change an int by another */
+	fragment@0 {
+		target = <&test>;
+
+		__overlay__ {
+			test-int-property = <43>;
+		};
+	};
+
+	/* Test that we can replace a string by a longer one */
+	fragment@1 {
+		target = <&test>;
+
+		__overlay__ {
+			test-str-property = "foobar";
+		};
+	};
+
+	/* Test that we add a new property */
+	fragment@2 {
+		target = <&test>;
+
+		__overlay__ {
+			test-str-property-2 = "foobar2";
+		};
+	};
+
+	/* Test that we add a new node (by phandle) */
+	fragment@3 {
+		target = <&test>;
+
+		__overlay__ {
+			new-node {
+				new-property;
+			};
+		};
+	};
+
+	fragment@5 {
+		target = <&test>;
+
+		__overlay__ {
+			local: new-local-node {
+				new-property;
+			};
+		};
+	};
+
+	fragment@6 {
+		target = <&test>;
+
+		__overlay__ {
+			test-phandle = <&test>, <&local>;
+		};
+	};
+
+	fragment@7 {
+		target = <&test>;
+
+		__overlay__ {
+			test-several-phandle = <&local>, <&local>;
+		};
+	};
+
+	fragment@8 {
+		target = <&test>;
+
+		__overlay__ {
+			sub-test-node {
+				new-sub-test-property;
+			};
+		};
+	};
+};
diff --git a/tests/parent_offset.c b/tests/parent_offset.c
index d4ab3cf..a935a53 100644
--- a/tests/parent_offset.c
+++ b/tests/parent_offset.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_parent_offset()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 #include <stdlib.h>
 #include <stdio.h>
diff --git a/tests/path-references.c b/tests/path-references.c
index 5e332e8..4db61a5 100644
--- a/tests/path-references.c
+++ b/tests/path-references.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for string references in dtc
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 #include <stdlib.h>
 #include <stdio.h>
diff --git a/tests/path-references.dts b/tests/path-references.dts
index 8c66d80..1fb7d70 100644
--- a/tests/path-references.dts
+++ b/tests/path-references.dts
@@ -16,7 +16,7 @@
 	foobar {
 		n3: baz {
 			ref = &{/foo/baz};
-			lref = &n4;
+			lref = start: &n4 end:;
 		};
 	};
 	foo {
diff --git a/tests/path_offset.c b/tests/path_offset.c
index bfebe9f..82527d4 100644
--- a/tests/path_offset.c
+++ b/tests/path_offset.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_path_offset()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 #include <stdlib.h>
 #include <stdio.h>
diff --git a/tests/path_offset_aliases.c b/tests/path_offset_aliases.c
index 78d5a46..0112e72 100644
--- a/tests/path_offset_aliases.c
+++ b/tests/path_offset_aliases.c
@@ -1,22 +1,9 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_path_offset()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
  * Copyright 2008 Kumar Gala, Freescale Semiconductor, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 #include <stdlib.h>
 #include <stdio.h>
diff --git a/tests/pci-bridge-bad1.dts b/tests/pci-bridge-bad1.dts
new file mode 100644
index 0000000..17aac04
--- /dev/null
+++ b/tests/pci-bridge-bad1.dts
@@ -0,0 +1,16 @@
+/dts-v1/;
+
+/ {
+	compatible = "example,pci-bridge-ok";
+	#address-cells = < 2 >;
+	#size-cells = < 2 >;
+	abadname@0 {
+		device_type = "pci";
+		compatible = "example,pci-bridge";
+		#address-cells = < 3 >;
+		#size-cells = < 2 >;
+		reg = <0 0 0 0x1000>;
+		bus-range = <0 0xff>;
+		ranges = <0 0 0 0 0 0 0x10000>;
+	};
+};
diff --git a/tests/pci-bridge-bad2.dts b/tests/pci-bridge-bad2.dts
new file mode 100644
index 0000000..a7e5c05
--- /dev/null
+++ b/tests/pci-bridge-bad2.dts
@@ -0,0 +1,16 @@
+/dts-v1/;
+
+/ {
+	compatible = "example,pci-bridge-ok";
+	#address-cells = < 2 >;
+	#size-cells = < 2 >;
+	p@0 {
+		device_type = "pci";
+		compatible = "example,pci-bridge";
+		#address-cells = < 3 >;
+		#size-cells = < 2 >;
+		reg = <0 0 0 0x1000>;
+		bus-range = <0 0xff>;
+		ranges = <0 0 0 0 0 0 0x10000>;
+	};
+};
diff --git a/tests/pci-bridge-ok.dts b/tests/pci-bridge-ok.dts
new file mode 100644
index 0000000..02e32e0
--- /dev/null
+++ b/tests/pci-bridge-ok.dts
@@ -0,0 +1,25 @@
+/dts-v1/;
+
+/ {
+	compatible = "example,pci-bridge-ok";
+	#address-cells = < 2 >;
+	#size-cells = < 2 >;
+	pci@0 {
+		device_type = "pci";
+		compatible = "example,pci-bridge";
+		#address-cells = < 3 >;
+		#size-cells = < 2 >;
+		reg = <0 0 0 0x1000>;
+		bus-range = <0 0xff>;
+		ranges = <0 0 0 0 0 0 0x10000>;
+	};
+	pcie@10000000000 {
+		device_type = "pci";
+		compatible = "example,pcie-bridge";
+		#address-cells = < 3 >;
+		#size-cells = < 2 >;
+		reg = <0x10 0x00000000 0 0x1000>;
+		bus-range = <0 0xff>;
+		ranges = <0 0 0 0 0 0 0x10000>;
+	};
+};
diff --git a/tests/phandle_format.c b/tests/phandle_format.c
index 5874ae7..d00618f 100644
--- a/tests/phandle_format.c
+++ b/tests/phandle_format.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for phandle format options
  * Copyright (C) 2009 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 #include <stdlib.h>
 #include <stdio.h>
diff --git a/tests/property_iterate.c b/tests/property_iterate.c
index b5cedbe..9a67f49 100644
--- a/tests/property_iterate.c
+++ b/tests/property_iterate.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Tests that fdt_next_subnode() works as expected
@@ -5,20 +6,6 @@
  * Copyright (C) 2013 Google, Inc
  *
  * Copyright (C) 2007 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
diff --git a/tests/propname_escapes.c b/tests/propname_escapes.c
index e91bd99..3e41e63 100644
--- a/tests/propname_escapes.c
+++ b/tests/propname_escapes.c
@@ -1,22 +1,9 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_getprop()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
  * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
diff --git a/tests/pylibfdt_tests.py b/tests/pylibfdt_tests.py
index ae392bb..64b5bd1 100644
--- a/tests/pylibfdt_tests.py
+++ b/tests/pylibfdt_tests.py
@@ -1,61 +1,48 @@
+# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 # 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 struct
 import sys
 import types
 import unittest
 
-sys.path.append('../pylibfdt')
+sys.path.insert(0, '../pylibfdt')
 import libfdt
-from libfdt import FdtException, QUIET_NOTFOUND, QUIET_ALL
+from libfdt import Fdt, FdtSw, FdtException, QUIET_NOTFOUND, QUIET_ALL
+
+TEST_ADDR_1H = 0xdeadbeef
+TEST_ADDR_1L = 0x00000000
+TEST_ADDR_1 = (TEST_ADDR_1H << 32) | TEST_ADDR_1L
+TEST_ADDR_1 = 0x8000000000000000
+TEST_SIZE_1H = 0x00000000
+TEST_SIZE_1L = 0x00100000
+TEST_SIZE_1 = (TEST_SIZE_1H << 32) | TEST_SIZE_1L
+TEST_ADDR_2H = 0
+TEST_ADDR_2L = 123456789
+TEST_ADDR_2 = (TEST_ADDR_2H << 32) | TEST_ADDR_2L
+TEST_SIZE_2H = 0
+TEST_SIZE_2L = 0o10000
+TEST_SIZE_2 = (TEST_SIZE_2H << 32) | TEST_SIZE_2L
+
+TEST_VALUE_1 = 0xdeadbeef
+TEST_VALUE_2 = 123456789
+
+TEST_VALUE64_1H = 0xdeadbeef
+TEST_VALUE64_1L = 0x01abcdef
+TEST_VALUE64_1 = (TEST_VALUE64_1H << 32) | TEST_VALUE64_1L
+
+PHANDLE_1 = 0x2000
+PHANDLE_2 = 0x2001
+
+TEST_BYTES_1 = b'hello world'
+
+TEST_STRING_1 = 'hello world'
+TEST_STRING_2 = 'hi world'
+TEST_STRING_3 = u'unicode \u01d3'
+
 
 def get_err(err_code):
     """Convert an error code into an error message
@@ -66,7 +53,7 @@
     Returns:
         String error code
     """
-    return 'pylibfdt error %d: %s' % (-err_code, libfdt.fdt_strerror(-err_code))
+    return 'pylibfdt error %d: %s' % (-err_code, libfdt.strerror(-err_code))
 
 def _ReadFdt(fname):
     """Read a device tree file into an Fdt object, ready for use
@@ -77,10 +64,11 @@
     Returns:
         Fdt bytearray suitable for passing to libfdt functions
     """
-    return libfdt.Fdt(open(fname).read())
+    with open(fname, mode='rb') as f:
+        return libfdt.Fdt(f.read())
 
-class PyLibfdtTests(unittest.TestCase):
-    """Test class for pylibfdt
+class PyLibfdtBasicTests(unittest.TestCase):
+    """Test class for basic pylibfdt access functions
 
     Properties:
         fdt: Device tree file used for testing
@@ -89,6 +77,8 @@
     def setUp(self):
         """Read in the device tree we use for testing"""
         self.fdt = _ReadFdt('test_tree1.dtb')
+        self.fdt2 = _ReadFdt('test_props.dtb')
+        self.fdt3 = _ReadFdt('aliases.dtb')
 
     def GetPropList(self, node_path):
         """Read a list of properties from a node
@@ -108,24 +98,54 @@
             poffset = self.fdt.next_property_offset(poffset, QUIET_NOTFOUND)
         return prop_list
 
+    def GetSubnodes(self, node_path):
+        """Read a list of subnodes from a node
+
+        Args:
+            node_path: Full path to node, e.g. '/subnode@1/subsubnode'
+
+        Returns:
+            List of subnode names for that node, e.g. ['subsubnode', 'ss1']
+        """
+        subnode_list = []
+        node = self.fdt.path_offset(node_path)
+        offset = self.fdt.first_subnode(node, QUIET_NOTFOUND)
+        while offset > 0:
+            name = self.fdt.get_name(offset)
+            subnode_list.append(name)
+            offset = self.fdt.next_subnode(offset, QUIET_NOTFOUND)
+        return subnode_list
+
     def testImport(self):
         """Check that we can import the library correctly"""
-        self.assertEquals(type(libfdt), types.ModuleType)
+        self.assertEqual(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)
+            fdt = libfdt.Fdt(b'a string')
+        self.assertEqual(e.exception.err, -libfdt.BADMAGIC)
+
+    def testSubnodeOffset(self):
+        """check that we can locate a subnode by name"""
+        node1 = self.fdt.path_offset('/subnode@1')
+        self.assertEqual(self.fdt.subnode_offset(0, 'subnode@1'), node1)
+
+        with self.assertRaises(FdtException) as e:
+            self.fdt.subnode_offset(0, 'missing')
+        self.assertEqual(e.exception.err, -libfdt.NOTFOUND)
+
+        node2 = self.fdt.path_offset('/subnode@1/subsubnode')
+        self.assertEqual(self.fdt.subnode_offset(node1, 'subsubnode'), node2)
 
     def testPathOffset(self):
         """Check that we can find the offset of a node"""
-        self.assertEquals(self.fdt.path_offset('/'), 0)
+        self.assertEqual(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),
+        self.assertEqual(e.exception.err, -libfdt.NOTFOUND)
+        self.assertEqual(self.fdt.path_offset('/wibble', QUIET_NOTFOUND),
                           -libfdt.NOTFOUND)
 
     def testPropertyOffset(self):
@@ -136,54 +156,54 @@
             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),
+        self.assertEqual(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)
+        self.assertEqual(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)
+        self.assertEqual(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)
+        self.assertEqual(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),
+        self.assertEqual(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)
+        self.assertEqual(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), '')
+        self.assertEqual(self.fdt.get_name(0), '')
         node = self.fdt.path_offset('/subnode@1/subsubnode')
-        self.assertEquals(self.fdt.get_name(node), 'subsubnode')
+        self.assertEqual(self.fdt.get_name(node), 'subsubnode')
 
         with self.assertRaises(FdtException) as e:
             self.fdt.get_name(-2)
-        self.assertEquals(e.exception.err, -libfdt.BADOFFSET)
+        self.assertEqual(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')
+        self.assertEqual(prop.name, 'compatible')
+        self.assertEqual(prop, b'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(
+        self.assertEqual(e.exception.err, -libfdt.BADOFFSET)
+        self.assertEqual(
                 -libfdt.BADOFFSET,
                 self.fdt.get_property_by_offset(-2, [libfdt.BADOFFSET]))
 
@@ -191,23 +211,41 @@
         """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',
+        self.assertEqual(value, b'test_tree1\0')
+        self.assertEqual(-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)
+        self.assertEqual(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')
+        self.assertEqual(value, b'subsubnode1\0subsubnode\0')
 
     def testStrError(self):
         """Check that we can get an error string"""
-        self.assertEquals(libfdt.strerror(-libfdt.NOTFOUND),
+        self.assertEqual(libfdt.strerror(-libfdt.NOTFOUND),
                           'FDT_ERR_NOTFOUND')
 
+    def testNextNodeOffset(self):
+        """Check that we can walk through nodes"""
+        node_list = []
+        node = 0
+        depth = 0
+        while depth >= 0:
+            node_list.append([depth, self.fdt.get_name(node)])
+            node, depth = self.fdt.next_node(node, depth, (libfdt.BADOFFSET,))
+        self.assertEqual(node_list, [
+            [0, ''],
+            [1, 'subnode@1'],
+            [2, 'subsubnode'],
+            [2, 'ss1'],
+            [1, 'subnode@2'],
+            [2, 'subsubnode@0'],
+            [2, 'ss2'],
+            ])
+
     def testFirstNextSubnodeOffset(self):
         """Check that we can walk through subnodes"""
         node_list = []
@@ -215,74 +253,340 @@
         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'])
+        self.assertEqual(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),
+        self.assertEqual(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)
+        self.assertEqual(e.exception.err, -libfdt.NOTFOUND)
 
         node = self.fdt.path_offset('/subnode@1/ss1', QUIET_NOTFOUND)
-        self.assertEquals(self.fdt.next_subnode(node, QUIET_NOTFOUND),
+        self.assertEqual(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)
+        self.assertEqual(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),
+        self.assertEqual(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),
+        self.assertEqual(self.fdt.delprop(node, 'reg'), 0)
+        self.assertEqual(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)
+        self.assertEqual(self.fdt.magic(), 0xd00dfeed)
+        self.assertEqual(self.fdt.totalsize(), len(self.fdt._fdt))
+        self.assertEqual(self.fdt.off_dt_struct(), 88)
+        self.assertEqual(self.fdt.off_dt_strings(), 652)
+        self.assertEqual(self.fdt.off_mem_rsvmap(), 40)
+        self.assertEqual(self.fdt.version(), 17)
+        self.assertEqual(self.fdt.last_comp_version(), 16)
+        self.assertEqual(self.fdt.boot_cpuid_phys(), 0)
+        self.assertEqual(self.fdt.size_dt_strings(), 105)
+        self.assertEqual(self.fdt.size_dt_struct(), 564)
 
     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.assertEqual(self.fdt.delprop(node, 'prop-int'), 0)
+        self.assertEqual(orig_size, self.fdt.totalsize())
+        self.assertEqual(self.fdt.pack(), 0)
         self.assertTrue(self.fdt.totalsize() < orig_size)
+        self.assertEqual(self.fdt.totalsize(), len(self.fdt.as_bytearray()))
 
     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)
+        self.assertEqual(e.exception.err, -libfdt.BADOFFSET)
         with self.assertRaises(FdtException) as e:
             self.fdt.first_property_offset(3)
-        self.assertEquals(e.exception.err, -libfdt.BADOFFSET)
+        self.assertEqual(e.exception.err, -libfdt.BADOFFSET)
         with self.assertRaises(FdtException) as e:
             self.fdt.next_property_offset(3)
-        self.assertEquals(e.exception.err, -libfdt.BADOFFSET)
+        self.assertEqual(e.exception.err, -libfdt.BADOFFSET)
 
     def testBadPathOffset(self):
         """Test that bad path names are detected"""
-        with self.assertRaisesRegexp(FdtException, get_err(libfdt.BADPATH)):
+        with self.assertRaisesRegex(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.assertEqual(-libfdt.NOTFOUND,
                           self.fdt.path_offset('/missing', QUIET_ALL))
-        self.assertEquals(-libfdt.BADOFFSET,
+        self.assertEqual(-libfdt.BADOFFSET,
                           self.fdt.get_property_by_offset(13, QUIET_ALL))
-        self.assertEquals(-libfdt.BADPATH,
+        self.assertEqual(-libfdt.BADPATH,
                           self.fdt.path_offset('missing', QUIET_ALL))
 
+    def testIntegers(self):
+        """Check that integers can be passed and returned"""
+        self.assertEqual(0, libfdt.fdt_get_phandle(self.fdt._fdt, 0))
+        node2 = self.fdt.path_offset('/subnode@2')
+        self.assertEqual(0x2000, libfdt.fdt_get_phandle(self.fdt._fdt, node2))
+
+    def testGetPhandle(self):
+        """Test for the get_phandle() method"""
+        self.assertEqual(0, self.fdt.get_phandle(0))
+        node2 = self.fdt.path_offset('/subnode@2')
+        self.assertEqual(0x2000, self.fdt.get_phandle(node2))
+
+    def testGetAlias(self):
+        """Test for the get_alias() method"""
+        self.assertEqual("/subnode@1", self.fdt3.get_alias('s1'))
+        self.assertEqual("/subnode@1/subsubnode", self.fdt3.get_alias('ss1'))
+        self.assertEqual("/subnode@1/subsubnode/subsubsubnode", self.fdt3.get_alias('sss1'))
+
+    def testParentOffset(self):
+        """Test for the parent_offset() method"""
+        self.assertEqual(-libfdt.NOTFOUND,
+                          self.fdt.parent_offset(0, QUIET_NOTFOUND))
+        with self.assertRaises(FdtException) as e:
+            self.fdt.parent_offset(0)
+        self.assertEqual(e.exception.err, -libfdt.NOTFOUND)
+
+        node1 = self.fdt.path_offset('/subnode@2')
+        self.assertEqual(0, self.fdt.parent_offset(node1))
+        node2 = self.fdt.path_offset('/subnode@2/subsubnode@0')
+        self.assertEqual(node1, self.fdt.parent_offset(node2))
+
+    def testNodeOffsetByPhandle(self):
+        """Test for the node_offset_by_phandle() method"""
+        self.assertEqual(-libfdt.NOTFOUND,
+                          self.fdt.node_offset_by_phandle(1, QUIET_NOTFOUND))
+        node1 = self.fdt.path_offset('/subnode@2')
+        self.assertEqual(node1, self.fdt.node_offset_by_phandle(0x2000))
+        node2 = self.fdt.path_offset('/subnode@2/subsubnode@0')
+        self.assertEqual(node2, self.fdt.node_offset_by_phandle(0x2001))
+
+    def get_prop(self, name):
+        return self.fdt2.getprop(0, name)
+
+    def testGetIntProperties(self):
+        """Test that we can access properties as integers"""
+        self.assertEqual(0xdeadbeef, self.get_prop("prop-hex32").as_uint32())
+        self.assertEqual(123, self.get_prop("prop-uint32").as_uint32())
+        self.assertEqual(-2, self.get_prop("prop-int32").as_int32())
+        self.assertEqual(9223372036854775807,
+                          self.get_prop("prop-uint64").as_uint64())
+        self.assertEqual(-2, self.get_prop("prop-int64").as_int64())
+
+    def testReserveMap(self):
+        """Test that we can access the memory reserve map"""
+        self.assertEqual(2, self.fdt.num_mem_rsv())
+        self.assertEqual([ 0xdeadbeef00000000, 0x100000],
+                          self.fdt.get_mem_rsv(0))
+        self.assertEqual([123456789, 0o10000], self.fdt.get_mem_rsv(1))
+
+    def testEmpty(self):
+        """Test that we can create an empty tree"""
+        self.assertEqual(-libfdt.NOSPACE,
+                          Fdt.create_empty_tree(1, (libfdt.NOSPACE,)))
+        fdt = Fdt.create_empty_tree(128)
+        self.assertEqual(128, fdt.totalsize())
+
+    def testOpenInto(self):
+        """Test that we can resize a tree"""
+        fdt = Fdt.create_empty_tree(128)
+        self.assertEqual(128, fdt.totalsize())
+        fdt.resize(256)
+        self.assertEqual(256, fdt.totalsize())
+        fdt.pack()
+        self.assertTrue(fdt.totalsize() < 128)
+
+    def testSetProp(self):
+        """Test that we can update and create properties"""
+        node = self.fdt.path_offset('/subnode@1')
+        self.fdt.setprop(node, 'compatible', TEST_BYTES_1)
+        self.assertEqual(TEST_BYTES_1, self.fdt.getprop(node, 'compatible'))
+
+        # Check that this property is missing, and that we don't have space to
+        # add it
+        self.assertEqual(-libfdt.NOTFOUND,
+                          self.fdt.getprop(node, 'missing', QUIET_NOTFOUND))
+        self.assertEqual(-libfdt.NOSPACE,
+                          self.fdt.setprop(node, 'missing', TEST_BYTES_1,
+                                           quiet=(libfdt.NOSPACE,)))
+
+        # Expand the device tree so we now have room
+        self.fdt.resize(self.fdt.totalsize() + 50)
+        self.fdt.setprop(node, 'missing', TEST_BYTES_1)
+        self.assertEqual(TEST_BYTES_1, self.fdt.getprop(node, 'missing'))
+
+    def testSetPropU32(self):
+        """Test that we can update and create integer properties"""
+        node = 0
+        prop = 'prop-int'
+        self.fdt.setprop_u32(node, prop, TEST_VALUE_1)
+        self.assertEqual(struct.pack('>I', TEST_VALUE_1),
+                          self.fdt.getprop(node, prop))
+
+    def testSetPropU64(self):
+        """Test that we can update and create integer properties"""
+        node = 0
+        prop = 'prop-int64'
+        self.fdt.setprop_u64(node, prop, TEST_VALUE64_1)
+        self.assertEqual(struct.pack('>Q', TEST_VALUE64_1),
+                          self.fdt.getprop(node, prop))
+
+    def testSetPropStr(self):
+        """Test that we can set a property to a particular string"""
+        node = 0
+        prop = 'prop-str'
+        self.assertEqual(TEST_STRING_1, self.fdt.getprop(node, prop).as_str())
+        self.fdt.setprop_str(node, prop, TEST_STRING_2)
+        self.assertEqual(TEST_STRING_2, self.fdt.getprop(node, prop).as_str())
+        with self.assertRaises(ValueError) as e:
+            self.fdt.getprop(node, 'prop-int').as_str()
+        self.assertIn('lacks nul termination', str(e.exception))
+
+        node2 = self.fdt.path_offset('/subnode@1/subsubnode')
+        with self.assertRaises(ValueError) as e:
+            self.fdt.getprop(node2, 'compatible').as_str()
+        self.assertIn('embedded nul', str(e.exception))
+
+        # Expand the device tree so we now have room
+        self.fdt.resize(self.fdt.totalsize() + 50)
+        prop = 'prop-unicode'
+        self.fdt.setprop_str(node, prop, TEST_STRING_3)
+        self.assertEqual(TEST_STRING_3,
+                          self.fdt.getprop(node, prop).as_str())
+
+    def testSetName(self):
+        """Test that we can update a node name"""
+        node = self.fdt.path_offset('/subnode@1')
+        old_val = self.fdt.get_name(node)
+        self.fdt.set_name(node, 'test')
+        self.assertEqual('test', self.fdt.get_name(node))
+
+        with self.assertRaises(ValueError) as e:
+            self.fdt.set_name(node, 'some\0name')
+        self.assertIn('embedded nul', str(e.exception))
+
+        with self.assertRaises(ValueError) as e:
+            self.fdt.set_name(node, 'name\0')
+        self.assertIn('embedded nul', str(e.exception))
+
+    def testAddDeleteNodes(self):
+        """Test that we can add and delete nodes"""
+        node_name = '/subnode@1'
+        self.assertEqual(self.GetSubnodes(node_name), ['subsubnode', 'ss1'])
+        node = self.fdt.path_offset('%s/subsubnode' % node_name)
+        self.assertEqual(self.fdt.del_node(node, 'subsubnode'), 0)
+        self.assertEqual(self.GetSubnodes(node_name), ['ss1'])
+
+        node = self.fdt.path_offset(node_name)
+        offset = self.fdt.add_subnode(node, 'more')
+        self.assertTrue(offset > 0)
+        self.assertEqual(self.GetSubnodes(node_name), ['more', 'ss1'])
+
+
+class PyLibfdtSwTests(unittest.TestCase):
+    """Test class for pylibfdt sequential-write DT creation
+    """
+    def assertOk(self, err_code):
+        self.assertEqual(0, err_code)
+
+    def testCreate(self):
+        # First check the minimum size and also the FdtSw() constructor
+        with self.assertRaisesRegex(FdtException, get_err(libfdt.NOSPACE)):
+            self.assertEqual(-libfdt.NOSPACE, FdtSw(3))
+
+        sw = FdtSw()
+        sw.add_reservemap_entry(TEST_ADDR_1, TEST_SIZE_1)
+        sw.add_reservemap_entry(TEST_ADDR_2, TEST_SIZE_2)
+        sw.finish_reservemap()
+
+        sw.begin_node('')
+        sw.property_string('compatible', 'test_tree1')
+        sw.property_u32('prop-int', TEST_VALUE_1)
+
+        sw.property_u32('prop-int', TEST_VALUE_1)
+        sw.property_u64('prop-int64', TEST_VALUE64_1)
+        sw.property_string('prop-str', TEST_STRING_1)
+        sw.property_u32('#address-cells', 1)
+        sw.property_u32('#size-cells', 0)
+
+        sw.begin_node('subnode@1')
+        sw.property_string('compatible', 'subnode1')
+        sw.property_u32('reg', 1)
+        sw.property_cell('prop-int', TEST_VALUE_1)
+        sw.property('data', b'\x00data\x01')
+        sw.begin_node('subsubnode')
+        sw.property('compatible', b'subsubnode1\0subsubnode')
+        sw.property_cell('prop-int', TEST_VALUE_1)
+        sw.end_node()
+        sw.begin_node('ss1')
+        sw.end_node()
+        sw.end_node()
+
+        for i in range(2, 11):
+            with sw.add_node('subnode@%d' % i):
+                sw.property_u32('reg', 2)
+                sw.property_cell('linux,phandle', PHANDLE_1)
+                sw.property_cell('prop-int', TEST_VALUE_2)
+                sw.property_u32('#address-cells', 1)
+                sw.property_u32('#size-cells', 0)
+                with sw.add_node('subsubnode@0'):
+                    sw.property_u32('reg', 0)
+                    sw.property_cell('phandle', PHANDLE_2)
+                    sw.property('compatible', b'subsubnode2\0subsubnode')
+                    sw.property_cell('prop-int', TEST_VALUE_2)
+                with sw.add_node('ss2'):
+                    pass
+        sw.end_node()
+
+        fdt = sw.as_fdt()
+        self.assertEqual(2, fdt.num_mem_rsv())
+        self.assertEqual([TEST_ADDR_1, TEST_SIZE_1], fdt.get_mem_rsv(0))
+
+        # Make sure we can add a few more things
+        with sw.add_node('another'):
+            sw.property_u32('reg', 3)
+
+        # Make sure we can read from the tree too
+        node = sw.path_offset('/subnode@1')
+        self.assertEqual(b'subnode1\0', sw.getprop(node, 'compatible'))
+
+        # Make sure we did at least two resizes
+        self.assertTrue(len(fdt.as_bytearray()) > FdtSw.INC_SIZE * 2)
+
+
+class PyLibfdtRoTests(unittest.TestCase):
+    """Test class for read-only pylibfdt access functions
+
+    This just tests a few simple cases. Most of the tests are in
+    PyLibfdtBasicTests.
+
+    Properties:
+        fdt: Device tree file used for testing
+    """
+
+    def setUp(self):
+        """Read in the device tree we use for testing"""
+        with open('test_tree1.dtb', mode='rb') as f:
+            self.fdt = libfdt.FdtRo(f.read())
+
+    def testAccess(self):
+        """Basic sanity check for the FdtRo class"""
+        node = self.fdt.path_offset('/subnode@1')
+        self.assertEqual(b'subnode1\0',
+                         self.fdt.getprop(node, 'compatible'))
+        node = self.fdt.first_subnode(node)
+        self.assertEqual(b'this is a placeholder string\0string2\0',
+                         self.fdt.getprop(node, 'placeholder'))
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/tests/references.c b/tests/references.c
index cab70f6..d18e722 100644
--- a/tests/references.c
+++ b/tests/references.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for phandle references in dtc
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 #include <stdlib.h>
 #include <stdio.h>
@@ -76,8 +63,8 @@
 int main(int argc, char *argv[])
 {
 	void *fdt;
-	int n1, n2, n3, n4, n5;
-	uint32_t h1, h2, h4, h5;
+	int n1, n2, n3, n4, n5, n6, err;
+	uint32_t h1, h2, h4, h5, h6, hn;
 
 	test_init(argc, argv);
 	fdt = load_blob_arg(argc, argv);
@@ -97,11 +84,15 @@
 	n5 = fdt_path_offset(fdt, "/node5");
 	if (n5 < 0)
 		FAIL("fdt_path_offset(/node5): %s", fdt_strerror(n5));
+	n6 = fdt_path_offset(fdt, "/node6");
+	if (n6 < 0)
+		FAIL("fdt_path_offset(/node6): %s", fdt_strerror(n6));
 
 	h1 = fdt_get_phandle(fdt, n1);
 	h2 = fdt_get_phandle(fdt, n2);
 	h4 = fdt_get_phandle(fdt, n4);
 	h5 = fdt_get_phandle(fdt, n5);
+	h6 = fdt_get_phandle(fdt, n6);
 
 	if (h1 != 0x2000)
 		FAIL("/node1 has wrong phandle, 0x%x instead of 0x%x",
@@ -109,6 +100,9 @@
 	if (h2 != 0x1)
 		FAIL("/node2 has wrong phandle, 0x%x instead of 0x%x",
 		     h2, 0x1);
+	if (h6 != FDT_MAX_PHANDLE)
+		FAIL("/node6 has wrong phandle, 0x%x instead of 0x%x",
+		     h6, FDT_MAX_PHANDLE);
 	if ((h4 == 0x2000) || (h4 == 0x1) || (h4 == 0))
 		FAIL("/node4 has bad phandle, 0x%x", h4);
 
@@ -117,6 +111,14 @@
 	if ((h5 == h4) || (h5 == h2) || (h5 == h1))
 		FAIL("/node5 has duplicate phandle, 0x%x", h5);
 
+	/*
+	 * /node6 has phandle FDT_MAX_PHANDLE, so fdt_generate_phandle() is
+	 * expected to fail.
+	 */
+	err = fdt_generate_phandle(fdt, &hn);
+	if (err != -FDT_ERR_NOPHANDLES)
+		FAIL("generated invalid phandle 0x%x\n", hn);
+
 	check_ref(fdt, n1, h2);
 	check_ref(fdt, n2, h1);
 	check_ref(fdt, n3, h4);
diff --git a/tests/references.dts b/tests/references.dts
index f783e8b..b390639 100644
--- a/tests/references.dts
+++ b/tests/references.dts
@@ -33,4 +33,9 @@
 		linux,phandle = <&n5>;
 		phandle = <&n5>;
 	};
+
+	node6 {
+		linux,phandle = <0xfffffffe>;
+		phandle = <0xfffffffe>;
+	};
 };
diff --git a/tests/root_node.c b/tests/root_node.c
index 58aebf6..37e6f05 100644
--- a/tests/root_node.c
+++ b/tests/root_node.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Basic testcase for read-only access
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index b8a2825..294585b 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -1,11 +1,62 @@
 #! /bin/sh
 
-. ./tests.sh
+SRCDIR=`dirname "$0"`
+. "$SRCDIR/testutils.sh"
 
 if [ -z "$CC" ]; then
-    CC=gcc
+    CC=cc
 fi
 
+if [ -z "$PYTHON" ]; then
+    PYTHON=python3
+fi
+
+if [ -n "$NO_PYTHON" ]; then
+    if [ "$NO_PYTHON" != "0" ]; then
+        no_python=true
+    else
+        no_python=false
+    fi
+else
+    if [ -f ../pylibfdt/_libfdt.so ] || [ -f ../pylibfdt/_libfdt.cpython-3*.so ]; then
+        no_python=false
+    else
+        no_python=true
+    fi
+fi
+
+if [ -n "$NO_YAML" ]; then
+    if [ "$NO_YAML" != "0" ]; then
+        no_yaml=true
+    else
+        no_yaml=false
+    fi
+else
+    if pkg-config --exists yaml-0.1; then
+        no_yaml=false
+    else
+        no_yaml=true
+    fi
+fi
+
+# stat differs between platforms
+if [ -z "$STATSZ" ]; then
+	stat --version 2>/dev/null | grep -q 'GNU'
+	GNUSTAT=$?
+	if [ "$GNUSTAT" -ne 0 ]; then
+		# Assume BSD stat if we can't detect as GNU stat
+		STATSZ="stat -f %Uz"
+	else
+		STATSZ="stat -c %s"
+	fi
+fi
+
+# Help things find the libfdt shared object
+if [ -z "$TEST_LIBDIR" ]; then
+    TEST_LIBDIR=../libfdt
+fi
+export LD_LIBRARY_PATH="$TEST_LIBDIR"
+
 export QUIET_TEST=1
 STOP_ON_FAIL=0
 
@@ -76,6 +127,9 @@
 	    if [ "$ret" -gt 127 ]; then
 		signame=$(kill -l $((ret - 128)))
 		FAIL "Killed by SIG$signame"
+	    elif [ "$ret" -eq $VGCODE ]; then
+		echo "VALGRIND ERROR"
+		exit $VGCODE
 	    else
 		FAIL "Returned error code $ret"
 	    fi
@@ -114,7 +168,7 @@
 # $2: align base
 check_align () {
     shorten_echo "check_align $@:	"
-    local size=$(stat -c %s "$1")
+    local size=$($STATSZ "$1")
     local align="$2"
     (
 	if [ $(($size % $align)) -eq 0 ] ;then
@@ -131,7 +185,7 @@
 }
 
 asm_to_so () {
-    $CC -shared -o $1.test.so data.S $1.test.s
+    $CC -shared -o $1.test.so "$SRCDIR/data.S" $1.test.s
 }
 
 asm_to_so_test () {
@@ -142,7 +196,7 @@
     expect="$1"
     shift
     printf "fdtget-runtest.sh %s $*:	" "$(echo $expect)"
-    base_run_test sh fdtget-runtest.sh "$expect" "$@"
+    base_run_test sh "$SRCDIR/fdtget-runtest.sh" "$expect" "$@"
 }
 
 run_fdtput_test () {
@@ -150,14 +204,14 @@
     shift
     shorten_echo fdtput-runtest.sh "$expect" "$@"
     printf ":	"
-    base_run_test sh fdtput-runtest.sh "$expect" "$@"
+    base_run_test sh "$SRCDIR/fdtput-runtest.sh" "$expect" "$@"
 }
 
 run_fdtdump_test() {
     file="$1"
     shorten_echo fdtdump-runtest.sh "$file"
     printf ":	"
-    base_run_test sh fdtdump-runtest.sh "$file" 2>/dev/null
+    base_run_test sh "$SRCDIR/fdtdump-runtest.sh" "$file" 2>/dev/null
 }
 
 run_fdtoverlay_test() {
@@ -165,7 +219,7 @@
     shift
     shorten_echo fdtoverlay-runtest.sh "$expect" "$@"
     printf ":	"
-    base_run_test sh fdtoverlay-runtest.sh "$expect" "$@"
+    base_run_test sh "$SRCDIR/fdtoverlay-runtest.sh" "$expect" "$@"
 }
 
 BAD_FIXUP_TREES="bad_index \
@@ -180,12 +234,12 @@
 # Test to exercise libfdt overlay application without dtc's overlay support
 libfdt_overlay_tests () {
     # First test a doctored overlay which requires only local fixups
-    run_dtc_test -I dts -O dtb -o overlay_base_no_symbols.test.dtb overlay_base.dts
+    run_dtc_test -I dts -O dtb -o overlay_base_no_symbols.test.dtb "$SRCDIR/overlay_base.dts"
     run_test check_path overlay_base_no_symbols.test.dtb not-exists "/__symbols__"
     run_test check_path overlay_base_no_symbols.test.dtb not-exists "/__fixups__"
     run_test check_path overlay_base_no_symbols.test.dtb not-exists "/__local_fixups__"
 
-    run_dtc_test -I dts -O dtb -o overlay_overlay_no_fixups.test.dtb overlay_overlay_no_fixups.dts
+    run_dtc_test -I dts -O dtb -o overlay_overlay_no_fixups.test.dtb "$SRCDIR/overlay_overlay_no_fixups.dts"
     run_test check_path overlay_overlay_no_fixups.test.dtb not-exists "/__symbols__"
     run_test check_path overlay_overlay_no_fixups.test.dtb not-exists "/__fixups__"
     run_test check_path overlay_overlay_no_fixups.test.dtb exists "/__local_fixups__"
@@ -193,22 +247,28 @@
     run_test overlay overlay_base_no_symbols.test.dtb overlay_overlay_no_fixups.test.dtb
 
     # Then test with manually constructed fixups
-    run_dtc_test -I dts -O dtb -o overlay_base_manual_symbols.test.dtb overlay_base_manual_symbols.dts
+    run_dtc_test -I dts -O dtb -o overlay_base_manual_symbols.test.dtb "$SRCDIR/overlay_base_manual_symbols.dts"
     run_test check_path overlay_base_manual_symbols.test.dtb exists "/__symbols__"
     run_test check_path overlay_base_manual_symbols.test.dtb not-exists "/__fixups__"
     run_test check_path overlay_base_manual_symbols.test.dtb not-exists "/__local_fixups__"
 
-    run_dtc_test -I dts -O dtb -o overlay_overlay_manual_fixups.test.dtb overlay_overlay_manual_fixups.dts
+    run_dtc_test -I dts -O dtb -o overlay_overlay_manual_fixups.test.dtb "$SRCDIR/overlay_overlay_manual_fixups.dts"
     run_test check_path overlay_overlay_manual_fixups.test.dtb not-exists "/__symbols__"
     run_test check_path overlay_overlay_manual_fixups.test.dtb exists "/__fixups__"
     run_test check_path overlay_overlay_manual_fixups.test.dtb exists "/__local_fixups__"
 
     run_test overlay overlay_base_manual_symbols.test.dtb overlay_overlay_manual_fixups.test.dtb
 
+    # test simplified plugin syntax
+    run_dtc_test -@ -I dts -O dtb -o overlay_overlay_simple.dtb "$SRCDIR/overlay_overlay_simple.dts"
+
+    # verify non-generation of local fixups
+    run_test check_path overlay_overlay_simple.dtb not-exists "/__local_fixups__"
+
     # Bad fixup tests
     for test in $BAD_FIXUP_TREES; do
 	tree="overlay_bad_fixup_$test"
-	run_dtc_test -I dts -O dtb -o $tree.test.dtb $tree.dts
+	run_dtc_test -I dts -O dtb -o $tree.test.dtb "$SRCDIR/$tree.dts"
 	run_test overlay_bad_fixup overlay_base_no_symbols.test.dtb $tree.test.dtb
     done
 }
@@ -216,25 +276,55 @@
 # Tests to exercise dtc's overlay generation support
 dtc_overlay_tests () {
     # Overlay tests for dtc
-    run_dtc_test -@ -I dts -O dtb -o overlay_base.test.dtb overlay_base.dts
+    run_dtc_test -@ -I dts -O dtb -o overlay_base.test.dtb "$SRCDIR/overlay_base.dts"
     run_test check_path overlay_base.test.dtb exists "/__symbols__"
     run_test check_path overlay_base.test.dtb not-exists "/__fixups__"
     run_test check_path overlay_base.test.dtb not-exists "/__local_fixups__"
 
-    run_dtc_test -I dts -O dtb -o overlay_overlay.test.dtb overlay_overlay.dts
+    # With syntactic sugar
+    run_dtc_test -I dts -O dtb -o overlay_overlay.test.dtb "$SRCDIR/overlay_overlay.dts"
     run_test check_path overlay_overlay.test.dtb not-exists "/__symbols__"
     run_test check_path overlay_overlay.test.dtb exists "/__fixups__"
     run_test check_path overlay_overlay.test.dtb exists "/__local_fixups__"
 
+    # Without syntactic sugar
+    run_dtc_test -I dts -O dtb -o overlay_overlay_nosugar.test.dtb "$SRCDIR/overlay_overlay.dts"
+    run_test check_path overlay_overlay_nosugar.test.dtb not-exists "/__symbols__"
+    run_test check_path overlay_overlay_nosugar.test.dtb exists "/__fixups__"
+    run_test check_path overlay_overlay_nosugar.test.dtb exists "/__local_fixups__"
+
+    # Using target-path
+    run_dtc_test -I dts -O dtb -o overlay_overlay_bypath.test.dtb "$SRCDIR/overlay_overlay_bypath.dts"
+    run_test check_path overlay_overlay_bypath.test.dtb not-exists "/__symbols__"
+    run_test check_path overlay_overlay_bypath.test.dtb not-exists "/__fixups__"
+    run_test check_path overlay_overlay_bypath.test.dtb exists "/__local_fixups__"
+
+    # Make sure local target references are resolved and nodes are merged and that path references are not
+    run_dtc_test -I dts -O dtb -o overlay_overlay_local_merge.test.dtb "$SRCDIR/overlay_overlay_local_merge.dts"
+    run_test check_path overlay_overlay_local_merge.test.dtb exists "/fragment@0/__overlay__/new-node/new-merged-node"
+    run_test check_path overlay_overlay_local_merge.test.dtb exists "/fragment@1/__overlay__/new-root-node"
+
+    # Check building works the same as manual constructions
+    run_test dtbs_equal_ordered overlay_overlay.test.dtb overlay_overlay_nosugar.test.dtb
+
+    run_dtc_test -I dts -O dtb -o overlay_overlay_manual_fixups.test.dtb "$SRCDIR/overlay_overlay_manual_fixups.dts"
+    run_test dtbs_equal_ordered overlay_overlay.test.dtb overlay_overlay_manual_fixups.test.dtb
+
+    run_dtc_test -I dts -O dtb -o overlay_overlay_no_fixups.test.dtb "$SRCDIR/overlay_overlay_no_fixups.dts"
+    run_test dtbs_equal_ordered overlay_overlay_bypath.test.dtb overlay_overlay_no_fixups.test.dtb
+
+    # Check we can actually apply the result
+    run_dtc_test -I dts -O dtb -o overlay_base_no_symbols.test.dtb "$SRCDIR/overlay_base.dts"
     run_test overlay overlay_base.test.dtb overlay_overlay.test.dtb
+    run_test overlay overlay_base_no_symbols.test.dtb overlay_overlay_bypath.test.dtb
 
     # test plugin source to dtb and back
     run_dtc_test -I dtb -O dts -o overlay_overlay_decompile.test.dts overlay_overlay.test.dtb
     run_dtc_test -I dts -O dtb -o overlay_overlay_decompile.test.dtb overlay_overlay_decompile.test.dts
     run_test dtbs_equal_ordered overlay_overlay.test.dtb overlay_overlay_decompile.test.dtb
 
-    # Test generation of aliases insted of symbols
-    run_dtc_test -A -I dts -O dtb -o overlay_base_with_aliases.dtb overlay_base.dts
+    # Test generation of aliases instead of symbols
+    run_dtc_test -A -I dts -O dtb -o overlay_base_with_aliases.dtb "$SRCDIR/overlay_base.dts"
     run_test check_path overlay_base_with_aliases.dtb exists "/aliases"
     run_test check_path overlay_base_with_aliases.dtb not-exists "/__symbols__"
     run_test check_path overlay_base_with_aliases.dtb not-exists "/__fixups__"
@@ -252,6 +342,7 @@
     run_test path_offset $TREE
     run_test get_name $TREE
     run_test getprop $TREE
+    run_test get_prop_offset $TREE
     run_test get_phandle $TREE
     run_test get_path $TREE
     run_test supernode_atdepth_offset $TREE
@@ -281,9 +372,9 @@
 check_tests () {
     tree="$1"
     shift
-    run_sh_test dtc-checkfails.sh "$@" -- -I dts -O dtb $tree
+    run_sh_test "$SRCDIR/dtc-checkfails.sh" "$@" -- -I dts -O dtb $tree
     run_dtc_test -I dts -O dtb -o $tree.test.dtb -f $tree
-    run_sh_test dtc-checkfails.sh "$@" -- -I dtb -O dtb $tree.test.dtb
+    run_sh_test "$SRCDIR/dtc-checkfails.sh" "$@" -- -I dtb -O dtb $tree.test.dtb
 }
 
 ALL_LAYOUTS="mts mst tms tsm smt stm"
@@ -291,24 +382,29 @@
 libfdt_tests () {
     tree1_tests test_tree1.dtb
 
-    run_dtc_test -I dts -O dtb -o addresses.test.dtb addresses.dts
+    run_dtc_test -I dts -O dtb -o addresses.test.dtb "$SRCDIR/addresses.dts"
     run_test addr_size_cells addresses.test.dtb
+    run_dtc_test -I dts -O dtb -o addresses2.test.dtb "$SRCDIR/empty.dts"
+    run_test addr_size_cells2 addresses2.test.dtb
 
-    run_dtc_test -I dts -O dtb -o stringlist.test.dtb stringlist.dts
+    run_dtc_test -I dts -O dtb -o stringlist.test.dtb "$SRCDIR/stringlist.dts"
     run_test stringlist stringlist.test.dtb
 
-    # Sequential write tests
-    run_test sw_tree1
-    tree1_tests sw_tree1.test.dtb
-    tree1_tests unfinished_tree1.test.dtb
-    run_test dtbs_equal_ordered test_tree1.dtb sw_tree1.test.dtb
+    for flags in default no_name_dedup; do
+        # Sequential write tests
+        run_test sw_tree1 fixed $flags
+        tree1_tests sw_tree1.test.dtb
+        tree1_tests unfinished_tree1.test.dtb
+        run_test dtbs_equal_ordered test_tree1.dtb sw_tree1.test.dtb
+        run_test sw_states
 
-    # Resizing tests
-    for mode in resize realloc; do
-	run_test sw_tree1 $mode
-	tree1_tests sw_tree1.test.dtb
-	tree1_tests unfinished_tree1.test.dtb
-	run_test dtbs_equal_ordered test_tree1.dtb sw_tree1.test.dtb
+        # Resizing tests
+        for mode in resize realloc newalloc; do
+            run_test sw_tree1 $mode $flags
+            tree1_tests sw_tree1.test.dtb
+            tree1_tests unfinished_tree1.test.dtb
+            run_test dtbs_equal_ordered test_tree1.dtb sw_tree1.test.dtb
+        done
     done
 
     # fdt_move tests
@@ -352,7 +448,7 @@
     tree1_tests_rw rw_tree1.test.dtb
     run_test appendprop1
     run_test appendprop2 appendprop1.test.dtb
-    run_dtc_test -I dts -O dtb -o appendprop.test.dtb appendprop.dts
+    run_dtc_test -I dts -O dtb -o appendprop.test.dtb "$SRCDIR/appendprop.dts"
     run_test dtbs_equal_ordered appendprop2.test.dtb appendprop.test.dtb
     libfdt_overlay_tests
 
@@ -363,99 +459,127 @@
 	tree1_tests_rw noppy.$basetree
     done
 
-    run_dtc_test -I dts -O dtb -o subnode_iterate.dtb subnode_iterate.dts
+    run_test rw_oom
+
+    run_dtc_test -I dts -O dtb -o subnode_iterate.dtb "$SRCDIR/subnode_iterate.dts"
     run_test subnode_iterate subnode_iterate.dtb
 
-    run_dtc_test -I dts -O dtb -o property_iterate.dtb property_iterate.dts
+    run_dtc_test -I dts -O dtb -o property_iterate.dtb "$SRCDIR/property_iterate.dts"
     run_test property_iterate property_iterate.dtb
 
+    run_dtc_test -I dts -O dtb -o unit-addr-without-reg.dtb "$SRCDIR/unit-addr-without-reg.dts"
+    run_test appendprop_addrrange unit-addr-without-reg.dtb 1 1 1
+    run_test appendprop_addrrange unit-addr-without-reg.dtb 2 2 2
+    run_test appendprop_addrrange unit-addr-without-reg.dtb 2 1 3
+
     # Tests for behaviour on various sorts of corrupted trees
     run_test truncated_property
+    run_test truncated_string
+    run_test truncated_memrsv
 
     # Check aliases support in fdt_path_offset
-    run_dtc_test -I dts -O dtb -o aliases.dtb aliases.dts
+    run_dtc_test -I dts -O dtb -o aliases.dtb "$SRCDIR/aliases.dts"
     run_test get_alias aliases.dtb
     run_test path_offset_aliases aliases.dtb
 
     # Specific bug tests
     run_test add_subnode_with_nops
-    run_dtc_test -I dts -O dts -o sourceoutput.test.dts sourceoutput.dts
-    run_dtc_test -I dts -O dtb -o sourceoutput.test.dtb sourceoutput.dts
+    run_dtc_test -I dts -O dts -o sourceoutput.test.dts "$SRCDIR/sourceoutput.dts"
+    run_dtc_test -I dts -O dtb -o sourceoutput.test.dtb "$SRCDIR/sourceoutput.dts"
     run_dtc_test -I dts -O dtb -o sourceoutput.test.dts.test.dtb sourceoutput.test.dts
     run_test dtbs_equal_ordered sourceoutput.test.dtb sourceoutput.test.dts.test.dtb
 
-    run_dtc_test -I dts -O dtb -o embedded_nul.test.dtb embedded_nul.dts
-    run_dtc_test -I dts -O dtb -o embedded_nul_equiv.test.dtb embedded_nul_equiv.dts
+    run_dtc_test -I dts -O dtb -o embedded_nul.test.dtb "$SRCDIR/embedded_nul.dts"
+    run_dtc_test -I dts -O dtb -o embedded_nul_equiv.test.dtb "$SRCDIR/embedded_nul_equiv.dts"
     run_test dtbs_equal_ordered embedded_nul.test.dtb embedded_nul_equiv.test.dtb
 
-    run_dtc_test -I dts -O dtb bad-size-cells.dts
+    run_dtc_test -I dts -O dtb "$SRCDIR/bad-size-cells.dts"
 
     run_wrap_error_test $DTC division-by-zero.dts
     run_wrap_error_test $DTC bad-octal-literal.dts
-    run_dtc_test -I dts -O dtb nul-in-escape.dts
+    run_dtc_test -I dts -O dtb "$SRCDIR/nul-in-escape.dts"
     run_wrap_error_test $DTC nul-in-line-info1.dts
     run_wrap_error_test $DTC nul-in-line-info2.dts
 
     run_wrap_error_test $DTC -I dtb -O dts -o /dev/null ovf_size_strings.dtb
+
+    run_test check_header test_tree1.dtb
+
+    FSBASE=fs
+    rm -rf $FSBASE
+    mkdir -p $FSBASE
+    run_test fs_tree1 $FSBASE/test_tree1
+    run_dtc_test -I fs -O dts -o fs.test_tree1.test.dts $FSBASE/test_tree1
+    run_dtc_test -I fs -O dtb -o fs.test_tree1.test.dtb $FSBASE/test_tree1
+    run_test dtbs_equal_unordered -m fs.test_tree1.test.dtb test_tree1.dtb
+
+    # check full tests
+    for good in test_tree1.dtb; do
+	run_test check_full $good
+    done
+    for bad in truncated_property.dtb truncated_string.dtb \
+				      truncated_memrsv.dtb; do
+	run_test check_full -n $bad
+    done
 }
 
 dtc_tests () {
-    run_dtc_test -I dts -O dtb -o dtc_tree1.test.dtb test_tree1.dts
+    run_dtc_test -I dts -O dtb -o dtc_tree1.test.dtb "$SRCDIR/test_tree1.dts"
     tree1_tests dtc_tree1.test.dtb
     tree1_tests_rw dtc_tree1.test.dtb
     run_test dtbs_equal_ordered dtc_tree1.test.dtb test_tree1.dtb
 
-    run_dtc_test -I dts -O dtb -o dtc_escapes.test.dtb propname_escapes.dts
+    run_dtc_test -I dts -O dtb -o dtc_escapes.test.dtb "$SRCDIR/propname_escapes.dts"
     run_test propname_escapes dtc_escapes.test.dtb
 
-    run_dtc_test -I dts -O dtb -o line_directives.test.dtb line_directives.dts
+    run_dtc_test -I dts -O dtb -o line_directives.test.dtb "$SRCDIR/line_directives.dts"
 
-    run_dtc_test -I dts -O dtb -o dtc_escapes.test.dtb escapes.dts
+    run_dtc_test -I dts -O dtb -o dtc_escapes.test.dtb "$SRCDIR/escapes.dts"
     run_test string_escapes dtc_escapes.test.dtb
 
-    run_dtc_test -I dts -O dtb -o dtc_char_literal.test.dtb char_literal.dts
+    run_dtc_test -I dts -O dtb -o dtc_char_literal.test.dtb "$SRCDIR/char_literal.dts"
     run_test char_literal dtc_char_literal.test.dtb
 
-    run_dtc_test -I dts -O dtb -o dtc_sized_cells.test.dtb sized_cells.dts
+    run_dtc_test -I dts -O dtb -o dtc_sized_cells.test.dtb "$SRCDIR/sized_cells.dts"
     run_test sized_cells dtc_sized_cells.test.dtb
 
-    run_dtc_test -I dts -O dtb -o dtc_extra-terminating-null.test.dtb extra-terminating-null.dts
+    run_dtc_test -I dts -O dtb -o dtc_extra-terminating-null.test.dtb "$SRCDIR/extra-terminating-null.dts"
     run_test extra-terminating-null dtc_extra-terminating-null.test.dtb
 
-    run_dtc_test -I dts -O dtb -o dtc_references.test.dtb references.dts
+    run_dtc_test -I dts -O dtb -o dtc_references.test.dtb "$SRCDIR/references.dts"
     run_test references dtc_references.test.dtb
 
-    run_dtc_test -I dts -O dtb -o dtc_path-references.test.dtb path-references.dts
+    run_dtc_test -I dts -O dtb -o dtc_path-references.test.dtb "$SRCDIR/path-references.dts"
     run_test path-references dtc_path-references.test.dtb
 
     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_dtc_test -I dts -O dtb -H $f -o dtc_references.test.$f.dtb "$SRCDIR/references.dts"
 	run_test phandle_format dtc_references.test.$f.dtb $f
     done
 
-    run_dtc_test -I dts -O dtb -o multilabel.test.dtb multilabel.dts
+    run_dtc_test -I dts -O dtb -o multilabel.test.dtb "$SRCDIR/multilabel.dts"
     run_test references multilabel.test.dtb
 
-    run_dtc_test -I dts -O dtb -o label_repeated.test.dtb label_repeated.dts
+    run_dtc_test -I dts -O dtb -o label_repeated.test.dtb "$SRCDIR/label_repeated.dts"
 
-    run_dtc_test -I dts -O dtb -o dtc_comments.test.dtb comments.dts
-    run_dtc_test -I dts -O dtb -o dtc_comments-cmp.test.dtb comments-cmp.dts
+    run_dtc_test -I dts -O dtb -o dtc_comments.test.dtb "$SRCDIR/comments.dts"
+    run_dtc_test -I dts -O dtb -o dtc_comments-cmp.test.dtb "$SRCDIR/comments-cmp.dts"
     run_test dtbs_equal_ordered dtc_comments.test.dtb dtc_comments-cmp.test.dtb
 
     # Check /include/ directive
-    run_dtc_test -I dts -O dtb -o includes.test.dtb include0.dts
+    run_dtc_test -I dts -O dtb -o includes.test.dtb "$SRCDIR/include0.dts"
     run_test dtbs_equal_ordered includes.test.dtb test_tree1.dtb
 
     # Check /incbin/ directive
-    run_dtc_test -I dts -O dtb -o incbin.test.dtb incbin.dts
-    run_test incbin incbin.test.dtb
+    run_dtc_test -I dts -O dtb -o incbin.test.dtb "$SRCDIR/incbin.dts"
+    run_test incbin "$SRCDIR/incbin.bin" incbin.test.dtb
 
     # Check boot_cpuid_phys handling
-    run_dtc_test -I dts -O dtb -o boot_cpuid.test.dtb boot-cpuid.dts
+    run_dtc_test -I dts -O dtb -o boot_cpuid.test.dtb "$SRCDIR/boot-cpuid.dts"
     run_test boot-cpuid boot_cpuid.test.dtb 16
 
-    run_dtc_test -I dts -O dtb -b 17 -o boot_cpuid_17.test.dtb boot-cpuid.dts
+    run_dtc_test -I dts -O dtb -b 17 -o boot_cpuid_17.test.dtb "$SRCDIR/boot-cpuid.dts"
     run_test boot-cpuid boot_cpuid_17.test.dtb 17
 
     run_dtc_test -I dtb -O dtb -o preserve_boot_cpuid.test.dtb boot_cpuid.test.dtb
@@ -477,9 +601,9 @@
     for tree in test_tree1.dts escapes.dts references.dts path-references.dts \
 	comments.dts aliases.dts include0.dts incbin.dts \
 	value-labels.dts ; do
-	run_dtc_test -I dts -O asm -o oasm_$tree.test.s $tree
+	run_dtc_test -I dts -O asm -o oasm_$tree.test.s "$SRCDIR/$tree"
 	asm_to_so_test oasm_$tree
-	run_dtc_test -I dts -O dtb -o $tree.test.dtb $tree
+	run_dtc_test -I dts -O dtb -o $tree.test.dtb "$SRCDIR/$tree"
 	run_test asm_tree_dump ./oasm_$tree.test.so oasm_$tree.test.dtb
 	run_wrap_test cmp oasm_$tree.test.dtb $tree.test.dtb
     done
@@ -494,6 +618,27 @@
 	run_test dtbs_equal_ordered $tree odts_$tree.test.dtb
     done
 
+    # Check -Odts preserving type information
+    for tree in type-preservation.dts; do
+        run_dtc_test -I dts -O dts -o $tree.test.dts "$SRCDIR/$tree"
+        run_dtc_test -I dts -O dts $tree.test.dts
+        run_wrap_test cmp "$SRCDIR/$tree" $tree.test.dts
+    done
+    for tree in path-references; do
+        run_dtc_test -I dts -O dtb -o $tree.test.dtb "$SRCDIR/$tree.dts"
+        run_dtc_test -I dts -O dts -o $tree.test.dts "$SRCDIR/$tree.dts"
+        run_dtc_test -I dts -O dtb -o $tree.test.dts.test.dtb $tree.test.dts
+        run_test dtbs_equal_ordered $tree.test.dtb $tree.test.dts.test.dtb
+    done
+
+    # Check -Oyaml output
+    if ! $no_yaml; then
+            for tree in type-preservation; do
+                run_dtc_test -I dts -O yaml -o $tree.test.dt.yaml "$SRCDIR/$tree.dts"
+                run_wrap_test cmp "$SRCDIR/$tree.dt.yaml" $tree.test.dt.yaml
+            done
+    fi
+
     # Check version conversions
     for tree in test_tree1.dtb ; do
 	 for aver in 1 2 3 16 17; do
@@ -508,76 +653,104 @@
     done
 
     # Check merge/overlay functionality
-    run_dtc_test -I dts -O dtb -o dtc_tree1_merge.test.dtb test_tree1_merge.dts
+    run_dtc_test -I dts -O dtb -o dtc_tree1_merge.test.dtb "$SRCDIR/test_tree1_merge.dts"
     tree1_tests dtc_tree1_merge.test.dtb test_tree1.dtb
-    run_dtc_test -I dts -O dtb -o dtc_tree1_merge_labelled.test.dtb test_tree1_merge_labelled.dts
+    run_dtc_test -I dts -O dtb -o dtc_tree1_merge_labelled.test.dtb "$SRCDIR/test_tree1_merge_labelled.dts"
     tree1_tests dtc_tree1_merge_labelled.test.dtb test_tree1.dtb
-    run_dtc_test -I dts -O dtb -o dtc_tree1_label_noderef.test.dtb test_tree1_label_noderef.dts
+    run_dtc_test -I dts -O dtb -o dtc_tree1_label_noderef.test.dtb "$SRCDIR/test_tree1_label_noderef.dts"
     run_test dtbs_equal_unordered dtc_tree1_label_noderef.test.dtb test_tree1.dtb
-    run_dtc_test -I dts -O dtb -o multilabel_merge.test.dtb multilabel_merge.dts
+    run_dtc_test -I dts -O dtb -o multilabel_merge.test.dtb "$SRCDIR/multilabel_merge.dts"
     run_test references multilabel.test.dtb
     run_test dtbs_equal_ordered multilabel.test.dtb multilabel_merge.test.dtb
-    run_dtc_test -I dts -O dtb -o dtc_tree1_merge_path.test.dtb test_tree1_merge_path.dts
+    run_dtc_test -I dts -O dtb -o dtc_tree1_merge_path.test.dtb "$SRCDIR/test_tree1_merge_path.dts"
     tree1_tests dtc_tree1_merge_path.test.dtb test_tree1.dtb
-    run_wrap_error_test $DTC -I dts -O dtb -o /dev/null test_label_ref.dts
+    run_wrap_error_test $DTC -I dts -O dtb -o /dev/null "$SRCDIR/test_label_ref.dts"
 
     # Check prop/node delete functionality
-    run_dtc_test -I dts -O dtb -o dtc_tree1_delete.test.dtb test_tree1_delete.dts
+    run_dtc_test -I dts -O dtb -o dtc_tree1_delete.test.dtb "$SRCDIR/test_tree1_delete.dts"
     tree1_tests dtc_tree1_delete.test.dtb
 
-    run_dtc_test -I dts -O dts -o delete_reinstate_multilabel.dts.test.dts delete_reinstate_multilabel.dts
-    run_wrap_test cmp delete_reinstate_multilabel.dts.test.dts delete_reinstate_multilabel_ref.dts
+    # Check omit-if-no-ref functionality
+    run_dtc_test -I dts -O dtb -o omit-no-ref.test.dtb "$SRCDIR/omit-no-ref.dts"
+    run_test check_path omit-no-ref.test.dtb not-exists "/node1"
+    run_test check_path omit-no-ref.test.dtb not-exists "/node2"
+    run_test check_path omit-no-ref.test.dtb exists "/node3"
+    run_test check_path omit-no-ref.test.dtb exists "/node4"
+
+    run_dtc_test -I dts -O dts -o delete_reinstate_multilabel.dts.test.dts "$SRCDIR/delete_reinstate_multilabel.dts"
+    run_wrap_test cmp delete_reinstate_multilabel.dts.test.dts "$SRCDIR/delete_reinstate_multilabel_ref.dts"
 
     # Check some checks
-    check_tests dup-nodename.dts duplicate_node_names
-    check_tests dup-propname.dts duplicate_property_names
-    check_tests dup-phandle.dts explicit_phandles
-    check_tests zero-phandle.dts explicit_phandles
-    check_tests minusone-phandle.dts explicit_phandles
-    run_sh_test dtc-checkfails.sh phandle_references -- -I dts -O dtb nonexist-node-ref.dts
-    run_sh_test dtc-checkfails.sh phandle_references -- -I dts -O dtb nonexist-label-ref.dts
-    run_sh_test dtc-fatal.sh -I dts -O dtb nonexist-node-ref2.dts
-    check_tests bad-name-property.dts name_properties
+    check_tests "$SRCDIR/dup-nodename.dts" duplicate_node_names
+    check_tests "$SRCDIR/dup-propname.dts" duplicate_property_names
+    check_tests "$SRCDIR/dup-phandle.dts" explicit_phandles
+    check_tests "$SRCDIR/zero-phandle.dts" explicit_phandles
+    check_tests "$SRCDIR/minusone-phandle.dts" explicit_phandles
+    run_sh_test "$SRCDIR/dtc-checkfails.sh" phandle_references -- -I dts -O dtb "$SRCDIR/nonexist-node-ref.dts"
+    run_sh_test "$SRCDIR/dtc-checkfails.sh" phandle_references -- -I dts -O dtb "$SRCDIR/nonexist-label-ref.dts"
+    run_sh_test "$SRCDIR/dtc-fatal.sh" -I dts -O dtb "$SRCDIR/nonexist-node-ref2.dts"
+    check_tests "$SRCDIR/bad-name-property.dts" name_properties
 
-    check_tests bad-ncells.dts address_cells_is_cell size_cells_is_cell interrupt_cells_is_cell
-    check_tests bad-string-props.dts device_type_is_string model_is_string status_is_string
-    check_tests bad-reg-ranges.dts reg_format ranges_format
-    check_tests bad-empty-ranges.dts ranges_format
-    check_tests reg-ranges-root.dts reg_format ranges_format
-    check_tests default-addr-size.dts avoid_default_addr_size
-    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
+    check_tests "$SRCDIR/bad-ncells.dts" address_cells_is_cell size_cells_is_cell interrupt_cells_is_cell
+    check_tests "$SRCDIR/bad-string-props.dts" device_type_is_string model_is_string status_is_string label_is_string compatible_is_string_list names_is_string_list
+    check_tests "$SRCDIR/bad-chosen.dts" chosen_node_is_root
+    check_tests "$SRCDIR/bad-chosen.dts" chosen_node_bootargs
+    check_tests "$SRCDIR/bad-chosen.dts" chosen_node_stdout_path
+    check_tests "$SRCDIR/bad-reg-ranges.dts" reg_format ranges_format
+    check_tests "$SRCDIR/bad-empty-ranges.dts" ranges_format
+    check_tests "$SRCDIR/reg-ranges-root.dts" reg_format ranges_format
+    check_tests "$SRCDIR/bad-dma-ranges.dts" dma_ranges_format
+    check_tests "$SRCDIR/default-addr-size.dts" avoid_default_addr_size
+    check_tests "$SRCDIR/obsolete-chosen-interrupt-controller.dts" obsolete_chosen_interrupt_controller
+    check_tests "$SRCDIR/reg-without-unit-addr.dts" unit_address_vs_reg
+    check_tests "$SRCDIR/unit-addr-without-reg.dts" unit_address_vs_reg
+    check_tests "$SRCDIR/unit-addr-leading-0x.dts" unit_address_format
+    check_tests "$SRCDIR/unit-addr-leading-0s.dts" unit_address_format
+    check_tests "$SRCDIR/unit-addr-unique.dts" unique_unit_address
+    check_tests "$SRCDIR/bad-phandle-cells.dts" interrupts_extended_property
+    check_tests "$SRCDIR/bad-gpio.dts" gpios_property
+    check_tests "$SRCDIR/bad-graph.dts" graph_child_address
+    check_tests "$SRCDIR/bad-graph.dts" graph_port
+    check_tests "$SRCDIR/bad-graph.dts" graph_endpoint
+    run_sh_test "$SRCDIR/dtc-checkfails.sh" deprecated_gpio_property -- -Wdeprecated_gpio_property -I dts -O dtb "$SRCDIR/bad-gpio.dts"
+    check_tests "$SRCDIR/bad-interrupt-cells.dts" interrupts_property
+    check_tests "$SRCDIR/bad-interrupt-controller.dts" interrupt_provider
+    run_sh_test "$SRCDIR/dtc-checkfails.sh" node_name_chars -- -I dtb -O dtb bad_node_char.dtb
+    run_sh_test "$SRCDIR/dtc-checkfails.sh" node_name_format -- -I dtb -O dtb bad_node_format.dtb
+    run_sh_test "$SRCDIR/dtc-checkfails.sh" property_name_chars -- -I dtb -O dtb bad_prop_char.dtb
 
-    run_sh_test dtc-checkfails.sh duplicate_label -- -I dts -O dtb reuse-label1.dts
-    run_sh_test dtc-checkfails.sh duplicate_label -- -I dts -O dtb reuse-label2.dts
-    run_sh_test dtc-checkfails.sh duplicate_label -- -I dts -O dtb reuse-label3.dts
-    run_sh_test dtc-checkfails.sh duplicate_label -- -I dts -O dtb reuse-label4.dts
-    run_sh_test dtc-checkfails.sh duplicate_label -- -I dts -O dtb reuse-label5.dts
-    run_sh_test dtc-checkfails.sh duplicate_label -- -I dts -O dtb reuse-label6.dts
+    run_sh_test "$SRCDIR/dtc-checkfails.sh" duplicate_label -- -I dts -O dtb "$SRCDIR/reuse-label1.dts"
+    run_sh_test "$SRCDIR/dtc-checkfails.sh" duplicate_label -- -I dts -O dtb "$SRCDIR/reuse-label2.dts"
+    run_sh_test "$SRCDIR/dtc-checkfails.sh" duplicate_label -- -I dts -O dtb "$SRCDIR/reuse-label3.dts"
+    run_sh_test "$SRCDIR/dtc-checkfails.sh" duplicate_label -- -I dts -O dtb "$SRCDIR/reuse-label4.dts"
+    run_sh_test "$SRCDIR/dtc-checkfails.sh" duplicate_label -- -I dts -O dtb "$SRCDIR/reuse-label5.dts"
+    run_sh_test "$SRCDIR/dtc-checkfails.sh" duplicate_label -- -I dts -O dtb "$SRCDIR/reuse-label6.dts"
 
     run_test check_path test_tree1.dtb exists "/subnode@1"
     run_test check_path test_tree1.dtb not-exists "/subnode@10"
 
+    check_tests "$SRCDIR/pci-bridge-ok.dts" -n pci_bridge
+    check_tests "$SRCDIR/pci-bridge-bad1.dts" pci_bridge
+    check_tests "$SRCDIR/pci-bridge-bad2.dts" pci_bridge
+
+    check_tests "$SRCDIR/unit-addr-simple-bus-reg-mismatch.dts" simple_bus_reg
+    check_tests "$SRCDIR/unit-addr-simple-bus-compatible.dts" simple_bus_reg
+
+
     # Check warning options
-    run_sh_test dtc-checkfails.sh address_cells_is_cell interrupt_cells_is_cell -n size_cells_is_cell -- -Wno_size_cells_is_cell -I dts -O dtb bad-ncells.dts
-    run_sh_test dtc-fails.sh -n test-warn-output.test.dtb -I dts -O dtb bad-ncells.dts
-    run_sh_test dtc-fails.sh test-error-output.test.dtb -I dts -O dtb bad-ncells.dts -Esize_cells_is_cell
-    run_sh_test dtc-checkfails.sh always_fail -- -Walways_fail -I dts -O dtb test_tree1.dts
-    run_sh_test dtc-checkfails.sh -n always_fail -- -Walways_fail -Wno_always_fail -I dts -O dtb test_tree1.dts
-    run_sh_test dtc-fails.sh test-negation-1.test.dtb -Ealways_fail -I dts -O dtb test_tree1.dts
-    run_sh_test dtc-fails.sh -n test-negation-2.test.dtb -Ealways_fail -Eno_always_fail -I dts -O dtb test_tree1.dts
-    run_sh_test dtc-fails.sh test-negation-3.test.dtb -Ealways_fail -Wno_always_fail -I dts -O dtb test_tree1.dts
-    run_sh_test dtc-fails.sh -n test-negation-4.test.dtb -Esize_cells_is_cell -Eno_size_cells_is_cell -I dts -O dtb bad-ncells.dts
-    run_sh_test dtc-checkfails.sh size_cells_is_cell -- -Esize_cells_is_cell -Eno_size_cells_is_cell -I dts -O dtb bad-ncells.dts
+    run_sh_test "$SRCDIR/dtc-checkfails.sh" address_cells_is_cell interrupt_cells_is_cell -n size_cells_is_cell -- -Wno_size_cells_is_cell -I dts -O dtb "$SRCDIR/bad-ncells.dts"
+    run_sh_test "$SRCDIR/dtc-fails.sh" -n test-warn-output.test.dtb -I dts -O dtb "$SRCDIR/bad-ncells.dts"
+    run_sh_test "$SRCDIR/dtc-fails.sh" test-error-output.test.dtb -I dts -O dtb bad-ncells.dts -Esize_cells_is_cell
+    run_sh_test "$SRCDIR/dtc-checkfails.sh" always_fail -- -Walways_fail -I dts -O dtb "$SRCDIR/test_tree1.dts"
+    run_sh_test "$SRCDIR/dtc-checkfails.sh" -n always_fail -- -Walways_fail -Wno_always_fail -I dts -O dtb "$SRCDIR/test_tree1.dts"
+    run_sh_test "$SRCDIR/dtc-fails.sh" test-negation-1.test.dtb -Ealways_fail -I dts -O dtb "$SRCDIR/test_tree1.dts"
+    run_sh_test "$SRCDIR/dtc-fails.sh" -n test-negation-2.test.dtb -Ealways_fail -Eno_always_fail -I dts -O dtb "$SRCDIR/test_tree1.dts"
+    run_sh_test "$SRCDIR/dtc-fails.sh" test-negation-3.test.dtb -Ealways_fail -Wno_always_fail -I dts -O dtb "$SRCDIR/test_tree1.dts"
+    run_sh_test "$SRCDIR/dtc-fails.sh" -n test-negation-4.test.dtb -Esize_cells_is_cell -Eno_size_cells_is_cell -I dts -O dtb "$SRCDIR/bad-ncells.dts"
+    run_sh_test "$SRCDIR/dtc-checkfails.sh" size_cells_is_cell -- -Esize_cells_is_cell -Eno_size_cells_is_cell -I dts -O dtb "$SRCDIR/bad-ncells.dts"
 
     # Check for proper behaviour reading from stdin
-    run_dtc_test -I dts -O dtb -o stdin_dtc_tree1.test.dtb - < test_tree1.dts
+    run_dtc_test -I dts -O dtb -o stdin_dtc_tree1.test.dtb - < "$SRCDIR/test_tree1.dts"
     run_wrap_test cmp stdin_dtc_tree1.test.dtb dtc_tree1.test.dtb
     run_dtc_test -I dtb -O dts -o stdin_odts_test_tree1.dtb.test.dts - < test_tree1.dtb
     run_wrap_test cmp stdin_odts_test_tree1.dtb.test.dts odts_test_tree1.dtb.test.dts
@@ -588,33 +761,34 @@
     run_test integer-expressions integer-expressions.test.dtb
 
     # Check for graceful failure in some error conditions
-    run_sh_test dtc-fatal.sh -I dts -O dtb nosuchfile.dts
-    run_sh_test dtc-fatal.sh -I dtb -O dtb nosuchfile.dtb
-    run_sh_test dtc-fatal.sh -I fs -O dtb nosuchfile
+    run_sh_test "$SRCDIR/dtc-fatal.sh" -I dts -O dtb nosuchfile.dts
+    run_sh_test "$SRCDIR/dtc-fatal.sh" -I dtb -O dtb nosuchfile.dtb
+    run_sh_test "$SRCDIR/dtc-fatal.sh" -I fs -O dtb nosuchfile
 
     # Dependencies
-    run_dtc_test -I dts -O dtb -o dependencies.test.dtb -d dependencies.test.d dependencies.dts
-    run_wrap_test cmp dependencies.test.d dependencies.cmp
+    run_dtc_test -I dts -O dtb -o dependencies.test.dtb -d dependencies.test.d "$SRCDIR/dependencies.dts"
+    sed -i.bak "s,$SRCDIR/,,g" dependencies.test.d
+    run_wrap_test cmp dependencies.test.d "$SRCDIR/dependencies.cmp"
 
     # Search paths
-    run_wrap_error_test $DTC -I dts -O dtb -o search_paths.dtb search_paths.dts
-    run_dtc_test -i search_dir -I dts -O dtb -o search_paths.dtb \
-	search_paths.dts
-    run_wrap_error_test $DTC -i search_dir_b -I dts -O dtb \
-	-o search_paths_b.dtb search_paths_b.dts
-    run_dtc_test -i search_dir_b -i search_dir -I dts -O dtb \
-	-o search_paths_b.dtb search_paths_b.dts
+    run_wrap_error_test $DTC -I dts -O dtb -o search_paths.dtb "$SRCDIR/search_paths.dts"
+    run_dtc_test -i "$SRCDIR/search_dir" -I dts -O dtb -o search_paths.dtb \
+	"$SRCDIR/search_paths.dts"
+    run_wrap_error_test $DTC -i "$SRCDIR/search_dir_b" -I dts -O dtb \
+	-o search_paths_b.dtb "$SRCDIR/search_paths_b.dts"
+    run_dtc_test -i "$SRCDIR/search_dir_b" -i "$SRCDIR/search_dir" -I dts -O dtb \
+	-o search_paths_b.dtb "$SRCDIR/search_paths_b.dts"
     run_dtc_test -I dts -O dtb -o search_paths_subdir.dtb \
-	search_dir_b/search_paths_subdir.dts
+	"$SRCDIR/search_dir_b/search_paths_subdir.dts"
 
     # Check -a option
     for align in 2 4 8 16 32 64; do
 	# -p -a
-	run_dtc_test -O dtb -p 1000 -a $align -o align0.dtb subnode_iterate.dts
-	check_align align0.dtb $align
+	run_dtc_test -O dtb -p 1000 -a $align -o align0.dtb "$SRCDIR/subnode_iterate.dts"
+	base_run_test check_align align0.dtb $align
 	# -S -a
-	run_dtc_test -O dtb -S 1999 -a $align -o align1.dtb subnode_iterate.dts
-	check_align align1.dtb $align
+	run_dtc_test -O dtb -S 1999 -a $align -o align1.dtb "$SRCDIR/subnode_iterate.dts"
+	base_run_test check_align align1.dtb $align
     done
 
     # Tests for overlay/plugin generation
@@ -654,7 +828,7 @@
 dtbs_equal_tests () {
     WRONG_TREE1=""
     for x in 1 2 3 4 5 6 7 8 9; do
-	run_dtc_test -I dts -O dtb -o test_tree1_wrong$x.test.dtb test_tree1_wrong$x.dts
+	run_dtc_test -I dts -O dtb -o test_tree1_wrong$x.test.dtb "$SRCDIR/test_tree1_wrong$x.dts"
 	WRONG_TREE1="$WRONG_TREE1 test_tree1_wrong$x.test.dtb"
     done
     cmp_tests test_tree1.dtb $WRONG_TREE1
@@ -663,7 +837,7 @@
 fdtget_tests () {
     dts=label01.dts
     dtb=$dts.fdtget.test.dtb
-    run_dtc_test -O dtb -o $dtb $dts
+    run_dtc_test -O dtb -o $dtb "$SRCDIR/$dts"
 
     # run_fdtget_test <expected-result> [<flags>] <file> <node> <property>
     run_fdtget_test "MyBoardName" $dtb / model
@@ -697,10 +871,10 @@
 fdtput_tests () {
     dts=label01.dts
     dtb=$dts.fdtput.test.dtb
-    text=lorem.txt
+    text="$SRCDIR/lorem.txt"
 
     # Allow just enough space for $text
-    run_dtc_test -O dtb -p $(stat -c %s $text) -o $dtb $dts
+    run_dtc_test -O dtb -p $($STATSZ $text) -o $dtb "$SRCDIR/$dts"
 
     # run_fdtput_test <expected-result> <file> <node> <property> <flags> <value>
     run_fdtput_test "a_model" $dtb / model -ts "a_model"
@@ -719,7 +893,7 @@
     run_fdtput_test "$(cat $text $text)" $dtb /randomnode blob -ts "$(cat $text $text)"
 
     # Start again with a fresh dtb
-    run_dtc_test -O dtb -p $(stat -c %s $text) -o $dtb $dts
+    run_dtc_test -O dtb -p $($STATSZ $text) -o $dtb "$SRCDIR/$dts"
 
     # Node creation
     run_wrap_error_test $DTPUT $dtb -c /baldrick sod
@@ -739,7 +913,7 @@
 	"-ts" "fine wine"
     run_wrap_test $DTPUT $dtb -p /you/are/drunk/sir/winston slurp -ts twice
 
-    # Test expansion of the blob when insufficent room for a new node
+    # Test expansion of the blob when insufficient room for a new node
     run_wrap_test $DTPUT $dtb -cp "$(cat $text $text)/longish"
 
     # Allowed to create an existing node with -p
@@ -747,7 +921,7 @@
     run_wrap_test $DTPUT $dtb -cp /chosen/son
 
     # Start again with a fresh dtb
-    run_dtc_test -O dtb -p $(stat -c %s $text) -o $dtb $dts
+    run_dtc_test -O dtb -p $($STATSZ $text) -o $dtb "$SRCDIR/$dts"
 
     # Node delete
     run_wrap_test $DTPUT $dtb -c /chosen/node1 /chosen/node2 /chosen/node3
@@ -776,13 +950,13 @@
 }
 
 fdtdump_tests () {
-    run_fdtdump_test fdtdump.dts
+    run_fdtdump_test "$SRCDIR/fdtdump.dts"
 }
 
 fdtoverlay_tests() {
-    base=overlay_base.dts
+    base="$SRCDIR/overlay_base.dts"
     basedtb=overlay_base.fdoverlay.test.dtb
-    overlay=overlay_overlay_manual_fixups.dts
+    overlay="$SRCDIR/overlay_overlay_manual_fixups.dts"
     overlaydtb=overlay_overlay_manual_fixups.fdoverlay.test.dtb
     targetdtb=target.fdoverlay.test.dtb
 
@@ -791,17 +965,57 @@
 
     # test that the new property is installed
     run_fdtoverlay_test foobar "/test-node" "test-str-property" "-ts" ${basedtb} ${targetdtb} ${overlaydtb}
+
+    stacked_base="$SRCDIR/stacked_overlay_base.dts"
+    stacked_basedtb=stacked_overlay_base.fdtoverlay.test.dtb
+    stacked_bar="$SRCDIR/stacked_overlay_bar.dts"
+    stacked_bardtb=stacked_overlay_bar.fdtoverlay.test.dtb
+    stacked_baz="$SRCDIR/stacked_overlay_baz.dts"
+    stacked_bazdtb=stacked_overlay_baz.fdtoverlay.test.dtb
+    stacked_targetdtb=stacked_overlay_target.fdtoverlay.test.dtb
+
+    run_dtc_test -@ -I dts -O dtb -o $stacked_basedtb $stacked_base
+    run_dtc_test -@ -I dts -O dtb -o $stacked_bardtb $stacked_bar
+    run_dtc_test -@ -I dts -O dtb -o $stacked_bazdtb $stacked_baz
+
+    # test that baz correctly inserted the property
+    run_fdtoverlay_test baz "/foonode/barnode/baznode" "baz-property" "-ts" ${stacked_basedtb} ${stacked_targetdtb} ${stacked_bardtb} ${stacked_bazdtb}
+
+    # test that bar and baz are correctly appended to __symbols__
+    run_fdtoverlay_test "/foonode/barnode" "/__symbols__"  "bar" "-ts" ${stacked_basedtb} ${stacked_targetdtb} ${stacked_bardtb}
+    run_fdtoverlay_test "/foonode/barnode/baznode" "/__symbols__"  "baz" "-ts" ${stacked_basedtb} ${stacked_targetdtb} ${stacked_bardtb} ${stacked_bazdtb}
+
+    overlay_long_path="$SRCDIR/overlay_overlay_long_path.dts"
+    overlay_long_pathdtb=overlay_overlay_long_path.fdoverlay.test.dtb
+    target_long_pathdtb=overlay_overlay_long_path_target.fdoverlay.test.dtb
+    run_dtc_test -@ -I dts -O dtb -o $overlay_long_pathdtb $overlay_long_path
+
+    # test that fdtoverlay manages to apply overlays with long target path
+    run_fdtoverlay_test lpath "/test-node/sub-test-node/sub-test-node-with-very-long-target-path/test-0" "prop" "-ts" ${basedtb} ${target_long_pathdtb} ${overlay_long_pathdtb}
+
+    # test adding a label to the root of a fragment
+    stacked_base_nolabel="$SRCDIR/stacked_overlay_base_nolabel.dts"
+    stacked_base_nolabeldtb=stacked_overlay_base_nolabel.test.dtb
+    stacked_addlabel="$SRCDIR/stacked_overlay_addlabel.dts"
+    stacked_addlabeldtb=stacked_overlay_addlabel.test.dtb
+    stacked_addlabel_targetdtb=stacked_overlay_target_nolabel.fdtoverlay.test.dtb
+
+    run_dtc_test -@ -I dts -O dtb -o $stacked_base_nolabeldtb $stacked_base_nolabel
+    run_dtc_test -@ -I dts -O dtb -o $stacked_addlabeldtb $stacked_addlabel
+
+    run_fdtoverlay_test baz "/foonode/barnode/baznode" "baz-property" "-ts" ${stacked_base_nolabeldtb} ${stacked_addlabel_targetdtb} ${stacked_addlabeldtb} ${stacked_bardtb} ${stacked_bazdtb}
 }
 
 pylibfdt_tests () {
+    run_dtc_test -I dts -O dtb -o test_props.dtb "$SRCDIR/test_props.dts"
     TMP=/tmp/tests.stderr.$$
-    python pylibfdt_tests.py -v 2> $TMP
+    $PYTHON "$SRCDIR/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)
+    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
@@ -834,7 +1048,7 @@
     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
+    if ! $no_python; then
         TESTSETS="$TESTSETS pylibfdt"
     fi
 fi
@@ -885,3 +1099,4 @@
 echo "* Strange test result:	$tot_strange"
 echo "**********"
 
+[ "$tot_tests" -eq "$tot_pass" ] || exit 1
diff --git a/tests/rw_oom.c b/tests/rw_oom.c
new file mode 100644
index 0000000..39fc312
--- /dev/null
+++ b/tests/rw_oom.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ * libfdt - Flat Device Tree manipulation
+ *	Testcase for fdt_nop_node()
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+/* This is not derived programmatically. May require adjustment to changes. */
+#define SPACE	285
+
+#define CHECK(code) \
+	{ \
+		err = (code); \
+		if (err) \
+			FAIL(#code ": %s", fdt_strerror(err)); \
+	}
+
+#define OFF_CHECK(off, code) \
+	{ \
+		(off) = (code); \
+		if (off < 0) \
+			FAIL(#code ": %s", fdt_strerror(off)); \
+	}
+
+int main(int argc, char *argv[])
+{
+	void *fdt;
+	int err;
+	int offset, s1;
+	int strsize1, strsize2;
+
+	/*
+	 * Check OOM path, and check that property is cleaned up if it fails
+	 * with OOM, rather than adding an orphan name.
+	 *
+	 * SW OOM is tested with the realloc/resize strategies.
+	 */
+	test_init(argc, argv);
+
+	fdt = xmalloc(SPACE);
+
+	/* First create empty tree with SW */
+	CHECK(fdt_create_empty_tree(fdt, SPACE));
+
+	CHECK(fdt_add_mem_rsv(fdt, TEST_ADDR_1, TEST_SIZE_1));
+	CHECK(fdt_add_mem_rsv(fdt, TEST_ADDR_2, TEST_SIZE_2));
+
+	CHECK(fdt_setprop_string(fdt, 0, "compatible", "test_oom"));
+	CHECK(fdt_setprop_u32(fdt, 0, "prop-int", TEST_VALUE_1));
+	CHECK(fdt_setprop_u64(fdt, 0, "prop-int64", TEST_VALUE64_1));
+	CHECK(fdt_setprop_string(fdt, 0, "prop-str", TEST_STRING_1));
+
+	OFF_CHECK(offset, fdt_add_subnode(fdt, 0, "subnode@1"));
+	s1 = offset;
+
+	strsize1 = fdt_size_dt_strings(fdt);
+	err = fdt_setprop_string(fdt, s1, "unique", "subnode1");
+	if (err != -FDT_ERR_NOSPACE)
+		FAIL("fdt_setprop_string(fdt, s1, \"compatible\", \"subnode1\"): %s", fdt_strerror(err));
+	strsize2 = fdt_size_dt_strings(fdt);
+
+	if (strsize1 != strsize2)
+		FAIL("fdt_setprop NOSPACE error failed to clean up allocated string\n");
+	err = 0;
+
+	/* Ensure we failed in the right place */
+	CHECK(fdt_setprop_string(fdt, s1, "unique", ""));
+
+	CHECK(fdt_pack(fdt));
+
+	PASS();
+}
diff --git a/tests/rw_tree1.c b/tests/rw_tree1.c
index efd4718..1fe2351 100644
--- a/tests/rw_tree1.c
+++ b/tests/rw_tree1.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_nop_node()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
diff --git a/tests/set_name.c b/tests/set_name.c
index 9861587..a62cb58 100644
--- a/tests/set_name.c
+++ b/tests/set_name.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_set_name()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 #include <stdlib.h>
 #include <stdio.h>
diff --git a/tests/setprop.c b/tests/setprop.c
index be1b147..fa3938d 100644
--- a/tests/setprop.c
+++ b/tests/setprop.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_setprop()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
diff --git a/tests/setprop_inplace.c b/tests/setprop_inplace.c
index 80447a0..7e1198d 100644
--- a/tests/setprop_inplace.c
+++ b/tests/setprop_inplace.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_setprop_inplace()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <inttypes.h>
diff --git a/tests/sized_cells.c b/tests/sized_cells.c
index 0b2b8dc..9ca5a59 100644
--- a/tests/sized_cells.c
+++ b/tests/sized_cells.c
@@ -1,22 +1,9 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for variable sized cells in dtc
  * Copyright (C) 2006 David Gibson, IBM Corporation.
  * Copyright (C) 2011 The Chromium Authors. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 #include <stdlib.h>
 #include <stdio.h>
diff --git a/tests/sourceoutput.dts b/tests/sourceoutput.dts
index 477762f..5a7459b 100644
--- a/tests/sourceoutput.dts
+++ b/tests/sourceoutput.dts
@@ -2,7 +2,7 @@
 
 / {
 	/* Some versions had an off-by-2 bug which caused an abort
-	 * when outputing labels within strings like this in source
+	 * when outputting labels within strings like this in source
 	 * format */
 	prop1: prop1 = start1: "foo", mid1: "bar" end1: ;
 
diff --git a/tests/stacked_overlay_addlabel.dts b/tests/stacked_overlay_addlabel.dts
new file mode 100644
index 0000000..e7187a3
--- /dev/null
+++ b/tests/stacked_overlay_addlabel.dts
@@ -0,0 +1,15 @@
+/dts-v1/;
+/plugin/;
+/ {
+	frag1: fragment@1 {
+		target-path = "/foonode";
+		local: localinfo {
+		};
+		foo: __overlay__ {
+			overlay-1-property;
+			bar: barnode {
+				bar-property = "bar";
+			};
+		};
+	};
+};
diff --git a/tests/stacked_overlay_bar.dts b/tests/stacked_overlay_bar.dts
new file mode 100644
index 0000000..c646399
--- /dev/null
+++ b/tests/stacked_overlay_bar.dts
@@ -0,0 +1,13 @@
+/dts-v1/;
+/plugin/;
+/ {
+	fragment@1 {
+		target = <&foo>;
+		__overlay__ {
+			overlay-1-property;
+			bar: barnode {
+				bar-property = "bar";
+			};
+		};
+	};
+};
diff --git a/tests/stacked_overlay_base.dts b/tests/stacked_overlay_base.dts
new file mode 100644
index 0000000..2916423
--- /dev/null
+++ b/tests/stacked_overlay_base.dts
@@ -0,0 +1,6 @@
+/dts-v1/;
+/ {
+	foo: foonode {
+		foo-property = "foo";
+	};
+};
diff --git a/tests/stacked_overlay_base_nolabel.dts b/tests/stacked_overlay_base_nolabel.dts
new file mode 100644
index 0000000..0c47f0d
--- /dev/null
+++ b/tests/stacked_overlay_base_nolabel.dts
@@ -0,0 +1,6 @@
+/dts-v1/;
+/ {
+	foonode {
+		foo-property = "foo";
+	};
+};
diff --git a/tests/stacked_overlay_baz.dts b/tests/stacked_overlay_baz.dts
new file mode 100644
index 0000000..a52f0cc
--- /dev/null
+++ b/tests/stacked_overlay_baz.dts
@@ -0,0 +1,13 @@
+/dts-v1/;
+/plugin/;
+/ {
+	fragment@1 {
+		target = <&bar>;
+		__overlay__ {
+			overlay-2-property;
+			baz: baznode {
+				baz-property = "baz";
+			};
+		};
+	};
+};
diff --git a/tests/string_escapes.c b/tests/string_escapes.c
index 8cdee4b..53c9dfc 100644
--- a/tests/string_escapes.c
+++ b/tests/string_escapes.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for string escapes in dtc
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 #include <stdlib.h>
 #include <stdio.h>
diff --git a/tests/stringlist.c b/tests/stringlist.c
index a9d3e73..bbc3020 100644
--- a/tests/stringlist.c
+++ b/tests/stringlist.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for string handling
  * Copyright (C) 2015 NVIDIA Corporation
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
@@ -60,10 +47,11 @@
 		FAIL("empty string not found in #address-cells: %d\n", err);
 
 	/*
-	 * fdt_get_string() can successfully extract strings from non-string
-	 * properties. This is because it doesn't necessarily parse the whole
-	 * property value, which would be necessary for it to determine if a
-	 * valid string or string list is present.
+	 * fdt_getprop_string() can successfully extract strings from
+	 * non-string properties. This is because it doesn't
+	 * necessarily parse the whole property value, which would be
+	 * necessary for it to determine if a valid string or string
+	 * list is present.
 	 */
 }
 
diff --git a/tests/subnode_iterate.c b/tests/subnode_iterate.c
index 7be5706..2dc9b2d 100644
--- a/tests/subnode_iterate.c
+++ b/tests/subnode_iterate.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Tests that fdt_next_subnode() works as expected
@@ -5,20 +6,6 @@
  * Copyright (C) 2013 Google, Inc
  *
  * Copyright (C) 2007 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
diff --git a/tests/subnode_offset.c b/tests/subnode_offset.c
index 231fcb5..1362f99 100644
--- a/tests/subnode_offset.c
+++ b/tests/subnode_offset.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_subnode_offset()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 #include <stdlib.h>
 #include <stdio.h>
diff --git a/tests/supernode_atdepth_offset.c b/tests/supernode_atdepth_offset.c
index 43e120d..4435b49 100644
--- a/tests/supernode_atdepth_offset.c
+++ b/tests/supernode_atdepth_offset.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_supernode_atdepth_offset()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 #include <stdlib.h>
 #include <stdio.h>
diff --git a/tests/sw_states.c b/tests/sw_states.c
new file mode 100644
index 0000000..42d57ae
--- /dev/null
+++ b/tests/sw_states.c
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ * libfdt - Flat Device Tree manipulation
+ *	Testcase for error handling with sequential write states
+ * Copyright (C) 2018 David Gibson, Red Hat Inc.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+#define SPACE	65536
+
+#define CHECK_OK(code)							\
+	do {								\
+		verbose_printf(" OK: %s\n", #code);			\
+		err = (code);						\
+		if (err)						\
+			FAIL(#code ": %s", fdt_strerror(err));		\
+	} while (0)
+
+#define CHECK_BADSTATE(code)						\
+	do {								\
+		verbose_printf("BAD: %s\n", #code);			\
+		err = (code);						\
+		if (err == 0)						\
+			FAIL(#code ": succeeded in bad state");		\
+		else if (err != -FDT_ERR_BADSTATE)			\
+			FAIL(#code ": %s", fdt_strerror(err));		\
+	} while (0)
+
+int main(int argc, char *argv[])
+{
+	void *fdt = NULL;
+	int err;
+
+	test_init(argc, argv);
+
+	fdt = xmalloc(SPACE);
+
+	err = fdt_create(fdt, SPACE);
+	if (err)
+		FAIL("fdt_create(): %s", fdt_strerror(err));
+
+	/* Memory reserve state */
+
+	CHECK_BADSTATE(fdt_begin_node(fdt, ""));
+	CHECK_BADSTATE(fdt_property_string(fdt, "bad-str", "TEST_STRING_1"));
+	CHECK_BADSTATE(fdt_end_node(fdt));
+	CHECK_BADSTATE(fdt_finish(fdt));
+
+	CHECK_OK(fdt_add_reservemap_entry(fdt, TEST_ADDR_1, TEST_SIZE_1));
+	CHECK_OK(fdt_add_reservemap_entry(fdt, TEST_ADDR_2, TEST_SIZE_2));
+
+	CHECK_BADSTATE(fdt_begin_node(fdt, ""));
+	CHECK_BADSTATE(fdt_property_string(fdt, "bad-str", "TEST_STRING_1"));
+	CHECK_BADSTATE(fdt_end_node(fdt));
+	CHECK_BADSTATE(fdt_finish(fdt));
+
+	CHECK_OK(fdt_finish_reservemap(fdt));
+
+	/* Structure state */
+
+	CHECK_BADSTATE(fdt_add_reservemap_entry(fdt, TEST_ADDR_1, TEST_SIZE_1));
+	CHECK_BADSTATE(fdt_finish_reservemap(fdt));
+
+	CHECK_OK(fdt_begin_node(fdt, ""));
+	CHECK_OK(fdt_property_string(fdt, "compatible", "test_tree1"));
+	CHECK_OK(fdt_property_u32(fdt, "prop-int", TEST_VALUE_1));
+	CHECK_OK(fdt_property_u64(fdt, "prop-int64", TEST_VALUE64_1));
+	CHECK_OK(fdt_property_string(fdt, "prop-str", TEST_STRING_1));
+	CHECK_OK(fdt_property_u32(fdt, "#address-cells", 1));
+	CHECK_OK(fdt_property_u32(fdt, "#size-cells", 0));
+
+	CHECK_OK(fdt_begin_node(fdt, "subnode@1"));
+	CHECK_OK(fdt_property_string(fdt, "compatible", "subnode1"));
+	CHECK_OK(fdt_property_u32(fdt, "reg", 1));
+	CHECK_OK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_1));
+	CHECK_OK(fdt_begin_node(fdt, "subsubnode"));
+	CHECK_OK(fdt_property(fdt, "compatible", "subsubnode1\0subsubnode",
+			   23));
+	CHECK_OK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_1));
+	CHECK_OK(fdt_end_node(fdt));
+	CHECK_OK(fdt_begin_node(fdt, "ss1"));
+	CHECK_OK(fdt_end_node(fdt));
+	CHECK_OK(fdt_end_node(fdt));
+
+	CHECK_OK(fdt_begin_node(fdt, "subnode@2"));
+	CHECK_OK(fdt_property_u32(fdt, "reg", 2));
+	CHECK_OK(fdt_property_cell(fdt, "linux,phandle", PHANDLE_1));
+	CHECK_OK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_2));
+	CHECK_OK(fdt_property_u32(fdt, "#address-cells", 1));
+	CHECK_OK(fdt_property_u32(fdt, "#size-cells", 0));
+	CHECK_OK(fdt_begin_node(fdt, "subsubnode@0"));
+	CHECK_OK(fdt_property_u32(fdt, "reg", 0));
+	CHECK_OK(fdt_property_cell(fdt, "phandle", PHANDLE_2));
+	CHECK_OK(fdt_property(fdt, "compatible", "subsubnode2\0subsubnode",
+			   23));
+	CHECK_OK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_2));
+	CHECK_OK(fdt_end_node(fdt));
+	CHECK_OK(fdt_begin_node(fdt, "ss2"));
+	CHECK_OK(fdt_end_node(fdt));
+
+	CHECK_OK(fdt_end_node(fdt));
+
+	CHECK_OK(fdt_end_node(fdt));
+
+	CHECK_OK(fdt_finish(fdt));
+
+	/* Completed state */
+
+	CHECK_BADSTATE(fdt_add_reservemap_entry(fdt, TEST_ADDR_1, TEST_SIZE_1));
+	CHECK_BADSTATE(fdt_finish_reservemap(fdt));
+	CHECK_BADSTATE(fdt_begin_node(fdt, ""));
+	CHECK_BADSTATE(fdt_property_string(fdt, "bad-str", "TEST_STRING_1"));
+	CHECK_BADSTATE(fdt_end_node(fdt));
+	CHECK_BADSTATE(fdt_finish(fdt));
+
+	PASS();
+}
diff --git a/tests/sw_tree1.c b/tests/sw_tree1.c
index 6a338fc..7069ace 100644
--- a/tests/sw_tree1.c
+++ b/tests/sw_tree1.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for fdt_nop_node()
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
@@ -35,10 +22,13 @@
 	FIXED = 0,
 	RESIZE,
 	REALLOC,
+	NEWALLOC,
 } alloc_mode;
 
 static void realloc_fdt(void **fdt, size_t *size, bool created)
 {
+	int err;
+
 	switch (alloc_mode) {
 	case FIXED:
 		if (!(*fdt))
@@ -52,7 +42,10 @@
 			*fdt = xmalloc(SPACE);
 		} else if (*size < SPACE) {
 			*size += 1;
-			fdt_resize(*fdt, *fdt, *size);
+			err = fdt_resize(*fdt, *fdt, *size);
+			if (err < 0)
+				FAIL("fdt_resize() failed: %s",
+				     fdt_strerror(err));
 		} else {
 			FAIL("Ran out of space");
 		}		
@@ -61,10 +54,30 @@
 	case REALLOC:
 		*size += 1;
 		*fdt = xrealloc(*fdt, *size);
-		if (created)
-			fdt_resize(*fdt, *fdt, *size);
+		if (created) {
+			err = fdt_resize(*fdt, *fdt, *size);
+			if (err < 0)
+				FAIL("fdt_resize() failed: %s",
+				     fdt_strerror(err));
+		}
 		return;
 
+	case NEWALLOC: {
+		void *buf;
+
+		*size += 1;
+		buf = xmalloc(*size);
+		if (created) {
+			err = fdt_resize(*fdt, buf, *size);
+			if (err < 0)
+				FAIL("fdt_resize() failed: %s",
+				     fdt_strerror(err));
+		}
+		free(*fdt);
+		*fdt = buf;
+		return;
+	}
+
 	default:
 		CONFIG("Bad allocation mode");
 	}
@@ -88,19 +101,27 @@
 	void *place;
 	const char place_str[] = "this is a placeholder string\0string2";
 	int place_len = sizeof(place_str);
+	int create_flags;
 
 	test_init(argc, argv);
 
-	if (argc == 1) {
-		alloc_mode = FIXED;
-		size = SPACE;
-	} else if (argc == 2) {
-		if (streq(argv[1], "resize")) {
+	alloc_mode = FIXED;
+	size = SPACE;
+	create_flags = 0;
+
+	if (argc == 2 || argc == 3) {
+		if (streq(argv[1], "fixed")) {
+			alloc_mode = FIXED;
+			size = SPACE;
+		} else if (streq(argv[1], "resize")) {
 			alloc_mode = REALLOC;
 			size = 0;
 		} else if (streq(argv[1], "realloc")) {
 			alloc_mode = REALLOC;
 			size = 0;
+		} else if (streq(argv[1], "newalloc")) {
+			alloc_mode = NEWALLOC;
+			size = 0;
 		} else {
 			char *endp;
 
@@ -112,9 +133,35 @@
 				       argv[1]);
 		}
 	}
+	if (argc == 3) {
+		char *str = argv[2], *saveptr, *tok;
+		bool default_flag = false;
+
+		while ((tok = strtok_r(str, ",", &saveptr)) != NULL) {
+			str = NULL;
+			if (streq(tok, "default")) {
+				default_flag = true;
+			} else if (streq(tok, "no_name_dedup")) {
+				create_flags |= FDT_CREATE_FLAG_NO_NAME_DEDUP;
+			} else if (streq(tok, "bad")) {
+				create_flags |= 0xffffffff;
+			} else {
+				CONFIG("Bad creation flags \"%s\" specified",
+				       argv[2]);
+			}
+		}
+
+		if (default_flag && create_flags != 0)
+			CONFIG("Bad creation flags \"%s\" specified",
+			       argv[2]);
+	}
+
+	if (argc > 3) {
+		CONFIG("sw_tree1 [<allocation mode>] [<create flags>]");
+	}
 
 	fdt = xmalloc(size);
-	CHECK(fdt_create(fdt, size));
+	CHECK(fdt_create_with_flags(fdt, size, create_flags));
 
 	created = true;
 
diff --git a/tests/sw_tree1.supp b/tests/sw_tree1.supp
deleted file mode 100644
index 279f9e5..0000000
--- a/tests/sw_tree1.supp
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-   allocation methods causes uninitialized data in alignment gap
-   Memcheck:Param
-   write(buf)
-   fun:__write_nocancel
-   fun:utilfdt_write_err
-   fun:save_blob
-   fun:main
-}
-{
-   allocation methods causes uninitialized data in alignment gap
-   Memcheck:Param
-   write(buf)
-   fun:__write_nocancel
-   fun:utilfdt_write_err
-   fun:save_blob
-   fun:main
-}
diff --git a/tests/test_props.dts b/tests/test_props.dts
new file mode 100644
index 0000000..7e59bd1
--- /dev/null
+++ b/tests/test_props.dts
@@ -0,0 +1,11 @@
+/dts-v1/;
+
+/ {
+	compatible = "test_props";
+	prop-hex32 = <0xdeadbeef>;
+	prop-uint32 = <123>;
+	prop-int32 = <0xfffffffe>;
+	prop-hex64 = /bits/ 64 <0xdeadbeef01abcdef>;
+	prop-uint64 = /bits/ 64 <9223372036854775807>;
+	prop-int64 = /bits/ 64 <0xfffffffffffffffe>;
+};
diff --git a/tests/testdata.h b/tests/testdata.h
index 3588778..0d08efb 100644
--- a/tests/testdata.h
+++ b/tests/testdata.h
@@ -4,15 +4,25 @@
 #define ASM_CONST_LL(x)	(x##ULL)
 #endif
 
-#define TEST_ADDR_1	ASM_CONST_LL(0xdeadbeef00000000)
-#define TEST_SIZE_1	ASM_CONST_LL(0x100000)
-#define TEST_ADDR_2	ASM_CONST_LL(123456789)
-#define TEST_SIZE_2	ASM_CONST_LL(010000)
+#define TEST_ADDR_1H	ASM_CONST_LL(0xdeadbeef)
+#define TEST_ADDR_1L	ASM_CONST_LL(0x00000000)
+#define TEST_ADDR_1	((TEST_ADDR_1H << 32) | TEST_ADDR_1L)
+#define TEST_SIZE_1H	ASM_CONST_LL(0x00000000)
+#define TEST_SIZE_1L	ASM_CONST_LL(0x00100000)
+#define TEST_SIZE_1	((TEST_SIZE_1H << 32) | TEST_SIZE_1L)
+#define TEST_ADDR_2H	ASM_CONST_LL(0)
+#define TEST_ADDR_2L	ASM_CONST_LL(123456789)
+#define TEST_ADDR_2	((TEST_ADDR_2H << 32) | TEST_ADDR_2L)
+#define TEST_SIZE_2H	ASM_CONST_LL(0)
+#define TEST_SIZE_2L	ASM_CONST_LL(010000)
+#define TEST_SIZE_2	((TEST_SIZE_2H << 32) | TEST_SIZE_2L)
 
 #define TEST_VALUE_1	0xdeadbeef
 #define TEST_VALUE_2	123456789
 
-#define TEST_VALUE64_1	ASM_CONST_LL(0xdeadbeef01abcdef)
+#define TEST_VALUE64_1H	ASM_CONST_LL(0xdeadbeef)
+#define TEST_VALUE64_1L	ASM_CONST_LL(0x01abcdef)
+#define TEST_VALUE64_1	((TEST_VALUE64_1H << 32) | TEST_VALUE64_1L)
 
 #define PHANDLE_1	0x2000
 #define PHANDLE_2	0x2001
@@ -30,11 +40,19 @@
 #define TEST_CHAR4	'\''
 #define TEST_CHAR5	'\xff'
 
+#define TEST_MEMREGION_ADDR	0x12345678
+#define TEST_MEMREGION_ADDR_HI	0x8765432100000000
+#define TEST_MEMREGION_SIZE	0x9abcdef0
+#define TEST_MEMREGION_SIZE_HI	0x0fedcba900000000
+#define TEST_MEMREGION_SIZE_INC	0x1000
+
 #ifndef __ASSEMBLY__
-extern struct fdt_header _test_tree1;
-extern struct fdt_header _truncated_property;
-extern struct fdt_header _bad_node_char;
-extern struct fdt_header _bad_node_format;
-extern struct fdt_header _bad_prop_char;
-extern struct fdt_header _ovf_size_strings;
+extern struct fdt_header test_tree1;
+extern struct fdt_header truncated_property;
+extern struct fdt_header bad_node_char;
+extern struct fdt_header bad_node_format;
+extern struct fdt_header bad_prop_char;
+extern struct fdt_header ovf_size_strings;
+extern struct fdt_header truncated_string;
+extern struct fdt_header truncated_memrsv;
 #endif /* ! __ASSEMBLY */
diff --git a/tests/tests.h b/tests/tests.h
index c0e4d3c..1017366 100644
--- a/tests/tests.h
+++ b/tests/tests.h
@@ -1,23 +1,10 @@
-#ifndef _TESTS_H
-#define _TESTS_H
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#ifndef TESTS_H
+#define TESTS_H
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase definitions
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #define DEBUG
@@ -118,7 +105,21 @@
 	})
 #define check_getprop_string(fdt, nodeoffset, name, s) \
 	check_getprop((fdt), (nodeoffset), (name), strlen(s)+1, (s))
+
+/* Returns non-NULL if the property at poffset has the name in_name */
+const void *check_get_prop_offset(void *fdt, int poffset, const char *in_name,
+				  int in_len, const void *in_val);
+#define check_get_prop_offset_cell(fdt, poffset, name, val) \
+	({ \
+		fdt32_t x = cpu_to_fdt32(val);			     \
+		check_get_prop_offset(fdt, poffset, name, sizeof(x), &x); \
+	})
+
+const void *check_getprop_addrrange(void *fdt, int parent, int nodeoffset,
+				    const char *name, int num);
+
 int nodename_eq(const char *s1, const char *s2);
+void vg_prepare_blob(void *fdt, size_t bufsize);
 void *load_blob(const char *filename);
 void *load_blob_arg(int argc, char *argv[]);
 void save_blob(const char *filename, void *blob);
@@ -126,4 +127,4 @@
 
 #include "util.h"
 
-#endif /* _TESTS_H */
+#endif /* TESTS_H */
diff --git a/tests/testutils.c b/tests/testutils.c
index 521f4f1..5e494c5 100644
--- a/tests/testutils.c
+++ b/tests/testutils.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase common utility functions
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #define _GNU_SOURCE /* for strsignal() in glibc.  FreeBSD has it either way */
@@ -30,9 +17,25 @@
 #include <unistd.h>
 #include <fcntl.h>
 
+#if NO_VALGRIND
+static inline void VALGRIND_MAKE_MEM_UNDEFINED(void *p, size_t len)
+{
+}
+
+static inline void VALGRIND_MAKE_MEM_DEFINED(void *p, size_t len)
+{
+}
+#else
+#include <valgrind/memcheck.h>
+#endif
+
 #include <libfdt.h>
 
 #include "tests.h"
+#include "testdata.h"
+
+/* For FDT_SW_MAGIC */
+#include "libfdt_internal.h"
 
 int verbose_test = 1;
 char *test_name;
@@ -88,7 +91,7 @@
 		    int len, const void *val)
 {
 	const struct fdt_property *prop;
-	int retlen;
+	int retlen, namelen;
 	uint32_t tag, nameoff, proplen;
 	const char *propname;
 
@@ -96,7 +99,7 @@
 	prop = fdt_get_property(fdt, nodeoffset, name, &retlen);
 	verbose_printf("pointer %p\n", prop);
 	if (! prop)
-		FAIL("Error retreiving \"%s\" pointer: %s", name,
+		FAIL("Error retrieving \"%s\" pointer: %s", name,
 		     fdt_strerror(retlen));
 
 	tag = fdt32_to_cpu(prop->tag);
@@ -106,8 +109,13 @@
 	if (tag != FDT_PROP)
 		FAIL("Incorrect tag 0x%08x on property \"%s\"", tag, name);
 
-	propname = fdt_string(fdt, nameoff);
-	if (!propname || !streq(propname, name))
+	propname = fdt_get_string(fdt, nameoff, &namelen);
+	if (!propname)
+		FAIL("Couldn't get property name: %s", fdt_strerror(namelen));
+	if (namelen != strlen(propname))
+		FAIL("Incorrect prop name length: %d instead of %zd",
+		     namelen, strlen(propname));
+	if (!streq(propname, name))
 		FAIL("Property name mismatch \"%s\" instead of \"%s\"",
 		     propname, name);
 	if (proplen != retlen)
@@ -117,7 +125,7 @@
 	if (proplen != len)
 		FAIL("Size mismatch on property \"%s\": %d insead of %d",
 		     name, proplen, len);
-	if (memcmp(val, prop->data, len) != 0)
+	if (len && memcmp(val, prop->data, len) != 0)
 		FAIL("Data mismatch on property \"%s\"", name);
 }
 
@@ -134,12 +142,94 @@
 	if (proplen != len)
 		FAIL("Size mismatch on property \"%s\": %d insead of %d",
 		     name, proplen, len);
-	if (memcmp(val, propval, len) != 0)
+	if (len && memcmp(val, propval, len) != 0)
 		FAIL("Data mismatch on property \"%s\"", name);
 
 	return propval;
 }
 
+const void *check_get_prop_offset(void *fdt, int poffset, const char *exp_name,
+				  int exp_len, const void *exp_val)
+{
+	const void *propval;
+	const char *name;
+	int proplen;
+
+	propval = fdt_getprop_by_offset(fdt, poffset, &name, &proplen);
+	if (!propval)
+		FAIL("fdt_getprop(\"%s\"): %s", name, fdt_strerror(proplen));
+
+	/* Not testing for this field, so ignore */
+	if (strcmp(name, exp_name))
+		return NULL;
+
+	if (proplen != exp_len)
+		FAIL("Size mismatch on property \"%s\": %d insead of %d",
+		     name, proplen, exp_len);
+	if (exp_len && memcmp(exp_val, propval, exp_len))
+		FAIL("Data mismatch on property \"%s\"", name);
+
+	return propval;
+}
+
+const void *check_getprop_addrrange(void *fdt, int parent, int nodeoffset,
+				    const char *name, int num)
+{
+	const void *propval;
+	int xac, xsc, buf_size, cells, i;
+	char *buf, *p;
+	uint64_t addr, size;
+	fdt32_t val;
+
+	xac = fdt_address_cells(fdt, parent);
+	xsc = fdt_size_cells(fdt, parent);
+
+	if (xac <= 0)
+		FAIL("Couldn't identify #address-cells: %s",
+		     fdt_strerror(xac));
+	if (xsc <= 0)
+		FAIL("Couldn't identify #size-cells: %s",
+		     fdt_strerror(xsc));
+
+	buf_size = (xac + xsc) * sizeof(fdt32_t) * num;
+	buf = malloc(buf_size);
+	if (!buf)
+		FAIL("Couldn't allocate temporary buffer");
+
+	/* expected value */
+	addr = TEST_MEMREGION_ADDR;
+	if (xac > 1)
+		addr += TEST_MEMREGION_ADDR_HI;
+	size = TEST_MEMREGION_SIZE;
+	if (xsc > 1)
+		size += TEST_MEMREGION_SIZE_HI;
+	for (p = buf, i = 0; i < num; i++) {
+		cells = xac;
+		while (cells) {
+			val = cpu_to_fdt32(addr >> (32 * (--cells)));
+			memcpy(p, &val, sizeof(val));
+			p += sizeof(val);
+		}
+		cells = xsc;
+		while (cells) {
+			val = cpu_to_fdt32(size >> (32 * (--cells)));
+			memcpy(p, &val, sizeof(val));
+			p += sizeof(val);
+		}
+
+		addr += size;
+		size += TEST_MEMREGION_SIZE_INC;
+	}
+
+	/* check */
+	propval = check_getprop(fdt, nodeoffset, name, buf_size,
+				(const void *)buf);
+
+	free(buf);
+
+	return propval;
+}
+
 int nodename_eq(const char *s1, const char *s2)
 {
 	int len = strlen(s2);
@@ -154,16 +244,66 @@
 		return 0;
 }
 
-#define CHUNKSIZE	128
+void vg_prepare_blob(void *fdt, size_t bufsize)
+{
+	char *blob = fdt;
+	int off_memrsv, off_strings, off_struct;
+	int num_memrsv;
+	size_t size_memrsv, size_strings, size_struct;
+
+	off_memrsv = fdt_off_mem_rsvmap(fdt);
+	num_memrsv = fdt_num_mem_rsv(fdt);
+	if (num_memrsv < 0)
+		size_memrsv = fdt_totalsize(fdt) - off_memrsv;
+	else
+		size_memrsv = (num_memrsv + 1)
+			* sizeof(struct fdt_reserve_entry);
+
+	VALGRIND_MAKE_MEM_UNDEFINED(blob, bufsize);
+	VALGRIND_MAKE_MEM_DEFINED(blob, FDT_V1_SIZE);
+	VALGRIND_MAKE_MEM_DEFINED(blob, fdt_header_size(fdt));
+
+	if (fdt_magic(fdt) == FDT_MAGIC) {
+		off_strings = fdt_off_dt_strings(fdt);
+		if (fdt_version(fdt) >= 3)
+			size_strings = fdt_size_dt_strings(fdt);
+		else
+			size_strings = fdt_totalsize(fdt) - off_strings;
+
+		off_struct = fdt_off_dt_struct(fdt);
+		if (fdt_version(fdt) >= 17)
+			size_struct = fdt_size_dt_struct(fdt);
+		else
+			size_struct = fdt_totalsize(fdt) - off_struct;
+	} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
+		size_strings = fdt_size_dt_strings(fdt);
+		off_strings = fdt_off_dt_strings(fdt) - size_strings;
+
+		off_struct = fdt_off_dt_struct(fdt);
+		size_struct = fdt_size_dt_struct(fdt);
+		size_struct = fdt_totalsize(fdt) - off_struct;
+
+	} else {
+		CONFIG("Bad magic on vg_prepare_blob()");
+	}
+
+	VALGRIND_MAKE_MEM_DEFINED(blob + off_memrsv, size_memrsv);
+	VALGRIND_MAKE_MEM_DEFINED(blob + off_strings, size_strings);
+	VALGRIND_MAKE_MEM_DEFINED(blob + off_struct, size_struct);
+}
 
 void *load_blob(const char *filename)
 {
 	char *blob;
-	int ret = utilfdt_read_err(filename, &blob);
+	size_t len;
+	int ret = utilfdt_read_err(filename, &blob, &len);
 
 	if (ret)
 		CONFIG("Couldn't open blob from \"%s\": %s", filename,
 		       strerror(ret));
+
+	vg_prepare_blob(blob, len);
+
 	return blob;
 }
 
@@ -176,11 +316,20 @@
 
 void save_blob(const char *filename, void *fdt)
 {
-	int ret = utilfdt_write_err(filename, fdt);
+	size_t size = fdt_totalsize(fdt);
+	void *tmp;
+	int ret;
 
+	/* Make a temp copy of the blob so that valgrind won't check
+	 * about uninitialized bits in the pieces between blocks */
+	tmp = xmalloc(size);
+	fdt_move(fdt, tmp, size);
+	VALGRIND_MAKE_MEM_DEFINED(tmp, size);
+	ret = utilfdt_write_err(filename, tmp);
 	if (ret)
 		CONFIG("Couldn't write blob to \"%s\": %s", filename,
 		       strerror(ret));
+	free(tmp);
 }
 
 void *open_blob_rw(void *blob)
diff --git a/tests/tests.sh b/tests/testutils.sh
similarity index 80%
rename from tests/tests.sh
rename to tests/testutils.sh
index 8dda6e1..6b2f0d1 100644
--- a/tests/tests.sh
+++ b/tests/testutils.sh
@@ -18,11 +18,15 @@
     fi
 }
 
-DTC=../dtc
-DTGET=../fdtget
-DTPUT=../fdtput
-FDTDUMP=../fdtdump
-FDTOVERLAY=../fdtoverlay
+if [ -z "$TEST_BINDIR" ]; then
+    TEST_BINDIR=..
+fi
+
+DTC=${TEST_BINDIR}/dtc
+DTGET=${TEST_BINDIR}/fdtget
+DTPUT=${TEST_BINDIR}/fdtput
+FDTDUMP=${TEST_BINDIR}/fdtdump
+FDTOVERLAY=${TEST_BINDIR}/fdtoverlay
 
 verbose_run () {
     if [ -z "$QUIET_TEST" ]; then
diff --git a/tests/trees.S b/tests/trees.S
index 9854d1d..efab287 100644
--- a/tests/trees.S
+++ b/tests/trees.S
@@ -7,20 +7,9 @@
 	.byte	((val) >> 8) & 0xff ; \
 	.byte	(val) & 0xff	;
 
-#define FDTQUAD(val) \
-	.byte	((val) >> 56) & 0xff ; \
-	.byte	((val) >> 48) & 0xff ; \
-	.byte	((val) >> 40) & 0xff ; \
-	.byte	((val) >> 32) & 0xff ; \
-	.byte	((val) >> 24) & 0xff ; \
-	.byte	((val) >> 16) & 0xff ; \
-	.byte	((val) >> 8) & 0xff ; \
-	.byte	(val) & 0xff	;
-
 #define TREE_HDR(tree) \
 	.balign	8		; \
-	.globl	_##tree		; \
-_##tree:	\
+	.globl	tree		; \
 tree:	\
 	FDTLONG(FDT_MAGIC)	; \
 	FDTLONG(tree##_end - tree) ; \
@@ -33,14 +22,16 @@
 	FDTLONG(tree##_strings_end - tree##_strings) ; \
 	FDTLONG(tree##_struct_end - tree##_struct) ;
 
-#define RSVMAP_ENTRY(addr, len) \
-	FDTQUAD(addr)		; \
-	FDTQUAD(len)		; \
+#define RSVMAP_ENTRY(addrh, addrl, lenh, lenl) \
+	FDTLONG(addrh)		; \
+	FDTLONG(addrl)		; \
+	FDTLONG(lenh)		; \
+	FDTLONG(lenl)
 
 #define EMPTY_RSVMAP(tree) \
 	.balign	8		; \
 tree##_rsvmap:			; \
-	RSVMAP_ENTRY(0, 0) \
+	RSVMAP_ENTRY(0, 0, 0, 0) \
 tree##_rsvmap_end:		;
 
 #define PROPHDR(tree, name, len) \
@@ -48,13 +39,17 @@
 	FDTLONG(len)		; \
 	FDTLONG(tree##_##name - tree##_strings) ;
 
+#define PROP_EMPTY(tree, name) \
+	PROPHDR(tree, name, 0)	;
+
 #define PROP_INT(tree, name, val) \
 	PROPHDR(tree, name, 4) \
 	FDTLONG(val)		;
 
-#define PROP_INT64(tree, name, val) \
+#define PROP_INT64(tree, name, valh, vall) \
 	PROPHDR(tree, name, 8) \
-	FDTQUAD(val)		;
+	FDTLONG(valh)		; \
+	FDTLONG(vall)		;
 
 #define PROP_STR(tree, name, str) \
 	PROPHDR(tree, name, 55f - 54f) \
@@ -81,16 +76,16 @@
 
 	.balign	8
 test_tree1_rsvmap:
-	RSVMAP_ENTRY(TEST_ADDR_1, TEST_SIZE_1)
-	RSVMAP_ENTRY(TEST_ADDR_2, TEST_SIZE_2)
-	RSVMAP_ENTRY(0, 0)
+	RSVMAP_ENTRY(TEST_ADDR_1H, TEST_ADDR_1L, TEST_SIZE_1H, TEST_SIZE_1L)
+	RSVMAP_ENTRY(TEST_ADDR_2H, TEST_ADDR_2L, TEST_SIZE_2H, TEST_SIZE_2L)
+	RSVMAP_ENTRY(0, 0, 0, 0)
 test_tree1_rsvmap_end:
 
 test_tree1_struct:
 	BEGIN_NODE("")
 	PROP_STR(test_tree1, compatible, "test_tree1")
 	PROP_INT(test_tree1, prop_int, TEST_VALUE_1)
-	PROP_INT64(test_tree1, prop_int64, TEST_VALUE64_1)
+	PROP_INT64(test_tree1, prop_int64, TEST_VALUE64_1H, TEST_VALUE64_1L)
 	PROP_STR(test_tree1, prop_str, TEST_STRING_1)
 	PROP_INT(test_tree1, address_cells, 1)
 	PROP_INT(test_tree1, size_cells, 0)
@@ -215,8 +210,7 @@
 
 	/* overflow_size_strings */
 	.balign	8
-	.globl	_ovf_size_strings
-_ovf_size_strings:
+	.globl	ovf_size_strings
 ovf_size_strings:
 	FDTLONG(FDT_MAGIC)
 	FDTLONG(ovf_size_strings_end - ovf_size_strings)
@@ -242,3 +236,46 @@
 	ovf_size_strings_bad_string = ovf_size_strings_strings + 0x10000000
 ovf_size_strings_strings_end:
 ovf_size_strings_end:
+
+
+	/* truncated_string */
+	TREE_HDR(truncated_string)
+	EMPTY_RSVMAP(truncated_string)
+
+truncated_string_struct:
+	BEGIN_NODE("")
+	PROP_EMPTY(truncated_string, good_string)
+	PROP_EMPTY(truncated_string, bad_string)
+	END_NODE
+	FDTLONG(FDT_END)
+truncated_string_struct_end:
+
+truncated_string_strings:
+	STRING(truncated_string, good_string, "good")
+truncated_string_bad_string:
+	.byte	'b'
+	.byte	'a'
+	.byte	'd'
+	/* NOTE: terminating \0 deliberately missing */
+truncated_string_strings_end:
+truncated_string_end:
+
+
+	/* truncated_memrsv */
+	TREE_HDR(truncated_memrsv)
+
+truncated_memrsv_struct:
+	BEGIN_NODE("")
+	END_NODE
+	FDTLONG(FDT_END)
+truncated_memrsv_struct_end:
+
+truncated_memrsv_strings:
+truncated_memrsv_strings_end:
+
+	.balign	8
+truncated_memrsv_rsvmap:
+	RSVMAP_ENTRY(TEST_ADDR_1H, TEST_ADDR_1L, TEST_SIZE_1H, TEST_SIZE_1L)
+truncated_memrsv_rsvmap_end:
+
+truncated_memrsv_end:
diff --git a/tests/truncated_memrsv.c b/tests/truncated_memrsv.c
new file mode 100644
index 0000000..d78036c
--- /dev/null
+++ b/tests/truncated_memrsv.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ * libfdt - Flat Device Tree manipulation
+ *	Testcase for misbehaviour on a truncated string
+ * Copyright (C) 2018 David Gibson, IBM Corporation.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+int main(int argc, char *argv[])
+{
+	void *fdt = &truncated_memrsv;
+	int err;
+	uint64_t addr, size;
+
+	test_init(argc, argv);
+
+	err = fdt_check_header(fdt);
+	if (err != 0)
+		FAIL("Bad header: %s", fdt_strerror(err));
+
+	err = fdt_num_mem_rsv(fdt);
+	if (err != -FDT_ERR_TRUNCATED)
+		FAIL("fdt_num_mem_rsv() returned %d instead of -FDT_ERR_TRUNCATED",
+		     err);
+
+	err = fdt_get_mem_rsv(fdt, 0, &addr, &size);
+	if (err != 0)
+		FAIL("fdt_get_mem_rsv() failed on first entry: %s",
+		     fdt_strerror(err));
+	if ((addr != TEST_ADDR_1) || (size != TEST_SIZE_1))
+		FAIL("Entry doesn't match: (0x%llx, 0x%llx) != (0x%llx, 0x%llx)",
+		     (unsigned long long)addr, (unsigned long long)size,
+		     TEST_ADDR_1, TEST_SIZE_1);
+
+	err = fdt_get_mem_rsv(fdt, 1, &addr, &size);
+	if (err != -FDT_ERR_BADOFFSET)
+		FAIL("fdt_get_mem_rsv(1) returned %d instead of -FDT_ERR_BADOFFSET",
+		     err);
+
+	PASS();
+}
diff --git a/tests/truncated_property.c b/tests/truncated_property.c
index f820d99..d9d52b2 100644
--- a/tests/truncated_property.c
+++ b/tests/truncated_property.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Testcase for misbehaviour on a truncated property
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
@@ -30,12 +17,14 @@
 
 int main(int argc, char *argv[])
 {
-	void *fdt = &_truncated_property;
+	void *fdt = &truncated_property;
 	const void *prop;
 	int len;
 
 	test_init(argc, argv);
 
+	vg_prepare_blob(fdt, fdt_totalsize(fdt));
+
 	prop = fdt_getprop(fdt, 0, "truncated", &len);
 	if (prop)
 		FAIL("fdt_getprop() succeeded on truncated property");
diff --git a/tests/truncated_string.c b/tests/truncated_string.c
new file mode 100644
index 0000000..d745414
--- /dev/null
+++ b/tests/truncated_string.c
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ * libfdt - Flat Device Tree manipulation
+ *	Testcase for misbehaviour on a truncated string
+ * Copyright (C) 2018 David Gibson, IBM Corporation.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+int main(int argc, char *argv[])
+{
+	void *fdt = &truncated_string;
+	const struct fdt_property *good, *bad;
+	int off, len;
+	const char *name;
+
+	test_init(argc, argv);
+
+	vg_prepare_blob(fdt, fdt_totalsize(fdt));
+
+	off = fdt_first_property_offset(fdt, 0);
+	good = fdt_get_property_by_offset(fdt, off, NULL);
+
+	off = fdt_next_property_offset(fdt, off);
+	bad = fdt_get_property_by_offset(fdt, off, NULL);
+
+	if (fdt32_to_cpu(good->len) != 0)
+		FAIL("Unexpected length for good property");
+	name = fdt_get_string(fdt, fdt32_to_cpu(good->nameoff), &len);
+	if (!name)
+		FAIL("fdt_get_string() failed on good property: %s",
+		     fdt_strerror(len));
+	if (len != 4)
+		FAIL("fdt_get_string() returned length %d (not 4) on good property",
+		     len);
+	if (!streq(name, "good"))
+		FAIL("fdt_get_string() returned \"%s\" (not \"good\") on good property",
+		     name);
+
+	if (fdt32_to_cpu(bad->len) != 0)
+		FAIL("Unexpected length for bad property\n");
+	name = fdt_get_string(fdt, fdt32_to_cpu(bad->nameoff), &len);
+	if (name)
+		FAIL("fdt_get_string() succeeded incorrectly on bad property");
+	else if (len != -FDT_ERR_TRUNCATED)
+		FAIL("fdt_get_string() gave unexpected error on bad property: %s",
+		     fdt_strerror(len));
+
+	/* Make sure the 'good' property breaks correctly if we
+	 * truncate the strings section */
+	fdt_set_size_dt_strings(fdt, fdt32_to_cpu(good->nameoff) + 4);
+	name = fdt_get_string(fdt, fdt32_to_cpu(good->nameoff), &len);
+	if (name)
+		FAIL("fdt_get_string() succeeded incorrectly on mangled property");
+	else if (len != -FDT_ERR_TRUNCATED)
+		FAIL("fdt_get_string() gave unexpected error on mangled property: %s",
+		     fdt_strerror(len));
+
+	PASS();
+}
diff --git a/tests/type-preservation.dt.yaml b/tests/type-preservation.dt.yaml
new file mode 100644
index 0000000..ee8cfde
--- /dev/null
+++ b/tests/type-preservation.dt.yaml
@@ -0,0 +1,20 @@
+---
+- '#address-cells': [[0x1]]
+  '#size-cells': [[0x0]]
+  subnode@1:
+    compatible: ["subnode1"]
+    reg: [[0x1]]
+    int-array: [[0x0, 0x1], [0x2, 0x3]]
+    int8: [!u8 [0x56]]
+    int8-array: [!u8 [0x0, 0x12, 0x34, 0x56]]
+    int16: [!u16 [0x3210]]
+    int16-array: [!u16 [0x1234, 0x5678, 0x90ab, 0xcdef]]
+    int16-matrix: [!u16 [0x1234, 0x5678], [0x90ab, 0xcdef]]
+    int64: [!u64 [0x200000000]]
+    int64-array: [!u64 [0x100000000, 0x0]]
+    a-string-with-nulls: ["foo\0bar", "baz"]
+    subsubnode:
+      compatible: ["subsubnode1", "subsubnode"]
+      subsubsubnode:
+        compatible: ["subsubsubnode1", [0x1234], "subsubsubnode"]
+...
diff --git a/tests/type-preservation.dts b/tests/type-preservation.dts
new file mode 100644
index 0000000..3e380ba
--- /dev/null
+++ b/tests/type-preservation.dts
@@ -0,0 +1,28 @@
+/dts-v1/;
+
+/ {
+	#address-cells = <0x01>;
+	#size-cells = <0x00>;
+
+	sub1: subnode@1 {
+		prop_label: compatible = value_label: "subnode1";
+		reg = <0x01>;
+		int-array = <0x00 0x01>, int_value_label: <0x02 0x03>;
+		int8 = [56];
+		int8-array = [00 12 34 56] label:;
+		int16 = /bits/ 16 <0x3210>;
+		int16-array = /bits/ 16 <0x1234 0x5678 0x90ab 0xcdef>;
+		int16-matrix = /bits/ 16 <0x1234 0x5678>, <0x90ab 0xcdef>;
+		int64 = /bits/ 64 <0x200000000>;
+		int64-array = /bits/ 64 <0x100000000 0x00> int64_array_label_end:;
+		a-string-with-nulls = "foo\0bar", "baz";
+
+		subsub1: subsubnode {
+			compatible = "subsubnode1", "subsubnode";
+
+			subsubsub1: subsubsubnode {
+				compatible = "subsubsubnode1", <0x1234>, valuea: valueb: "subsubsubnode";
+			};
+		};
+	};
+};
diff --git a/tests/unit-addr-simple-bus-compatible.dts b/tests/unit-addr-simple-bus-compatible.dts
new file mode 100644
index 0000000..c8f9341
--- /dev/null
+++ b/tests/unit-addr-simple-bus-compatible.dts
@@ -0,0 +1,18 @@
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	bus@10000000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "foo-bus", "simple-bus";
+		ranges = <0x0 0x10000000 0x10000>;
+
+		node@100 {
+			reg = <0x1000 1>;
+		};
+	};
+
+};
diff --git a/tests/unit-addr-simple-bus-reg-mismatch.dts b/tests/unit-addr-simple-bus-reg-mismatch.dts
new file mode 100644
index 0000000..2823377
--- /dev/null
+++ b/tests/unit-addr-simple-bus-reg-mismatch.dts
@@ -0,0 +1,18 @@
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	bus@10000000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "simple-bus";
+		ranges = <0x0 0x10000000 0x10000>;
+
+		node@100 {
+			reg = <0x1000 1>;
+		};
+	};
+
+};
diff --git a/tests/unit-addr-unique.dts b/tests/unit-addr-unique.dts
new file mode 100644
index 0000000..7cc650b
--- /dev/null
+++ b/tests/unit-addr-unique.dts
@@ -0,0 +1,14 @@
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	foo@1 {
+		reg = <1>;
+	};
+
+	bar@1 {
+		reg = <1>;
+	};
+};
diff --git a/tests/utilfdt_test.c b/tests/utilfdt_test.c
index 274c3d6..c621759 100644
--- a/tests/utilfdt_test.c
+++ b/tests/utilfdt_test.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * Copyright 2011 The Chromium Authors, All Rights Reserved.
  *
  * utilfdt_test - Tests for utilfdt library
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 #include <assert.h>
 #include <stdlib.h>
diff --git a/tests/value-labels.c b/tests/value-labels.c
index 8aced74..e318357 100644
--- a/tests/value-labels.c
+++ b/tests/value-labels.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
 /*
  * libfdt - Flat Device Tree manipulation
  *	Test labels within values
  * Copyright (C) 2008 David Gibson, IBM Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
  */
 
 #include <stdlib.h>
diff --git a/treesource.c b/treesource.c
index 2461a3d..061ba8c 100644
--- a/treesource.c
+++ b/treesource.c
@@ -1,21 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
- *                                                                   USA
  */
 
 #include "dtc.h"
@@ -61,24 +46,18 @@
 		|| strchr("\a\b\t\n\v\f\r", c));
 }
 
-static void write_propval_string(FILE *f, struct data val)
+static void write_propval_string(FILE *f, const char *s, size_t len)
 {
-	const char *str = val.val;
-	int i;
-	struct marker *m = val.markers;
+	const char *end = s + len - 1;
 
-	assert(str[val.len-1] == '\0');
+	if (!len)
+		return;
 
-	while (m && (m->offset == 0)) {
-		if (m->type == LABEL)
-			fprintf(f, "%s: ", m->ref);
-		m = m->next;
-	}
+	assert(*end == '\0');
+
 	fprintf(f, "\"");
-
-	for (i = 0; i < (val.len-1); i++) {
-		char c = str[i];
-
+	while (s < end) {
+		char c = *s++;
 		switch (c) {
 		case '\a':
 			fprintf(f, "\\a");
@@ -108,91 +87,80 @@
 			fprintf(f, "\\\"");
 			break;
 		case '\0':
-			fprintf(f, "\", ");
-			while (m && (m->offset <= (i + 1))) {
-				if (m->type == LABEL) {
-					assert(m->offset == (i+1));
-					fprintf(f, "%s: ", m->ref);
-				}
-				m = m->next;
-			}
-			fprintf(f, "\"");
+			fprintf(f, "\\0");
 			break;
 		default:
 			if (isprint((unsigned char)c))
 				fprintf(f, "%c", c);
 			else
-				fprintf(f, "\\x%02hhx", c);
+				fprintf(f, "\\x%02"PRIx8, c);
 		}
 	}
 	fprintf(f, "\"");
-
-	/* Wrap up any labels at the end of the value */
-	for_each_marker_of_type(m, LABEL) {
-		assert (m->offset == val.len);
-		fprintf(f, " %s:", m->ref);
-	}
 }
 
-static void write_propval_cells(FILE *f, struct data val)
+static void write_propval_int(FILE *f, const char *p, size_t len, size_t width)
 {
-	void *propend = val.val + val.len;
-	fdt32_t *cp = (fdt32_t *)val.val;
-	struct marker *m = val.markers;
+	const char *end = p + len;
+	assert(len % width == 0);
 
-	fprintf(f, "<");
-	for (;;) {
-		while (m && (m->offset <= ((char *)cp - val.val))) {
-			if (m->type == LABEL) {
-				assert(m->offset == ((char *)cp - val.val));
-				fprintf(f, "%s: ", m->ref);
-			}
-			m = m->next;
-		}
-
-		fprintf(f, "0x%x", fdt32_to_cpu(*cp++));
-		if ((void *)cp >= propend)
+	for (; p < end; p += width) {
+		switch (width) {
+		case 1:
+			fprintf(f, "%02"PRIx8, *(const uint8_t*)p);
 			break;
-		fprintf(f, " ");
+		case 2:
+			fprintf(f, "0x%02"PRIx16, dtb_ld16(p));
+			break;
+		case 4:
+			fprintf(f, "0x%02"PRIx32, dtb_ld32(p));
+			break;
+		case 8:
+			fprintf(f, "0x%02"PRIx64, dtb_ld64(p));
+			break;
+		}
+		if (p + width < end)
+			fputc(' ', f);
 	}
-
-	/* Wrap up any labels at the end of the value */
-	for_each_marker_of_type(m, LABEL) {
-		assert (m->offset == val.len);
-		fprintf(f, " %s:", m->ref);
-	}
-	fprintf(f, ">");
 }
 
-static void write_propval_bytes(FILE *f, struct data val)
+static bool has_data_type_information(struct marker *m)
 {
-	void *propend = val.val + val.len;
-	const char *bp = val.val;
-	struct marker *m = val.markers;
-
-	fprintf(f, "[");
-	for (;;) {
-		while (m && (m->offset == (bp-val.val))) {
-			if (m->type == LABEL)
-				fprintf(f, "%s: ", m->ref);
-			m = m->next;
-		}
-
-		fprintf(f, "%02hhx", (unsigned char)(*bp++));
-		if ((const void *)bp >= propend)
-			break;
-		fprintf(f, " ");
-	}
-
-	/* Wrap up any labels at the end of the value */
-	for_each_marker_of_type(m, LABEL) {
-		assert (m->offset == val.len);
-		fprintf(f, " %s:", m->ref);
-	}
-	fprintf(f, "]");
+	return m->type >= TYPE_UINT8;
 }
 
-static void write_propval(FILE *f, struct property *prop)
+static struct marker *next_type_marker(struct marker *m)
+{
+	while (m && !has_data_type_information(m))
+		m = m->next;
+	return m;
+}
+
+size_t type_marker_length(struct marker *m)
+{
+	struct marker *next = next_type_marker(m->next);
+
+	if (next)
+		return next->offset - m->offset;
+	return 0;
+}
+
+static const char *delim_start[] = {
+	[TYPE_UINT8] = "[",
+	[TYPE_UINT16] = "/bits/ 16 <",
+	[TYPE_UINT32] = "<",
+	[TYPE_UINT64] = "/bits/ 64 <",
+	[TYPE_STRING] = "",
+};
+static const char *delim_end[] = {
+	[TYPE_UINT8] = "]",
+	[TYPE_UINT16] = ">",
+	[TYPE_UINT32] = ">",
+	[TYPE_UINT64] = ">",
+	[TYPE_STRING] = "",
+};
+
+static enum markertype guess_value_type(struct property *prop)
 {
 	int len = prop->val.len;
 	const char *p = prop->val.val;
@@ -201,11 +169,6 @@
 	int nnotstringlbl = 0, nnotcelllbl = 0;
 	int i;
 
-	if (len == 0) {
-		fprintf(f, ";\n");
-		return;
-	}
-
 	for (i = 0; i < len; i++) {
 		if (! isstring(p[i]))
 			nnotstring++;
@@ -220,17 +183,99 @@
 			nnotcelllbl++;
 	}
 
-	fprintf(f, " = ");
-	if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul < (len-nnul))
+	if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul <= (len-nnul))
 	    && (nnotstringlbl == 0)) {
-		write_propval_string(f, prop->val);
+		return TYPE_STRING;
 	} else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) {
-		write_propval_cells(f, prop->val);
-	} else {
-		write_propval_bytes(f, prop->val);
+		return TYPE_UINT32;
 	}
 
-	fprintf(f, ";\n");
+	return TYPE_UINT8;
+}
+
+static void write_propval(FILE *f, struct property *prop)
+{
+	size_t len = prop->val.len;
+	struct marker *m = prop->val.markers;
+	struct marker dummy_marker;
+	enum markertype emit_type = TYPE_NONE;
+	char *srcstr;
+
+	if (len == 0) {
+		fprintf(f, ";");
+		if (annotate) {
+			srcstr = srcpos_string_first(prop->srcpos, annotate);
+			if (srcstr) {
+				fprintf(f, " /* %s */", srcstr);
+				free(srcstr);
+			}
+		}
+		fprintf(f, "\n");
+		return;
+	}
+
+	fprintf(f, " =");
+
+	if (!next_type_marker(m)) {
+		/* data type information missing, need to guess */
+		dummy_marker.type = guess_value_type(prop);
+		dummy_marker.next = prop->val.markers;
+		dummy_marker.offset = 0;
+		dummy_marker.ref = NULL;
+		m = &dummy_marker;
+	}
+
+	for_each_marker(m) {
+		size_t chunk_len = (m->next ? m->next->offset : len) - m->offset;
+		size_t data_len = type_marker_length(m) ? : len - m->offset;
+		const char *p = &prop->val.val[m->offset];
+
+		if (has_data_type_information(m)) {
+			emit_type = m->type;
+			fprintf(f, " %s", delim_start[emit_type]);
+		} else if (m->type == LABEL)
+			fprintf(f, " %s:", m->ref);
+		else if (m->offset)
+			fputc(' ', f);
+
+		if (emit_type == TYPE_NONE) {
+			assert(chunk_len == 0);
+			continue;
+		}
+
+		switch(emit_type) {
+		case TYPE_UINT16:
+			write_propval_int(f, p, chunk_len, 2);
+			break;
+		case TYPE_UINT32:
+			write_propval_int(f, p, chunk_len, 4);
+			break;
+		case TYPE_UINT64:
+			write_propval_int(f, p, chunk_len, 8);
+			break;
+		case TYPE_STRING:
+			write_propval_string(f, p, chunk_len);
+			break;
+		default:
+			write_propval_int(f, p, chunk_len, 1);
+		}
+
+		if (chunk_len == data_len) {
+			size_t pos = m->offset + chunk_len;
+			fprintf(f, pos == len ? "%s" : "%s,",
+			        delim_end[emit_type] ? : "");
+			emit_type = TYPE_NONE;
+		}
+	}
+	fprintf(f, ";");
+	if (annotate) {
+		srcstr = srcpos_string_first(prop->srcpos, annotate);
+		if (srcstr) {
+			fprintf(f, " /* %s */", srcstr);
+			free(srcstr);
+		}
+	}
+	fprintf(f, "\n");
 }
 
 static void write_tree_source_node(FILE *f, struct node *tree, int level)
@@ -238,14 +283,24 @@
 	struct property *prop;
 	struct node *child;
 	struct label *l;
+	char *srcstr;
 
 	write_prefix(f, level);
 	for_each_label(tree->labels, l)
 		fprintf(f, "%s: ", l->label);
 	if (tree->name && (*tree->name))
-		fprintf(f, "%s {\n", tree->name);
+		fprintf(f, "%s {", tree->name);
 	else
-		fprintf(f, "/ {\n");
+		fprintf(f, "/ {");
+
+	if (annotate) {
+		srcstr = srcpos_string_first(tree->srcpos, annotate);
+		if (srcstr) {
+			fprintf(f, " /* %s */", srcstr);
+			free(srcstr);
+		}
+	}
+	fprintf(f, "\n");
 
 	for_each_property(tree, prop) {
 		write_prefix(f, level+1);
@@ -259,10 +314,17 @@
 		write_tree_source_node(f, child, level+1);
 	}
 	write_prefix(f, level);
-	fprintf(f, "};\n");
+	fprintf(f, "};");
+	if (annotate) {
+		srcstr = srcpos_string_last(tree->srcpos, annotate);
+		if (srcstr) {
+			fprintf(f, " /* %s */", srcstr);
+			free(srcstr);
+		}
+	}
+	fprintf(f, "\n");
 }
 
-
 void dt_to_source(FILE *f, struct dt_info *dti)
 {
 	struct reserve_info *re;
@@ -281,4 +343,3 @@
 
 	write_tree_source_node(f, dti->dt, 0);
 }
-
diff --git a/util.c b/util.c
index 6ae5976..62feff4 100644
--- a/util.c
+++ b/util.c
@@ -1,24 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * Copyright 2011 The Chromium Authors, All Rights Reserved.
  * Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
  *
  * util_is_printable_string contributed by
  *	Pantelis Antoniou <pantelis.antoniou AT gmail.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
- *                                                                   USA
  */
 
 #include <ctype.h>
@@ -27,6 +13,7 @@
 #include <stdarg.h>
 #include <string.h>
 #include <assert.h>
+#include <inttypes.h>
 
 #include <errno.h>
 #include <fcntl.h>
@@ -46,36 +33,54 @@
 	return d;
 }
 
-/* based in part from (3) vsnprintf */
-int xasprintf(char **strp, const char *fmt, ...)
+int xavsprintf_append(char **strp, const char *fmt, va_list ap)
 {
-	int n, size = 128;	/* start with 128 bytes */
+	int n, size = 0;	/* start with 128 bytes */
 	char *p;
-	va_list ap;
+	va_list ap_copy;
 
-	/* initial pointer is NULL making the fist realloc to be malloc */
-	p = NULL;
-	while (1) {
-		p = xrealloc(p, size);
+	p = *strp;
+	if (p)
+		size = strlen(p);
 
-		/* Try to print in the allocated space. */
-		va_start(ap, fmt);
-		n = vsnprintf(p, size, fmt, ap);
-		va_end(ap);
+	va_copy(ap_copy, ap);
+	n = vsnprintf(NULL, 0, fmt, ap_copy) + 1;
+	va_end(ap_copy);
 
-		/* If that worked, return the string. */
-		if (n > -1 && n < size)
-			break;
-		/* Else try again with more space. */
-		if (n > -1)	/* glibc 2.1 */
-			size = n + 1; /* precisely what is needed */
-		else		/* glibc 2.0 */
-			size *= 2; /* twice the old size */
-	}
+	p = xrealloc(p, size + n);
+
+	n = vsnprintf(p + size, n, fmt, ap);
+
 	*strp = p;
 	return strlen(p);
 }
 
+int xasprintf_append(char **strp, const char *fmt, ...)
+{
+	int n;
+	va_list ap;
+
+	va_start(ap, fmt);
+	n = xavsprintf_append(strp, fmt, ap);
+	va_end(ap);
+
+	return n;
+}
+
+int xasprintf(char **strp, const char *fmt, ...)
+{
+	int n;
+	va_list ap;
+
+	*strp = NULL;
+
+	va_start(ap, fmt);
+	n = xavsprintf_append(strp, fmt, ap);
+	va_end(ap);
+
+	return n;
+}
+
 char *join_path(const char *path, const char *name)
 {
 	int lenp = strlen(path);
@@ -227,11 +232,11 @@
 	return val;
 }
 
-int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len)
+int utilfdt_read_err(const char *filename, char **buffp, size_t *len)
 {
 	int fd = 0;	/* assume stdin */
 	char *buf = NULL;
-	off_t bufsize = 1024, offset = 0;
+	size_t bufsize = 1024, offset = 0;
 	int ret = 0;
 
 	*buffp = NULL;
@@ -264,20 +269,15 @@
 		free(buf);
 	else
 		*buffp = buf;
-	*len = bufsize;
+	if (len)
+		*len = bufsize;
 	return ret;
 }
 
-int utilfdt_read_err(const char *filename, char **buffp)
-{
-	off_t len;
-	return utilfdt_read_err_len(filename, buffp, &len);
-}
-
-char *utilfdt_read_len(const char *filename, off_t *len)
+char *utilfdt_read(const char *filename, size_t *len)
 {
 	char *buff;
-	int ret = utilfdt_read_err_len(filename, &buff, len);
+	int ret = utilfdt_read_err(filename, &buff, len);
 
 	if (ret) {
 		fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
@@ -288,12 +288,6 @@
 	return buff;
 }
 
-char *utilfdt_read(const char *filename)
-{
-	off_t len;
-	return utilfdt_read_len(filename, &len);
-}
-
 int utilfdt_write_err(const char *filename, const void *blob)
 {
 	int fd = 1;	/* assume stdout */
@@ -400,7 +394,7 @@
 
 		printf(" = <");
 		for (i = 0, len /= 4; i < len; i++)
-			printf("0x%08x%s", fdt32_to_cpu(cell[i]),
+			printf("0x%08" PRIx32 "%s", fdt32_to_cpu(cell[i]),
 			       i < (len - 1) ? " " : "");
 		printf(">");
 	} else {
diff --git a/util.h b/util.h
index ad5f411..5a4172d 100644
--- a/util.h
+++ b/util.h
@@ -1,5 +1,6 @@
-#ifndef _UTIL_H
-#define _UTIL_H
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef UTIL_H
+#define UTIL_H
 
 #include <stdarg.h>
 #include <stdbool.h>
@@ -8,25 +9,14 @@
 /*
  * Copyright 2011 The Chromium Authors, All Rights Reserved.
  * Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
- *                                                                   USA
  */
 
 #ifdef __GNUC__
+#ifdef __clang__
 #define PRINTF(i, j)	__attribute__((format (printf, i, j)))
+#else
+#define PRINTF(i, j)	__attribute__((format (gnu_printf, i, j)))
+#endif
 #define NORETURN	__attribute__((noreturn))
 #else
 #define PRINTF(i, j)
@@ -35,6 +25,9 @@
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 
+#define stringify(s)	stringify_(s)
+#define stringify_(s)	#s
+
 static inline void NORETURN PRINTF(1, 2) die(const char *str, ...)
 {
 	va_list ap;
@@ -69,6 +62,8 @@
 extern char *xstrdup(const char *s);
 
 extern int PRINTF(2, 3) xasprintf(char **strp, const char *fmt, ...);
+extern int PRINTF(2, 3) xasprintf_append(char **strp, const char *fmt, ...);
+extern int xavsprintf_append(char **strp, const char *fmt, va_list ap);
 extern char *join_path(const char *path, const char *name);
 
 /**
@@ -95,16 +90,10 @@
  * stderr.
  *
  * @param filename	The filename to read, or - for stdin
+ * @param len		If non-NULL, the amount of data we managed to read
  * @return Pointer to allocated buffer containing fdt, or NULL on error
  */
-char *utilfdt_read(const char *filename);
-
-/**
- * Like utilfdt_read(), but also passes back the size of the file read.
- *
- * @param len		If non-NULL, the amount of data we managed to read
- */
-char *utilfdt_read_len(const char *filename, off_t *len);
+char *utilfdt_read(const char *filename, size_t *len);
 
 /**
  * Read a device tree file into a buffer. Does not report errors, but only
@@ -113,23 +102,17 @@
  *
  * @param filename	The filename to read, or - for stdin
  * @param buffp		Returns pointer to buffer containing fdt
+ * @param len		If non-NULL, the amount of data we managed to read
  * @return 0 if ok, else an errno value representing the error
  */
-int utilfdt_read_err(const char *filename, char **buffp);
-
-/**
- * Like utilfdt_read_err(), but also passes back the size of the file read.
- *
- * @param len		If non-NULL, the amount of data we managed to read
- */
-int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len);
+int utilfdt_read_err(const char *filename, char **buffp, size_t *len);
 
 /**
  * Write a device tree buffer to a file. This will report any errors on
  * stderr.
  *
  * @param filename	The filename to write, or - for stdout
- * @param blob		Poiner to buffer containing fdt
+ * @param blob		Pointer to buffer containing fdt
  * @return 0 if ok, -1 on error
  */
 int utilfdt_write(const char *filename, const void *blob);
@@ -140,7 +123,7 @@
  * an error message for the user.
  *
  * @param filename	The filename to write, or - for stdout
- * @param blob		Poiner to buffer containing fdt
+ * @param blob		Pointer to buffer containing fdt
  * @return 0 if ok, else an errno value representing the error
  */
 int utilfdt_write_err(const char *filename, const void *blob);
@@ -260,4 +243,4 @@
 	case 'V': util_version(); \
 	case '?': usage("unknown option");
 
-#endif /* _UTIL_H */
+#endif /* UTIL_H */
diff --git a/version_non_gen.h b/version_non_gen.h
index 71d542d..3376b35 100644
--- a/version_non_gen.h
+++ b/version_non_gen.h
@@ -1 +1 @@
-#define DTC_VERSION "DTC 1.4.4-Android-build"
+#define DTC_VERSION "DTC 1.6.0-Android-build"
diff --git a/yamltree.c b/yamltree.c
new file mode 100644
index 0000000..4e93c12
--- /dev/null
+++ b/yamltree.c
@@ -0,0 +1,233 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright Linaro, Ltd. 2018
+ * (C) Copyright Arm Holdings.  2017
+ * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
+ */
+
+#include <stdlib.h>
+#include <yaml.h>
+#include "dtc.h"
+#include "srcpos.h"
+
+char *yaml_error_name[] = {
+	[YAML_NO_ERROR] = "no error",
+	[YAML_MEMORY_ERROR] = "memory error",
+	[YAML_READER_ERROR] = "reader error",
+	[YAML_SCANNER_ERROR] = "scanner error",
+	[YAML_PARSER_ERROR] = "parser error",
+	[YAML_COMPOSER_ERROR] = "composer error",
+	[YAML_WRITER_ERROR] = "writer error",
+	[YAML_EMITTER_ERROR] = "emitter error",
+};
+
+#define yaml_emitter_emit_or_die(emitter, event) (			\
+{									\
+	if (!yaml_emitter_emit(emitter, event))				\
+		die("yaml '%s': %s in %s, line %i\n",			\
+		    yaml_error_name[(emitter)->error], 			\
+		    (emitter)->problem, __func__, __LINE__);		\
+})
+
+static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, char *data, int len, int width)
+{
+	yaml_event_t event;
+	void *tag;
+	int off, start_offset = markers->offset;
+
+	switch(width) {
+		case 1: tag = "!u8"; break;
+		case 2: tag = "!u16"; break;
+		case 4: tag = "!u32"; break;
+		case 8: tag = "!u64"; break;
+		default:
+			die("Invalid width %i", width);
+	}
+	assert(len % width == 0);
+
+	yaml_sequence_start_event_initialize(&event, NULL,
+		(yaml_char_t *)tag, width == 4, YAML_FLOW_SEQUENCE_STYLE);
+	yaml_emitter_emit_or_die(emitter, &event);
+
+	for (off = 0; off < len; off += width) {
+		char buf[32];
+		struct marker *m;
+		bool is_phandle = false;
+
+		switch(width) {
+		case 1:
+			sprintf(buf, "0x%"PRIx8, *(uint8_t*)(data + off));
+			break;
+		case 2:
+			sprintf(buf, "0x%"PRIx16, dtb_ld16(data + off));
+			break;
+		case 4:
+			sprintf(buf, "0x%"PRIx32, dtb_ld32(data + off));
+			m = markers;
+			is_phandle = false;
+			for_each_marker_of_type(m, REF_PHANDLE) {
+				if (m->offset == (start_offset + off)) {
+					is_phandle = true;
+					break;
+				}
+			}
+			break;
+		case 8:
+			sprintf(buf, "0x%"PRIx64, dtb_ld64(data + off));
+			break;
+		}
+
+		if (is_phandle)
+			yaml_scalar_event_initialize(&event, NULL,
+				(yaml_char_t*)"!phandle", (yaml_char_t *)buf,
+				strlen(buf), 0, 0, YAML_PLAIN_SCALAR_STYLE);
+		else
+			yaml_scalar_event_initialize(&event, NULL,
+				(yaml_char_t*)YAML_INT_TAG, (yaml_char_t *)buf,
+				strlen(buf), 1, 1, YAML_PLAIN_SCALAR_STYLE);
+		yaml_emitter_emit_or_die(emitter, &event);
+	}
+
+	yaml_sequence_end_event_initialize(&event);
+	yaml_emitter_emit_or_die(emitter, &event);
+}
+
+static void yaml_propval_string(yaml_emitter_t *emitter, char *str, int len)
+{
+	yaml_event_t event;
+	int i;
+
+	assert(str[len-1] == '\0');
+
+	/* Make sure the entire string is in the lower 7-bit ascii range */
+	for (i = 0; i < len; i++)
+		assert(isascii(str[i]));
+
+	yaml_scalar_event_initialize(&event, NULL,
+		(yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)str,
+		len-1, 0, 1, YAML_DOUBLE_QUOTED_SCALAR_STYLE);
+	yaml_emitter_emit_or_die(emitter, &event);
+}
+
+static void yaml_propval(yaml_emitter_t *emitter, struct property *prop)
+{
+	yaml_event_t event;
+	int len = prop->val.len;
+	struct marker *m = prop->val.markers;
+
+	/* Emit the property name */
+	yaml_scalar_event_initialize(&event, NULL,
+		(yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)prop->name,
+		strlen(prop->name), 1, 1, YAML_PLAIN_SCALAR_STYLE);
+	yaml_emitter_emit_or_die(emitter, &event);
+
+	/* Boolean properties are easiest to deal with. Length is zero, so just emit 'true' */
+	if (len == 0) {
+		yaml_scalar_event_initialize(&event, NULL,
+			(yaml_char_t *)YAML_BOOL_TAG,
+			(yaml_char_t*)"true",
+			strlen("true"), 1, 0, YAML_PLAIN_SCALAR_STYLE);
+		yaml_emitter_emit_or_die(emitter, &event);
+		return;
+	}
+
+	if (!m)
+		die("No markers present in property '%s' value\n", prop->name);
+
+	yaml_sequence_start_event_initialize(&event, NULL,
+		(yaml_char_t *)YAML_SEQ_TAG, 1, YAML_FLOW_SEQUENCE_STYLE);
+	yaml_emitter_emit_or_die(emitter, &event);
+
+	for_each_marker(m) {
+		int chunk_len;
+		char *data = &prop->val.val[m->offset];
+
+		if (m->type < TYPE_UINT8)
+			continue;
+
+		chunk_len = type_marker_length(m) ? : len;
+		assert(chunk_len > 0);
+		len -= chunk_len;
+
+		switch(m->type) {
+		case TYPE_UINT16:
+			yaml_propval_int(emitter, m, data, chunk_len, 2);
+			break;
+		case TYPE_UINT32:
+			yaml_propval_int(emitter, m, data, chunk_len, 4);
+			break;
+		case TYPE_UINT64:
+			yaml_propval_int(emitter, m, data, chunk_len, 8);
+			break;
+		case TYPE_STRING:
+			yaml_propval_string(emitter, data, chunk_len);
+			break;
+		default:
+			yaml_propval_int(emitter, m, data, chunk_len, 1);
+			break;
+		}
+	}
+
+	yaml_sequence_end_event_initialize(&event);
+	yaml_emitter_emit_or_die(emitter, &event);
+}
+
+
+static void yaml_tree(struct node *tree, yaml_emitter_t *emitter)
+{
+	struct property *prop;
+	struct node *child;
+	yaml_event_t event;
+
+	if (tree->deleted)
+		return;
+
+	yaml_mapping_start_event_initialize(&event, NULL,
+		(yaml_char_t *)YAML_MAP_TAG, 1, YAML_ANY_MAPPING_STYLE);
+	yaml_emitter_emit_or_die(emitter, &event);
+
+	for_each_property(tree, prop)
+		yaml_propval(emitter, prop);
+
+	/* Loop over all the children, emitting them into the map */
+	for_each_child(tree, child) {
+		yaml_scalar_event_initialize(&event, NULL,
+			(yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)child->name,
+			strlen(child->name), 1, 0, YAML_PLAIN_SCALAR_STYLE);
+		yaml_emitter_emit_or_die(emitter, &event);
+		yaml_tree(child, emitter);
+	}
+
+	yaml_mapping_end_event_initialize(&event);
+	yaml_emitter_emit_or_die(emitter, &event);
+}
+
+void dt_to_yaml(FILE *f, struct dt_info *dti)
+{
+	yaml_emitter_t emitter;
+	yaml_event_t event;
+
+	yaml_emitter_initialize(&emitter);
+	yaml_emitter_set_output_file(&emitter, f);
+	yaml_stream_start_event_initialize(&event, YAML_UTF8_ENCODING);
+	yaml_emitter_emit_or_die(&emitter, &event);
+
+	yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
+	yaml_emitter_emit_or_die(&emitter, &event);
+
+	yaml_sequence_start_event_initialize(&event, NULL, (yaml_char_t *)YAML_SEQ_TAG, 1, YAML_ANY_SEQUENCE_STYLE);
+	yaml_emitter_emit_or_die(&emitter, &event);
+
+	yaml_tree(dti->dt, &emitter);
+
+	yaml_sequence_end_event_initialize(&event);
+	yaml_emitter_emit_or_die(&emitter, &event);
+
+	yaml_document_end_event_initialize(&event, 0);
+	yaml_emitter_emit_or_die(&emitter, &event);
+
+	yaml_stream_end_event_initialize(&event);
+	yaml_emitter_emit_or_die(&emitter, &event);
+
+	yaml_emitter_delete(&emitter);
+}