summaryrefslogtreecommitdiffstats
path: root/src/dtc
diff options
context:
space:
mode:
Diffstat (limited to 'src/dtc')
-rw-r--r--src/dtc/.gitignore17
-rw-r--r--src/dtc/Documentation/dtc-paper.bib43
-rw-r--r--src/dtc/Documentation/dtc-paper.tex597
-rw-r--r--src/dtc/Documentation/dts-format.txt122
-rw-r--r--src/dtc/Documentation/manual.txt660
-rw-r--r--src/dtc/GPL340
-rw-r--r--src/dtc/Makefile263
-rw-r--r--src/dtc/Makefile.convert-dtsv013
-rw-r--r--src/dtc/Makefile.dtc18
-rw-r--r--src/dtc/Makefile.utils24
-rw-r--r--src/dtc/README.license56
-rw-r--r--src/dtc/TODO8
-rw-r--r--src/dtc/checks.c759
-rw-r--r--src/dtc/convert-dtsv0-lexer.l248
-rw-r--r--src/dtc/data.c269
-rw-r--r--src/dtc/dtc-lexer.l250
-rw-r--r--src/dtc/dtc-parser.y532
-rw-r--r--src/dtc/dtc.c259
-rw-r--r--src/dtc/dtc.h269
-rw-r--r--src/dtc/dtdiff38
-rw-r--r--src/dtc/fdtdump.c227
-rw-r--r--src/dtc/fdtget.c360
-rw-r--r--src/dtc/fdtput.c401
-rw-r--r--src/dtc/flattree.c933
-rw-r--r--src/dtc/fstree.c91
-rw-r--r--src/dtc/libfdt/Makefile.libfdt10
-rw-r--r--src/dtc/libfdt/TODO3
-rw-r--r--src/dtc/libfdt/fdt.c250
-rw-r--r--src/dtc/libfdt/fdt.h111
-rw-r--r--src/dtc/libfdt/fdt_empty_tree.c84
-rw-r--r--src/dtc/libfdt/fdt_ro.c573
-rw-r--r--src/dtc/libfdt/fdt_rw.c492
-rw-r--r--src/dtc/libfdt/fdt_strerror.c96
-rw-r--r--src/dtc/libfdt/fdt_sw.c256
-rw-r--r--src/dtc/libfdt/fdt_wip.c118
-rw-r--r--src/dtc/libfdt/libfdt.h1514
-rw-r--r--src/dtc/libfdt/libfdt_env.h111
-rw-r--r--src/dtc/libfdt/libfdt_internal.h95
-rw-r--r--src/dtc/libfdt/version.lds60
-rw-r--r--src/dtc/livetree.c709
-rwxr-xr-xsrc/dtc/scripts/setlocalversion22
-rw-r--r--src/dtc/srcpos.c336
-rw-r--r--src/dtc/srcpos.h118
-rw-r--r--src/dtc/tests/.gitignore57
-rw-r--r--src/dtc/tests/Makefile.tests82
-rw-r--r--src/dtc/tests/add_subnode_with_nops.c84
-rw-r--r--src/dtc/tests/aliases.dts21
-rw-r--r--src/dtc/tests/appendprop.dts8
-rw-r--r--src/dtc/tests/appendprop1.c70
-rw-r--r--src/dtc/tests/appendprop2.c64
-rw-r--r--src/dtc/tests/asm_tree_dump.c61
-rw-r--r--src/dtc/tests/bad-empty-ranges.dts11
-rw-r--r--src/dtc/tests/bad-name-property.dts7
-rw-r--r--src/dtc/tests/bad-ncells.dts7
-rw-r--r--src/dtc/tests/bad-reg-ranges.dts12
-rw-r--r--src/dtc/tests/bad-string-props.dts7
-rw-r--r--src/dtc/tests/base01.asm175
-rw-r--r--src/dtc/tests/base01.cmd1
-rw-r--r--src/dtc/tests/base01.dts33
-rw-r--r--src/dtc/tests/base01.stderr6
-rw-r--r--src/dtc/tests/boot-cpuid.c47
-rw-r--r--src/dtc/tests/boot-cpuid.dts16
-rw-r--r--src/dtc/tests/char_literal.c49
-rw-r--r--src/dtc/tests/char_literal.dts5
-rw-r--r--src/dtc/tests/comments-cmp.dts16
-rw-r--r--src/dtc/tests/comments.dts39
-rw-r--r--src/dtc/tests/data.S3
-rw-r--r--src/dtc/tests/default-addr-size.dts7
-rw-r--r--src/dtc/tests/del_node.c123
-rw-r--r--src/dtc/tests/del_property.c90
-rw-r--r--src/dtc/tests/delete_reinstate_multilabel.dts37
-rw-r--r--src/dtc/tests/delete_reinstate_multilabel_ref.dts9
-rw-r--r--src/dtc/tests/dependencies.cmp1
-rw-r--r--src/dtc/tests/dependencies.dts6
-rw-r--r--src/dtc/tests/deps_inc1.dtsi1
-rw-r--r--src/dtc/tests/deps_inc2.dtsi1
-rw-r--r--src/dtc/tests/dtb_reverse.c163
-rw-r--r--src/dtc/tests/dtbs_equal_ordered.c173
-rw-r--r--src/dtc/tests/dtbs_equal_unordered.c223
-rwxr-xr-xsrc/dtc/tests/dtc-checkfails.sh44
-rwxr-xr-xsrc/dtc/tests/dtc-fails.sh30
-rw-r--r--src/dtc/tests/dtc-fatal.sh14
-rw-r--r--src/dtc/tests/dumptrees.c69
-rw-r--r--src/dtc/tests/dup-nodename.dts8
-rw-r--r--src/dtc/tests/dup-phandle.dts10
-rw-r--r--src/dtc/tests/dup-propname.dts6
-rw-r--r--src/dtc/tests/empty.dts4
-rw-r--r--src/dtc/tests/escapes.dts7
-rw-r--r--src/dtc/tests/extra-terminating-null.c58
-rw-r--r--src/dtc/tests/extra-terminating-null.dts11
-rwxr-xr-xsrc/dtc/tests/fdtget-runtest.sh24
-rw-r--r--src/dtc/tests/fdtput-runtest.sh39
-rw-r--r--src/dtc/tests/find_property.c41
-rw-r--r--src/dtc/tests/get_alias.c57
-rw-r--r--src/dtc/tests/get_mem_rsv.c48
-rw-r--r--src/dtc/tests/get_name.c82
-rw-r--r--src/dtc/tests/get_path.c92
-rw-r--r--src/dtc/tests/get_phandle.c57
-rw-r--r--src/dtc/tests/getprop.c42
-rw-r--r--src/dtc/tests/incbin.bin1
-rw-r--r--src/dtc/tests/incbin.c75
-rw-r--r--src/dtc/tests/incbin.dts6
-rw-r--r--src/dtc/tests/include0.dts1
-rw-r--r--src/dtc/tests/include1.dts27
-rw-r--r--src/dtc/tests/include2.dts1
-rw-r--r--src/dtc/tests/include3.dts1
-rw-r--r--src/dtc/tests/include4.dts1
-rw-r--r--src/dtc/tests/include5.dts1
-rw-r--r--src/dtc/tests/include5a.dts1
-rw-r--r--src/dtc/tests/include6.dts1
-rw-r--r--src/dtc/tests/include7.dts12
-rw-r--r--src/dtc/tests/include8.dts1
-rw-r--r--src/dtc/tests/integer-expressions.c116
-rw-r--r--src/dtc/tests/label01.dts63
-rw-r--r--src/dtc/tests/label_repeated.dts15
-rw-r--r--src/dtc/tests/line_directives.dts21
-rw-r--r--src/dtc/tests/lorem.txt35
-rw-r--r--src/dtc/tests/mangle-layout.c164
-rw-r--r--src/dtc/tests/mangle-layout.supp7
-rw-r--r--src/dtc/tests/minusone-phandle.dts7
-rw-r--r--src/dtc/tests/move_and_save.c75
-rw-r--r--src/dtc/tests/multilabel.dts42
-rw-r--r--src/dtc/tests/multilabel_merge.dts66
-rw-r--r--src/dtc/tests/node_check_compatible.c62
-rw-r--r--src/dtc/tests/node_offset_by_compatible.c85
-rw-r--r--src/dtc/tests/node_offset_by_phandle.c63
-rw-r--r--src/dtc/tests/node_offset_by_prop_value.c110
-rw-r--r--src/dtc/tests/nonexist-label-ref.dts8
-rw-r--r--src/dtc/tests/nonexist-node-ref.dts8
-rw-r--r--src/dtc/tests/nonexist-node-ref2.dts10
-rw-r--r--src/dtc/tests/nop_node.c104
-rw-r--r--src/dtc/tests/nop_property.c70
-rw-r--r--src/dtc/tests/nopulate.c105
-rw-r--r--src/dtc/tests/notfound.c70
-rw-r--r--src/dtc/tests/obsolete-chosen-interrupt-controller.dts13
-rw-r--r--src/dtc/tests/open_pack.c71
-rw-r--r--src/dtc/tests/open_pack.supp7
-rw-r--r--src/dtc/tests/parent_offset.c90
-rw-r--r--src/dtc/tests/path-references.c82
-rw-r--r--src/dtc/tests/path-references.dts14
-rw-r--r--src/dtc/tests/path_offset.c111
-rw-r--r--src/dtc/tests/path_offset_aliases.c58
-rw-r--r--src/dtc/tests/phandle_format.c77
-rw-r--r--src/dtc/tests/prop-after-subnode.dts9
-rw-r--r--src/dtc/tests/propname_escapes.c42
-rw-r--r--src/dtc/tests/propname_escapes.dts6
-rw-r--r--src/dtc/tests/references.c108
-rw-r--r--src/dtc/tests/references.dts34
-rw-r--r--src/dtc/tests/reg-ranges-root.dts8
-rw-r--r--src/dtc/tests/reuse-label.dts15
-rw-r--r--src/dtc/tests/reuse-label1.dts10
-rw-r--r--src/dtc/tests/reuse-label2.dts6
-rw-r--r--src/dtc/tests/reuse-label3.dts9
-rw-r--r--src/dtc/tests/reuse-label4.dts5
-rw-r--r--src/dtc/tests/reuse-label5.dts6
-rw-r--r--src/dtc/tests/reuse-label6.dts6
-rw-r--r--src/dtc/tests/root_node.c52
-rwxr-xr-xsrc/dtc/tests/run_tests.sh644
-rw-r--r--src/dtc/tests/rw_tree1.c95
-rw-r--r--src/dtc/tests/search_dir/search_test.dtsi4
-rw-r--r--src/dtc/tests/search_dir/search_test2.dtsi3
-rw-r--r--src/dtc/tests/search_dir_b/search_paths_subdir.dts6
-rw-r--r--src/dtc/tests/search_dir_b/search_test_b.dtsi4
-rw-r--r--src/dtc/tests/search_dir_b/search_test_b2.dtsi5
-rw-r--r--src/dtc/tests/search_dir_b/search_test_c.dtsi2
-rw-r--r--src/dtc/tests/search_paths.dts6
-rw-r--r--src/dtc/tests/search_paths_b.dts6
-rw-r--r--src/dtc/tests/set_name.c90
-rw-r--r--src/dtc/tests/setprop.c95
-rw-r--r--src/dtc/tests/setprop_inplace.c87
-rw-r--r--src/dtc/tests/sized_cells.c83
-rw-r--r--src/dtc/tests/sized_cells.dts11
-rw-r--r--src/dtc/tests/string_escapes.c43
-rw-r--r--src/dtc/tests/subnode_iterate.c94
-rw-r--r--src/dtc/tests/subnode_iterate.dts44
-rw-r--r--src/dtc/tests/subnode_offset.c98
-rw-r--r--src/dtc/tests/supernode_atdepth_offset.c145
-rw-r--r--src/dtc/tests/sw_tree1.c99
-rw-r--r--src/dtc/tests/test01.asm294
-rw-r--r--src/dtc/tests/test01.dts57
-rw-r--r--src/dtc/tests/test01.stderr4
-rwxr-xr-xsrc/dtc/tests/test_kernel_dts86
-rw-r--r--src/dtc/tests/test_tree1.dts3
-rw-r--r--src/dtc/tests/test_tree1_body.dtsi36
-rw-r--r--src/dtc/tests/test_tree1_delete.dts68
-rw-r--r--src/dtc/tests/test_tree1_merge.dts44
-rw-r--r--src/dtc/tests/test_tree1_merge_labelled.dts42
-rw-r--r--src/dtc/tests/test_tree1_merge_path.dts42
-rw-r--r--src/dtc/tests/test_tree1_wrong1.dts36
-rw-r--r--src/dtc/tests/test_tree1_wrong2.dts36
-rw-r--r--src/dtc/tests/test_tree1_wrong3.dts36
-rw-r--r--src/dtc/tests/test_tree1_wrong4.dts34
-rw-r--r--src/dtc/tests/test_tree1_wrong5.dts37
-rw-r--r--src/dtc/tests/test_tree1_wrong6.dts38
-rw-r--r--src/dtc/tests/test_tree1_wrong7.dts39
-rw-r--r--src/dtc/tests/test_tree1_wrong8.dts37
-rw-r--r--src/dtc/tests/test_tree1_wrong9.dts38
-rw-r--r--src/dtc/tests/testdata.h36
-rw-r--r--src/dtc/tests/tests.h129
-rw-r--r--src/dtc/tests/tests.sh61
-rw-r--r--src/dtc/tests/testutils.c203
-rw-r--r--src/dtc/tests/trees.S201
-rw-r--r--src/dtc/tests/truncated_property.c47
-rw-r--r--src/dtc/tests/utilfdt_test.c127
-rw-r--r--src/dtc/tests/value-labels.c127
-rw-r--r--src/dtc/tests/value-labels.dts8
-rw-r--r--src/dtc/tests/zero-phandle.dts7
-rw-r--r--src/dtc/treesource.c284
-rw-r--r--src/dtc/util.c448
-rw-r--r--src/dtc/util.h250
210 files changed, 21086 insertions, 0 deletions
diff --git a/src/dtc/.gitignore b/src/dtc/.gitignore
new file mode 100644
index 0000000..545b899
--- /dev/null
+++ b/src/dtc/.gitignore
@@ -0,0 +1,17 @@
+*.o
+*.d
+*.a
+*.patch
+*.so
+*~
+*.tab.[ch]
+lex.yy.c
+*.lex.c
+/dtc
+/fdtdump
+/convert-dtsv0
+/version_gen.h
+/fdtget
+/fdtput
+/patches
+/.pc
diff --git a/src/dtc/Documentation/dtc-paper.bib b/src/dtc/Documentation/dtc-paper.bib
new file mode 100644
index 0000000..d01e2ff
--- /dev/null
+++ b/src/dtc/Documentation/dtc-paper.bib
@@ -0,0 +1,43 @@
+@STRING{pub-IEEE = "IEEE Computer Society"}
+@STRING{pub-IEEE:adr = "345 E. 47th St, New York, NY 10017, USA"}
+
+@BOOK{IEEE1275,
+ key = "IEEE1275",
+ title = "{IEEE} {S}tandard for {B}oot ({I}nitialization {C}onfiguration) {F}irmware: {C}ore {R}equirements and {P}ractices",
+ publisher = pub-IEEE,
+ address = pub-IEEE:adr,
+ series = "IEEE Std 1275-1994",
+ year = 1994,
+}
+
+@BOOK{IEEE1275-pci,
+ key = "IEEE1275-pci",
+ title = "{PCI} {B}us {B}inding to: {IEEE} {S}td 1275-1994 {S}tandard for {B}oot ({I}nitialization {C}onfiguration) {F}irmware",
+ publisher = pub-IEEE,
+ address = pub-IEEE:adr,
+ note = "Revision 2.1",
+ year = 1998,
+}
+
+@MISC{noof1,
+ author = "Benjamin Herrenschmidt",
+ title = "Booting the {L}inux/ppc kernel without {O}pen {F}irmware",
+ month = may,
+ year = 2005,
+ note = "v0.1, \url{http://ozlabs.org/pipermail/linuxppc64-dev/2005-May/004073.html}",
+}
+
+@MISC{noof5,
+ author = "Benjamin Herrenschmidt",
+ title = "Booting the {L}inux/ppc kernel without {O}pen {F}irmware",
+ month = nov,
+ year = 2005,
+ note = "v0.5, \url{http://ozlabs.org/pipermail/linuxppc64-dev/2005-December/006994.html}",
+}
+
+@MISC{dtcgit,
+ author = "David Gibson et al.",
+ title = "\dtc{}",
+ howpublished = "git tree",
+ note = "\url{http://ozlabs.org/~dgibson/dtc/dtc.git}",
+}
diff --git a/src/dtc/Documentation/dtc-paper.tex b/src/dtc/Documentation/dtc-paper.tex
new file mode 100644
index 0000000..4494226
--- /dev/null
+++ b/src/dtc/Documentation/dtc-paper.tex
@@ -0,0 +1,597 @@
+\documentclass[a4paper,twocolumn]{article}
+
+\usepackage{abstract}
+\usepackage{xspace}
+\usepackage{amssymb}
+\usepackage{latexsym}
+\usepackage{tabularx}
+\usepackage[T1]{fontenc}
+\usepackage{calc}
+\usepackage{listings}
+\usepackage{color}
+\usepackage{url}
+
+\title{Device trees everywhere}
+
+\author{David Gibson \texttt{<{dwg}{@}{au1.ibm.com}>}\\
+ Benjamin Herrenschmidt \texttt{<{benh}{@}{kernel.crashing.org}>}\\
+ \emph{OzLabs, IBM Linux Technology Center}}
+
+\newcommand{\R}{\textsuperscript{\textregistered}\xspace}
+\newcommand{\tm}{\textsuperscript{\texttrademark}\xspace}
+\newcommand{\tge}{$\geqslant$}
+%\newcommand{\ditto}{\textquotedbl\xspace}
+
+\newcommand{\fixme}[1]{$\bigstar$\emph{\textbf{\large #1}}$\bigstar$\xspace}
+
+\newcommand{\ppc}{\mbox{PowerPC}\xspace}
+\newcommand{\of}{Open Firmware\xspace}
+\newcommand{\benh}{Ben Herrenschmidt\xspace}
+\newcommand{\kexec}{\texttt{kexec()}\xspace}
+\newcommand{\dtbeginnode}{\texttt{OF\_DT\_BEGIN\_NODE\xspace}}
+\newcommand{\dtendnode}{\texttt{OF\_DT\_END\_NODE\xspace}}
+\newcommand{\dtprop}{\texttt{OF\_DT\_PROP\xspace}}
+\newcommand{\dtend}{\texttt{OF\_DT\_END\xspace}}
+\newcommand{\dtc}{\texttt{dtc}\xspace}
+\newcommand{\phandle}{\texttt{linux,phandle}\xspace}
+\begin{document}
+
+\maketitle
+
+\begin{abstract}
+ We present a method for booting a \ppc{}\R Linux\R kernel on an
+ embedded machine. To do this, we supply the kernel with a compact
+ flattened-tree representation of the system's hardware based on the
+ device tree supplied by Open Firmware on IBM\R servers and Apple\R
+ Power Macintosh\R machines.
+
+ The ``blob'' representing the device tree can be created using \dtc
+ --- the Device Tree Compiler --- that turns a simple text
+ representation of the tree into the compact representation used by
+ the kernel. The compiler can produce either a binary ``blob'' or an
+ assembler file ready to be built into a firmware or bootwrapper
+ image.
+
+ This flattened-tree approach is now the only supported method of
+ booting a \texttt{ppc64} kernel without Open Firmware, and we plan
+ to make it the only supported method for all \texttt{powerpc}
+ kernels in the future.
+\end{abstract}
+
+\section{Introduction}
+
+\subsection{OF and the device tree}
+
+Historically, ``everyday'' \ppc machines have booted with the help of
+\of (OF), a firmware environment defined by IEEE1275 \cite{IEEE1275}.
+Among other boot-time services, OF maintains a device tree that
+describes all of the system's hardware devices and how they're
+connected. During boot, before taking control of memory management,
+the Linux kernel uses OF calls to scan the device tree and transfer it
+to an internal representation that is used at run time to look up
+various device information.
+
+The device tree consists of nodes representing devices or
+buses\footnote{Well, mostly. There are a few special exceptions.}.
+Each node contains \emph{properties}, name--value pairs that give
+information about the device. The values are arbitrary byte strings,
+and for some properties, they contain tables or other structured
+information.
+
+\subsection{The bad old days}
+
+Embedded systems, by contrast, usually have a minimal firmware that
+might supply a few vital system parameters (size of RAM and the like),
+but nothing as detailed or complete as the OF device tree. This has
+meant that the various 32-bit \ppc embedded ports have required a
+variety of hacks spread across the kernel to deal with the lack of
+device tree. These vary from specialised boot wrappers to parse
+parameters (which are at least reasonably localised) to
+CONFIG-dependent hacks in drivers to override normal probe logic with
+hardcoded addresses for a particular board. As well as being ugly of
+itself, such CONFIG-dependent hacks make it hard to build a single
+kernel image that supports multiple embedded machines.
+
+Until relatively recently, the only 64-bit \ppc machines without OF
+were legacy (pre-POWER5\R) iSeries\R machines. iSeries machines often
+only have virtual IO devices, which makes it quite simple to work
+around the lack of a device tree. Even so, the lack means the iSeries
+boot sequence must be quite different from the pSeries or Macintosh,
+which is not ideal.
+
+The device tree also presents a problem for implementing \kexec. When
+the kernel boots, it takes over full control of the system from OF,
+even re-using OF's memory. So, when \kexec comes to boot another
+kernel, OF is no longer around for the second kernel to query.
+
+\section{The Flattened Tree}
+
+In May 2005 \benh implemented a new approach to handling the device
+tree that addresses all these problems. When booting on OF systems,
+the first thing the kernel runs is a small piece of code in
+\texttt{prom\_init.c}, which executes in the context of OF. This code
+walks the device tree using OF calls, and transcribes it into a
+compact, flattened format. The resulting device tree ``blob'' is then
+passed to the kernel proper, which eventually unflattens the tree into
+its runtime form. This blob is the only data communicated between the
+\texttt{prom\_init.c} bootstrap and the rest of the kernel.
+
+When OF isn't available, either because the machine doesn't have it at
+all or because \kexec has been used, the kernel instead starts
+directly from the entry point taking a flattened device tree. The
+device tree blob must be passed in from outside, rather than generated
+by part of the kernel from OF. For \kexec, the userland
+\texttt{kexec} tools build the blob from the runtime device tree
+before invoking the new kernel. For embedded systems the blob can
+come either from the embedded bootloader, or from a specialised
+version of the \texttt{zImage} wrapper for the system in question.
+
+\subsection{Properties of the flattened tree}
+
+The flattened tree format should be easy to handle, both for the
+kernel that parses it and the bootloader that generates it. In
+particular, the following properties are desirable:
+
+\begin{itemize}
+\item \emph{relocatable}: the bootloader or kernel should be able to
+ move the blob around as a whole, without needing to parse or adjust
+ its internals. In practice that means we must not use pointers
+ within the blob.
+\item \emph{insert and delete}: sometimes the bootloader might want to
+ make tweaks to the flattened tree, such as deleting or inserting a
+ node (or whole subtree). It should be possible to do this without
+ having to effectively regenerate the whole flattened tree. In
+ practice this means limiting the use of internal offsets in the blob
+ that need recalculation if a section is inserted or removed with
+ \texttt{memmove()}.
+\item \emph{compact}: embedded systems are frequently short of
+ resources, particularly RAM and flash memory space. Thus, the tree
+ representation should be kept as small as conveniently possible.
+\end{itemize}
+
+\subsection{Format of the device tree blob}
+\label{sec:format}
+
+\begin{figure}[htb!]
+ \centering
+ \footnotesize
+ \begin{tabular}{r|c|l}
+ \multicolumn{1}{r}{\textbf{Offset}}& \multicolumn{1}{c}{\textbf{Contents}} \\\cline{2-2}
+ \texttt{0x00} & \texttt{0xd00dfeed} & magic number \\\cline{2-2}
+ \texttt{0x04} & \emph{totalsize} \\\cline{2-2}
+ \texttt{0x08} & \emph{off\_struct} & \\\cline{2-2}
+ \texttt{0x0C} & \emph{off\_strs} & \\\cline{2-2}
+ \texttt{0x10} & \emph{off\_rsvmap} & \\\cline{2-2}
+ \texttt{0x14} & \emph{version} \\\cline{2-2}
+ \texttt{0x18} & \emph{last\_comp\_ver} & \\\cline{2-2}
+ \texttt{0x1C} & \emph{boot\_cpu\_id} & \tge v2 only\\\cline{2-2}
+ \texttt{0x20} & \emph{size\_strs} & \tge v3 only\\\cline{2-2}
+ \multicolumn{1}{r}{\vdots} & \multicolumn{1}{c}{\vdots} & \\\cline{2-2}
+ \emph{off\_rsvmap} & \emph{address0} & memory reserve \\
+ + \texttt{0x04} & ...& table \\\cline{2-2}
+ + \texttt{0x08} & \emph{len0} & \\
+ + \texttt{0x0C} & ...& \\\cline{2-2}
+ \vdots & \multicolumn{1}{c|}{\vdots} & \\\cline{2-2}
+ & \texttt{0x00000000}- & end marker\\
+ & \texttt{00000000} & \\\cline{2-2}
+ & \texttt{0x00000000}- & \\
+ & \texttt{00000000} & \\\cline{2-2}
+ \multicolumn{1}{r}{\vdots} & \multicolumn{1}{c}{\vdots} & \\\cline{2-2}
+ \emph{off\_strs} & \texttt{'n' 'a' 'm' 'e'} & strings block \\
+ + \texttt{0x04} & \texttt{~0~ 'm' 'o' 'd'} & \\
+ + \texttt{0x08} & \texttt{'e' 'l' ~0~ \makebox[\widthof{~~~}]{\textrm{...}}} & \\
+ \vdots & \multicolumn{1}{c|}{\vdots} & \\\cline{2-2}
+ \multicolumn{1}{r}{+ \emph{size\_strs}} \\
+ \multicolumn{1}{r}{\vdots} & \multicolumn{1}{c}{\vdots} & \\\cline{2-2}
+ \emph{off\_struct} & \dtbeginnode & structure block \\\cline{2-2}
+ + \texttt{0x04} & \texttt{'/' ~0~ ~0~ ~0~} & root node\\\cline{2-2}
+ + \texttt{0x08} & \dtprop & \\\cline{2-2}
+ + \texttt{0x0C} & \texttt{0x00000005} & ``\texttt{model}''\\\cline{2-2}
+ + \texttt{0x10} & \texttt{0x00000008} & \\\cline{2-2}
+ + \texttt{0x14} & \texttt{'M' 'y' 'B' 'o'} & \\
+ + \texttt{0x18} & \texttt{'a' 'r' 'd' ~0~} & \\\cline{2-2}
+ \vdots & \multicolumn{1}{c|}{\vdots} & \\\cline{2-2}
+ & \texttt{\dtendnode} \\\cline{2-2}
+ & \texttt{\dtend} \\\cline{2-2}
+ \multicolumn{1}{r}{\vdots} & \multicolumn{1}{c}{\vdots} & \\\cline{2-2}
+ \multicolumn{1}{r}{\emph{totalsize}} \\
+ \end{tabular}
+ \caption{Device tree blob layout}
+ \label{fig:blob-layout}
+\end{figure}
+
+The format for the blob we devised, was first described on the
+\texttt{linuxppc64-dev} mailing list in \cite{noof1}. The format has
+since evolved through various revisions, and the current version is
+included as part of the \dtc (see \S\ref{sec:dtc}) git tree,
+\cite{dtcgit}.
+
+Figure \ref{fig:blob-layout} shows the layout of the blob of data
+containing the device tree. It has three sections of variable size:
+the \emph{memory reserve table}, the \emph{structure block} and the
+\emph{strings block}. A small header gives the blob's size and
+version and the locations of the three sections, plus a handful of
+vital parameters used during early boot.
+
+The memory reserve map section gives a list of regions of memory that
+the kernel must not use\footnote{Usually such ranges contain some data
+structure initialised by the firmware that must be preserved by the
+kernel.}. The list is represented as a simple array of (address,
+size) pairs of 64 bit values, terminated by a zero size entry. The
+strings block is similarly simple, consisting of a number of
+null-terminated strings appended together, which are referenced from
+the structure block as described below.
+
+The structure block contains the device tree proper. Each node is
+introduced with a 32-bit \dtbeginnode tag, followed by the node's name
+as a null-terminated string, padded to a 32-bit boundary. Then
+follows all of the properties of the node, each introduced with a
+\dtprop tag, then all of the node's subnodes, each introduced with
+their own \dtbeginnode tag. The node ends with an \dtendnode tag, and
+after the \dtendnode for the root node is an \dtend tag, indicating
+the end of the whole tree\footnote{This is redundant, but included for
+ease of parsing.}. The structure block starts with the \dtbeginnode
+introducing the description of the root node (named \texttt{/}).
+
+Each property, after the \dtprop, has a 32-bit value giving an offset
+from the beginning of the strings block at which the property name is
+stored. Because it's common for many nodes to have properties with
+the same name, this approach can substantially reduce the total size
+of the blob. The name offset is followed by the length of the
+property value (as a 32-bit value) and then the data itself padded to
+a 32-bit boundary.
+
+\subsection{Contents of the tree}
+\label{sec:treecontents}
+
+Having seen how to represent the device tree structure as a flattened
+blob, what actually goes into the tree? The short answer is ``the
+same as an OF tree''. On OF systems, the flattened tree is
+transcribed directly from the OF device tree, so for simplicity we
+also use OF conventions for the tree on other systems.
+
+In many cases a flat tree can be simpler than a typical OF provided
+device tree. The flattened tree need only provide those nodes and
+properties that the kernel actually requires; the flattened tree
+generally need not include devices that the kernel can probe itself.
+For example, an OF device tree would normally include nodes for each
+PCI device on the system. A flattened tree need only include nodes
+for the PCI host bridges; the kernel will scan the buses thus
+described to find the subsidiary devices. The device tree can include
+nodes for devices where the kernel needs extra information, though:
+for example, for ISA devices on a subsidiary PCI/ISA bridge, or for
+devices with unusual interrupt routing.
+
+Where they exist, we follow the IEEE1275 bindings that specify how to
+describe various buses in the device tree (for example,
+\cite{IEEE1275-pci} describe how to represent PCI devices). The
+standard has not been updated for a long time, however, and lacks
+bindings for many modern buses and devices. In particular, embedded
+specific devices such as the various System-on-Chip buses are not
+covered. We intend to create new bindings for such buses, in keeping
+with the general conventions of IEEE1275 (a simple such binding for a
+System-on-Chip bus was included in \cite{noof5} a revision of
+\cite{noof1}).
+
+One complication arises for representing ``phandles'' in the flattened
+tree. In OF, each node in the tree has an associated phandle, a
+32-bit integer that uniquely identifies the node\footnote{In practice
+usually implemented as a pointer or offset within OF memory.}. This
+handle is used by the various OF calls to query and traverse the tree.
+Sometimes phandles are also used within the tree to refer to other
+nodes in the tree. For example, devices that produce interrupts
+generally have an \texttt{interrupt-parent} property giving the
+phandle of the interrupt controller that handles interrupts from this
+device. Parsing these and other interrupt related properties allows
+the kernel to build a complete representation of the system's
+interrupt tree, which can be quite different from the tree of bus
+connections.
+
+In the flattened tree, a node's phandle is represented by a special
+\phandle property. When the kernel generates a flattened tree from
+OF, it adds a \phandle property to each node, containing the phandle
+retrieved from OF. When the tree is generated without OF, however,
+only nodes that are actually referred to by phandle need to have this
+property.
+
+Another complication arises because nodes in an OF tree have two
+names. First they have the ``unit name'', which is how the node is
+referred to in an OF path. The unit name generally consists of a
+device type followed by an \texttt{@} followed by a \emph{unit
+address}. For example \texttt{/memory@0} is the full path of a memory
+node at address 0, \texttt{/ht@0,f2000000/pci@1} is the path of a PCI
+bus node, which is under a HyperTransport\tm bus node. The form of
+the unit address is bus dependent, but is generally derived from the
+node's \texttt{reg} property. In addition, nodes have a property,
+\texttt{name}, whose value is usually equal to the first path of the
+unit name. For example, the nodes in the previous example would have
+\texttt{name} properties equal to \texttt{memory} and \texttt{pci},
+respectively. To save space in the blob, the current version of the
+flattened tree format only requires the unit names to be present.
+When the kernel unflattens the tree, it automatically generates a
+\texttt{name} property from the node's path name.
+
+\section{The Device Tree Compiler}
+\label{sec:dtc}
+
+\begin{figure}[htb!]
+ \centering
+ \begin{lstlisting}[frame=single,basicstyle=\footnotesize\ttfamily,
+ tabsize=3,numbers=left,xleftmargin=2em]
+/memreserve/ 0x20000000-0x21FFFFFF;
+
+/ {
+ model = "MyBoard";
+ compatible = "MyBoardFamily";
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ PowerPC,970@0 {
+ device_type = "cpu";
+ reg = <0>;
+ clock-frequency = <5f5e1000>;
+ timebase-frequency = <1FCA055>;
+ linux,boot-cpu;
+ i-cache-size = <10000>;
+ d-cache-size = <8000>;
+ };
+ };
+
+ memory@0 {
+ device_type = "memory";
+ memreg: reg = <00000000 00000000
+ 00000000 20000000>;
+ };
+
+ mpic@0x3fffdd08400 {
+ /* Interrupt controller */
+ /* ... */
+ };
+
+ pci@40000000000000 {
+ /* PCI host bridge */
+ /* ... */
+ };
+
+ chosen {
+ bootargs = "root=/dev/sda2";
+ linux,platform = <00000600>;
+ interrupt-controller =
+ < &/mpic@0x3fffdd08400 >;
+ };
+};
+\end{lstlisting}
+ \caption{Example \dtc source}
+ \label{fig:dts}
+\end{figure}
+
+As we've seen, the flattened device tree format provides a convenient
+way of communicating device tree information to the kernel. It's
+simple for the kernel to parse, and simple for bootloaders to
+manipulate. On OF systems, it's easy to generate the flattened tree
+by walking the OF maintained tree. However, for embedded systems, the
+flattened tree must be generated from scratch.
+
+Embedded bootloaders are generally built for a particular board. So,
+it's usually possible to build the device tree blob at compile time
+and include it in the bootloader image. For minor revisions of the
+board, the bootloader can contain code to make the necessary tweaks to
+the tree before passing it to the booted kernel.
+
+The device trees for embedded boards are usually quite simple, and
+it's possible to hand construct the necessary blob by hand, but doing
+so is tedious. The ``device tree compiler'', \dtc{}\footnote{\dtc can
+be obtained from \cite{dtcgit}.}, is designed to make creating device
+tree blobs easier by converting a text representation of the tree
+into the necessary blob.
+
+\subsection{Input and output formats}
+
+As well as the normal mode of compiling a device tree blob from text
+source, \dtc can convert a device tree between a number of
+representations. It can take its input in one of three different
+formats:
+\begin{itemize}
+\item source, the normal case. The device tree is described in a text
+ form, described in \S\ref{sec:dts}.
+\item blob (\texttt{dtb}), the flattened tree format described in
+ \S\ref{sec:format}. This mode is useful for checking a pre-existing
+ device tree blob.
+\item filesystem (\texttt{fs}), input is a directory tree in the
+ layout of \texttt{/proc/device-tree} (roughly, a directory for each
+ node in the device tree, a file for each property). This is useful
+ for building a blob for the device tree in use by the currently
+ running kernel.
+\end{itemize}
+
+In addition, \dtc can output the tree in one of three different
+formats:
+\begin{itemize}
+\item blob (\texttt{dtb}), as in \S\ref{sec:format}. The most
+ straightforward use of \dtc is to compile from ``source'' to
+ ``blob'' format.
+\item source (\texttt{dts}), as in \S\ref{sec:dts}. If used with blob
+ input, this allows \dtc to act as a ``decompiler''.
+\item assembler source (\texttt{asm}). \dtc can produce an assembler
+ file, which will assemble into a \texttt{.o} file containing the
+ device tree blob, with symbols giving the beginning of the blob and
+ its various subsections. This can then be linked directly into a
+ bootloader or firmware image.
+\end{itemize}
+
+For maximum applicability, \dtc can both read and write any of the
+existing revisions of the blob format. When reading, \dtc takes the
+version from the blob header, and when writing it takes a command line
+option specifying the desired version. It automatically makes any
+necessary adjustments to the tree that are necessary for the specified
+version. For example, formats before 0x10 require each node to have
+an explicit \texttt{name} property. When \dtc creates such a blob, it
+will automatically generate \texttt{name} properties from the unit
+names.
+
+\subsection{Source format}
+\label{sec:dts}
+
+The ``source'' format for \dtc is a text description of the device
+tree in a vaguely C-like form. Figure \ref{fig:dts} shows an
+example. The file starts with \texttt{/memreserve/} directives, which
+gives address ranges to add to the output blob's memory reserve table,
+then the device tree proper is described.
+
+Nodes of the tree are introduced with the node name, followed by a
+\texttt{\{} ... \texttt{\};} block containing the node's properties
+and subnodes. Properties are given as just {\emph{name} \texttt{=}
+ \emph{value}\texttt{;}}. The property values can be given in any
+of three forms:
+\begin{itemize}
+\item \emph{string} (for example, \texttt{"MyBoard"}). The property
+ value is the given string, including terminating NULL. C-style
+ escapes (\verb+\t+, \verb+\n+, \verb+\0+ and so forth) are allowed.
+\item \emph{cells} (for example, \texttt{<0 8000 f0000000>}). The
+ property value is made up of a list of 32-bit ``cells'', each given
+ as a hex value.
+\item \emph{bytestring} (for example, \texttt{[1234abcdef]}). The
+ property value is given as a hex bytestring.
+\end{itemize}
+
+Cell properties can also contain \emph{references}. Instead of a hex
+number, the source can give an ampersand (\texttt{\&}) followed by the
+full path to some node in the tree. For example, in Figure
+\ref{fig:dts}, the \texttt{/chosen} node has an
+\texttt{interrupt-controller} property referring to the interrupt
+controller described by the node \texttt{/mpic@0x3fffdd08400}. In the
+output tree, the value of the referenced node's phandle is included in
+the property. If that node doesn't have an explicit phandle property,
+\dtc will automatically create a unique phandle for it. This approach
+makes it easy to create interrupt trees without having to explicitly
+assign and remember phandles for the various interrupt controller
+nodes.
+
+The \dtc source can also include ``labels'', which are placed on a
+particular node or property. For example, Figure \ref{fig:dts} has a
+label ``\texttt{memreg}'' on the \texttt{reg} property of the node
+\texttt{/memory@0}. When using assembler output, corresponding labels
+in the output are generated, which will assemble into symbols
+addressing the part of the blob with the node or property in question.
+This is useful for the common case where an embedded board has an
+essentially fixed device tree with a few variable properties, such as
+the size of memory. The bootloader for such a board can have a device
+tree linked in, including a symbol referring to the right place in the
+blob to update the parameter with the correct value determined at
+runtime.
+
+\subsection{Tree checking}
+
+Between reading in the device tree and writing it out in the new
+format, \dtc performs a number of checks on the tree:
+\begin{itemize}
+\item \emph{syntactic structure}: \dtc checks that node and property
+ names contain only allowed characters and meet length restrictions.
+ It checks that a node does not have multiple properties or subnodes
+ with the same name.
+\item \emph{semantic structure}: In some cases, \dtc checks that
+ properties whose contents are defined by convention have appropriate
+ values. For example, it checks that \texttt{reg} properties have a
+ length that makes sense given the address forms specified by the
+ \texttt{\#address-cells} and \texttt{\#size-cells} properties. It
+ checks that properties such as \texttt{interrupt-parent} contain a
+ valid phandle.
+\item \emph{Linux requirements}: \dtc checks that the device tree
+ contains those nodes and properties that are required by the Linux
+ kernel to boot correctly.
+\end{itemize}
+
+These checks are useful to catch simple problems with the device tree,
+rather than having to debug the results on an embedded kernel. With
+the blob input mode, it can also be used for diagnosing problems with
+an existing blob.
+
+\section{Future Work}
+
+\subsection{Board ports}
+
+The flattened device tree has always been the only supported way to
+boot a \texttt{ppc64} kernel on an embedded system. With the merge of
+\texttt{ppc32} and \texttt{ppc64} code it has also become the only
+supported way to boot any merged \texttt{powerpc} kernel, 32-bit or
+64-bit. In fact, the old \texttt{ppc} architecture exists mainly just
+to support the old ppc32 embedded ports that have not been migrated
+to the flattened device tree approach. We plan to remove the
+\texttt{ppc} architecture eventually, which will mean porting all the
+various embedded boards to use the flattened device tree.
+
+\subsection{\dtc features}
+
+While it is already quite usable, there are a number of extra features
+that \dtc could include to make creating device trees more convenient:
+\begin{itemize}
+\item \emph{better tree checking}: Although \dtc already performs a
+ number of checks on the device tree, they are rather haphazard. In
+ many cases \dtc will give up after detecting a minor error early and
+ won't pick up more interesting errors later on. There is a
+ \texttt{-f} parameter that forces \dtc to generate an output tree
+ even if there are errors. At present, this needs to be used more
+ often than one might hope, because \dtc is bad at deciding which
+ errors should really be fatal, and which rate mere warnings.
+\item \emph{binary include}: Occasionally, it is useful for the device
+ tree to incorporate as a property a block of binary data for some
+ board-specific purpose. For example, many of Apple's device trees
+ incorporate bytecode drivers for certain platform devices. \dtc's
+ source format ought to allow this by letting a property's value be
+ read directly from a binary file.
+\item \emph{macros}: it might be useful for \dtc to implement some
+ sort of macros so that a tree containing a number of similar devices
+ (for example, multiple identical ethernet controllers or PCI buses)
+ can be written more quickly. At present, this can be accomplished
+ in part by running the source file through CPP before compiling with
+ \dtc. It's not clear whether ``native'' support for macros would be
+ more useful.
+\end{itemize}
+
+\bibliographystyle{amsplain}
+\bibliography{dtc-paper}
+
+\section*{About the authors}
+
+David Gibson has been a member of the IBM Linux Technology Center,
+working from Canberra, Australia, since 2001. Recently he has worked
+on Linux hugepage support and performance counter support for ppc64,
+as well as the device tree compiler. In the past, he has worked on
+bringup for various ppc and ppc64 embedded systems, the orinoco
+wireless driver, ramfs, and a userspace checkpointing system
+(\texttt{esky}).
+
+Benjamin Herrenschmidt was a MacOS developer for about 10 years, but
+ultimately saw the light and installed Linux on his Apple PowerPC
+machine. After writing a bootloader, BootX, for it in 1998, he
+started contributing to the PowerPC Linux port in various areas,
+mostly around the support for Apple machines. He became official
+PowerMac maintainer in 2001. In 2003, he joined the IBM Linux
+Technology Center in Canberra, Australia, where he ported the 64 bit
+PowerPC kernel to Apple G5 machines and the Maple embedded board,
+among others things. He's a member of the ppc64 development ``team''
+and one of his current goals is to make the integration of embedded
+platforms smoother and more maintainable than in the 32-bit PowerPC
+kernel.
+
+\section*{Legal Statement}
+
+This work represents the view of the author and does not necessarily
+represent the view of IBM.
+
+IBM, \ppc, \ppc Architecture, POWER5, pSeries and iSeries are
+trademarks or registered trademarks of International Business Machines
+Corporation in the United States and/or other countries.
+
+Apple and Power Macintosh are a registered trademarks of Apple
+Computer Inc. in the United States, other countries, or both.
+
+Linux is a registered trademark of Linus Torvalds.
+
+Other company, product, and service names may be trademarks or service
+marks of others.
+
+\end{document}
diff --git a/src/dtc/Documentation/dts-format.txt b/src/dtc/Documentation/dts-format.txt
new file mode 100644
index 0000000..41741df
--- /dev/null
+++ b/src/dtc/Documentation/dts-format.txt
@@ -0,0 +1,122 @@
+Device Tree Source Format (version 1)
+=====================================
+
+The Device Tree Source (DTS) format is a textual representation of a
+device tree in a form that can be processed by dtc into a binary
+device tree in the form expected by the kernel. The description below
+is not a formal syntax definition of DTS, but describes the basic
+constructs used to represent device trees.
+
+Node and property definitions
+-----------------------------
+
+Device tree nodes are defined with a node name and unit address with
+braces marking the start and end of the node definition. They may be
+preceded by a label.
+
+ [label:] node-name[@unit-address] {
+ [properties definitions]
+ [child nodes]
+ }
+
+Nodes may contain property definitions and/or child node
+definitions. If both are present, properties must come before child
+nodes.
+
+Property definitions are name value pairs in the form:
+ [label:] property-name = value;
+except for properties with empty (zero length) value which have the
+form:
+ [label:] property-name;
+
+Property values may be defined as an array of 8, 16, 32, or 64-bit integer
+elements, as NUL-terminated strings, as bytestrings or a combination of these.
+
+* Arrays are represented by angle brackets surrounding a space separated list
+ of C-style integers or character literals. Array elements default to 32-bits
+ in size. An array of 32-bit elements is also known as a cell list or a list
+ of cells. A cell being an unsigned 32-bit integer.
+
+ e.g. interrupts = <17 0xc>;
+
+* A 64-bit value can be represented with two 32-bit elements.
+
+ e.g. clock-frequency = <0x00000001 0x00000000>;
+
+* The storage size of an element can be changed using the /bits/ prefix. The
+ /bits/ prefix allows for the creation of 8, 16, 32, and 64-bit elements.
+ The resulting array will not be padded to a multiple of the default 32-bit
+ element size.
+
+ e.g. interrupts = /bits/ 8 <17 0xc>;
+ e.g. clock-frequency = /bits/ 64 <0x0000000100000000>;
+
+* A NUL-terminated string value is represented using double quotes
+ (the property value is considered to include the terminating NUL
+ character).
+
+ e.g. compatible = "simple-bus";
+
+* A bytestring is enclosed in square brackets [] with each byte
+ represented by two hexadecimal digits. Spaces between each byte are
+ optional.
+
+ e.g. local-mac-address = [00 00 12 34 56 78]; or equivalently
+ local-mac-address = [000012345678];
+
+* Values may have several comma-separated components, which are
+ concatenated together.
+ e.g. compatible = "ns16550", "ns8250";
+ example = <0xf00f0000 19>, "a strange property format";
+
+* In an array a reference to another node will be expanded to that node's
+ phandle. References may by '&' followed by a node's label:
+ e.g. interrupt-parent = < &mpic >;
+ or they may be '&' followed by a node's full path in braces:
+ e.g. interrupt-parent = < &{/soc/interrupt-controller@40000} >;
+ References are only permitted in arrays that have an element size of
+ 32-bits.
+
+* Outside an array, a reference to another node will be expanded to that
+ node's full path.
+ e.g. ethernet0 = &EMAC0;
+
+* Labels may also appear before or after any component of a property
+ value, or between elements of an array, or between bytes of a bytestring.
+ e.g. reg = reglabel: <0 sizelabel: 0x1000000>;
+ e.g. prop = [ab cd ef byte4: 00 ff fe];
+ e.g. str = start: "string value" end: ;
+
+
+File layout
+-----------
+
+Version 1 DTS files have the overall layout:
+ /dts-v1/;
+
+ [memory reservations]
+
+ / {
+ [property definitions]
+ [child nodes]
+ };
+
+* The "/dts-v1/;" must be present to identify the file as a version 1
+ DTS (dts files without this tag will be treated by dtc as being in
+ the obsolete "version 0", which uses a different format for integers
+ amongst other small but incompatible changes).
+
+* Memory reservations define an entry for the device tree blob's
+ memory reservation table. They have the form:
+ e.g. /memreserve/ <address> <length>;
+ Where <address> and <length> are 64-bit C-style integers.
+
+* The / { ... }; section defines the root node of the device tree.
+
+* C style (/* ... */) and C++ style (// ...) comments are supported.
+
+
+
+ -- David Gibson <david@gibson.dropbear.id.au>
+ -- Yoder Stuart <stuart.yoder@freescale.com>
+ -- Anton Staaf <robotboy@chromium.org>
diff --git a/src/dtc/Documentation/manual.txt b/src/dtc/Documentation/manual.txt
new file mode 100644
index 0000000..65c8540
--- /dev/null
+++ b/src/dtc/Documentation/manual.txt
@@ -0,0 +1,660 @@
+Device Tree Compiler Manual
+===========================
+
+I - "dtc", the device tree compiler
+ 1) Obtaining Sources
+ 1.1) Submitting Patches
+ 2) Description
+ 3) Command Line
+ 4) Source File
+ 4.1) Overview
+ 4.2) Properties
+ 4.3) Labels and References
+
+II - The DT block format
+ 1) Header
+ 2) Device tree generalities
+ 3) Device tree "structure" block
+ 4) Device tree "strings" block
+
+
+III - libfdt
+
+IV - Utility Tools
+ 1) convert-dtsv0 -- Conversion to Version 1
+ 1) fdtdump
+
+
+I - "dtc", the device tree compiler
+===================================
+
+1) Sources
+
+Source code for the Device Tree Compiler can be found at jdl.com.
+The gitweb interface is:
+
+ http://git.jdl.com/gitweb/
+
+The repository is here:
+
+ git://www.jdl.com/software/dtc.git
+ http://www.jdl.com/software/dtc.git
+
+Tarballs of the 1.0.0 and latest releases are here:
+
+ http://www.jdl.com/software/dtc-v1.2.0.tgz
+ http://www.jdl.com/software/dtc-latest.tgz
+
+1.1) Submitting Patches
+
+Patches should be sent to jdl@jdl.com, and CC'ed to
+devicetree-discuss@lists.ozlabs.org.
+
+2) Description
+
+The Device Tree Compiler, dtc, takes as input a device-tree in
+a given format and outputs a device-tree in another format.
+Typically, the input format is "dts", a human readable source
+format, and creates a "dtb", or binary format as output.
+
+The currently supported Input Formats are:
+
+ - "dtb": "blob" format. A flattened device-tree block with
+ header in one binary blob.
+
+ - "dts": "source" format. A text file containing a "source"
+ for a device-tree.
+
+ - "fs" format. A representation equivalent to the output of
+ /proc/device-tree where nodes are directories and
+ properties are files.
+
+The currently supported Output Formats are:
+
+ - "dtb": "blob" format
+
+ - "dts": "source" format
+
+ - "asm": assembly language file. A file that can be sourced
+ by gas to generate a device-tree "blob". That file can
+ then simply be added to your Makefile. Additionally, the
+ assembly file exports some symbols that can be used.
+
+
+3) Command Line
+
+The syntax of the dtc command line is:
+
+ dtc [options] [<input_filename>]
+
+Options:
+
+ <input_filename>
+ The name of the input source file. If no <input_filename>
+ or "-" is given, stdin is used.
+
+ -b <number>
+ Set the physical boot cpu.
+
+ -f
+ Force. Try to produce output even if the input tree has errors.
+
+ -h
+ Emit a brief usage and help message.
+
+ -I <input_format>
+ The source input format, as listed above.
+
+ -o <output_filename>
+ The name of the generated output file. Use "-" for stdout.
+
+ -O <output_format>
+ The generated output format, as listed above.
+
+ -d <dependency_filename>
+ Generate a dependency file during compilation.
+
+ -q
+ Quiet: -q suppress warnings, -qq errors, -qqq all
+
+ -R <number>
+ Make space for <number> reserve map entries
+ Relevant for dtb and asm output only.
+
+ -S <bytes>
+ Ensure the blob at least <bytes> long, adding additional
+ space if needed.
+
+ -v
+ Print DTC version and exit.
+
+ -V <output_version>
+ Generate output conforming to the given <output_version>.
+ By default the most recent version is generated.
+ Relevant for dtb and asm output only.
+
+
+The <output_version> defines what version of the "blob" format will be
+generated. Supported versions are 1, 2, 3, 16 and 17. The default is
+always the most recent version and is likely the highest number.
+
+Additionally, dtc performs various sanity checks on the tree.
+
+
+4) Device Tree Source file
+
+4.1) Overview
+
+Here is a very rough overview of the layout of a DTS source file:
+
+
+ sourcefile: list_of_memreserve devicetree
+
+ memreserve: label 'memreserve' ADDR ADDR ';'
+ | label 'memreserve' ADDR '-' ADDR ';'
+
+ devicetree: '/' nodedef
+
+ nodedef: '{' list_of_property list_of_subnode '}' ';'
+
+ property: label PROPNAME '=' propdata ';'
+
+ propdata: STRING
+ | '<' list_of_cells '>'
+ | '[' list_of_bytes ']'
+
+ subnode: label nodename nodedef
+
+That structure forms a hierarchical layout of nodes and properties
+rooted at an initial node as:
+
+ / {
+ }
+
+Both classic C style and C++ style comments are supported.
+
+Source files may be directly included using the syntax:
+
+ /include/ "filename"
+
+
+4.2) Properties
+
+Properties are named, possibly labeled, values. Each value
+is one of:
+
+ - A null-teminated C-like string,
+ - A numeric value fitting in 32 bits,
+ - A list of 32-bit values
+ - A byte sequence
+
+Here are some example property definitions:
+
+ - A property containing a 0 terminated string
+
+ property1 = "string_value";
+
+ - A property containing a numerical 32-bit hexadecimal value
+
+ property2 = <1234abcd>;
+
+ - A property containing 3 numerical 32-bit hexadecimal values
+
+ property3 = <12345678 12345678 deadbeef>;
+
+ - A property whose content is an arbitrary array of bytes
+
+ property4 = [0a 0b 0c 0d de ea ad be ef];
+
+
+Node may contain sub-nodes to obtain a hierarchical structure.
+For example:
+
+ - A child node named "childnode" whose unit name is
+ "childnode at address". It it turn has a string property
+ called "childprop".
+
+ childnode@addresss {
+ childprop = "hello\n";
+ };
+
+
+By default, all numeric values are hexadecimal. Alternate bases
+may be specified using a prefix "d#" for decimal, "b#" for binary,
+and "o#" for octal.
+
+Strings support common escape sequences from C: "\n", "\t", "\r",
+"\(octal value)", "\x(hex value)".
+
+
+4.3) Labels and References
+
+Labels may be applied to nodes or properties. Labels appear
+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:
+
+ mpic: interrupt-controller@40000 {
+ ...
+ };
+
+ ethernet-phy@3 {
+ interrupt-parent = <&mpic>;
+ ...
+ };
+
+And used in properties, lables may appear before or after any value:
+
+ randomnode {
+ prop: string = data: "mystring\n" data_end: ;
+ ...
+ };
+
+
+
+II - The DT block format
+========================
+
+This chapter defines the format of the flattened device-tree
+passed to the kernel. The actual content of the device tree
+are described in the kernel documentation in the file
+
+ linux-2.6/Documentation/powerpc/booting-without-of.txt
+
+You can find example of code manipulating that format within
+the kernel. For example, the file:
+
+ including arch/powerpc/kernel/prom_init.c
+
+will generate a flattened device-tree from the Open Firmware
+representation. Other utilities such as fs2dt, which is part of
+the kexec tools, will generate one from a filesystem representation.
+Some bootloaders such as U-Boot provide a bit more support by
+using the libfdt code.
+
+For booting the kernel, the device tree block has to be in main memory.
+It has to be accessible in both real mode and virtual mode with no
+mapping other than main memory. If you are writing a simple flash
+bootloader, it should copy the block to RAM before passing it to
+the kernel.
+
+
+1) Header
+---------
+
+The kernel is entered with r3 pointing to an area of memory that is
+roughly described in include/asm-powerpc/prom.h by the structure
+boot_param_header:
+
+ struct boot_param_header {
+ u32 magic; /* magic word OF_DT_HEADER */
+ u32 totalsize; /* total size of DT block */
+ u32 off_dt_struct; /* offset to structure */
+ u32 off_dt_strings; /* offset to strings */
+ u32 off_mem_rsvmap; /* offset to memory reserve map */
+ u32 version; /* format version */
+ u32 last_comp_version; /* last compatible version */
+
+ /* version 2 fields below */
+ u32 boot_cpuid_phys; /* Which physical CPU id we're
+ booting on */
+ /* version 3 fields below */
+ u32 size_dt_strings; /* size of the strings block */
+
+ /* version 17 fields below */
+ u32 size_dt_struct; /* size of the DT structure block */
+ };
+
+Along with the constants:
+
+ /* Definitions used by the flattened device tree */
+ #define OF_DT_HEADER 0xd00dfeed /* 4: version,
+ 4: total size */
+ #define OF_DT_BEGIN_NODE 0x1 /* Start node: full name
+ */
+ #define OF_DT_END_NODE 0x2 /* End node */
+ #define OF_DT_PROP 0x3 /* Property: name off,
+ size, content */
+ #define OF_DT_END 0x9
+
+All values in this header are in big endian format, the various
+fields in this header are defined more precisely below. All "offset"
+values are in bytes from the start of the header; that is from the
+value of r3.
+
+ - magic
+
+ This is a magic value that "marks" the beginning of the
+ device-tree block header. It contains the value 0xd00dfeed and is
+ defined by the constant OF_DT_HEADER
+
+ - totalsize
+
+ This is the total size of the DT block including the header. The
+ "DT" block should enclose all data structures defined in this
+ chapter (who are pointed to by offsets in this header). That is,
+ the device-tree structure, strings, and the memory reserve map.
+
+ - off_dt_struct
+
+ This is an offset from the beginning of the header to the start
+ of the "structure" part the device tree. (see 2) device tree)
+
+ - off_dt_strings
+
+ This is an offset from the beginning of the header to the start
+ of the "strings" part of the device-tree
+
+ - off_mem_rsvmap
+
+ This is an offset from the beginning of the header to the start
+ of the reserved memory map. This map is a list of pairs of 64-
+ bit integers. Each pair is a physical address and a size. The
+ list is terminated by an entry of size 0. This map provides the
+ kernel with a list of physical memory areas that are "reserved"
+ and thus not to be used for memory allocations, especially during
+ early initialization. The kernel needs to allocate memory during
+ boot for things like un-flattening the device-tree, allocating an
+ MMU hash table, etc... Those allocations must be done in such a
+ way to avoid overriding critical things like, on Open Firmware
+ capable machines, the RTAS instance, or on some pSeries, the TCE
+ tables used for the iommu. Typically, the reserve map should
+ contain _at least_ this DT block itself (header,total_size). If
+ you are passing an initrd to the kernel, you should reserve it as
+ well. You do not need to reserve the kernel image itself. The map
+ should be 64-bit aligned.
+
+ - version
+
+ This is the version of this structure. Version 1 stops
+ here. Version 2 adds an additional field boot_cpuid_phys.
+ Version 3 adds the size of the strings block, allowing the kernel
+ to reallocate it easily at boot and free up the unused flattened
+ structure after expansion. Version 16 introduces a new more
+ "compact" format for the tree itself that is however not backward
+ compatible. Version 17 adds an additional field, size_dt_struct,
+ allowing it to be reallocated or moved more easily (this is
+ particularly useful for bootloaders which need to make
+ adjustments to a device tree based on probed information). You
+ should always generate a structure of the highest version defined
+ at the time of your implementation. Currently that is version 17,
+ unless you explicitly aim at being backward compatible.
+
+ - last_comp_version
+
+ Last compatible version. This indicates down to what version of
+ the DT block you are backward compatible. For example, version 2
+ is backward compatible with version 1 (that is, a kernel build
+ for version 1 will be able to boot with a version 2 format). You
+ should put a 1 in this field if you generate a device tree of
+ version 1 to 3, or 16 if you generate a tree of version 16 or 17
+ using the new unit name format.
+
+ - boot_cpuid_phys
+
+ This field only exist on version 2 headers. It indicate which
+ physical CPU ID is calling the kernel entry point. This is used,
+ 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
+ device-tree contents)
+
+ - size_dt_strings
+
+ This field only exists on version 3 and later headers. It
+ gives the size of the "strings" section of the device tree (which
+ starts at the offset given by off_dt_strings).
+
+ - size_dt_struct
+
+ This field only exists on version 17 and later headers. It gives
+ the size of the "structure" section of the device tree (which
+ starts at the offset given by off_dt_struct).
+
+So the typical layout of a DT block (though the various parts don't
+need to be in that order) looks like this (addresses go from top to
+bottom):
+
+ ------------------------------
+ r3 -> | struct boot_param_header |
+ ------------------------------
+ | (alignment gap) (*) |
+ ------------------------------
+ | memory reserve map |
+ ------------------------------
+ | (alignment gap) |
+ ------------------------------
+ | |
+ | device-tree structure |
+ | |
+ ------------------------------
+ | (alignment gap) |
+ ------------------------------
+ | |
+ | device-tree strings |
+ | |
+ -----> ------------------------------
+ |
+ |
+ --- (r3 + totalsize)
+
+ (*) The alignment gaps are not necessarily present; their presence
+ and size are dependent on the various alignment requirements of
+ the individual data blocks.
+
+
+2) Device tree generalities
+---------------------------
+
+This device-tree itself is separated in two different blocks, a
+structure block and a strings block. Both need to be aligned to a 4
+byte boundary.
+
+First, let's quickly describe the device-tree concept before detailing
+the storage format. This chapter does _not_ describe the detail of the
+required types of nodes & properties for the kernel, this is done
+later in chapter III.
+
+The device-tree layout is strongly inherited from the definition of
+the Open Firmware IEEE 1275 device-tree. It's basically a tree of
+nodes, each node having two or more named properties. A property can
+have a value or not.
+
+It is a tree, so each node has one and only one parent except for the
+root node who has no parent.
+
+A node has 2 names. The actual node name is generally contained in a
+property of type "name" in the node property list whose value is a
+zero terminated string and is mandatory for version 1 to 3 of the
+format definition (as it is in Open Firmware). Version 16 makes it
+optional as it can generate it from the unit name defined below.
+
+There is also a "unit name" that is used to differentiate nodes with
+the same name at the same level, it is usually made of the node
+names, the "@" sign, and a "unit address", which definition is
+specific to the bus type the node sits on.
+
+The unit name doesn't exist as a property per-se but is included in
+the device-tree structure. It is typically used to represent "path" in
+the device-tree. More details about the actual format of these will be
+below.
+
+The kernel powerpc generic code does not make any formal use of the
+unit address (though some board support code may do) so the only real
+requirement here for the unit address is to ensure uniqueness of
+the node unit name at a given level of the tree. Nodes with no notion
+of address and no possible sibling of the same name (like /memory or
+/cpus) may omit the unit address in the context of this specification,
+or use the "@0" default unit address. The unit name is used to define
+a node "full path", which is the concatenation of all parent node
+unit names separated with "/".
+
+The root node doesn't have a defined name, and isn't required to have
+a name property either if you are using version 3 or earlier of the
+format. It also has no unit address (no @ symbol followed by a unit
+address). The root node unit name is thus an empty string. The full
+path to the root node is "/".
+
+Every node which actually represents an actual device (that is, a node
+which isn't only a virtual "container" for more nodes, like "/cpus"
+is) is also required to have a "device_type" property indicating the
+type of node .
+
+Finally, every node that can be referenced from a property in another
+node is required to have a "linux,phandle" property. Real open
+firmware implementations provide a unique "phandle" value for every
+node that the "prom_init()" trampoline code turns into
+"linux,phandle" properties. However, this is made optional if the
+flattened device tree is used directly. An example of a node
+referencing another node via "phandle" is when laying out the
+interrupt tree which will be described in a further version of this
+document.
+
+This "linux, phandle" property is a 32-bit value that uniquely
+identifies a node. You are free to use whatever values or system of
+values, internal pointers, or whatever to generate these, the only
+requirement is that every node for which you provide that property has
+a unique value for it.
+
+Here is an example of a simple device-tree. In this example, an "o"
+designates a node followed by the node unit name. Properties are
+presented with their name followed by their content. "content"
+represents an ASCII string (zero terminated) value, while <content>
+represents a 32-bit hexadecimal value. The various nodes in this
+example will be discussed in a later chapter. At this point, it is
+only meant to give you a idea of what a device-tree looks like. I have
+purposefully kept the "name" and "linux,phandle" properties which
+aren't necessary in order to give you a better idea of what the tree
+looks like in practice.
+
+ / o device-tree
+ |- name = "device-tree"
+ |- model = "MyBoardName"
+ |- compatible = "MyBoardFamilyName"
+ |- #address-cells = <2>
+ |- #size-cells = <2>
+ |- linux,phandle = <0>
+ |
+ o cpus
+ | | - name = "cpus"
+ | | - linux,phandle = <1>
+ | | - #address-cells = <1>
+ | | - #size-cells = <0>
+ | |
+ | o PowerPC,970@0
+ | |- name = "PowerPC,970"
+ | |- device_type = "cpu"
+ | |- reg = <0>
+ | |- clock-frequency = <5f5e1000>
+ | |- 64-bit
+ | |- linux,phandle = <2>
+ |
+ o memory@0
+ | |- name = "memory"
+ | |- device_type = "memory"
+ | |- reg = <00000000 00000000 00000000 20000000>
+ | |- linux,phandle = <3>
+ |
+ o chosen
+ |- name = "chosen"
+ |- bootargs = "root=/dev/sda2"
+ |- linux,phandle = <4>
+
+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
+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).
+
+The /cpus/PowerPC,970@0/64-bit property is an example of a
+property without a value. All other properties have a value. The
+significance of the #address-cells and #size-cells properties will be
+explained in chapter IV which defines precisely the required nodes and
+properties and their content.
+
+
+3) Device tree "structure" block
+
+The structure of the device tree is a linearized tree structure. The
+"OF_DT_BEGIN_NODE" token starts a new node, and the "OF_DT_END_NODE"
+ends that node definition. Child nodes are simply defined before
+"OF_DT_END_NODE" (that is nodes within the node). A 'token' is a 32
+bit value. The tree has to be "finished" with a OF_DT_END token
+
+Here's the basic structure of a single node:
+
+ * token OF_DT_BEGIN_NODE (that is 0x00000001)
+ * for version 1 to 3, this is the node full path as a zero
+ terminated string, starting with "/". For version 16 and later,
+ this is the node unit name only (or an empty string for the
+ root node)
+ * [align gap to next 4 bytes boundary]
+ * for each property:
+ * token OF_DT_PROP (that is 0x00000003)
+ * 32-bit value of property value size in bytes (or 0 if no
+ value)
+ * 32-bit value of offset in string block of property name
+ * property value data if any
+ * [align gap to next 4 bytes boundary]
+ * [child nodes if any]
+ * token OF_DT_END_NODE (that is 0x00000002)
+
+So the node content can be summarized as a start token, a full path,
+a list of properties, a list of child nodes, and an end token. Every
+child node is a full node structure itself as defined above.
+
+NOTE: The above definition requires that all property definitions for
+a particular node MUST precede any subnode definitions for that node.
+Although the structure would not be ambiguous if properties and
+subnodes were intermingled, the kernel parser requires that the
+properties come first (up until at least 2.6.22). Any tools
+manipulating a flattened tree must take care to preserve this
+constraint.
+
+4) Device tree "strings" block
+
+In order to save space, property names, which are generally redundant,
+are stored separately in the "strings" block. This block is simply the
+whole bunch of zero terminated strings for all property names
+concatenated together. The device-tree property definitions in the
+structure block will contain offset values from the beginning of the
+strings block.
+
+
+III - libfdt
+============
+
+This library should be merged into dtc proper.
+This library should likely be worked into U-Boot and the kernel.
+
+
+IV - Utility Tools
+==================
+
+1) convert-dtsv0 -- Conversion to Version 1
+
+convert-dtsv0 is a small utility program which converts (DTS)
+Device Tree Source from the obsolete version 0 to version 1.
+
+Version 1 DTS files are marked by line "/dts-v1/;" at the top of the file.
+
+The syntax of the convert-dtsv0 command line is:
+
+ convert-dtsv0 [<input_filename ... >]
+
+Each file passed will be converted to the new /dts-v1/ version by creating
+a new file with a "v1" appended the filename.
+
+Comments, empty lines, etc. are preserved.
+
+
+2) fdtdump -- Flat Device Tree dumping utility
+
+The fdtdump program prints a readable version of a flat device tree file.
+
+The syntax of the fdtdump command line is:
+
+ fdtdump <DTB-file-name>
diff --git a/src/dtc/GPL b/src/dtc/GPL
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/src/dtc/GPL
@@ -0,0 +1,340 @@
+ 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
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+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
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ 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
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+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
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+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
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ 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
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+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
+
+ 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
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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
+
+
+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 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.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+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
+Public License instead of this License.
diff --git a/src/dtc/Makefile b/src/dtc/Makefile
new file mode 100644
index 0000000..962f94e
--- /dev/null
+++ b/src/dtc/Makefile
@@ -0,0 +1,263 @@
+#
+# Device Tree Compiler
+#
+
+#
+# Version information will be constructed in this order:
+# EXTRAVERSION might be "-rc", for example.
+# LOCAL_VERSION is likely from command line.
+# CONFIG_LOCALVERSION from some future config system.
+#
+VERSION = 1
+PATCHLEVEL = 4
+SUBLEVEL = 0
+EXTRAVERSION =
+LOCAL_VERSION =
+CONFIG_LOCALVERSION =
+
+CPPFLAGS = -I libfdt -I .
+WARNINGS = -Werror -Wall -Wpointer-arith -Wcast-qual -Wnested-externs \
+ -Wstrict-prototypes -Wmissing-prototypes -Wredundant-decls
+CFLAGS = -g -Os -fPIC -Werror $(WARNINGS)
+
+BISON = bison
+LEX = flex
+
+INSTALL = /usr/bin/install
+DESTDIR =
+PREFIX = $(HOME)
+BINDIR = $(PREFIX)/bin
+LIBDIR = $(PREFIX)/lib
+INCLUDEDIR = $(PREFIX)/include
+
+HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
+ sed -e 's/\(cygwin\).*/cygwin/')
+
+ifeq ($(HOSTOS),darwin)
+SHAREDLIB_EXT=dylib
+SHAREDLIB_LINK_OPTIONS=-dynamiclib -Wl,-install_name -Wl,
+else
+SHAREDLIB_EXT=so
+SHAREDLIB_LINK_OPTIONS=-shared -Wl,--version-script=$(LIBFDT_version) -Wl,-soname,
+endif
+
+#
+# Overall rules
+#
+ifdef V
+VECHO = :
+else
+VECHO = echo " "
+ARFLAGS = rc
+.SILENT:
+endif
+
+NODEPTARGETS = clean
+ifeq ($(MAKECMDGOALS),)
+DEPTARGETS = all
+else
+DEPTARGETS = $(filter-out $(NODEPTARGETS),$(MAKECMDGOALS))
+endif
+
+#
+# Rules for versioning
+#
+
+DTC_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
+VERSION_FILE = version_gen.h
+
+CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
+ else if [ -x /bin/bash ]; then echo /bin/bash; \
+ else echo sh; fi ; fi)
+
+nullstring :=
+space := $(nullstring) # end of line
+
+localver_config = $(subst $(space),, $(string) \
+ $(patsubst "%",%,$(CONFIG_LOCALVERSION)))
+
+localver_cmd = $(subst $(space),, $(string) \
+ $(patsubst "%",%,$(LOCALVERSION)))
+
+localver_scm = $(shell $(CONFIG_SHELL) ./scripts/setlocalversion)
+localver_full = $(localver_config)$(localver_cmd)$(localver_scm)
+
+dtc_version = $(DTC_VERSION)$(localver_full)
+
+# Contents of the generated version file.
+define filechk_version
+ (echo "#define DTC_VERSION \"DTC $(dtc_version)\""; )
+endef
+
+define filechk
+ set -e; \
+ echo ' CHK $@'; \
+ mkdir -p $(dir $@); \
+ $(filechk_$(1)) < $< > $@.tmp; \
+ if [ -r $@ ] && cmp -s $@ $@.tmp; then \
+ rm -f $@.tmp; \
+ else \
+ echo ' UPD $@'; \
+ mv -f $@.tmp $@; \
+ fi;
+endef
+
+
+include Makefile.convert-dtsv0
+include Makefile.dtc
+include Makefile.utils
+
+BIN += convert-dtsv0
+BIN += dtc
+BIN += fdtdump
+BIN += fdtget
+BIN += fdtput
+
+SCRIPTS = dtdiff
+
+all: $(BIN) libfdt
+
+
+ifneq ($(DEPTARGETS),)
+-include $(DTC_OBJS:%.o=%.d)
+-include $(CONVERT_OBJS:%.o=%.d)
+-include $(FDTDUMP_OBJS:%.o=%.d)
+-include $(FDTGET_OBJS:%.o=%.d)
+-include $(FDTPUT_OBJS:%.o=%.d)
+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))
+
+include $(LIBFDT_srcdir)/Makefile.libfdt
+
+.PHONY: libfdt
+libfdt: $(LIBFDT_archive) $(LIBFDT_lib)
+
+$(LIBFDT_archive): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS))
+$(LIBFDT_lib): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS))
+
+libfdt_clean:
+ @$(VECHO) CLEAN "(libfdt)"
+ rm -f $(addprefix $(LIBFDT_objdir)/,$(STD_CLEANFILES))
+ rm -f $(LIBFDT_objdir)/*.so
+
+ifneq ($(DEPTARGETS),)
+-include $(LIBFDT_OBJS:%.o=$(LIBFDT_objdir)/%.d)
+endif
+
+# This stops make from generating the lex and bison output during
+# auto-dependency computation, but throwing them away as an
+# intermediate target and building them again "for real"
+.SECONDARY: $(DTC_GEN_SRCS) $(CONVERT_GEN_SRCS)
+
+install: all $(SCRIPTS)
+ @$(VECHO) INSTALL
+ $(INSTALL) -d $(DESTDIR)$(BINDIR)
+ $(INSTALL) $(BIN) $(SCRIPTS) $(DESTDIR)$(BINDIR)
+ $(INSTALL) -d $(DESTDIR)$(LIBDIR)
+ $(INSTALL) $(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) -d $(DESTDIR)$(INCLUDEDIR)
+ $(INSTALL) -m 644 $(LIBFDT_include) $(DESTDIR)$(INCLUDEDIR)
+
+$(VERSION_FILE): Makefile FORCE
+ $(call filechk,version)
+
+
+dtc: $(DTC_OBJS)
+
+convert-dtsv0: $(CONVERT_OBJS)
+ @$(VECHO) LD $@
+ $(LINK.c) -o $@ $^
+
+fdtdump: $(FDTDUMP_OBJS)
+
+fdtget: $(FDTGET_OBJS) $(LIBFDT_archive)
+
+fdtput: $(FDTPUT_OBJS) $(LIBFDT_archive)
+
+
+#
+# Testsuite rules
+#
+TESTS_PREFIX=tests/
+
+TESTS_BIN += dtc
+TESTS_BIN += convert-dtsv0
+TESTS_BIN += fdtput
+TESTS_BIN += fdtget
+
+include tests/Makefile.tests
+
+#
+# Clean rules
+#
+STD_CLEANFILES = *~ *.o *.$(SHAREDLIB_EXT) *.d *.a *.i *.s core a.out vgcore.* \
+ *.tab.[ch] *.lex.c *.output
+
+clean: libfdt_clean tests_clean
+ @$(VECHO) CLEAN
+ rm -f $(STD_CLEANFILES)
+ rm -f $(VERSION_FILE)
+ rm -f $(BIN)
+
+#
+# Generic compile rules
+#
+%: %.o
+ @$(VECHO) LD $@
+ $(LINK.c) -o $@ $^
+
+%.o: %.c
+ @$(VECHO) CC $@
+ $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $<
+
+%.o: %.S
+ @$(VECHO) AS $@
+ $(CC) $(CPPFLAGS) $(AFLAGS) -D__ASSEMBLY__ -o $@ -c $<
+
+%.d: %.c
+ @$(VECHO) DEP $<
+ $(CC) $(CPPFLAGS) -MM -MG -MT "$*.o $@" $< > $@
+
+%.d: %.S
+ @$(VECHO) DEP $<
+ $(CC) $(CPPFLAGS) -MM -MG -MT "$*.o $@" $< > $@
+
+%.i: %.c
+ @$(VECHO) CPP $@
+ $(CC) $(CPPFLAGS) -E $< > $@
+
+%.s: %.c
+ @$(VECHO) CC -S $@
+ $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -S $<
+
+%.a:
+ @$(VECHO) AR $@
+ $(AR) $(ARFLAGS) $@ $^
+
+$(LIBFDT_lib):
+ @$(VECHO) LD $@
+ $(CC) $(LDFLAGS) -fPIC $(SHAREDLIB_LINK_OPTIONS)$(LIBFDT_soname) -o $(LIBFDT_lib) $^
+
+%.lex.c: %.l
+ @$(VECHO) LEX $@
+ $(LEX) -o$@ $<
+
+%.tab.c %.tab.h %.output: %.y
+ @$(VECHO) BISON $@
+ $(BISON) -d $<
+
+FORCE:
diff --git a/src/dtc/Makefile.convert-dtsv0 b/src/dtc/Makefile.convert-dtsv0
new file mode 100644
index 0000000..08ea40a
--- /dev/null
+++ b/src/dtc/Makefile.convert-dtsv0
@@ -0,0 +1,13 @@
+#
+# This is not a complete Makefile of itself.
+# Instead, it is designed to be easily embeddable
+# into other systems of Makefiles.
+#
+
+CONVERT_SRCS = \
+ srcpos.c \
+ util.c
+
+CONVERT_GEN_SRCS = convert-dtsv0-lexer.lex.c
+
+CONVERT_OBJS = $(CONVERT_SRCS:%.c=%.o) $(CONVERT_GEN_SRCS:%.c=%.o)
diff --git a/src/dtc/Makefile.dtc b/src/dtc/Makefile.dtc
new file mode 100644
index 0000000..bece49b
--- /dev/null
+++ b/src/dtc/Makefile.dtc
@@ -0,0 +1,18 @@
+# Makefile.dtc
+#
+# This is not a complete Makefile of itself. Instead, it is designed to
+# be easily embeddable into other systems of Makefiles.
+#
+DTC_SRCS = \
+ checks.c \
+ data.c \
+ dtc.c \
+ flattree.c \
+ fstree.c \
+ livetree.c \
+ srcpos.c \
+ treesource.c \
+ util.c
+
+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/src/dtc/Makefile.utils b/src/dtc/Makefile.utils
new file mode 100644
index 0000000..48ece49
--- /dev/null
+++ b/src/dtc/Makefile.utils
@@ -0,0 +1,24 @@
+#
+# This is not a complete Makefile of itself. Instead, it is designed to
+# be easily embeddable into other systems of Makefiles.
+#
+
+FDTDUMP_SRCS = \
+ fdtdump.c \
+ util.c
+
+FDTDUMP_OBJS = $(FDTDUMP_SRCS:%.c=%.o)
+
+
+FDTGET_SRCS = \
+ fdtget.c \
+ util.c
+
+FDTGET_OBJS = $(FDTGET_SRCS:%.c=%.o)
+
+
+FDTPUT_SRCS = \
+ fdtput.c \
+ util.c
+
+FDTPUT_OBJS = $(FDTPUT_SRCS:%.c=%.o)
diff --git a/src/dtc/README.license b/src/dtc/README.license
new file mode 100644
index 0000000..d56c88f
--- /dev/null
+++ b/src/dtc/README.license
@@ -0,0 +1,56 @@
+Licensing and contribution policy of dtc and libfdt
+===================================================
+
+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
+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
+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
+compatible license.
+
+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.
+
+I made the decision to license libfdt in this way because I want to
+encourage widespread and correct usage of flattened device trees,
+including by proprietary or otherwise GPL-incompatible firmware or
+tools. Allowing libfdt to be used under the terms of the BSD license
+makes that it easier for vendors or authors of such software to do so.
+
+This does mean that libfdt code could be "stolen" - say, included in a
+proprietary fimware and extended without contributing those extensions
+back to the libfdt mainline. While I hope that doesn't happen, I
+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.
+
+Licenses such as the LGPL which would allow code to be used in non-GPL
+software, but also require contributions to be returned were
+considered. However, libfdt is designed to be used in firmwares and
+other environments with unusual technical constraints. It's difficult
+to anticipate all possible changes which might be needed to meld
+libfdt into such environments and so difficult to suitably word a
+license that puts the boundary between what is and isn't permitted in
+the intended place. Again, I judged encouraging widespread use of
+libfdt by keeping the license terms simple and familiar to be the more
+important goal.
+
+**IMPORTANT** It's intended that all of libfdt as released remain
+permissively licensed this way. Therefore only contributions which
+are released under these terms can be merged into the libfdt mainline.
+
+
+David Gibson <david@gibson.dropbear.id.au>
+(principal original author of dtc and libfdt)
+2 November 2007
diff --git a/src/dtc/TODO b/src/dtc/TODO
new file mode 100644
index 0000000..a3e7182
--- /dev/null
+++ b/src/dtc/TODO
@@ -0,0 +1,8 @@
+- Bugfixes:
+ * Proper handling of boot cpu information
+- Generate mem reserve map
+ * linux,reserve-map property
+ * generating reserve entry for device tree itself
+ * generating reserve entries from tce, rtas etc. properties
+- Expression support
+- Macro system
diff --git a/src/dtc/checks.c b/src/dtc/checks.c
new file mode 100644
index 0000000..ee96a25
--- /dev/null
+++ b/src/dtc/checks.c
@@ -0,0 +1,759 @@
+/*
+ * (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"
+
+#ifdef TRACE_CHECKS
+#define TRACE(c, ...) \
+ do { \
+ fprintf(stderr, "=== %s: ", (c)->name); \
+ fprintf(stderr, __VA_ARGS__); \
+ fprintf(stderr, "\n"); \
+ } while (0)
+#else
+#define TRACE(c, fmt, ...) do { } while (0)
+#endif
+
+enum checkstatus {
+ UNCHECKED = 0,
+ PREREQ,
+ PASSED,
+ FAILED,
+};
+
+struct check;
+
+typedef void (*tree_check_fn)(struct check *c, struct node *dt);
+typedef void (*node_check_fn)(struct check *c, struct node *dt, struct node *node);
+typedef void (*prop_check_fn)(struct check *c, struct node *dt,
+ struct node *node, struct property *prop);
+
+struct check {
+ const char *name;
+ tree_check_fn tree_fn;
+ node_check_fn node_fn;
+ prop_check_fn prop_fn;
+ void *data;
+ bool warn, error;
+ enum checkstatus status;
+ int inprogress;
+ int num_prereqs;
+ struct check **prereq;
+};
+
+#define CHECK_ENTRY(nm, tfn, nfn, pfn, d, w, e, ...) \
+ static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \
+ static struct check nm = { \
+ .name = #nm, \
+ .tree_fn = (tfn), \
+ .node_fn = (nfn), \
+ .prop_fn = (pfn), \
+ .data = (d), \
+ .warn = (w), \
+ .error = (e), \
+ .status = UNCHECKED, \
+ .num_prereqs = ARRAY_SIZE(nm##_prereqs), \
+ .prereq = nm##_prereqs, \
+ };
+#define WARNING(nm, tfn, nfn, pfn, d, ...) \
+ CHECK_ENTRY(nm, tfn, nfn, pfn, d, true, false, __VA_ARGS__)
+#define ERROR(nm, tfn, nfn, pfn, d, ...) \
+ CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, true, __VA_ARGS__)
+#define CHECK(nm, tfn, nfn, pfn, d, ...) \
+ CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, false, __VA_ARGS__)
+
+#define TREE_WARNING(nm, d, ...) \
+ WARNING(nm, check_##nm, NULL, NULL, d, __VA_ARGS__)
+#define TREE_ERROR(nm, d, ...) \
+ ERROR(nm, check_##nm, NULL, NULL, d, __VA_ARGS__)
+#define TREE_CHECK(nm, d, ...) \
+ CHECK(nm, check_##nm, NULL, NULL, d, __VA_ARGS__)
+#define NODE_WARNING(nm, d, ...) \
+ WARNING(nm, NULL, check_##nm, NULL, d, __VA_ARGS__)
+#define NODE_ERROR(nm, d, ...) \
+ ERROR(nm, NULL, check_##nm, NULL, d, __VA_ARGS__)
+#define NODE_CHECK(nm, d, ...) \
+ CHECK(nm, NULL, check_##nm, NULL, d, __VA_ARGS__)
+#define PROP_WARNING(nm, d, ...) \
+ WARNING(nm, NULL, NULL, check_##nm, d, __VA_ARGS__)
+#define PROP_ERROR(nm, d, ...) \
+ ERROR(nm, NULL, NULL, check_##nm, d, __VA_ARGS__)
+#define PROP_CHECK(nm, d, ...) \
+ CHECK(nm, NULL, NULL, check_##nm, d, __VA_ARGS__)
+
+#ifdef __GNUC__
+static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
+#endif
+static inline void check_msg(struct check *c, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+
+ if ((c->warn && (quiet < 1))
+ || (c->error && (quiet < 2))) {
+ fprintf(stderr, "%s (%s): ",
+ (c->error) ? "ERROR" : "Warning", c->name);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ }
+}
+
+#define FAIL(c, ...) \
+ do { \
+ TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__); \
+ (c)->status = FAILED; \
+ check_msg((c), __VA_ARGS__); \
+ } while (0)
+
+static void check_nodes_props(struct check *c, struct node *dt, struct node *node)
+{
+ struct node *child;
+ struct property *prop;
+
+ TRACE(c, "%s", node->fullpath);
+ if (c->node_fn)
+ c->node_fn(c, dt, node);
+
+ if (c->prop_fn)
+ for_each_property(node, prop) {
+ TRACE(c, "%s\t'%s'", node->fullpath, prop->name);
+ c->prop_fn(c, dt, node, prop);
+ }
+
+ for_each_child(node, child)
+ check_nodes_props(c, dt, child);
+}
+
+static int run_check(struct check *c, struct node *dt)
+{
+ int error = 0;
+ int i;
+
+ assert(!c->inprogress);
+
+ if (c->status != UNCHECKED)
+ goto out;
+
+ c->inprogress = 1;
+
+ for (i = 0; i < c->num_prereqs; i++) {
+ struct check *prq = c->prereq[i];
+ error |= run_check(prq, dt);
+ if (prq->status != PASSED) {
+ c->status = PREREQ;
+ check_msg(c, "Failed prerequisite '%s'",
+ c->prereq[i]->name);
+ }
+ }
+
+ if (c->status != UNCHECKED)
+ goto out;
+
+ if (c->node_fn || c->prop_fn)
+ check_nodes_props(c, dt, dt);
+
+ if (c->tree_fn)
+ c->tree_fn(c, dt);
+ if (c->status == UNCHECKED)
+ c->status = PASSED;
+
+ TRACE(c, "\tCompleted, status %d", c->status);
+
+out:
+ c->inprogress = 0;
+ if ((c->status != PASSED) && (c->error))
+ error = 1;
+ return error;
+}
+
+/*
+ * Utility check functions
+ */
+
+/* A check which always fails, for testing purposes only */
+static inline void check_always_fail(struct check *c, struct node *dt)
+{
+ FAIL(c, "always_fail check");
+}
+TREE_CHECK(always_fail, NULL);
+
+static void check_is_string(struct check *c, struct node *root,
+ struct node *node)
+{
+ struct property *prop;
+ char *propname = c->data;
+
+ prop = get_property(node, propname);
+ if (!prop)
+ return; /* Not present, assumed ok */
+
+ if (!data_is_one_string(prop->val))
+ FAIL(c, "\"%s\" property in %s is not a string",
+ propname, node->fullpath);
+}
+#define WARNING_IF_NOT_STRING(nm, propname) \
+ WARNING(nm, NULL, check_is_string, NULL, (propname))
+#define ERROR_IF_NOT_STRING(nm, propname) \
+ ERROR(nm, NULL, check_is_string, NULL, (propname))
+
+static void check_is_cell(struct check *c, struct node *root,
+ struct node *node)
+{
+ struct property *prop;
+ char *propname = c->data;
+
+ prop = get_property(node, propname);
+ if (!prop)
+ return; /* Not present, assumed ok */
+
+ if (prop->val.len != sizeof(cell_t))
+ FAIL(c, "\"%s\" property in %s is not a single cell",
+ propname, node->fullpath);
+}
+#define WARNING_IF_NOT_CELL(nm, propname) \
+ WARNING(nm, NULL, check_is_cell, NULL, (propname))
+#define ERROR_IF_NOT_CELL(nm, propname) \
+ ERROR(nm, NULL, check_is_cell, NULL, (propname))
+
+/*
+ * Structural check functions
+ */
+
+static void check_duplicate_node_names(struct check *c, struct node *dt,
+ struct node *node)
+{
+ struct node *child, *child2;
+
+ for_each_child(node, child)
+ for (child2 = child->next_sibling;
+ child2;
+ child2 = child2->next_sibling)
+ if (streq(child->name, child2->name))
+ FAIL(c, "Duplicate node name %s",
+ child->fullpath);
+}
+NODE_ERROR(duplicate_node_names, NULL);
+
+static void check_duplicate_property_names(struct check *c, struct node *dt,
+ struct node *node)
+{
+ struct property *prop, *prop2;
+
+ for_each_property(node, prop) {
+ for (prop2 = prop->next; prop2; prop2 = prop2->next) {
+ if (prop2->deleted)
+ continue;
+ if (streq(prop->name, prop2->name))
+ FAIL(c, "Duplicate property name %s in %s",
+ prop->name, node->fullpath);
+ }
+ }
+}
+NODE_ERROR(duplicate_property_names, NULL);
+
+#define LOWERCASE "abcdefghijklmnopqrstuvwxyz"
+#define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define DIGITS "0123456789"
+#define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-"
+
+static void check_node_name_chars(struct check *c, struct node *dt,
+ struct node *node)
+{
+ int n = strspn(node->name, c->data);
+
+ if (n < strlen(node->name))
+ FAIL(c, "Bad character '%c' in node %s",
+ node->name[n], node->fullpath);
+}
+NODE_ERROR(node_name_chars, PROPNODECHARS "@");
+
+static void check_node_name_format(struct check *c, struct node *dt,
+ struct node *node)
+{
+ if (strchr(get_unitname(node), '@'))
+ FAIL(c, "Node %s has multiple '@' characters in name",
+ node->fullpath);
+}
+NODE_ERROR(node_name_format, NULL, &node_name_chars);
+
+static void check_property_name_chars(struct check *c, struct node *dt,
+ struct node *node, struct property *prop)
+{
+ int n = strspn(prop->name, c->data);
+
+ if (n < strlen(prop->name))
+ FAIL(c, "Bad character '%c' in property name \"%s\", node %s",
+ prop->name[n], prop->name, node->fullpath);
+}
+PROP_ERROR(property_name_chars, PROPNODECHARS);
+
+#define DESCLABEL_FMT "%s%s%s%s%s"
+#define DESCLABEL_ARGS(node,prop,mark) \
+ ((mark) ? "value of " : ""), \
+ ((prop) ? "'" : ""), \
+ ((prop) ? (prop)->name : ""), \
+ ((prop) ? "' in " : ""), (node)->fullpath
+
+static void check_duplicate_label(struct check *c, struct node *dt,
+ const char *label, struct node *node,
+ struct property *prop, struct marker *mark)
+{
+ struct node *othernode = NULL;
+ struct property *otherprop = NULL;
+ struct marker *othermark = NULL;
+
+ othernode = get_node_by_label(dt, label);
+
+ if (!othernode)
+ otherprop = get_property_by_label(dt, label, &othernode);
+ if (!othernode)
+ othermark = get_marker_label(dt, label, &othernode,
+ &otherprop);
+
+ if (!othernode)
+ return;
+
+ if ((othernode != node) || (otherprop != prop) || (othermark != mark))
+ FAIL(c, "Duplicate label '%s' on " DESCLABEL_FMT
+ " and " DESCLABEL_FMT,
+ label, DESCLABEL_ARGS(node, prop, mark),
+ DESCLABEL_ARGS(othernode, otherprop, othermark));
+}
+
+static void check_duplicate_label_node(struct check *c, struct node *dt,
+ struct node *node)
+{
+ struct label *l;
+
+ for_each_label(node->labels, l)
+ check_duplicate_label(c, dt, l->label, node, NULL, NULL);
+}
+static void check_duplicate_label_prop(struct check *c, struct node *dt,
+ struct node *node, struct property *prop)
+{
+ struct marker *m = prop->val.markers;
+ struct label *l;
+
+ for_each_label(prop->labels, l)
+ check_duplicate_label(c, dt, l->label, node, prop, NULL);
+
+ for_each_marker_of_type(m, LABEL)
+ check_duplicate_label(c, dt, m->ref, node, prop, m);
+}
+ERROR(duplicate_label, NULL, check_duplicate_label_node,
+ check_duplicate_label_prop, NULL);
+
+static void check_explicit_phandles(struct check *c, struct node *root,
+ struct node *node, struct property *prop)
+{
+ struct marker *m;
+ struct node *other;
+ cell_t phandle;
+
+ if (!streq(prop->name, "phandle")
+ && !streq(prop->name, "linux,phandle"))
+ return;
+
+ if (prop->val.len != sizeof(cell_t)) {
+ FAIL(c, "%s has bad length (%d) %s property",
+ node->fullpath, prop->val.len, prop->name);
+ return;
+ }
+
+ m = prop->val.markers;
+ for_each_marker_of_type(m, REF_PHANDLE) {
+ assert(m->offset == 0);
+ if (node != get_node_by_ref(root, m->ref))
+ /* "Set this node's phandle equal to some
+ * other node's phandle". That's nonsensical
+ * by construction. */ {
+ FAIL(c, "%s in %s is a reference to another node",
+ prop->name, node->fullpath);
+ return;
+ }
+ /* But setting this node's phandle equal to its own
+ * phandle is allowed - that means allocate a unique
+ * phandle for this node, even if it's not otherwise
+ * referenced. The value will be filled in later, so
+ * no further checking for now. */
+ return;
+ }
+
+ phandle = propval_cell(prop);
+
+ if ((phandle == 0) || (phandle == -1)) {
+ FAIL(c, "%s has bad value (0x%x) in %s property",
+ node->fullpath, phandle, prop->name);
+ return;
+ }
+
+ if (node->phandle && (node->phandle != phandle))
+ FAIL(c, "%s has %s property which replaces existing phandle information",
+ node->fullpath, prop->name);
+
+ other = get_node_by_phandle(root, phandle);
+ if (other && (other != node)) {
+ FAIL(c, "%s has duplicated phandle 0x%x (seen before at %s)",
+ node->fullpath, phandle, other->fullpath);
+ return;
+ }
+
+ node->phandle = phandle;
+}
+PROP_ERROR(explicit_phandles, NULL);
+
+static void check_name_properties(struct check *c, struct node *root,
+ struct node *node)
+{
+ struct property **pp, *prop = NULL;
+
+ for (pp = &node->proplist; *pp; pp = &((*pp)->next))
+ if (streq((*pp)->name, "name")) {
+ prop = *pp;
+ break;
+ }
+
+ if (!prop)
+ return; /* No name property, that's fine */
+
+ if ((prop->val.len != node->basenamelen+1)
+ || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) {
+ FAIL(c, "\"name\" property in %s is incorrect (\"%s\" instead"
+ " of base node name)", node->fullpath, prop->val.val);
+ } else {
+ /* The name property is correct, and therefore redundant.
+ * Delete it */
+ *pp = prop->next;
+ free(prop->name);
+ data_free(prop->val);
+ free(prop);
+ }
+}
+ERROR_IF_NOT_STRING(name_is_string, "name");
+NODE_ERROR(name_properties, NULL, &name_is_string);
+
+/*
+ * Reference fixup functions
+ */
+
+static void fixup_phandle_references(struct check *c, struct node *dt,
+ struct node *node, struct property *prop)
+{
+ struct marker *m = prop->val.markers;
+ struct node *refnode;
+ cell_t phandle;
+
+ for_each_marker_of_type(m, REF_PHANDLE) {
+ assert(m->offset + sizeof(cell_t) <= prop->val.len);
+
+ refnode = get_node_by_ref(dt, m->ref);
+ if (! refnode) {
+ FAIL(c, "Reference to non-existent node or label \"%s\"\n",
+ m->ref);
+ continue;
+ }
+
+ phandle = get_node_phandle(dt, refnode);
+ *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
+ }
+}
+ERROR(phandle_references, NULL, NULL, fixup_phandle_references, NULL,
+ &duplicate_node_names, &explicit_phandles);
+
+static void fixup_path_references(struct check *c, struct node *dt,
+ struct node *node, struct property *prop)
+{
+ struct marker *m = prop->val.markers;
+ struct node *refnode;
+ char *path;
+
+ for_each_marker_of_type(m, REF_PATH) {
+ assert(m->offset <= prop->val.len);
+
+ refnode = get_node_by_ref(dt, m->ref);
+ if (!refnode) {
+ FAIL(c, "Reference to non-existent node or label \"%s\"\n",
+ m->ref);
+ continue;
+ }
+
+ path = refnode->fullpath;
+ prop->val = data_insert_at_marker(prop->val, m, path,
+ strlen(path) + 1);
+ }
+}
+ERROR(path_references, NULL, NULL, fixup_path_references, NULL,
+ &duplicate_node_names);
+
+/*
+ * Semantic checks
+ */
+WARNING_IF_NOT_CELL(address_cells_is_cell, "#address-cells");
+WARNING_IF_NOT_CELL(size_cells_is_cell, "#size-cells");
+WARNING_IF_NOT_CELL(interrupt_cells_is_cell, "#interrupt-cells");
+
+WARNING_IF_NOT_STRING(device_type_is_string, "device_type");
+WARNING_IF_NOT_STRING(model_is_string, "model");
+WARNING_IF_NOT_STRING(status_is_string, "status");
+
+static void fixup_addr_size_cells(struct check *c, struct node *dt,
+ struct node *node)
+{
+ struct property *prop;
+
+ node->addr_cells = -1;
+ node->size_cells = -1;
+
+ prop = get_property(node, "#address-cells");
+ if (prop)
+ node->addr_cells = propval_cell(prop);
+
+ prop = get_property(node, "#size-cells");
+ if (prop)
+ node->size_cells = propval_cell(prop);
+}
+WARNING(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL,
+ &address_cells_is_cell, &size_cells_is_cell);
+
+#define node_addr_cells(n) \
+ (((n)->addr_cells == -1) ? 2 : (n)->addr_cells)
+#define node_size_cells(n) \
+ (((n)->size_cells == -1) ? 1 : (n)->size_cells)
+
+static void check_reg_format(struct check *c, struct node *dt,
+ struct node *node)
+{
+ struct property *prop;
+ int addr_cells, size_cells, entrylen;
+
+ prop = get_property(node, "reg");
+ if (!prop)
+ return; /* No "reg", that's fine */
+
+ if (!node->parent) {
+ FAIL(c, "Root node has a \"reg\" property");
+ return;
+ }
+
+ if (prop->val.len == 0)
+ FAIL(c, "\"reg\" property in %s is empty", node->fullpath);
+
+ addr_cells = node_addr_cells(node->parent);
+ size_cells = node_size_cells(node->parent);
+ entrylen = (addr_cells + size_cells) * sizeof(cell_t);
+
+ if ((prop->val.len % entrylen) != 0)
+ FAIL(c, "\"reg\" property in %s has invalid length (%d bytes) "
+ "(#address-cells == %d, #size-cells == %d)",
+ node->fullpath, prop->val.len, addr_cells, size_cells);
+}
+NODE_WARNING(reg_format, NULL, &addr_size_cells);
+
+static void check_ranges_format(struct check *c, struct node *dt,
+ struct node *node)
+{
+ struct property *prop;
+ int c_addr_cells, p_addr_cells, c_size_cells, p_size_cells, entrylen;
+
+ prop = get_property(node, "ranges");
+ if (!prop)
+ return;
+
+ if (!node->parent) {
+ FAIL(c, "Root node has a \"ranges\" property");
+ return;
+ }
+
+ p_addr_cells = node_addr_cells(node->parent);
+ p_size_cells = node_size_cells(node->parent);
+ c_addr_cells = node_addr_cells(node);
+ c_size_cells = node_size_cells(node);
+ entrylen = (p_addr_cells + c_addr_cells + c_size_cells) * sizeof(cell_t);
+
+ if (prop->val.len == 0) {
+ if (p_addr_cells != c_addr_cells)
+ FAIL(c, "%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);
+ if (p_size_cells != c_size_cells)
+ FAIL(c, "%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);
+ } else if ((prop->val.len % entrylen) != 0) {
+ FAIL(c, "\"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);
+ }
+}
+NODE_WARNING(ranges_format, NULL, &addr_size_cells);
+
+/*
+ * Style checks
+ */
+static void check_avoid_default_addr_size(struct check *c, struct node *dt,
+ struct node *node)
+{
+ struct property *reg, *ranges;
+
+ if (!node->parent)
+ return; /* Ignore root node */
+
+ reg = get_property(node, "reg");
+ ranges = get_property(node, "ranges");
+
+ if (!reg && !ranges)
+ return;
+
+ if ((node->parent->addr_cells == -1))
+ FAIL(c, "Relying on default #address-cells value for %s",
+ node->fullpath);
+
+ if ((node->parent->size_cells == -1))
+ FAIL(c, "Relying on default #size-cells value for %s",
+ node->fullpath);
+}
+NODE_WARNING(avoid_default_addr_size, NULL, &addr_size_cells);
+
+static void check_obsolete_chosen_interrupt_controller(struct check *c,
+ struct node *dt)
+{
+ struct node *chosen;
+ struct property *prop;
+
+ chosen = get_node_by_path(dt, "/chosen");
+ if (!chosen)
+ return;
+
+ prop = get_property(chosen, "interrupt-controller");
+ if (prop)
+ FAIL(c, "/chosen has obsolete \"interrupt-controller\" "
+ "property");
+}
+TREE_WARNING(obsolete_chosen_interrupt_controller, NULL);
+
+static struct check *check_table[] = {
+ &duplicate_node_names, &duplicate_property_names,
+ &node_name_chars, &node_name_format, &property_name_chars,
+ &name_is_string, &name_properties,
+
+ &duplicate_label,
+
+ &explicit_phandles,
+ &phandle_references, &path_references,
+
+ &address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell,
+ &device_type_is_string, &model_is_string, &status_is_string,
+
+ &addr_size_cells, &reg_format, &ranges_format,
+
+ &avoid_default_addr_size,
+ &obsolete_chosen_interrupt_controller,
+
+ &always_fail,
+};
+
+static void enable_warning_error(struct check *c, bool warn, bool error)
+{
+ int i;
+
+ /* Raising level, also raise it for prereqs */
+ if ((warn && !c->warn) || (error && !c->error))
+ for (i = 0; i < c->num_prereqs; i++)
+ enable_warning_error(c->prereq[i], warn, error);
+
+ c->warn = c->warn || warn;
+ c->error = c->error || error;
+}
+
+static void disable_warning_error(struct check *c, bool warn, bool error)
+{
+ int i;
+
+ /* Lowering level, also lower it for things this is the prereq
+ * for */
+ if ((warn && c->warn) || (error && c->error)) {
+ for (i = 0; i < ARRAY_SIZE(check_table); i++) {
+ struct check *cc = check_table[i];
+ int j;
+
+ for (j = 0; j < cc->num_prereqs; j++)
+ if (cc->prereq[j] == c)
+ disable_warning_error(cc, warn, error);
+ }
+ }
+
+ c->warn = c->warn && !warn;
+ c->error = c->error && !error;
+}
+
+void parse_checks_option(bool warn, bool error, const char *optarg)
+{
+ int i;
+ const char *name = optarg;
+ bool enable = true;
+
+ if ((strncmp(optarg, "no-", 3) == 0)
+ || (strncmp(optarg, "no_", 3) == 0)) {
+ name = optarg + 3;
+ enable = false;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(check_table); i++) {
+ struct check *c = check_table[i];
+
+ if (streq(c->name, name)) {
+ if (enable)
+ enable_warning_error(c, warn, error);
+ else
+ disable_warning_error(c, warn, error);
+ return;
+ }
+ }
+
+ die("Unrecognized check name \"%s\"\n", name);
+}
+
+void process_checks(int force, struct boot_info *bi)
+{
+ struct node *dt = bi->dt;
+ int i;
+ int error = 0;
+
+ for (i = 0; i < ARRAY_SIZE(check_table); i++) {
+ struct check *c = check_table[i];
+
+ if (c->warn || c->error)
+ error = error || run_check(c, dt);
+ }
+
+ if (error) {
+ if (!force) {
+ fprintf(stderr, "ERROR: Input tree has errors, aborting "
+ "(use -f to force output)\n");
+ exit(2);
+ } else if (quiet < 3) {
+ fprintf(stderr, "Warning: Input tree has errors, "
+ "output forced\n");
+ }
+ }
+}
diff --git a/src/dtc/convert-dtsv0-lexer.l b/src/dtc/convert-dtsv0-lexer.l
new file mode 100644
index 0000000..548e719
--- /dev/null
+++ b/src/dtc/convert-dtsv0-lexer.l
@@ -0,0 +1,248 @@
+/*
+ * (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
+
+%x INCLUDE
+%x BYTESTRING
+%x PROPNODENAME
+
+PROPNODECHAR [a-zA-Z0-9,._+*#?@-]
+PATHCHAR ({PROPNODECHAR}|[/])
+LABEL [a-zA-Z_][a-zA-Z0-9_]*
+STRING \"([^\\"]|\\.)*\"
+WS [[:space:]]
+COMMENT "/*"([^*]|\*+[^*/])*\*+"/"
+LINECOMMENT "//".*\n
+GAP ({WS}|{COMMENT}|{LINECOMMENT})*
+
+%{
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <errno.h>
+#include <assert.h>
+#include <fnmatch.h>
+
+#include "srcpos.h"
+#include "util.h"
+
+static int v1_tagged; /* = 0 */
+static int cbase = 16;
+static int saw_hyphen; /* = 0 */
+static unsigned long long last_val;
+static char *last_name; /* = NULL */
+
+const struct {
+ const char *pattern;
+ int obase, width;
+} guess_table[] = {
+ { "*-frequency", 10, 0 },
+ { "num-*", 10, 0 },
+ { "#*-cells", 10, 0 },
+ { "*cache-line-size", 10, 0 },
+ { "*cache-block-size", 10, 0 },
+ { "*cache-size", 10, 0 },
+ { "*cache-sets", 10, 0 },
+ { "cell-index", 10, 0 },
+ { "bank-width", 10, 0 },
+ { "*-fifo-size", 10, 0 },
+ { "*-frame-size", 10, 0 },
+ { "*-channel", 10, 0 },
+ { "current-speed", 10, 0 },
+ { "phy-map", 16, 8 },
+ { "dcr-reg", 16, 3 },
+ { "reg", 16, 8 },
+ { "ranges", 16, 8},
+};
+%}
+
+%%
+<*>"/include/"{GAP}{STRING} ECHO;
+
+<*>\"([^\\"]|\\.)*\" ECHO;
+
+<*>"/dts-v1/" {
+ die("Input dts file is already version 1\n");
+ }
+
+<*>"/memreserve/" {
+ if (!v1_tagged) {
+ fprintf(yyout, "/dts-v1/;\n\n");
+ v1_tagged = 1;
+ }
+
+ ECHO;
+ BEGIN(INITIAL);
+ }
+
+<*>{LABEL}: ECHO;
+
+<INITIAL>[bodh]# {
+ if (*yytext == 'b')
+ cbase = 2;
+ else if (*yytext == 'o')
+ cbase = 8;
+ else if (*yytext == 'd')
+ cbase = 10;
+ else
+ cbase = 16;
+ }
+
+<INITIAL>[0-9a-fA-F]+ {
+ unsigned long long val;
+ int obase = 16, width = 0;
+ int i;
+
+ val = strtoull(yytext, NULL, cbase);
+
+ if (saw_hyphen)
+ val = val - last_val + 1;
+
+ if (last_name) {
+ for (i = 0; i < ARRAY_SIZE(guess_table); i++)
+ if (fnmatch(guess_table[i].pattern,
+ last_name, 0) == 0) {
+ obase = guess_table[i].obase;
+ width = guess_table[i].width;
+ }
+ } else {
+ obase = 16;
+ width = 16;
+ }
+
+ if (cbase != 16)
+ obase = cbase;
+
+ switch (obase) {
+ case 2:
+ case 16:
+ fprintf(yyout, "0x%0*llx", width, val);
+ break;
+ case 8:
+ fprintf(yyout, "0%0*llo", width, val);
+ break;
+ case 10:
+ fprintf(yyout, "%*llu", width, val);
+ break;
+ }
+
+ cbase = 16;
+ last_val = val;
+ saw_hyphen = 0;
+ }
+
+\&{LABEL} ECHO;
+
+"&{/"{PATHCHAR}+\} ECHO;
+
+<INITIAL>"&/"{PATHCHAR}+ fprintf(yyout, "&{/%s}", yytext + 2);
+
+<BYTESTRING>[0-9a-fA-F]{2} ECHO;
+
+<BYTESTRING>"]" {
+ ECHO;
+ BEGIN(INITIAL);
+ }
+
+<PROPNODENAME>{PROPNODECHAR}+ {
+ ECHO;
+ last_name = xstrdup(yytext);
+ BEGIN(INITIAL);
+ }
+
+<*>{GAP} ECHO;
+
+<*>- { /* Hack to convert old style memreserves */
+ saw_hyphen = 1;
+ fprintf(yyout, " ");
+ }
+
+<*>. {
+ if (!v1_tagged) {
+ fprintf(yyout, "/dts-v1/;\n\n");
+ v1_tagged = 1;
+ }
+
+ ECHO;
+ if (yytext[0] == '[') {
+ BEGIN(BYTESTRING);
+ }
+ if ((yytext[0] == '{')
+ || (yytext[0] == ';')) {
+ BEGIN(PROPNODENAME);
+ }
+ }
+
+%%
+/* Usage related data. */
+static const char usage_synopsis[] = "convert-dtsv0 [options] <v0 dts file>...";
+static const char usage_short_opts[] = "" USAGE_COMMON_SHORT_OPTS;
+static struct option const usage_long_opts[] = {
+ USAGE_COMMON_LONG_OPTS
+};
+static const char * const usage_opts_help[] = {
+ USAGE_COMMON_OPTS_HELP
+};
+
+static void convert_file(const char *fname)
+{
+ const char suffix[] = "v1";
+ int len = strlen(fname);
+ char *newname;
+
+ newname = xmalloc(len + sizeof(suffix));
+ memcpy(newname, fname, len);
+ memcpy(newname + len, suffix, sizeof(suffix));
+
+ yyin = fopen(fname, "r");
+ if (!yyin)
+ die("Couldn't open input file %s: %s\n",
+ fname, strerror(errno));
+
+ yyout = fopen(newname, "w");
+ if (!yyout)
+ die("Couldn't open output file %s: %s\n",
+ newname, strerror(errno));
+
+ while(yylex())
+ ;
+}
+
+int main(int argc, char *argv[])
+{
+ int opt;
+ int i;
+
+ while ((opt = util_getopt_long()) != EOF) {
+ switch (opt) {
+ case_USAGE_COMMON_FLAGS
+ }
+ }
+ if (argc < 2)
+ usage("missing filename");
+
+ for (i = 1; i < argc; i++) {
+ fprintf(stderr, "Converting %s from dts v0 to dts v1\n", argv[i]);
+ convert_file(argv[i]);
+ }
+
+ exit(0);
+}
diff --git a/src/dtc/data.c b/src/dtc/data.c
new file mode 100644
index 0000000..4a40c5b
--- /dev/null
+++ b/src/dtc/data.c
@@ -0,0 +1,269 @@
+/*
+ * (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"
+
+void data_free(struct data d)
+{
+ struct marker *m, *nm;
+
+ m = d.markers;
+ while (m) {
+ nm = m->next;
+ free(m->ref);
+ free(m);
+ m = nm;
+ }
+
+ if (d.val)
+ free(d.val);
+}
+
+struct data data_grow_for(struct data d, int xlen)
+{
+ struct data nd;
+ int newsize;
+
+ if (xlen == 0)
+ return d;
+
+ nd = d;
+
+ newsize = xlen;
+
+ while ((d.len + xlen) > newsize)
+ newsize *= 2;
+
+ nd.val = xrealloc(d.val, newsize);
+
+ return nd;
+}
+
+struct data data_copy_mem(const char *mem, int len)
+{
+ struct data d;
+
+ d = data_grow_for(empty_data, len);
+
+ d.len = len;
+ memcpy(d.val, mem, len);
+
+ return d;
+}
+
+struct data data_copy_escape_string(const char *s, int len)
+{
+ int i = 0;
+ struct data d;
+ char *q;
+
+ d = data_grow_for(empty_data, strlen(s)+1);
+
+ q = d.val;
+ while (i < len) {
+ char c = s[i++];
+
+ if (c == '\\')
+ c = get_escape_char(s, &i);
+
+ q[d.len++] = c;
+ }
+
+ q[d.len++] = '\0';
+ return d;
+}
+
+struct data data_copy_file(FILE *f, size_t maxlen)
+{
+ struct data d = empty_data;
+
+ while (!feof(f) && (d.len < maxlen)) {
+ size_t chunksize, ret;
+
+ if (maxlen == -1)
+ chunksize = 4096;
+ else
+ chunksize = maxlen - d.len;
+
+ d = data_grow_for(d, chunksize);
+ ret = fread(d.val + d.len, 1, chunksize, f);
+
+ if (ferror(f))
+ die("Error reading file into data: %s", strerror(errno));
+
+ if (d.len + ret < d.len)
+ die("Overflow reading file into data\n");
+
+ d.len += ret;
+ }
+
+ return d;
+}
+
+struct data data_append_data(struct data d, const void *p, int len)
+{
+ d = data_grow_for(d, len);
+ memcpy(d.val + d.len, p, len);
+ d.len += len;
+ return d;
+}
+
+struct data data_insert_at_marker(struct data d, struct marker *m,
+ const void *p, int len)
+{
+ d = data_grow_for(d, len);
+ memmove(d.val + m->offset + len, d.val + m->offset, d.len - m->offset);
+ memcpy(d.val + m->offset, p, len);
+ d.len += len;
+
+ /* Adjust all markers after the one we're inserting at */
+ m = m->next;
+ for_each_marker(m)
+ m->offset += len;
+ return d;
+}
+
+static struct data data_append_markers(struct data d, struct marker *m)
+{
+ struct marker **mp = &d.markers;
+
+ /* Find the end of the markerlist */
+ while (*mp)
+ mp = &((*mp)->next);
+ *mp = m;
+ return d;
+}
+
+struct data data_merge(struct data d1, struct data d2)
+{
+ struct data d;
+ struct marker *m2 = d2.markers;
+
+ d = data_append_markers(data_append_data(d1, d2.val, d2.len), m2);
+
+ /* Adjust for the length of d1 */
+ for_each_marker(m2)
+ m2->offset += d1.len;
+
+ d2.markers = NULL; /* So data_free() doesn't clobber them */
+ data_free(d2);
+
+ return d;
+}
+
+struct data data_append_integer(struct data d, uint64_t value, int bits)
+{
+ uint8_t value_8;
+ uint16_t value_16;
+ uint32_t value_32;
+ uint64_t value_64;
+
+ switch (bits) {
+ case 8:
+ value_8 = value;
+ return data_append_data(d, &value_8, 1);
+
+ case 16:
+ value_16 = cpu_to_fdt16(value);
+ return data_append_data(d, &value_16, 2);
+
+ case 32:
+ value_32 = cpu_to_fdt32(value);
+ return data_append_data(d, &value_32, 4);
+
+ case 64:
+ value_64 = cpu_to_fdt64(value);
+ return data_append_data(d, &value_64, 8);
+
+ default:
+ die("Invalid literal size (%d)\n", bits);
+ }
+}
+
+struct data data_append_re(struct data d, const struct fdt_reserve_entry *re)
+{
+ struct fdt_reserve_entry bere;
+
+ bere.address = cpu_to_fdt64(re->address);
+ bere.size = cpu_to_fdt64(re->size);
+
+ return data_append_data(d, &bere, sizeof(bere));
+}
+
+struct data data_append_cell(struct data d, cell_t word)
+{
+ return data_append_integer(d, word, sizeof(word) * 8);
+}
+
+struct data data_append_addr(struct data d, uint64_t addr)
+{
+ return data_append_integer(d, addr, sizeof(addr) * 8);
+}
+
+struct data data_append_byte(struct data d, uint8_t byte)
+{
+ return data_append_data(d, &byte, 1);
+}
+
+struct data data_append_zeroes(struct data d, int len)
+{
+ d = data_grow_for(d, len);
+
+ memset(d.val + d.len, 0, len);
+ d.len += len;
+ return d;
+}
+
+struct data data_append_align(struct data d, int align)
+{
+ int newlen = ALIGN(d.len, align);
+ return data_append_zeroes(d, newlen - d.len);
+}
+
+struct data data_add_marker(struct data d, enum markertype type, char *ref)
+{
+ struct marker *m;
+
+ m = xmalloc(sizeof(*m));
+ m->offset = d.len;
+ m->type = type;
+ m->ref = ref;
+ m->next = NULL;
+
+ return data_append_markers(d, m);
+}
+
+int data_is_one_string(struct data d)
+{
+ int i;
+ int len = d.len;
+
+ if (len == 0)
+ return 0;
+
+ for (i = 0; i < len-1; i++)
+ if (d.val[i] == '\0')
+ return 0;
+
+ if (d.val[len-1] != '\0')
+ return 0;
+
+ return 1;
+}
diff --git a/src/dtc/dtc-lexer.l b/src/dtc/dtc-lexer.l
new file mode 100644
index 0000000..3b41bfc
--- /dev/null
+++ b/src/dtc/dtc-lexer.l
@@ -0,0 +1,250 @@
+/*
+ * (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
+
+%x INCLUDE
+%x BYTESTRING
+%x PROPNODENAME
+%s V1
+
+PROPNODECHAR [a-zA-Z0-9,._+*#?@-]
+PATHCHAR ({PROPNODECHAR}|[/])
+LABEL [a-zA-Z_][a-zA-Z0-9_]*
+STRING \"([^\\"]|\\.)*\"
+CHAR_LITERAL '([^']|\\')*'
+WS [[:space:]]
+COMMENT "/*"([^*]|\*+[^*/])*\*+"/"
+LINECOMMENT "//".*\n
+
+%{
+#include "dtc.h"
+#include "srcpos.h"
+#include "dtc-parser.tab.h"
+
+YYLTYPE yylloc;
+
+/* CAUTION: this will stop working if we ever use yyless() or yyunput() */
+#define YY_USER_ACTION \
+ { \
+ srcpos_update(&yylloc, yytext, yyleng); \
+ }
+
+/*#define LEXDEBUG 1*/
+
+#ifdef LEXDEBUG
+#define DPRINT(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
+#else
+#define DPRINT(fmt, ...) do { } while (0)
+#endif
+
+static int dts_version = 1;
+
+#define BEGIN_DEFAULT() DPRINT("<V1>\n"); \
+ BEGIN(V1); \
+
+static void push_input_file(const char *filename);
+static int pop_input_file(void);
+%}
+
+%%
+<*>"/include/"{WS}*{STRING} {
+ char *name = strchr(yytext, '\"') + 1;
+ yytext[yyleng-1] = '\0';
+ push_input_file(name);
+ }
+
+<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)? {
+ char *line, *tmp, *fn;
+ /* skip text before line # */
+ line = yytext;
+ while (!isdigit(*line))
+ line++;
+ /* skip digits in line # */
+ tmp = line;
+ while (!isspace(*tmp))
+ tmp++;
+ /* "NULL"-terminate line # */
+ *tmp = '\0';
+ /* start of filename */
+ fn = strchr(tmp + 1, '"') + 1;
+ /* strip trailing " from filename */
+ tmp = strchr(fn, '"');
+ *tmp = 0;
+ /* -1 since #line is the number of the next line */
+ srcpos_set_line(xstrdup(fn), atoi(line) - 1);
+ }
+
+<*><<EOF>> {
+ if (!pop_input_file()) {
+ yyterminate();
+ }
+ }
+
+<*>{STRING} {
+ DPRINT("String: %s\n", yytext);
+ yylval.data = data_copy_escape_string(yytext+1,
+ yyleng-2);
+ return DT_STRING;
+ }
+
+<*>"/dts-v1/" {
+ DPRINT("Keyword: /dts-v1/\n");
+ dts_version = 1;
+ BEGIN_DEFAULT();
+ return DT_V1;
+ }
+
+<*>"/memreserve/" {
+ DPRINT("Keyword: /memreserve/\n");
+ BEGIN_DEFAULT();
+ return DT_MEMRESERVE;
+ }
+
+<*>"/bits/" {
+ DPRINT("Keyword: /bits/\n");
+ BEGIN_DEFAULT();
+ return DT_BITS;
+ }
+
+<*>"/delete-property/" {
+ DPRINT("Keyword: /delete-property/\n");
+ DPRINT("<PROPNODENAME>\n");
+ BEGIN(PROPNODENAME);
+ return DT_DEL_PROP;
+ }
+
+<*>"/delete-node/" {
+ DPRINT("Keyword: /delete-node/\n");
+ DPRINT("<PROPNODENAME>\n");
+ BEGIN(PROPNODENAME);
+ return DT_DEL_NODE;
+ }
+
+<*>{LABEL}: {
+ DPRINT("Label: %s\n", yytext);
+ yylval.labelref = xstrdup(yytext);
+ yylval.labelref[yyleng-1] = '\0';
+ return DT_LABEL;
+ }
+
+<V1>([0-9]+|0[xX][0-9a-fA-F]+)(U|L|UL|LL|ULL)? {
+ yylval.literal = xstrdup(yytext);
+ DPRINT("Literal: '%s'\n", yylval.literal);
+ return DT_LITERAL;
+ }
+
+<*>{CHAR_LITERAL} {
+ yytext[yyleng-1] = '\0';
+ yylval.literal = xstrdup(yytext+1);
+ DPRINT("Character literal: %s\n", yylval.literal);
+ return DT_CHAR_LITERAL;
+ }
+
+<*>\&{LABEL} { /* label reference */
+ DPRINT("Ref: %s\n", yytext+1);
+ yylval.labelref = xstrdup(yytext+1);
+ return DT_REF;
+ }
+
+<*>"&{/"{PATHCHAR}+\} { /* new-style path reference */
+ yytext[yyleng-1] = '\0';
+ DPRINT("Ref: %s\n", yytext+2);
+ yylval.labelref = xstrdup(yytext+2);
+ return DT_REF;
+ }
+
+<BYTESTRING>[0-9a-fA-F]{2} {
+ yylval.byte = strtol(yytext, NULL, 16);
+ DPRINT("Byte: %02x\n", (int)yylval.byte);
+ return DT_BYTE;
+ }
+
+<BYTESTRING>"]" {
+ DPRINT("/BYTESTRING\n");
+ BEGIN_DEFAULT();
+ return ']';
+ }
+
+<PROPNODENAME>\\?{PROPNODECHAR}+ {
+ DPRINT("PropNodeName: %s\n", yytext);
+ yylval.propnodename = xstrdup((yytext[0] == '\\') ?
+ yytext + 1 : yytext);
+ BEGIN_DEFAULT();
+ return DT_PROPNODENAME;
+ }
+
+"/incbin/" {
+ DPRINT("Binary Include\n");
+ return DT_INCBIN;
+ }
+
+<*>{WS}+ /* eat whitespace */
+<*>{COMMENT}+ /* eat C-style comments */
+<*>{LINECOMMENT}+ /* eat C++-style comments */
+
+<*>"<<" { return DT_LSHIFT; };
+<*>">>" { return DT_RSHIFT; };
+<*>"<=" { return DT_LE; };
+<*>">=" { return DT_GE; };
+<*>"==" { return DT_EQ; };
+<*>"!=" { return DT_NE; };
+<*>"&&" { return DT_AND; };
+<*>"||" { return DT_OR; };
+
+<*>. {
+ DPRINT("Char: %c (\\x%02x)\n", yytext[0],
+ (unsigned)yytext[0]);
+ if (yytext[0] == '[') {
+ DPRINT("<BYTESTRING>\n");
+ BEGIN(BYTESTRING);
+ }
+ if ((yytext[0] == '{')
+ || (yytext[0] == ';')) {
+ DPRINT("<PROPNODENAME>\n");
+ BEGIN(PROPNODENAME);
+ }
+ return yytext[0];
+ }
+
+%%
+
+static void push_input_file(const char *filename)
+{
+ assert(filename);
+
+ srcfile_push(filename);
+
+ yyin = current_srcfile->f;
+
+ yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE));
+}
+
+
+static int pop_input_file(void)
+{
+ if (srcfile_pop() == 0)
+ return 0;
+
+ yypop_buffer_state();
+ yyin = current_srcfile->f;
+
+ return 1;
+}
diff --git a/src/dtc/dtc-parser.y b/src/dtc/dtc-parser.y
new file mode 100644
index 0000000..f412460
--- /dev/null
+++ b/src/dtc/dtc-parser.y
@@ -0,0 +1,532 @@
+/*
+ * (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>
+
+#include "dtc.h"
+#include "srcpos.h"
+
+YYLTYPE yylloc;
+
+extern int yylex(void);
+extern void print_error(char const *fmt, ...);
+extern void yyerror(char const *s);
+
+extern struct boot_info *the_boot_info;
+extern int treesource_error;
+
+static unsigned long long eval_literal(const char *s, int base, int bits);
+static unsigned char eval_char_literal(const char *s);
+%}
+
+%union {
+ char *propnodename;
+ char *literal;
+ char *labelref;
+ unsigned int cbase;
+ uint8_t byte;
+ struct data data;
+
+ struct {
+ struct data data;
+ int bits;
+ } array;
+
+ struct property *prop;
+ struct property *proplist;
+ struct node *node;
+ struct node *nodelist;
+ struct reserve_info *re;
+ uint64_t integer;
+}
+
+%token DT_V1
+%token DT_MEMRESERVE
+%token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
+%token DT_BITS
+%token DT_DEL_PROP
+%token DT_DEL_NODE
+%token <propnodename> DT_PROPNODENAME
+%token <literal> DT_LITERAL
+%token <literal> DT_CHAR_LITERAL
+%token <cbase> DT_BASE
+%token <byte> DT_BYTE
+%token <data> DT_STRING
+%token <labelref> DT_LABEL
+%token <labelref> DT_REF
+%token DT_INCBIN
+
+%type <data> propdata
+%type <data> propdataprefix
+%type <re> memreserve
+%type <re> memreserves
+%type <array> arrayprefix
+%type <data> bytestring
+%type <prop> propdef
+%type <proplist> proplist
+
+%type <node> devicetree
+%type <node> nodedef
+%type <node> subnode
+%type <nodelist> subnodes
+
+%type <integer> integer_prim
+%type <integer> integer_unary
+%type <integer> integer_mul
+%type <integer> integer_add
+%type <integer> integer_shift
+%type <integer> integer_rela
+%type <integer> integer_eq
+%type <integer> integer_bitand
+%type <integer> integer_bitxor
+%type <integer> integer_bitor
+%type <integer> integer_and
+%type <integer> integer_or
+%type <integer> integer_trinary
+%type <integer> integer_expr
+
+%%
+
+sourcefile:
+ DT_V1 ';' memreserves devicetree
+ {
+ the_boot_info = build_boot_info($3, $4,
+ guess_boot_cpuid($4));
+ }
+ ;
+
+memreserves:
+ /* empty */
+ {
+ $$ = NULL;
+ }
+ | memreserve memreserves
+ {
+ $$ = chain_reserve_entry($1, $2);
+ }
+ ;
+
+memreserve:
+ DT_MEMRESERVE integer_prim integer_prim ';'
+ {
+ $$ = build_reserve_entry($2, $3);
+ }
+ | DT_LABEL memreserve
+ {
+ add_label(&$2->labels, $1);
+ $$ = $2;
+ }
+ ;
+
+devicetree:
+ '/' nodedef
+ {
+ $$ = name_node($2, "");
+ }
+ | devicetree '/' nodedef
+ {
+ $$ = merge_nodes($1, $3);
+ }
+ | devicetree DT_REF nodedef
+ {
+ struct node *target = get_node_by_ref($1, $2);
+
+ if (target)
+ merge_nodes(target, $3);
+ else
+ print_error("label or path, '%s', not found", $2);
+ $$ = $1;
+ }
+ | devicetree DT_DEL_NODE DT_REF ';'
+ {
+ struct node *target = get_node_by_ref($1, $3);
+
+ if (!target)
+ print_error("label or path, '%s', not found", $3);
+ else
+ delete_node(target);
+
+ $$ = $1;
+ }
+ ;
+
+nodedef:
+ '{' proplist subnodes '}' ';'
+ {
+ $$ = build_node($2, $3);
+ }
+ ;
+
+proplist:
+ /* empty */
+ {
+ $$ = NULL;
+ }
+ | proplist propdef
+ {
+ $$ = chain_property($2, $1);
+ }
+ ;
+
+propdef:
+ DT_PROPNODENAME '=' propdata ';'
+ {
+ $$ = build_property($1, $3);
+ }
+ | DT_PROPNODENAME ';'
+ {
+ $$ = build_property($1, empty_data);
+ }
+ | DT_DEL_PROP DT_PROPNODENAME ';'
+ {
+ $$ = build_property_delete($2);
+ }
+ | DT_LABEL propdef
+ {
+ add_label(&$2->labels, $1);
+ $$ = $2;
+ }
+ ;
+
+propdata:
+ propdataprefix DT_STRING
+ {
+ $$ = data_merge($1, $2);
+ }
+ | propdataprefix arrayprefix '>'
+ {
+ $$ = data_merge($1, $2.data);
+ }
+ | propdataprefix '[' bytestring ']'
+ {
+ $$ = data_merge($1, $3);
+ }
+ | propdataprefix DT_REF
+ {
+ $$ = data_add_marker($1, REF_PATH, $2);
+ }
+ | propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
+ {
+ FILE *f = srcfile_relative_open($4.val, NULL);
+ struct data d;
+
+ if ($6 != 0)
+ if (fseek(f, $6, SEEK_SET) != 0)
+ print_error("Couldn't seek to offset %llu in \"%s\": %s",
+ (unsigned long long)$6,
+ $4.val,
+ strerror(errno));
+
+ d = data_copy_file(f, $8);
+
+ $$ = data_merge($1, d);
+ fclose(f);
+ }
+ | propdataprefix DT_INCBIN '(' DT_STRING ')'
+ {
+ FILE *f = srcfile_relative_open($4.val, NULL);
+ struct data d = empty_data;
+
+ d = data_copy_file(f, -1);
+
+ $$ = data_merge($1, d);
+ fclose(f);
+ }
+ | propdata DT_LABEL
+ {
+ $$ = data_add_marker($1, LABEL, $2);
+ }
+ ;
+
+propdataprefix:
+ /* empty */
+ {
+ $$ = empty_data;
+ }
+ | propdata ','
+ {
+ $$ = $1;
+ }
+ | propdataprefix DT_LABEL
+ {
+ $$ = data_add_marker($1, LABEL, $2);
+ }
+ ;
+
+arrayprefix:
+ DT_BITS DT_LITERAL '<'
+ {
+ $$.data = empty_data;
+ $$.bits = eval_literal($2, 0, 7);
+
+ if (($$.bits != 8) &&
+ ($$.bits != 16) &&
+ ($$.bits != 32) &&
+ ($$.bits != 64))
+ {
+ print_error("Only 8, 16, 32 and 64-bit elements"
+ " are currently supported");
+ $$.bits = 32;
+ }
+ }
+ | '<'
+ {
+ $$.data = empty_data;
+ $$.bits = 32;
+ }
+ | arrayprefix integer_prim
+ {
+ if ($1.bits < 64) {
+ uint64_t mask = (1ULL << $1.bits) - 1;
+ /*
+ * Bits above mask must either be all zero
+ * (positive within range of mask) or all one
+ * (negative and sign-extended). The second
+ * condition is true if when we set all bits
+ * within the mask to one (i.e. | in the
+ * mask), all bits are one.
+ */
+ if (($2 > mask) && (($2 | mask) != -1ULL))
+ print_error(
+ "integer value out of range "
+ "%016lx (%d bits)", $1.bits);
+ }
+
+ $$.data = data_append_integer($1.data, $2, $1.bits);
+ }
+ | arrayprefix DT_REF
+ {
+ uint64_t val = ~0ULL >> (64 - $1.bits);
+
+ if ($1.bits == 32)
+ $1.data = data_add_marker($1.data,
+ REF_PHANDLE,
+ $2);
+ else
+ print_error("References are only allowed in "
+ "arrays with 32-bit elements.");
+
+ $$.data = data_append_integer($1.data, val, $1.bits);
+ }
+ | arrayprefix DT_LABEL
+ {
+ $$.data = data_add_marker($1.data, LABEL, $2);
+ }
+ ;
+
+integer_prim:
+ DT_LITERAL
+ {
+ $$ = eval_literal($1, 0, 64);
+ }
+ | DT_CHAR_LITERAL
+ {
+ $$ = eval_char_literal($1);
+ }
+ | '(' integer_expr ')'
+ {
+ $$ = $2;
+ }
+ ;
+
+integer_expr:
+ integer_trinary
+ ;
+
+integer_trinary:
+ integer_or
+ | integer_or '?' integer_expr ':' integer_trinary { $$ = $1 ? $3 : $5; }
+ ;
+
+integer_or:
+ integer_and
+ | integer_or DT_OR integer_and { $$ = $1 || $3; }
+ ;
+
+integer_and:
+ integer_bitor
+ | integer_and DT_AND integer_bitor { $$ = $1 && $3; }
+ ;
+
+integer_bitor:
+ integer_bitxor
+ | integer_bitor '|' integer_bitxor { $$ = $1 | $3; }
+ ;
+
+integer_bitxor:
+ integer_bitand
+ | integer_bitxor '^' integer_bitand { $$ = $1 ^ $3; }
+ ;
+
+integer_bitand:
+ integer_eq
+ | integer_bitand '&' integer_eq { $$ = $1 & $3; }
+ ;
+
+integer_eq:
+ integer_rela
+ | integer_eq DT_EQ integer_rela { $$ = $1 == $3; }
+ | integer_eq DT_NE integer_rela { $$ = $1 != $3; }
+ ;
+
+integer_rela:
+ integer_shift
+ | integer_rela '<' integer_shift { $$ = $1 < $3; }
+ | integer_rela '>' integer_shift { $$ = $1 > $3; }
+ | integer_rela DT_LE integer_shift { $$ = $1 <= $3; }
+ | integer_rela DT_GE integer_shift { $$ = $1 >= $3; }
+ ;
+
+integer_shift:
+ integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; }
+ | integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; }
+ | integer_add
+ ;
+
+integer_add:
+ integer_add '+' integer_mul { $$ = $1 + $3; }
+ | integer_add '-' integer_mul { $$ = $1 - $3; }
+ | integer_mul
+ ;
+
+integer_mul:
+ integer_mul '*' integer_unary { $$ = $1 * $3; }
+ | integer_mul '/' integer_unary { $$ = $1 / $3; }
+ | integer_mul '%' integer_unary { $$ = $1 % $3; }
+ | integer_unary
+ ;
+
+integer_unary:
+ integer_prim
+ | '-' integer_unary { $$ = -$2; }
+ | '~' integer_unary { $$ = ~$2; }
+ | '!' integer_unary { $$ = !$2; }
+ ;
+
+bytestring:
+ /* empty */
+ {
+ $$ = empty_data;
+ }
+ | bytestring DT_BYTE
+ {
+ $$ = data_append_byte($1, $2);
+ }
+ | bytestring DT_LABEL
+ {
+ $$ = data_add_marker($1, LABEL, $2);
+ }
+ ;
+
+subnodes:
+ /* empty */
+ {
+ $$ = NULL;
+ }
+ | subnode subnodes
+ {
+ $$ = chain_node($1, $2);
+ }
+ | subnode propdef
+ {
+ print_error("syntax error: properties must precede subnodes");
+ YYERROR;
+ }
+ ;
+
+subnode:
+ DT_PROPNODENAME nodedef
+ {
+ $$ = name_node($2, $1);
+ }
+ | DT_DEL_NODE DT_PROPNODENAME ';'
+ {
+ $$ = name_node(build_node_delete(), $2);
+ }
+ | DT_LABEL subnode
+ {
+ add_label(&$2->labels, $1);
+ $$ = $2;
+ }
+ ;
+
+%%
+
+void print_error(char const *fmt, ...)
+{
+ va_list va;
+
+ va_start(va, fmt);
+ srcpos_verror(&yylloc, fmt, va);
+ va_end(va);
+
+ treesource_error = 1;
+}
+
+void yyerror(char const *s) {
+ print_error("%s", s);
+}
+
+static unsigned long long eval_literal(const char *s, int base, int bits)
+{
+ unsigned long long val;
+ char *e;
+
+ errno = 0;
+ val = strtoull(s, &e, base);
+ if (*e) {
+ size_t uls = strspn(e, "UL");
+ if (e[uls])
+ print_error("bad characters in literal");
+ }
+ if ((errno == ERANGE)
+ || ((bits < 64) && (val >= (1ULL << bits))))
+ print_error("literal out of range");
+ else if (errno != 0)
+ print_error("bad literal");
+ return val;
+}
+
+static unsigned char eval_char_literal(const char *s)
+{
+ int i = 1;
+ char c = s[0];
+
+ if (c == '\0')
+ {
+ print_error("empty character literal");
+ return 0;
+ }
+
+ /*
+ * If the first character in the character literal is a \ then process
+ * the remaining characters as an escape encoding. If the first
+ * character is neither an escape or a terminator it should be the only
+ * character in the literal and will be returned.
+ */
+ if (c == '\\')
+ c = get_escape_char(s, &i);
+
+ if (s[i] != '\0')
+ print_error("malformed character literal");
+
+ return c;
+}
diff --git a/src/dtc/dtc.c b/src/dtc/dtc.c
new file mode 100644
index 0000000..e3c9653
--- /dev/null
+++ b/src/dtc/dtc.c
@@ -0,0 +1,259 @@
+/*
+ * (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"
+
+/*
+ * Command line options
+ */
+int quiet; /* Level of quietness */
+int reservenum; /* Number of memory reservation slots */
+int minsize; /* Minimum blob size */
+int padsize; /* Additional padding to blob */
+int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */
+
+static void fill_fullpaths(struct node *tree, const char *prefix)
+{
+ struct node *child;
+ const char *unit;
+
+ tree->fullpath = join_path(prefix, tree->name);
+
+ unit = strchr(tree->name, '@');
+ if (unit)
+ tree->basenamelen = unit - tree->name;
+ else
+ tree->basenamelen = strlen(tree->name);
+
+ for_each_child(tree, child)
+ fill_fullpaths(child, tree->fullpath);
+}
+
+/* Usage related data. */
+static const char usage_synopsis[] = "dtc [options] <input file>";
+static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv";
+static struct option const usage_long_opts[] = {
+ {"quiet", no_argument, NULL, 'q'},
+ {"in-format", a_argument, NULL, 'I'},
+ {"out", a_argument, NULL, 'o'},
+ {"out-format", a_argument, NULL, 'O'},
+ {"out-version", a_argument, NULL, 'V'},
+ {"out-dependency", a_argument, NULL, 'd'},
+ {"reserve", a_argument, NULL, 'R'},
+ {"space", a_argument, NULL, 'S'},
+ {"pad", a_argument, NULL, 'p'},
+ {"boot-cpu", a_argument, NULL, 'b'},
+ {"force", no_argument, NULL, 'f'},
+ {"include", a_argument, NULL, 'i'},
+ {"sort", no_argument, NULL, 's'},
+ {"phandle", a_argument, NULL, 'H'},
+ {"warning", a_argument, NULL, 'W'},
+ {"error", a_argument, NULL, 'E'},
+ {"help", no_argument, NULL, 'h'},
+ {"version", no_argument, NULL, 'v'},
+ {NULL, no_argument, NULL, 0x0},
+};
+static const char * const usage_opts_help[] = {
+ "\n\tQuiet: -q suppress warnings, -qq errors, -qqq all",
+ "\n\tInput formats are:\n"
+ "\t\tdts - device tree source text\n"
+ "\t\tdtb - device tree blob\n"
+ "\t\tfs - /proc/device-tree style directory",
+ "\n\tOutput file",
+ "\n\tOutput formats are:\n"
+ "\t\tdts - device tree source text\n"
+ "\t\tdtb - device tree blob\n"
+ "\t\tasm - assembler source",
+ "\n\tBlob version to produce, defaults to %d (for dtb and asm output)", //, DEFAULT_FDT_VERSION);
+ "\n\tOutput dependency file",
+ "\n\ttMake space for <number> reserve map entries (for dtb and asm output)",
+ "\n\tMake the blob at least <bytes> long (extra space)",
+ "\n\tAdd padding to the blob of <bytes> long (extra space)",
+ "\n\tSet the physical boot cpu",
+ "\n\tTry to produce output even if the input tree has errors",
+ "\n\tAdd a path to search for include files",
+ "\n\tSort nodes and properties before outputting (useful for comparing trees)",
+ "\n\tValid phandle formats are:\n"
+ "\t\tlegacy - \"linux,phandle\" properties only\n"
+ "\t\tepapr - \"phandle\" properties only\n"
+ "\t\tboth - Both \"linux,phandle\" and \"phandle\" properties",
+ "\n\tEnable/disable warnings (prefix with \"no-\")",
+ "\n\tEnable/disable errors (prefix with \"no-\")",
+ "\n\tPrint this help and exit",
+ "\n\tPrint version and exit",
+ NULL,
+};
+
+int main(int argc, char *argv[])
+{
+ struct boot_info *bi;
+ const char *inform = "dts";
+ const char *outform = "dts";
+ const char *outname = "-";
+ const char *depname = NULL;
+ int force = 0, sort = 0;
+ const char *arg;
+ int opt;
+ FILE *outf = NULL;
+ int outversion = DEFAULT_FDT_VERSION;
+ long long cmdline_boot_cpuid = -1;
+
+ quiet = 0;
+ reservenum = 0;
+ minsize = 0;
+ padsize = 0;
+
+ while ((opt = util_getopt_long()) != EOF) {
+ switch (opt) {
+ case 'I':
+ inform = optarg;
+ break;
+ case 'O':
+ outform = optarg;
+ break;
+ case 'o':
+ outname = optarg;
+ break;
+ case 'V':
+ outversion = strtol(optarg, NULL, 0);
+ break;
+ case 'd':
+ depname = optarg;
+ break;
+ case 'R':
+ reservenum = strtol(optarg, NULL, 0);
+ break;
+ case 'S':
+ minsize = strtol(optarg, NULL, 0);
+ break;
+ case 'p':
+ padsize = strtol(optarg, NULL, 0);
+ break;
+ case 'f':
+ force = 1;
+ break;
+ case 'q':
+ quiet++;
+ break;
+ case 'b':
+ cmdline_boot_cpuid = strtoll(optarg, NULL, 0);
+ break;
+ case 'i':
+ srcfile_add_search_path(optarg);
+ break;
+ case 'v':
+ util_version();
+ case 'H':
+ if (streq(optarg, "legacy"))
+ phandle_format = PHANDLE_LEGACY;
+ else if (streq(optarg, "epapr"))
+ phandle_format = PHANDLE_EPAPR;
+ else if (streq(optarg, "both"))
+ phandle_format = PHANDLE_BOTH;
+ else
+ die("Invalid argument \"%s\" to -H option\n",
+ optarg);
+ break;
+
+ case 's':
+ sort = 1;
+ break;
+
+ case 'W':
+ parse_checks_option(true, false, optarg);
+ break;
+
+ case 'E':
+ parse_checks_option(false, true, optarg);
+ break;
+
+ case 'h':
+ usage(NULL);
+ default:
+ usage("unknown option");
+ }
+ }
+
+ if (argc > (optind+1))
+ usage("missing files");
+ else if (argc < (optind+1))
+ arg = "-";
+ else
+ arg = argv[optind];
+
+ /* minsize and padsize are mutually exclusive */
+ if (minsize && padsize)
+ die("Can't set both -p and -S\n");
+
+ if (depname) {
+ depfile = fopen(depname, "w");
+ if (!depfile)
+ die("Couldn't open dependency file %s: %s\n", depname,
+ strerror(errno));
+ fprintf(depfile, "%s:", outname);
+ }
+
+ if (streq(inform, "dts"))
+ bi = dt_from_source(arg);
+ else if (streq(inform, "fs"))
+ bi = dt_from_fs(arg);
+ else if(streq(inform, "dtb"))
+ bi = dt_from_blob(arg);
+ else
+ die("Unknown input format \"%s\"\n", inform);
+
+ if (depfile) {
+ fputc('\n', depfile);
+ fclose(depfile);
+ }
+
+ if (cmdline_boot_cpuid != -1)
+ bi->boot_cpuid_phys = cmdline_boot_cpuid;
+
+ fill_fullpaths(bi->dt, "");
+ process_checks(force, bi);
+
+ if (sort)
+ sort_tree(bi);
+
+ if (streq(outname, "-")) {
+ outf = stdout;
+ } else {
+ outf = fopen(outname, "w");
+ if (! outf)
+ die("Couldn't open output file %s: %s\n",
+ outname, strerror(errno));
+ }
+
+ if (streq(outform, "dts")) {
+ dt_to_source(outf, bi);
+ } else if (streq(outform, "dtb")) {
+ dt_to_blob(outf, bi, outversion);
+ } else if (streq(outform, "asm")) {
+ dt_to_asm(outf, bi, outversion);
+ } else if (streq(outform, "null")) {
+ /* do nothing */
+ } else {
+ die("Unknown output format \"%s\"\n", outform);
+ }
+
+ exit(0);
+}
diff --git a/src/dtc/dtc.h b/src/dtc/dtc.h
new file mode 100644
index 0000000..264a20c
--- /dev/null
+++ b/src/dtc/dtc.h
@@ -0,0 +1,269 @@
+#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>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <libfdt_env.h>
+#include <fdt.h>
+
+#include "util.h"
+
+#ifdef DEBUG
+#define debug(fmt,args...) printf(fmt, ##args)
+#else
+#define debug(fmt,args...)
+#endif
+
+
+#define DEFAULT_FDT_VERSION 17
+
+/*
+ * Command line options
+ */
+extern int quiet; /* Level of quietness */
+extern int reservenum; /* Number of memory reservation slots */
+extern int minsize; /* Minimum blob size */
+extern int padsize; /* Additional padding to blob */
+extern int phandle_format; /* Use linux,phandle or phandle properties */
+
+#define PHANDLE_LEGACY 0x1
+#define PHANDLE_EPAPR 0x2
+#define PHANDLE_BOTH 0x3
+
+typedef uint32_t cell_t;
+
+
+#define streq(a, b) (strcmp((a), (b)) == 0)
+#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
+
+#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
+
+/* Data blobs */
+enum markertype {
+ REF_PHANDLE,
+ REF_PATH,
+ LABEL,
+};
+
+struct marker {
+ enum markertype type;
+ int offset;
+ char *ref;
+ struct marker *next;
+};
+
+struct data {
+ int len;
+ char *val;
+ struct marker *markers;
+};
+
+
+#define empty_data ((struct data){ /* all .members = 0 or NULL */ })
+
+#define for_each_marker(m) \
+ for (; (m); (m) = (m)->next)
+#define for_each_marker_of_type(m, t) \
+ for_each_marker(m) \
+ if ((m)->type == (t))
+
+void data_free(struct data d);
+
+struct data data_grow_for(struct data d, int xlen);
+
+struct data data_copy_mem(const char *mem, int len);
+struct data data_copy_escape_string(const char *s, int len);
+struct data data_copy_file(FILE *f, size_t len);
+
+struct data data_append_data(struct data d, const void *p, int len);
+struct data data_insert_at_marker(struct data d, struct marker *m,
+ const void *p, int len);
+struct data data_merge(struct data d1, struct data d2);
+struct data data_append_cell(struct data d, cell_t word);
+struct data data_append_integer(struct data d, uint64_t word, int bits);
+struct data data_append_re(struct data d, const struct fdt_reserve_entry *re);
+struct data data_append_addr(struct data d, uint64_t addr);
+struct data data_append_byte(struct data d, uint8_t byte);
+struct data data_append_zeroes(struct data d, int len);
+struct data data_append_align(struct data d, int align);
+
+struct data data_add_marker(struct data d, enum markertype type, char *ref);
+
+int data_is_one_string(struct data d);
+
+/* DT constraints */
+
+#define MAX_PROPNAME_LEN 31
+#define MAX_NODENAME_LEN 31
+
+/* Live trees */
+struct label {
+ int deleted;
+ char *label;
+ struct label *next;
+};
+
+struct property {
+ int deleted;
+ char *name;
+ struct data val;
+
+ struct property *next;
+
+ struct label *labels;
+};
+
+struct node {
+ int deleted;
+ char *name;
+ struct property *proplist;
+ struct node *children;
+
+ struct node *parent;
+ struct node *next_sibling;
+
+ char *fullpath;
+ int basenamelen;
+
+ cell_t phandle;
+ int addr_cells, size_cells;
+
+ struct label *labels;
+};
+
+#define for_each_label_withdel(l0, l) \
+ for ((l) = (l0); (l); (l) = (l)->next)
+
+#define for_each_label(l0, l) \
+ for_each_label_withdel(l0, l) \
+ if (!(l)->deleted)
+
+#define for_each_property_withdel(n, p) \
+ for ((p) = (n)->proplist; (p); (p) = (p)->next)
+
+#define for_each_property(n, p) \
+ for_each_property_withdel(n, p) \
+ if (!(p)->deleted)
+
+#define for_each_child_withdel(n, c) \
+ for ((c) = (n)->children; (c); (c) = (c)->next_sibling)
+
+#define for_each_child(n, c) \
+ for_each_child_withdel(n, c) \
+ if (!(c)->deleted)
+
+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_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 *name_node(struct node *node, char *name);
+struct node *chain_node(struct node *first, struct node *list);
+struct node *merge_nodes(struct node *old_node, struct node *new_node);
+
+void add_property(struct node *node, struct property *prop);
+void delete_property_by_name(struct node *node, char *name);
+void delete_property(struct property *prop);
+void add_child(struct node *parent, struct node *child);
+void delete_node_by_name(struct node *parent, char *name);
+void delete_node(struct node *node);
+
+const char *get_unitname(struct node *node);
+struct property *get_property(struct node *node, const char *propname);
+cell_t propval_cell(struct property *prop);
+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,
+ struct node **node, struct property **prop);
+struct node *get_subnode(struct node *node, const char *nodename);
+struct node *get_node_by_path(struct node *tree, const char *path);
+struct node *get_node_by_label(struct node *tree, const char *label);
+struct node *get_node_by_phandle(struct node *tree, cell_t phandle);
+struct node *get_node_by_ref(struct node *tree, const char *ref);
+cell_t get_node_phandle(struct node *root, struct node *node);
+
+uint32_t guess_boot_cpuid(struct node *tree);
+
+/* Boot info (tree plus memreserve information */
+
+struct reserve_info {
+ struct fdt_reserve_entry re;
+
+ struct reserve_info *next;
+
+ struct label *labels;
+};
+
+struct reserve_info *build_reserve_entry(uint64_t start, uint64_t len);
+struct reserve_info *chain_reserve_entry(struct reserve_info *first,
+ struct reserve_info *list);
+struct reserve_info *add_reserve_entry(struct reserve_info *list,
+ struct reserve_info *new);
+
+
+struct boot_info {
+ struct reserve_info *reservelist;
+ struct node *dt; /* the device tree */
+ uint32_t boot_cpuid_phys;
+};
+
+struct boot_info *build_boot_info(struct reserve_info *reservelist,
+ struct node *tree, uint32_t boot_cpuid_phys);
+void sort_tree(struct boot_info *bi);
+
+/* Checks */
+
+void parse_checks_option(bool warn, bool error, const char *optarg);
+void process_checks(int force, struct boot_info *bi);
+
+/* Flattened trees */
+
+void dt_to_blob(FILE *f, struct boot_info *bi, int version);
+void dt_to_asm(FILE *f, struct boot_info *bi, int version);
+
+struct boot_info *dt_from_blob(const char *fname);
+
+/* Tree source */
+
+void dt_to_source(FILE *f, struct boot_info *bi);
+struct boot_info *dt_from_source(const char *f);
+
+/* FS trees */
+
+struct boot_info *dt_from_fs(const char *dirname);
+
+#endif /* _DTC_H */
diff --git a/src/dtc/dtdiff b/src/dtc/dtdiff
new file mode 100644
index 0000000..5fa772b
--- /dev/null
+++ b/src/dtc/dtdiff
@@ -0,0 +1,38 @@
+#! /bin/bash
+
+# This script uses the bash <(...) extension.
+# If you want to change this to work with a generic /bin/sh, make sure
+# you fix that.
+
+
+DTC=dtc
+
+source_and_sort () {
+ DT="$1"
+ if [ -d "$DT" ]; then
+ IFORMAT=fs
+ elif [ -f "$DT" ]; then
+ case "$DT" in
+ *.dts)
+ IFORMAT=dts
+ ;;
+ *.dtb)
+ IFORMAT=dtb
+ ;;
+ esac
+ fi
+
+ if [ -z "$IFORMAT" ]; then
+ echo "Unrecognized format for $DT" >&2
+ exit 2
+ fi
+
+ $DTC -I $IFORMAT -O dts -qq -f -s -o - "$DT"
+}
+
+if [ $# != 2 ]; then
+ echo "Usage: dtdiff <device tree> <device tree>" >&2
+ exit 1
+fi
+
+diff -u <(source_and_sort "$1") <(source_and_sort "$2")
diff --git a/src/dtc/fdtdump.c b/src/dtc/fdtdump.c
new file mode 100644
index 0000000..723770d
--- /dev/null
+++ b/src/dtc/fdtdump.c
@@ -0,0 +1,227 @@
+/*
+ * fdtdump.c - Contributed by Pantelis Antoniou <pantelis.antoniou AT gmail.com>
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <libfdt.h>
+#include <libfdt_env.h>
+#include <fdt.h>
+
+#include "util.h"
+
+#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
+#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a))))
+#define GET_CELL(p) (p += 4, *((const uint32_t *)(p-4)))
+
+static const char *tagname(uint32_t tag)
+{
+ static const char * const names[] = {
+#define TN(t) [t] #t
+ TN(FDT_BEGIN_NODE),
+ TN(FDT_END_NODE),
+ TN(FDT_PROP),
+ TN(FDT_NOP),
+ TN(FDT_END),
+#undef TN
+ };
+ if (tag < ARRAY_SIZE(names))
+ if (names[tag])
+ return names[tag];
+ return "FDT_???";
+}
+
+#define dumpf(fmt, args...) \
+ do { if (debug) printf("// " fmt, ## args); } while (0)
+
+static void dump_blob(void *blob, bool debug)
+{
+ uintptr_t blob_off = (uintptr_t)blob;
+ struct fdt_header *bph = blob;
+ uint32_t off_mem_rsvmap = fdt32_to_cpu(bph->off_mem_rsvmap);
+ uint32_t off_dt = fdt32_to_cpu(bph->off_dt_struct);
+ uint32_t off_str = fdt32_to_cpu(bph->off_dt_strings);
+ struct fdt_reserve_entry *p_rsvmap =
+ (struct fdt_reserve_entry *)((char *)blob + off_mem_rsvmap);
+ const char *p_struct = (const char *)blob + off_dt;
+ const char *p_strings = (const char *)blob + off_str;
+ uint32_t version = fdt32_to_cpu(bph->version);
+ uint32_t totalsize = fdt32_to_cpu(bph->totalsize);
+ uint32_t tag;
+ const char *p, *s, *t;
+ int depth, sz, shift;
+ int i;
+ uint64_t addr, size;
+
+ depth = 0;
+ shift = 4;
+
+ printf("/dts-v1/;\n");
+ printf("// magic:\t\t0x%x\n", fdt32_to_cpu(bph->magic));
+ printf("// totalsize:\t\t0x%x (%d)\n", totalsize, totalsize);
+ printf("// off_dt_struct:\t0x%x\n", off_dt);
+ printf("// off_dt_strings:\t0x%x\n", off_str);
+ printf("// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap);
+ printf("// version:\t\t%d\n", version);
+ printf("// last_comp_version:\t%d\n",
+ fdt32_to_cpu(bph->last_comp_version));
+ if (version >= 2)
+ printf("// boot_cpuid_phys:\t0x%x\n",
+ fdt32_to_cpu(bph->boot_cpuid_phys));
+
+ if (version >= 3)
+ printf("// size_dt_strings:\t0x%x\n",
+ fdt32_to_cpu(bph->size_dt_strings));
+ if (version >= 17)
+ printf("// size_dt_struct:\t0x%x\n",
+ fdt32_to_cpu(bph->size_dt_struct));
+ printf("\n");
+
+ for (i = 0; ; i++) {
+ addr = fdt64_to_cpu(p_rsvmap[i].address);
+ size = fdt64_to_cpu(p_rsvmap[i].size);
+ if (addr == 0 && size == 0)
+ break;
+
+ printf("/memreserve/ %llx %llx;\n",
+ (unsigned long long)addr, (unsigned long long)size);
+ }
+
+ p = p_struct;
+ while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) {
+
+ dumpf("%04zx: tag: 0x%08x (%s)\n",
+ (uintptr_t)p - blob_off - 4, tag, tagname(tag));
+
+ if (tag == FDT_BEGIN_NODE) {
+ s = p;
+ p = PALIGN(p + strlen(s) + 1, 4);
+
+ if (*s == '\0')
+ s = "/";
+
+ printf("%*s%s {\n", depth * shift, "", s);
+
+ depth++;
+ continue;
+ }
+
+ if (tag == FDT_END_NODE) {
+ depth--;
+
+ printf("%*s};\n", depth * shift, "");
+ continue;
+ }
+
+ if (tag == FDT_NOP) {
+ printf("%*s// [NOP]\n", depth * shift, "");
+ continue;
+ }
+
+ if (tag != FDT_PROP) {
+ fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", depth * shift, "", tag);
+ break;
+ }
+ sz = fdt32_to_cpu(GET_CELL(p));
+ s = p_strings + fdt32_to_cpu(GET_CELL(p));
+ if (version < 16 && sz >= 8)
+ p = PALIGN(p, 8);
+ t = p;
+
+ p = PALIGN(p + sz, 4);
+
+ dumpf("%04zx: string: %s\n", (uintptr_t)s - blob_off, s);
+ dumpf("%04zx: value\n", (uintptr_t)t - blob_off);
+ printf("%*s%s", depth * shift, "", s);
+ utilfdt_print_data(t, sz);
+ printf(";\n");
+ }
+}
+
+/* Usage related data. */
+static const char usage_synopsis[] = "fdtdump [options] <file>";
+static const char usage_short_opts[] = "ds" USAGE_COMMON_SHORT_OPTS;
+static struct option const usage_long_opts[] = {
+ {"debug", no_argument, NULL, 'd'},
+ {"scan", no_argument, NULL, 's'},
+ USAGE_COMMON_LONG_OPTS
+};
+static const char * const usage_opts_help[] = {
+ "Dump debug information while decoding the file",
+ "Scan for an embedded fdt in file",
+ USAGE_COMMON_OPTS_HELP
+};
+
+int main(int argc, char *argv[])
+{
+ int opt;
+ const char *file;
+ char *buf;
+ bool debug = false;
+ bool scan = false;
+ off_t len;
+
+ while ((opt = util_getopt_long()) != EOF) {
+ switch (opt) {
+ case_USAGE_COMMON_FLAGS
+
+ case 'd':
+ debug = true;
+ break;
+ case 's':
+ scan = true;
+ break;
+ }
+ }
+ if (optind != argc - 1)
+ usage("missing input filename");
+ file = argv[optind];
+
+ buf = utilfdt_read_len(file, &len);
+ if (!buf)
+ die("could not read: %s\n", file);
+
+ /* try and locate an embedded fdt in a bigger blob */
+ if (scan) {
+ unsigned char smagic[4];
+ char *p = buf;
+ char *endp = buf + len;
+
+ fdt_set_magic(smagic, FDT_MAGIC);
+
+ /* poor man's memmem */
+ while (true) {
+ p = memchr(p, smagic[0], endp - p - 4);
+ if (!p)
+ break;
+ if (fdt_magic(p) == FDT_MAGIC) {
+ /* try and validate the main struct */
+ off_t this_len = endp - p;
+ fdt32_t max_version = 17;
+ if (fdt_version(p) <= max_version &&
+ fdt_last_comp_version(p) < max_version &&
+ fdt_totalsize(p) < this_len &&
+ fdt_off_dt_struct(p) < this_len &&
+ fdt_off_dt_strings(p) < this_len)
+ break;
+ if (debug)
+ printf("%s: skipping fdt magic at offset %#zx\n",
+ file, p - buf);
+ }
+ ++p;
+ }
+ if (!p)
+ die("%s: could not locate fdt magic\n", file);
+ printf("%s: found fdt at offset %#zx\n", file, p - buf);
+ buf = p;
+ }
+
+ dump_blob(buf, debug);
+
+ return 0;
+}
diff --git a/src/dtc/fdtget.c b/src/dtc/fdtget.c
new file mode 100644
index 0000000..4377419
--- /dev/null
+++ b/src/dtc/fdtget.c
@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ *
+ * Portions from U-Boot cmd_fdt.c (C) Copyright 2007
+ * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
+ * 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>
+#include <ctype.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libfdt.h>
+
+#include "util.h"
+
+enum display_mode {
+ MODE_SHOW_VALUE, /* show values for node properties */
+ MODE_LIST_PROPS, /* list the properties for a node */
+ MODE_LIST_SUBNODES, /* list the subnodes of a node */
+};
+
+/* Holds information which controls our output and options */
+struct display_info {
+ int type; /* data type (s/i/u/x or 0 for default) */
+ int size; /* data size (1/2/4) */
+ enum display_mode mode; /* display mode that we are using */
+ const char *default_val; /* default value if node/property not found */
+};
+
+static void report_error(const char *where, int err)
+{
+ fprintf(stderr, "Error at '%s': %s\n", where, fdt_strerror(err));
+}
+
+/**
+ * Displays data of a given length according to selected options
+ *
+ * If a specific data type is provided in disp, then this is used. Otherwise
+ * we try to guess the data type / size from the contents.
+ *
+ * @param disp Display information / options
+ * @param data Data to display
+ * @param len Maximum length of buffer
+ * @return 0 if ok, -1 if data does not match format
+ */
+static int show_data(struct display_info *disp, const char *data, int len)
+{
+ int i, size;
+ const uint8_t *p = (const uint8_t *)data;
+ const char *s;
+ int value;
+ int is_string;
+ char fmt[3];
+
+ /* no data, don't print */
+ if (len == 0)
+ return 0;
+
+ is_string = (disp->type) == 's' ||
+ (!disp->type && util_is_printable_string(data, len));
+ if (is_string) {
+ if (data[len - 1] != '\0') {
+ fprintf(stderr, "Unterminated string\n");
+ return -1;
+ }
+ for (s = data; s - data < len; s += strlen(s) + 1) {
+ if (s != data)
+ printf(" ");
+ printf("%s", (const char *)s);
+ }
+ return 0;
+ }
+ size = disp->size;
+ if (size == -1) {
+ size = (len % 4) == 0 ? 4 : 1;
+ } else if (len % size) {
+ fprintf(stderr, "Property length must be a multiple of "
+ "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 uint32_t *)p) :
+ size == 2 ? (*p << 8) | p[1] : *p;
+ printf(fmt, value);
+ }
+ return 0;
+}
+
+/**
+ * List all properties in a node, one per line.
+ *
+ * @param blob FDT blob
+ * @param node Node to display
+ * @return 0 if ok, or FDT_ERR... if not.
+ */
+static int list_properties(const void *blob, int node)
+{
+ const struct fdt_property *data;
+ const char *name;
+ int prop;
+
+ prop = fdt_first_property_offset(blob, node);
+ do {
+ /* 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));
+ if (name)
+ puts(name);
+ prop = fdt_next_property_offset(blob, prop);
+ } while (1);
+}
+
+#define MAX_LEVEL 32 /* how deeply nested we will go */
+
+/**
+ * List all subnodes in a node, one per line
+ *
+ * @param blob FDT blob
+ * @param node Node to display
+ * @return 0 if ok, or FDT_ERR... if not.
+ */
+static int list_subnodes(const void *blob, int node)
+{
+ int nextoffset; /* next node offset from libfdt */
+ uint32_t tag; /* current tag */
+ int level = 0; /* keep track of nesting level */
+ const char *pathp;
+ int depth = 1; /* the assumed depth of this node */
+
+ while (level >= 0) {
+ tag = fdt_next_tag(blob, node, &nextoffset);
+ switch (tag) {
+ case FDT_BEGIN_NODE:
+ pathp = fdt_get_name(blob, node, NULL);
+ if (level <= depth) {
+ if (pathp == NULL)
+ pathp = "/* NULL pointer error */";
+ if (*pathp == '\0')
+ pathp = "/"; /* root is nameless */
+ if (level == 1)
+ puts(pathp);
+ }
+ level++;
+ if (level >= MAX_LEVEL) {
+ printf("Nested too deep, aborting.\n");
+ return 1;
+ }
+ break;
+ case FDT_END_NODE:
+ level--;
+ if (level == 0)
+ level = -1; /* exit the loop */
+ break;
+ case FDT_END:
+ return 1;
+ case FDT_PROP:
+ break;
+ default:
+ if (level <= depth)
+ printf("Unknown tag 0x%08X\n", tag);
+ return 1;
+ }
+ node = nextoffset;
+ }
+ return 0;
+}
+
+/**
+ * Show the data for a given node (and perhaps property) according to the
+ * display option provided.
+ *
+ * @param blob FDT blob
+ * @param disp Display information / options
+ * @param node Node to display
+ * @param property Name of property to display, or NULL if none
+ * @return 0 if ok, -ve on error
+ */
+static int show_data_for_item(const void *blob, struct display_info *disp,
+ int node, const char *property)
+{
+ const void *value = NULL;
+ int len, err = 0;
+
+ switch (disp->mode) {
+ case MODE_LIST_PROPS:
+ err = list_properties(blob, node);
+ break;
+
+ case MODE_LIST_SUBNODES:
+ err = list_subnodes(blob, node);
+ break;
+
+ default:
+ assert(property);
+ value = fdt_getprop(blob, node, property, &len);
+ if (value) {
+ if (show_data(disp, value, len))
+ err = -1;
+ else
+ printf("\n");
+ } else if (disp->default_val) {
+ puts(disp->default_val);
+ } else {
+ report_error(property, len);
+ err = -1;
+ }
+ break;
+ }
+
+ return err;
+}
+
+/**
+ * Run the main fdtget operation, given a filename and valid arguments
+ *
+ * @param disp Display information / options
+ * @param filename Filename of blob file
+ * @param arg List of arguments to process
+ * @param arg_count Number of arguments
+ * @param return 0 if ok, -ve on error
+ */
+static int do_fdtget(struct display_info *disp, const char *filename,
+ char **arg, int arg_count, int args_per_step)
+{
+ char *blob;
+ const char *prop;
+ int i, node;
+
+ blob = utilfdt_read(filename);
+ if (!blob)
+ return -1;
+
+ for (i = 0; i + args_per_step <= arg_count; i += args_per_step) {
+ node = fdt_path_offset(blob, arg[i]);
+ if (node < 0) {
+ if (disp->default_val) {
+ puts(disp->default_val);
+ continue;
+ } else {
+ report_error(arg[i], node);
+ return -1;
+ }
+ }
+ prop = args_per_step == 1 ? NULL : arg[i + 1];
+
+ if (show_data_for_item(blob, disp, node, prop))
+ return -1;
+ }
+ return 0;
+}
+
+/* Usage related data. */
+static const char usage_synopsis[] =
+ "read values from device tree\n"
+ " fdtget <options> <dt file> [<node> <property>]...\n"
+ " fdtget -p <options> <dt file> [<node> ]...\n"
+ "\n"
+ "Each value is printed on a new line.\n"
+ USAGE_TYPE_MSG;
+static const char usage_short_opts[] = "t:pld:" USAGE_COMMON_SHORT_OPTS;
+static struct option const usage_long_opts[] = {
+ {"type", a_argument, NULL, 't'},
+ {"properties", no_argument, NULL, 'p'},
+ {"list", no_argument, NULL, 'l'},
+ {"default", a_argument, NULL, 'd'},
+ USAGE_COMMON_LONG_OPTS,
+};
+static const char * const usage_opts_help[] = {
+ "Type of data",
+ "List properties for each node",
+ "List subnodes for each node",
+ "Default value to display when the property is missing",
+ USAGE_COMMON_OPTS_HELP
+};
+
+int main(int argc, char *argv[])
+{
+ int opt;
+ char *filename = NULL;
+ struct display_info disp;
+ int args_per_step = 2;
+
+ /* set defaults */
+ memset(&disp, '\0', sizeof(disp));
+ disp.size = -1;
+ disp.mode = MODE_SHOW_VALUE;
+ while ((opt = util_getopt_long()) != EOF) {
+ switch (opt) {
+ case_USAGE_COMMON_FLAGS
+
+ case 't':
+ if (utilfdt_decode_type(optarg, &disp.type,
+ &disp.size))
+ usage("invalid type string");
+ break;
+
+ case 'p':
+ disp.mode = MODE_LIST_PROPS;
+ args_per_step = 1;
+ break;
+
+ case 'l':
+ disp.mode = MODE_LIST_SUBNODES;
+ args_per_step = 1;
+ break;
+
+ case 'd':
+ disp.default_val = optarg;
+ break;
+ }
+ }
+
+ if (optind < argc)
+ filename = argv[optind++];
+ if (!filename)
+ usage("missing filename");
+
+ argv += optind;
+ argc -= optind;
+
+ /* Allow no arguments, and silently succeed */
+ if (!argc)
+ return 0;
+
+ /* Check for node, property arguments */
+ if (args_per_step == 2 && (argc % 2))
+ usage("must have an even number of arguments");
+
+ if (do_fdtget(&disp, filename, argv, argc, args_per_step))
+ return 1;
+ return 0;
+}
diff --git a/src/dtc/fdtput.c b/src/dtc/fdtput.c
new file mode 100644
index 0000000..5226a4e
--- /dev/null
+++ b/src/dtc/fdtput.c
@@ -0,0 +1,401 @@
+/*
+ * 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>
+#include <ctype.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libfdt.h>
+
+#include "util.h"
+
+/* These are the operations we support */
+enum oper_type {
+ OPER_WRITE_PROP, /* Write a property in a node */
+ OPER_CREATE_NODE, /* Create a new node */
+};
+
+struct display_info {
+ enum oper_type oper; /* operation to perform */
+ int type; /* data type (s/i/u/x or 0 for default) */
+ int size; /* data size (1/2/4) */
+ int verbose; /* verbose output */
+ int auto_path; /* automatically create all path components */
+};
+
+
+/**
+ * Report an error with a particular node.
+ *
+ * @param name Node name to report error on
+ * @param namelen Length of node name, or -1 to use entire string
+ * @param err Error number to report (-FDT_ERR_...)
+ */
+static void report_error(const char *name, int namelen, int err)
+{
+ if (namelen == -1)
+ namelen = strlen(name);
+ fprintf(stderr, "Error at '%1.*s': %s\n", namelen, name,
+ fdt_strerror(err));
+}
+
+/**
+ * Encode a series of arguments in a property value.
+ *
+ * @param disp Display information / options
+ * @param arg List of arguments from command line
+ * @param arg_count Number of arguments (may be 0)
+ * @param valuep Returns buffer containing value
+ * @param *value_len Returns length of value encoded
+ */
+static int encode_value(struct display_info *disp, char **arg, int arg_count,
+ char **valuep, int *value_len)
+{
+ char *value = NULL; /* holding area for value */
+ int value_size = 0; /* size of holding area */
+ char *ptr; /* pointer to current value position */
+ int len; /* length of this cell/string/byte */
+ int ival;
+ int upto; /* the number of bytes we have written to buf */
+ char fmt[3];
+
+ upto = 0;
+
+ if (disp->verbose)
+ fprintf(stderr, "Decoding value:\n");
+
+ fmt[0] = '%';
+ fmt[1] = disp->type ? disp->type : 'd';
+ fmt[2] = '\0';
+ for (; arg_count > 0; arg++, arg_count--, upto += len) {
+ /* assume integer unless told otherwise */
+ if (disp->type == 's')
+ len = strlen(*arg) + 1;
+ else
+ len = disp->size == -1 ? 4 : disp->size;
+
+ /* enlarge our value buffer by a suitable margin if needed */
+ if (upto + len > value_size) {
+ value_size = (upto + len) + 500;
+ value = realloc(value, value_size);
+ if (!value) {
+ fprintf(stderr, "Out of mmory: cannot alloc "
+ "%d bytes\n", value_size);
+ return -1;
+ }
+ }
+
+ ptr = value + upto;
+ if (disp->type == 's') {
+ memcpy(ptr, *arg, len);
+ if (disp->verbose)
+ fprintf(stderr, "\tstring: '%s'\n", ptr);
+ } else {
+ int *iptr = (int *)ptr;
+ sscanf(*arg, fmt, &ival);
+ if (len == 4)
+ *iptr = cpu_to_fdt32(ival);
+ else
+ *ptr = (uint8_t)ival;
+ if (disp->verbose) {
+ fprintf(stderr, "\t%s: %d\n",
+ disp->size == 1 ? "byte" :
+ disp->size == 2 ? "short" : "int",
+ ival);
+ }
+ }
+ }
+ *value_len = upto;
+ *valuep = value;
+ if (disp->verbose)
+ fprintf(stderr, "Value size %d\n", upto);
+ return 0;
+}
+
+#define ALIGN(x) (((x) + (FDT_TAGSIZE) - 1) & ~((FDT_TAGSIZE) - 1))
+
+static char *_realloc_fdt(char *fdt, int delta)
+{
+ int new_sz = fdt_totalsize(fdt) + delta;
+ fdt = xrealloc(fdt, new_sz);
+ fdt_open_into(fdt, fdt, new_sz);
+ return fdt;
+}
+
+static char *realloc_node(char *fdt, const char *name)
+{
+ int delta;
+ /* 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);
+}
+
+static char *realloc_property(char *fdt, int nodeoffset,
+ const char *name, int newlen)
+{
+ int delta = 0;
+ int oldlen = 0;
+
+ if (!fdt_get_property(fdt, nodeoffset, name, &oldlen))
+ /* strings + property header */
+ delta = sizeof(struct fdt_property) + strlen(name) + 1;
+
+ if (newlen > oldlen)
+ /* actual value in off_struct */
+ delta += ALIGN(newlen) - ALIGN(oldlen);
+
+ return _realloc_fdt(fdt, delta);
+}
+
+static int store_key_value(char **blob, const char *node_name,
+ const char *property, const char *buf, int len)
+{
+ int node;
+ int err;
+
+ node = fdt_path_offset(*blob, node_name);
+ if (node < 0) {
+ report_error(node_name, -1, node);
+ return -1;
+ }
+
+ err = fdt_setprop(*blob, node, property, buf, len);
+ if (err == -FDT_ERR_NOSPACE) {
+ *blob = realloc_property(*blob, node, property, len);
+ err = fdt_setprop(*blob, node, property, buf, len);
+ }
+ if (err) {
+ report_error(property, -1, err);
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * Create paths as needed for all components of a path
+ *
+ * Any components of the path that do not exist are created. Errors are
+ * reported.
+ *
+ * @param blob FDT blob to write into
+ * @param in_path Path to process
+ * @return 0 if ok, -1 on error
+ */
+static int create_paths(char **blob, const char *in_path)
+{
+ const char *path = in_path;
+ const char *sep;
+ int node, offset = 0;
+
+ /* skip leading '/' */
+ while (*path == '/')
+ path++;
+
+ for (sep = path; *sep; path = sep + 1, offset = node) {
+ /* equivalent to strchrnul(), but it requires _GNU_SOURCE */
+ sep = strchr(path, '/');
+ if (!sep)
+ sep = path + strlen(path);
+
+ node = fdt_subnode_offset_namelen(*blob, offset, path,
+ sep - path);
+ if (node == -FDT_ERR_NOTFOUND) {
+ *blob = realloc_node(*blob, path);
+ node = fdt_add_subnode_namelen(*blob, offset, path,
+ sep - path);
+ }
+ if (node < 0) {
+ report_error(path, sep - path, node);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Create a new node in the fdt.
+ *
+ * This will overwrite the node_name string. Any error is reported.
+ *
+ * TODO: Perhaps create fdt_path_offset_namelen() so we don't need to do this.
+ *
+ * @param blob FDT blob to write into
+ * @param node_name Name of node to create
+ * @return new node offset if found, or -1 on failure
+ */
+static int create_node(char **blob, const char *node_name)
+{
+ int node = 0;
+ char *p;
+
+ p = strrchr(node_name, '/');
+ if (!p) {
+ report_error(node_name, -1, -FDT_ERR_BADPATH);
+ return -1;
+ }
+ *p = '\0';
+
+ *blob = realloc_node(*blob, p + 1);
+
+ if (p > node_name) {
+ node = fdt_path_offset(*blob, node_name);
+ if (node < 0) {
+ report_error(node_name, -1, node);
+ return -1;
+ }
+ }
+
+ node = fdt_add_subnode(*blob, node, p + 1);
+ if (node < 0) {
+ report_error(p + 1, -1, node);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int do_fdtput(struct display_info *disp, const char *filename,
+ char **arg, int arg_count)
+{
+ char *value;
+ char *blob;
+ int len, ret = 0;
+
+ blob = utilfdt_read(filename);
+ if (!blob)
+ return -1;
+
+ switch (disp->oper) {
+ case OPER_WRITE_PROP:
+ /*
+ * Convert the arguments into a single binary value, then
+ * store them into the property.
+ */
+ assert(arg_count >= 2);
+ if (disp->auto_path && create_paths(&blob, *arg))
+ return -1;
+ if (encode_value(disp, arg + 2, arg_count - 2, &value, &len) ||
+ store_key_value(&blob, *arg, arg[1], value, len))
+ ret = -1;
+ break;
+ case OPER_CREATE_NODE:
+ for (; ret >= 0 && arg_count--; arg++) {
+ if (disp->auto_path)
+ ret = create_paths(&blob, *arg);
+ else
+ ret = create_node(&blob, *arg);
+ }
+ break;
+ }
+ if (ret >= 0) {
+ fdt_pack(blob);
+ ret = utilfdt_write(filename, blob);
+ }
+
+ free(blob);
+ return ret;
+}
+
+/* Usage related data. */
+static const char usage_synopsis[] =
+ "write a property value to a device tree\n"
+ " fdtput <options> <dt file> <node> <property> [<value>...]\n"
+ " fdtput -c <options> <dt file> [<node>...]\n"
+ "\n"
+ "The command line arguments are joined together into a single value.\n"
+ USAGE_TYPE_MSG;
+static const char usage_short_opts[] = "cpt:v" USAGE_COMMON_SHORT_OPTS;
+static struct option const usage_long_opts[] = {
+ {"create", no_argument, NULL, 'c'},
+ {"auto-path", no_argument, NULL, 'p'},
+ {"type", a_argument, NULL, 't'},
+ {"verbose", no_argument, NULL, 'v'},
+ USAGE_COMMON_LONG_OPTS,
+};
+static const char * const usage_opts_help[] = {
+ "Create nodes if they don't already exist",
+ "Automatically create nodes as needed for the node path",
+ "Type of data",
+ "Display each value decoded from command line",
+ USAGE_COMMON_OPTS_HELP
+};
+
+int main(int argc, char *argv[])
+{
+ int opt;
+ struct display_info disp;
+ char *filename = NULL;
+
+ memset(&disp, '\0', sizeof(disp));
+ disp.size = -1;
+ disp.oper = OPER_WRITE_PROP;
+ while ((opt = util_getopt_long()) != EOF) {
+ /*
+ * TODO: add options to:
+ * - delete property
+ * - delete node (optionally recursively)
+ * - rename node
+ * - pack fdt before writing
+ * - set amount of free space when writing
+ */
+ switch (opt) {
+ case_USAGE_COMMON_FLAGS
+
+ case 'c':
+ disp.oper = OPER_CREATE_NODE;
+ break;
+ case 'p':
+ disp.auto_path = 1;
+ break;
+ case 't':
+ if (utilfdt_decode_type(optarg, &disp.type,
+ &disp.size))
+ usage("Invalid type string");
+ break;
+
+ case 'v':
+ disp.verbose = 1;
+ break;
+ }
+ }
+
+ if (optind < argc)
+ filename = argv[optind++];
+ if (!filename)
+ usage("missing filename");
+
+ argv += optind;
+ argc -= optind;
+
+ if (disp.oper == OPER_WRITE_PROP) {
+ if (argc < 1)
+ usage("missing node");
+ if (argc < 2)
+ usage("missing property");
+ }
+
+ if (do_fdtput(&disp, filename, argv, argc))
+ return 1;
+ return 0;
+}
diff --git a/src/dtc/flattree.c b/src/dtc/flattree.c
new file mode 100644
index 0000000..665dad7
--- /dev/null
+++ b/src/dtc/flattree.c
@@ -0,0 +1,933 @@
+/*
+ * (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"
+
+#define FTF_FULLPATH 0x1
+#define FTF_VARALIGN 0x2
+#define FTF_NAMEPROPS 0x4
+#define FTF_BOOTCPUID 0x8
+#define FTF_STRTABSIZE 0x10
+#define FTF_STRUCTSIZE 0x20
+#define FTF_NOPS 0x40
+
+static struct version_info {
+ int version;
+ int last_comp_version;
+ int hdr_size;
+ int flags;
+} version_table[] = {
+ {1, 1, FDT_V1_SIZE,
+ FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS},
+ {2, 1, FDT_V2_SIZE,
+ FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS|FTF_BOOTCPUID},
+ {3, 1, FDT_V3_SIZE,
+ FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS|FTF_BOOTCPUID|FTF_STRTABSIZE},
+ {16, 16, FDT_V3_SIZE,
+ FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_NOPS},
+ {17, 16, FDT_V17_SIZE,
+ FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS},
+};
+
+struct emitter {
+ void (*cell)(void *, cell_t);
+ void (*string)(void *, char *, int);
+ void (*align)(void *, int);
+ void (*data)(void *, struct data);
+ void (*beginnode)(void *, struct label *labels);
+ void (*endnode)(void *, struct label *labels);
+ void (*property)(void *, struct label *labels);
+};
+
+static void bin_emit_cell(void *e, cell_t val)
+{
+ struct data *dtbuf = e;
+
+ *dtbuf = data_append_cell(*dtbuf, val);
+}
+
+static void bin_emit_string(void *e, char *str, int len)
+{
+ struct data *dtbuf = e;
+
+ if (len == 0)
+ len = strlen(str);
+
+ *dtbuf = data_append_data(*dtbuf, str, len);
+ *dtbuf = data_append_byte(*dtbuf, '\0');
+}
+
+static void bin_emit_align(void *e, int a)
+{
+ struct data *dtbuf = e;
+
+ *dtbuf = data_append_align(*dtbuf, a);
+}
+
+static void bin_emit_data(void *e, struct data d)
+{
+ struct data *dtbuf = e;
+
+ *dtbuf = data_append_data(*dtbuf, d.val, d.len);
+}
+
+static void bin_emit_beginnode(void *e, struct label *labels)
+{
+ bin_emit_cell(e, FDT_BEGIN_NODE);
+}
+
+static void bin_emit_endnode(void *e, struct label *labels)
+{
+ bin_emit_cell(e, FDT_END_NODE);
+}
+
+static void bin_emit_property(void *e, struct label *labels)
+{
+ bin_emit_cell(e, FDT_PROP);
+}
+
+static struct emitter bin_emitter = {
+ .cell = bin_emit_cell,
+ .string = bin_emit_string,
+ .align = bin_emit_align,
+ .data = bin_emit_data,
+ .beginnode = bin_emit_beginnode,
+ .endnode = bin_emit_endnode,
+ .property = bin_emit_property,
+};
+
+static void emit_label(FILE *f, const char *prefix, const char *label)
+{
+ fprintf(f, "\t.globl\t%s_%s\n", prefix, label);
+ fprintf(f, "%s_%s:\n", prefix, label);
+ fprintf(f, "_%s_%s:\n", prefix, label);
+}
+
+static void emit_offset_label(FILE *f, const char *label, int offset)
+{
+ fprintf(f, "\t.globl\t%s\n", label);
+ fprintf(f, "%s\t= . + %d\n", label, offset);
+}
+
+#define ASM_EMIT_BELONG(f, fmt, ...) \
+ { \
+ fprintf((f), "\t.byte\t((" fmt ") >> 24) & 0xff\n", __VA_ARGS__); \
+ fprintf((f), "\t.byte\t((" fmt ") >> 16) & 0xff\n", __VA_ARGS__); \
+ fprintf((f), "\t.byte\t((" fmt ") >> 8) & 0xff\n", __VA_ARGS__); \
+ fprintf((f), "\t.byte\t(" fmt ") & 0xff\n", __VA_ARGS__); \
+ }
+
+static void asm_emit_cell(void *e, cell_t val)
+{
+ FILE *f = e;
+
+ fprintf(f, "\t.byte 0x%02x; .byte 0x%02x; .byte 0x%02x; .byte 0x%02x\n",
+ (val >> 24) & 0xff, (val >> 16) & 0xff,
+ (val >> 8) & 0xff, val & 0xff);
+}
+
+static void asm_emit_string(void *e, char *str, int len)
+{
+ FILE *f = e;
+ char c = 0;
+
+ if (len != 0) {
+ /* XXX: ewww */
+ c = str[len];
+ str[len] = '\0';
+ }
+
+ fprintf(f, "\t.string\t\"%s\"\n", str);
+
+ if (len != 0) {
+ str[len] = c;
+ }
+}
+
+static void asm_emit_align(void *e, int a)
+{
+ FILE *f = e;
+
+ fprintf(f, "\t.balign\t%d, 0\n", a);
+}
+
+static void asm_emit_data(void *e, struct data d)
+{
+ FILE *f = e;
+ int off = 0;
+ struct marker *m = d.markers;
+
+ for_each_marker_of_type(m, LABEL)
+ emit_offset_label(f, m->ref, m->offset);
+
+ while ((d.len - off) >= sizeof(uint32_t)) {
+ asm_emit_cell(e, fdt32_to_cpu(*((uint32_t *)(d.val+off))));
+ off += sizeof(uint32_t);
+ }
+
+ while ((d.len - off) >= 1) {
+ fprintf(f, "\t.byte\t0x%hhx\n", d.val[off]);
+ off += 1;
+ }
+
+ assert(off == d.len);
+}
+
+static void asm_emit_beginnode(void *e, struct label *labels)
+{
+ FILE *f = e;
+ struct label *l;
+
+ for_each_label(labels, l) {
+ fprintf(f, "\t.globl\t%s\n", l->label);
+ fprintf(f, "%s:\n", l->label);
+ }
+ fprintf(f, "\t/* FDT_BEGIN_NODE */\n");
+ asm_emit_cell(e, FDT_BEGIN_NODE);
+}
+
+static void asm_emit_endnode(void *e, struct label *labels)
+{
+ FILE *f = e;
+ struct label *l;
+
+ fprintf(f, "\t/* FDT_END_NODE */\n");
+ asm_emit_cell(e, FDT_END_NODE);
+ for_each_label(labels, l) {
+ fprintf(f, "\t.globl\t%s_end\n", l->label);
+ fprintf(f, "%s_end:\n", l->label);
+ }
+}
+
+static void asm_emit_property(void *e, struct label *labels)
+{
+ FILE *f = e;
+ struct label *l;
+
+ for_each_label(labels, l) {
+ fprintf(f, "\t.globl\t%s\n", l->label);
+ fprintf(f, "%s:\n", l->label);
+ }
+ fprintf(f, "\t/* FDT_PROP */\n");
+ asm_emit_cell(e, FDT_PROP);
+}
+
+static struct emitter asm_emitter = {
+ .cell = asm_emit_cell,
+ .string = asm_emit_string,
+ .align = asm_emit_align,
+ .data = asm_emit_data,
+ .beginnode = asm_emit_beginnode,
+ .endnode = asm_emit_endnode,
+ .property = asm_emit_property,
+};
+
+static int stringtable_insert(struct data *d, const char *str)
+{
+ int i;
+
+ /* FIXME: do this more efficiently? */
+
+ for (i = 0; i < d->len; i++) {
+ if (streq(str, d->val + i))
+ return i;
+ }
+
+ *d = data_append_data(*d, str, strlen(str)+1);
+ return i;
+}
+
+static void flatten_tree(struct node *tree, struct emitter *emit,
+ void *etarget, struct data *strbuf,
+ struct version_info *vi)
+{
+ struct property *prop;
+ struct node *child;
+ int seen_name_prop = 0;
+
+ if (tree->deleted)
+ return;
+
+ emit->beginnode(etarget, tree->labels);
+
+ if (vi->flags & FTF_FULLPATH)
+ emit->string(etarget, tree->fullpath, 0);
+ else
+ emit->string(etarget, tree->name, 0);
+
+ emit->align(etarget, sizeof(cell_t));
+
+ for_each_property(tree, prop) {
+ int nameoff;
+
+ if (streq(prop->name, "name"))
+ seen_name_prop = 1;
+
+ nameoff = stringtable_insert(strbuf, prop->name);
+
+ emit->property(etarget, prop->labels);
+ emit->cell(etarget, prop->val.len);
+ emit->cell(etarget, nameoff);
+
+ if ((vi->flags & FTF_VARALIGN) && (prop->val.len >= 8))
+ emit->align(etarget, 8);
+
+ emit->data(etarget, prop->val);
+ emit->align(etarget, sizeof(cell_t));
+ }
+
+ if ((vi->flags & FTF_NAMEPROPS) && !seen_name_prop) {
+ emit->property(etarget, NULL);
+ emit->cell(etarget, tree->basenamelen+1);
+ emit->cell(etarget, stringtable_insert(strbuf, "name"));
+
+ if ((vi->flags & FTF_VARALIGN) && ((tree->basenamelen+1) >= 8))
+ emit->align(etarget, 8);
+
+ emit->string(etarget, tree->name, tree->basenamelen);
+ emit->align(etarget, sizeof(cell_t));
+ }
+
+ for_each_child(tree, child) {
+ flatten_tree(child, emit, etarget, strbuf, vi);
+ }
+
+ emit->endnode(etarget, tree->labels);
+}
+
+static struct data flatten_reserve_list(struct reserve_info *reservelist,
+ struct version_info *vi)
+{
+ struct reserve_info *re;
+ struct data d = empty_data;
+ static struct fdt_reserve_entry null_re = {0,0};
+ int j;
+
+ for (re = reservelist; re; re = re->next) {
+ d = data_append_re(d, &re->re);
+ }
+ /*
+ * Add additional reserved slots if the user asked for them.
+ */
+ for (j = 0; j < reservenum; j++) {
+ d = data_append_re(d, &null_re);
+ }
+
+ return d;
+}
+
+static void make_fdt_header(struct fdt_header *fdt,
+ struct version_info *vi,
+ int reservesize, int dtsize, int strsize,
+ int boot_cpuid_phys)
+{
+ int reserve_off;
+
+ reservesize += sizeof(struct fdt_reserve_entry);
+
+ memset(fdt, 0xff, sizeof(*fdt));
+
+ fdt->magic = cpu_to_fdt32(FDT_MAGIC);
+ fdt->version = cpu_to_fdt32(vi->version);
+ fdt->last_comp_version = cpu_to_fdt32(vi->last_comp_version);
+
+ /* Reserve map should be doubleword aligned */
+ reserve_off = ALIGN(vi->hdr_size, 8);
+
+ fdt->off_mem_rsvmap = cpu_to_fdt32(reserve_off);
+ fdt->off_dt_struct = cpu_to_fdt32(reserve_off + reservesize);
+ fdt->off_dt_strings = cpu_to_fdt32(reserve_off + reservesize
+ + dtsize);
+ fdt->totalsize = cpu_to_fdt32(reserve_off + reservesize + dtsize + strsize);
+
+ if (vi->flags & FTF_BOOTCPUID)
+ fdt->boot_cpuid_phys = cpu_to_fdt32(boot_cpuid_phys);
+ if (vi->flags & FTF_STRTABSIZE)
+ fdt->size_dt_strings = cpu_to_fdt32(strsize);
+ if (vi->flags & FTF_STRUCTSIZE)
+ fdt->size_dt_struct = cpu_to_fdt32(dtsize);
+}
+
+void dt_to_blob(FILE *f, struct boot_info *bi, int version)
+{
+ struct version_info *vi = NULL;
+ int i;
+ struct data blob = empty_data;
+ struct data reservebuf = empty_data;
+ struct data dtbuf = empty_data;
+ struct data strbuf = empty_data;
+ struct fdt_header fdt;
+ int padlen = 0;
+
+ for (i = 0; i < ARRAY_SIZE(version_table); i++) {
+ if (version_table[i].version == version)
+ vi = &version_table[i];
+ }
+ if (!vi)
+ die("Unknown device tree blob version %d\n", version);
+
+ flatten_tree(bi->dt, &bin_emitter, &dtbuf, &strbuf, vi);
+ bin_emit_cell(&dtbuf, FDT_END);
+
+ reservebuf = flatten_reserve_list(bi->reservelist, vi);
+
+ /* Make header */
+ make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
+ bi->boot_cpuid_phys);
+
+ /*
+ * If the user asked for more space than is used, adjust the totalsize.
+ */
+ if (minsize > 0) {
+ padlen = minsize - fdt32_to_cpu(fdt.totalsize);
+ if ((padlen < 0) && (quiet < 1))
+ fprintf(stderr,
+ "Warning: blob size %d >= minimum size %d\n",
+ fdt32_to_cpu(fdt.totalsize), minsize);
+ }
+
+ if (padsize > 0)
+ padlen = padsize;
+
+ if (padlen > 0) {
+ int tsize = fdt32_to_cpu(fdt.totalsize);
+ tsize += padlen;
+ fdt.totalsize = cpu_to_fdt32(tsize);
+ }
+
+ /*
+ * Assemble the blob: start with the header, add with alignment
+ * the reserve buffer, add the reserve map terminating zeroes,
+ * the device tree itself, and finally the strings.
+ */
+ blob = data_append_data(blob, &fdt, vi->hdr_size);
+ blob = data_append_align(blob, 8);
+ blob = data_merge(blob, reservebuf);
+ blob = data_append_zeroes(blob, sizeof(struct fdt_reserve_entry));
+ blob = data_merge(blob, dtbuf);
+ blob = data_merge(blob, strbuf);
+
+ /*
+ * If the user asked for more space than is used, pad out the blob.
+ */
+ if (padlen > 0)
+ blob = data_append_zeroes(blob, padlen);
+
+ if (fwrite(blob.val, blob.len, 1, f) != 1) {
+ if (ferror(f))
+ die("Error writing device tree blob: %s\n",
+ strerror(errno));
+ else
+ die("Short write on device tree blob\n");
+ }
+
+ /*
+ * data_merge() frees the right-hand element so only the blob
+ * remains to be freed.
+ */
+ data_free(blob);
+}
+
+static void dump_stringtable_asm(FILE *f, struct data strbuf)
+{
+ const char *p;
+ int len;
+
+ p = strbuf.val;
+
+ while (p < (strbuf.val + strbuf.len)) {
+ len = strlen(p);
+ fprintf(f, "\t.string \"%s\"\n", p);
+ p += len+1;
+ }
+}
+
+void dt_to_asm(FILE *f, struct boot_info *bi, int version)
+{
+ struct version_info *vi = NULL;
+ int i;
+ struct data strbuf = empty_data;
+ struct reserve_info *re;
+ const char *symprefix = "dt";
+
+ for (i = 0; i < ARRAY_SIZE(version_table); i++) {
+ if (version_table[i].version == version)
+ vi = &version_table[i];
+ }
+ if (!vi)
+ die("Unknown device tree blob version %d\n", version);
+
+ fprintf(f, "/* autogenerated by dtc, do not edit */\n\n");
+
+ emit_label(f, symprefix, "blob_start");
+ emit_label(f, symprefix, "header");
+ fprintf(f, "\t/* magic */\n");
+ asm_emit_cell(f, FDT_MAGIC);
+ fprintf(f, "\t/* totalsize */\n");
+ ASM_EMIT_BELONG(f, "_%s_blob_abs_end - _%s_blob_start",
+ symprefix, symprefix);
+ fprintf(f, "\t/* off_dt_struct */\n");
+ ASM_EMIT_BELONG(f, "_%s_struct_start - _%s_blob_start",
+ symprefix, symprefix);
+ fprintf(f, "\t/* off_dt_strings */\n");
+ ASM_EMIT_BELONG(f, "_%s_strings_start - _%s_blob_start",
+ symprefix, symprefix);
+ fprintf(f, "\t/* off_mem_rsvmap */\n");
+ ASM_EMIT_BELONG(f, "_%s_reserve_map - _%s_blob_start",
+ symprefix, symprefix);
+ fprintf(f, "\t/* version */\n");
+ asm_emit_cell(f, vi->version);
+ fprintf(f, "\t/* last_comp_version */\n");
+ asm_emit_cell(f, vi->last_comp_version);
+
+ if (vi->flags & FTF_BOOTCPUID) {
+ fprintf(f, "\t/* boot_cpuid_phys */\n");
+ asm_emit_cell(f, bi->boot_cpuid_phys);
+ }
+
+ if (vi->flags & FTF_STRTABSIZE) {
+ fprintf(f, "\t/* size_dt_strings */\n");
+ ASM_EMIT_BELONG(f, "_%s_strings_end - _%s_strings_start",
+ symprefix, symprefix);
+ }
+
+ if (vi->flags & FTF_STRUCTSIZE) {
+ fprintf(f, "\t/* size_dt_struct */\n");
+ ASM_EMIT_BELONG(f, "_%s_struct_end - _%s_struct_start",
+ symprefix, symprefix);
+ }
+
+ /*
+ * Reserve map entries.
+ * Align the reserve map to a doubleword boundary.
+ * Each entry is an (address, size) pair of u64 values.
+ * Always supply a zero-sized temination entry.
+ */
+ asm_emit_align(f, 8);
+ emit_label(f, symprefix, "reserve_map");
+
+ fprintf(f, "/* Memory reserve map from source file */\n");
+
+ /*
+ * Use .long on high and low halfs of u64s to avoid .quad
+ * as it appears .quad isn't available in some assemblers.
+ */
+ for (re = bi->reservelist; re; re = re->next) {
+ struct label *l;
+
+ for_each_label(re->labels, l) {
+ fprintf(f, "\t.globl\t%s\n", l->label);
+ fprintf(f, "%s:\n", l->label);
+ }
+ ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.address >> 32));
+ ASM_EMIT_BELONG(f, "0x%08x",
+ (unsigned int)(re->re.address & 0xffffffff));
+ ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.size >> 32));
+ ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.size & 0xffffffff));
+ }
+ for (i = 0; i < reservenum; i++) {
+ fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
+ }
+
+ fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
+
+ emit_label(f, symprefix, "struct_start");
+ flatten_tree(bi->dt, &asm_emitter, f, &strbuf, vi);
+
+ fprintf(f, "\t/* FDT_END */\n");
+ asm_emit_cell(f, FDT_END);
+ emit_label(f, symprefix, "struct_end");
+
+ emit_label(f, symprefix, "strings_start");
+ dump_stringtable_asm(f, strbuf);
+ emit_label(f, symprefix, "strings_end");
+
+ emit_label(f, symprefix, "blob_end");
+
+ /*
+ * If the user asked for more space than is used, pad it out.
+ */
+ if (minsize > 0) {
+ fprintf(f, "\t.space\t%d - (_%s_blob_end - _%s_blob_start), 0\n",
+ minsize, symprefix, symprefix);
+ }
+ if (padsize > 0) {
+ fprintf(f, "\t.space\t%d, 0\n", padsize);
+ }
+ emit_label(f, symprefix, "blob_abs_end");
+
+ data_free(strbuf);
+}
+
+struct inbuf {
+ char *base, *limit, *ptr;
+};
+
+static void inbuf_init(struct inbuf *inb, void *base, void *limit)
+{
+ inb->base = base;
+ inb->limit = limit;
+ inb->ptr = inb->base;
+}
+
+static void flat_read_chunk(struct inbuf *inb, void *p, int len)
+{
+ if ((inb->ptr + len) > inb->limit)
+ die("Premature end of data parsing flat device tree\n");
+
+ memcpy(p, inb->ptr, len);
+
+ inb->ptr += len;
+}
+
+static uint32_t flat_read_word(struct inbuf *inb)
+{
+ uint32_t val;
+
+ assert(((inb->ptr - inb->base) % sizeof(val)) == 0);
+
+ flat_read_chunk(inb, &val, sizeof(val));
+
+ return fdt32_to_cpu(val);
+}
+
+static void flat_realign(struct inbuf *inb, int align)
+{
+ int off = inb->ptr - inb->base;
+
+ inb->ptr = inb->base + ALIGN(off, align);
+ if (inb->ptr > inb->limit)
+ die("Premature end of data parsing flat device tree\n");
+}
+
+static char *flat_read_string(struct inbuf *inb)
+{
+ int len = 0;
+ const char *p = inb->ptr;
+ char *str;
+
+ do {
+ if (p >= inb->limit)
+ die("Premature end of data parsing flat device tree\n");
+ len++;
+ } while ((*p++) != '\0');
+
+ str = xstrdup(inb->ptr);
+
+ inb->ptr += len;
+
+ flat_realign(inb, sizeof(uint32_t));
+
+ return str;
+}
+
+static struct data flat_read_data(struct inbuf *inb, int len)
+{
+ struct data d = empty_data;
+
+ if (len == 0)
+ return empty_data;
+
+ d = data_grow_for(d, len);
+ d.len = len;
+
+ flat_read_chunk(inb, d.val, len);
+
+ flat_realign(inb, sizeof(uint32_t));
+
+ return d;
+}
+
+static char *flat_read_stringtable(struct inbuf *inb, int offset)
+{
+ const char *p;
+
+ p = inb->base + offset;
+ while (1) {
+ if (p >= inb->limit || p < inb->base)
+ die("String offset %d overruns string table\n",
+ offset);
+
+ if (*p == '\0')
+ break;
+
+ p++;
+ }
+
+ return xstrdup(inb->base + offset);
+}
+
+static struct property *flat_read_property(struct inbuf *dtbuf,
+ struct inbuf *strbuf, int flags)
+{
+ uint32_t proplen, stroff;
+ char *name;
+ struct data val;
+
+ proplen = flat_read_word(dtbuf);
+ stroff = flat_read_word(dtbuf);
+
+ name = flat_read_stringtable(strbuf, stroff);
+
+ if ((flags & FTF_VARALIGN) && (proplen >= 8))
+ flat_realign(dtbuf, 8);
+
+ val = flat_read_data(dtbuf, proplen);
+
+ return build_property(name, val);
+}
+
+
+static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
+{
+ struct reserve_info *reservelist = NULL;
+ struct reserve_info *new;
+ struct fdt_reserve_entry re;
+
+ /*
+ * Each entry is a pair of u64 (addr, size) values for 4 cell_t's.
+ * List terminates at an entry with size equal to zero.
+ *
+ * First pass, count entries.
+ */
+ while (1) {
+ flat_read_chunk(inb, &re, sizeof(re));
+ re.address = fdt64_to_cpu(re.address);
+ re.size = fdt64_to_cpu(re.size);
+ if (re.size == 0)
+ break;
+
+ new = build_reserve_entry(re.address, re.size);
+ reservelist = add_reserve_entry(reservelist, new);
+ }
+
+ return reservelist;
+}
+
+
+static char *nodename_from_path(const char *ppath, const char *cpath)
+{
+ int plen;
+
+ plen = strlen(ppath);
+
+ if (!strneq(ppath, cpath, plen))
+ die("Path \"%s\" is not valid as a child of \"%s\"\n",
+ cpath, ppath);
+
+ /* root node is a special case */
+ if (!streq(ppath, "/"))
+ plen++;
+
+ return xstrdup(cpath + plen);
+}
+
+static struct node *unflatten_tree(struct inbuf *dtbuf,
+ struct inbuf *strbuf,
+ const char *parent_flatname, int flags)
+{
+ struct node *node;
+ char *flatname;
+ uint32_t val;
+
+ node = build_node(NULL, NULL);
+
+ flatname = flat_read_string(dtbuf);
+
+ if (flags & FTF_FULLPATH)
+ node->name = nodename_from_path(parent_flatname, flatname);
+ else
+ node->name = flatname;
+
+ do {
+ struct property *prop;
+ struct node *child;
+
+ val = flat_read_word(dtbuf);
+ switch (val) {
+ case FDT_PROP:
+ if (node->children)
+ fprintf(stderr, "Warning: Flat tree input has "
+ "subnodes preceding a property.\n");
+ prop = flat_read_property(dtbuf, strbuf, flags);
+ add_property(node, prop);
+ break;
+
+ case FDT_BEGIN_NODE:
+ child = unflatten_tree(dtbuf,strbuf, flatname, flags);
+ add_child(node, child);
+ break;
+
+ case FDT_END_NODE:
+ break;
+
+ case FDT_END:
+ die("Premature FDT_END in device tree blob\n");
+ break;
+
+ case FDT_NOP:
+ if (!(flags & FTF_NOPS))
+ fprintf(stderr, "Warning: NOP tag found in flat tree"
+ " version <16\n");
+
+ /* Ignore */
+ break;
+
+ default:
+ die("Invalid opcode word %08x in device tree blob\n",
+ val);
+ }
+ } while (val != FDT_END_NODE);
+
+ return node;
+}
+
+
+struct boot_info *dt_from_blob(const char *fname)
+{
+ FILE *f;
+ uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys;
+ uint32_t off_dt, off_str, off_mem_rsvmap;
+ int rc;
+ char *blob;
+ struct fdt_header *fdt;
+ char *p;
+ struct inbuf dtbuf, strbuf;
+ struct inbuf memresvbuf;
+ int sizeleft;
+ struct reserve_info *reservelist;
+ struct node *tree;
+ uint32_t val;
+ int flags = 0;
+
+ f = srcfile_relative_open(fname, NULL);
+
+ rc = fread(&magic, sizeof(magic), 1, f);
+ if (ferror(f))
+ die("Error reading DT blob magic number: %s\n",
+ strerror(errno));
+ if (rc < 1) {
+ if (feof(f))
+ die("EOF reading DT blob magic number\n");
+ else
+ die("Mysterious short read reading magic number\n");
+ }
+
+ magic = fdt32_to_cpu(magic);
+ if (magic != FDT_MAGIC)
+ die("Blob has incorrect magic number\n");
+
+ rc = fread(&totalsize, sizeof(totalsize), 1, f);
+ if (ferror(f))
+ die("Error reading DT blob size: %s\n", strerror(errno));
+ if (rc < 1) {
+ if (feof(f))
+ die("EOF reading DT blob size\n");
+ else
+ die("Mysterious short read reading blob size\n");
+ }
+
+ totalsize = fdt32_to_cpu(totalsize);
+ if (totalsize < FDT_V1_SIZE)
+ die("DT blob size (%d) is too small\n", totalsize);
+
+ blob = xmalloc(totalsize);
+
+ fdt = (struct fdt_header *)blob;
+ fdt->magic = cpu_to_fdt32(magic);
+ fdt->totalsize = cpu_to_fdt32(totalsize);
+
+ sizeleft = totalsize - sizeof(magic) - sizeof(totalsize);
+ p = blob + sizeof(magic) + sizeof(totalsize);
+
+ while (sizeleft) {
+ if (feof(f))
+ die("EOF before reading %d bytes of DT blob\n",
+ totalsize);
+
+ rc = fread(p, 1, sizeleft, f);
+ if (ferror(f))
+ die("Error reading DT blob: %s\n",
+ strerror(errno));
+
+ sizeleft -= rc;
+ p += rc;
+ }
+
+ off_dt = fdt32_to_cpu(fdt->off_dt_struct);
+ off_str = fdt32_to_cpu(fdt->off_dt_strings);
+ off_mem_rsvmap = fdt32_to_cpu(fdt->off_mem_rsvmap);
+ version = fdt32_to_cpu(fdt->version);
+ boot_cpuid_phys = fdt32_to_cpu(fdt->boot_cpuid_phys);
+
+ if (off_mem_rsvmap >= totalsize)
+ die("Mem Reserve structure offset exceeds total size\n");
+
+ if (off_dt >= totalsize)
+ die("DT structure offset exceeds total size\n");
+
+ if (off_str > totalsize)
+ die("String table offset exceeds total size\n");
+
+ if (version >= 3) {
+ uint32_t size_str = fdt32_to_cpu(fdt->size_dt_strings);
+ if (off_str+size_str > totalsize)
+ die("String table extends past total size\n");
+ inbuf_init(&strbuf, blob + off_str, blob + off_str + size_str);
+ } else {
+ inbuf_init(&strbuf, blob + off_str, blob + totalsize);
+ }
+
+ if (version >= 17) {
+ size_dt = fdt32_to_cpu(fdt->size_dt_struct);
+ if (off_dt+size_dt > totalsize)
+ die("Structure block extends past total size\n");
+ }
+
+ if (version < 16) {
+ flags |= FTF_FULLPATH | FTF_NAMEPROPS | FTF_VARALIGN;
+ } else {
+ flags |= FTF_NOPS;
+ }
+
+ inbuf_init(&memresvbuf,
+ blob + off_mem_rsvmap, blob + totalsize);
+ inbuf_init(&dtbuf, blob + off_dt, blob + totalsize);
+
+ reservelist = flat_read_mem_reserve(&memresvbuf);
+
+ val = flat_read_word(&dtbuf);
+
+ if (val != FDT_BEGIN_NODE)
+ die("Device tree blob doesn't begin with FDT_BEGIN_NODE (begins with 0x%08x)\n", val);
+
+ tree = unflatten_tree(&dtbuf, &strbuf, "", flags);
+
+ val = flat_read_word(&dtbuf);
+ if (val != FDT_END)
+ die("Device tree blob doesn't end with FDT_END\n");
+
+ free(blob);
+
+ fclose(f);
+
+ return build_boot_info(reservelist, tree, boot_cpuid_phys);
+}
diff --git a/src/dtc/fstree.c b/src/dtc/fstree.c
new file mode 100644
index 0000000..f377453
--- /dev/null
+++ b/src/dtc/fstree.c
@@ -0,0 +1,91 @@
+/*
+ * (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 <dirent.h>
+#include <sys/stat.h>
+
+static struct node *read_fstree(const char *dirname)
+{
+ DIR *d;
+ struct dirent *de;
+ struct stat st;
+ struct node *tree;
+
+ d = opendir(dirname);
+ if (!d)
+ die("Couldn't opendir() \"%s\": %s\n", dirname, strerror(errno));
+
+ tree = build_node(NULL, NULL);
+
+ while ((de = readdir(d)) != NULL) {
+ char *tmpnam;
+
+ if (streq(de->d_name, ".")
+ || streq(de->d_name, ".."))
+ continue;
+
+ tmpnam = join_path(dirname, de->d_name);
+
+ if (lstat(tmpnam, &st) < 0)
+ die("stat(%s): %s\n", tmpnam, strerror(errno));
+
+ if (S_ISREG(st.st_mode)) {
+ struct property *prop;
+ FILE *pfile;
+
+ pfile = fopen(tmpnam, "r");
+ if (! pfile) {
+ fprintf(stderr,
+ "WARNING: Cannot open %s: %s\n",
+ tmpnam, strerror(errno));
+ } else {
+ prop = build_property(xstrdup(de->d_name),
+ data_copy_file(pfile,
+ st.st_size));
+ add_property(tree, prop);
+ fclose(pfile);
+ }
+ } else if (S_ISDIR(st.st_mode)) {
+ struct node *newchild;
+
+ newchild = read_fstree(tmpnam);
+ newchild = name_node(newchild, xstrdup(de->d_name));
+ add_child(tree, newchild);
+ }
+
+ free(tmpnam);
+ }
+
+ closedir(d);
+ return tree;
+}
+
+struct boot_info *dt_from_fs(const char *dirname)
+{
+ struct node *tree;
+
+ tree = read_fstree(dirname);
+ tree = name_node(tree, "");
+
+ return build_boot_info(NULL, tree, guess_boot_cpuid(tree));
+}
+
diff --git a/src/dtc/libfdt/Makefile.libfdt b/src/dtc/libfdt/Makefile.libfdt
new file mode 100644
index 0000000..91126c0
--- /dev/null
+++ b/src/dtc/libfdt/Makefile.libfdt
@@ -0,0 +1,10 @@
+# Makefile.libfdt
+#
+# This is not a complete Makefile of itself. Instead, it is designed to
+# be easily embeddable into other systems of Makefiles.
+#
+LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1
+LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h
+LIBFDT_VERSION = version.lds
+LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c
+LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
diff --git a/src/dtc/libfdt/TODO b/src/dtc/libfdt/TODO
new file mode 100644
index 0000000..288437e
--- /dev/null
+++ b/src/dtc/libfdt/TODO
@@ -0,0 +1,3 @@
+- Tree traversal functions
+- Graft function
+- Complete libfdt.h documenting comments
diff --git a/src/dtc/libfdt/fdt.c b/src/dtc/libfdt/fdt.c
new file mode 100644
index 0000000..2ce6a44
--- /dev/null
+++ b/src/dtc/libfdt/fdt.c
@@ -0,0 +1,250 @@
+/*
+ * 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>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+int fdt_check_header(const void *fdt)
+{
+ 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;
+ } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
+ /* Unfinished sequential-write blob */
+ if (fdt_size_dt_struct(fdt) == 0)
+ return -FDT_ERR_BADSTATE;
+ } else {
+ return -FDT_ERR_BADMAGIC;
+ }
+
+ return 0;
+}
+
+const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
+{
+ const char *p;
+
+ if (fdt_version(fdt) >= 0x11)
+ if (((offset + len) < offset)
+ || ((offset + len) > fdt_size_dt_struct(fdt)))
+ return NULL;
+
+ p = _fdt_offset_ptr(fdt, offset);
+
+ if (p + len < p)
+ return NULL;
+ return p;
+}
+
+uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
+{
+ const fdt32_t *tagp, *lenp;
+ uint32_t tag;
+ int offset = startoffset;
+ const char *p;
+
+ *nextoffset = -FDT_ERR_TRUNCATED;
+ tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
+ if (!tagp)
+ return FDT_END; /* premature end */
+ tag = fdt32_to_cpu(*tagp);
+ offset += FDT_TAGSIZE;
+
+ *nextoffset = -FDT_ERR_BADSTRUCTURE;
+ switch (tag) {
+ case FDT_BEGIN_NODE:
+ /* skip name */
+ do {
+ p = fdt_offset_ptr(fdt, offset++, 1);
+ } while (p && (*p != '\0'));
+ if (!p)
+ return FDT_END; /* premature end */
+ break;
+
+ case FDT_PROP:
+ lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
+ if (!lenp)
+ return FDT_END; /* premature end */
+ /* skip-name offset, length and value */
+ offset += sizeof(struct fdt_property) - FDT_TAGSIZE
+ + fdt32_to_cpu(*lenp);
+ break;
+
+ case FDT_END:
+ case FDT_END_NODE:
+ case FDT_NOP:
+ break;
+
+ default:
+ return FDT_END;
+ }
+
+ if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset))
+ return FDT_END; /* premature end */
+
+ *nextoffset = FDT_TAGALIGN(offset);
+ return tag;
+}
+
+int _fdt_check_node_offset(const void *fdt, int offset)
+{
+ if ((offset < 0) || (offset % FDT_TAGSIZE)
+ || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
+ return -FDT_ERR_BADOFFSET;
+
+ return 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))
+ return -FDT_ERR_BADOFFSET;
+
+ return offset;
+}
+
+int fdt_next_node(const void *fdt, int offset, int *depth)
+{
+ int nextoffset = 0;
+ uint32_t tag;
+
+ if (offset >= 0)
+ if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0)
+ return nextoffset;
+
+ do {
+ offset = nextoffset;
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+ switch (tag) {
+ case FDT_PROP:
+ case FDT_NOP:
+ break;
+
+ case FDT_BEGIN_NODE:
+ if (depth)
+ (*depth)++;
+ break;
+
+ case FDT_END_NODE:
+ if (depth && ((--(*depth)) < 0))
+ return nextoffset;
+ break;
+
+ case FDT_END:
+ if ((nextoffset >= 0)
+ || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth))
+ return -FDT_ERR_NOTFOUND;
+ else
+ return nextoffset;
+ }
+ } while (tag != FDT_BEGIN_NODE);
+
+ return offset;
+}
+
+int fdt_first_subnode(const void *fdt, int offset)
+{
+ int depth = 0;
+
+ offset = fdt_next_node(fdt, offset, &depth);
+ if (offset < 0 || depth != 1)
+ return -FDT_ERR_NOTFOUND;
+
+ return offset;
+}
+
+int fdt_next_subnode(const void *fdt, int offset)
+{
+ int depth = 1;
+
+ /*
+ * With respect to the parent, the depth of the next subnode will be
+ * the same as the last.
+ */
+ do {
+ offset = fdt_next_node(fdt, offset, &depth);
+ if (offset < 0 || depth < 1)
+ return -FDT_ERR_NOTFOUND;
+ } while (depth > 1);
+
+ return offset;
+}
+
+const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
+{
+ int len = strlen(s) + 1;
+ const char *last = strtab + tabsize - len;
+ const char *p;
+
+ for (p = strtab; p <= last; p++)
+ if (memcmp(p, s, len) == 0)
+ return p;
+ return NULL;
+}
+
+int fdt_move(const void *fdt, void *buf, int bufsize)
+{
+ FDT_CHECK_HEADER(fdt);
+
+ if (fdt_totalsize(fdt) > bufsize)
+ return -FDT_ERR_NOSPACE;
+
+ memmove(buf, fdt, fdt_totalsize(fdt));
+ return 0;
+}
diff --git a/src/dtc/libfdt/fdt.h b/src/dtc/libfdt/fdt.h
new file mode 100644
index 0000000..526aedb
--- /dev/null
+++ b/src/dtc/libfdt/fdt.h
@@ -0,0 +1,111 @@
+#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__
+
+struct fdt_header {
+ fdt32_t magic; /* magic word FDT_MAGIC */
+ fdt32_t totalsize; /* total size of DT block */
+ fdt32_t off_dt_struct; /* offset to structure */
+ fdt32_t off_dt_strings; /* offset to strings */
+ fdt32_t off_mem_rsvmap; /* offset to memory reserve map */
+ fdt32_t version; /* format version */
+ fdt32_t last_comp_version; /* last compatible version */
+
+ /* version 2 fields below */
+ fdt32_t boot_cpuid_phys; /* Which physical CPU id we're
+ booting on */
+ /* version 3 fields below */
+ fdt32_t size_dt_strings; /* size of the strings block */
+
+ /* version 17 fields below */
+ fdt32_t size_dt_struct; /* size of the structure block */
+};
+
+struct fdt_reserve_entry {
+ fdt64_t address;
+ fdt64_t size;
+};
+
+struct fdt_node_header {
+ fdt32_t tag;
+ char name[0];
+};
+
+struct fdt_property {
+ fdt32_t tag;
+ fdt32_t len;
+ fdt32_t nameoff;
+ char data[0];
+};
+
+#endif /* !__ASSEMBLY */
+
+#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */
+#define FDT_TAGSIZE sizeof(fdt32_t)
+
+#define FDT_BEGIN_NODE 0x1 /* Start node: full name */
+#define FDT_END_NODE 0x2 /* End node */
+#define FDT_PROP 0x3 /* Property: name off,
+ size, content */
+#define FDT_NOP 0x4 /* nop */
+#define FDT_END 0x9
+
+#define FDT_V1_SIZE (7*sizeof(fdt32_t))
+#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t))
+#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t))
+#define FDT_V16_SIZE FDT_V3_SIZE
+#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t))
+
+#endif /* _FDT_H */
diff --git a/src/dtc/libfdt/fdt_empty_tree.c b/src/dtc/libfdt/fdt_empty_tree.c
new file mode 100644
index 0000000..f72d13b
--- /dev/null
+++ b/src/dtc/libfdt/fdt_empty_tree.c
@@ -0,0 +1,84 @@
+/*
+ * 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"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+int fdt_create_empty_tree(void *buf, int bufsize)
+{
+ int err;
+
+ err = fdt_create(buf, bufsize);
+ if (err)
+ return err;
+
+ err = fdt_finish_reservemap(buf);
+ if (err)
+ return err;
+
+ err = fdt_begin_node(buf, "");
+ if (err)
+ return err;
+
+ err = fdt_end_node(buf);
+ if (err)
+ return err;
+
+ err = fdt_finish(buf);
+ if (err)
+ return err;
+
+ return fdt_open_into(buf, buf, bufsize);
+}
+
diff --git a/src/dtc/libfdt/fdt_ro.c b/src/dtc/libfdt/fdt_ro.c
new file mode 100644
index 0000000..50007f6
--- /dev/null
+++ b/src/dtc/libfdt/fdt_ro.c
@@ -0,0 +1,573 @@
+/*
+ * 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>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+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);
+
+ if (! p)
+ /* short match */
+ return 0;
+
+ if (memcmp(p, s, len) != 0)
+ return 0;
+
+ if (p[len] == '\0')
+ return 1;
+ else if (!memchr(s, '@', len) && (p[len] == '@'))
+ return 1;
+ else
+ return 0;
+}
+
+const char *fdt_string(const void *fdt, int stroffset)
+{
+ return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
+}
+
+static int _fdt_string_eq(const void *fdt, int stroffset,
+ const char *s, int len)
+{
+ const char *p = fdt_string(fdt, stroffset);
+
+ return (strlen(p) == len) && (memcmp(p, s, len) == 0);
+}
+
+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);
+ return 0;
+}
+
+int fdt_num_mem_rsv(const void *fdt)
+{
+ int i = 0;
+
+ while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
+ i++;
+ return i;
+}
+
+static int _nextprop(const void *fdt, int offset)
+{
+ uint32_t tag;
+ int nextoffset;
+
+ do {
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+ switch (tag) {
+ case FDT_END:
+ if (nextoffset >= 0)
+ return -FDT_ERR_BADSTRUCTURE;
+ else
+ return nextoffset;
+
+ case FDT_PROP:
+ return offset;
+ }
+ offset = nextoffset;
+ } while (tag == FDT_NOP);
+
+ return -FDT_ERR_NOTFOUND;
+}
+
+int fdt_subnode_offset_namelen(const void *fdt, int offset,
+ const char *name, int namelen)
+{
+ int depth;
+
+ FDT_CHECK_HEADER(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))
+ return offset;
+
+ if (depth < 0)
+ return -FDT_ERR_NOTFOUND;
+ return offset; /* error */
+}
+
+int fdt_subnode_offset(const void *fdt, int parentoffset,
+ const char *name)
+{
+ return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
+}
+
+int fdt_path_offset(const void *fdt, const char *path)
+{
+ const char *end = path + strlen(path);
+ const char *p = path;
+ int offset = 0;
+
+ FDT_CHECK_HEADER(fdt);
+
+ /* see if we have an alias */
+ if (*path != '/') {
+ const char *q = strchr(path, '/');
+
+ if (!q)
+ q = end;
+
+ p = fdt_get_alias_namelen(fdt, p, q - p);
+ if (!p)
+ return -FDT_ERR_BADPATH;
+ offset = fdt_path_offset(fdt, p);
+
+ p = q;
+ }
+
+ while (*p) {
+ const char *q;
+
+ while (*p == '/')
+ p++;
+ if (! *p)
+ return offset;
+ q = strchr(p, '/');
+ if (! q)
+ q = end;
+
+ offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
+ if (offset < 0)
+ return offset;
+
+ p = q;
+ }
+
+ return offset;
+}
+
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
+{
+ const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
+ int err;
+
+ if (((err = fdt_check_header(fdt)) != 0)
+ || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
+ goto fail;
+
+ if (len)
+ *len = strlen(nh->name);
+
+ return nh->name;
+
+ fail:
+ if (len)
+ *len = err;
+ return NULL;
+}
+
+int fdt_first_property_offset(const void *fdt, int nodeoffset)
+{
+ int offset;
+
+ if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
+ return offset;
+
+ return _nextprop(fdt, offset);
+}
+
+int fdt_next_property_offset(const void *fdt, int offset)
+{
+ if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0)
+ return offset;
+
+ return _nextprop(fdt, offset);
+}
+
+const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
+ int offset,
+ int *lenp)
+{
+ int err;
+ const struct fdt_property *prop;
+
+ if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) {
+ if (lenp)
+ *lenp = err;
+ return NULL;
+ }
+
+ prop = _fdt_offset_ptr(fdt, offset);
+
+ if (lenp)
+ *lenp = fdt32_to_cpu(prop->len);
+
+ return prop;
+}
+
+const struct fdt_property *fdt_get_property_namelen(const void *fdt,
+ int offset,
+ const char *name,
+ int namelen, int *lenp)
+{
+ 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))) {
+ offset = -FDT_ERR_INTERNAL;
+ break;
+ }
+ if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),
+ name, namelen))
+ return prop;
+ }
+
+ if (lenp)
+ *lenp = offset;
+ return NULL;
+}
+
+const struct fdt_property *fdt_get_property(const void *fdt,
+ int nodeoffset,
+ const char *name, int *lenp)
+{
+ return fdt_get_property_namelen(fdt, nodeoffset, name,
+ strlen(name), lenp);
+}
+
+const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
+ const char *name, int namelen, int *lenp)
+{
+ const struct fdt_property *prop;
+
+ prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
+ if (! prop)
+ return NULL;
+
+ return prop->data;
+}
+
+const void *fdt_getprop_by_offset(const void *fdt, int offset,
+ const char **namep, int *lenp)
+{
+ const struct fdt_property *prop;
+
+ prop = fdt_get_property_by_offset(fdt, offset, lenp);
+ if (!prop)
+ return NULL;
+ if (namep)
+ *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+ return prop->data;
+}
+
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+ const char *name, int *lenp)
+{
+ return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
+}
+
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
+{
+ const fdt32_t *php;
+ int len;
+
+ /* FIXME: This is a bit sub-optimal, since we potentially scan
+ * over all the properties twice. */
+ php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
+ if (!php || (len != sizeof(*php))) {
+ php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
+ if (!php || (len != sizeof(*php)))
+ return 0;
+ }
+
+ return fdt32_to_cpu(*php);
+}
+
+const char *fdt_get_alias_namelen(const void *fdt,
+ const char *name, int namelen)
+{
+ int aliasoffset;
+
+ aliasoffset = fdt_path_offset(fdt, "/aliases");
+ if (aliasoffset < 0)
+ return NULL;
+
+ return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
+}
+
+const char *fdt_get_alias(const void *fdt, const char *name)
+{
+ return fdt_get_alias_namelen(fdt, name, strlen(name));
+}
+
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
+{
+ int pdepth = 0, p = 0;
+ int offset, depth, namelen;
+ const char *name;
+
+ FDT_CHECK_HEADER(fdt);
+
+ if (buflen < 2)
+ return -FDT_ERR_NOSPACE;
+
+ for (offset = 0, depth = 0;
+ (offset >= 0) && (offset <= nodeoffset);
+ offset = fdt_next_node(fdt, offset, &depth)) {
+ while (pdepth > depth) {
+ do {
+ p--;
+ } while (buf[p-1] != '/');
+ pdepth--;
+ }
+
+ if (pdepth >= depth) {
+ name = fdt_get_name(fdt, offset, &namelen);
+ if (!name)
+ return namelen;
+ if ((p + namelen + 1) <= buflen) {
+ memcpy(buf + p, name, namelen);
+ p += namelen;
+ buf[p++] = '/';
+ pdepth++;
+ }
+ }
+
+ if (offset == nodeoffset) {
+ if (pdepth < (depth + 1))
+ return -FDT_ERR_NOSPACE;
+
+ if (p > 1) /* special case so that root path is "/", not "" */
+ p--;
+ buf[p] = '\0';
+ return 0;
+ }
+ }
+
+ 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() */
+}
+
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+ int supernodedepth, int *nodedepth)
+{
+ int offset, depth;
+ int supernodeoffset = -FDT_ERR_INTERNAL;
+
+ FDT_CHECK_HEADER(fdt);
+
+ if (supernodedepth < 0)
+ return -FDT_ERR_NOTFOUND;
+
+ for (offset = 0, depth = 0;
+ (offset >= 0) && (offset <= nodeoffset);
+ offset = fdt_next_node(fdt, offset, &depth)) {
+ if (depth == supernodedepth)
+ supernodeoffset = offset;
+
+ if (offset == nodeoffset) {
+ if (nodedepth)
+ *nodedepth = depth;
+
+ if (supernodedepth > depth)
+ return -FDT_ERR_NOTFOUND;
+ else
+ return supernodeoffset;
+ }
+ }
+
+ 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() */
+}
+
+int fdt_node_depth(const void *fdt, int nodeoffset)
+{
+ int nodedepth;
+ int err;
+
+ err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
+ if (err)
+ return (err < 0) ? err : -FDT_ERR_INTERNAL;
+ return nodedepth;
+}
+
+int fdt_parent_offset(const void *fdt, int nodeoffset)
+{
+ int nodedepth = fdt_node_depth(fdt, nodeoffset);
+
+ if (nodedepth < 0)
+ return nodedepth;
+ return fdt_supernode_atdepth_offset(fdt, nodeoffset,
+ nodedepth - 1, NULL);
+}
+
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+ const char *propname,
+ const void *propval, int proplen)
+{
+ int offset;
+ const void *val;
+ int len;
+
+ FDT_CHECK_HEADER(fdt);
+
+ /* FIXME: The algorithm here is pretty horrible: we scan each
+ * property of a node in fdt_getprop(), then if that didn't
+ * find what we want, we scan over them again making our way
+ * to the next node. Still it's the easiest to implement
+ * approach; performance can come later. */
+ for (offset = fdt_next_node(fdt, startoffset, NULL);
+ offset >= 0;
+ offset = fdt_next_node(fdt, offset, NULL)) {
+ val = fdt_getprop(fdt, offset, propname, &len);
+ if (val && (len == proplen)
+ && (memcmp(val, propval, len) == 0))
+ return offset;
+ }
+
+ return offset; /* error from fdt_next_node() */
+}
+
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
+{
+ int offset;
+
+ if ((phandle == 0) || (phandle == -1))
+ return -FDT_ERR_BADPHANDLE;
+
+ FDT_CHECK_HEADER(fdt);
+
+ /* FIXME: The algorithm here is pretty horrible: we
+ * potentially scan each property of a node in
+ * fdt_get_phandle(), then if that didn't find what
+ * we want, we scan over them again making our way to the next
+ * node. Still it's the easiest to implement approach;
+ * performance can come later. */
+ for (offset = fdt_next_node(fdt, -1, NULL);
+ offset >= 0;
+ offset = fdt_next_node(fdt, offset, NULL)) {
+ if (fdt_get_phandle(fdt, offset) == phandle)
+ return offset;
+ }
+
+ return offset; /* error from fdt_next_node() */
+}
+
+int fdt_stringlist_contains(const char *strlist, int listlen, const char *str)
+{
+ int len = strlen(str);
+ const char *p;
+
+ while (listlen >= len) {
+ if (memcmp(str, strlist, len+1) == 0)
+ return 1;
+ p = memchr(strlist, '\0', listlen);
+ if (!p)
+ return 0; /* malformed strlist.. */
+ listlen -= (p-strlist) + 1;
+ strlist = p + 1;
+ }
+ return 0;
+}
+
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+ const char *compatible)
+{
+ const void *prop;
+ int len;
+
+ prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
+ if (!prop)
+ return len;
+ if (fdt_stringlist_contains(prop, len, compatible))
+ return 0;
+ else
+ return 1;
+}
+
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+ const char *compatible)
+{
+ int offset, err;
+
+ FDT_CHECK_HEADER(fdt);
+
+ /* FIXME: The algorithm here is pretty horrible: we scan each
+ * property of a node in fdt_node_check_compatible(), then if
+ * that didn't find what we want, we scan over them again
+ * making our way to the next node. Still it's the easiest to
+ * implement approach; performance can come later. */
+ for (offset = fdt_next_node(fdt, startoffset, NULL);
+ offset >= 0;
+ offset = fdt_next_node(fdt, offset, NULL)) {
+ err = fdt_node_check_compatible(fdt, offset, compatible);
+ if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
+ return err;
+ else if (err == 0)
+ return offset;
+ }
+
+ return offset; /* error from fdt_next_node() */
+}
diff --git a/src/dtc/libfdt/fdt_rw.c b/src/dtc/libfdt/fdt_rw.c
new file mode 100644
index 0000000..fdba618
--- /dev/null
+++ b/src/dtc/libfdt/fdt_rw.c
@@ -0,0 +1,492 @@
+/*
+ * 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>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+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) <
+ (fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
+ || (fdt_off_dt_strings(fdt) <
+ (fdt_off_dt_struct(fdt) + struct_size))
+ || (fdt_totalsize(fdt) <
+ (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
+}
+
+static int _fdt_rw_check_header(void *fdt)
+{
+ FDT_CHECK_HEADER(fdt);
+
+ if (fdt_version(fdt) < 17)
+ return -FDT_ERR_BADVERSION;
+ if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
+ fdt_size_dt_struct(fdt)))
+ return -FDT_ERR_BADLAYOUT;
+ if (fdt_version(fdt) > 17)
+ fdt_set_version(fdt, 17);
+
+ return 0;
+}
+
+#define FDT_RW_CHECK_HEADER(fdt) \
+ { \
+ int err; \
+ if ((err = _fdt_rw_check_header(fdt)) != 0) \
+ return err; \
+ }
+
+static inline 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)
+{
+ char *p = splicepoint;
+ char *end = (char *)fdt + _fdt_data_size(fdt);
+
+ if (((p + oldlen) < p) || ((p + oldlen) > end))
+ return -FDT_ERR_BADOFFSET;
+ if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
+ return -FDT_ERR_NOSPACE;
+ memmove(p + newlen, p + oldlen, end - p - oldlen);
+ return 0;
+}
+
+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));
+ if (err)
+ return err;
+ fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
+ fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
+ return 0;
+}
+
+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)))
+ return err;
+
+ fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
+ fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
+ return 0;
+}
+
+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)))
+ 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)
+{
+ char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
+ const char *p;
+ char *new;
+ int len = strlen(s) + 1;
+ int err;
+
+ 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);
+ if (err)
+ return err;
+
+ memcpy(new, s, len);
+ return (new - strtab);
+}
+
+int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
+{
+ struct fdt_reserve_entry *re;
+ int err;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
+ err = _fdt_splice_mem_rsv(fdt, re, 0, 1);
+ if (err)
+ return err;
+
+ re->address = cpu_to_fdt64(address);
+ re->size = cpu_to_fdt64(size);
+ return 0;
+}
+
+int fdt_del_mem_rsv(void *fdt, int n)
+{
+ struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
+ int err;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ if (n >= fdt_num_mem_rsv(fdt))
+ return -FDT_ERR_NOTFOUND;
+
+ err = _fdt_splice_mem_rsv(fdt, re, 1, 0);
+ if (err)
+ return err;
+ return 0;
+}
+
+static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
+ int len, struct fdt_property **prop)
+{
+ int oldlen;
+ int err;
+
+ *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
+ if (! (*prop))
+ return oldlen;
+
+ if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
+ FDT_TAGALIGN(len))))
+ return err;
+
+ (*prop)->len = cpu_to_fdt32(len);
+ return 0;
+}
+
+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;
+
+ if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
+ return nextoffset;
+
+ namestroff = _fdt_find_add_string(fdt, name);
+ if (namestroff < 0)
+ return namestroff;
+
+ *prop = _fdt_offset_ptr_w(fdt, nextoffset);
+ proplen = sizeof(**prop) + FDT_TAGALIGN(len);
+
+ err = _fdt_splice_struct(fdt, *prop, 0, proplen);
+ if (err)
+ return err;
+
+ (*prop)->tag = cpu_to_fdt32(FDT_PROP);
+ (*prop)->nameoff = cpu_to_fdt32(namestroff);
+ (*prop)->len = cpu_to_fdt32(len);
+ return 0;
+}
+
+int fdt_set_name(void *fdt, int nodeoffset, const char *name)
+{
+ char *namep;
+ int oldlen, newlen;
+ int err;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
+ if (!namep)
+ return oldlen;
+
+ newlen = strlen(name);
+
+ err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1),
+ FDT_TAGALIGN(newlen+1));
+ if (err)
+ return err;
+
+ memcpy(namep, name, newlen+1);
+ return 0;
+}
+
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len)
+{
+ struct fdt_property *prop;
+ int err;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop);
+ if (err == -FDT_ERR_NOTFOUND)
+ err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
+ if (err)
+ return err;
+
+ memcpy(prop->data, val, len);
+ return 0;
+}
+
+int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len)
+{
+ struct fdt_property *prop;
+ int err, oldlen, newlen;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
+ if (prop) {
+ newlen = len + oldlen;
+ err = _fdt_splice_struct(fdt, prop->data,
+ FDT_TAGALIGN(oldlen),
+ FDT_TAGALIGN(newlen));
+ if (err)
+ return err;
+ prop->len = cpu_to_fdt32(newlen);
+ memcpy(prop->data + oldlen, val, len);
+ } else {
+ err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
+ if (err)
+ return err;
+ memcpy(prop->data, val, len);
+ }
+ return 0;
+}
+
+int fdt_delprop(void *fdt, int nodeoffset, const char *name)
+{
+ struct fdt_property *prop;
+ int len, proplen;
+
+ FDT_RW_CHECK_HEADER(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);
+}
+
+int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+ const char *name, int namelen)
+{
+ struct fdt_node_header *nh;
+ int offset, nextoffset;
+ int nodelen;
+ int err;
+ uint32_t tag;
+ fdt32_t *endtag;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
+ if (offset >= 0)
+ return -FDT_ERR_EXISTS;
+ else if (offset != -FDT_ERR_NOTFOUND)
+ return offset;
+
+ /* Try to place the new node after the parent's properties */
+ fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
+ do {
+ offset = nextoffset;
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+ } while ((tag == FDT_PROP) || (tag == FDT_NOP));
+
+ nh = _fdt_offset_ptr_w(fdt, offset);
+ nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;
+
+ err = _fdt_splice_struct(fdt, nh, 0, nodelen);
+ if (err)
+ return err;
+
+ nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
+ memset(nh->name, 0, FDT_TAGALIGN(namelen+1));
+ memcpy(nh->name, name, namelen);
+ endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE);
+ *endtag = cpu_to_fdt32(FDT_END_NODE);
+
+ return offset;
+}
+
+int fdt_add_subnode(void *fdt, int parentoffset, const char *name)
+{
+ return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
+}
+
+int fdt_del_node(void *fdt, int nodeoffset)
+{
+ int endoffset;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+ if (endoffset < 0)
+ return endoffset;
+
+ return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
+ endoffset - nodeoffset, 0);
+}
+
+static void _fdt_packblocks(const char *old, char *new,
+ int mem_rsv_size, int struct_size)
+{
+ int mem_rsv_off, struct_off, strings_off;
+
+ mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
+ struct_off = mem_rsv_off + mem_rsv_size;
+ strings_off = struct_off + struct_size;
+
+ memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size);
+ fdt_set_off_mem_rsvmap(new, mem_rsv_off);
+
+ memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size);
+ fdt_set_off_dt_struct(new, struct_off);
+ fdt_set_size_dt_struct(new, struct_size);
+
+ memmove(new + strings_off, old + fdt_off_dt_strings(old),
+ fdt_size_dt_strings(old));
+ fdt_set_off_dt_strings(new, strings_off);
+ fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
+}
+
+int fdt_open_into(const void *fdt, void *buf, int bufsize)
+{
+ int err;
+ int mem_rsv_size, struct_size;
+ int newsize;
+ const char *fdtstart = fdt;
+ const char *fdtend = fdtstart + fdt_totalsize(fdt);
+ char *tmp;
+
+ FDT_CHECK_HEADER(fdt);
+
+ mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
+ * sizeof(struct fdt_reserve_entry);
+
+ if (fdt_version(fdt) >= 17) {
+ struct_size = fdt_size_dt_struct(fdt);
+ } else {
+ struct_size = 0;
+ while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
+ ;
+ if (struct_size < 0)
+ return struct_size;
+ }
+
+ if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
+ /* no further work necessary */
+ err = fdt_move(fdt, buf, bufsize);
+ if (err)
+ return err;
+ fdt_set_version(buf, 17);
+ fdt_set_size_dt_struct(buf, struct_size);
+ fdt_set_totalsize(buf, bufsize);
+ return 0;
+ }
+
+ /* Need to reorder */
+ newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
+ + struct_size + fdt_size_dt_strings(fdt);
+
+ if (bufsize < newsize)
+ return -FDT_ERR_NOSPACE;
+
+ /* First attempt to build converted tree at beginning of buffer */
+ tmp = buf;
+ /* But if that overlaps with the old tree... */
+ if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) {
+ /* Try right after the old tree instead */
+ tmp = (char *)(uintptr_t)fdtend;
+ if ((tmp + newsize) > ((char *)buf + bufsize))
+ return -FDT_ERR_NOSPACE;
+ }
+
+ _fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size);
+ memmove(buf, tmp, newsize);
+
+ fdt_set_magic(buf, FDT_MAGIC);
+ fdt_set_totalsize(buf, bufsize);
+ fdt_set_version(buf, 17);
+ fdt_set_last_comp_version(buf, 16);
+ fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
+
+ return 0;
+}
+
+int fdt_pack(void *fdt)
+{
+ int mem_rsv_size;
+
+ FDT_RW_CHECK_HEADER(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));
+
+ return 0;
+}
diff --git a/src/dtc/libfdt/fdt_strerror.c b/src/dtc/libfdt/fdt_strerror.c
new file mode 100644
index 0000000..e6c3cee
--- /dev/null
+++ b/src/dtc/libfdt/fdt_strerror.c
@@ -0,0 +1,96 @@
+/*
+ * 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>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+struct fdt_errtabent {
+ const char *str;
+};
+
+#define FDT_ERRTABENT(val) \
+ [(val)] = { .str = #val, }
+
+static struct fdt_errtabent fdt_errtable[] = {
+ FDT_ERRTABENT(FDT_ERR_NOTFOUND),
+ FDT_ERRTABENT(FDT_ERR_EXISTS),
+ FDT_ERRTABENT(FDT_ERR_NOSPACE),
+
+ FDT_ERRTABENT(FDT_ERR_BADOFFSET),
+ FDT_ERRTABENT(FDT_ERR_BADPATH),
+ FDT_ERRTABENT(FDT_ERR_BADSTATE),
+
+ FDT_ERRTABENT(FDT_ERR_TRUNCATED),
+ FDT_ERRTABENT(FDT_ERR_BADMAGIC),
+ FDT_ERRTABENT(FDT_ERR_BADVERSION),
+ FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE),
+ FDT_ERRTABENT(FDT_ERR_BADLAYOUT),
+};
+#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
+
+const char *fdt_strerror(int errval)
+{
+ if (errval > 0)
+ return "<valid offset/length>";
+ else if (errval == 0)
+ return "<no error>";
+ else if (errval > -FDT_ERRTABSIZE) {
+ const char *s = fdt_errtable[-errval].str;
+
+ if (s)
+ return s;
+ }
+
+ return "<unknown error>";
+}
diff --git a/src/dtc/libfdt/fdt_sw.c b/src/dtc/libfdt/fdt_sw.c
new file mode 100644
index 0000000..f422754
--- /dev/null
+++ b/src/dtc/libfdt/fdt_sw.c
@@ -0,0 +1,256 @@
+/*
+ * 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>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int _fdt_sw_check_header(void *fdt)
+{
+ if (fdt_magic(fdt) != FDT_SW_MAGIC)
+ return -FDT_ERR_BADMAGIC;
+ /* FIXME: should check more details about the header state */
+ return 0;
+}
+
+#define FDT_SW_CHECK_HEADER(fdt) \
+ { \
+ int err; \
+ if ((err = _fdt_sw_check_header(fdt)) != 0) \
+ return err; \
+ }
+
+static void *_fdt_grab_space(void *fdt, size_t len)
+{
+ int offset = fdt_size_dt_struct(fdt);
+ int spaceleft;
+
+ spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
+ - fdt_size_dt_strings(fdt);
+
+ if ((offset + len < offset) || (offset + len > spaceleft))
+ return NULL;
+
+ fdt_set_size_dt_struct(fdt, offset + len);
+ return _fdt_offset_ptr_w(fdt, offset);
+}
+
+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;
+}
+
+int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
+{
+ struct fdt_reserve_entry *re;
+ int offset;
+
+ FDT_SW_CHECK_HEADER(fdt);
+
+ if (fdt_size_dt_struct(fdt))
+ return -FDT_ERR_BADSTATE;
+
+ offset = fdt_off_dt_struct(fdt);
+ if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
+ return -FDT_ERR_NOSPACE;
+
+ re = (struct fdt_reserve_entry *)((char *)fdt + offset);
+ re->address = cpu_to_fdt64(addr);
+ re->size = cpu_to_fdt64(size);
+
+ fdt_set_off_dt_struct(fdt, offset + sizeof(*re));
+
+ return 0;
+}
+
+int fdt_finish_reservemap(void *fdt)
+{
+ return fdt_add_reservemap_entry(fdt, 0, 0);
+}
+
+int fdt_begin_node(void *fdt, const char *name)
+{
+ struct fdt_node_header *nh;
+ int namelen = strlen(name) + 1;
+
+ FDT_SW_CHECK_HEADER(fdt);
+
+ nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
+ if (! nh)
+ return -FDT_ERR_NOSPACE;
+
+ nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
+ memcpy(nh->name, name, namelen);
+ return 0;
+}
+
+int fdt_end_node(void *fdt)
+{
+ fdt32_t *en;
+
+ FDT_SW_CHECK_HEADER(fdt);
+
+ en = _fdt_grab_space(fdt, FDT_TAGSIZE);
+ if (! en)
+ return -FDT_ERR_NOSPACE;
+
+ *en = cpu_to_fdt32(FDT_END_NODE);
+ return 0;
+}
+
+static int _fdt_find_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)
+ return 0; /* no more room :( */
+
+ memcpy(strtab + offset, s, len);
+ fdt_set_size_dt_strings(fdt, strtabsize + len);
+ return offset;
+}
+
+int fdt_property(void *fdt, const char *name, const void *val, int len)
+{
+ struct fdt_property *prop;
+ int nameoff;
+
+ FDT_SW_CHECK_HEADER(fdt);
+
+ nameoff = _fdt_find_add_string(fdt, name);
+ if (nameoff == 0)
+ return -FDT_ERR_NOSPACE;
+
+ prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
+ if (! prop)
+ return -FDT_ERR_NOSPACE;
+
+ prop->tag = cpu_to_fdt32(FDT_PROP);
+ prop->nameoff = cpu_to_fdt32(nameoff);
+ prop->len = cpu_to_fdt32(len);
+ memcpy(prop->data, val, len);
+ return 0;
+}
+
+int fdt_finish(void *fdt)
+{
+ char *p = (char *)fdt;
+ fdt32_t *end;
+ int oldstroffset, newstroffset;
+ uint32_t tag;
+ int offset, nextoffset;
+
+ FDT_SW_CHECK_HEADER(fdt);
+
+ /* Add terminator */
+ end = _fdt_grab_space(fdt, sizeof(*end));
+ if (! end)
+ return -FDT_ERR_NOSPACE;
+ *end = cpu_to_fdt32(FDT_END);
+
+ /* Relocate the string table */
+ oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);
+ newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+ memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));
+ fdt_set_off_dt_strings(fdt, newstroffset);
+
+ /* Walk the structure, correcting string offsets */
+ offset = 0;
+ while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
+ if (tag == FDT_PROP) {
+ struct fdt_property *prop =
+ _fdt_offset_ptr_w(fdt, offset);
+ int nameoff;
+
+ nameoff = fdt32_to_cpu(prop->nameoff);
+ nameoff += fdt_size_dt_strings(fdt);
+ prop->nameoff = cpu_to_fdt32(nameoff);
+ }
+ offset = nextoffset;
+ }
+ if (nextoffset < 0)
+ return nextoffset;
+
+ /* Finally, adjust the header */
+ fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
+ fdt_set_magic(fdt, FDT_MAGIC);
+ return 0;
+}
diff --git a/src/dtc/libfdt/fdt_wip.c b/src/dtc/libfdt/fdt_wip.c
new file mode 100644
index 0000000..c5bbb68
--- /dev/null
+++ b/src/dtc/libfdt/fdt_wip.c
@@ -0,0 +1,118 @@
+/*
+ * 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>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len)
+{
+ void *propval;
+ int proplen;
+
+ propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen);
+ if (! propval)
+ return proplen;
+
+ if (proplen != len)
+ return -FDT_ERR_NOSPACE;
+
+ memcpy(propval, val, len);
+ return 0;
+}
+
+static void _fdt_nop_region(void *start, int len)
+{
+ fdt32_t *p;
+
+ for (p = start; (char *)p < ((char *)start + len); p++)
+ *p = cpu_to_fdt32(FDT_NOP);
+}
+
+int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
+{
+ struct fdt_property *prop;
+ int len;
+
+ prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
+ if (! prop)
+ return len;
+
+ _fdt_nop_region(prop, len + sizeof(*prop));
+
+ return 0;
+}
+
+int _fdt_node_end_offset(void *fdt, int offset)
+{
+ int depth = 0;
+
+ while ((offset >= 0) && (depth >= 0))
+ offset = fdt_next_node(fdt, offset, &depth);
+
+ return offset;
+}
+
+int fdt_nop_node(void *fdt, int nodeoffset)
+{
+ int endoffset;
+
+ endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+ if (endoffset < 0)
+ return endoffset;
+
+ _fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0),
+ endoffset - nodeoffset);
+ return 0;
+}
diff --git a/src/dtc/libfdt/libfdt.h b/src/dtc/libfdt/libfdt.h
new file mode 100644
index 0000000..02baa84
--- /dev/null
+++ b/src/dtc/libfdt/libfdt.h
@@ -0,0 +1,1514 @@
+#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
+#define FDT_LAST_SUPPORTED_VERSION 0x11
+
+/* Error codes: informative error codes */
+#define FDT_ERR_NOTFOUND 1
+ /* FDT_ERR_NOTFOUND: The requested node or property does not exist */
+#define FDT_ERR_EXISTS 2
+ /* FDT_ERR_EXISTS: Attemped to create a node or property which
+ * already exists */
+#define FDT_ERR_NOSPACE 3
+ /* FDT_ERR_NOSPACE: Operation needed to expand the device
+ * tree, but its buffer did not have sufficient space to
+ * contain the expanded tree. Use fdt_open_into() to move the
+ * device tree to a buffer with more space. */
+
+/* Error codes: codes for bad parameters */
+#define FDT_ERR_BADOFFSET 4
+ /* FDT_ERR_BADOFFSET: Function was passed a structure block
+ * offset which is out-of-bounds, or which points to an
+ * unsuitable part of the structure for the operation. */
+#define FDT_ERR_BADPATH 5
+ /* FDT_ERR_BADPATH: Function was passed a badly formatted path
+ * (e.g. missing a leading / for a function which requires an
+ * absolute path) */
+#define FDT_ERR_BADPHANDLE 6
+ /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle
+ * value. phandle values of 0 and -1 are not permitted. */
+#define FDT_ERR_BADSTATE 7
+ /* FDT_ERR_BADSTATE: Function was passed an incomplete device
+ * tree created by the sequential-write functions, which is
+ * not sufficiently complete for the requested operation. */
+
+/* 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. */
+#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
+ * tree magic number. */
+#define FDT_ERR_BADVERSION 10
+ /* FDT_ERR_BADVERSION: Given device tree has a version which
+ * can't be handled by the requested operation. For
+ * read-write functions, this may mean that fdt_open_into() is
+ * required to convert the tree to the expected version. */
+#define FDT_ERR_BADSTRUCTURE 11
+ /* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt
+ * structure block or other serious error (e.g. misnested
+ * nodes, or subnodes preceding properties). */
+#define FDT_ERR_BADLAYOUT 12
+ /* FDT_ERR_BADLAYOUT: For read-write functions, the given
+ * device tree has it's sub-blocks in an order that the
+ * function can't handle (memory reserve map, then structure,
+ * then strings). Use fdt_open_into() to reorganize the tree
+ * into a form suitable for the read-write operations. */
+
+/* "Can't happen" error indicating a bug in libfdt */
+#define FDT_ERR_INTERNAL 13
+ /* FDT_ERR_INTERNAL: libfdt has failed an internal assertion.
+ * Should never be returned, if it is, it indicates a bug in
+ * libfdt itself. */
+
+#define FDT_ERR_MAX 13
+
+/**********************************************************************/
+/* Low-level functions (you probably don't need these) */
+/**********************************************************************/
+
+const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen);
+static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
+{
+ return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen);
+}
+
+uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
+
+/**********************************************************************/
+/* Traversal functions */
+/**********************************************************************/
+
+int fdt_next_node(const void *fdt, int offset, int *depth);
+
+/**
+ * fdt_first_subnode() - get offset of first direct subnode
+ *
+ * @fdt: FDT blob
+ * @offset: Offset of node to check
+ * @return offset of first subnode, or -FDT_ERR_NOTFOUND if there is none
+ */
+int fdt_first_subnode(const void *fdt, int offset);
+
+/**
+ * fdt_next_subnode() - get offset of next direct subnode
+ *
+ * After first calling fdt_first_subnode(), call this function repeatedly to
+ * get direct subnodes of a parent node.
+ *
+ * @fdt: FDT blob
+ * @offset: Offset of previous subnode
+ * @return offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more
+ * subnodes
+ */
+int fdt_next_subnode(const void *fdt, int offset);
+
+/**********************************************************************/
+/* General functions */
+/**********************************************************************/
+
+#define fdt_get_header(fdt, field) \
+ (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
+#define fdt_magic(fdt) (fdt_get_header(fdt, magic))
+#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize))
+#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct))
+#define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings))
+#define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap))
+#define fdt_version(fdt) (fdt_get_header(fdt, version))
+#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version))
+#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys))
+#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) \
+ 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_check_header - sanity check a device tree or possible device tree
+ * @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.
+ *
+ * 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
+ */
+int fdt_check_header(const void *fdt);
+
+/**
+ * fdt_move - move a device tree around in memory
+ * @fdt: pointer to the device tree to move
+ * @buf: pointer to memory where the device is to be moved
+ * @bufsize: size of the memory space at buf
+ *
+ * fdt_move() relocates, if possible, the device tree blob located at
+ * fdt to the buffer at buf of size bufsize. The buffer may overlap
+ * with the existing device tree blob at fdt. Therefore,
+ * fdt_move(fdt, fdt, fdt_totalsize(fdt))
+ * should always succeed.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_move(const void *fdt, void *buf, int bufsize);
+
+/**********************************************************************/
+/* Read-only functions */
+/**********************************************************************/
+
+/**
+ * fdt_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)
+ *
+ * fdt_string() retrieves a pointer to a single string from the
+ * strings block of the device tree blob at fdt.
+ *
+ * returns:
+ * a pointer to the string, on success
+ * NULL, if stroffset is out of bounds
+ */
+const char *fdt_string(const void *fdt, int stroffset);
+
+/**
+ * fdt_num_mem_rsv - retrieve the number of memory reserve map entries
+ * @fdt: pointer to the device tree blob
+ *
+ * Returns the number of entries in the device tree blob's memory
+ * reservation map. This does not include the terminating 0,0 entry
+ * or any other (0,0) entries reserved for expansion.
+ *
+ * returns:
+ * the number of entries
+ */
+int fdt_num_mem_rsv(const void *fdt);
+
+/**
+ * fdt_get_mem_rsv - retrieve one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: pointers to 64-bit variables
+ *
+ * On success, *address and *size will contain the address and size of
+ * the n-th reserve map entry from the device tree blob, in
+ * native-endian format.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size);
+
+/**
+ * fdt_subnode_offset_namelen - find a subnode based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_subnode_offset(), but only examine the first
+ * namelen characters of name for matching the subnode name. This is
+ * useful for finding subnodes based on a portion of a larger string,
+ * such as a full path.
+ */
+int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
+ const char *name, int namelen);
+/**
+ * fdt_subnode_offset - find a subnode of a given node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_subnode_offset() finds a subnode of the node at structure block
+ * offset parentoffset with the given name. name may include a unit
+ * address, in which case fdt_subnode_offset() will find the subnode
+ * with that unit address, or the unit address may be omitted, in
+ * which case fdt_subnode_offset() will find an arbitrary subnode
+ * whose name excluding unit address matches the given name.
+ *
+ * returns:
+ * structure block offset of the requested subnode (>=0), on success
+ * -FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_path_offset - find a tree node by its full path
+ * @fdt: pointer to the device tree blob
+ * @path: full path of the node to locate
+ *
+ * fdt_path_offset() finds a node of a given path in the device tree.
+ * Each path component may omit the unit address portion, but the
+ * results of this are undefined if any such path component is
+ * ambiguous (that is if there are multiple nodes at the relevant
+ * level matching the given component, differentiated only by unit
+ * address).
+ *
+ * returns:
+ * structure block offset of the node with the requested path (>=0), on success
+ * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid
+ * -FDT_ERR_NOTFOUND, if the requested node does not exist
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_path_offset(const void *fdt, const char *path);
+
+/**
+ * fdt_get_name - retrieve the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the starting node
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_name() retrieves the name (including unit address) of the
+ * device tree node at structure block offset nodeoffset. If lenp is
+ * non-NULL, the length of this name is also returned, in the integer
+ * pointed to by lenp.
+ *
+ * returns:
+ * pointer to the node's name, on success
+ * If lenp is non-NULL, *lenp contains the length of that name (>=0)
+ * NULL, on error
+ * if lenp is non-NULL *lenp contains an error code (<0):
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp);
+
+/**
+ * fdt_first_property_offset - find the offset of a node's first property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of a node
+ *
+ * fdt_first_property_offset() finds the first property of the node at
+ * the given structure block offset.
+ *
+ * returns:
+ * structure block offset of the property (>=0), on success
+ * -FDT_ERR_NOTFOUND, if the requested node has no properties
+ * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_first_property_offset(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_next_property_offset - step through a node's properties
+ * @fdt: pointer to the device tree blob
+ * @offset: structure block offset of a property
+ *
+ * fdt_next_property_offset() finds the property immediately after the
+ * one at the given structure block offset. This will be a property
+ * of the same node as the given property.
+ *
+ * returns:
+ * structure block offset of the next property (>=0), on success
+ * -FDT_ERR_NOTFOUND, if the given property is the last in its node
+ * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_next_property_offset(const void *fdt, int offset);
+
+/**
+ * fdt_get_property_by_offset - retrieve the property at a given offset
+ * @fdt: pointer to the device tree blob
+ * @offset: offset of the property to retrieve
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_property_by_offset() retrieves a pointer to the
+ * fdt_property structure within the device tree blob at the given
+ * offset. If lenp is non-NULL, the length of the property value is
+ * also returned, in the integer pointed to by lenp.
+ *
+ * returns:
+ * pointer to the structure representing the property
+ * if lenp is non-NULL, *lenp contains the length of the property
+ * value (>=0)
+ * NULL, on error
+ * if lenp is non-NULL, *lenp contains an error code (<0):
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
+ int offset,
+ int *lenp);
+
+/**
+ * fdt_get_property_namelen - find a property based on substring
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @namelen: number of characters of name to consider
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * Identical to fdt_get_property_namelen(), but only examine the first
+ * namelen characters of name for matching the property name.
+ */
+const struct fdt_property *fdt_get_property_namelen(const void *fdt,
+ int nodeoffset,
+ const char *name,
+ int namelen, int *lenp);
+
+/**
+ * fdt_get_property - find a given property in a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_property() retrieves a pointer to the fdt_property
+ * structure within the device tree blob corresponding to the property
+ * named 'name' of the node at offset nodeoffset. If lenp is
+ * non-NULL, the length of the property value is also returned, in the
+ * integer pointed to by lenp.
+ *
+ * returns:
+ * pointer to the structure representing the property
+ * if lenp is non-NULL, *lenp contains the length of the property
+ * value (>=0)
+ * NULL, on error
+ * if lenp is non-NULL, *lenp contains an error code (<0):
+ * -FDT_ERR_NOTFOUND, node does not have named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset,
+ const char *name, int *lenp);
+static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
+ const char *name,
+ int *lenp)
+{
+ return (struct fdt_property *)(uintptr_t)
+ fdt_get_property(fdt, nodeoffset, name, lenp);
+}
+
+/**
+ * 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
+ * @namep: pointer to a string variable (will be overwritten) or NULL
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_getprop_by_offset() retrieves a pointer to the value of the
+ * property at structure block offset 'offset' (this will be a pointer
+ * to within the device blob itself, not a copy of the value). If
+ * lenp is non-NULL, the length of the property value is also
+ * returned, in the integer pointed to by lenp. If namep is non-NULL,
+ * the property's namne will also be returned in the char * pointed to
+ * by namep (this will be a pointer to within the device tree's string
+ * block, not a new copy of the name).
+ *
+ * returns:
+ * pointer to the property's value
+ * if lenp is non-NULL, *lenp contains the length of the property
+ * value (>=0)
+ * if namep is non-NULL *namep contiains a pointer to the property
+ * name.
+ * NULL, on error
+ * if lenp is non-NULL, *lenp contains an error code (<0):
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+const void *fdt_getprop_by_offset(const void *fdt, int offset,
+ const char **namep, int *lenp);
+
+/**
+ * fdt_getprop_namelen - get property value based on substring
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @namelen: number of characters of name to consider
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * Identical to fdt_getprop(), but only examine the first namelen
+ * characters of name for matching the property name.
+ */
+const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
+ const char *name, int namelen, int *lenp);
+
+/**
+ * fdt_getprop - retrieve the value of a given property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_getprop() retrieves a pointer to the value of the property
+ * named 'name' of the node at offset nodeoffset (this will be a
+ * pointer to within the device blob itself, not a copy of the value).
+ * If lenp is non-NULL, the length of the property value is also
+ * returned, in the integer pointed to by lenp.
+ *
+ * returns:
+ * pointer to the property's value
+ * if lenp is non-NULL, *lenp contains the length of the property
+ * value (>=0)
+ * NULL, on error
+ * if lenp is non-NULL, *lenp contains an error code (<0):
+ * -FDT_ERR_NOTFOUND, node does not have named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+ const char *name, int *lenp);
+static inline void *fdt_getprop_w(void *fdt, int nodeoffset,
+ const char *name, int *lenp)
+{
+ return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp);
+}
+
+/**
+ * fdt_get_phandle - retrieve the phandle of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the node
+ *
+ * fdt_get_phandle() retrieves the phandle of the device tree node at
+ * structure block offset nodeoffset.
+ *
+ * returns:
+ * the phandle of the node at nodeoffset, on success (!= 0, != -1)
+ * 0, if the node has no phandle, or another error occurs
+ */
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_get_alias_namelen - get alias based on substring
+ * @fdt: pointer to the device tree blob
+ * @name: name of the alias th look up
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_get_alias(), but only examine the first namelen
+ * characters of name for matching the alias name.
+ */
+const char *fdt_get_alias_namelen(const void *fdt,
+ const char *name, int namelen);
+
+/**
+ * fdt_get_alias - retreive the path referenced by a given alias
+ * @fdt: pointer to the device tree blob
+ * @name: name of the alias th look up
+ *
+ * fdt_get_alias() retrieves the value of a given alias. That is, the
+ * value of the property named 'name' in the node /aliases.
+ *
+ * returns:
+ * a pointer to the expansion of the alias named 'name', if it exists
+ * NULL, if the given alias or the /aliases node does not exist
+ */
+const char *fdt_get_alias(const void *fdt, const char *name);
+
+/**
+ * fdt_get_path - determine the full path of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose path to find
+ * @buf: character buffer to contain the returned path (will be overwritten)
+ * @buflen: size of the character buffer at buf
+ *
+ * fdt_get_path() computes the full path of the node at offset
+ * nodeoffset, and records that path in the buffer at buf.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ * 0, on success
+ * buf contains the absolute path of the node at
+ * nodeoffset, as a NUL-terminated string.
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1)
+ * characters and will not fit in the given buffer.
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen);
+
+/**
+ * fdt_supernode_atdepth_offset - find a specific ancestor of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ * @supernodedepth: depth of the ancestor to find
+ * @nodedepth: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_supernode_atdepth_offset() finds an ancestor of the given node
+ * at a specific depth from the root (where the root itself has depth
+ * 0, its immediate subnodes depth 1 and so forth). So
+ * fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL);
+ * will always return 0, the offset of the root node. If the node at
+ * nodeoffset has depth D, then:
+ * fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL);
+ * will return nodeoffset itself.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+
+ * structure block offset of the node at node offset's ancestor
+ * of depth supernodedepth (>=0), on success
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+* -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+ int supernodedepth, int *nodedepth);
+
+/**
+ * fdt_node_depth - find the depth of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_node_depth() finds the depth of a given node. The root node
+ * has depth 0, its immediate subnodes depth 1 and so forth.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ * depth of the node at nodeoffset (>=0), on success
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_depth(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_parent_offset - find the parent of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_parent_offset() locates the parent node of a given node (that
+ * is, it finds the offset of the node which contains the node at
+ * nodeoffset as a subnode).
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset, *twice*.
+ *
+ * returns:
+ * structure block offset of the parent of the node at nodeoffset
+ * (>=0), on success
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_parent_offset(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_node_offset_by_prop_value - find nodes with a given property value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @propname: property name to check
+ * @propval: property value to search for
+ * @proplen: length of the value in propval
+ *
+ * fdt_node_offset_by_prop_value() returns the offset of the first
+ * node after startoffset, which has a property named propname whose
+ * value is of length proplen and has value equal to propval; or if
+ * startoffset is -1, the very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ * offset = fdt_node_offset_by_prop_value(fdt, -1, propname,
+ * propval, proplen);
+ * while (offset != -FDT_ERR_NOTFOUND) {
+ * // other code here
+ * offset = fdt_node_offset_by_prop_value(fdt, offset, propname,
+ * propval, proplen);
+ * }
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ * structure block offset of the located node (>= 0, >startoffset),
+ * on success
+ * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ * tree after startoffset
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+ const char *propname,
+ const void *propval, int proplen);
+
+/**
+ * fdt_node_offset_by_phandle - find the node with a given phandle
+ * @fdt: pointer to the device tree blob
+ * @phandle: phandle value
+ *
+ * fdt_node_offset_by_phandle() returns the offset of the node
+ * which has the given phandle value. If there is more than one node
+ * in the tree with the given phandle (an invalid tree), results are
+ * undefined.
+ *
+ * returns:
+ * structure block offset of the located node (>= 0), on success
+ * -FDT_ERR_NOTFOUND, no node with that phandle exists
+ * -FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1)
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle);
+
+/**
+ * fdt_node_check_compatible: check a node's compatible property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @compatible: string to match against
+ *
+ *
+ * fdt_node_check_compatible() returns 0 if the given node contains a
+ * 'compatible' property with the given string as one of its elements,
+ * it returns non-zero otherwise, or on error.
+ *
+ * returns:
+ * 0, if the node has a 'compatible' property listing the given string
+ * 1, if the node has a 'compatible' property, but it does not list
+ * the given string
+ * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property
+ * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+ const char *compatible);
+
+/**
+ * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @compatible: 'compatible' string to match against
+ *
+ * fdt_node_offset_by_compatible() returns the offset of the first
+ * node after startoffset, which has a 'compatible' property which
+ * lists the given compatible string; or if startoffset is -1, the
+ * very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ * offset = fdt_node_offset_by_compatible(fdt, -1, compatible);
+ * while (offset != -FDT_ERR_NOTFOUND) {
+ * // other code here
+ * offset = fdt_node_offset_by_compatible(fdt, offset, compatible);
+ * }
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ * structure block offset of the located node (>= 0, >startoffset),
+ * on success
+ * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ * tree after startoffset
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+ const char *compatible);
+
+/**
+ * fdt_stringlist_contains - check a string list property for a string
+ * @strlist: Property containing a list of strings to check
+ * @listlen: Length of property
+ * @str: String to search for
+ *
+ * This is a utility function provided for convenience. The list contains
+ * one or more strings, each terminated by \0, as is found in a device tree
+ * "compatible" property.
+ *
+ * @return: 1 if the string is found in the list, 0 not found, or invalid list
+ */
+int fdt_stringlist_contains(const char *strlist, int listlen, const char *str);
+
+/**********************************************************************/
+/* Write-in-place functions */
+/**********************************************************************/
+
+/**
+ * fdt_setprop_inplace - change a property's value, but not its size
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to replace the property value with
+ * @len: length of the property value
+ *
+ * fdt_setprop_inplace() replaces the value of a given property with
+ * the data in val, of length len. This function cannot change the
+ * size of a property, and so will only work if len is equal to the
+ * current length of the property.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, if len is not equal to the property's current length
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len);
+
+/**
+ * fdt_setprop_inplace_u32 - change the value of a 32-bit integer property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value to replace the property with
+ *
+ * fdt_setprop_inplace_u32() replaces the value of a given property
+ * with the 32-bit integer value in val, converting val to big-endian
+ * if necessary. This function cannot change the size of a property,
+ * and so will only work if the property already exists and has length
+ * 4.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, if the property's length is not equal to 4
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_inplace_u32(void *fdt, int nodeoffset,
+ const char *name, uint32_t val)
+{
+ fdt32_t tmp = cpu_to_fdt32(val);
+ return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_setprop_inplace_u64 - change the value of a 64-bit integer property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 64-bit integer value to replace the property with
+ *
+ * fdt_setprop_inplace_u64() replaces the value of a given property
+ * with the 64-bit integer value in val, converting val to big-endian
+ * if necessary. This function cannot change the size of a property,
+ * and so will only work if the property already exists and has length
+ * 8.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, if the property's length is not equal to 8
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset,
+ const char *name, uint64_t val)
+{
+ fdt64_t tmp = cpu_to_fdt64(val);
+ return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_setprop_inplace_cell - change the value of a single-cell property
+ *
+ * This is an alternative name for fdt_setprop_inplace_u32()
+ */
+static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset,
+ const char *name, uint32_t val)
+{
+ return fdt_setprop_inplace_u32(fdt, nodeoffset, name, val);
+}
+
+/**
+ * fdt_nop_property - replace a property with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_nop_property() will replace a given property's representation
+ * in the blob with FDT_NOP tags, effectively removing it from the
+ * tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the property, and will not alter or move any other part of the
+ * tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_property(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_nop_node - replace a node (subtree) with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_nop_node() will replace a given node's representation in the
+ * blob, including all its subnodes, if any, with FDT_NOP tags,
+ * effectively removing it from the tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the node and its properties and subnodes, and will not alter or
+ * move any other part of the tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_node(void *fdt, int nodeoffset);
+
+/**********************************************************************/
+/* Sequential write functions */
+/**********************************************************************/
+
+int fdt_create(void *buf, int bufsize);
+int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
+int fdt_finish_reservemap(void *fdt);
+int fdt_begin_node(void *fdt, const char *name);
+int fdt_property(void *fdt, const char *name, const void *val, int len);
+static inline int fdt_property_u32(void *fdt, const char *name, uint32_t val)
+{
+ fdt32_t tmp = cpu_to_fdt32(val);
+ return fdt_property(fdt, name, &tmp, sizeof(tmp));
+}
+static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val)
+{
+ fdt64_t tmp = cpu_to_fdt64(val);
+ return fdt_property(fdt, name, &tmp, sizeof(tmp));
+}
+static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
+{
+ return fdt_property_u32(fdt, name, val);
+}
+#define fdt_property_string(fdt, name, str) \
+ fdt_property(fdt, name, str, strlen(str)+1)
+int fdt_end_node(void *fdt);
+int fdt_finish(void *fdt);
+
+/**********************************************************************/
+/* Read-write functions */
+/**********************************************************************/
+
+int fdt_create_empty_tree(void *buf, int bufsize);
+int fdt_open_into(const void *fdt, void *buf, int bufsize);
+int fdt_pack(void *fdt);
+
+/**
+ * fdt_add_mem_rsv - add one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: 64-bit values (native endian)
+ *
+ * Adds a reserve map entry to the given blob reserving a region at
+ * address address of length size.
+ *
+ * This function will insert data into the reserve map and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new reservation entry
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size);
+
+/**
+ * fdt_del_mem_rsv - remove a memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @n: entry to remove
+ *
+ * fdt_del_mem_rsv() removes the n-th memory reserve map entry from
+ * the blob.
+ *
+ * This function will delete data from the reservation table and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there
+ * are less than n+1 reserve map entries)
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_del_mem_rsv(void *fdt, int n);
+
+/**
+ * fdt_set_name - change the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of a node
+ * @name: name to give the node
+ *
+ * fdt_set_name() replaces the name (including unit address, if any)
+ * of the given node with the given string. NOTE: this function can't
+ * efficiently check if the new name is unique amongst the given
+ * node's siblings; results are undefined if this function is invoked
+ * with a name equal to one of the given node's siblings.
+ *
+ * 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 name
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_set_name(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_setprop - create or change a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to set the property value to
+ * @len: length of the property value
+ *
+ * fdt_setprop() sets the value of the named property in the given
+ * node to the given value and length, creating the property if it
+ * does not already exist.
+ *
+ * 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(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len);
+
+/**
+ * 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
+ * @name: name of the property to change
+ * @val: 32-bit integer value for the property (native endian)
+ *
+ * fdt_setprop_u32() sets the value of the named property in the given
+ * node to the given 32-bit integer value (converting to big-endian if
+ * necessary), or creates a new property with that value if it does
+ * not already exist.
+ *
+ * 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
+ */
+static inline int fdt_setprop_u32(void *fdt, int nodeoffset, const char *name,
+ uint32_t val)
+{
+ fdt32_t tmp = cpu_to_fdt32(val);
+ return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_setprop_u64 - set a property to a 64-bit integer
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 64-bit integer value for the property (native endian)
+ *
+ * fdt_setprop_u64() sets the value of the named property in the given
+ * node to the given 64-bit integer value (converting to big-endian if
+ * necessary), or creates a new property with that value if it does
+ * not already exist.
+ *
+ * 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
+ */
+static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name,
+ uint64_t val)
+{
+ fdt64_t tmp = cpu_to_fdt64(val);
+ return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_setprop_cell - set a property to a single cell value
+ *
+ * This is an alternative name for fdt_setprop_u32()
+ */
+static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
+ uint32_t val)
+{
+ return fdt_setprop_u32(fdt, nodeoffset, name, val);
+}
+
+/**
+ * fdt_setprop_string - set a property to a string value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @str: string value for the property
+ *
+ * fdt_setprop_string() sets the value of the named property in the
+ * given node to the given string value (using the length of the
+ * string to determine the new length of the property), or creates a
+ * new property with that value if it does not already exist.
+ *
+ * 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
+ */
+#define fdt_setprop_string(fdt, nodeoffset, name, str) \
+ fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
+
+/**
+ * fdt_appendprop - append to or create a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to append to
+ * @val: pointer to data to append to the property value
+ * @len: length of the data to append to the property value
+ *
+ * fdt_appendprop() appends the value to the named property in the
+ * given node, creating the property if it does not already exist.
+ *
+ * This function may insert data into 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_appendprop(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len);
+
+/**
+ * fdt_appendprop_u32 - append a 32-bit integer value to a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value to append to the property (native endian)
+ *
+ * fdt_appendprop_u32() appends the given 32-bit integer value
+ * (converting to big-endian if necessary) 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.
+ *
+ * This function may insert data into 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
+ */
+static inline int fdt_appendprop_u32(void *fdt, int nodeoffset,
+ const char *name, uint32_t val)
+{
+ fdt32_t tmp = cpu_to_fdt32(val);
+ return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_appendprop_u64 - append a 64-bit integer value to a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 64-bit integer value to append to the property (native endian)
+ *
+ * fdt_appendprop_u64() appends the given 64-bit integer value
+ * (converting to big-endian if necessary) 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.
+ *
+ * This function may insert data into 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
+ */
+static inline int fdt_appendprop_u64(void *fdt, int nodeoffset,
+ const char *name, uint64_t val)
+{
+ fdt64_t tmp = cpu_to_fdt64(val);
+ return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_appendprop_cell - append a single cell value to a property
+ *
+ * This is an alternative name for fdt_appendprop_u32()
+ */
+static inline int fdt_appendprop_cell(void *fdt, int nodeoffset,
+ const char *name, uint32_t val)
+{
+ return fdt_appendprop_u32(fdt, nodeoffset, name, val);
+}
+
+/**
+ * fdt_appendprop_string - append a string to a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @str: string value to append to the property
+ *
+ * fdt_appendprop_string() appends the given string 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.
+ *
+ * This function may insert data into 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
+ */
+#define fdt_appendprop_string(fdt, nodeoffset, name, str) \
+ fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
+
+/**
+ * fdt_delprop - delete a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_del_property() will delete the given property.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -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_TRUNCATED, standard meanings
+ */
+int fdt_delprop(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_add_subnode_namelen - creates a new node based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_add_subnode(), but use only the first namelen
+ * characters of name as the name of the new node. This is useful for
+ * creating subnodes based on a portion of a larger string, such as a
+ * full path.
+ */
+int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+ const char *name, int namelen);
+
+/**
+ * fdt_add_subnode - creates a new node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_add_subnode() creates a new node as a subnode of the node at
+ * structure block offset parentoffset, with the given name (which
+ * should include the unit address, if any).
+ *
+ * This function will insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+
+ * returns:
+ * structure block offset of the created nodeequested subnode (>=0), on success
+ * -FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of
+ * the given name
+ * -FDT_ERR_NOSPACE, if there is insufficient free space in the
+ * blob to contain the new node
+ * -FDT_ERR_NOSPACE
+ * -FDT_ERR_BADLAYOUT
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_add_subnode(void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_del_node - delete a node (subtree)
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_del_node() will remove the given node, including all its
+ * subnodes if any, from the blob.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -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_TRUNCATED, standard meanings
+ */
+int fdt_del_node(void *fdt, int nodeoffset);
+
+/**********************************************************************/
+/* Debugging / informational functions */
+/**********************************************************************/
+
+const char *fdt_strerror(int errval);
+
+#endif /* _LIBFDT_H */
diff --git a/src/dtc/libfdt/libfdt_env.h b/src/dtc/libfdt/libfdt_env.h
new file mode 100644
index 0000000..9dea97d
--- /dev/null
+++ b/src/dtc/libfdt/libfdt_env.h
@@ -0,0 +1,111 @@
+#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 <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#ifdef __CHECKER__
+#define __force __attribute__((force))
+#define __bitwise __attribute__((bitwise))
+#else
+#define __force
+#define __bitwise
+#endif
+
+typedef uint16_t __bitwise fdt16_t;
+typedef uint32_t __bitwise fdt32_t;
+typedef uint64_t __bitwise fdt64_t;
+
+#define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n])
+#define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1))
+#define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \
+ (EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3))
+#define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \
+ (EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \
+ (EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \
+ (EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7))
+
+static inline uint16_t fdt16_to_cpu(fdt16_t x)
+{
+ return (__force uint16_t)CPU_TO_FDT16(x);
+}
+static inline fdt16_t cpu_to_fdt16(uint16_t x)
+{
+ return (__force fdt16_t)CPU_TO_FDT16(x);
+}
+
+static inline uint32_t fdt32_to_cpu(fdt32_t x)
+{
+ return (__force uint32_t)CPU_TO_FDT32(x);
+}
+static inline fdt32_t cpu_to_fdt32(uint32_t x)
+{
+ return (__force fdt32_t)CPU_TO_FDT32(x);
+}
+
+static inline uint64_t fdt64_to_cpu(fdt64_t x)
+{
+ return (__force uint64_t)CPU_TO_FDT64(x);
+}
+static inline fdt64_t cpu_to_fdt64(uint64_t x)
+{
+ return (__force fdt64_t)CPU_TO_FDT64(x);
+}
+#undef CPU_TO_FDT64
+#undef CPU_TO_FDT32
+#undef CPU_TO_FDT16
+#undef EXTRACT_BYTE
+
+#endif /* _LIBFDT_ENV_H */
diff --git a/src/dtc/libfdt/libfdt_internal.h b/src/dtc/libfdt/libfdt_internal.h
new file mode 100644
index 0000000..381133b
--- /dev/null
+++ b/src/dtc/libfdt/libfdt_internal.h
@@ -0,0 +1,95 @@
+#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; \
+ }
+
+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)
+{
+ return (const char *)fdt + fdt_off_dt_struct(fdt) + offset;
+}
+
+static inline void *_fdt_offset_ptr_w(void *fdt, int 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)
+{
+ const struct fdt_reserve_entry *rsv_table =
+ (const struct fdt_reserve_entry *)
+ ((const char *)fdt + fdt_off_mem_rsvmap(fdt));
+
+ return rsv_table + n;
+}
+static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n)
+{
+ return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n);
+}
+
+#define FDT_SW_MAGIC (~FDT_MAGIC)
+
+#endif /* _LIBFDT_INTERNAL_H */
diff --git a/src/dtc/libfdt/version.lds b/src/dtc/libfdt/version.lds
new file mode 100644
index 0000000..80b322b
--- /dev/null
+++ b/src/dtc/libfdt/version.lds
@@ -0,0 +1,60 @@
+LIBFDT_1.2 {
+ global:
+ fdt_next_node;
+ fdt_check_header;
+ fdt_move;
+ fdt_string;
+ fdt_num_mem_rsv;
+ fdt_get_mem_rsv;
+ fdt_subnode_offset_namelen;
+ fdt_subnode_offset;
+ fdt_path_offset;
+ fdt_get_name;
+ fdt_get_property_namelen;
+ fdt_get_property;
+ fdt_getprop_namelen;
+ fdt_getprop;
+ fdt_get_phandle;
+ fdt_get_alias_namelen;
+ fdt_get_alias;
+ fdt_get_path;
+ fdt_supernode_atdepth_offset;
+ fdt_node_depth;
+ fdt_parent_offset;
+ fdt_node_offset_by_prop_value;
+ fdt_node_offset_by_phandle;
+ fdt_node_check_compatible;
+ fdt_node_offset_by_compatible;
+ fdt_setprop_inplace;
+ fdt_nop_property;
+ fdt_nop_node;
+ fdt_create;
+ fdt_add_reservemap_entry;
+ fdt_finish_reservemap;
+ fdt_begin_node;
+ fdt_property;
+ fdt_end_node;
+ fdt_finish;
+ fdt_open_into;
+ fdt_pack;
+ fdt_add_mem_rsv;
+ fdt_del_mem_rsv;
+ fdt_set_name;
+ fdt_setprop;
+ fdt_delprop;
+ fdt_add_subnode_namelen;
+ fdt_add_subnode;
+ fdt_del_node;
+ fdt_strerror;
+ fdt_offset_ptr;
+ fdt_next_tag;
+ fdt_appendprop;
+ fdt_create_empty_tree;
+ fdt_first_property_offset;
+ fdt_get_property_by_offset;
+ fdt_getprop_by_offset;
+ fdt_next_property_offset;
+
+ local:
+ *;
+};
diff --git a/src/dtc/livetree.c b/src/dtc/livetree.c
new file mode 100644
index 0000000..b61465f
--- /dev/null
+++ b/src/dtc/livetree.c
@@ -0,0 +1,709 @@
+/*
+ * (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"
+
+/*
+ * Tree building functions
+ */
+
+void add_label(struct label **labels, char *label)
+{
+ struct label *new;
+
+ /* Make sure the label isn't already there */
+ for_each_label_withdel(*labels, new)
+ if (streq(new->label, label)) {
+ new->deleted = 0;
+ return;
+ }
+
+ new = xmalloc(sizeof(*new));
+ memset(new, 0, sizeof(*new));
+ new->label = label;
+ new->next = *labels;
+ *labels = new;
+}
+
+void delete_labels(struct label **labels)
+{
+ struct label *label;
+
+ for_each_label(*labels, label)
+ label->deleted = 1;
+}
+
+struct property *build_property(char *name, struct data val)
+{
+ struct property *new = xmalloc(sizeof(*new));
+
+ memset(new, 0, sizeof(*new));
+
+ new->name = name;
+ new->val = val;
+
+ return new;
+}
+
+struct property *build_property_delete(char *name)
+{
+ struct property *new = xmalloc(sizeof(*new));
+
+ memset(new, 0, sizeof(*new));
+
+ new->name = name;
+ new->deleted = 1;
+
+ return new;
+}
+
+struct property *chain_property(struct property *first, struct property *list)
+{
+ assert(first->next == NULL);
+
+ first->next = list;
+ return first;
+}
+
+struct property *reverse_properties(struct property *first)
+{
+ struct property *p = first;
+ struct property *head = NULL;
+ struct property *next;
+
+ while (p) {
+ next = p->next;
+ p->next = head;
+ head = p;
+ p = next;
+ }
+ return head;
+}
+
+struct node *build_node(struct property *proplist, struct node *children)
+{
+ struct node *new = xmalloc(sizeof(*new));
+ struct node *child;
+
+ memset(new, 0, sizeof(*new));
+
+ new->proplist = reverse_properties(proplist);
+ new->children = children;
+
+ for_each_child(new, child) {
+ child->parent = new;
+ }
+
+ return new;
+}
+
+struct node *build_node_delete(void)
+{
+ struct node *new = xmalloc(sizeof(*new));
+
+ memset(new, 0, sizeof(*new));
+
+ new->deleted = 1;
+
+ return new;
+}
+
+struct node *name_node(struct node *node, char *name)
+{
+ assert(node->name == NULL);
+
+ node->name = name;
+
+ return node;
+}
+
+struct node *merge_nodes(struct node *old_node, struct node *new_node)
+{
+ struct property *new_prop, *old_prop;
+ struct node *new_child, *old_child;
+ struct label *l;
+
+ old_node->deleted = 0;
+
+ /* Add new node labels to old node */
+ for_each_label_withdel(new_node->labels, l)
+ add_label(&old_node->labels, l->label);
+
+ /* Move properties from the new node to the old node. If there
+ * is a collision, replace the old value with the new */
+ while (new_node->proplist) {
+ /* Pop the property off the list */
+ new_prop = new_node->proplist;
+ new_node->proplist = new_prop->next;
+ new_prop->next = NULL;
+
+ if (new_prop->deleted) {
+ delete_property_by_name(old_node, new_prop->name);
+ free(new_prop);
+ continue;
+ }
+
+ /* Look for a collision, set new value if there is */
+ for_each_property_withdel(old_node, old_prop) {
+ if (streq(old_prop->name, new_prop->name)) {
+ /* Add new labels to old property */
+ for_each_label_withdel(new_prop->labels, l)
+ add_label(&old_prop->labels, l->label);
+
+ old_prop->val = new_prop->val;
+ old_prop->deleted = 0;
+ free(new_prop);
+ new_prop = NULL;
+ break;
+ }
+ }
+
+ /* if no collision occurred, add property to the old node. */
+ if (new_prop)
+ add_property(old_node, new_prop);
+ }
+
+ /* Move the override child nodes into the primary node. If
+ * there is a collision, then merge the nodes. */
+ while (new_node->children) {
+ /* Pop the child node off the list */
+ new_child = new_node->children;
+ new_node->children = new_child->next_sibling;
+ new_child->parent = NULL;
+ new_child->next_sibling = NULL;
+
+ if (new_child->deleted) {
+ delete_node_by_name(old_node, new_child->name);
+ free(new_child);
+ continue;
+ }
+
+ /* Search for a collision. Merge if there is */
+ for_each_child_withdel(old_node, old_child) {
+ if (streq(old_child->name, new_child->name)) {
+ merge_nodes(old_child, new_child);
+ new_child = NULL;
+ break;
+ }
+ }
+
+ /* if no collision occured, add child to the old node. */
+ if (new_child)
+ add_child(old_node, new_child);
+ }
+
+ /* The new node contents are now merged into the old node. Free
+ * the new node. */
+ free(new_node);
+
+ return old_node;
+}
+
+struct node *chain_node(struct node *first, struct node *list)
+{
+ assert(first->next_sibling == NULL);
+
+ first->next_sibling = list;
+ return first;
+}
+
+void add_property(struct node *node, struct property *prop)
+{
+ struct property **p;
+
+ prop->next = NULL;
+
+ p = &node->proplist;
+ while (*p)
+ p = &((*p)->next);
+
+ *p = prop;
+}
+
+void delete_property_by_name(struct node *node, char *name)
+{
+ struct property *prop = node->proplist;
+
+ while (prop) {
+ if (!strcmp(prop->name, name)) {
+ delete_property(prop);
+ return;
+ }
+ prop = prop->next;
+ }
+}
+
+void delete_property(struct property *prop)
+{
+ prop->deleted = 1;
+ delete_labels(&prop->labels);
+}
+
+void add_child(struct node *parent, struct node *child)
+{
+ struct node **p;
+
+ child->next_sibling = NULL;
+ child->parent = parent;
+
+ p = &parent->children;
+ while (*p)
+ p = &((*p)->next_sibling);
+
+ *p = child;
+}
+
+void delete_node_by_name(struct node *parent, char *name)
+{
+ struct node *node = parent->children;
+
+ while (node) {
+ if (!strcmp(node->name, name)) {
+ delete_node(node);
+ return;
+ }
+ node = node->next_sibling;
+ }
+}
+
+void delete_node(struct node *node)
+{
+ struct property *prop;
+ struct node *child;
+
+ node->deleted = 1;
+ for_each_child(node, child)
+ delete_node(child);
+ for_each_property(node, prop)
+ delete_property(prop);
+ delete_labels(&node->labels);
+}
+
+struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
+{
+ struct reserve_info *new = xmalloc(sizeof(*new));
+
+ memset(new, 0, sizeof(*new));
+
+ new->re.address = address;
+ new->re.size = size;
+
+ return new;
+}
+
+struct reserve_info *chain_reserve_entry(struct reserve_info *first,
+ struct reserve_info *list)
+{
+ assert(first->next == NULL);
+
+ first->next = list;
+ return first;
+}
+
+struct reserve_info *add_reserve_entry(struct reserve_info *list,
+ struct reserve_info *new)
+{
+ struct reserve_info *last;
+
+ new->next = NULL;
+
+ if (! list)
+ return new;
+
+ for (last = list; last->next; last = last->next)
+ ;
+
+ last->next = new;
+
+ return list;
+}
+
+struct boot_info *build_boot_info(struct reserve_info *reservelist,
+ struct node *tree, uint32_t boot_cpuid_phys)
+{
+ struct boot_info *bi;
+
+ bi = xmalloc(sizeof(*bi));
+ bi->reservelist = reservelist;
+ bi->dt = tree;
+ bi->boot_cpuid_phys = boot_cpuid_phys;
+
+ return bi;
+}
+
+/*
+ * Tree accessor functions
+ */
+
+const char *get_unitname(struct node *node)
+{
+ if (node->name[node->basenamelen] == '\0')
+ return "";
+ else
+ return node->name + node->basenamelen + 1;
+}
+
+struct property *get_property(struct node *node, const char *propname)
+{
+ struct property *prop;
+
+ for_each_property(node, prop)
+ if (streq(prop->name, propname))
+ return prop;
+
+ return NULL;
+}
+
+cell_t propval_cell(struct property *prop)
+{
+ assert(prop->val.len == sizeof(cell_t));
+ return fdt32_to_cpu(*((cell_t *)prop->val.val));
+}
+
+struct property *get_property_by_label(struct node *tree, const char *label,
+ struct node **node)
+{
+ struct property *prop;
+ struct node *c;
+
+ *node = tree;
+
+ for_each_property(tree, prop) {
+ struct label *l;
+
+ for_each_label(prop->labels, l)
+ if (streq(l->label, label))
+ return prop;
+ }
+
+ for_each_child(tree, c) {
+ prop = get_property_by_label(c, label, node);
+ if (prop)
+ return prop;
+ }
+
+ *node = NULL;
+ return NULL;
+}
+
+struct marker *get_marker_label(struct node *tree, const char *label,
+ struct node **node, struct property **prop)
+{
+ struct marker *m;
+ struct property *p;
+ struct node *c;
+
+ *node = tree;
+
+ for_each_property(tree, p) {
+ *prop = p;
+ m = p->val.markers;
+ for_each_marker_of_type(m, LABEL)
+ if (streq(m->ref, label))
+ return m;
+ }
+
+ for_each_child(tree, c) {
+ m = get_marker_label(c, label, node, prop);
+ if (m)
+ return m;
+ }
+
+ *prop = NULL;
+ *node = NULL;
+ return NULL;
+}
+
+struct node *get_subnode(struct node *node, const char *nodename)
+{
+ struct node *child;
+
+ for_each_child(node, child)
+ if (streq(child->name, nodename))
+ return child;
+
+ return NULL;
+}
+
+struct node *get_node_by_path(struct node *tree, const char *path)
+{
+ const char *p;
+ struct node *child;
+
+ if (!path || ! (*path)) {
+ if (tree->deleted)
+ return NULL;
+ return tree;
+ }
+
+ while (path[0] == '/')
+ path++;
+
+ p = strchr(path, '/');
+
+ for_each_child(tree, child) {
+ if (p && strneq(path, child->name, p-path))
+ return get_node_by_path(child, p+1);
+ else if (!p && streq(path, child->name))
+ return child;
+ }
+
+ return NULL;
+}
+
+struct node *get_node_by_label(struct node *tree, const char *label)
+{
+ struct node *child, *node;
+ struct label *l;
+
+ assert(label && (strlen(label) > 0));
+
+ for_each_label(tree->labels, l)
+ if (streq(l->label, label))
+ return tree;
+
+ for_each_child(tree, child) {
+ node = get_node_by_label(child, label);
+ if (node)
+ return node;
+ }
+
+ return NULL;
+}
+
+struct node *get_node_by_phandle(struct node *tree, cell_t phandle)
+{
+ struct node *child, *node;
+
+ assert((phandle != 0) && (phandle != -1));
+
+ if (tree->phandle == phandle) {
+ if (tree->deleted)
+ return NULL;
+ return tree;
+ }
+
+ for_each_child(tree, child) {
+ node = get_node_by_phandle(child, phandle);
+ if (node)
+ return node;
+ }
+
+ return NULL;
+}
+
+struct node *get_node_by_ref(struct node *tree, const char *ref)
+{
+ if (ref[0] == '/')
+ return get_node_by_path(tree, ref);
+ else
+ return get_node_by_label(tree, ref);
+}
+
+cell_t get_node_phandle(struct node *root, struct node *node)
+{
+ static cell_t phandle = 1; /* FIXME: ick, static local */
+
+ if ((node->phandle != 0) && (node->phandle != -1))
+ return node->phandle;
+
+ while (get_node_by_phandle(root, phandle))
+ phandle++;
+
+ node->phandle = phandle;
+
+ if (!get_property(node, "linux,phandle")
+ && (phandle_format & PHANDLE_LEGACY))
+ add_property(node,
+ build_property("linux,phandle",
+ data_append_cell(empty_data, phandle)));
+
+ if (!get_property(node, "phandle")
+ && (phandle_format & PHANDLE_EPAPR))
+ add_property(node,
+ build_property("phandle",
+ data_append_cell(empty_data, phandle)));
+
+ /* If the node *does* have a phandle property, we must
+ * be dealing with a self-referencing phandle, which will be
+ * fixed up momentarily in the caller */
+
+ return node->phandle;
+}
+
+uint32_t guess_boot_cpuid(struct node *tree)
+{
+ struct node *cpus, *bootcpu;
+ struct property *reg;
+
+ cpus = get_node_by_path(tree, "/cpus");
+ if (!cpus)
+ return 0;
+
+
+ bootcpu = cpus->children;
+ if (!bootcpu)
+ return 0;
+
+ reg = get_property(bootcpu, "reg");
+ if (!reg || (reg->val.len != sizeof(uint32_t)))
+ return 0;
+
+ /* FIXME: Sanity check node? */
+
+ return propval_cell(reg);
+}
+
+static int cmp_reserve_info(const void *ax, const void *bx)
+{
+ const struct reserve_info *a, *b;
+
+ a = *((const struct reserve_info * const *)ax);
+ b = *((const struct reserve_info * const *)bx);
+
+ if (a->re.address < b->re.address)
+ return -1;
+ else if (a->re.address > b->re.address)
+ return 1;
+ else if (a->re.size < b->re.size)
+ return -1;
+ else if (a->re.size > b->re.size)
+ return 1;
+ else
+ return 0;
+}
+
+static void sort_reserve_entries(struct boot_info *bi)
+{
+ struct reserve_info *ri, **tbl;
+ int n = 0, i = 0;
+
+ for (ri = bi->reservelist;
+ ri;
+ ri = ri->next)
+ n++;
+
+ if (n == 0)
+ return;
+
+ tbl = xmalloc(n * sizeof(*tbl));
+
+ for (ri = bi->reservelist;
+ ri;
+ ri = ri->next)
+ tbl[i++] = ri;
+
+ qsort(tbl, n, sizeof(*tbl), cmp_reserve_info);
+
+ bi->reservelist = tbl[0];
+ for (i = 0; i < (n-1); i++)
+ tbl[i]->next = tbl[i+1];
+ tbl[n-1]->next = NULL;
+
+ free(tbl);
+}
+
+static int cmp_prop(const void *ax, const void *bx)
+{
+ const struct property *a, *b;
+
+ a = *((const struct property * const *)ax);
+ b = *((const struct property * const *)bx);
+
+ return strcmp(a->name, b->name);
+}
+
+static void sort_properties(struct node *node)
+{
+ int n = 0, i = 0;
+ struct property *prop, **tbl;
+
+ for_each_property_withdel(node, prop)
+ n++;
+
+ if (n == 0)
+ return;
+
+ tbl = xmalloc(n * sizeof(*tbl));
+
+ for_each_property_withdel(node, prop)
+ tbl[i++] = prop;
+
+ qsort(tbl, n, sizeof(*tbl), cmp_prop);
+
+ node->proplist = tbl[0];
+ for (i = 0; i < (n-1); i++)
+ tbl[i]->next = tbl[i+1];
+ tbl[n-1]->next = NULL;
+
+ free(tbl);
+}
+
+static int cmp_subnode(const void *ax, const void *bx)
+{
+ const struct node *a, *b;
+
+ a = *((const struct node * const *)ax);
+ b = *((const struct node * const *)bx);
+
+ return strcmp(a->name, b->name);
+}
+
+static void sort_subnodes(struct node *node)
+{
+ int n = 0, i = 0;
+ struct node *subnode, **tbl;
+
+ for_each_child_withdel(node, subnode)
+ n++;
+
+ if (n == 0)
+ return;
+
+ tbl = xmalloc(n * sizeof(*tbl));
+
+ for_each_child_withdel(node, subnode)
+ tbl[i++] = subnode;
+
+ qsort(tbl, n, sizeof(*tbl), cmp_subnode);
+
+ node->children = tbl[0];
+ for (i = 0; i < (n-1); i++)
+ tbl[i]->next_sibling = tbl[i+1];
+ tbl[n-1]->next_sibling = NULL;
+
+ free(tbl);
+}
+
+static void sort_node(struct node *node)
+{
+ struct node *c;
+
+ sort_properties(node);
+ sort_subnodes(node);
+ for_each_child_withdel(node, c)
+ sort_node(c);
+}
+
+void sort_tree(struct boot_info *bi)
+{
+ sort_reserve_entries(bi);
+ sort_node(bi->dt);
+}
diff --git a/src/dtc/scripts/setlocalversion b/src/dtc/scripts/setlocalversion
new file mode 100755
index 0000000..82e4993
--- /dev/null
+++ b/src/dtc/scripts/setlocalversion
@@ -0,0 +1,22 @@
+#!/bin/sh
+# Print additional version information for non-release trees.
+
+usage() {
+ echo "Usage: $0 [srctree]" >&2
+ exit 1
+}
+
+cd "${1:-.}" || usage
+
+# Check for git and a git repo.
+if head=`git rev-parse --verify HEAD 2>/dev/null`; then
+ # Do we have an untagged version?
+ if git name-rev --tags HEAD | grep -E '^HEAD[[:space:]]+(.*~[0-9]*|undefined)$' > /dev/null; then
+ printf '%s%s' -g `echo "$head" | cut -c1-8`
+ fi
+
+ # Are there uncommitted changes?
+ if git diff-index HEAD | read dummy; then
+ printf '%s' -dirty
+ fi
+fi
diff --git a/src/dtc/srcpos.c b/src/dtc/srcpos.c
new file mode 100644
index 0000000..c20bc53
--- /dev/null
+++ b/src/dtc/srcpos.c
@@ -0,0 +1,336 @@
+/*
+ * 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
+
+#include <stdio.h>
+
+#include "dtc.h"
+#include "srcpos.h"
+
+/* A node in our list of directories to search for source/include files */
+struct search_path {
+ struct search_path *next; /* next node in list, NULL for end */
+ const char *dirname; /* name of directory to search */
+};
+
+/* This is the list of directories that we search for source files */
+static struct search_path *search_path_head, **search_path_tail;
+
+
+static char *dirname(const char *path)
+{
+ const char *slash = strrchr(path, '/');
+
+ if (slash) {
+ int len = slash - path;
+ char *dir = xmalloc(len + 1);
+
+ memcpy(dir, path, len);
+ dir[len] = '\0';
+ return dir;
+ }
+ return NULL;
+}
+
+FILE *depfile; /* = NULL */
+struct srcfile_state *current_srcfile; /* = NULL */
+
+/* Detect infinite include recursion. */
+#define MAX_SRCFILE_DEPTH (100)
+static int srcfile_depth; /* = 0 */
+
+
+/**
+ * Try to open a file in a given directory.
+ *
+ * If the filename is an absolute path, then dirname is ignored. If it is a
+ * relative path, then we look in that directory for the file.
+ *
+ * @param dirname Directory to look in, or NULL for none
+ * @param fname Filename to look for
+ * @param fp Set to NULL if file did not open
+ * @return allocated filename on success (caller must free), NULL on failure
+ */
+static char *try_open(const char *dirname, const char *fname, FILE **fp)
+{
+ char *fullname;
+
+ if (!dirname || fname[0] == '/')
+ fullname = xstrdup(fname);
+ else
+ fullname = join_path(dirname, fname);
+
+ *fp = fopen(fullname, "r");
+ if (!*fp) {
+ free(fullname);
+ fullname = NULL;
+ }
+
+ return fullname;
+}
+
+/**
+ * Open a file for read access
+ *
+ * If it is a relative filename, we search the full search path for it.
+ *
+ * @param fname Filename to open
+ * @param fp Returns pointer to opened FILE, or NULL on failure
+ * @return pointer to allocated filename, which caller must free
+ */
+static char *fopen_any_on_path(const char *fname, FILE **fp)
+{
+ const char *cur_dir = NULL;
+ struct search_path *node;
+ char *fullname;
+
+ /* Try current directory first */
+ assert(fp);
+ if (current_srcfile)
+ cur_dir = current_srcfile->dir;
+ fullname = try_open(cur_dir, fname, fp);
+
+ /* Failing that, try each search path in turn */
+ for (node = search_path_head; !*fp && node; node = node->next)
+ fullname = try_open(node->dirname, fname, fp);
+
+ return fullname;
+}
+
+FILE *srcfile_relative_open(const char *fname, char **fullnamep)
+{
+ FILE *f;
+ char *fullname;
+
+ if (streq(fname, "-")) {
+ f = stdin;
+ fullname = xstrdup("<stdin>");
+ } else {
+ fullname = fopen_any_on_path(fname, &f);
+ if (!f)
+ die("Couldn't open \"%s\": %s\n", fname,
+ strerror(errno));
+ }
+
+ if (depfile)
+ fprintf(depfile, " %s", fullname);
+
+ if (fullnamep)
+ *fullnamep = fullname;
+ else
+ free(fullname);
+
+ return f;
+}
+
+void srcfile_push(const char *fname)
+{
+ struct srcfile_state *srcfile;
+
+ if (srcfile_depth++ >= MAX_SRCFILE_DEPTH)
+ die("Includes nested too deeply");
+
+ srcfile = xmalloc(sizeof(*srcfile));
+
+ srcfile->f = srcfile_relative_open(fname, &srcfile->name);
+ srcfile->dir = dirname(srcfile->name);
+ srcfile->prev = current_srcfile;
+
+ srcfile->lineno = 1;
+ srcfile->colno = 1;
+
+ current_srcfile = srcfile;
+}
+
+int srcfile_pop(void)
+{
+ struct srcfile_state *srcfile = current_srcfile;
+
+ assert(srcfile);
+
+ current_srcfile = srcfile->prev;
+
+ if (fclose(srcfile->f))
+ die("Error closing \"%s\": %s\n", srcfile->name,
+ strerror(errno));
+
+ /* FIXME: We allow the srcfile_state structure to leak,
+ * because it could still be referenced from a location
+ * variable being carried through the parser somewhere. To
+ * fix this we could either allocate all the files from a
+ * table, or use a pool allocator. */
+
+ return current_srcfile ? 1 : 0;
+}
+
+void srcfile_add_search_path(const char *dirname)
+{
+ struct search_path *node;
+
+ /* Create the node */
+ node = xmalloc(sizeof(*node));
+ node->next = NULL;
+ node->dirname = xstrdup(dirname);
+
+ /* Add to the end of our list */
+ if (search_path_tail)
+ *search_path_tail = node;
+ else
+ search_path_head = node;
+ 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;
+
+ pos->file = current_srcfile;
+
+ pos->first_line = current_srcfile->lineno;
+ pos->first_column = current_srcfile->colno;
+
+ for (i = 0; i < len; i++)
+ 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++;
+ }
+
+ pos->last_line = current_srcfile->lineno;
+ pos->last_column = current_srcfile->colno;
+}
+
+struct srcpos *
+srcpos_copy(struct srcpos *pos)
+{
+ struct srcpos *pos_new;
+
+ pos_new = xmalloc(sizeof(struct srcpos));
+ memcpy(pos_new, pos, sizeof(struct srcpos));
+
+ return pos_new;
+}
+
+
+
+void
+srcpos_dump(struct srcpos *pos)
+{
+ printf("file : \"%s\"\n",
+ pos->file ? (char *) pos->file : "<no file>");
+ printf("first_line : %d\n", pos->first_line);
+ printf("first_column: %d\n", pos->first_column);
+ printf("last_line : %d\n", pos->last_line);
+ printf("last_column : %d\n", pos->last_column);
+ printf("file : %s\n", pos->file->name);
+}
+
+
+char *
+srcpos_string(struct srcpos *pos)
+{
+ const char *fname = "<no-file>";
+ char *pos_str;
+ int rc;
+
+ if (pos)
+ fname = pos->file->name;
+
+
+ if (pos->first_line != pos->last_line)
+ rc = asprintf(&pos_str, "%s:%d.%d-%d.%d", fname,
+ pos->first_line, pos->first_column,
+ pos->last_line, pos->last_column);
+ else if (pos->first_column != pos->last_column)
+ rc = asprintf(&pos_str, "%s:%d.%d-%d", fname,
+ pos->first_line, pos->first_column,
+ pos->last_column);
+ else
+ rc = asprintf(&pos_str, "%s:%d.%d", fname,
+ pos->first_line, pos->first_column);
+
+ if (rc == -1)
+ die("Couldn't allocate in srcpos string");
+
+ return pos_str;
+}
+
+void
+srcpos_verror(struct srcpos *pos, char const *fmt, va_list va)
+{
+ const char *srcstr;
+
+ srcstr = srcpos_string(pos);
+
+ fprintf(stderr, "Error: %s ", srcstr);
+ vfprintf(stderr, fmt, va);
+ fprintf(stderr, "\n");
+}
+
+void
+srcpos_error(struct srcpos *pos, char const *fmt, ...)
+{
+ va_list va;
+
+ va_start(va, fmt);
+ srcpos_verror(pos, fmt, va);
+ va_end(va);
+}
+
+
+void
+srcpos_warn(struct srcpos *pos, char const *fmt, ...)
+{
+ const char *srcstr;
+ va_list va;
+ va_start(va, fmt);
+
+ srcstr = srcpos_string(pos);
+
+ fprintf(stderr, "Warning: %s ", srcstr);
+ vfprintf(stderr, fmt, va);
+ fprintf(stderr, "\n");
+
+ va_end(va);
+}
+
+void srcpos_set_line(char *f, int l)
+{
+ current_srcfile->name = f;
+ current_srcfile->lineno = l;
+}
diff --git a/src/dtc/srcpos.h b/src/dtc/srcpos.h
new file mode 100644
index 0000000..93a2712
--- /dev/null
+++ b/src/dtc/srcpos.h
@@ -0,0 +1,118 @@
+/*
+ * 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_
+
+#include <stdio.h>
+
+struct srcfile_state {
+ FILE *f;
+ char *name;
+ char *dir;
+ int lineno, colno;
+ struct srcfile_state *prev;
+};
+
+extern FILE *depfile; /* = NULL */
+extern struct srcfile_state *current_srcfile; /* = NULL */
+
+/**
+ * Open a source file.
+ *
+ * If the source file is a relative pathname, then it is searched for in the
+ * current directory (the directory of the last source file read) and after
+ * that in the search path.
+ *
+ * We work through the search path in order from the first path specified to
+ * the last.
+ *
+ * If the file is not found, then this function does not return, but calls
+ * die().
+ *
+ * @param fname Filename to search
+ * @param fullnamep If non-NULL, it is set to the allocated filename of the
+ * file that was opened. The caller is then responsible
+ * for freeing the pointer.
+ * @return pointer to opened FILE
+ */
+FILE *srcfile_relative_open(const char *fname, char **fullnamep);
+
+void srcfile_push(const char *fname);
+int srcfile_pop(void);
+
+/**
+ * Add a new directory to the search path for input files
+ *
+ * The new path is added at the end of the list.
+ *
+ * @param dirname Directory to add
+ */
+void srcfile_add_search_path(const char *dirname);
+
+struct srcpos {
+ int first_line;
+ int first_column;
+ int last_line;
+ int last_column;
+ struct srcfile_state *file;
+};
+
+#define YYLTYPE struct srcpos
+
+#define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do { \
+ if (N) { \
+ (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC(Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC(Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ (Current).file = YYRHSLOC(Rhs, N).file; \
+ } else { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC(Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC(Rhs, 0).last_column; \
+ (Current).file = YYRHSLOC (Rhs, 0).file; \
+ } \
+ } 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 char *srcpos_string(struct srcpos *pos);
+extern void srcpos_dump(struct srcpos *pos);
+
+extern void srcpos_verror(struct srcpos *pos, char const *, va_list va)
+ __attribute__((format(printf, 2, 0)));
+extern void srcpos_error(struct srcpos *pos, char const *, ...)
+ __attribute__((format(printf, 2, 3)));
+extern void srcpos_warn(struct srcpos *pos, char const *, ...)
+ __attribute__((format(printf, 2, 3)));
+
+extern void srcpos_set_line(char *f, int l);
+
+#endif /* _SRCPOS_H_ */
diff --git a/src/dtc/tests/.gitignore b/src/dtc/tests/.gitignore
new file mode 100644
index 0000000..bb5e33a
--- /dev/null
+++ b/src/dtc/tests/.gitignore
@@ -0,0 +1,57 @@
+*.dtb
+*.dts.test.s
+*.test.dts
+tmp.*
+/add_subnode_with_nops
+/appendprop[12]
+/asm_tree_dump
+/boot-cpuid
+/char_literal
+/del_node
+/del_property
+/dtbs_equal_ordered
+/dtbs_equal_unordered
+/dtb_reverse
+/dumptrees
+/extra-terminating-null
+/find_property
+/get_alias
+/get_mem_rsv
+/get_name
+/get_path
+/get_phandle
+/getprop
+/incbin
+/integer-expressions
+/mangle-layout
+/move_and_save
+/node_check_compatible
+/node_offset_by_compatible
+/node_offset_by_phandle
+/node_offset_by_prop_value
+/nop_node
+/nop_property
+/nopulate
+/notfound
+/open_pack
+/parent_offset
+/path-references
+/path_offset
+/path_offset_aliases
+/phandle_format
+/propname_escapes
+/references
+/root_node
+/rw_tree1
+/set_name
+/setprop
+/setprop_inplace
+/sized_cells
+/string_escapes
+/subnode_iterate
+/subnode_offset
+/supernode_atdepth_offset
+/sw_tree1
+/truncated_property
+/utilfdt_test
+/value-labels
diff --git a/src/dtc/tests/Makefile.tests b/src/dtc/tests/Makefile.tests
new file mode 100644
index 0000000..dafb618
--- /dev/null
+++ b/src/dtc/tests/Makefile.tests
@@ -0,0 +1,82 @@
+LIB_TESTS_L = get_mem_rsv \
+ root_node find_property subnode_offset path_offset \
+ get_name getprop 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 \
+ get_alias \
+ char_literal \
+ sized_cells \
+ notfound \
+ setprop_inplace nop_property nop_node \
+ sw_tree1 \
+ move_and_save mangle-layout nopulate \
+ open_pack rw_tree1 set_name setprop del_property del_node \
+ appendprop1 appendprop2 propname_escapes \
+ string_escapes references path-references phandle_format \
+ boot-cpuid incbin \
+ extra-terminating-null \
+ dtbs_equal_ordered \
+ dtb_reverse dtbs_equal_unordered \
+ add_subnode_with_nops path_offset_aliases \
+ utilfdt_test \
+ integer-expressions \
+ subnode_iterate
+LIB_TESTS = $(LIB_TESTS_L:%=$(TESTS_PREFIX)%)
+
+LIBTREE_TESTS_L = truncated_property
+LIBTREE_TESTS = $(LIBTREE_TESTS_L:%=$(TESTS_PREFIX)%)
+
+DL_LIB_TESTS_L = asm_tree_dump value-labels
+DL_LIB_TESTS = $(DL_LIB_TESTS_L:%=$(TESTS_PREFIX)%)
+
+TESTS = $(LIB_TESTS) $(LIBTREE_TESTS) $(DL_LIB_TESTS)
+
+TESTS_TREES_L = test_tree1.dtb
+TESTS_TREES = $(TESTS_TREES_L:%=$(TESTS_PREFIX)%)
+
+TESTS_TARGETS = $(TESTS) $(TESTS_TREES)
+
+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 = $(TESTS) $(TESTS_CLEANFILES_L:%=$(TESTS_PREFIX)%)
+
+.PHONY: tests
+tests: $(TESTS) $(TESTS_TREES)
+
+$(LIB_TESTS): %: $(TESTS_PREFIX)testutils.o util.o $(LIBFDT_archive)
+
+$(DL_LIB_TESTS): %: %.o $(TESTS_PREFIX)testutils.o util.o $(LIBFDT_archive)
+ @$(VECHO) LD [libdl] $@
+ $(LINK.c) -o $@ $^ -ldl
+
+$(LIBTREE_TESTS): %: $(TESTS_PREFIX)testutils.o $(TESTS_PREFIX)trees.o \
+ util.o $(LIBFDT_archive)
+
+$(TESTS_PREFIX)dumptrees: $(TESTS_PREFIX)trees.o
+
+$(TESTS_TREES): $(TESTS_PREFIX)dumptrees
+ @$(VECHO) DUMPTREES
+ cd $(TESTS_PREFIX); ./dumptrees >/dev/null
+
+tests_clean:
+ @$(VECHO) CLEAN "(tests)"
+ rm -f $(STD_CLEANFILES:%=$(TESTS_PREFIX)%)
+ rm -f $(TESTS_CLEANFILES)
+
+check: tests ${TESTS_BIN}
+ cd $(TESTS_PREFIX); ./run_tests.sh
+
+checkm: tests ${TESTS_BIN}
+ cd $(TESTS_PREFIX); ./run_tests.sh -m 2>&1 | tee vglog.$$$$
+
+checkv: tests ${TESTS_BIN}
+ cd $(TESTS_PREFIX); ./run_tests.sh -v
+
+ifneq ($(DEPTARGETS),)
+-include $(TESTS_DEPFILES)
+endif
+
diff --git a/src/dtc/tests/add_subnode_with_nops.c b/src/dtc/tests/add_subnode_with_nops.c
new file mode 100644
index 0000000..95ddf6a
--- /dev/null
+++ b/src/dtc/tests/add_subnode_with_nops.c
@@ -0,0 +1,84 @@
+/*
+ * 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>
+#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(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;
+
+ test_init(argc, argv);
+
+ fdt = xmalloc(SPACE);
+
+ CHECK(fdt_create(fdt, SPACE));
+
+ CHECK(fdt_finish_reservemap(fdt));
+ CHECK(fdt_begin_node(fdt, ""));
+ CHECK(fdt_property_cell(fdt, "prop1", TEST_VALUE_1));
+ CHECK(fdt_property_cell(fdt, "prop2", TEST_VALUE_2));
+ CHECK(fdt_end_node(fdt));
+ CHECK(fdt_finish(fdt));
+
+ verbose_printf("Built empty tree, totalsize = %d\n",
+ fdt_totalsize(fdt));
+
+ CHECK(fdt_open_into(fdt, fdt, SPACE));
+
+ check_getprop_cell(fdt, 0, "prop1", TEST_VALUE_1);
+ check_getprop_cell(fdt, 0, "prop2", TEST_VALUE_2);
+
+ CHECK(fdt_nop_property(fdt, 0, "prop1"));
+
+ check_getprop_cell(fdt, 0, "prop2", TEST_VALUE_2);
+
+ OFF_CHECK(offset, fdt_add_subnode(fdt, 0, "subnode"));
+
+ check_getprop_cell(fdt, 0, "prop2", TEST_VALUE_2);
+
+ PASS();
+}
diff --git a/src/dtc/tests/aliases.dts b/src/dtc/tests/aliases.dts
new file mode 100644
index 0000000..39d88ff
--- /dev/null
+++ b/src/dtc/tests/aliases.dts
@@ -0,0 +1,21 @@
+/dts-v1/;
+
+/ {
+ aliases {
+ s1 = &sub1;
+ ss1 = &subsub1;
+ sss1 = &subsubsub1;
+ };
+
+ sub1: subnode@1 {
+ compatible = "subnode1";
+
+ subsub1: subsubnode {
+ compatible = "subsubnode1", "subsubnode";
+
+ subsubsub1: subsubsubnode {
+ compatible = "subsubsubnode1", "subsubsubnode";
+ };
+ };
+ };
+};
diff --git a/src/dtc/tests/appendprop.dts b/src/dtc/tests/appendprop.dts
new file mode 100644
index 0000000..f4bc730
--- /dev/null
+++ b/src/dtc/tests/appendprop.dts
@@ -0,0 +1,8 @@
+/dts-v1/;
+
+/ {
+ prop-str = "hello world", "nastystring: \a\b\t\n\v\f\r\\\"";
+ prop-int64 = /bits/ 64 <0xdeadbeef01abcdef 0xdeadbeef01abcdef>;
+ prop-int = <0xdeadbeef 123456789>;
+ prop-bytes = [00010203040001020304];
+};
diff --git a/src/dtc/tests/appendprop1.c b/src/dtc/tests/appendprop1.c
new file mode 100644
index 0000000..9d6b3ad
--- /dev/null
+++ b/src/dtc/tests/appendprop1.c
@@ -0,0 +1,70 @@
+/*
+ * 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>
+#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(code) \
+ { \
+ err = (code); \
+ if (err) \
+ FAIL(#code ": %s", fdt_strerror(err)); \
+ }
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ int err;
+ uint8_t bytes[] = {0x00, 0x01, 0x02, 0x03, 0x04};
+
+ test_init(argc, argv);
+
+ /* Create an empty tree first */
+ fdt = xmalloc(SPACE);
+ CHECK(fdt_create(fdt, SPACE));
+ CHECK(fdt_finish_reservemap(fdt));
+ CHECK(fdt_begin_node(fdt, ""));
+ CHECK(fdt_end_node(fdt));
+ CHECK(fdt_finish(fdt));
+
+ /* Now use appendprop to add properties */
+ CHECK(fdt_open_into(fdt, fdt, SPACE));
+
+ CHECK(fdt_appendprop(fdt, 0, "prop-bytes", bytes, sizeof(bytes)));
+ CHECK(fdt_appendprop_cell(fdt, 0, "prop-int", TEST_VALUE_1));
+ CHECK(fdt_appendprop_u64(fdt, 0, "prop-int64", TEST_VALUE64_1));
+ CHECK(fdt_appendprop_string(fdt, 0, "prop-str", TEST_STRING_1));
+
+ CHECK(fdt_pack(fdt));
+
+ save_blob("appendprop1.test.dtb", fdt);
+
+ PASS();
+}
diff --git a/src/dtc/tests/appendprop2.c b/src/dtc/tests/appendprop2.c
new file mode 100644
index 0000000..ca1446c
--- /dev/null
+++ b/src/dtc/tests/appendprop2.c
@@ -0,0 +1,64 @@
+/*
+ * 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>
+#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(code) \
+ { \
+ err = (code); \
+ if (err) \
+ FAIL(#code ": %s", fdt_strerror(err)); \
+ }
+
+int main(int argc, char *argv[])
+{
+ void *fdt, *buf;
+ int err;
+ uint8_t bytes[] = {0x00, 0x01, 0x02, 0x03, 0x04};
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ buf = xmalloc(SPACE);
+ CHECK(fdt_open_into(fdt, buf, SPACE));
+ fdt = buf;
+
+ CHECK(fdt_appendprop(fdt, 0, "prop-bytes", bytes, sizeof(bytes)));
+ CHECK(fdt_appendprop_cell(fdt, 0, "prop-int", TEST_VALUE_2));
+ CHECK(fdt_appendprop_u64(fdt, 0, "prop-int64", TEST_VALUE64_1));
+ CHECK(fdt_appendprop_string(fdt, 0, "prop-str", TEST_STRING_2));
+
+ CHECK(fdt_pack(fdt));
+
+ save_blob("appendprop2.test.dtb", fdt);
+
+ PASS();
+}
diff --git a/src/dtc/tests/asm_tree_dump.c b/src/dtc/tests/asm_tree_dump.c
new file mode 100644
index 0000000..bd12eda
--- /dev/null
+++ b/src/dtc/tests/asm_tree_dump.c
@@ -0,0 +1,61 @@
+/*
+ * 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>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <dlfcn.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+int main(int argc, char *argv[])
+{
+ void *sohandle;
+ void *fdt;
+ int err;
+
+ test_init(argc, argv);
+ if (argc != 3)
+ CONFIG("Usage: %s <so file> <dtb file>", argv[0]);
+
+ sohandle = dlopen(argv[1], RTLD_NOW);
+ if (!sohandle)
+ FAIL("Couldn't dlopen() %s", argv[1]);
+
+ fdt = dlsym(sohandle, "dt_blob_start");
+ if (!fdt)
+ FAIL("Couldn't locate \"dt_blob_start\" symbol in %s",
+ argv[1]);
+
+ err = fdt_check_header(fdt);
+ if (err != 0)
+ FAIL("%s contains invalid tree: %s", argv[1],
+ fdt_strerror(err));
+
+ save_blob(argv[2], fdt);
+
+ PASS();
+}
diff --git a/src/dtc/tests/bad-empty-ranges.dts b/src/dtc/tests/bad-empty-ranges.dts
new file mode 100644
index 0000000..2be7bc8
--- /dev/null
+++ b/src/dtc/tests/bad-empty-ranges.dts
@@ -0,0 +1,11 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ node {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ };
+};
diff --git a/src/dtc/tests/bad-name-property.dts b/src/dtc/tests/bad-name-property.dts
new file mode 100644
index 0000000..4fde4be
--- /dev/null
+++ b/src/dtc/tests/bad-name-property.dts
@@ -0,0 +1,7 @@
+/dts-v1/;
+
+/ {
+ node@0 {
+ name = "badthing";
+ };
+};
diff --git a/src/dtc/tests/bad-ncells.dts b/src/dtc/tests/bad-ncells.dts
new file mode 100644
index 0000000..636198c
--- /dev/null
+++ b/src/dtc/tests/bad-ncells.dts
@@ -0,0 +1,7 @@
+/dts-v1/;
+
+/ {
+ #address-cells = "badthing";
+ #size-cells = "badthing";
+ #interrupt-cells = "badthing";
+};
diff --git a/src/dtc/tests/bad-reg-ranges.dts b/src/dtc/tests/bad-reg-ranges.dts
new file mode 100644
index 0000000..77419f5
--- /dev/null
+++ b/src/dtc/tests/bad-reg-ranges.dts
@@ -0,0 +1,12 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ node {
+ reg = <0 0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0 0>;
+ };
+};
diff --git a/src/dtc/tests/bad-string-props.dts b/src/dtc/tests/bad-string-props.dts
new file mode 100644
index 0000000..396f820
--- /dev/null
+++ b/src/dtc/tests/bad-string-props.dts
@@ -0,0 +1,7 @@
+/dts-v1/;
+
+/ {
+ device_type = <0xdeadbeef>;
+ model = <0xdeadbeef>;
+ status = <0xdeadbeef>;
+};
diff --git a/src/dtc/tests/base01.asm b/src/dtc/tests/base01.asm
new file mode 100644
index 0000000..266e446
--- /dev/null
+++ b/src/dtc/tests/base01.asm
@@ -0,0 +1,175 @@
+/* autogenerated by dtc, do not edit */
+
+#define OF_DT_HEADER 0xd00dfeed
+#define OF_DT_BEGIN_NODE 0x1
+#define OF_DT_END_NODE 0x2
+#define OF_DT_PROP 0x3
+#define OF_DT_END 0x9
+
+ .globl dt_blob_start
+dt_blob_start:
+_dt_blob_start:
+ .globl dt_header
+dt_header:
+_dt_header:
+ .long OF_DT_HEADER /* magic */
+ .long _dt_blob_end - _dt_blob_start /* totalsize */
+ .long _dt_struct_start - _dt_blob_start /* off_dt_struct */
+ .long _dt_strings_start - _dt_blob_start /* off_dt_strings */
+ .long _dt_reserve_map - _dt_blob_start /* off_dt_strings */
+ .long 16 /* version */
+ .long 16 /* last_comp_version */
+ .long 0 /*boot_cpuid_phys*/
+ .long _dt_strings_end - _dt_strings_start /* size_dt_strings */
+ .balign 8
+ .globl dt_reserve_map
+dt_reserve_map:
+_dt_reserve_map:
+/* Memory reserve map from source file */
+ .long 0, 0
+ .long 0, 0
+ .globl dt_struct_start
+dt_struct_start:
+_dt_struct_start:
+ .long OF_DT_BEGIN_NODE
+ .string ""
+ .balign 4
+ .long OF_DT_PROP
+ .long 0xa
+ .long 0x0
+ .long 0x536f6d65
+ .long 0x4d6f6465
+ .short 0x6c00
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x8
+ .long 0x6
+ .long 0x4e6f7468
+ .long 0x696e6700
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x11
+ .long 0x2
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x20
+ .long 0x2
+ .balign 4
+ .long OF_DT_BEGIN_NODE
+ .string "memory@0"
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x7
+ .long 0x2c
+ .long 0x6d656d6f
+ .short 0x7279
+ .byte 0x0
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x10
+ .long 0x38
+ .long 0x0
+ .long 0x0
+ .long 0x0
+ .long 0x20000000
+ .balign 4
+ .long OF_DT_END_NODE
+ .long OF_DT_BEGIN_NODE
+ .string "cpus"
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x11
+ .long 0x1
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x20
+ .long 0x0
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x3c
+ .long 0xa
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x40
+ .long 0x17
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x44
+ .long 0x5
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x49
+ .long 0xf
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x4d
+ .long 0xd00d
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x10
+ .long 0x53
+ .long 0x4d2
+ .long 0x162e
+ .long 0x2334
+ .long 0xd80
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x59
+ .long 0x0
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x61
+ .long 0xffffffff
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x69
+ .long 0x0
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x71
+ .long 0xffffffff
+ .balign 4
+ .long OF_DT_END_NODE
+ .long OF_DT_END_NODE
+ .long OF_DT_END
+ .globl dt_struct_end
+dt_struct_end:
+_dt_struct_end:
+ .globl dt_strings_start
+dt_strings_start:
+_dt_strings_start:
+ .string "model"
+ .string "compatible"
+ .string "#address-cells"
+ .string "#size-cells"
+ .string "device_type"
+ .string "reg"
+ .string "d10"
+ .string "d23"
+ .string "b101"
+ .string "o17"
+ .string "hd00d"
+ .string "stuff"
+ .string "bad-d-1"
+ .string "bad-d-2"
+ .string "bad-o-1"
+ .string "bad-o-2"
+ .globl dt_strings_end
+dt_strings_end:
+_dt_strings_end:
+ .globl dt_blob_end
+dt_blob_end:
+_dt_blob_end:
diff --git a/src/dtc/tests/base01.cmd b/src/dtc/tests/base01.cmd
new file mode 100644
index 0000000..e1fce6c
--- /dev/null
+++ b/src/dtc/tests/base01.cmd
@@ -0,0 +1 @@
+dtc -f -b 0 -V 16 -I dts -O asm
diff --git a/src/dtc/tests/base01.dts b/src/dtc/tests/base01.dts
new file mode 100644
index 0000000..97a5dd5
--- /dev/null
+++ b/src/dtc/tests/base01.dts
@@ -0,0 +1,33 @@
+/dts-v1/;
+
+/ {
+ model = "SomeModel";
+ compatible = "Nothing";
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x00000000 0x00000000 0x20000000>;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ d10 = < 10>; // hex: 0xa
+ d23 = < 23>; // hex: 0x17
+ b101 = < 0x5>; // hex: 0x5
+ o17 = < 017>; // hex: 0xf
+ hd00d = < 0xd00d>; // hex: 0xd00d
+
+ // hex: 0x4d2 0x163e 0x2334 0xd80
+ stuff = < 1234 5678 9012 3456>;
+
+
+ bad-d-1 = < 0>; // Hrm. 0
+ bad-d-2 = < 123456789012345>;
+ bad-o-1 = < 00>;
+ bad-o-2 = < 0123456123456>;
+ };
+
+};
diff --git a/src/dtc/tests/base01.stderr b/src/dtc/tests/base01.stderr
new file mode 100644
index 0000000..0510b0f
--- /dev/null
+++ b/src/dtc/tests/base01.stderr
@@ -0,0 +1,6 @@
+DTC: dts->asm on file "tests/base01.dts"
+Line 26: Invalid cell value '123456789012345'; -1 assumed
+Line 27: Invalid cell value '891'; 0 assumed
+Line 28: Invalid cell value '123456123456'; -1 assumed
+ERROR: Missing /chosen node
+Input tree has errors
diff --git a/src/dtc/tests/boot-cpuid.c b/src/dtc/tests/boot-cpuid.c
new file mode 100644
index 0000000..ca39f4b
--- /dev/null
+++ b/src/dtc/tests/boot-cpuid.c
@@ -0,0 +1,47 @@
+/*
+ * 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>
+#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;
+ uint32_t cpuid;
+
+ test_init(argc, argv);
+
+ if (argc != 3)
+ CONFIG("Usage: %s <dtb file> <cpuid>", argv[0]);
+
+ fdt = load_blob(argv[1]);
+ cpuid = strtoul(argv[2], NULL, 0);
+
+ if (fdt_boot_cpuid_phys(fdt) != cpuid)
+ FAIL("Incorrect boot_cpuid_phys (0x%x instead of 0x%x)",
+ fdt_boot_cpuid_phys(fdt), cpuid);
+
+ PASS();
+}
diff --git a/src/dtc/tests/boot-cpuid.dts b/src/dtc/tests/boot-cpuid.dts
new file mode 100644
index 0000000..7021a24
--- /dev/null
+++ b/src/dtc/tests/boot-cpuid.dts
@@ -0,0 +1,16 @@
+/dts-v1/;
+
+/ {
+ cpus {
+ cpu@10 {
+ device_type = "cpu";
+ compatible = "fake-cpu";
+ reg = <0x10>;
+ };
+ cpu@11 {
+ device_type = "cpu";
+ compatible = "fake-cpu";
+ reg = <0x11>;
+ };
+ };
+};
diff --git a/src/dtc/tests/char_literal.c b/src/dtc/tests/char_literal.c
new file mode 100644
index 0000000..d7a4773
--- /dev/null
+++ b/src/dtc/tests/char_literal.c
@@ -0,0 +1,49 @@
+/*
+ * 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>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ uint32_t expected_cells[5];
+
+ expected_cells[0] = cpu_to_fdt32((unsigned char)TEST_CHAR1);
+ expected_cells[1] = cpu_to_fdt32((unsigned char)TEST_CHAR2);
+ expected_cells[2] = cpu_to_fdt32((unsigned char)TEST_CHAR3);
+ expected_cells[3] = cpu_to_fdt32((unsigned char)TEST_CHAR4);
+ expected_cells[4] = cpu_to_fdt32((unsigned char)TEST_CHAR5);
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ check_getprop(fdt, 0, "char-literal-cells",
+ sizeof(expected_cells), expected_cells);
+
+ PASS();
+}
diff --git a/src/dtc/tests/char_literal.dts b/src/dtc/tests/char_literal.dts
new file mode 100644
index 0000000..22e17ed
--- /dev/null
+++ b/src/dtc/tests/char_literal.dts
@@ -0,0 +1,5 @@
+/dts-v1/;
+
+/ {
+ char-literal-cells = <'\r' 'b' '\0' '\'' '\xff'>;
+};
diff --git a/src/dtc/tests/comments-cmp.dts b/src/dtc/tests/comments-cmp.dts
new file mode 100644
index 0000000..4ee9f52
--- /dev/null
+++ b/src/dtc/tests/comments-cmp.dts
@@ -0,0 +1,16 @@
+/dts-v1/;
+
+/ {
+ prop1;
+ prop2;
+ prop3;
+ prop4;
+ prop5;
+ prop6;
+ prop7;
+ prop8;
+ prop9;
+ prop10;
+ child {
+ };
+};
diff --git a/src/dtc/tests/comments.dts b/src/dtc/tests/comments.dts
new file mode 100644
index 0000000..0b04b6b
--- /dev/null
+++ b/src/dtc/tests/comments.dts
@@ -0,0 +1,39 @@
+/* regexps for lexing comments are.. tricky. Check if we've actually
+ * got it right */
+/dts-v1/;
+
+/ {
+ // line comment
+ prop1;
+ /* comment */
+ prop2;
+ /* multiline
+
+ notaprop1;
+
+ comment */
+ prop3;
+ /**/
+ prop4;
+ /***/
+ prop5;
+ /****/
+ prop6;
+ /* another
+ * multiline
+ * comment */
+ prop7;
+ /* yet
+ * another
+ * multline
+ * comment
+ */
+ prop8;
+ /** try this */
+ prop9;
+ /* and this **/
+ prop10;
+ child /* finally */ {
+ };
+};
+/* final comment */
diff --git a/src/dtc/tests/data.S b/src/dtc/tests/data.S
new file mode 100644
index 0000000..86ad539
--- /dev/null
+++ b/src/dtc/tests/data.S
@@ -0,0 +1,3 @@
+/* Used in combination with dtc -Oasm output to embed
+ * a device tree in the data section of a .o */
+ .data
diff --git a/src/dtc/tests/default-addr-size.dts b/src/dtc/tests/default-addr-size.dts
new file mode 100644
index 0000000..e964a55
--- /dev/null
+++ b/src/dtc/tests/default-addr-size.dts
@@ -0,0 +1,7 @@
+/dts-v1/;
+
+/ {
+ node {
+ reg = <0 0 0>;
+ };
+};
diff --git a/src/dtc/tests/del_node.c b/src/dtc/tests/del_node.c
new file mode 100644
index 0000000..45cb060
--- /dev/null
+++ b/src/dtc/tests/del_node.c
@@ -0,0 +1,123 @@
+/*
+ * 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>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ int subnode1_offset, subnode2_offset, subsubnode2_offset;
+ int err;
+ int oldsize, delsize, newsize;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ fdt = open_blob_rw(fdt);
+
+ oldsize = fdt_totalsize(fdt);
+
+ subnode1_offset = fdt_path_offset(fdt, "/subnode@1");
+ if (subnode1_offset < 0)
+ FAIL("Couldn't find \"/subnode@1\": %s",
+ fdt_strerror(subnode1_offset));
+ check_getprop_cell(fdt, subnode1_offset, "prop-int", TEST_VALUE_1);
+
+ subnode2_offset = fdt_path_offset(fdt, "/subnode@2");
+ if (subnode2_offset < 0)
+ FAIL("Couldn't find \"/subnode@2\": %s",
+ fdt_strerror(subnode2_offset));
+ check_getprop_cell(fdt, subnode2_offset, "prop-int", TEST_VALUE_2);
+
+ subsubnode2_offset = fdt_path_offset(fdt, "/subnode@2/subsubnode");
+ if (subsubnode2_offset < 0)
+ FAIL("Couldn't find \"/subnode@2/subsubnode\": %s",
+ fdt_strerror(subsubnode2_offset));
+ check_getprop_cell(fdt, subsubnode2_offset, "prop-int", TEST_VALUE_2);
+
+ err = fdt_del_node(fdt, subnode1_offset);
+ if (err)
+ FAIL("fdt_del_node(subnode1): %s", fdt_strerror(err));
+
+ subnode1_offset = fdt_path_offset(fdt, "/subnode@1");
+ if (subnode1_offset != -FDT_ERR_NOTFOUND)
+ FAIL("fdt_path_offset(subnode1) returned \"%s\" instead of \"%s\"",
+ fdt_strerror(subnode1_offset),
+ fdt_strerror(-FDT_ERR_NOTFOUND));
+
+ subnode2_offset = fdt_path_offset(fdt, "/subnode@2");
+ if (subnode2_offset < 0)
+ FAIL("Couldn't find \"/subnode2\": %s",
+ fdt_strerror(subnode2_offset));
+ check_getprop_cell(fdt, subnode2_offset, "prop-int", TEST_VALUE_2);
+
+ subsubnode2_offset = fdt_path_offset(fdt, "/subnode@2/subsubnode");
+ if (subsubnode2_offset < 0)
+ FAIL("Couldn't find \"/subnode@2/subsubnode\": %s",
+ fdt_strerror(subsubnode2_offset));
+ check_getprop_cell(fdt, subsubnode2_offset, "prop-int", TEST_VALUE_2);
+
+ err = fdt_del_node(fdt, subnode2_offset);
+ if (err)
+ FAIL("fdt_del_node(subnode2): %s", fdt_strerror(err));
+
+ subnode1_offset = fdt_path_offset(fdt, "/subnode@1");
+ if (subnode1_offset != -FDT_ERR_NOTFOUND)
+ FAIL("fdt_path_offset(subnode1) returned \"%s\" instead of \"%s\"",
+ fdt_strerror(subnode1_offset),
+ fdt_strerror(-FDT_ERR_NOTFOUND));
+
+ subnode2_offset = fdt_path_offset(fdt, "/subnode@2");
+ if (subnode2_offset != -FDT_ERR_NOTFOUND)
+ FAIL("fdt_path_offset(subnode2) returned \"%s\" instead of \"%s\"",
+ fdt_strerror(subnode2_offset),
+ fdt_strerror(-FDT_ERR_NOTFOUND));
+
+ subsubnode2_offset = fdt_path_offset(fdt, "/subnode@2/subsubnode");
+ if (subsubnode2_offset != -FDT_ERR_NOTFOUND)
+ FAIL("fdt_path_offset(subsubnode2) returned \"%s\" instead of \"%s\"",
+ fdt_strerror(subsubnode2_offset),
+ fdt_strerror(-FDT_ERR_NOTFOUND));
+
+ delsize = fdt_totalsize(fdt);
+
+ err = fdt_pack(fdt);
+ if (err)
+ FAIL("fdt_pack(): %s", fdt_strerror(err));
+
+ newsize = fdt_totalsize(fdt);
+
+ verbose_printf("oldsize = %d, delsize = %d, newsize = %d\n",
+ oldsize, delsize, newsize);
+
+ if (newsize >= oldsize)
+ FAIL("Tree failed to shrink after deletions");
+
+ PASS();
+}
diff --git a/src/dtc/tests/del_property.c b/src/dtc/tests/del_property.c
new file mode 100644
index 0000000..42fd7cb
--- /dev/null
+++ b/src/dtc/tests/del_property.c
@@ -0,0 +1,90 @@
+/*
+ * 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>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ const uint32_t *intp;
+ const char *strp;
+ int err, lenerr;
+ int oldsize, delsize, newsize;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ fdt = open_blob_rw(fdt);
+
+ oldsize = fdt_totalsize(fdt);
+
+ intp = check_getprop_cell(fdt, 0, "prop-int", TEST_VALUE_1);
+ verbose_printf("int value was 0x%08x\n", *intp);
+
+ err = fdt_delprop(fdt, 0, "prop-int");
+ if (err)
+ FAIL("Failed to delete \"prop-int\": %s", fdt_strerror(err));
+
+ intp = fdt_getprop(fdt, 0, "prop-int", &lenerr);
+ if (intp)
+ FAIL("prop-int still present after deletion");
+ if (lenerr != -FDT_ERR_NOTFOUND)
+ FAIL("Unexpected error on second getprop: %s",
+ fdt_strerror(lenerr));
+
+ strp = check_getprop(fdt, 0, "prop-str", strlen(TEST_STRING_1)+1,
+ TEST_STRING_1);
+ verbose_printf("string value was \"%s\"\n", strp);
+ err = fdt_delprop(fdt, 0, "prop-str");
+ if (err)
+ FAIL("Failed to delete \"prop-str\": %s", fdt_strerror(err));
+
+ strp = fdt_getprop(fdt, 0, "prop-str", &lenerr);
+ if (strp)
+ FAIL("prop-str still present after deletion");
+ if (lenerr != -FDT_ERR_NOTFOUND)
+ FAIL("Unexpected error on second getprop: %s",
+ fdt_strerror(lenerr));
+
+ delsize = fdt_totalsize(fdt);
+
+ err = fdt_pack(fdt);
+ if (err)
+ FAIL("fdt_pack(): %s\n", fdt_strerror(err));
+
+ newsize = fdt_totalsize(fdt);
+
+ verbose_printf("oldsize = %d, delsize = %d, newsize = %d\n",
+ oldsize, delsize, newsize);
+
+ if (newsize >= oldsize)
+ FAIL("Tree failed to shrink after deletions");
+
+ PASS();
+}
diff --git a/src/dtc/tests/delete_reinstate_multilabel.dts b/src/dtc/tests/delete_reinstate_multilabel.dts
new file mode 100644
index 0000000..281a6b2
--- /dev/null
+++ b/src/dtc/tests/delete_reinstate_multilabel.dts
@@ -0,0 +1,37 @@
+/dts-v1/;
+
+/* Create some nodes and properties with multiple labels */
+
+/ {
+ label1: label2: prop = "value";
+
+ label3: label4: node {
+ label5: label6: prop = "value";
+ };
+};
+
+/* Delete them, and everything that's part of them, i.e. the labels */
+
+/ {
+ /delete-property/ prop;
+ /delete-node/ node;
+};
+
+/*
+ * Re-instate them. None of the old labels should come back
+ *
+ * Note: Do not add any new/extra labels here. As of the time of writing,
+ * when dtc adds labels to an object, they are added to the head of the list
+ * of labels, and this test is specifically about ensuring the correct
+ * handling of lists of labels where the first label in the list is marked as
+ * deleted. Failure to observe this note may result in the test passing when
+ * it should not.
+ */
+
+/ {
+ prop = "value";
+
+ node {
+ prop = "value";
+ };
+};
diff --git a/src/dtc/tests/delete_reinstate_multilabel_ref.dts b/src/dtc/tests/delete_reinstate_multilabel_ref.dts
new file mode 100644
index 0000000..28fa117
--- /dev/null
+++ b/src/dtc/tests/delete_reinstate_multilabel_ref.dts
@@ -0,0 +1,9 @@
+/dts-v1/;
+
+/ {
+ prop = "value";
+
+ node {
+ prop = "value";
+ };
+};
diff --git a/src/dtc/tests/dependencies.cmp b/src/dtc/tests/dependencies.cmp
new file mode 100644
index 0000000..bcd9432
--- /dev/null
+++ b/src/dtc/tests/dependencies.cmp
@@ -0,0 +1 @@
+dependencies.test.dtb: dependencies.dts deps_inc1.dtsi deps_inc2.dtsi
diff --git a/src/dtc/tests/dependencies.dts b/src/dtc/tests/dependencies.dts
new file mode 100644
index 0000000..2cfe31b
--- /dev/null
+++ b/src/dtc/tests/dependencies.dts
@@ -0,0 +1,6 @@
+/dts-v1/;
+
+/include/ "deps_inc1.dtsi"
+
+/ {
+};
diff --git a/src/dtc/tests/deps_inc1.dtsi b/src/dtc/tests/deps_inc1.dtsi
new file mode 100644
index 0000000..5c607dc
--- /dev/null
+++ b/src/dtc/tests/deps_inc1.dtsi
@@ -0,0 +1 @@
+/include/ "deps_inc2.dtsi"
diff --git a/src/dtc/tests/deps_inc2.dtsi b/src/dtc/tests/deps_inc2.dtsi
new file mode 100644
index 0000000..710cecc
--- /dev/null
+++ b/src/dtc/tests/deps_inc2.dtsi
@@ -0,0 +1 @@
+/* Empty */
diff --git a/src/dtc/tests/dtb_reverse.c b/src/dtc/tests/dtb_reverse.c
new file mode 100644
index 0000000..527fd71
--- /dev/null
+++ b/src/dtc/tests/dtb_reverse.c
@@ -0,0 +1,163 @@
+/*
+ * 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>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <limits.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+#define CHECK(code) \
+ { \
+ err = (code); \
+ if (err) \
+ FAIL(#code ": %s", fdt_strerror(err)); \
+ }
+
+static void reverse_reservemap(void *in, void *out, int n)
+{
+ int err;
+ uint64_t addr, size;
+
+ verbose_printf("reverse_reservemap(): %d/%d\n",
+ n, fdt_num_mem_rsv(in));
+
+ if (n < (fdt_num_mem_rsv(in)-1))
+ reverse_reservemap(in, out, n+1);
+
+ CHECK(fdt_get_mem_rsv(in, n, &addr, &size));
+ CHECK(fdt_add_reservemap_entry(out, addr, size));
+ verbose_printf("Added entry 0x%llx 0x%llx\n",
+ (unsigned long long)addr, (unsigned long long)size);
+}
+
+static void reverse_properties(void *in, void *out, int offset)
+{
+ int err;
+ int len;
+ const char *name;
+ const void *data;
+
+ data = fdt_getprop_by_offset(in, offset, &name, &len);
+ if (!data)
+ FAIL("fdt_getprop_by_offset(): %s\n", fdt_strerror(len));
+
+ verbose_printf("reverse_properties(): offset=%d name=%s\n",
+ offset, name);
+
+ offset = fdt_next_property_offset(in, offset);
+ if (offset >= 0)
+ reverse_properties(in, out, offset);
+ else if (offset != -FDT_ERR_NOTFOUND)
+ FAIL("fdt_next_property_offset(): %s\n", fdt_strerror(offset));
+
+ CHECK(fdt_property(out, name, data, len));
+ verbose_printf(" -> output property %s\n", name);
+}
+
+static void reverse_node(void *in, void *out, int nodeoffset);
+
+static void reverse_children(void *in, void *out, int offset)
+{
+ int err;
+ int nextoffset = offset;
+ int depth = 1;
+
+ do {
+ char path[PATH_MAX];
+
+ CHECK(fdt_get_path(in, nextoffset, path, sizeof(path)));
+ verbose_printf("reverse_children() offset=%d nextoffset=%d [%s]"
+ " depth=%d\n", offset, nextoffset, path, depth);
+
+ nextoffset = fdt_next_node(in, nextoffset, &depth);
+ } while ((depth >= 0) && (depth != 1));
+
+ if (depth == 1)
+ reverse_children(in, out, nextoffset);
+
+ reverse_node(in, out, offset);
+}
+
+static void reverse_node(void *in, void *out, int nodeoffset)
+{
+ const char *name = fdt_get_name(in, nodeoffset, NULL);
+ char path[PATH_MAX];
+ int err;
+ int offset;
+ int depth = 0;
+
+ CHECK(fdt_get_path(in, nodeoffset, path, sizeof(path)));
+ verbose_printf("reverse_node(): nodeoffset=%d [%s]\n",
+ nodeoffset, path);
+
+ CHECK(fdt_begin_node(out, name));
+
+ offset = fdt_first_property_offset(in, nodeoffset);
+ if (offset >= 0)
+ reverse_properties(in, out, offset);
+ else if (offset != -FDT_ERR_NOTFOUND)
+ FAIL("fdt_first_property(): %s\n", fdt_strerror(offset));
+
+ offset = fdt_next_node(in, nodeoffset, &depth);
+
+ if (depth == 1)
+ reverse_children(in, out, offset);
+
+ CHECK(fdt_end_node(out));
+}
+
+int main(int argc, char *argv[])
+{
+ void *in, *out;
+ char outname[PATH_MAX];
+ int bufsize;
+ int err;
+
+ test_init(argc, argv);
+ if (argc != 2)
+ CONFIG("Usage: %s <dtb file>", argv[0]);
+
+ in = load_blob(argv[1]);
+ sprintf(outname, "%s.reversed.test.dtb", argv[1]);
+
+ bufsize = fdt_totalsize(in);
+ out = xmalloc(bufsize);
+
+ CHECK(fdt_create(out, bufsize));
+
+ fdt_set_boot_cpuid_phys(out, fdt_boot_cpuid_phys(in));
+
+ reverse_reservemap(in, out, 0);
+ CHECK(fdt_finish_reservemap(out));
+
+ reverse_node(in, out, 0);
+
+ CHECK(fdt_finish(out));
+
+ save_blob(outname, out);
+
+ PASS();
+}
diff --git a/src/dtc/tests/dtbs_equal_ordered.c b/src/dtc/tests/dtbs_equal_ordered.c
new file mode 100644
index 0000000..12495de
--- /dev/null
+++ b/src/dtc/tests/dtbs_equal_ordered.c
@@ -0,0 +1,173 @@
+/*
+ * 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>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+int notequal; /* = 0 */
+
+#define MISMATCH(fmt, ...) \
+ do { \
+ if (notequal) \
+ PASS(); \
+ else \
+ FAIL(fmt, ##__VA_ARGS__); \
+ } while (0)
+
+#define MATCH() \
+ do { \
+ if (!notequal) \
+ PASS(); \
+ else \
+ FAIL("Trees match which shouldn't"); \
+ } while (0)
+
+#define CHECK(code) \
+ { \
+ err = (code); \
+ if (err) \
+ FAIL(#code ": %s", fdt_strerror(err)); \
+ }
+
+static void compare_mem_rsv(const void *fdt1, const void *fdt2)
+{
+ int i;
+ uint64_t addr1, size1, addr2, size2;
+ int err;
+
+ if (fdt_num_mem_rsv(fdt1) != fdt_num_mem_rsv(fdt2))
+ MISMATCH("Trees have different number of reserve entries");
+ for (i = 0; i < fdt_num_mem_rsv(fdt1); i++) {
+ CHECK(fdt_get_mem_rsv(fdt1, i, &addr1, &size1));
+ CHECK(fdt_get_mem_rsv(fdt2, i, &addr2, &size2));
+
+ if ((addr1 != addr2) || (size1 != size2))
+ MISMATCH("Mismatch in reserve entry %d: "
+ "(0x%llx, 0x%llx) != (0x%llx, 0x%llx)", i,
+ (unsigned long long)addr1,
+ (unsigned long long)size1,
+ (unsigned long long)addr2,
+ (unsigned long long)size2);
+ }
+}
+
+static void compare_structure(const void *fdt1, const void *fdt2)
+{
+ int nextoffset1 = 0, nextoffset2 = 0;
+ int offset1, offset2;
+ uint32_t tag1, tag2;
+ const char *name1, *name2;
+ int err;
+ const struct fdt_property *prop1, *prop2;
+ int len1, len2;
+
+ while (1) {
+ do {
+ offset1 = nextoffset1;
+ tag1 = fdt_next_tag(fdt1, offset1, &nextoffset1);
+ } while (tag1 == FDT_NOP);
+ do {
+ offset2 = nextoffset2;
+ tag2 = fdt_next_tag(fdt2, offset2, &nextoffset2);
+ } while (tag2 == FDT_NOP);
+
+ if (tag1 != tag2)
+ MISMATCH("Tag mismatch (%d != %d) at (%d, %d)",
+ tag1, tag2, offset1, offset2);
+
+ switch (tag1) {
+ case FDT_BEGIN_NODE:
+ name1 = fdt_get_name(fdt1, offset1, &err);
+ if (!name1)
+ FAIL("fdt_get_name(fdt1, %d, ..): %s",
+ offset1, fdt_strerror(err));
+ name2 = fdt_get_name(fdt2, offset2, NULL);
+ if (!name2)
+ FAIL("fdt_get_name(fdt2, %d, ..): %s",
+ offset2, fdt_strerror(err));
+
+ if (!streq(name1, name2))
+ MISMATCH("Name mismatch (\"%s\" != \"%s\") at (%d, %d)",
+ name1, name2, offset1, offset2);
+ break;
+
+ case FDT_PROP:
+ prop1 = fdt_offset_ptr(fdt1, offset1, sizeof(*prop1));
+ if (!prop1)
+ FAIL("Could get fdt1 property at %d", offset1);
+ prop2 = fdt_offset_ptr(fdt2, offset2, sizeof(*prop2));
+ if (!prop2)
+ FAIL("Could get fdt2 property at %d", offset2);
+
+ name1 = fdt_string(fdt1, fdt32_to_cpu(prop1->nameoff));
+ name2 = fdt_string(fdt2, fdt32_to_cpu(prop2->nameoff));
+ if (!streq(name1, name2))
+ MISMATCH("Property name mismatch \"%s\" != \"%s\" "
+ "at (%d, %d)", name1, name2, offset1, offset2);
+ len1 = fdt32_to_cpu(prop1->len);
+ len2 = fdt32_to_cpu(prop2->len);
+ if (len1 != len2)
+ MISMATCH("Property length mismatch %u != %u "
+ "at (%d, %d)", len1, len2, offset1, offset2);
+
+ if (memcmp(prop1->data, prop2->data, len1) != 0)
+ MISMATCH("Property value mismatch at (%d, %d)",
+ offset1, offset2);
+ break;
+
+ case FDT_END:
+ return;
+ }
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ void *fdt1, *fdt2;
+ uint32_t cpuid1, cpuid2;
+
+ 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]);
+
+ compare_mem_rsv(fdt1, fdt2);
+ compare_structure(fdt1, fdt2);
+
+ cpuid1 = fdt_boot_cpuid_phys(fdt1);
+ cpuid2 = fdt_boot_cpuid_phys(fdt2);
+ if (cpuid1 != cpuid2)
+ MISMATCH("boot_cpuid_phys mismatch 0x%x != 0x%x",
+ cpuid1, cpuid2);
+
+ MATCH();
+}
diff --git a/src/dtc/tests/dtbs_equal_unordered.c b/src/dtc/tests/dtbs_equal_unordered.c
new file mode 100644
index 0000000..20b4356
--- /dev/null
+++ b/src/dtc/tests/dtbs_equal_unordered.c
@@ -0,0 +1,223 @@
+/*
+ * 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>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <limits.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+int notequal; /* = 0 */
+
+#define MISMATCH(fmt, ...) \
+ do { \
+ if (notequal) \
+ PASS(); \
+ else \
+ FAIL(fmt, ##__VA_ARGS__); \
+ } while (0)
+
+#define MATCH() \
+ do { \
+ if (!notequal) \
+ PASS(); \
+ else \
+ FAIL("Trees match which shouldn't"); \
+ } while (0)
+
+#define CHECK(code) \
+ { \
+ err = (code); \
+ if (err) \
+ FAIL(#code ": %s", fdt_strerror(err)); \
+ }
+
+static int mem_rsv_cmp(const void *p1, const void *p2)
+{
+ const struct fdt_reserve_entry *re1 = p1;
+ const struct fdt_reserve_entry *re2 = p2;
+
+ if (re1->address < re2->address)
+ return -1;
+ else if (re1->address > re2->address)
+ return 1;
+
+ if (re1->size < re2->size)
+ return -1;
+ else if (re1->size > re2->size)
+ return 1;
+
+ return 0;
+}
+
+static void compare_mem_rsv(void *fdt1, void *fdt2)
+{
+ int i;
+ uint64_t addr1, size1, addr2, size2;
+ int err;
+
+ if (fdt_num_mem_rsv(fdt1) != fdt_num_mem_rsv(fdt2))
+ MISMATCH("Trees have different number of reserve entries");
+
+ qsort((char *)fdt1 + fdt_off_mem_rsvmap(fdt1), fdt_num_mem_rsv(fdt1),
+ sizeof(struct fdt_reserve_entry), mem_rsv_cmp);
+ qsort((char *)fdt2 + fdt_off_mem_rsvmap(fdt2), fdt_num_mem_rsv(fdt2),
+ sizeof(struct fdt_reserve_entry), mem_rsv_cmp);
+
+ for (i = 0; i < fdt_num_mem_rsv(fdt1); i++) {
+ CHECK(fdt_get_mem_rsv(fdt1, i, &addr1, &size1));
+ CHECK(fdt_get_mem_rsv(fdt2, i, &addr2, &size2));
+
+ if ((addr1 != addr2) || (size1 != size2))
+ MISMATCH("Mismatch in reserve entry %d: "
+ "(0x%llx, 0x%llx) != (0x%llx, 0x%llx)", i,
+ (unsigned long long)addr1,
+ (unsigned long long)size1,
+ (unsigned long long)addr2,
+ (unsigned long long)size2);
+ }
+}
+
+static void compare_properties(const void *fdt1, int offset1,
+ const void *fdt2, int offset2)
+{
+ int offset = offset1;
+
+ /* Check the properties */
+ for (offset = fdt_first_property_offset(fdt1, offset1);
+ offset >= 0;
+ offset = fdt_next_property_offset(fdt1, offset)) {
+ const char *name;
+ int len1, len2;
+ const void *data1, *data2;
+ int i;
+
+ data1 = fdt_getprop_by_offset(fdt1, offset, &name, &len1);
+ if (!data1)
+ FAIL("fdt_getprop_by_offset(): %s\n",
+ fdt_strerror(len1));
+
+ verbose_printf("Property '%s'\n", name);
+
+ data2 = fdt_getprop(fdt2, offset2, name, &len2);
+ if (!data2) {
+ if (len2 == -FDT_ERR_NOTFOUND)
+ MISMATCH("Property '%s' missing\n", name);
+ else
+ FAIL("fdt_get_property(): %s\n",
+ fdt_strerror(len2));
+ }
+
+ verbose_printf("len1=%d data1=", len1);
+ for (i = 0; i < len1; i++)
+ verbose_printf(" %02x", ((const char *)data1)[i]);
+ verbose_printf("\nlen2=%d data2=", len2);
+ for (i = 0; i < len1; i++)
+ verbose_printf(" %02x", ((const char *)data2)[i]);
+ verbose_printf("\n");
+
+ if (len1 != len2)
+ MISMATCH("Property '%s' mismatched length %d vs. %d\n",
+ name, len1, len2);
+ else if (memcmp(data1, data2, len1) != 0)
+ MISMATCH("Property '%s' mismatched value\n", name);
+ }
+}
+
+static void compare_node(const void *fdt1, int offset1,
+ const void *fdt2, int offset2);
+
+static void compare_subnodes(const void *fdt1, int offset1,
+ const void *fdt2, int offset2,
+ int recurse)
+{
+ int coffset1, coffset2, depth;
+
+ for (depth = 0, coffset1 = offset1;
+ (coffset1 >= 0) && (depth >= 0);
+ coffset1 = fdt_next_node(fdt1, coffset1, &depth))
+ if (depth == 1) {
+ const char *name = fdt_get_name(fdt1, coffset1, NULL);
+
+ verbose_printf("Subnode %s\n", name);
+ coffset2 = fdt_subnode_offset(fdt2, offset2, name);
+ if (coffset2 == -FDT_ERR_NOTFOUND)
+ MISMATCH("Subnode %s missing\n", name);
+ else if (coffset2 < 0)
+ FAIL("fdt_subnode_offset(): %s\n",
+ fdt_strerror(coffset2));
+
+ if (recurse)
+ compare_node(fdt1, coffset1, fdt2, coffset2);
+ }
+}
+
+static void compare_node(const void *fdt1, int offset1,
+ const void *fdt2, int offset2)
+{
+ int err;
+ char path1[PATH_MAX], path2[PATH_MAX];
+
+ CHECK(fdt_get_path(fdt1, offset1, path1, sizeof(path1)));
+ CHECK(fdt_get_path(fdt2, offset2, path2, sizeof(path2)));
+
+ if (!streq(path1, path2))
+ TEST_BUG("Path mismatch %s vs. %s\n", path1, path2);
+
+ verbose_printf("Checking %s\n", path1);
+
+ compare_properties(fdt1, offset1, fdt2, offset2);
+ compare_properties(fdt2, offset2, fdt1, offset1);
+
+ compare_subnodes(fdt1, offset1, fdt2, offset2, 1);
+ compare_subnodes(fdt2, offset2, fdt1, offset1, 0);
+}
+
+int main(int argc, char *argv[])
+{
+ void *fdt1, *fdt2;
+ uint32_t cpuid1, cpuid2;
+
+ 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]);
+
+ compare_mem_rsv(fdt1, fdt2);
+ compare_node(fdt1, 0, fdt2, 0);
+
+ cpuid1 = fdt_boot_cpuid_phys(fdt1);
+ cpuid2 = fdt_boot_cpuid_phys(fdt2);
+ if (cpuid1 != cpuid2)
+ MISMATCH("boot_cpuid_phys mismatch 0x%x != 0x%x",
+ cpuid1, cpuid2);
+
+ MATCH();
+}
diff --git a/src/dtc/tests/dtc-checkfails.sh b/src/dtc/tests/dtc-checkfails.sh
new file mode 100755
index 0000000..76ded15
--- /dev/null
+++ b/src/dtc/tests/dtc-checkfails.sh
@@ -0,0 +1,44 @@
+#! /bin/sh
+
+. ./tests.sh
+
+for x; do
+ shift
+ if [ "$x" = "-n" ]; then
+ for x; do
+ shift
+ if [ "$x" = "--" ]; then
+ break;
+ fi
+ NOCHECKS="$NOCHECKS $x"
+ done
+ break;
+ fi
+ if [ "$x" = "--" ]; then
+ break;
+ fi
+ YESCHECKS="$YESCHECKS $x"
+done
+
+LOG=tmp.log.$$
+rm -f $LOG
+trap "rm -f $LOG" 0
+
+verbose_run_log "$LOG" $VALGRIND "$DTC" -o /dev/null "$@"
+ret="$?"
+
+FAIL_IF_SIGNAL $ret
+
+for c in $YESCHECKS; do
+ 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
+ FAIL "Incorrectly triggered check \"$c\""
+ fi
+done
+
+PASS
diff --git a/src/dtc/tests/dtc-fails.sh b/src/dtc/tests/dtc-fails.sh
new file mode 100755
index 0000000..4ddcb27
--- /dev/null
+++ b/src/dtc/tests/dtc-fails.sh
@@ -0,0 +1,30 @@
+#! /bin/sh
+
+. ./tests.sh
+
+if [ "$1" = "-n" ]; then
+ NEG="$1"
+ shift
+fi
+
+OUTPUT="$1"
+shift
+
+verbose_run $VALGRIND "$DTC" -o "$OUTPUT" "$@"
+ret="$?"
+
+FAIL_IF_SIGNAL $ret
+
+if [ -n "$NEG" ]; then
+ if [ ! -e "$OUTPUT" ]; then
+ FAIL "Produced no output"
+ fi
+else
+ if [ -e "$OUTPUT" ]; then
+ FAIL "Incorrectly produced output"
+ fi
+fi
+
+rm -f "$OUTPUT"
+
+PASS
diff --git a/src/dtc/tests/dtc-fatal.sh b/src/dtc/tests/dtc-fatal.sh
new file mode 100644
index 0000000..6781ced
--- /dev/null
+++ b/src/dtc/tests/dtc-fatal.sh
@@ -0,0 +1,14 @@
+#! /bin/sh
+
+. ./tests.sh
+
+verbose_run $VALGRIND "$DTC" -o/dev/null "$@"
+ret="$?"
+
+if [ "$ret" -gt 127 ]; then
+ FAIL "dtc killed by signal (ret=$ret)"
+elif [ "$ret" != "1" ]; then
+ FAIL "dtc returned incorrect status $ret instead of 1"
+fi
+
+PASS
diff --git a/src/dtc/tests/dumptrees.c b/src/dtc/tests/dumptrees.c
new file mode 100644
index 0000000..bebf553
--- /dev/null
+++ b/src/dtc/tests/dumptrees.c
@@ -0,0 +1,69 @@
+/*
+ * 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>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "testdata.h"
+
+struct {
+ void *blob;
+ const char *filename;
+} trees[] = {
+#define TREE(name) { &_##name, #name ".dtb" }
+ TREE(test_tree1),
+ TREE(bad_node_char), TREE(bad_node_format), TREE(bad_prop_char),
+};
+
+#define NUM_TREES (sizeof(trees) / sizeof(trees[0]))
+
+int main(int argc, char *argv[])
+{
+ int i;
+
+ for (i = 0; i < NUM_TREES; i++) {
+ void *blob = trees[i].blob;
+ const char *filename = trees[i].filename;
+ int size;
+ int fd;
+ int ret;
+
+ size = fdt_totalsize(blob);
+
+ printf("Tree \"%s\", %d bytes\n", filename, size);
+
+ fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (fd < 0)
+ perror("open()");
+
+ ret = write(fd, blob, size);
+ if (ret != size)
+ perror("write()");
+
+ close(fd);
+ }
+ exit(0);
+}
diff --git a/src/dtc/tests/dup-nodename.dts b/src/dtc/tests/dup-nodename.dts
new file mode 100644
index 0000000..2a3aa75
--- /dev/null
+++ b/src/dtc/tests/dup-nodename.dts
@@ -0,0 +1,8 @@
+/dts-v1/;
+
+/ {
+ node {
+ };
+ node {
+ };
+};
diff --git a/src/dtc/tests/dup-phandle.dts b/src/dtc/tests/dup-phandle.dts
new file mode 100644
index 0000000..c266c61
--- /dev/null
+++ b/src/dtc/tests/dup-phandle.dts
@@ -0,0 +1,10 @@
+/dts-v1/;
+
+/ {
+ node1 {
+ linux,phandle = <1>;
+ };
+ node2 {
+ linux,phandle = <1>;
+ };
+};
diff --git a/src/dtc/tests/dup-propname.dts b/src/dtc/tests/dup-propname.dts
new file mode 100644
index 0000000..8145f6e
--- /dev/null
+++ b/src/dtc/tests/dup-propname.dts
@@ -0,0 +1,6 @@
+/dts-v1/;
+
+/ {
+ prop;
+ prop;
+};
diff --git a/src/dtc/tests/empty.dts b/src/dtc/tests/empty.dts
new file mode 100644
index 0000000..e160dad
--- /dev/null
+++ b/src/dtc/tests/empty.dts
@@ -0,0 +1,4 @@
+/dts-v1/;
+
+/ {
+};
diff --git a/src/dtc/tests/escapes.dts b/src/dtc/tests/escapes.dts
new file mode 100644
index 0000000..e05ab46
--- /dev/null
+++ b/src/dtc/tests/escapes.dts
@@ -0,0 +1,7 @@
+/dts-v1/;
+
+/ {
+ compatible = "test_string_escapes";
+ escape-str = "nastystring: \a\b\t\n\v\f\r\\\"";
+ escape-str-2 = "\xde\xad\xbe\xef";
+};
diff --git a/src/dtc/tests/extra-terminating-null.c b/src/dtc/tests/extra-terminating-null.c
new file mode 100644
index 0000000..dc1fe89
--- /dev/null
+++ b/src/dtc/tests/extra-terminating-null.c
@@ -0,0 +1,58 @@
+/*
+ * 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>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+static void check_extranull(void *fdt, const char *prop, const char *str, int numnulls)
+{
+ int len = strlen(str);
+ char checkbuf[len+numnulls];
+
+ memset(checkbuf, 0, sizeof(checkbuf));
+ memcpy(checkbuf, TEST_STRING_1, len);
+
+ check_getprop(fdt, 0, prop, len+numnulls, checkbuf);
+}
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+
+ test_init(argc, argv);
+
+ fdt = load_blob_arg(argc, argv);
+
+ check_extranull(fdt, "extranull0", TEST_STRING_1, 1);
+ check_extranull(fdt, "extranull1,1", TEST_STRING_1, 2);
+ check_extranull(fdt, "extranull1,2", TEST_STRING_1, 2);
+ check_extranull(fdt, "extranull2,1", TEST_STRING_1, 3);
+ check_extranull(fdt, "extranull2,2", TEST_STRING_1, 3);
+ check_extranull(fdt, "extranull2,3", TEST_STRING_1, 3);
+ check_extranull(fdt, "extranull2,4", TEST_STRING_1, 3);
+
+ PASS();
+}
diff --git a/src/dtc/tests/extra-terminating-null.dts b/src/dtc/tests/extra-terminating-null.dts
new file mode 100644
index 0000000..b6cc19c
--- /dev/null
+++ b/src/dtc/tests/extra-terminating-null.dts
@@ -0,0 +1,11 @@
+/dts-v1/;
+
+/ {
+ extranull0 = "hello world";
+ extranull1,1 = "hello world\0";
+ extranull1,2 = "hello world", "";
+ extranull2,1 = "hello world\0\0";
+ extranull2,2 = "hello world", "", "";
+ extranull2,3 = "hello world\0", "";
+ extranull2,4 = "hello world", "\0";
+};
diff --git a/src/dtc/tests/fdtget-runtest.sh b/src/dtc/tests/fdtget-runtest.sh
new file mode 100755
index 0000000..8d8b058
--- /dev/null
+++ b/src/dtc/tests/fdtget-runtest.sh
@@ -0,0 +1,24 @@
+#! /bin/sh
+
+. ./tests.sh
+
+LOG=tmp.log.$$
+EXPECT=tmp.expect.$$
+rm -f $LOG $EXPECT
+trap "rm -f $LOG $EXPECT" 0
+
+expect="$1"
+printf '%b\n' "$expect" > $EXPECT
+shift
+
+verbose_run_log_check "$LOG" $VALGRIND $DTGET "$@"
+
+if cmp $EXPECT $LOG>/dev/null; then
+ PASS
+else
+ if [ -z "$QUIET_TEST" ]; then
+ echo "EXPECTED :-:"
+ cat $EXPECT
+ fi
+ FAIL "Results differ from expected"
+fi
diff --git a/src/dtc/tests/fdtput-runtest.sh b/src/dtc/tests/fdtput-runtest.sh
new file mode 100644
index 0000000..527a968
--- /dev/null
+++ b/src/dtc/tests/fdtput-runtest.sh
@@ -0,0 +1,39 @@
+#! /bin/sh
+
+# Run script for fdtput tests
+# We run fdtput to update the device tree, thn fdtget to check it
+
+# Usage
+# fdtput-runtest.sh name expected_output dtb_file node property flags value
+
+. ./tests.sh
+
+LOG=tmp.log.$$
+EXPECT=tmp.expect.$$
+rm -f $LOG $EXPECT
+trap "rm -f $LOG $EXPECT" 0
+
+expect="$1"
+echo $expect >$EXPECT
+dtb="$2"
+node="$3"
+property="$4"
+flags="$5"
+shift 5
+value="$@"
+
+# First run fdtput
+verbose_run_check $VALGRIND "$DTPUT" "$dtb" "$node" "$property" $value $flags
+
+# Now fdtget to read the value
+verbose_run_log_check "$LOG" $VALGRIND "$DTGET" "$dtb" "$node" "$property" $flags
+
+if cmp $EXPECT $LOG >/dev/null; then
+ PASS
+else
+ if [ -z "$QUIET_TEST" ]; then
+ echo "EXPECTED :-:"
+ cat $EXPECT
+ fi
+ FAIL "Results differ from expected"
+fi
diff --git a/src/dtc/tests/find_property.c b/src/dtc/tests/find_property.c
new file mode 100644
index 0000000..4dc3030
--- /dev/null
+++ b/src/dtc/tests/find_property.c
@@ -0,0 +1,41 @@
+/*
+ * 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>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ check_property_cell(fdt, 0, "prop-int", TEST_VALUE_1);
+ check_property(fdt, 0, "prop-str", strlen(TEST_STRING_1)+1, TEST_STRING_1);
+
+ PASS();
+}
diff --git a/src/dtc/tests/get_alias.c b/src/dtc/tests/get_alias.c
new file mode 100644
index 0000000..5060795
--- /dev/null
+++ b/src/dtc/tests/get_alias.c
@@ -0,0 +1,57 @@
+/*
+ * 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>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+static void check_alias(void *fdt, const char *path, const char *alias)
+{
+ const char *aliaspath;
+
+ aliaspath = fdt_get_alias(fdt, alias);
+
+ if (path && !aliaspath)
+ FAIL("fdt_get_alias(%s) failed\n", alias);
+
+ if (strcmp(aliaspath, path) != 0)
+ FAIL("fdt_get_alias(%s) returned %s instead of %s\n",
+ alias, aliaspath, path);
+}
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ check_alias(fdt, "/subnode@1", "s1");
+ check_alias(fdt, "/subnode@1/subsubnode", "ss1");
+ check_alias(fdt, "/subnode@1/subsubnode/subsubsubnode", "sss1");
+
+ PASS();
+}
diff --git a/src/dtc/tests/get_mem_rsv.c b/src/dtc/tests/get_mem_rsv.c
new file mode 100644
index 0000000..1812639
--- /dev/null
+++ b/src/dtc/tests/get_mem_rsv.c
@@ -0,0 +1,48 @@
+/*
+ * 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>
+#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;
+ int rc;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ rc = fdt_num_mem_rsv(fdt);
+ if (rc < 0)
+ FAIL("fdt_num_mem_rsv(): %s", fdt_strerror(rc));
+ if (rc != 2)
+ FAIL("fdt_num_mem_rsv() returned %d instead of 2", rc);
+
+ check_mem_rsv(fdt, 0, TEST_ADDR_1, TEST_SIZE_1);
+ check_mem_rsv(fdt, 1, TEST_ADDR_2, TEST_SIZE_2);
+ PASS();
+}
diff --git a/src/dtc/tests/get_name.c b/src/dtc/tests/get_name.c
new file mode 100644
index 0000000..c6ca9f9
--- /dev/null
+++ b/src/dtc/tests/get_name.c
@@ -0,0 +1,82 @@
+/*
+ * 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>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+static void check_name(void *fdt, const char *path)
+{
+ int offset;
+ const char *getname, *getname2, *checkname;
+ int len;
+
+ checkname = strrchr(path, '/');
+ if (!checkname)
+ TEST_BUG();
+ checkname += 1;
+
+ offset = fdt_path_offset(fdt, path);
+ if (offset < 0)
+ FAIL("Couldn't find %s", path);
+
+ getname = fdt_get_name(fdt, offset, &len);
+ verbose_printf("fdt_get_name(%d) returns \"%s\" (len=%d)\n",
+ offset, getname, len);
+ if (!getname)
+ FAIL("fdt_get_name(%d): %s", offset, fdt_strerror(len));
+
+ if (strcmp(getname, checkname) != 0)
+ FAIL("fdt_get_name(%s) returned \"%s\" instead of \"%s\"",
+ path, getname, checkname);
+
+ if (len != strlen(getname))
+ FAIL("fdt_get_name(%s) returned length %d instead of %zd",
+ path, len, strlen(getname));
+
+ /* Now check that it doesn't break if we omit len */
+ getname2 = fdt_get_name(fdt, offset, NULL);
+ if (!getname2)
+ FAIL("fdt_get_name(%d, NULL) failed", offset);
+ if (strcmp(getname2, getname) != 0)
+ FAIL("fdt_get_name(%d, NULL) returned \"%s\" instead of \"%s\"",
+ offset, getname2, getname);
+}
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ check_name(fdt, "/");
+ check_name(fdt, "/subnode@1");
+ check_name(fdt, "/subnode@2");
+ check_name(fdt, "/subnode@1/subsubnode");
+ check_name(fdt, "/subnode@2/subsubnode@0");
+
+ PASS();
+}
diff --git a/src/dtc/tests/get_path.c b/src/dtc/tests/get_path.c
new file mode 100644
index 0000000..7352976
--- /dev/null
+++ b/src/dtc/tests/get_path.c
@@ -0,0 +1,92 @@
+/*
+ * 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>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+#define POISON ('\xff')
+
+static void check_path_buf(void *fdt, const char *path, int pathlen, int buflen)
+{
+ int offset;
+ char buf[buflen+1];
+ int len;
+
+ offset = fdt_path_offset(fdt, path);
+ if (offset < 0)
+ FAIL("Couldn't find path \"%s\": %s", path, fdt_strerror(offset));
+
+ 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);
+
+ if (buflen <= pathlen) {
+ if (len != -FDT_ERR_NOSPACE)
+ FAIL("fdt_get_path([%d bytes]) returns %d with "
+ "insufficient buffer space", buflen, len);
+ } else {
+ if (len < 0)
+ FAIL("fdt_get_path([%d bytes]): %s", buflen,
+ fdt_strerror(len));
+ if (len != 0)
+ FAIL("fdt_get_path([%d bytes]) returns %d "
+ "instead of 0", buflen, len);
+ if (strcmp(buf, path) != 0)
+ FAIL("fdt_get_path([%d bytes]) returns \"%s\" "
+ "instead of \"%s\"", buflen, buf, path);
+ }
+
+ if (buf[buflen] != POISON)
+ FAIL("fdt_get_path([%d bytes]) overran buffer", buflen);
+}
+
+static void check_path(void *fdt, const char *path)
+{
+ int pathlen = strlen(path);
+
+ check_path_buf(fdt, path, pathlen, 1024);
+ check_path_buf(fdt, path, pathlen, pathlen+1);
+ check_path_buf(fdt, path, pathlen, pathlen);
+ check_path_buf(fdt, path, pathlen, 0);
+ check_path_buf(fdt, path, pathlen, 2);
+}
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ check_path(fdt, "/");
+ check_path(fdt, "/subnode@1");
+ check_path(fdt, "/subnode@2");
+ check_path(fdt, "/subnode@1/subsubnode");
+ check_path(fdt, "/subnode@2/subsubnode@0");
+
+ PASS();
+}
diff --git a/src/dtc/tests/get_phandle.c b/src/dtc/tests/get_phandle.c
new file mode 100644
index 0000000..2079591
--- /dev/null
+++ b/src/dtc/tests/get_phandle.c
@@ -0,0 +1,57 @@
+/*
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+static void check_phandle(void *fdt, const char *path, uint32_t checkhandle)
+{
+ int offset;
+ uint32_t phandle;
+
+ offset = fdt_path_offset(fdt, path);
+ if (offset < 0)
+ FAIL("Couldn't find %s", path);
+
+ phandle = fdt_get_phandle(fdt, offset);
+ if (phandle != checkhandle)
+ FAIL("fdt_get_phandle(%s) returned 0x%x instead of 0x%x\n",
+ path, phandle, checkhandle);
+}
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ check_phandle(fdt, "/", 0);
+ check_phandle(fdt, "/subnode@2", PHANDLE_1);
+ check_phandle(fdt, "/subnode@2/subsubnode@0", PHANDLE_2);
+
+ PASS();
+}
diff --git a/src/dtc/tests/getprop.c b/src/dtc/tests/getprop.c
new file mode 100644
index 0000000..6255bad
--- /dev/null
+++ b/src/dtc/tests/getprop.c
@@ -0,0 +1,42 @@
+/*
+ * 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>
+#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;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ check_getprop_cell(fdt, 0, "prop-int", TEST_VALUE_1);
+ check_getprop(fdt, 0, "prop-str", strlen(TEST_STRING_1)+1, TEST_STRING_1);
+
+ PASS();
+}
diff --git a/src/dtc/tests/incbin.bin b/src/dtc/tests/incbin.bin
new file mode 100644
index 0000000..e6e3e48
--- /dev/null
+++ b/src/dtc/tests/incbin.bin
@@ -0,0 +1 @@
+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ \ No newline at end of file
diff --git a/src/dtc/tests/incbin.c b/src/dtc/tests/incbin.c
new file mode 100644
index 0000000..4100ba0
--- /dev/null
+++ b/src/dtc/tests/incbin.c
@@ -0,0 +1,75 @@
+/*
+ * 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>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+#define CHUNKSIZE 1024
+
+static char *load_file(const char *name, int *len)
+{
+ FILE *f;
+ char *buf = NULL;
+ int bufsize = 0, n;
+
+ *len = 0;
+
+ f = fopen(name, "r");
+ if (!f)
+ FAIL("Couldn't open \"%s\": %s", name, strerror(errno));
+
+ while (!feof(f)) {
+ if (bufsize < (*len + CHUNKSIZE)) {
+ buf = xrealloc(buf, *len + CHUNKSIZE);
+ bufsize = *len + CHUNKSIZE;
+ }
+
+ n = fread(buf + *len, 1, CHUNKSIZE, f);
+ if (ferror(f))
+ FAIL("Error reading \"%s\": %s", name, strerror(errno));
+ *len += n;
+ }
+
+ return buf;
+}
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ char *incbin;
+ int len;
+
+ test_init(argc, argv);
+
+ incbin = load_file("incbin.bin", &len);
+ fdt = load_blob_arg(argc, argv);
+
+ check_getprop(fdt, 0, "incbin", len, incbin);
+ check_getprop(fdt, 0, "incbin-partial", 17, incbin + 13);
+
+ PASS();
+}
diff --git a/src/dtc/tests/incbin.dts b/src/dtc/tests/incbin.dts
new file mode 100644
index 0000000..7c30e0e
--- /dev/null
+++ b/src/dtc/tests/incbin.dts
@@ -0,0 +1,6 @@
+/dts-v1/;
+
+/ {
+ incbin = /incbin/("incbin.bin");
+ incbin-partial = /incbin/("incbin.bin", 13, 17);
+};
diff --git a/src/dtc/tests/include0.dts b/src/dtc/tests/include0.dts
new file mode 100644
index 0000000..355ed6a
--- /dev/null
+++ b/src/dtc/tests/include0.dts
@@ -0,0 +1 @@
+/include/ "include1.dts"
diff --git a/src/dtc/tests/include1.dts b/src/dtc/tests/include1.dts
new file mode 100644
index 0000000..893aaff
--- /dev/null
+++ b/src/dtc/tests/include1.dts
@@ -0,0 +1,27 @@
+/dts-v1/;
+
+/include/ "include2.dts"
+/memreserve/ /include/ "include3.dts";
+
+/ {
+ /include/ "include4.dts"
+ /include/ "include5.dts" = <0xdeadbeef>;
+ prop-int64 /include/ "include5a.dts";
+ prop-str = /include/ "include6.dts";
+
+ /include/ "include7.dts"
+
+ subnode@2 {
+ linux,phandle = <0x2000>;
+ prop-int = <123456789>;
+
+ /include/ "include8.dts"
+ phandle = <0x2001>;
+ compatible = "subsubnode2", "subsubnode";
+ prop-int = <0726746425>;
+ };
+
+ ss2 {
+ };
+ };
+};
diff --git a/src/dtc/tests/include2.dts b/src/dtc/tests/include2.dts
new file mode 100644
index 0000000..7e189dd
--- /dev/null
+++ b/src/dtc/tests/include2.dts
@@ -0,0 +1 @@
+/memreserve/ 0xdeadbeef00000000 0x100000;
diff --git a/src/dtc/tests/include3.dts b/src/dtc/tests/include3.dts
new file mode 100644
index 0000000..ee9d277
--- /dev/null
+++ b/src/dtc/tests/include3.dts
@@ -0,0 +1 @@
+123456789 010000
diff --git a/src/dtc/tests/include4.dts b/src/dtc/tests/include4.dts
new file mode 100644
index 0000000..b2ddbe5
--- /dev/null
+++ b/src/dtc/tests/include4.dts
@@ -0,0 +1 @@
+ compatible = "test_tree1";
diff --git a/src/dtc/tests/include5.dts b/src/dtc/tests/include5.dts
new file mode 100644
index 0000000..9a35dc5
--- /dev/null
+++ b/src/dtc/tests/include5.dts
@@ -0,0 +1 @@
+prop-int
diff --git a/src/dtc/tests/include5a.dts b/src/dtc/tests/include5a.dts
new file mode 100644
index 0000000..39ddba4
--- /dev/null
+++ b/src/dtc/tests/include5a.dts
@@ -0,0 +1 @@
+= /bits/ 64 <0xdeadbeef01abcdef> \ No newline at end of file
diff --git a/src/dtc/tests/include6.dts b/src/dtc/tests/include6.dts
new file mode 100644
index 0000000..cd4bc1a
--- /dev/null
+++ b/src/dtc/tests/include6.dts
@@ -0,0 +1 @@
+"hello world"
diff --git a/src/dtc/tests/include7.dts b/src/dtc/tests/include7.dts
new file mode 100644
index 0000000..dba5e47
--- /dev/null
+++ b/src/dtc/tests/include7.dts
@@ -0,0 +1,12 @@
+ subnode@1 {
+ compatible = "subnode1";
+ prop-int = [deadbeef];
+
+ subsubnode {
+ compatible = "subsubnode1", "subsubnode";
+ prop-int = <0xdeadbeef>;
+ };
+
+ ss1 {
+ };
+ };
diff --git a/src/dtc/tests/include8.dts b/src/dtc/tests/include8.dts
new file mode 100644
index 0000000..ec70064
--- /dev/null
+++ b/src/dtc/tests/include8.dts
@@ -0,0 +1 @@
+subsubnode@0 { \ No newline at end of file
diff --git a/src/dtc/tests/integer-expressions.c b/src/dtc/tests/integer-expressions.c
new file mode 100644
index 0000000..57e2ff6
--- /dev/null
+++ b/src/dtc/tests/integer-expressions.c
@@ -0,0 +1,116 @@
+/*
+ * 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>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+struct test_expr {
+ const char *expr;
+ uint32_t result;
+} expr_table[] = {
+#define TE(expr) { #expr, (expr) }
+ TE(0xdeadbeef),
+ TE(-0x21524111),
+ TE(1+1),
+ TE(2*3),
+ TE(4/2),
+ TE(10/3),
+ TE(19%4),
+ TE(1 << 13),
+ TE(0x1000 >> 4),
+ TE(3*2+1), TE(3*(2+1)),
+ TE(1+2*3), TE((1+2)*3),
+ TE(1 < 2), TE(2 < 1), TE(1 < 1),
+ TE(1 <= 2), TE(2 <= 1), TE(1 <= 1),
+ TE(1 > 2), TE(2 > 1), TE(1 > 1),
+ TE(1 >= 2), TE(2 >= 1), TE(1 >= 1),
+ TE(1 == 1), TE(1 == 2),
+ TE(1 != 1), TE(1 != 2),
+ TE(0xabcdabcd & 0xffff0000),
+ TE(0xdead4110 ^ 0xf0f0f0f0),
+ TE(0xabcd0000 | 0x0000abcd),
+ TE(~0x21524110),
+ TE(~~0xdeadbeef),
+ TE(0 && 0), TE(17 && 0), TE(0 && 17), TE(17 && 17),
+ TE(0 || 0), TE(17 || 0), TE(0 || 17), TE(17 || 17),
+ TE(!0), TE(!1), TE(!17), TE(!!0), TE(!!17),
+ TE(0 ? 17 : 39), TE(1 ? 17 : 39), TE(17 ? 0xdeadbeef : 0xabcd1234),
+ TE(11 * 257 * 1321517ULL),
+ TE(123456790 - 4/2 + 17%4),
+};
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ const uint32_t *res;
+ int reslen;
+ int i;
+
+ test_init(argc, argv);
+
+ if ((argc == 3) && (strcmp(argv[1], "-g") == 0)) {
+ FILE *f = fopen(argv[2], "w");
+
+ if (!f)
+ FAIL("Couldn't open \"%s\" for output: %s\n",
+ argv[2], strerror(errno));
+
+ fprintf(f, "/dts-v1/;\n");
+ fprintf(f, "/ {\n");
+ fprintf(f, "\texpressions = <\n");
+ for (i = 0; i < ARRAY_SIZE(expr_table); i++)
+ fprintf(f, "\t\t(%s)\n", expr_table[i].expr);
+ fprintf(f, "\t>;\n");
+ fprintf(f, "};\n");
+ fclose(f);
+ } else {
+ fdt = load_blob_arg(argc, argv);
+
+ res = fdt_getprop(fdt, 0, "expressions", &reslen);
+
+ if (!res)
+ FAIL("Error retreiving expression results: %s\n",
+ fdt_strerror(reslen));
+
+ if (reslen != (ARRAY_SIZE(expr_table) * sizeof(uint32_t)))
+ FAIL("Unexpected length of results %d instead of %zd\n",
+ reslen, ARRAY_SIZE(expr_table) * sizeof(uint32_t));
+
+ for (i = 0; i < ARRAY_SIZE(expr_table); i++)
+ if (fdt32_to_cpu(res[i]) != expr_table[i].result)
+ FAIL("Incorrect result for expression \"%s\","
+ " 0x%x instead of 0x%x\n",
+ expr_table[i].expr, fdt32_to_cpu(res[i]),
+ expr_table[i].result);
+ }
+
+ PASS();
+}
diff --git a/src/dtc/tests/label01.dts b/src/dtc/tests/label01.dts
new file mode 100644
index 0000000..a895803
--- /dev/null
+++ b/src/dtc/tests/label01.dts
@@ -0,0 +1,63 @@
+/dts-v1/;
+
+/memreserve/ 0x1000000000000000 0x0000000002000000;
+memrsv2: /memreserve/ 0x2000000000000000 0x0100000000000000;
+/memreserve/ 0x0000000000000000 0x0000000000000014;
+
+/ {
+ model = "MyBoardName";
+ compatible = "MyBoardName", "MyBoardFamilyName";
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ cpus {
+ linux,phandle = <0x1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ PowerPC,970@0 {
+ name = "PowerPC,970";
+ device_type = "cpu";
+ reg = <0x00000000>;
+ clock-frequency = <1600000000>;
+ timebase-frequency = <33333333>;
+ linux,boot-cpu;
+ i-cache-size = <65536>;
+ d-cache-size = <32768>;
+ };
+
+ PowerPC,970@1 {
+ name = "PowerPC,970";
+ device_type = "cpu";
+ reg = <0x00000001>;
+ clock-frequency = <1600000000>;
+ timebase-frequency = <33333333>;
+ i-cache-size = <65536>;
+ d-cache-size = <32768>;
+ };
+
+ };
+
+ node: randomnode {
+ prop: string = str: "foo", str_mid: "stuffstuff\t\t\t\n\n\n" str_end: ;
+ blob = [byte: 0a 0b 0c 0d byte_mid: de ea ad be ef byte_end: ];
+ ref = < cell: &{/memory@0} 0x0 cell_mid: 0xffffffff cell_end: >;
+ mixed = "abc", pre: [1234] post: , gap: < aligned: 0xa 0xb 0xc>;
+ tricky1 = [61 lt1: 62 63 00];
+ subnode: child {
+ };
+ /* subnode_end: is auto-generated by node emit */
+ };
+ /* node_end: is auto-generated by node emit */
+
+ memory@0 {
+ device_type = "memory";
+ memreg: reg = <0x00000000 0x00000000 0x00000000 0x20000000>;
+ };
+
+ chosen {
+ bootargs = "root=/dev/sda2";
+ linux,platform = <0x600>;
+ };
+
+};
+
diff --git a/src/dtc/tests/label_repeated.dts b/src/dtc/tests/label_repeated.dts
new file mode 100644
index 0000000..34225d3
--- /dev/null
+++ b/src/dtc/tests/label_repeated.dts
@@ -0,0 +1,15 @@
+/dts-v1/;
+
+/ {
+ l0: prop = "foo";
+
+ l1: node {
+ };
+};
+
+/ {
+ l0: prop = "foo";
+
+ l1: node {
+ };
+};
diff --git a/src/dtc/tests/line_directives.dts b/src/dtc/tests/line_directives.dts
new file mode 100644
index 0000000..046ef37
--- /dev/null
+++ b/src/dtc/tests/line_directives.dts
@@ -0,0 +1,21 @@
+/dts-v1/;
+
+/* common format */
+#line 3 "foo.dts"
+/* newer gcc format */
+# 9 "baz.dts" 1
+/* flags are optional */
+# 6 "bar.dts"
+
+/ {
+/*
+ * Make sure optional flags don't consume integer data on next line. The issue
+ * was that the {WS} in the trailing ({WS}+[0-9]+)? could cross the * line-
+ * break, and consume the leading "0" of the hex constant, leaving "x12345678"
+ * to be parsed as a number, which is invalid syntax.
+ */
+ prop1 = <
+# 10 "qux.dts"
+ 0x12345678
+ >;
+};
diff --git a/src/dtc/tests/lorem.txt b/src/dtc/tests/lorem.txt
new file mode 100644
index 0000000..acff698
--- /dev/null
+++ b/src/dtc/tests/lorem.txt
@@ -0,0 +1,35 @@
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris eros
+arcu, egestas non pellentesque non, euismod eu nibh. Proin arcu metus,
+dapibus vitae sodales rhoncus, suscipit vel nulla. Etiam lorem est,
+aliquam ut fringilla sit amet, condimentum et quam. Duis eu arcu odio,
+at pulvinar nisi. Morbi condimentum eros ut turpis rhoncus
+pharetra. Pellentesque habitant morbi tristique senectus et netus et
+malesuada fames ac turpis egestas. Nam et nulla enim. Etiam fringilla
+eleifend neque, at posuere ante lacinia a. Duis orci tortor, dictum ac
+gravida ac, euismod eu leo. Sed eget dolor tortor. Pellentesque
+venenatis, lectus eu vulputate porta, libero ipsum convallis mi, sit
+amet vehicula arcu elit sit amet odio.
+
+Fusce iaculis massa metus, id sagittis diam. Praesent molestie ante
+vel odio tincidunt auctor. Cum sociis natoque penatibus et magnis dis
+parturient montes, nascetur ridiculus mus. Duis rutrum vehicula nisl
+eget condimentum. In in justo nisl. Nullam id arcu at nisl eleifend
+pretium. Nulla interdum ligula id elit mollis dictum a sit amet
+quam. Nullam iaculis laoreet ipsum at tempus. Vestibulum in cursus
+dui. Curabitur porta lectus eget urna bibendum congue eget elementum
+nisi. Proin sit amet lectus ut neque iaculis consectetur eu sit amet
+nibh. Maecenas rhoncus dolor ac nunc gravida blandit. Fusce sem felis,
+aliquam a porttitor a, porta quis odio.
+
+Nunc purus lorem, sollicitudin non ultricies id, porta vitae
+enim. Nulla tristique gravida leo ut suscipit. Phasellus vitae turpis
+libero. Proin ac purus dolor, in suscipit magna. Sed et enim
+arcu. Morbi semper aliquet suscipit. Aenean laoreet condimentum massa,
+eu pharetra magna fermentum ut. Morbi euismod convallis tortor, eget
+fringilla lacus sagittis non. Nullam bibendum posuere feugiat.
+
+In at pulvinar massa. Mauris nunc lectus, mollis et malesuada
+pharetra, cursus sed lacus. Integer dolor urna, interdum a mollis at,
+vestibulum non nisl. Sed in urna tortor. Mauris arcu felis, volutpat
+quis euismod vel, congue sit amet ipsum. Morbi in aliquet purus. Duis
+cras amet.
diff --git a/src/dtc/tests/mangle-layout.c b/src/dtc/tests/mangle-layout.c
new file mode 100644
index 0000000..a76e51e
--- /dev/null
+++ b/src/dtc/tests/mangle-layout.c
@@ -0,0 +1,164 @@
+/*
+ * 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>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+struct bufstate {
+ char *buf;
+ int size;
+};
+
+static void expand_buf(struct bufstate *buf, int newsize)
+{
+ buf->buf = realloc(buf->buf, newsize);
+ if (!buf->buf)
+ CONFIG("Allocation failure");
+ buf->size = newsize;
+}
+
+static void new_header(struct bufstate *buf, int version, const void *fdt)
+{
+ int hdrsize;
+
+ if (version == 16)
+ hdrsize = FDT_V16_SIZE;
+ else if (version == 17)
+ hdrsize = FDT_V17_SIZE;
+ else
+ CONFIG("Bad version %d", version);
+
+ expand_buf(buf, hdrsize);
+ memset(buf->buf, 0, hdrsize);
+
+ fdt_set_magic(buf->buf, FDT_MAGIC);
+ fdt_set_version(buf->buf, version);
+ fdt_set_last_comp_version(buf->buf, 16);
+ fdt_set_boot_cpuid_phys(buf->buf, fdt_boot_cpuid_phys(fdt));
+}
+
+static void add_block(struct bufstate *buf, int version, char block, const void *fdt)
+{
+ int align, size, oldsize;
+ const void *src;
+ int offset;
+
+ switch (block) {
+ case 'm':
+ /* Memory reserve map */
+ align = 8;
+ src = (const char *)fdt + fdt_off_mem_rsvmap(fdt);
+ size = (fdt_num_mem_rsv(fdt) + 1)
+ * sizeof(struct fdt_reserve_entry);
+ break;
+
+ case 't':
+ /* Structure block */
+ align = 4;
+ src = (const char *)fdt + fdt_off_dt_struct(fdt);
+ size = fdt_size_dt_struct(fdt);
+ break;
+
+ case 's':
+ /* Strings block */
+ align = 1;
+ src = (const char *)fdt + fdt_off_dt_strings(fdt);
+ size = fdt_size_dt_strings(fdt);
+ break;
+ default:
+ CONFIG("Bad block '%c'", block);
+ }
+
+ oldsize = buf->size;
+ offset = ALIGN(oldsize, align);
+ expand_buf(buf, offset+size);
+ memset(buf->buf + oldsize, 0, offset - oldsize);
+
+ memcpy(buf->buf + offset, src, size);
+
+ switch (block) {
+ case 'm':
+ fdt_set_off_mem_rsvmap(buf->buf, offset);
+ break;
+
+ case 't':
+ fdt_set_off_dt_struct(buf->buf, offset);
+ if (version >= 17)
+ fdt_set_size_dt_struct(buf->buf, size);
+ break;
+
+ case 's':
+ fdt_set_off_dt_strings(buf->buf, offset);
+ fdt_set_size_dt_strings(buf->buf, size);
+ break;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ int version;
+ const char *blockorder;
+ struct bufstate buf = {NULL, 0};
+ int err;
+ const char *inname;
+ char outname[PATH_MAX];
+
+ test_init(argc, argv);
+ if (argc != 4)
+ CONFIG("Usage: %s <dtb file> <version> <block order>", argv[0]);
+
+ inname = argv[1];
+ fdt = load_blob(argv[1]);
+ version = atoi(argv[2]);
+ blockorder = argv[3];
+ sprintf(outname, "v%d.%s.%s", version, blockorder, inname);
+
+ if ((version != 16) && (version != 17))
+ CONFIG("Version must be 16 or 17");
+
+ if (fdt_version(fdt) < 17)
+ CONFIG("Input tree must be v17");
+
+ new_header(&buf, version, fdt);
+
+ while (*blockorder) {
+ add_block(&buf, version, *blockorder, fdt);
+ blockorder++;
+ }
+
+ fdt_set_totalsize(buf.buf, buf.size);
+
+ err = fdt_check_header(buf.buf);
+ if (err)
+ FAIL("Output tree fails check: %s", fdt_strerror(err));
+
+ save_blob(outname, buf.buf);
+
+ PASS();
+}
diff --git a/src/dtc/tests/mangle-layout.supp b/src/dtc/tests/mangle-layout.supp
new file mode 100644
index 0000000..2890420
--- /dev/null
+++ b/src/dtc/tests/mangle-layout.supp
@@ -0,0 +1,7 @@
+{
+ uninitialized alignment gaps can be dumped to output
+ Memcheck:Param
+ write(buf)
+ obj:/lib/ld-*.so
+ fun:main
+}
diff --git a/src/dtc/tests/minusone-phandle.dts b/src/dtc/tests/minusone-phandle.dts
new file mode 100644
index 0000000..21d9986
--- /dev/null
+++ b/src/dtc/tests/minusone-phandle.dts
@@ -0,0 +1,7 @@
+/dts-v1/;
+
+/ {
+ node {
+ linux,phandle = <0xffffffff>;
+ };
+};
diff --git a/src/dtc/tests/move_and_save.c b/src/dtc/tests/move_and_save.c
new file mode 100644
index 0000000..393b60a
--- /dev/null
+++ b/src/dtc/tests/move_and_save.c
@@ -0,0 +1,75 @@
+/*
+ * 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>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+int main(int argc, char *argv[])
+{
+ void *fdt, *fdt1, *fdt2, *fdt3;
+ char *buf;
+ int shuntsize;
+ int bufsize;
+ int err;
+ const char *inname;
+ char outname[PATH_MAX];
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+ inname = argv[1];
+
+ shuntsize = ALIGN(fdt_totalsize(fdt) / 2, sizeof(uint64_t));
+ bufsize = fdt_totalsize(fdt) + shuntsize;
+ buf = xmalloc(bufsize);
+
+ fdt1 = buf;
+ err = fdt_move(fdt, fdt1, bufsize);
+ if (err)
+ FAIL("Failed to move tree into new buffer: %s",
+ fdt_strerror(err));
+ sprintf(outname, "moved.%s", inname);
+ save_blob(outname, fdt1);
+
+ fdt2 = buf + shuntsize;
+ err = fdt_move(fdt1, fdt2, bufsize-shuntsize);
+ if (err)
+ FAIL("Failed to shunt tree %d bytes: %s",
+ shuntsize, fdt_strerror(err));
+ sprintf(outname, "shunted.%s", inname);
+ save_blob(outname, fdt2);
+
+ fdt3 = buf;
+ err = fdt_move(fdt2, fdt3, bufsize);
+ if (err)
+ FAIL("Failed to deshunt tree %d bytes: %s",
+ shuntsize, fdt_strerror(err));
+ sprintf(outname, "deshunted.%s", inname);
+ save_blob(outname, fdt3);
+
+ PASS();
+}
diff --git a/src/dtc/tests/multilabel.dts b/src/dtc/tests/multilabel.dts
new file mode 100644
index 0000000..31116ce
--- /dev/null
+++ b/src/dtc/tests/multilabel.dts
@@ -0,0 +1,42 @@
+/dts-v1/;
+
+m1: mq: /memreserve/ 0 0x1000;
+
+/ {
+ p0: pw: prop = "foo";
+
+ /* Explicit phandles */
+ n1: nx: node1 {
+ linux,phandle = <0x2000>;
+ ref = <&{/node2}>; /* reference precedes target */
+ p1: px: lref = <&ny>;
+ };
+ ny: n2: node2 {
+ p2: py: phandle = <0x1>;
+ ref = <&{/node1}>; /* reference after target */
+ lref = <&nx>;
+ };
+
+ /* Implicit phandles */
+ n3: node3 {
+ p3: ref = <&{/node4}>;
+ lref = <&n4>;
+ };
+ n4: node4 {
+ p4: prop;
+ };
+
+ /* Explicit phandle with implicit value */
+ /* This self-reference is the standard way to tag a node as requiring
+ * a phandle (perhaps for reference by nodes that will be dynamically
+ * added) without explicitly allocating it a phandle.
+ * The self-reference requires some special internal handling, though
+ * so check it actually works */
+ n5: nz: node5 {
+ linux,phandle = <&n5>;
+ phandle = <&nz>;
+ n1 = &n1;
+ n2 = &n2;
+ n3 = &n3;
+ };
+};
diff --git a/src/dtc/tests/multilabel_merge.dts b/src/dtc/tests/multilabel_merge.dts
new file mode 100644
index 0000000..1632300
--- /dev/null
+++ b/src/dtc/tests/multilabel_merge.dts
@@ -0,0 +1,66 @@
+/dts-v1/;
+
+m1: mq: /memreserve/ 0 0x1000;
+
+/ {
+ p0: pw: prop = "foo";
+
+ /* Explicit phandles */
+ n1: node1 {
+ linux,phandle = <0x2000>;
+ ref = <&{/node2}>; /* reference precedes target */
+ p1: lref;
+ };
+ node2 {
+ phandle = <0x1>;
+ ref = <&{/node1}>; /* reference after target */
+ lref = <&nx>;
+ };
+
+ /* Implicit phandles */
+ n3: node3 {
+ p3: ref = <&{/node4}>;
+ lref = <&n4>;
+ };
+ n4: node4 {
+ p4: prop = "foo";
+ };
+
+ /* Explicit phandle with implicit value */
+ /* This self-reference is the standard way to tag a node as requiring
+ * a phandle (perhaps for reference by nodes that will be dynamically
+ * added) without explicitly allocating it a phandle.
+ * The self-reference requires some special internal handling, though
+ * so check it actually works */
+ n5: nz: node5 {
+ linux,phandle = <&n5>;
+ phandle = <&nz>;
+ n1 = &n1;
+ n2 = &n2;
+ n3 = &n3;
+ };
+};
+
+/ {
+ /* Append labels (also changes property content) */
+ nx: node1 {
+ px: lref = <&ny>;
+ };
+
+ /* Add multiple labels */
+ ny: n2: node2 {
+ /* Add a label to a property */
+ p2: py: phandle = <0x1>;
+ };
+
+ /* Reassigning the same label should be a no-op */
+ n3: node3 {
+ p3: ref = <&{/node4}>;
+ };
+
+ /* Redefining a node/property should not remove labels */
+ node4 {
+ prop;
+ };
+
+};
diff --git a/src/dtc/tests/node_check_compatible.c b/src/dtc/tests/node_check_compatible.c
new file mode 100644
index 0000000..4bdf091
--- /dev/null
+++ b/src/dtc/tests/node_check_compatible.c
@@ -0,0 +1,62 @@
+/*
+ * 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>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+static void check_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 not compatible with \"%s\"", path, compat);
+}
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ check_compatible(fdt, "/", "test_tree1");
+ check_compatible(fdt, "/subnode@1/subsubnode", "subsubnode1");
+ check_compatible(fdt, "/subnode@1/subsubnode", "subsubnode");
+ check_compatible(fdt, "/subnode@2/subsubnode", "subsubnode2");
+ check_compatible(fdt, "/subnode@2/subsubnode", "subsubnode");
+
+ PASS();
+}
diff --git a/src/dtc/tests/node_offset_by_compatible.c b/src/dtc/tests/node_offset_by_compatible.c
new file mode 100644
index 0000000..f62b591
--- /dev/null
+++ b/src/dtc/tests/node_offset_by_compatible.c
@@ -0,0 +1,85 @@
+/*
+ * 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>
+#include <string.h>
+#include <stdint.h>
+#include <stdarg.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+static void check_search(void *fdt, const char *compat, ...)
+{
+ va_list ap;
+ int offset = -1, target;
+
+ va_start(ap, compat);
+ do {
+ target = va_arg(ap, int);
+ verbose_printf("Searching (target = %d): %d ->",
+ target, offset);
+ offset = fdt_node_offset_by_compatible(fdt, offset, compat);
+ verbose_printf("%d\n", offset);
+
+ if (offset != target)
+ FAIL("fdt_node_offset_by_compatible(%s) returns %d "
+ "instead of %d", compat, offset, target);
+ } while (target >= 0);
+
+ va_end(ap);
+}
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ int subnode1_offset, subnode2_offset;
+ int subsubnode1_offset, subsubnode2_offset;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ subnode1_offset = fdt_path_offset(fdt, "/subnode@1");
+ subnode2_offset = fdt_path_offset(fdt, "/subnode@2");
+ subsubnode1_offset = fdt_path_offset(fdt, "/subnode@1/subsubnode");
+ subsubnode2_offset = fdt_path_offset(fdt, "/subnode@2/subsubnode@0");
+
+ if ((subnode1_offset < 0) || (subnode2_offset < 0)
+ || (subsubnode1_offset < 0) || (subsubnode2_offset < 0))
+ FAIL("Can't find required nodes");
+
+ check_search(fdt, "test_tree1", 0, -FDT_ERR_NOTFOUND);
+ check_search(fdt, "subnode1", subnode1_offset, -FDT_ERR_NOTFOUND);
+ check_search(fdt, "subsubnode1", subsubnode1_offset, -FDT_ERR_NOTFOUND);
+ check_search(fdt, "subsubnode2", subsubnode2_offset, -FDT_ERR_NOTFOUND);
+ /* Eek.. HACK to make this work whatever the order in the
+ * example tree */
+ if (subsubnode1_offset < subsubnode2_offset)
+ check_search(fdt, "subsubnode", subsubnode1_offset,
+ subsubnode2_offset, -FDT_ERR_NOTFOUND);
+ else
+ check_search(fdt, "subsubnode", subsubnode2_offset,
+ subsubnode1_offset, -FDT_ERR_NOTFOUND);
+ check_search(fdt, "nothing-like-this", -FDT_ERR_NOTFOUND);
+
+ PASS();
+}
diff --git a/src/dtc/tests/node_offset_by_phandle.c b/src/dtc/tests/node_offset_by_phandle.c
new file mode 100644
index 0000000..becff0f
--- /dev/null
+++ b/src/dtc/tests/node_offset_by_phandle.c
@@ -0,0 +1,63 @@
+/*
+ * 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>
+#include <string.h>
+#include <stdint.h>
+#include <stdarg.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+static void check_search(void *fdt, uint32_t phandle, int target)
+{
+ int offset;
+
+ offset = fdt_node_offset_by_phandle(fdt, phandle);
+
+ if (offset != target)
+ FAIL("fdt_node_offset_by_phandle(0x%x) returns %d "
+ "instead of %d", phandle, offset, target);
+}
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ int subnode2_offset, subsubnode2_offset;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ subnode2_offset = fdt_path_offset(fdt, "/subnode@2");
+ subsubnode2_offset = fdt_path_offset(fdt, "/subnode@2/subsubnode@0");
+
+ if ((subnode2_offset < 0) || (subsubnode2_offset < 0))
+ FAIL("Can't find required nodes");
+
+ check_search(fdt, PHANDLE_1, subnode2_offset);
+ check_search(fdt, PHANDLE_2, subsubnode2_offset);
+ check_search(fdt, ~PHANDLE_1, -FDT_ERR_NOTFOUND);
+ check_search(fdt, 0, -FDT_ERR_BADPHANDLE);
+ check_search(fdt, -1, -FDT_ERR_BADPHANDLE);
+
+ PASS();
+}
diff --git a/src/dtc/tests/node_offset_by_prop_value.c b/src/dtc/tests/node_offset_by_prop_value.c
new file mode 100644
index 0000000..9212a4e
--- /dev/null
+++ b/src/dtc/tests/node_offset_by_prop_value.c
@@ -0,0 +1,110 @@
+/*
+ * 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>
+#include <string.h>
+#include <stdint.h>
+#include <stdarg.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+static void vcheck_search(void *fdt, const char *propname, const void *propval,
+ int proplen, va_list ap)
+{
+ int offset = -1, target;
+
+ do {
+ target = va_arg(ap, int);
+ verbose_printf("Searching (target = %d): %d ->",
+ target, offset);
+ offset = fdt_node_offset_by_prop_value(fdt, offset, propname,
+ propval, proplen);
+ verbose_printf("%d\n", offset);
+
+ if (offset != target)
+ FAIL("fdt_node_offset_by_prop_value() returns %d "
+ "instead of %d", offset, target);
+ } while (target >= 0);
+}
+
+static void check_search(void *fdt, const char *propname, const void *propval,
+ int proplen, ...)
+{
+ va_list ap;
+
+ va_start(ap, proplen);
+ vcheck_search(fdt, propname, propval, proplen, ap);
+ va_end(ap);
+}
+
+static void check_search_str(void *fdt, const char *propname,
+ const char *propval, ...)
+{
+ va_list ap;
+
+ va_start(ap, propval);
+ vcheck_search(fdt, propname, propval, strlen(propval)+1, ap);
+ va_end(ap);
+}
+
+#define check_search_cell(fdt, propname, propval, ...) \
+ { \
+ uint32_t val = cpu_to_fdt32(propval); \
+ check_search((fdt), (propname), &val, sizeof(val), \
+ ##__VA_ARGS__); \
+ }
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ int subnode1_offset, subnode2_offset;
+ int subsubnode1_offset, subsubnode2_offset;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ subnode1_offset = fdt_path_offset(fdt, "/subnode@1");
+ subnode2_offset = fdt_path_offset(fdt, "/subnode@2");
+ subsubnode1_offset = fdt_path_offset(fdt, "/subnode@1/subsubnode");
+ subsubnode2_offset = fdt_path_offset(fdt, "/subnode@2/subsubnode@0");
+
+ if ((subnode1_offset < 0) || (subnode2_offset < 0)
+ || (subsubnode1_offset < 0) || (subsubnode2_offset < 0))
+ FAIL("Can't find required nodes");
+
+ check_search_cell(fdt, "prop-int", TEST_VALUE_1, 0, subnode1_offset,
+ subsubnode1_offset, -FDT_ERR_NOTFOUND);
+
+ check_search_cell(fdt, "prop-int", TEST_VALUE_2, subnode2_offset,
+ subsubnode2_offset, -FDT_ERR_NOTFOUND);
+
+ check_search_str(fdt, "prop-str", TEST_STRING_1, 0, -FDT_ERR_NOTFOUND);
+
+ check_search_str(fdt, "prop-str", "no such string", -FDT_ERR_NOTFOUND);
+
+ check_search_cell(fdt, "prop-int", TEST_VALUE_1+1, -FDT_ERR_NOTFOUND);
+
+ check_search(fdt, "no-such-prop", NULL, 0, -FDT_ERR_NOTFOUND);
+
+ PASS();
+}
diff --git a/src/dtc/tests/nonexist-label-ref.dts b/src/dtc/tests/nonexist-label-ref.dts
new file mode 100644
index 0000000..25927a1
--- /dev/null
+++ b/src/dtc/tests/nonexist-label-ref.dts
@@ -0,0 +1,8 @@
+/dts-v1/;
+
+/ {
+ ref = <&label>;
+ badref = <&nosuchlabel>;
+ label: node {
+ };
+};
diff --git a/src/dtc/tests/nonexist-node-ref.dts b/src/dtc/tests/nonexist-node-ref.dts
new file mode 100644
index 0000000..efd4140
--- /dev/null
+++ b/src/dtc/tests/nonexist-node-ref.dts
@@ -0,0 +1,8 @@
+/dts-v1/;
+
+/ {
+ ref = < &{/node} >;
+ badref = < &{/nosuchnode} >;
+ label: node {
+ };
+};
diff --git a/src/dtc/tests/nonexist-node-ref2.dts b/src/dtc/tests/nonexist-node-ref2.dts
new file mode 100644
index 0000000..44b4ebe
--- /dev/null
+++ b/src/dtc/tests/nonexist-node-ref2.dts
@@ -0,0 +1,10 @@
+/dts-v1/;
+
+/ {
+ label: node {
+ };
+};
+
+/* Try to redefine a node using a non-existent label */
+&nosuchnode {
+};
diff --git a/src/dtc/tests/nop_node.c b/src/dtc/tests/nop_node.c
new file mode 100644
index 0000000..c316444
--- /dev/null
+++ b/src/dtc/tests/nop_node.c
@@ -0,0 +1,104 @@
+/*
+ * 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>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ int subnode1_offset, subnode2_offset, subsubnode2_offset;
+ int err;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ subnode1_offset = fdt_path_offset(fdt, "/subnode@1");
+ if (subnode1_offset < 0)
+ FAIL("Couldn't find \"/subnode1\": %s",
+ fdt_strerror(subnode1_offset));
+ check_getprop_cell(fdt, subnode1_offset, "prop-int", TEST_VALUE_1);
+
+ subnode2_offset = fdt_path_offset(fdt, "/subnode@2");
+ if (subnode2_offset < 0)
+ FAIL("Couldn't find \"/subnode2\": %s",
+ fdt_strerror(subnode2_offset));
+ check_getprop_cell(fdt, subnode2_offset, "prop-int", TEST_VALUE_2);
+
+ subsubnode2_offset = fdt_path_offset(fdt, "/subnode@2/subsubnode");
+ if (subsubnode2_offset < 0)
+ FAIL("Couldn't find \"/subnode@2/subsubnode\": %s",
+ fdt_strerror(subsubnode2_offset));
+ check_getprop_cell(fdt, subsubnode2_offset, "prop-int", TEST_VALUE_2);
+
+ err = fdt_nop_node(fdt, subnode1_offset);
+ if (err)
+ FAIL("fdt_nop_node(subnode1): %s", fdt_strerror(err));
+
+ subnode1_offset = fdt_path_offset(fdt, "/subnode@1");
+ if (subnode1_offset != -FDT_ERR_NOTFOUND)
+ FAIL("fdt_path_offset(subnode1) returned \"%s\" instead of \"%s\"",
+ fdt_strerror(subnode1_offset),
+ fdt_strerror(-FDT_ERR_NOTFOUND));
+
+ subnode2_offset = fdt_path_offset(fdt, "/subnode@2");
+ if (subnode2_offset < 0)
+ FAIL("Couldn't find \"/subnode2\": %s",
+ fdt_strerror(subnode2_offset));
+ check_getprop_cell(fdt, subnode2_offset, "prop-int", TEST_VALUE_2);
+
+ subsubnode2_offset = fdt_path_offset(fdt, "/subnode@2/subsubnode");
+ if (subsubnode2_offset < 0)
+ FAIL("Couldn't find \"/subnode@2/subsubnode\": %s",
+ fdt_strerror(subsubnode2_offset));
+ check_getprop_cell(fdt, subsubnode2_offset, "prop-int", TEST_VALUE_2);
+
+ err = fdt_nop_node(fdt, subnode2_offset);
+ if (err)
+ FAIL("fdt_nop_node(subnode2): %s", fdt_strerror(err));
+
+ subnode1_offset = fdt_path_offset(fdt, "/subnode@1");
+ if (subnode1_offset != -FDT_ERR_NOTFOUND)
+ FAIL("fdt_path_offset(subnode1) returned \"%s\" instead of \"%s\"",
+ fdt_strerror(subnode1_offset),
+ fdt_strerror(-FDT_ERR_NOTFOUND));
+
+ subnode2_offset = fdt_path_offset(fdt, "/subnode@2");
+ if (subnode2_offset != -FDT_ERR_NOTFOUND)
+ FAIL("fdt_path_offset(subnode2) returned \"%s\" instead of \"%s\"",
+ fdt_strerror(subnode2_offset),
+ fdt_strerror(-FDT_ERR_NOTFOUND));
+
+ subsubnode2_offset = fdt_path_offset(fdt, "/subnode@2/subsubnode");
+ if (subsubnode2_offset != -FDT_ERR_NOTFOUND)
+ FAIL("fdt_path_offset(subsubnode2) returned \"%s\" instead of \"%s\"",
+ fdt_strerror(subsubnode2_offset),
+ fdt_strerror(-FDT_ERR_NOTFOUND));
+
+ PASS();
+}
diff --git a/src/dtc/tests/nop_property.c b/src/dtc/tests/nop_property.c
new file mode 100644
index 0000000..644b0a6
--- /dev/null
+++ b/src/dtc/tests/nop_property.c
@@ -0,0 +1,70 @@
+/*
+ * 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>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ const uint32_t *intp;
+ const char *strp;
+ int err;
+ int lenerr;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ intp = check_getprop_cell(fdt, 0, "prop-int", TEST_VALUE_1);
+ verbose_printf("int value was 0x%08x\n", *intp);
+
+ err = fdt_nop_property(fdt, 0, "prop-int");
+ if (err)
+ FAIL("Failed to nop \"prop-int\": %s", fdt_strerror(err));
+
+ intp = fdt_getprop(fdt, 0, "prop-int", &lenerr);
+ if (intp)
+ FAIL("prop-int still present after nopping");
+ if (lenerr != -FDT_ERR_NOTFOUND)
+ FAIL("Unexpected error on second getprop: %s", fdt_strerror(err));
+
+ strp = check_getprop(fdt, 0, "prop-str", strlen(TEST_STRING_1)+1,
+ TEST_STRING_1);
+ verbose_printf("string value was \"%s\"\n", strp);
+ err = fdt_nop_property(fdt, 0, "prop-str");
+ if (err)
+ FAIL("Failed to nop \"prop-str\": %s", fdt_strerror(err));
+
+ strp = fdt_getprop(fdt, 0, "prop-str", &lenerr);
+ if (strp)
+ FAIL("prop-str still present after nopping");
+ if (lenerr != -FDT_ERR_NOTFOUND)
+ FAIL("Unexpected error on second getprop: %s", fdt_strerror(err));
+
+ PASS();
+}
diff --git a/src/dtc/tests/nopulate.c b/src/dtc/tests/nopulate.c
new file mode 100644
index 0000000..cd79872
--- /dev/null
+++ b/src/dtc/tests/nopulate.c
@@ -0,0 +1,105 @@
+/*
+ * 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>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+static int nopulate_struct(char *buf, const char *fdt)
+{
+ int offset, nextoffset = 0;
+ uint32_t tag;
+ char *p;
+
+ p = buf;
+
+ do {
+ offset = nextoffset;
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+ memcpy(p, (const char *)fdt + fdt_off_dt_struct(fdt) + offset,
+ nextoffset - offset);
+ p += nextoffset - offset;
+
+ *((uint32_t *)p) = cpu_to_fdt32(FDT_NOP);
+ p += FDT_TAGSIZE;
+
+ } while (tag != FDT_END);
+
+ return p - buf;
+}
+
+int main(int argc, char *argv[])
+{
+ char *fdt, *fdt2, *buf;
+ int newsize, struct_start, struct_end_old, struct_end_new, delta;
+ const char *inname;
+ char outname[PATH_MAX];
+
+ test_init(argc, argv);
+ if (argc != 2)
+ CONFIG("Usage: %s <dtb file>", argv[0]);
+
+ inname = argv[1];
+ fdt = load_blob(argv[1]);
+ sprintf(outname, "noppy.%s", inname);
+
+ if (fdt_version(fdt) < 17)
+ FAIL("Can't deal with version <17");
+
+ buf = xmalloc(2 * fdt_size_dt_struct(fdt));
+
+ newsize = nopulate_struct(buf, fdt);
+
+ verbose_printf("Nopulated structure block has new size %d\n", newsize);
+
+ /* Replace old strcutre block with the new */
+
+ fdt2 = xmalloc(fdt_totalsize(fdt) + newsize);
+
+ struct_start = fdt_off_dt_struct(fdt);
+ delta = newsize - fdt_size_dt_struct(fdt);
+ struct_end_old = struct_start + fdt_size_dt_struct(fdt);
+ struct_end_new = struct_start + newsize;
+
+ memcpy(fdt2, fdt, struct_start);
+ memcpy(fdt2 + struct_start, buf, newsize);
+ memcpy(fdt2 + struct_end_new, fdt + struct_end_old,
+ fdt_totalsize(fdt) - struct_end_old);
+
+ fdt_set_totalsize(fdt2, fdt_totalsize(fdt) + delta);
+ fdt_set_size_dt_struct(fdt2, newsize);
+
+ if (fdt_off_mem_rsvmap(fdt) > struct_start)
+ fdt_set_off_mem_rsvmap(fdt2, fdt_off_mem_rsvmap(fdt) + delta);
+ if (fdt_off_dt_strings(fdt) > struct_start)
+ fdt_set_off_dt_strings(fdt2, fdt_off_dt_strings(fdt) + delta);
+
+ save_blob(outname, fdt2);
+
+ PASS();
+}
diff --git a/src/dtc/tests/notfound.c b/src/dtc/tests/notfound.c
new file mode 100644
index 0000000..dc623d6
--- /dev/null
+++ b/src/dtc/tests/notfound.c
@@ -0,0 +1,70 @@
+/*
+ * 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>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+static void check_error(const char *s, int err)
+{
+ if (err != -FDT_ERR_NOTFOUND)
+ FAIL("%s return error %s instead of -FDT_ERR_NOTFOUND", s,
+ fdt_strerror(err));
+}
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ int offset;
+ int subnode1_offset;
+ int lenerr;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ fdt_get_property(fdt, 0, "nonexistant-property", &lenerr);
+ check_error("fdt_get_property(\"nonexistant-property\")", lenerr);
+
+ fdt_getprop(fdt, 0, "nonexistant-property", &lenerr);
+ check_error("fdt_getprop(\"nonexistant-property\"", lenerr);
+
+ subnode1_offset = fdt_subnode_offset(fdt, 0, "subnode@1");
+ if (subnode1_offset < 0)
+ FAIL("Couldn't find subnode1: %s", fdt_strerror(subnode1_offset));
+
+ fdt_getprop(fdt, subnode1_offset, "prop-str", &lenerr);
+ check_error("fdt_getprop(\"prop-str\")", lenerr);
+
+ offset = fdt_subnode_offset(fdt, 0, "nonexistant-subnode");
+ check_error("fdt_subnode_offset(\"nonexistant-subnode\")", offset);
+
+ offset = fdt_subnode_offset(fdt, 0, "subsubnode");
+ check_error("fdt_subnode_offset(\"subsubnode\")", offset);
+
+ offset = fdt_path_offset(fdt, "/nonexistant-subnode");
+ check_error("fdt_path_offset(\"/nonexistant-subnode\")", offset);
+
+ PASS();
+}
diff --git a/src/dtc/tests/obsolete-chosen-interrupt-controller.dts b/src/dtc/tests/obsolete-chosen-interrupt-controller.dts
new file mode 100644
index 0000000..36dd6e8
--- /dev/null
+++ b/src/dtc/tests/obsolete-chosen-interrupt-controller.dts
@@ -0,0 +1,13 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ PIC: pic@0 {
+ reg = <0x0 0x10>;
+ interrupt-controller;
+ };
+ chosen {
+ interrupt-controller = <&PIC>;
+ };
+};
diff --git a/src/dtc/tests/open_pack.c b/src/dtc/tests/open_pack.c
new file mode 100644
index 0000000..407ef6c
--- /dev/null
+++ b/src/dtc/tests/open_pack.c
@@ -0,0 +1,71 @@
+/*
+ * 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>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+int main(int argc, char *argv[])
+{
+ void *fdt, *fdt1;
+ void *buf;
+ int oldsize, bufsize, packsize;
+ int err;
+ const char *inname;
+ char outname[PATH_MAX];
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+ inname = argv[1];
+
+ oldsize = fdt_totalsize(fdt);
+
+ bufsize = oldsize * 2;
+
+ buf = xmalloc(bufsize);
+ /* don't leak uninitialized memory into our output */
+ memset(buf, 0, bufsize);
+
+ fdt1 = buf;
+ err = fdt_open_into(fdt, fdt1, bufsize);
+ if (err)
+ FAIL("fdt_open_into(): %s", fdt_strerror(err));
+ sprintf(outname, "opened.%s", inname);
+ save_blob(outname, fdt1);
+
+ err = fdt_pack(fdt1);
+ if (err)
+ FAIL("fdt_pack(): %s", fdt_strerror(err));
+ sprintf(outname, "repacked.%s", inname);
+ save_blob(outname, fdt1);
+
+ packsize = fdt_totalsize(fdt1);
+
+ verbose_printf("oldsize = %d, bufsize = %d, packsize = %d\n",
+ oldsize, bufsize, packsize);
+ PASS();
+}
diff --git a/src/dtc/tests/open_pack.supp b/src/dtc/tests/open_pack.supp
new file mode 100644
index 0000000..c954fe7
--- /dev/null
+++ b/src/dtc/tests/open_pack.supp
@@ -0,0 +1,7 @@
+{
+ opened blob dumps uninitialized data
+ Memcheck:Param
+ write(buf)
+ obj:/lib/ld-*.so
+ fun:main
+}
diff --git a/src/dtc/tests/parent_offset.c b/src/dtc/tests/parent_offset.c
new file mode 100644
index 0000000..d4ab3cf
--- /dev/null
+++ b/src/dtc/tests/parent_offset.c
@@ -0,0 +1,90 @@
+/*
+ * 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>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+static int path_parent_len(const char *path)
+{
+ const char *p = strrchr(path, '/');
+
+ if (!p)
+ TEST_BUG();
+ if (p == path)
+ return 1;
+ else
+ return p - path;
+}
+
+static void check_path(struct fdt_header *fdt, const char *path)
+{
+ char *parentpath;
+ int nodeoffset, parentoffset, parentpathoffset, pathparentlen;
+
+ pathparentlen = path_parent_len(path);
+ parentpath = alloca(pathparentlen + 1);
+ strncpy(parentpath, path, pathparentlen);
+ parentpath[pathparentlen] = '\0';
+
+ verbose_printf("Path: \"%s\"\tParent: \"%s\"\n", path, parentpath);
+
+ nodeoffset = fdt_path_offset(fdt, path);
+ if (nodeoffset < 0)
+ FAIL("fdt_path_offset(%s): %s", path, fdt_strerror(nodeoffset));
+
+ parentpathoffset = fdt_path_offset(fdt, parentpath);
+ if (parentpathoffset < 0)
+ FAIL("fdt_path_offset(%s): %s", parentpath,
+ fdt_strerror(parentpathoffset));
+
+ parentoffset = fdt_parent_offset(fdt, nodeoffset);
+ if (parentoffset < 0)
+ FAIL("fdt_parent_offset(): %s", fdt_strerror(parentoffset));
+
+ if (parentoffset != parentpathoffset)
+ FAIL("fdt_parent_offset() returns %d instead of %d",
+ parentoffset, parentpathoffset);
+}
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ int err;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ check_path(fdt, "/subnode@1");
+ check_path(fdt, "/subnode@2");
+ check_path(fdt, "/subnode@1/subsubnode");
+ check_path(fdt, "/subnode@2/subsubnode@0");
+ err = fdt_parent_offset(fdt, 0);
+ if (err != -FDT_ERR_NOTFOUND)
+ FAIL("fdt_parent_offset(/) returns %d instead of "
+ "-FDT_ERR_NOTFOUND", err);
+
+ PASS();
+}
diff --git a/src/dtc/tests/path-references.c b/src/dtc/tests/path-references.c
new file mode 100644
index 0000000..0746b3f
--- /dev/null
+++ b/src/dtc/tests/path-references.c
@@ -0,0 +1,82 @@
+/*
+ * 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>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+static void check_ref(const void *fdt, int node, const char *checkpath)
+{
+ const char *p;
+ int len;
+
+ p = fdt_getprop(fdt, node, "ref", &len);
+ if (!p)
+ FAIL("fdt_getprop(%d, \"ref\"): %s", node, fdt_strerror(len));
+ if (!streq(p, checkpath))
+ FAIL("'ref' in node at %d has value \"%s\" instead of \"%s\"",
+ node, p, checkpath);
+
+ p = fdt_getprop(fdt, node, "lref", &len);
+ if (!p)
+ FAIL("fdt_getprop(%d, \"lref\"): %s", node, fdt_strerror(len));
+ if (!streq(p, checkpath))
+ FAIL("'lref' in node at %d has value \"%s\" instead of \"%s\"",
+ node, p, checkpath);
+}
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ const char *p;
+ int len, multilen;
+ int n1, n2;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ n1 = fdt_path_offset(fdt, "/node1");
+ if (n1 < 0)
+ FAIL("fdt_path_offset(/node1): %s", fdt_strerror(n1));
+ n2 = fdt_path_offset(fdt, "/node2");
+ if (n2 < 0)
+ FAIL("fdt_path_offset(/node2): %s", fdt_strerror(n2));
+
+ check_ref(fdt, n1, "/node2");
+ check_ref(fdt, n2, "/node1");
+
+ /* Check multiple reference */
+ multilen = strlen("/node1") + strlen("/node2") + 2;
+ p = fdt_getprop(fdt, 0, "multiref", &len);
+ if (!p)
+ FAIL("fdt_getprop(0, \"multiref\"): %s", fdt_strerror(len));
+ if (len != multilen)
+ FAIL("multiref has wrong length, %d instead of %d",
+ len, multilen);
+ if ((!streq(p, "/node1") || !streq(p + strlen("/node1") + 1, "/node2")))
+ FAIL("multiref has wrong value");
+
+ PASS();
+}
diff --git a/src/dtc/tests/path-references.dts b/src/dtc/tests/path-references.dts
new file mode 100644
index 0000000..91e7ef7
--- /dev/null
+++ b/src/dtc/tests/path-references.dts
@@ -0,0 +1,14 @@
+/dts-v1/;
+
+/ {
+ /* Check multiple references case */
+ multiref = &n1 , &n2;
+ n1: node1 {
+ ref = &{/node2}; /* reference precedes target */
+ lref = &n2;
+ };
+ n2: node2 {
+ ref = &{/node1}; /* reference after target */
+ lref = &n1;
+ };
+};
diff --git a/src/dtc/tests/path_offset.c b/src/dtc/tests/path_offset.c
new file mode 100644
index 0000000..4e5b7a1
--- /dev/null
+++ b/src/dtc/tests/path_offset.c
@@ -0,0 +1,111 @@
+/*
+ * 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>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+static int check_subnode(void *fdt, int parent, const char *name)
+{
+ int offset;
+ const struct fdt_node_header *nh;
+ uint32_t tag;
+
+ verbose_printf("Checking subnode \"%s\" of %d...", name, parent);
+ offset = fdt_subnode_offset(fdt, parent, name);
+ verbose_printf("offset %d...", offset);
+ if (offset < 0)
+ FAIL("fdt_subnode_offset(\"%s\"): %s", name, fdt_strerror(offset));
+ nh = fdt_offset_ptr(fdt, offset, sizeof(*nh));
+ verbose_printf("pointer %p\n", nh);
+ if (! nh)
+ FAIL("NULL retrieving subnode \"%s\"", name);
+
+ tag = fdt32_to_cpu(nh->tag);
+
+ if (tag != FDT_BEGIN_NODE)
+ FAIL("Incorrect tag 0x%08x on property \"%s\"", tag, name);
+ if (!nodename_eq(nh->name, name))
+ FAIL("Subnode name mismatch \"%s\" instead of \"%s\"",
+ nh->name, name);
+
+ return offset;
+}
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ int root_offset;
+ int subnode1_offset, subnode2_offset;
+ int subnode1_offset_p, subnode2_offset_p;
+ int subsubnode1_offset, subsubnode2_offset, subsubnode2_offset2;
+ int subsubnode1_offset_p, subsubnode2_offset_p, subsubnode2_offset2_p;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ root_offset = fdt_path_offset(fdt, "/");
+ if (root_offset < 0)
+ FAIL("fdt_path_offset(\"/\") failed: %s",
+ fdt_strerror(root_offset));
+ else if (root_offset != 0)
+ FAIL("fdt_path_offset(\"/\") returns incorrect offset %d",
+ root_offset);
+ subnode1_offset = check_subnode(fdt, 0, "subnode@1");
+ subnode2_offset = check_subnode(fdt, 0, "subnode@2");
+
+ subnode1_offset_p = fdt_path_offset(fdt, "/subnode@1");
+ subnode2_offset_p = fdt_path_offset(fdt, "/subnode@2");
+
+ if (subnode1_offset != subnode1_offset_p)
+ FAIL("Mismatch between subnode_offset (%d) and path_offset (%d)",
+ subnode1_offset, subnode1_offset_p);
+
+ if (subnode2_offset != subnode2_offset_p)
+ FAIL("Mismatch between subnode_offset (%d) and path_offset (%d)",
+ subnode2_offset, subnode2_offset_p);
+
+ subsubnode1_offset = check_subnode(fdt, subnode1_offset, "subsubnode");
+ subsubnode2_offset = check_subnode(fdt, subnode2_offset, "subsubnode@0");
+ subsubnode2_offset2 = check_subnode(fdt, subnode2_offset, "subsubnode");
+
+ subsubnode1_offset_p = fdt_path_offset(fdt, "/subnode@1/subsubnode");
+ subsubnode2_offset_p = fdt_path_offset(fdt, "/subnode@2/subsubnode@0");
+ subsubnode2_offset2_p = fdt_path_offset(fdt, "/subnode@2/subsubnode");
+
+ if (subsubnode1_offset != subsubnode1_offset_p)
+ FAIL("Mismatch between subnode_offset (%d) and path_offset (%d)",
+ subsubnode1_offset, subsubnode1_offset_p);
+
+ if (subsubnode2_offset != subsubnode2_offset_p)
+ FAIL("Mismatch between subnode_offset (%d) and path_offset (%d)",
+ subsubnode2_offset, subsubnode2_offset_p);
+
+ if (subsubnode2_offset2 != subsubnode2_offset2_p)
+ FAIL("Mismatch between subnode_offset (%d) and path_offset (%d)",
+ subsubnode2_offset2, subsubnode2_offset2_p);
+
+ PASS();
+}
diff --git a/src/dtc/tests/path_offset_aliases.c b/src/dtc/tests/path_offset_aliases.c
new file mode 100644
index 0000000..78d5a46
--- /dev/null
+++ b/src/dtc/tests/path_offset_aliases.c
@@ -0,0 +1,58 @@
+/*
+ * 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>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+static void check_alias(void *fdt, const char *full_path, const char *alias_path)
+{
+ int offset, offset_a;
+
+ offset = fdt_path_offset(fdt, full_path);
+ offset_a = fdt_path_offset(fdt, alias_path);
+
+ if (offset != offset_a)
+ FAIL("Mismatch between %s path_offset (%d) and %s path_offset alias (%d)",
+ full_path, offset, alias_path, offset_a);
+}
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ check_alias(fdt, "/subnode@1", "s1");
+ check_alias(fdt, "/subnode@1/subsubnode", "ss1");
+ check_alias(fdt, "/subnode@1/subsubnode", "s1/subsubnode");
+ check_alias(fdt, "/subnode@1/subsubnode/subsubsubnode", "sss1");
+ check_alias(fdt, "/subnode@1/subsubnode/subsubsubnode", "ss1/subsubsubnode");
+ check_alias(fdt, "/subnode@1/subsubnode/subsubsubnode", "s1/subsubnode/subsubsubnode");
+
+ PASS();
+}
diff --git a/src/dtc/tests/phandle_format.c b/src/dtc/tests/phandle_format.c
new file mode 100644
index 0000000..5874ae7
--- /dev/null
+++ b/src/dtc/tests/phandle_format.c
@@ -0,0 +1,77 @@
+/*
+ * 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>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+#define PHANDLE_LEGACY 0x1
+#define PHANDLE_EPAPR 0x2
+#define PHANDLE_BOTH 0x3
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ int phandle_format;
+ int n4;
+ uint32_t h4;
+
+ if (argc != 3)
+ CONFIG("Usage: %s <dtb file> <legacy|epapr|both>\n", argv[0]);
+
+ test_init(argc, argv);
+ fdt = load_blob(argv[1]);
+
+ if (streq(argv[2], "legacy"))
+ phandle_format = PHANDLE_LEGACY;
+ else if (streq(argv[2], "epapr"))
+ phandle_format = PHANDLE_EPAPR;
+ else if (streq(argv[2], "both"))
+ phandle_format = PHANDLE_BOTH;
+ else
+ CONFIG("Usage: %s <dtb file> <legacy|epapr|both>\n", argv[0]);
+
+ n4 = fdt_path_offset(fdt, "/node4");
+ if (n4 < 0)
+ FAIL("fdt_path_offset(/node4): %s", fdt_strerror(n4));
+
+ h4 = fdt_get_phandle(fdt, n4);
+ if ((h4 == 0) || (h4 == -1))
+ FAIL("/node4 has bad phandle 0x%x\n", h4);
+
+ if (phandle_format & PHANDLE_LEGACY)
+ check_getprop_cell(fdt, n4, "linux,phandle", h4);
+ else
+ if (fdt_getprop(fdt, n4, "linux,phandle", NULL))
+ FAIL("linux,phandle property present in non-legacy mode");
+
+ if (phandle_format & PHANDLE_EPAPR)
+ check_getprop_cell(fdt, n4, "phandle", h4);
+ else
+ if (fdt_getprop(fdt, n4, "phandle", NULL))
+ FAIL("phandle property present in legacy-only mode");
+
+ PASS();
+}
diff --git a/src/dtc/tests/prop-after-subnode.dts b/src/dtc/tests/prop-after-subnode.dts
new file mode 100644
index 0000000..6dd0b66
--- /dev/null
+++ b/src/dtc/tests/prop-after-subnode.dts
@@ -0,0 +1,9 @@
+/dts-v1/;
+
+/ {
+ node1 {
+ };
+ prop;
+ node2 {
+ };
+};
diff --git a/src/dtc/tests/propname_escapes.c b/src/dtc/tests/propname_escapes.c
new file mode 100644
index 0000000..e91bd99
--- /dev/null
+++ b/src/dtc/tests/propname_escapes.c
@@ -0,0 +1,42 @@
+/*
+ * 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>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ check_getprop_cell(fdt, 0, "#address-cells", 1);
+ check_getprop_cell(fdt, 0, "#gpio-cells", 2);
+
+ PASS();
+}
diff --git a/src/dtc/tests/propname_escapes.dts b/src/dtc/tests/propname_escapes.dts
new file mode 100644
index 0000000..9f70618
--- /dev/null
+++ b/src/dtc/tests/propname_escapes.dts
@@ -0,0 +1,6 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ \#gpio-cells = <2>;
+};
diff --git a/src/dtc/tests/references.c b/src/dtc/tests/references.c
new file mode 100644
index 0000000..c9d05a2
--- /dev/null
+++ b/src/dtc/tests/references.c
@@ -0,0 +1,108 @@
+/*
+ * 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>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+static void check_ref(const void *fdt, int node, uint32_t checkref)
+{
+ const uint32_t *p;
+ uint32_t ref;
+ int len;
+
+ p = fdt_getprop(fdt, node, "ref", &len);
+ if (!p)
+ FAIL("fdt_getprop(%d, \"ref\"): %s", node, fdt_strerror(len));
+ if (len != sizeof(*p))
+ FAIL("'ref' in node at %d has wrong size (%d instead of %zd)",
+ node, len, sizeof(*p));
+ ref = fdt32_to_cpu(*p);
+ if (ref != checkref)
+ FAIL("'ref' in node at %d has value 0x%x instead of 0x%x",
+ node, ref, checkref);
+
+ p = fdt_getprop(fdt, node, "lref", &len);
+ if (!p)
+ FAIL("fdt_getprop(%d, \"lref\"): %s", node, fdt_strerror(len));
+ if (len != sizeof(*p))
+ FAIL("'lref' in node at %d has wrong size (%d instead of %zd)",
+ node, len, sizeof(*p));
+ ref = fdt32_to_cpu(*p);
+ if (ref != checkref)
+ FAIL("'lref' in node at %d has value 0x%x instead of 0x%x",
+ node, ref, checkref);
+}
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ int n1, n2, n3, n4, n5;
+ uint32_t h1, h2, h4, h5;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ n1 = fdt_path_offset(fdt, "/node1");
+ if (n1 < 0)
+ FAIL("fdt_path_offset(/node1): %s", fdt_strerror(n1));
+ n2 = fdt_path_offset(fdt, "/node2");
+ if (n2 < 0)
+ FAIL("fdt_path_offset(/node2): %s", fdt_strerror(n2));
+ n3 = fdt_path_offset(fdt, "/node3");
+ if (n3 < 0)
+ FAIL("fdt_path_offset(/node3): %s", fdt_strerror(n3));
+ n4 = fdt_path_offset(fdt, "/node4");
+ if (n4 < 0)
+ FAIL("fdt_path_offset(/node4): %s", fdt_strerror(n4));
+ n5 = fdt_path_offset(fdt, "/node5");
+ if (n5 < 0)
+ FAIL("fdt_path_offset(/node5): %s", fdt_strerror(n5));
+
+ h1 = fdt_get_phandle(fdt, n1);
+ h2 = fdt_get_phandle(fdt, n2);
+ h4 = fdt_get_phandle(fdt, n4);
+ h5 = fdt_get_phandle(fdt, n5);
+
+ if (h1 != 0x2000)
+ FAIL("/node1 has wrong phandle, 0x%x instead of 0x%x",
+ h1, 0x2000);
+ if (h2 != 0x1)
+ FAIL("/node2 has wrong phandle, 0x%x instead of 0x%x",
+ h2, 0x1);
+ if ((h4 == 0x2000) || (h4 == 0x1) || (h4 == 0))
+ FAIL("/node4 has bad phandle, 0x%x", h4);
+
+ if ((h5 == 0) || (h5 == -1))
+ FAIL("/node5 has bad phandle, 0x%x", h5);
+ if ((h5 == h4) || (h5 == h2) || (h5 == h1))
+ FAIL("/node5 has duplicate phandle, 0x%x", h5);
+
+ check_ref(fdt, n1, h2);
+ check_ref(fdt, n2, h1);
+ check_ref(fdt, n3, h4);
+
+ PASS();
+}
diff --git a/src/dtc/tests/references.dts b/src/dtc/tests/references.dts
new file mode 100644
index 0000000..640c931
--- /dev/null
+++ b/src/dtc/tests/references.dts
@@ -0,0 +1,34 @@
+/dts-v1/;
+
+/ {
+ /* Explicit phandles */
+ n1: node1 {
+ linux,phandle = <0x2000>;
+ ref = <&{/node2}>; /* reference precedes target */
+ lref = <&n2>;
+ };
+ n2: node2 {
+ phandle = <0x1>;
+ ref = <&{/node1}>; /* reference after target */
+ lref = <&n1>;
+ };
+
+ /* Implicit phandles */
+ n3: node3 {
+ ref = <&{/node4}>;
+ lref = <&n4>;
+ };
+ n4: node4 {
+ };
+
+ /* Explicit phandle with implicit value */
+ /* This self-reference is the standard way to tag a node as requiring
+ * a phandle (perhaps for reference by nodes that will be dynamically
+ * added) without explicitly allocating it a phandle.
+ * The self-reference requires some special internal handling, though
+ * so check it actually works */
+ n5: node5 {
+ linux,phandle = <&n5>;
+ phandle = <&n5>;
+ };
+};
diff --git a/src/dtc/tests/reg-ranges-root.dts b/src/dtc/tests/reg-ranges-root.dts
new file mode 100644
index 0000000..9935b41
--- /dev/null
+++ b/src/dtc/tests/reg-ranges-root.dts
@@ -0,0 +1,8 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x1000 0x10>;
+ ranges = <0x1000 0x2000 0x1000>;
+};
diff --git a/src/dtc/tests/reuse-label.dts b/src/dtc/tests/reuse-label.dts
new file mode 100644
index 0000000..98b5ca9
--- /dev/null
+++ b/src/dtc/tests/reuse-label.dts
@@ -0,0 +1,15 @@
+/dts-v1/;
+
+/ {
+ label: property1 = "foo";
+ label: property2 = "bar";
+
+ test1 = &label;
+
+ label: node1 {
+ prop = "foo";
+ };
+ label: node2 {
+ prop = "bar";
+ };
+};
diff --git a/src/dtc/tests/reuse-label1.dts b/src/dtc/tests/reuse-label1.dts
new file mode 100644
index 0000000..f229569
--- /dev/null
+++ b/src/dtc/tests/reuse-label1.dts
@@ -0,0 +1,10 @@
+/dts-v1/;
+
+/ {
+ label: node1 {
+ prop = "foo";
+ };
+ label: node2 {
+ prop = "bar";
+ };
+};
diff --git a/src/dtc/tests/reuse-label2.dts b/src/dtc/tests/reuse-label2.dts
new file mode 100644
index 0000000..01ea6b2
--- /dev/null
+++ b/src/dtc/tests/reuse-label2.dts
@@ -0,0 +1,6 @@
+/dts-v1/;
+
+/ {
+ label: property1 = "foo";
+ label: property2 = "bar";
+};
diff --git a/src/dtc/tests/reuse-label3.dts b/src/dtc/tests/reuse-label3.dts
new file mode 100644
index 0000000..fa3d2c7
--- /dev/null
+++ b/src/dtc/tests/reuse-label3.dts
@@ -0,0 +1,9 @@
+/dts-v1/;
+
+/ {
+ label: property = "foo";
+
+ label: node {
+ property = "foo";
+ };
+};
diff --git a/src/dtc/tests/reuse-label4.dts b/src/dtc/tests/reuse-label4.dts
new file mode 100644
index 0000000..6805de3
--- /dev/null
+++ b/src/dtc/tests/reuse-label4.dts
@@ -0,0 +1,5 @@
+/dts-v1/;
+
+/ {
+ property = label: "foo" label:;
+};
diff --git a/src/dtc/tests/reuse-label5.dts b/src/dtc/tests/reuse-label5.dts
new file mode 100644
index 0000000..b7238e6
--- /dev/null
+++ b/src/dtc/tests/reuse-label5.dts
@@ -0,0 +1,6 @@
+/dts-v1/;
+
+/ {
+ prop1 = label: "foo";
+ prop2 = "bar" label:;
+};
diff --git a/src/dtc/tests/reuse-label6.dts b/src/dtc/tests/reuse-label6.dts
new file mode 100644
index 0000000..f5d507c
--- /dev/null
+++ b/src/dtc/tests/reuse-label6.dts
@@ -0,0 +1,6 @@
+/dts-v1/;
+
+/ {
+ label: prop1 = "foo";
+ prop2 = "bar" label:;
+};
diff --git a/src/dtc/tests/root_node.c b/src/dtc/tests/root_node.c
new file mode 100644
index 0000000..58aebf6
--- /dev/null
+++ b/src/dtc/tests/root_node.c
@@ -0,0 +1,52 @@
+/*
+ * 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>
+#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;
+ const struct fdt_node_header *nh;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ nh = fdt_offset_ptr(fdt, 0, sizeof(*nh));
+
+ if (! nh)
+ FAIL("NULL retrieving root node");
+
+ if (fdt32_to_cpu(nh->tag) != FDT_BEGIN_NODE)
+ FAIL("Wrong tag on root node");
+
+ if (strlen(nh->name) != 0)
+ FAIL("Wrong name for root node, \"%s\" instead of empty",
+ nh->name);
+
+ PASS();
+}
diff --git a/src/dtc/tests/run_tests.sh b/src/dtc/tests/run_tests.sh
new file mode 100755
index 0000000..c0a136b
--- /dev/null
+++ b/src/dtc/tests/run_tests.sh
@@ -0,0 +1,644 @@
+#! /bin/sh
+
+. ./tests.sh
+
+if [ -z "$CC" ]; then
+ CC=gcc
+fi
+
+export QUIET_TEST=1
+
+export VALGRIND=
+VGCODE=126
+
+tot_tests=0
+tot_pass=0
+tot_fail=0
+tot_config=0
+tot_vg=0
+tot_strange=0
+
+base_run_test() {
+ tot_tests=$((tot_tests + 1))
+ if VALGRIND="$VALGRIND" "$@"; then
+ tot_pass=$((tot_pass + 1))
+ else
+ ret="$?"
+ if [ "$ret" -eq 1 ]; then
+ tot_config=$((tot_config + 1))
+ elif [ "$ret" -eq 2 ]; then
+ tot_fail=$((tot_fail + 1))
+ elif [ "$ret" -eq $VGCODE ]; then
+ tot_vg=$((tot_vg + 1))
+ else
+ tot_strange=$((tot_strange + 1))
+ fi
+ fi
+}
+
+shorten_echo () {
+ limit=32
+ echo -n "$1"
+ shift
+ for x; do
+ if [ ${#x} -le $limit ]; then
+ echo -n " $x"
+ else
+ short=$(echo "$x" | head -c$limit)
+ echo -n " \"$short\"...<${#x} bytes>"
+ fi
+ done
+}
+
+run_test () {
+ echo -n "$@: "
+ if [ -n "$VALGRIND" -a -f $1.supp ]; then
+ VGSUPP="--suppressions=$1.supp"
+ fi
+ base_run_test $VALGRIND $VGSUPP "./$@"
+}
+
+run_sh_test () {
+ echo -n "$@: "
+ base_run_test sh "$@"
+}
+
+wrap_test () {
+ (
+ if verbose_run "$@"; then
+ PASS
+ else
+ ret="$?"
+ if [ "$ret" -gt 127 ]; then
+ signame=$(kill -l $((ret - 128)))
+ FAIL "Killed by SIG$signame"
+ else
+ FAIL "Returned error code $ret"
+ fi
+ fi
+ )
+}
+
+run_wrap_test () {
+ shorten_echo "$@: "
+ base_run_test wrap_test "$@"
+}
+
+wrap_error () {
+ (
+ if verbose_run "$@"; then
+ FAIL "Expected non-zero return code"
+ else
+ ret="$?"
+ if [ "$ret" -gt 127 ]; then
+ signame=$(kill -l $((ret - 128)))
+ FAIL "Killed by SIG$signame"
+ else
+ PASS
+ fi
+ fi
+ )
+}
+
+run_wrap_error_test () {
+ shorten_echo "$@"
+ echo -n " {!= 0}: "
+ base_run_test wrap_error "$@"
+}
+
+run_dtc_test () {
+ echo -n "dtc $@: "
+ base_run_test wrap_test $VALGRIND $DTC "$@"
+}
+
+asm_to_so () {
+ $CC -shared -o $1.test.so data.S $1.test.s
+}
+
+asm_to_so_test () {
+ run_wrap_test asm_to_so "$@"
+}
+
+run_fdtget_test () {
+ expect="$1"
+ shift
+ echo -n "fdtget-runtest.sh "$expect" $@: "
+ base_run_test sh fdtget-runtest.sh "$expect" "$@"
+}
+
+run_fdtput_test () {
+ expect="$1"
+ shift
+ shorten_echo fdtput-runtest.sh "$expect" "$@"
+ echo -n ": "
+ base_run_test sh fdtput-runtest.sh "$expect" "$@"
+}
+
+tree1_tests () {
+ TREE=$1
+
+ # Read-only tests
+ run_test get_mem_rsv $TREE
+ run_test root_node $TREE
+ run_test find_property $TREE
+ run_test subnode_offset $TREE
+ run_test path_offset $TREE
+ run_test get_name $TREE
+ run_test getprop $TREE
+ run_test get_phandle $TREE
+ run_test get_path $TREE
+ run_test supernode_atdepth_offset $TREE
+ run_test parent_offset $TREE
+ run_test node_offset_by_prop_value $TREE
+ run_test node_offset_by_phandle $TREE
+ run_test node_check_compatible $TREE
+ run_test node_offset_by_compatible $TREE
+ run_test notfound $TREE
+
+ # Write-in-place tests
+ run_test setprop_inplace $TREE
+ run_test nop_property $TREE
+ run_test nop_node $TREE
+}
+
+tree1_tests_rw () {
+ TREE=$1
+
+ # Read-write tests
+ run_test set_name $TREE
+ run_test setprop $TREE
+ run_test del_property $TREE
+ run_test del_node $TREE
+}
+
+check_tests () {
+ tree="$1"
+ shift
+ run_sh_test 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
+}
+
+ALL_LAYOUTS="mts mst tms tsm smt stm"
+
+libfdt_tests () {
+ tree1_tests test_tree1.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
+
+ # fdt_move tests
+ for tree in test_tree1.dtb sw_tree1.test.dtb unfinished_tree1.test.dtb; do
+ rm -f moved.$tree shunted.$tree deshunted.$tree
+ run_test move_and_save $tree
+ run_test dtbs_equal_ordered $tree moved.$tree
+ run_test dtbs_equal_ordered $tree shunted.$tree
+ run_test dtbs_equal_ordered $tree deshunted.$tree
+ done
+
+ # v16 and alternate layout tests
+ for tree in test_tree1.dtb; do
+ for version in 17 16; do
+ for layout in $ALL_LAYOUTS; do
+ run_test mangle-layout $tree $version $layout
+ tree1_tests v$version.$layout.$tree
+ run_test dtbs_equal_ordered $tree v$version.$layout.$tree
+ done
+ done
+ done
+
+ # Read-write tests
+ for basetree in test_tree1.dtb; do
+ for version in 17 16; do
+ for layout in $ALL_LAYOUTS; do
+ tree=v$version.$layout.$basetree
+ rm -f opened.$tree repacked.$tree
+ run_test open_pack $tree
+ tree1_tests opened.$tree
+ tree1_tests repacked.$tree
+
+ tree1_tests_rw $tree
+ tree1_tests_rw opened.$tree
+ tree1_tests_rw repacked.$tree
+ done
+ done
+ done
+ run_test rw_tree1
+ tree1_tests rw_tree1.test.dtb
+ 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_test dtbs_equal_ordered appendprop2.test.dtb appendprop.test.dtb
+
+ for basetree in test_tree1.dtb sw_tree1.test.dtb rw_tree1.test.dtb; do
+ run_test nopulate $basetree
+ run_test dtbs_equal_ordered $basetree noppy.$basetree
+ tree1_tests noppy.$basetree
+ tree1_tests_rw noppy.$basetree
+ done
+
+ run_dtc_test -I dts -O dtb -o subnode_iterate.dtb subnode_iterate.dts
+ run_test subnode_iterate subnode_iterate.dtb
+
+ # Tests for behaviour on various sorts of corrupted trees
+ run_test truncated_property
+
+ # Specific bug tests
+ run_test add_subnode_with_nops
+}
+
+dtc_tests () {
+ run_dtc_test -I dts -O dtb -o dtc_tree1.test.dtb 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_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 dtc_escapes.test.dtb 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_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_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_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_test references dtc_references.test.dtb
+
+ run_dtc_test -I dts -O dtb -o dtc_path-references.test.dtb path-references.dts
+ run_test path-references dtc_path-references.test.dtb
+
+ run_test phandle_format dtc_references.test.dtb both
+ for f in legacy epapr both; do
+ run_dtc_test -I dts -O dtb -H $f -o dtc_references.test.$f.dtb references.dts
+ run_test phandle_format dtc_references.test.$f.dtb $f
+ done
+
+ run_dtc_test -I dts -O dtb -o multilabel.test.dtb 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 dtc_comments.test.dtb comments.dts
+ run_dtc_test -I dts -O dtb -o dtc_comments-cmp.test.dtb comments-cmp.dts
+ run_test dtbs_equal_ordered dtc_comments.test.dtb dtc_comments-cmp.test.dtb
+
+ # Check aliases support in fdt_path_offset
+ run_dtc_test -I dts -O dtb -o aliases.dtb aliases.dts
+ run_test get_alias aliases.dtb
+ run_test path_offset_aliases aliases.dtb
+
+ # Check /include/ directive
+ run_dtc_test -I dts -O dtb -o includes.test.dtb 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
+
+ # Check boot_cpuid_phys handling
+ run_dtc_test -I dts -O dtb -o boot_cpuid.test.dtb 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_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
+ run_test boot-cpuid preserve_boot_cpuid.test.dtb 16
+ run_test dtbs_equal_ordered preserve_boot_cpuid.test.dtb boot_cpuid.test.dtb
+
+ run_dtc_test -I dtb -O dtb -o preserve_boot_cpuid_17.test.dtb boot_cpuid_17.test.dtb
+ run_test boot-cpuid preserve_boot_cpuid_17.test.dtb 17
+ run_test dtbs_equal_ordered preserve_boot_cpuid_17.test.dtb boot_cpuid_17.test.dtb
+
+ run_dtc_test -I dtb -O dtb -b17 -o override17_boot_cpuid.test.dtb boot_cpuid.test.dtb
+ run_test boot-cpuid override17_boot_cpuid.test.dtb 17
+
+ run_dtc_test -I dtb -O dtb -b0 -o override0_boot_cpuid_17.test.dtb boot_cpuid_17.test.dtb
+ run_test boot-cpuid override0_boot_cpuid_17.test.dtb 0
+
+
+ # Check -Oasm mode
+ 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
+ asm_to_so_test oasm_$tree
+ run_dtc_test -I dts -O dtb -o $tree.test.dtb $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
+
+ run_test value-labels ./oasm_value-labels.dts.test.so
+
+ # Check -Odts mode preserve all dtb information
+ for tree in test_tree1.dtb dtc_tree1.test.dtb dtc_escapes.test.dtb \
+ dtc_extra-terminating-null.test.dtb dtc_references.test.dtb; do
+ run_dtc_test -I dtb -O dts -o odts_$tree.test.dts $tree
+ run_dtc_test -I dts -O dtb -o odts_$tree.test.dtb odts_$tree.test.dts
+ run_test dtbs_equal_ordered $tree odts_$tree.test.dtb
+ done
+
+ # Check version conversions
+ for tree in test_tree1.dtb ; do
+ for aver in 1 2 3 16 17; do
+ atree="ov${aver}_$tree.test.dtb"
+ run_dtc_test -I dtb -O dtb -V$aver -o $atree $tree
+ for bver in 16 17; do
+ btree="ov${bver}_$atree"
+ run_dtc_test -I dtb -O dtb -V$bver -o $btree $atree
+ run_test dtbs_equal_ordered $btree $tree
+ done
+ done
+ done
+
+ # Check merge/overlay functionality
+ run_dtc_test -I dts -O dtb -o dtc_tree1_merge.test.dtb 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
+ tree1_tests dtc_tree1_merge_labelled.test.dtb test_tree1.dtb
+ run_dtc_test -I dts -O dtb -o multilabel_merge.test.dtb 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
+ tree1_tests dtc_tree1_merge_path.test.dtb test_tree1.dtb
+
+ # Check prop/node delete functionality
+ run_dtc_test -I dts -O dtb -o dtc_tree1_delete.test.dtb 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 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 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
+ 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
+
+ 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
+
+ # 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
+
+ # Check for proper behaviour reading from stdin
+ run_dtc_test -I dts -O dtb -o stdin_dtc_tree1.test.dtb - < 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
+
+ # Check integer expresisons
+ run_test integer-expressions -g integer-expressions.test.dts
+ run_dtc_test -I dts -O dtb -o integer-expressions.test.dtb integer-expressions.test.dts
+ 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
+
+ # 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
+
+ # 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_dtc_test -I dts -O dtb -o search_paths_subdir.dtb \
+ search_dir_b/search_paths_subdir.dts
+}
+
+cmp_tests () {
+ basetree="$1"
+ shift
+ wrongtrees="$@"
+
+ run_test dtb_reverse $basetree
+
+ # First dtbs_equal_ordered
+ run_test dtbs_equal_ordered $basetree $basetree
+ run_test dtbs_equal_ordered -n $basetree $basetree.reversed.test.dtb
+ for tree in $wrongtrees; do
+ run_test dtbs_equal_ordered -n $basetree $tree
+ done
+
+ # now unordered
+ run_test dtbs_equal_unordered $basetree $basetree
+ run_test dtbs_equal_unordered $basetree $basetree.reversed.test.dtb
+ run_test dtbs_equal_unordered $basetree.reversed.test.dtb $basetree
+ for tree in $wrongtrees; do
+ run_test dtbs_equal_unordered -n $basetree $tree
+ done
+
+ # now dtc --sort
+ run_dtc_test -I dtb -O dtb -s -o $basetree.sorted.test.dtb $basetree
+ run_test dtbs_equal_unordered $basetree $basetree.sorted.test.dtb
+ run_dtc_test -I dtb -O dtb -s -o $basetree.reversed.sorted.test.dtb $basetree.reversed.test.dtb
+ run_test dtbs_equal_unordered $basetree.reversed.test.dtb $basetree.reversed.sorted.test.dtb
+ run_test dtbs_equal_ordered $basetree.sorted.test.dtb $basetree.reversed.sorted.test.dtb
+}
+
+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
+ WRONG_TREE1="$WRONG_TREE1 test_tree1_wrong$x.test.dtb"
+ done
+ cmp_tests test_tree1.dtb $WRONG_TREE1
+}
+
+fdtget_tests () {
+ dts=label01.dts
+ dtb=$dts.fdtget.test.dtb
+ run_dtc_test -O dtb -o $dtb $dts
+
+ # run_fdtget_test <expected-result> [<flags>] <file> <node> <property>
+ run_fdtget_test "MyBoardName" $dtb / model
+ run_fdtget_test "MyBoardName MyBoardFamilyName" $dtb / compatible
+ run_fdtget_test "77 121 66 111 \
+97 114 100 78 97 109 101 0 77 121 66 111 97 114 100 70 97 109 105 \
+108 121 78 97 109 101 0" -t bu $dtb / compatible
+ run_fdtget_test "MyBoardName MyBoardFamilyName" -t s $dtb / compatible
+ run_fdtget_test 32768 $dtb /cpus/PowerPC,970@1 d-cache-size
+ run_fdtget_test 8000 -tx $dtb /cpus/PowerPC,970@1 d-cache-size
+ run_fdtget_test "61 62 63 0" -tbx $dtb /randomnode tricky1
+ run_fdtget_test "a b c d de ea ad be ef" -tbx $dtb /randomnode blob
+
+ # Here the property size is not a multiple of 4 bytes, so it should fail
+ run_wrap_error_test $DTGET -tlx $dtb /randomnode mixed
+ run_fdtget_test "6162 6300 1234 0 a 0 b 0 c" -thx $dtb /randomnode mixed
+ run_fdtget_test "61 62 63 0 12 34 0 0 0 a 0 0 0 b 0 0 0 c" \
+ -thhx $dtb /randomnode mixed
+ run_wrap_error_test $DTGET -ts $dtb /randomnode doctor-who
+
+ # Test multiple arguments
+ run_fdtget_test "MyBoardName\nmemory" -ts $dtb / model /memory device_type
+
+ # Test defaults
+ run_wrap_error_test $DTGET -tx $dtb /randomnode doctor-who
+ run_fdtget_test "<the dead silence>" -tx \
+ -d "<the dead silence>" $dtb /randomnode doctor-who
+ run_fdtget_test "<blink>" -tx -d "<blink>" $dtb /memory doctor-who
+}
+
+fdtput_tests () {
+ dts=label01.dts
+ dtb=$dts.fdtput.test.dtb
+ text=lorem.txt
+
+ # Allow just enough space for $text
+ run_dtc_test -O dtb -p $(stat -c %s $text) -o $dtb $dts
+
+ # run_fdtput_test <expected-result> <file> <node> <property> <flags> <value>
+ run_fdtput_test "a_model" $dtb / model -ts "a_model"
+ run_fdtput_test "board1 board2" $dtb / compatible -ts board1 board2
+ run_fdtput_test "board1 board2" $dtb / compatible -ts "board1 board2"
+ run_fdtput_test "32768" $dtb /cpus/PowerPC,970@1 d-cache-size "" "32768"
+ run_fdtput_test "8001" $dtb /cpus/PowerPC,970@1 d-cache-size -tx 0x8001
+ run_fdtput_test "2 3 12" $dtb /randomnode tricky1 -tbi "02 003 12"
+ run_fdtput_test "a b c ea ad be ef" $dtb /randomnode blob \
+ -tbx "a b c ea ad be ef"
+ run_fdtput_test "a0b0c0d deeaae ef000000" $dtb /randomnode blob \
+ -tx "a0b0c0d deeaae ef000000"
+ run_fdtput_test "$(cat $text)" $dtb /randomnode blob -ts "$(cat $text)"
+
+ # Test expansion of the blob when insufficient room for property
+ 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
+
+ # Node creation
+ run_wrap_error_test $DTPUT $dtb -c /baldrick sod
+ run_wrap_test $DTPUT $dtb -c /chosen/son /chosen/daughter
+ run_fdtput_test "eva" $dtb /chosen/daughter name "" -ts "eva"
+ run_fdtput_test "adam" $dtb /chosen/son name "" -ts "adam"
+
+ # Not allowed to create an existing node
+ run_wrap_error_test $DTPUT $dtb -c /chosen
+ run_wrap_error_test $DTPUT $dtb -c /chosen/son
+
+ # Automatic node creation
+ run_wrap_test $DTPUT $dtb -cp /blackadder/the-second/turnip \
+ /blackadder/the-second/potato
+ run_fdtput_test 1000 $dtb /blackadder/the-second/turnip cost "" 1000
+ run_fdtput_test "fine wine" $dtb /blackadder/the-second/potato drink \
+ "-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
+ run_wrap_test $DTPUT $dtb -cp "$(cat $text $text)/longish"
+
+ # Allowed to create an existing node with -p
+ run_wrap_test $DTPUT $dtb -cp /chosen
+ run_wrap_test $DTPUT $dtb -cp /chosen/son
+
+ # TODO: Add tests for verbose mode?
+}
+
+utilfdt_tests () {
+ run_test utilfdt_test
+}
+
+while getopts "vt:m" ARG ; do
+ case $ARG in
+ "v")
+ unset QUIET_TEST
+ ;;
+ "t")
+ TESTSETS=$OPTARG
+ ;;
+ "m")
+ VALGRIND="valgrind --tool=memcheck -q --error-exitcode=$VGCODE"
+ ;;
+ esac
+done
+
+if [ -z "$TESTSETS" ]; then
+ TESTSETS="libfdt utilfdt dtc dtbs_equal fdtget fdtput"
+fi
+
+# Make sure we don't have stale blobs lying around
+rm -f *.test.dtb *.test.dts
+
+for set in $TESTSETS; do
+ case $set in
+ "libfdt")
+ libfdt_tests
+ ;;
+ "utilfdt")
+ utilfdt_tests
+ ;;
+ "dtc")
+ dtc_tests
+ ;;
+ "dtbs_equal")
+ dtbs_equal_tests
+ ;;
+ "fdtget")
+ fdtget_tests
+ ;;
+ "fdtput")
+ fdtput_tests
+ ;;
+ esac
+done
+
+echo "********** TEST SUMMARY"
+echo "* Total testcases: $tot_tests"
+echo "* PASS: $tot_pass"
+echo "* FAIL: $tot_fail"
+echo "* Bad configuration: $tot_config"
+if [ -n "$VALGRIND" ]; then
+ echo "* valgrind errors: $tot_vg"
+fi
+echo "* Strange test result: $tot_strange"
+echo "**********"
+
diff --git a/src/dtc/tests/rw_tree1.c b/src/dtc/tests/rw_tree1.c
new file mode 100644
index 0000000..efd4718
--- /dev/null
+++ b/src/dtc/tests/rw_tree1.c
@@ -0,0 +1,95 @@
+/*
+ * 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>
+#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(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, s2;
+
+ 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_tree1"));
+ 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;
+ CHECK(fdt_setprop_string(fdt, s1, "compatible", "subnode1"));
+ CHECK(fdt_setprop_cell(fdt, s1, "prop-int", TEST_VALUE_1));
+ OFF_CHECK(offset, fdt_add_subnode(fdt, s1, "subsubnode"));
+ CHECK(fdt_setprop(fdt, offset, "compatible",
+ "subsubnode1\0subsubnode", 23));
+ CHECK(fdt_setprop_cell(fdt, offset, "prop-int", TEST_VALUE_1));
+ OFF_CHECK(offset, fdt_add_subnode(fdt, s1, "ss1"));
+
+ OFF_CHECK(offset, fdt_add_subnode(fdt, 0, "subnode@2"));
+ s2 = offset;
+ CHECK(fdt_setprop_cell(fdt, s2, "linux,phandle", PHANDLE_1));
+ CHECK(fdt_setprop_cell(fdt, s2, "prop-int", TEST_VALUE_2));
+ OFF_CHECK(offset, fdt_add_subnode(fdt, s2, "subsubnode@0"));
+ CHECK(fdt_setprop_cell(fdt, offset, "linux,phandle", PHANDLE_2));
+ CHECK(fdt_setprop(fdt, offset, "compatible",
+ "subsubnode2\0subsubnode", 23));
+ CHECK(fdt_setprop_cell(fdt, offset, "prop-int", TEST_VALUE_2));
+ OFF_CHECK(offset, fdt_add_subnode(fdt, s2, "ss2"));
+
+ CHECK(fdt_pack(fdt));
+
+ save_blob("rw_tree1.test.dtb", fdt);
+
+ PASS();
+}
diff --git a/src/dtc/tests/search_dir/search_test.dtsi b/src/dtc/tests/search_dir/search_test.dtsi
new file mode 100644
index 0000000..217fb80
--- /dev/null
+++ b/src/dtc/tests/search_dir/search_test.dtsi
@@ -0,0 +1,4 @@
+/include/ "search_test2.dtsi"
+
+/ {
+};
diff --git a/src/dtc/tests/search_dir/search_test2.dtsi b/src/dtc/tests/search_dir/search_test2.dtsi
new file mode 100644
index 0000000..7b9099e
--- /dev/null
+++ b/src/dtc/tests/search_dir/search_test2.dtsi
@@ -0,0 +1,3 @@
+
+/ {
+};
diff --git a/src/dtc/tests/search_dir_b/search_paths_subdir.dts b/src/dtc/tests/search_dir_b/search_paths_subdir.dts
new file mode 100644
index 0000000..5c5c962
--- /dev/null
+++ b/src/dtc/tests/search_dir_b/search_paths_subdir.dts
@@ -0,0 +1,6 @@
+/dts-v1/;
+
+/include/ "search_test_c.dtsi"
+
+/ {
+};
diff --git a/src/dtc/tests/search_dir_b/search_test_b.dtsi b/src/dtc/tests/search_dir_b/search_test_b.dtsi
new file mode 100644
index 0000000..b06a7d6
--- /dev/null
+++ b/src/dtc/tests/search_dir_b/search_test_b.dtsi
@@ -0,0 +1,4 @@
+/include/ "search_test_b2.dtsi"
+
+/ {
+};
diff --git a/src/dtc/tests/search_dir_b/search_test_b2.dtsi b/src/dtc/tests/search_dir_b/search_test_b2.dtsi
new file mode 100644
index 0000000..2526b43
--- /dev/null
+++ b/src/dtc/tests/search_dir_b/search_test_b2.dtsi
@@ -0,0 +1,5 @@
+
+/include/ "search_test.dtsi"
+
+/ {
+};
diff --git a/src/dtc/tests/search_dir_b/search_test_c.dtsi b/src/dtc/tests/search_dir_b/search_test_c.dtsi
new file mode 100644
index 0000000..336d7a2
--- /dev/null
+++ b/src/dtc/tests/search_dir_b/search_test_c.dtsi
@@ -0,0 +1,2 @@
+/ {
+};
diff --git a/src/dtc/tests/search_paths.dts b/src/dtc/tests/search_paths.dts
new file mode 100644
index 0000000..a2bf179
--- /dev/null
+++ b/src/dtc/tests/search_paths.dts
@@ -0,0 +1,6 @@
+/dts-v1/;
+
+/include/ "search_test.dtsi"
+
+/ {
+};
diff --git a/src/dtc/tests/search_paths_b.dts b/src/dtc/tests/search_paths_b.dts
new file mode 100644
index 0000000..6ace6e2
--- /dev/null
+++ b/src/dtc/tests/search_paths_b.dts
@@ -0,0 +1,6 @@
+/dts-v1/;
+
+/include/ "search_test_b.dtsi"
+
+/ {
+};
diff --git a/src/dtc/tests/set_name.c b/src/dtc/tests/set_name.c
new file mode 100644
index 0000000..9861587
--- /dev/null
+++ b/src/dtc/tests/set_name.c
@@ -0,0 +1,90 @@
+/*
+ * 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>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+static void check_set_name(void *fdt, const char *path, const char *newname)
+{
+ int offset;
+ const char *getname, *oldname;
+ int len, err;
+
+ oldname = strrchr(path, '/');
+ if (!oldname)
+ TEST_BUG();
+ oldname += 1;
+
+ offset = fdt_path_offset(fdt, path);
+ if (offset < 0)
+ FAIL("Couldn't find %s", path);
+
+ getname = fdt_get_name(fdt, offset, &len);
+ verbose_printf("fdt_get_name(%d) returns \"%s\" (len=%d)\n",
+ offset, getname, len);
+ if (!getname)
+ FAIL("fdt_get_name(%d): %s", offset, fdt_strerror(len));
+
+ if (strcmp(getname, oldname) != 0)
+ FAIL("fdt_get_name(%s) returned \"%s\" instead of \"%s\"",
+ path, getname, oldname);
+
+ if (len != strlen(getname))
+ FAIL("fdt_get_name(%s) returned length %d instead of %zd",
+ path, len, strlen(getname));
+
+ err = fdt_set_name(fdt, offset, newname);
+ if (err)
+ FAIL("fdt_set_name(%d, \"%s\"): %s", offset, newname,
+ fdt_strerror(err));
+
+ getname = fdt_get_name(fdt, offset, &len);
+ if (!getname)
+ FAIL("fdt_get_name(%d): %s", offset, fdt_strerror(len));
+
+ if (strcmp(getname, newname) != 0)
+ FAIL("fdt_get_name(%s) returned \"%s\" instead of \"%s\"",
+ path, getname, newname);
+
+ if (len != strlen(getname))
+ FAIL("fdt_get_name(%s) returned length %d instead of %zd",
+ path, len, strlen(getname));
+}
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+ fdt = open_blob_rw(fdt);
+
+ check_set_name(fdt, "/subnode@1", "subnode@17");
+ check_set_name(fdt, "/subnode@2/subsubnode@0", "fred@0");
+ check_set_name(fdt, "/subnode@17/subsubnode", "something@0");
+
+ PASS();
+}
diff --git a/src/dtc/tests/setprop.c b/src/dtc/tests/setprop.c
new file mode 100644
index 0000000..d089f8d
--- /dev/null
+++ b/src/dtc/tests/setprop.c
@@ -0,0 +1,95 @@
+/*
+ * 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>
+#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 NEW_STRING "here is quite a long test string, blah blah blah"
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ void *buf;
+ const uint32_t *intp;
+ const char *strp;
+ int err;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ buf = xmalloc(SPACE);
+
+ err = fdt_open_into(fdt, buf, SPACE);
+ if (err)
+ FAIL("fdt_open_into(): %s", fdt_strerror(err));
+
+ fdt = buf;
+
+ intp = check_getprop_cell(fdt, 0, "prop-int", TEST_VALUE_1);
+
+ verbose_printf("Old int value was 0x%08x\n", *intp);
+ err = fdt_setprop_string(fdt, 0, "prop-int", NEW_STRING);
+ if (err)
+ FAIL("Failed to set \"prop-int\" to \"%s\": %s",
+ NEW_STRING, fdt_strerror(err));
+
+ strp = check_getprop_string(fdt, 0, "prop-int", NEW_STRING);
+ verbose_printf("New value is \"%s\"\n", strp);
+
+ strp = check_getprop(fdt, 0, "prop-str", strlen(TEST_STRING_1)+1,
+ TEST_STRING_1);
+
+ verbose_printf("Old string value was \"%s\"\n", strp);
+ err = fdt_setprop(fdt, 0, "prop-str", NULL, 0);
+ if (err)
+ FAIL("Failed to empty \"prop-str\": %s",
+ fdt_strerror(err));
+
+ check_getprop(fdt, 0, "prop-str", 0, NULL);
+
+ err = fdt_setprop_u32(fdt, 0, "prop-u32", TEST_VALUE_2);
+ if (err)
+ FAIL("Failed to set \"prop-u32\" to 0x%08x: %s",
+ TEST_VALUE_2, fdt_strerror(err));
+ check_getprop_cell(fdt, 0, "prop-u32", TEST_VALUE_2);
+
+ err = fdt_setprop_cell(fdt, 0, "prop-cell", TEST_VALUE_2);
+ if (err)
+ FAIL("Failed to set \"prop-cell\" to 0x%08x: %s",
+ TEST_VALUE_2, fdt_strerror(err));
+ check_getprop_cell(fdt, 0, "prop-cell", TEST_VALUE_2);
+
+ err = fdt_setprop_u64(fdt, 0, "prop-u64", TEST_VALUE64_1);
+ if (err)
+ FAIL("Failed to set \"prop-u64\" to 0x%016llx: %s",
+ TEST_VALUE64_1, fdt_strerror(err));
+ check_getprop_64(fdt, 0, "prop-u64", TEST_VALUE64_1);
+
+ PASS();
+}
diff --git a/src/dtc/tests/setprop_inplace.c b/src/dtc/tests/setprop_inplace.c
new file mode 100644
index 0000000..daef182
--- /dev/null
+++ b/src/dtc/tests/setprop_inplace.c
@@ -0,0 +1,87 @@
+/*
+ * 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>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ const uint32_t *intp;
+ const uint64_t *int64p;
+ const char *strp;
+ char *xstr;
+ int xlen, i;
+ int err;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ intp = check_getprop_cell(fdt, 0, "prop-int", TEST_VALUE_1);
+
+ verbose_printf("Old int value was 0x%08x\n", *intp);
+ err = fdt_setprop_inplace_cell(fdt, 0, "prop-int", ~TEST_VALUE_1);
+ if (err)
+ FAIL("Failed to set \"prop-int\" to 0x%08x: %s",
+ ~TEST_VALUE_1, fdt_strerror(err));
+ intp = check_getprop_cell(fdt, 0, "prop-int", ~TEST_VALUE_1);
+ verbose_printf("New int value is 0x%08x\n", *intp);
+
+ strp = check_getprop(fdt, 0, "prop-str", strlen(TEST_STRING_1)+1,
+ TEST_STRING_1);
+
+
+ int64p = check_getprop_64(fdt, 0, "prop-int64", TEST_VALUE64_1);
+
+ verbose_printf("Old int64 value was 0x%016" PRIx64 "\n", *int64p);
+ err = fdt_setprop_inplace_u64(fdt, 0, "prop-int64", ~TEST_VALUE64_1);
+ if (err)
+ FAIL("Failed to set \"prop-int64\" to 0x%016llx: %s",
+ ~TEST_VALUE64_1, fdt_strerror(err));
+ int64p = check_getprop_64(fdt, 0, "prop-int64", ~TEST_VALUE64_1);
+ verbose_printf("New int64 value is 0x%016" PRIx64 "\n", *int64p);
+
+ strp = check_getprop(fdt, 0, "prop-str", strlen(TEST_STRING_1)+1,
+ TEST_STRING_1);
+
+ verbose_printf("Old string value was \"%s\"\n", strp);
+ xstr = strdup(strp);
+ xlen = strlen(xstr);
+ for (i = 0; i < xlen; i++)
+ xstr[i] = toupper(xstr[i]);
+ err = fdt_setprop_inplace(fdt, 0, "prop-str", xstr, xlen+1);
+ if (err)
+ FAIL("Failed to set \"prop-str\" to \"%s\": %s",
+ xstr, fdt_strerror(err));
+
+ strp = check_getprop(fdt, 0, "prop-str", xlen+1, xstr);
+ verbose_printf("New string value is \"%s\"\n", strp);
+
+ PASS();
+}
diff --git a/src/dtc/tests/sized_cells.c b/src/dtc/tests/sized_cells.c
new file mode 100644
index 0000000..94da03b
--- /dev/null
+++ b/src/dtc/tests/sized_cells.c
@@ -0,0 +1,83 @@
+/*
+ * 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>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+static void check_compare_properties(void *fdt,
+ char const *name_one,
+ char const *name_two)
+{
+ const void *propval;
+ int proplen;
+
+ propval = fdt_getprop(fdt, 0, name_one, &proplen);
+
+ if (!propval)
+ FAIL("fdt_getprop(\"%s\"): %s",
+ name_one,
+ fdt_strerror(proplen));
+
+ check_getprop(fdt, 0, name_two, proplen, propval);
+}
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ uint8_t expected_8[6] = {TEST_CHAR1,
+ TEST_CHAR2,
+ TEST_CHAR3,
+ TEST_CHAR4,
+ TEST_CHAR5,
+ TEST_VALUE_1 >> 24};
+ uint16_t expected_16[6];
+ uint32_t expected_32[6];
+ uint64_t expected_64[6];
+ int i;
+
+ for (i = 0; i < 5; ++i) {
+ expected_16[i] = cpu_to_fdt16(expected_8[i]);
+ expected_32[i] = cpu_to_fdt32(expected_8[i]);
+ expected_64[i] = cpu_to_fdt64(expected_8[i]);
+ }
+
+ expected_16[5] = cpu_to_fdt16(TEST_VALUE_1 >> 16);
+ expected_32[5] = cpu_to_fdt32(TEST_VALUE_1);
+ expected_64[5] = cpu_to_fdt64(TEST_ADDR_1);
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ check_getprop(fdt, 0, "cells-8b", sizeof(expected_8), expected_8);
+ check_getprop(fdt, 0, "cells-16b", sizeof(expected_16), expected_16);
+ check_getprop(fdt, 0, "cells-32b", sizeof(expected_32), expected_32);
+ check_getprop(fdt, 0, "cells-64b", sizeof(expected_64), expected_64);
+
+ check_compare_properties(fdt, "cells-one-16b", "cells-one-32b");
+
+ PASS();
+}
diff --git a/src/dtc/tests/sized_cells.dts b/src/dtc/tests/sized_cells.dts
new file mode 100644
index 0000000..efea9f5
--- /dev/null
+++ b/src/dtc/tests/sized_cells.dts
@@ -0,0 +1,11 @@
+/dts-v1/;
+
+/ {
+ cells-8b = /bits/ 8 <'\r' 'b' '\0' '\'' '\xff' 0xde>;
+ cells-16b = /bits/ 16 <'\r' 'b' '\0' '\'' '\xff' 0xdead>;
+ cells-32b = /bits/ 32 <'\r' 'b' '\0' '\'' '\xff' 0xdeadbeef>;
+ cells-64b = /bits/ 64 <'\r' 'b' '\0' '\'' '\xff' 0xdeadbeef00000000>;
+
+ cells-one-16b = /bits/ 16 <0x1234 0x5678 0x0 0xffff>;
+ cells-one-32b = <0x12345678 0x0000ffff>;
+};
diff --git a/src/dtc/tests/string_escapes.c b/src/dtc/tests/string_escapes.c
new file mode 100644
index 0000000..8cdee4b
--- /dev/null
+++ b/src/dtc/tests/string_escapes.c
@@ -0,0 +1,43 @@
+/*
+ * 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>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ check_getprop(fdt, 0, "escape-str",
+ strlen(TEST_STRING_2)+1, TEST_STRING_2);
+ check_getprop(fdt, 0, "escape-str-2",
+ strlen(TEST_STRING_3)+1, TEST_STRING_3);
+
+ PASS();
+}
diff --git a/src/dtc/tests/subnode_iterate.c b/src/dtc/tests/subnode_iterate.c
new file mode 100644
index 0000000..b9f379d
--- /dev/null
+++ b/src/dtc/tests/subnode_iterate.c
@@ -0,0 +1,94 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Tests that fdt_next_subnode() works as expected
+ *
+ * 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>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+static void test_node(void *fdt, int parent_offset)
+{
+ fdt32_t subnodes;
+ const fdt32_t *prop;
+ int offset;
+ int count;
+ int len;
+
+ /* This property indicates the number of subnodes to expect */
+ prop = fdt_getprop(fdt, parent_offset, "subnodes", &len);
+ if (!prop || len != sizeof(fdt32_t)) {
+ FAIL("Missing/invalid subnodes property at '%s'",
+ fdt_get_name(fdt, parent_offset, NULL));
+ }
+ subnodes = cpu_to_fdt32(*prop);
+
+ count = 0;
+ for (offset = fdt_first_subnode(fdt, parent_offset);
+ offset >= 0;
+ offset = fdt_next_subnode(fdt, offset))
+ count++;
+
+ if (count != subnodes) {
+ FAIL("Node '%s': Expected %d subnodes, got %d\n",
+ fdt_get_name(fdt, parent_offset, NULL), subnodes,
+ count);
+ }
+}
+
+static void check_fdt_next_subnode(void *fdt)
+{
+ int offset;
+ int count = 0;
+
+ for (offset = fdt_first_subnode(fdt, 0);
+ offset >= 0;
+ offset = fdt_next_subnode(fdt, offset)) {
+ test_node(fdt, offset);
+ count++;
+ }
+
+ if (count != 2)
+ FAIL("Expected %d tests, got %d\n", 2, count);
+}
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+
+ test_init(argc, argv);
+ if (argc != 2)
+ CONFIG("Usage: %s <dtb file>", argv[0]);
+
+ fdt = load_blob(argv[1]);
+ if (!fdt)
+ FAIL("No device tree available");
+
+ check_fdt_next_subnode(fdt);
+
+ PASS();
+}
diff --git a/src/dtc/tests/subnode_iterate.dts b/src/dtc/tests/subnode_iterate.dts
new file mode 100644
index 0000000..14a0d3a
--- /dev/null
+++ b/src/dtc/tests/subnode_iterate.dts
@@ -0,0 +1,44 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ test1 {
+ subnodes = <2>;
+ linux,phandle = <0x1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ PowerPC,970@0 {
+ name = "PowerPC,970";
+ device_type = "cpu";
+ reg = <0x00000000>;
+ clock-frequency = <1600000000>;
+ timebase-frequency = <33333333>;
+ linux,boot-cpu;
+ i-cache-size = <65536>;
+ d-cache-size = <32768>;
+ another-sub-node {
+ should-be-ignored;
+ yet-another {
+ should-also-be-ignored;
+ };
+ };
+ };
+
+ PowerPC,970@1 {
+ name = "PowerPC,970";
+ device_type = "cpu";
+ reg = <0x00000001>;
+ clock-frequency = <1600000000>;
+ timebase-frequency = <33333333>;
+ i-cache-size = <65536>;
+ d-cache-size = <32768>;
+ };
+ };
+
+ test2 {
+ subnodes = <0>;
+ };
+};
+
diff --git a/src/dtc/tests/subnode_offset.c b/src/dtc/tests/subnode_offset.c
new file mode 100644
index 0000000..231fcb5
--- /dev/null
+++ b/src/dtc/tests/subnode_offset.c
@@ -0,0 +1,98 @@
+/*
+ * 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>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+static int check_subnode(struct fdt_header *fdt, int parent, const char *name)
+{
+ int offset;
+ const struct fdt_node_header *nh;
+ uint32_t tag;
+
+ verbose_printf("Checking subnode \"%s\" of %d...", name, parent);
+ offset = fdt_subnode_offset(fdt, parent, name);
+ verbose_printf("offset %d...", offset);
+ if (offset < 0)
+ FAIL("fdt_subnode_offset(\"%s\"): %s", name, fdt_strerror(offset));
+ nh = fdt_offset_ptr(fdt, offset, sizeof(*nh));
+ verbose_printf("pointer %p\n", nh);
+ if (! nh)
+ FAIL("NULL retrieving subnode \"%s\"", name);
+
+ tag = fdt32_to_cpu(nh->tag);
+
+ if (tag != FDT_BEGIN_NODE)
+ FAIL("Incorrect tag 0x%08x on property \"%s\"", tag, name);
+ if (!nodename_eq(nh->name, name))
+ FAIL("Subnode name mismatch \"%s\" instead of \"%s\"",
+ nh->name, name);
+
+ return offset;
+}
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ int subnode1_offset, subnode2_offset;
+ int subsubnode1_offset, subsubnode2_offset, subsubnode2_offset2;
+ int ss12_off, ss21_off;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ subnode1_offset = check_subnode(fdt, 0, "subnode@1");
+ subnode2_offset = check_subnode(fdt, 0, "subnode@2");
+
+ if (subnode1_offset == subnode2_offset)
+ FAIL("Different subnodes have same offset");
+
+ check_property_cell(fdt, subnode1_offset, "prop-int", TEST_VALUE_1);
+ check_property_cell(fdt, subnode2_offset, "prop-int", TEST_VALUE_2);
+
+ subsubnode1_offset = check_subnode(fdt, subnode1_offset, "subsubnode");
+ subsubnode2_offset = check_subnode(fdt, subnode2_offset, "subsubnode@0");
+ subsubnode2_offset2 = check_subnode(fdt, subnode2_offset, "subsubnode");
+
+ check_property_cell(fdt, subsubnode1_offset, "prop-int", TEST_VALUE_1);
+ check_property_cell(fdt, subsubnode2_offset, "prop-int", TEST_VALUE_2);
+ check_property_cell(fdt, subsubnode2_offset2, "prop-int", TEST_VALUE_2);
+
+ if (subsubnode2_offset != subsubnode2_offset2)
+ FAIL("Different offsets with and without unit address");
+
+ check_subnode(fdt, subnode1_offset, "ss1");
+ ss21_off = fdt_subnode_offset(fdt, subnode2_offset, "ss1");
+ if (ss21_off != -FDT_ERR_NOTFOUND)
+ FAIL("Incorrectly found ss1 in subnode2");
+
+ ss12_off = fdt_subnode_offset(fdt, subnode1_offset, "ss2");
+ if (ss12_off != -FDT_ERR_NOTFOUND)
+ FAIL("Incorrectly found ss2 in subnode1");
+ check_subnode(fdt, subnode2_offset, "ss2");
+
+ PASS();
+}
diff --git a/src/dtc/tests/supernode_atdepth_offset.c b/src/dtc/tests/supernode_atdepth_offset.c
new file mode 100644
index 0000000..43e120d
--- /dev/null
+++ b/src/dtc/tests/supernode_atdepth_offset.c
@@ -0,0 +1,145 @@
+/*
+ * 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>
+#include <string.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+static int path_depth(const char *path)
+{
+ const char *p;
+ int depth = 0;
+
+ if (path[0] != '/')
+ TEST_BUG();
+
+ if (strcmp(path, "/") == 0)
+ return 0;
+ for (p = path; *p; p++)
+ if (*p == '/')
+ depth++;
+
+ /* Special case for path == "/" */
+ if (p == (path + 1))
+ return 0;
+ else
+ return depth;
+}
+
+static int path_prefix(const char *path, int depth)
+{
+ const char *p;
+ int i;
+
+ if (path[0] != '/')
+ TEST_BUG();
+
+ if (depth == 0)
+ return 1;
+
+ p = path;
+ for (i = 0; i < depth; i++)
+ p = p+1 + strcspn(p+1, "/");
+
+ return p - path;
+}
+
+static void check_supernode_atdepth(struct fdt_header *fdt, const char *path,
+ int depth)
+{
+ int pdepth = path_depth(path);
+ char *superpath;
+ int nodeoffset, supernodeoffset, superpathoffset, pathprefixlen;
+ int nodedepth;
+
+ pathprefixlen = path_prefix(path, depth);
+ superpath = alloca(pathprefixlen + 1);
+ strncpy(superpath, path, pathprefixlen);
+ superpath[pathprefixlen] = '\0';
+
+ verbose_printf("Path %s (%d), depth %d, supernode is %s\n",
+ path, pdepth, depth, superpath);
+
+ nodeoffset = fdt_path_offset(fdt, path);
+ if (nodeoffset < 0)
+ FAIL("fdt_path_offset(%s): %s", path, fdt_strerror(nodeoffset));
+ superpathoffset = fdt_path_offset(fdt, superpath);
+ if (superpathoffset < 0)
+ FAIL("fdt_path_offset(%s): %s", superpath,
+ fdt_strerror(superpathoffset));
+
+ supernodeoffset = fdt_supernode_atdepth_offset(fdt, nodeoffset,
+ depth, &nodedepth);
+ if (supernodeoffset < 0)
+ FAIL("fdt_supernode_atdepth_offset(): %s",
+ fdt_strerror(supernodeoffset));
+
+ if (supernodeoffset != superpathoffset)
+ FAIL("fdt_supernode_atdepth_offset() returns %d instead of %d",
+ supernodeoffset, superpathoffset);
+
+ if (nodedepth != pdepth)
+ FAIL("fdt_supernode_atdept_offset() returns node depth %d "
+ "instead of %d", nodedepth, pdepth);
+}
+
+static void check_supernode_overdepth(struct fdt_header *fdt, const char *path)
+{
+ int pdepth = path_depth(path);
+ int nodeoffset, err;
+
+ nodeoffset = fdt_path_offset(fdt, path);
+ if (nodeoffset < 0)
+ FAIL("fdt_path_offset(%s): %s", path, fdt_strerror(nodeoffset));
+
+ err = fdt_supernode_atdepth_offset(fdt, nodeoffset, pdepth + 1, NULL);
+ if (err != -FDT_ERR_NOTFOUND)
+ FAIL("fdt_supernode_atdept_offset(%s, %d) returns %d instead "
+ "of FDT_ERR_NOTFOUND", path, pdepth+1, err);
+}
+
+static void check_path(struct fdt_header *fdt, const char *path)
+{
+ int i;
+
+ for (i = 0; i <= path_depth(path); i++)
+ check_supernode_atdepth(fdt, path, i);
+ check_supernode_overdepth(fdt, path);
+}
+int main(int argc, char *argv[])
+{
+ void *fdt;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ check_path(fdt, "/");
+ check_path(fdt, "/subnode@1");
+ check_path(fdt, "/subnode@2");
+ check_path(fdt, "/subnode@1/subsubnode");
+ check_path(fdt, "/subnode@2/subsubnode@0");
+
+ PASS();
+}
diff --git a/src/dtc/tests/sw_tree1.c b/src/dtc/tests/sw_tree1.c
new file mode 100644
index 0000000..8eb6e5f
--- /dev/null
+++ b/src/dtc/tests/sw_tree1.c
@@ -0,0 +1,99 @@
+/*
+ * 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>
+#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(code) \
+ { \
+ err = (code); \
+ if (err) \
+ FAIL(#code ": %s", fdt_strerror(err)); \
+ }
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ int err;
+
+ test_init(argc, argv);
+
+ fdt = xmalloc(SPACE);
+ CHECK(fdt_create(fdt, SPACE));
+
+ CHECK(fdt_add_reservemap_entry(fdt, TEST_ADDR_1, TEST_SIZE_1));
+ CHECK(fdt_add_reservemap_entry(fdt, TEST_ADDR_2, TEST_SIZE_2));
+ CHECK(fdt_finish_reservemap(fdt));
+
+ CHECK(fdt_begin_node(fdt, ""));
+ CHECK(fdt_property_string(fdt, "compatible", "test_tree1"));
+ CHECK(fdt_property_u32(fdt, "prop-int", TEST_VALUE_1));
+ CHECK(fdt_property_u64(fdt, "prop-int64", TEST_VALUE64_1));
+ CHECK(fdt_property_string(fdt, "prop-str", TEST_STRING_1));
+
+ CHECK(fdt_begin_node(fdt, "subnode@1"));
+ CHECK(fdt_property_string(fdt, "compatible", "subnode1"));
+ CHECK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_1));
+ CHECK(fdt_begin_node(fdt, "subsubnode"));
+ CHECK(fdt_property(fdt, "compatible", "subsubnode1\0subsubnode",
+ 23));
+ CHECK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_1));
+ CHECK(fdt_end_node(fdt));
+ CHECK(fdt_begin_node(fdt, "ss1"));
+ CHECK(fdt_end_node(fdt));
+ CHECK(fdt_end_node(fdt));
+
+ CHECK(fdt_begin_node(fdt, "subnode@2"));
+ CHECK(fdt_property_cell(fdt, "linux,phandle", PHANDLE_1));
+ CHECK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_2));
+ CHECK(fdt_begin_node(fdt, "subsubnode@0"));
+ CHECK(fdt_property_cell(fdt, "phandle", PHANDLE_2));
+ CHECK(fdt_property(fdt, "compatible", "subsubnode2\0subsubnode",
+ 23));
+ CHECK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_2));
+ CHECK(fdt_end_node(fdt));
+ CHECK(fdt_begin_node(fdt, "ss2"));
+ CHECK(fdt_end_node(fdt));
+
+ CHECK(fdt_end_node(fdt));
+
+ CHECK(fdt_end_node(fdt));
+
+ save_blob("unfinished_tree1.test.dtb", fdt);
+
+ CHECK(fdt_finish(fdt));
+
+ verbose_printf("Completed tree, totalsize = %d\n",
+ fdt_totalsize(fdt));
+
+ save_blob("sw_tree1.test.dtb", fdt);
+
+ PASS();
+}
diff --git a/src/dtc/tests/test01.asm b/src/dtc/tests/test01.asm
new file mode 100644
index 0000000..bbf66c7
--- /dev/null
+++ b/src/dtc/tests/test01.asm
@@ -0,0 +1,294 @@
+/* autogenerated by dtc, do not edit */
+
+#define OF_DT_HEADER 0xd00dfeed
+#define OF_DT_BEGIN_NODE 0x1
+#define OF_DT_END_NODE 0x2
+#define OF_DT_PROP 0x3
+#define OF_DT_END 0x9
+
+ .globl dt_blob_start
+dt_blob_start:
+_dt_blob_start:
+ .globl dt_header
+dt_header:
+_dt_header:
+ .long OF_DT_HEADER /* magic */
+ .long _dt_blob_end - _dt_blob_start /* totalsize */
+ .long _dt_struct_start - _dt_blob_start /* off_dt_struct */
+ .long _dt_strings_start - _dt_blob_start /* off_dt_strings */
+ .long _dt_reserve_map - _dt_blob_start /* off_dt_strings */
+ .long 16 /* version */
+ .long 16 /* last_comp_version */
+ .long 0 /*boot_cpuid_phys*/
+ .long _dt_strings_end - _dt_strings_start /* size_dt_strings */
+ .balign 8
+ .globl dt_reserve_map
+dt_reserve_map:
+_dt_reserve_map:
+/* Memory reserve map from source file */
+ .long 0x10000000
+ .long 0x00000000
+ .long 0x00000000
+ .long 0x02000000
+ .long 0x20000000
+ .long 0x00000000
+ .long 0x01000000
+ .long 0x00000000
+ .long 0x00000000
+ .long 0x00000000
+ .long 0x00000000
+ .long 0x00000014
+ .long 0, 0
+ .long 0, 0
+ .globl dt_struct_start
+dt_struct_start:
+_dt_struct_start:
+ .long OF_DT_BEGIN_NODE
+ .string ""
+ .balign 4
+ .long OF_DT_PROP
+ .long 0xc
+ .long 0x0
+ .long 0x4d79426f
+ .long 0x6172644e
+ .long 0x616d6500
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x1e
+ .long 0x6
+ .long 0x4d79426f
+ .long 0x6172644e
+ .long 0x616d6500
+ .long 0x4d79426f
+ .long 0x61726446
+ .long 0x616d696c
+ .long 0x794e616d
+ .short 0x6500
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x11
+ .long 0x2
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x20
+ .long 0x2
+ .balign 4
+ .long OF_DT_BEGIN_NODE
+ .string "cpus"
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x2c
+ .long 0x1
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x11
+ .long 0x1
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x20
+ .long 0x0
+ .balign 4
+ .long OF_DT_BEGIN_NODE
+ .string "PowerPC,970@0"
+ .balign 4
+ .long OF_DT_PROP
+ .long 0xc
+ .long 0x3a
+ .long 0x506f7765
+ .long 0x7250432c
+ .long 0x39373000
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x3f
+ .long 0x63707500
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x4b
+ .long 0x0
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x4f
+ .long 0x5f5e1000
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x5f
+ .long 0x1fca055
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x0
+ .long 0x72
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x81
+ .long 0x10000
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x8e
+ .long 0x8000
+ .balign 4
+ .long OF_DT_END_NODE
+ .long OF_DT_BEGIN_NODE
+ .string "PowerPC,970@1"
+ .balign 4
+ .long OF_DT_PROP
+ .long 0xc
+ .long 0x3a
+ .long 0x506f7765
+ .long 0x7250432c
+ .long 0x39373000
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x3f
+ .long 0x63707500
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x4b
+ .long 0x1
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x4f
+ .long 0x5f5e1000
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x5f
+ .long 0x1fca055
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x81
+ .long 0x10000
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x8e
+ .long 0x8000
+ .balign 4
+ .long OF_DT_END_NODE
+ .long OF_DT_END_NODE
+ .long OF_DT_BEGIN_NODE
+ .string "randomnode"
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x13
+ .long 0x9b
+ .long 0xff007374
+ .long 0x75666673
+ .long 0x74756666
+ .long 0x909090a
+ .short 0xa0a
+ .byte 0x0
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x9
+ .long 0xa2
+ .long 0xa0b0c0d
+ .long 0xdeeaadbe
+ .byte 0xef
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0xa7
+ .long 0x2
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x14
+ .long 0xab
+ .long 0x61626300
+ .long 0x12340000
+ .long 0xa
+ .long 0xb
+ .long 0xc
+ .balign 4
+ .long OF_DT_END_NODE
+ .long OF_DT_BEGIN_NODE
+ .string "memory@0"
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x7
+ .long 0x3f
+ .long 0x6d656d6f
+ .short 0x7279
+ .byte 0x0
+ .balign 4
+ .globl memreg
+memreg:
+ .long OF_DT_PROP
+ .long 0x10
+ .long 0x4b
+ .long 0x0
+ .long 0x0
+ .long 0x0
+ .long 0x20000000
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0x2c
+ .long 0x2
+ .balign 4
+ .long OF_DT_END_NODE
+ .long OF_DT_BEGIN_NODE
+ .string "chosen"
+ .balign 4
+ .long OF_DT_PROP
+ .long 0xf
+ .long 0xb1
+ .long 0x726f6f74
+ .long 0x3d2f6465
+ .long 0x762f7364
+ .short 0x6132
+ .byte 0x0
+ .balign 4
+ .long OF_DT_PROP
+ .long 0x4
+ .long 0xba
+ .long 0x600
+ .balign 4
+ .long OF_DT_END_NODE
+ .long OF_DT_END_NODE
+ .long OF_DT_END
+ .globl dt_struct_end
+dt_struct_end:
+_dt_struct_end:
+ .globl dt_strings_start
+dt_strings_start:
+_dt_strings_start:
+ .string "model"
+ .string "compatible"
+ .string "#address-cells"
+ .string "#size-cells"
+ .string "linux,phandle"
+ .string "name"
+ .string "device_type"
+ .string "reg"
+ .string "clock-frequency"
+ .string "timebase-frequency"
+ .string "linux,boot-cpu"
+ .string "i-cache-size"
+ .string "d-cache-size"
+ .string "string"
+ .string "blob"
+ .string "ref"
+ .string "mixed"
+ .string "bootargs"
+ .string "linux,platform"
+ .globl dt_strings_end
+dt_strings_end:
+_dt_strings_end:
+ .globl dt_blob_end
+dt_blob_end:
+_dt_blob_end:
diff --git a/src/dtc/tests/test01.dts b/src/dtc/tests/test01.dts
new file mode 100644
index 0000000..f9fd165
--- /dev/null
+++ b/src/dtc/tests/test01.dts
@@ -0,0 +1,57 @@
+/dts-v1/;
+
+/memreserve/ 0x1000000000000000 0x0000000002000000;
+/memreserve/ 0x2000000000000000 0x0100000000000000;
+/memreserve/ 0x0000000000000000 0x0000000000000014;
+
+/ {
+ model = "MyBoardName";
+ compatible = "MyBoardName", "MyBoardFamilyName";
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ cpus {
+ linux,phandle = <0x1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ PowerPC,970@0 {
+ name = "PowerPC,970";
+ device_type = "cpu";
+ reg = <0x00000000>;
+ clock-frequency = <1600000000>;
+ timebase-frequency = <33333333>;
+ linux,boot-cpu;
+ i-cache-size = <65536>;
+ d-cache-size = <32768>;
+ };
+
+ PowerPC,970@1 {
+ name = "PowerPC,970";
+ device_type = "cpu";
+ reg = <0x00000001>;
+ clock-frequency = <1600000000>;
+ timebase-frequency = <33333333>;
+ i-cache-size = <65536>;
+ d-cache-size = <32768>;
+ };
+
+ };
+
+ randomnode {
+ string = "\xff\0stuffstuff\t\t\t\n\n\n";
+ blob = [0a 0b 0c 0d de ea ad be ef];
+ ref = < &{/memory@0} >;
+ mixed = "abc", [1234], <0xa 0xb 0xc>;
+ };
+
+ memory@0 {
+ device_type = "memory";
+ memreg: reg = <0x00000000 0x00000000 0x00000000 0x20000000>;
+ };
+
+ chosen {
+ bootargs = "root=/dev/sda2";
+ linux,platform = <0x600>;
+ };
+
+};
diff --git a/src/dtc/tests/test01.stderr b/src/dtc/tests/test01.stderr
new file mode 100644
index 0000000..82ea3f6
--- /dev/null
+++ b/src/dtc/tests/test01.stderr
@@ -0,0 +1,4 @@
+DTC: dts->asm on file "test.dts"
+Warning: "linux,boot-cpu" property is deprecated in blob version 2 or higher
+Warning: /chosen has no "linux,stdout-path" property
+Warning: /chosen has no "interrupt-controller" property
diff --git a/src/dtc/tests/test_kernel_dts b/src/dtc/tests/test_kernel_dts
new file mode 100755
index 0000000..238f3f7
--- /dev/null
+++ b/src/dtc/tests/test_kernel_dts
@@ -0,0 +1,86 @@
+#!/usr/bin/perl
+
+my $dtc_old = "/home/jdl/FSL/dtc/dtc-old";
+my $dtc_new = "/home/jdl/FSL/dtc/dtc-new";
+
+my $basic_options = "-b 0 -f -I dts -O dtb";
+
+my $linux_dts_dir = "/usr/src/linux-2.6/arch/powerpc/boot/dts";
+
+# Yeah, sure, we could, like, readdir() this instead...
+my @boards = (
+ "bamboo",
+ "ebony",
+ "ep88xc",
+ "holly",
+ "kilauea",
+ "kuroboxHD",
+ "kuroboxHG",
+ "lite5200",
+ "lite5200b",
+ "mpc7448hpc2",
+ "mpc8272ads",
+ "mpc8313erdb",
+ "mpc832x_mds",
+ "mpc832x_rdb",
+ "mpc8349emitx",
+ "mpc8349emitxgp",
+ "mpc834x_mds",
+ "mpc836x_mds",
+ "mpc8540ads",
+ "mpc8541cds",
+ "mpc8544ds",
+ "mpc8548cds",
+ "mpc8555cds",
+ "mpc8560ads",
+ "mpc8568mds",
+ "mpc8572ds",
+ "mpc8610_hpcd",
+ "mpc8641_hpcn",
+ "mpc866ads", # Feh. Bad node references...
+ "mpc885ads",
+ "pq2fads",
+ "prpmc2800",
+ "ps3",
+ "sequoia",
+ "walnut",
+);
+
+foreach my $board (@boards) {
+ my $dts_file = "$linux_dts_dir/$board.dts";
+
+ my $old_dtb_file = "/tmp/$board.dtb.old";
+ my $new_dtb_file = "/tmp/$board.dtb.new";
+
+ my $cmd_old = "$dtc_old $basic_options -o $old_dtb_file $dts_file";
+ my $cmd_new = "$dtc_new $basic_options -o $new_dtb_file $dts_file";
+ my $cmd_cmp = "cmp $old_dtb_file $new_dtb_file";
+
+ print "------------------------------------------------\n";
+ print "OLD: $cmd_old\n";
+ unlink($old_dtb_file) if (-f $old_dtb_file);
+ system("$cmd_old >& /dev/null");
+ my $status = $?;
+ if ($status) {
+ print " FAILED to run old DTC on $board\n";
+ }
+
+ print "NEW: $cmd_new\n";
+ unlink($new_dtb_file) if (-f $new_dtb_file);
+ system("$cmd_new >& /dev/null");
+ $status = $?;
+ if ($status) {
+ print " FAILED to run new DTC on $board\n";
+ }
+
+ if (-f $old_dtb_file && -f $new_dtb_file) {
+ print "CMP: $cmd_cmp\n";
+ system($cmd_cmp);
+ $status = $?;
+ if ($status) {
+ print " FAILED $board\n";
+ }
+ } else {
+ printf " FAILED: Missing dtb file\n";
+ }
+}
diff --git a/src/dtc/tests/test_tree1.dts b/src/dtc/tests/test_tree1.dts
new file mode 100644
index 0000000..c7b170c
--- /dev/null
+++ b/src/dtc/tests/test_tree1.dts
@@ -0,0 +1,3 @@
+/dts-v1/;
+
+/include/ "test_tree1_body.dtsi"
diff --git a/src/dtc/tests/test_tree1_body.dtsi b/src/dtc/tests/test_tree1_body.dtsi
new file mode 100644
index 0000000..1446191
--- /dev/null
+++ b/src/dtc/tests/test_tree1_body.dtsi
@@ -0,0 +1,36 @@
+/memreserve/ 0xdeadbeef00000000 0x100000;
+/memreserve/ 123456789 010000;
+
+/ {
+ compatible = "test_tree1";
+ prop-int = <0xdeadbeef>;
+ prop-int64 = /bits/ 64 <0xdeadbeef01abcdef>;
+ prop-str = "hello world";
+
+ subnode@1 {
+ compatible = "subnode1";
+ prop-int = [deadbeef];
+
+ subsubnode {
+ compatible = "subsubnode1", "subsubnode";
+ prop-int = <0xdeadbeef>;
+ };
+
+ ss1 {
+ };
+ };
+
+ subnode@2 {
+ linux,phandle = <0x2000>;
+ prop-int = <123456789>;
+
+ ssn0: subsubnode@0 {
+ phandle = <0x2001>;
+ compatible = "subsubnode2", "subsubnode";
+ prop-int = <0726746425>;
+ };
+
+ ss2 {
+ };
+ };
+};
diff --git a/src/dtc/tests/test_tree1_delete.dts b/src/dtc/tests/test_tree1_delete.dts
new file mode 100644
index 0000000..a2f1bfd
--- /dev/null
+++ b/src/dtc/tests/test_tree1_delete.dts
@@ -0,0 +1,68 @@
+/dts-v1/;
+
+/include/ "test_tree1_body.dtsi"
+
+/ {
+ nonexistant-property = <0xdeadbeef>;
+
+ nonexistant-subnode {
+ prop-int = <1>;
+ };
+
+ dellabel: deleted-by-label {
+ prop-int = <1>;
+ };
+
+ subnode@1 {
+ delete-this-str = "deadbeef";
+ };
+
+};
+
+/ {
+ /delete-property/ nonexistant-property;
+
+ /delete-node/ nonexistant-subnode;
+
+ subnode@1 {
+ /delete-property/ delete-this-str;
+ };
+};
+
+/delete-node/ &dellabel;
+
+/ {
+ /delete-property/ prop-str;
+};
+
+/ {
+ prop-str = "hello world";
+};
+
+/ {
+ subnode@1 {
+ /delete-node/ ss1;
+ };
+};
+
+/ {
+ subnode@1 {
+ ss1 {
+ };
+ };
+};
+
+/{
+ duplabel1: foo1 = "bar";
+ duplabel2: foo2 = "bar";
+};
+
+/{
+ duplabel1: baz1 = "qux";
+ duplabel2: baz2 = "qux";
+};
+
+/{
+ /delete-property/ foo1;
+ /delete-property/ baz2;
+};
diff --git a/src/dtc/tests/test_tree1_merge.dts b/src/dtc/tests/test_tree1_merge.dts
new file mode 100644
index 0000000..ded08d8
--- /dev/null
+++ b/src/dtc/tests/test_tree1_merge.dts
@@ -0,0 +1,44 @@
+/dts-v1/;
+/memreserve/ 0xdeadbeef00000000 0x100000;
+/memreserve/ 123456789 010000;
+
+/ {
+ compatible = "test_tree1";
+ prop-int = "wrong!";
+ prop-str = "hello world";
+
+ subnode@1 {
+ compatible = "subnode1";
+
+ subsubnode {
+ compatible = "subsubnode1", "subsubnode";
+ prop-int = <0xdeadbeef>;
+ };
+
+ ss1 {
+ };
+ };
+
+ subnode@2 {
+ linux,phandle = <0x2000>;
+ prop-int = <123456789>;
+
+ ss2 {
+ };
+ };
+};
+
+/ {
+ prop-int = <0xdeadbeef>;
+ prop-int64 = /bits/ 64 <0xdeadbeef01abcdef>;
+ subnode@1 {
+ prop-int = [deadbeef];
+ };
+ subnode@2 {
+ ssn0: subsubnode@0 {
+ phandle = <0x2001>;
+ compatible = "subsubnode2", "subsubnode";
+ prop-int = <0726746425>;
+ };
+ };
+};
diff --git a/src/dtc/tests/test_tree1_merge_labelled.dts b/src/dtc/tests/test_tree1_merge_labelled.dts
new file mode 100644
index 0000000..29953b0
--- /dev/null
+++ b/src/dtc/tests/test_tree1_merge_labelled.dts
@@ -0,0 +1,42 @@
+/dts-v1/;
+
+/memreserve/ 0xdeadbeef00000000 0x100000;
+/memreserve/ 123456789 010000;
+
+/ {
+ compatible = "test_tree1";
+ prop-int = <0xdeadbeef>;
+ prop-int64 = /bits/ 64 <0xdeadbeef01abcdef>;
+ prop-str = "hello world";
+
+ subnode@1 {
+ compatible = "subnode1";
+ prop-int = [deadbeef];
+
+ subsubnode {
+ compatible = "subsubnode1", "subsubnode";
+ prop-int = <0xdeadbeef>;
+ };
+
+ ss1 {
+ };
+ };
+
+ subnode@2 {
+ linux,phandle = <0x2000>;
+ prop-int = <123456789>;
+
+ ssn0: subsubnode@0 {
+ phandle = <0x2001>;
+ prop-int = <0xbad>;
+ };
+
+ ss2 {
+ };
+ };
+};
+
+&ssn0 {
+ compatible = "subsubnode2", "subsubnode";
+ prop-int = <0726746425>;
+};
diff --git a/src/dtc/tests/test_tree1_merge_path.dts b/src/dtc/tests/test_tree1_merge_path.dts
new file mode 100644
index 0000000..168d066
--- /dev/null
+++ b/src/dtc/tests/test_tree1_merge_path.dts
@@ -0,0 +1,42 @@
+/dts-v1/;
+
+/memreserve/ 0xdeadbeef00000000 0x100000;
+/memreserve/ 123456789 010000;
+
+/ {
+ compatible = "test_tree1";
+ prop-int = <0xdeadbeef>;
+ prop-int64 = /bits/ 64 <0xdeadbeef01abcdef>;
+ prop-str = "hello world";
+
+ subnode@1 {
+ compatible = "subnode1";
+ prop-int = [deadbeef];
+
+ subsubnode {
+ compatible = "subsubnode1", "subsubnode";
+ prop-int = <0xdeadbeef>;
+ };
+
+ ss1 {
+ };
+ };
+
+ subnode@2 {
+ linux,phandle = <0x2000>;
+ prop-int = <123456789>;
+
+ ssn0: subsubnode@0 {
+ phandle = <0x2001>;
+ prop-int = <0xbad>;
+ };
+
+ ss2 {
+ };
+ };
+};
+
+&{/subnode@2/subsubnode@0} {
+ compatible = "subsubnode2", "subsubnode";
+ prop-int = <0726746425>;
+};
diff --git a/src/dtc/tests/test_tree1_wrong1.dts b/src/dtc/tests/test_tree1_wrong1.dts
new file mode 100644
index 0000000..d71820a
--- /dev/null
+++ b/src/dtc/tests/test_tree1_wrong1.dts
@@ -0,0 +1,36 @@
+/dts-v1/;
+
+/memreserve/ 123456789 010000;
+
+/ {
+ compatible = "test_tree1";
+ prop-int = <0xdeadbeef>;
+ prop-str = "hello world";
+
+ subnode@1 {
+ compatible = "subnode1";
+ prop-int = [deadbeef];
+
+ subsubnode {
+ compatible = "subsubnode1", "subsubnode";
+ prop-int = <0xdeadbeef>;
+ };
+
+ ss1 {
+ };
+ };
+
+ subnode@2 {
+ linux,phandle = <0x2000>;
+ prop-int = <123456789>;
+
+ subsubnode@0 {
+ phandle = <0x2001>;
+ compatible = "subsubnode2", "subsubnode";
+ prop-int = <0726746425>;
+ };
+
+ ss2 {
+ };
+ };
+};
diff --git a/src/dtc/tests/test_tree1_wrong2.dts b/src/dtc/tests/test_tree1_wrong2.dts
new file mode 100644
index 0000000..ac27023
--- /dev/null
+++ b/src/dtc/tests/test_tree1_wrong2.dts
@@ -0,0 +1,36 @@
+/dts-v1/;
+
+/memreserve/ 0xdeadbeef00000000 0x100000;
+/memreserve/ 123456789 010000;
+
+/ {
+ compatible = "test_tree1";
+ prop-str = "hello world";
+
+ subnode@1 {
+ compatible = "subnode1";
+ prop-int = [deadbeef];
+
+ subsubnode {
+ compatible = "subsubnode1", "subsubnode";
+ prop-int = <0xdeadbeef>;
+ };
+
+ ss1 {
+ };
+ };
+
+ subnode@2 {
+ linux,phandle = <0x2000>;
+ prop-int = <123456789>;
+
+ subsubnode@0 {
+ phandle = <0x2001>;
+ compatible = "subsubnode2", "subsubnode";
+ prop-int = <0726746425>;
+ };
+
+ ss2 {
+ };
+ };
+};
diff --git a/src/dtc/tests/test_tree1_wrong3.dts b/src/dtc/tests/test_tree1_wrong3.dts
new file mode 100644
index 0000000..80be2fa
--- /dev/null
+++ b/src/dtc/tests/test_tree1_wrong3.dts
@@ -0,0 +1,36 @@
+/dts-v1/;
+
+/memreserve/ 0xdeadbeef00000000 0x100000;
+/memreserve/ 123456789 010000;
+
+/ {
+ compatible = "test_tree1";
+ prop-int = <0xdeadbeef>;
+ prop-str = "hello world";
+
+ subnode@1 {
+ compatible = "subnode1";
+
+ subsubnode {
+ compatible = "subsubnode1", "subsubnode";
+ prop-int = <0xdeadbeef>;
+ };
+
+ ss1 {
+ };
+ };
+
+ subnode@2 {
+ linux,phandle = <0x2000>;
+ prop-int = <123456789>;
+
+ subsubnode@0 {
+ phandle = <0x2001>;
+ compatible = "subsubnode2", "subsubnode";
+ prop-int = <0726746425>;
+ };
+
+ ss2 {
+ };
+ };
+};
diff --git a/src/dtc/tests/test_tree1_wrong4.dts b/src/dtc/tests/test_tree1_wrong4.dts
new file mode 100644
index 0000000..09bb13b
--- /dev/null
+++ b/src/dtc/tests/test_tree1_wrong4.dts
@@ -0,0 +1,34 @@
+/dts-v1/;
+
+/memreserve/ 0xdeadbeef00000000 0x100000;
+/memreserve/ 123456789 010000;
+
+/ {
+ compatible = "test_tree1";
+ prop-int = <0xdeadbeef>;
+ prop-str = "hello world";
+
+ subnode@1 {
+ compatible = "subnode1";
+ prop-int = [deadbeef];
+
+ subsubnode {
+ compatible = "subsubnode1", "subsubnode";
+ prop-int = <0xdeadbeef>;
+ };
+
+ ss1 {
+ };
+ };
+
+ subnode@2 {
+ linux,phandle = <0x2000>;
+ prop-int = <123456789>;
+
+ subsubnode@0 {
+ phandle = <0x2001>;
+ compatible = "subsubnode2", "subsubnode";
+ prop-int = <0726746425>;
+ };
+ };
+};
diff --git a/src/dtc/tests/test_tree1_wrong5.dts b/src/dtc/tests/test_tree1_wrong5.dts
new file mode 100644
index 0000000..ef4c4f7
--- /dev/null
+++ b/src/dtc/tests/test_tree1_wrong5.dts
@@ -0,0 +1,37 @@
+/dts-v1/;
+
+/memreserve/ 0xdeadbeef00000000 0x100000;
+/memreserve/ 123456789 010000;
+
+/ {
+ compatible = "test_tree1";
+ prop-int = <0xdeadbefe>;
+ prop-str = "hello world";
+
+ subnode@1 {
+ compatible = "subnode1";
+ prop-int = [deadbeef];
+
+ subsubnode {
+ compatible = "subsubnode1", "subsubnode";
+ prop-int = <0xdeadbeef>;
+ };
+
+ ss1 {
+ };
+ };
+
+ subnode@2 {
+ linux,phandle = <0x2000>;
+ prop-int = <123456789>;
+
+ subsubnode@0 {
+ phandle = <0x2001>;
+ compatible = "subsubnode2", "subsubnode";
+ prop-int = <0726746425>;
+ };
+
+ ss2 {
+ };
+ };
+};
diff --git a/src/dtc/tests/test_tree1_wrong6.dts b/src/dtc/tests/test_tree1_wrong6.dts
new file mode 100644
index 0000000..98d6eda
--- /dev/null
+++ b/src/dtc/tests/test_tree1_wrong6.dts
@@ -0,0 +1,38 @@
+/dts-v1/;
+
+/memreserve/ 0xdeadbeef00000000 0x100000;
+/memreserve/ 123456789 010000;
+
+/ {
+ compatible = "test_tree1";
+ prop-int = <0xdeadbeef>;
+ prop-str = "hello world";
+
+ subnode@1 {
+ compatible = "subnode1";
+ prop-int = [deadbeef];
+
+ subsubnode {
+ compatible = "subsubnode1", "subsubnode";
+ prop-int = <0xdeadbeef>;
+ };
+
+ ss1 {
+ extra-prop;
+ };
+ };
+
+ subnode@2 {
+ linux,phandle = <0x2000>;
+ prop-int = <123456789>;
+
+ subsubnode@0 {
+ phandle = <0x2001>;
+ compatible = "subsubnode2", "subsubnode";
+ prop-int = <0726746425>;
+ };
+
+ ss2 {
+ };
+ };
+};
diff --git a/src/dtc/tests/test_tree1_wrong7.dts b/src/dtc/tests/test_tree1_wrong7.dts
new file mode 100644
index 0000000..f57ace0
--- /dev/null
+++ b/src/dtc/tests/test_tree1_wrong7.dts
@@ -0,0 +1,39 @@
+/dts-v1/;
+
+/memreserve/ 0xdeadbeef00000000 0x100000;
+/memreserve/ 123456789 010000;
+
+/ {
+ compatible = "test_tree1";
+ prop-int = <0xdeadbeef>;
+ prop-str = "hello world";
+
+ subnode@1 {
+ compatible = "subnode1";
+ prop-int = [deadbeef];
+
+ subsubnode {
+ compatible = "subsubnode1", "subsubnode";
+ prop-int = <0xdeadbeef>;
+ };
+
+ ss1 {
+ };
+ };
+
+ subnode@2 {
+ linux,phandle = <0x2000>;
+ prop-int = <123456789>;
+
+ subsubnode@0 {
+ phandle = <0x2001>;
+ compatible = "subsubnode2", "subsubnode";
+ prop-int = <0726746425>;
+ };
+
+ ss2 {
+ extranode {
+ };
+ };
+ };
+};
diff --git a/src/dtc/tests/test_tree1_wrong8.dts b/src/dtc/tests/test_tree1_wrong8.dts
new file mode 100644
index 0000000..811ce6c
--- /dev/null
+++ b/src/dtc/tests/test_tree1_wrong8.dts
@@ -0,0 +1,37 @@
+/dts-v1/;
+
+/memreserve/ 0xdeadbeef00000000 0x100000;
+/memreserve/ 123456789 010001;
+
+/ {
+ compatible = "test_tree1";
+ prop-int = <0xdeadbeef>;
+ prop-str = "hello world";
+
+ subnode@1 {
+ compatible = "subnode1";
+ prop-int = [deadbeef];
+
+ subsubnode {
+ compatible = "subsubnode1", "subsubnode";
+ prop-int = <0xdeadbeef>;
+ };
+
+ ss1 {
+ };
+ };
+
+ subnode@2 {
+ linux,phandle = <0x2000>;
+ prop-int = <123456789>;
+
+ subsubnode@0 {
+ phandle = <0x2001>;
+ compatible = "subsubnode2", "subsubnode";
+ prop-int = <0726746425>;
+ };
+
+ ss2 {
+ };
+ };
+};
diff --git a/src/dtc/tests/test_tree1_wrong9.dts b/src/dtc/tests/test_tree1_wrong9.dts
new file mode 100644
index 0000000..6ff6fab
--- /dev/null
+++ b/src/dtc/tests/test_tree1_wrong9.dts
@@ -0,0 +1,38 @@
+/dts-v1/;
+
+/memreserve/ 0xdeadbeef00000000 0x100000;
+/memreserve/ 123456789 010000;
+/memreserve/ 0 1;
+
+/ {
+ compatible = "test_tree1";
+ prop-int = <0xdeadbeef>;
+ prop-str = "hello world";
+
+ subnode@1 {
+ compatible = "subnode1";
+ prop-int = [deadbeef];
+
+ subsubnode {
+ compatible = "subsubnode1", "subsubnode";
+ prop-int = <0xdeadbeef>;
+ };
+
+ ss1 {
+ };
+ };
+
+ subnode@2 {
+ linux,phandle = <0x2000>;
+ prop-int = <123456789>;
+
+ subsubnode@0 {
+ phandle = <0x2001>;
+ compatible = "subsubnode2", "subsubnode";
+ prop-int = <0726746425>;
+ };
+
+ ss2 {
+ };
+ };
+};
diff --git a/src/dtc/tests/testdata.h b/src/dtc/tests/testdata.h
new file mode 100644
index 0000000..ce715e4
--- /dev/null
+++ b/src/dtc/tests/testdata.h
@@ -0,0 +1,36 @@
+#ifdef __ASSEMBLY__
+#define ASM_CONST_LL(x) (x)
+#else
+#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_VALUE_1 0xdeadbeef
+#define TEST_VALUE_2 123456789
+
+#define TEST_VALUE64_1 ASM_CONST_LL(0xdeadbeef01abcdef)
+
+#define PHANDLE_1 0x2000
+#define PHANDLE_2 0x2001
+
+#define TEST_STRING_1 "hello world"
+#define TEST_STRING_2 "nastystring: \a\b\t\n\v\f\r\\\""
+#define TEST_STRING_3 "\xde\xad\xbe\xef"
+
+#define TEST_CHAR1 '\r'
+#define TEST_CHAR2 'b'
+#define TEST_CHAR3 '\0'
+#define TEST_CHAR4 '\''
+#define TEST_CHAR5 '\xff'
+
+#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;
+#endif /* ! __ASSEMBLY */
diff --git a/src/dtc/tests/tests.h b/src/dtc/tests/tests.h
new file mode 100644
index 0000000..56a843c
--- /dev/null
+++ b/src/dtc/tests/tests.h
@@ -0,0 +1,129 @@
+#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
+
+/* Test return codes */
+#define RC_PASS 0
+#define RC_CONFIG 1
+#define RC_FAIL 2
+#define RC_BUG 99
+
+extern int verbose_test;
+extern char *test_name;
+void test_init(int argc, char *argv[]);
+
+#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
+#define PALIGN(p, a) ((void *)ALIGN((unsigned long)(p), (a)))
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+#define streq(s1, s2) (strcmp((s1),(s2)) == 0)
+
+/* Each test case must define this function */
+void cleanup(void);
+
+#define verbose_printf(...) \
+ if (verbose_test) { \
+ printf(__VA_ARGS__); \
+ fflush(stdout); \
+ }
+#define ERR "ERR: "
+#define ERROR(fmt, args...) fprintf(stderr, ERR fmt, ## args)
+
+
+#define PASS() \
+ do { \
+ cleanup(); \
+ printf("PASS\n"); \
+ exit(RC_PASS); \
+ } while (0)
+
+#define PASS_INCONCLUSIVE() \
+ do { \
+ cleanup(); \
+ printf("PASS (inconclusive)\n"); \
+ exit(RC_PASS); \
+ } while (0)
+
+#define IRRELEVANT() \
+ do { \
+ cleanup(); \
+ printf("PASS (irrelevant)\n"); \
+ exit(RC_PASS); \
+ } while (0)
+
+/* Look out, gcc extension below... */
+#define FAIL(fmt, ...) \
+ do { \
+ cleanup(); \
+ printf("FAIL\t" fmt "\n", ##__VA_ARGS__); \
+ exit(RC_FAIL); \
+ } while (0)
+
+#define CONFIG(fmt, ...) \
+ do { \
+ cleanup(); \
+ printf("Bad configuration: " fmt "\n", ##__VA_ARGS__); \
+ exit(RC_CONFIG); \
+ } while (0)
+
+#define TEST_BUG(fmt, ...) \
+ do { \
+ cleanup(); \
+ printf("BUG in testsuite: " fmt "\n", ##__VA_ARGS__); \
+ exit(RC_BUG); \
+ } while (0)
+
+void check_mem_rsv(void *fdt, int n, uint64_t addr, uint64_t size);
+
+void check_property(void *fdt, int nodeoffset, const char *name,
+ int len, const void *val);
+#define check_property_cell(fdt, nodeoffset, name, val) \
+ ({ \
+ uint32_t x = cpu_to_fdt32(val); \
+ check_property(fdt, nodeoffset, name, sizeof(x), &x); \
+ })
+
+
+const void *check_getprop(void *fdt, int nodeoffset, const char *name,
+ int len, const void *val);
+#define check_getprop_cell(fdt, nodeoffset, name, val) \
+ ({ \
+ uint32_t x = cpu_to_fdt32(val); \
+ check_getprop(fdt, nodeoffset, name, sizeof(x), &x); \
+ })
+#define check_getprop_64(fdt, nodeoffset, name, val) \
+ ({ \
+ uint64_t x = cpu_to_fdt64(val); \
+ check_getprop(fdt, nodeoffset, name, sizeof(x), &x); \
+ })
+#define check_getprop_string(fdt, nodeoffset, name, s) \
+ check_getprop((fdt), (nodeoffset), (name), strlen(s)+1, (s))
+int nodename_eq(const char *s1, const char *s2);
+void *load_blob(const char *filename);
+void *load_blob_arg(int argc, char *argv[]);
+void save_blob(const char *filename, void *blob);
+void *open_blob_rw(void *blob);
+
+#include "util.h"
+
+#endif /* _TESTS_H */
diff --git a/src/dtc/tests/tests.sh b/src/dtc/tests/tests.sh
new file mode 100644
index 0000000..31530d5
--- /dev/null
+++ b/src/dtc/tests/tests.sh
@@ -0,0 +1,61 @@
+# Common functions for shell testcases
+
+PASS () {
+ echo "PASS"
+ exit 0
+}
+
+FAIL () {
+ echo "FAIL" "$@"
+ exit 2
+}
+
+FAIL_IF_SIGNAL () {
+ ret="$1"
+ if [ "$ret" -gt 127 ]; then
+ signame=$(kill -l $((ret - 128)))
+ FAIL "Killed by SIG$signame"
+ fi
+}
+
+DTC=../dtc
+DTGET=../fdtget
+DTPUT=../fdtput
+
+verbose_run () {
+ if [ -z "$QUIET_TEST" ]; then
+ "$@"
+ else
+ "$@" > /dev/null 2> /dev/null
+ fi
+}
+
+verbose_run_check () {
+ verbose_run "$@"
+ ret="$?"
+ FAIL_IF_SIGNAL $ret
+ if [ $ret != 0 ]; then
+ FAIL "Returned error code $ret"
+ fi
+}
+
+verbose_run_log () {
+ LOG="$1"
+ shift
+ "$@" > "$LOG" 2>&1
+ ret=$?
+ if [ -z "$QUIET_TEST" ]; then
+ cat "$LOG" >&2
+ fi
+ return $ret
+}
+
+verbose_run_log_check () {
+ verbose_run_log "$@"
+ ret="$?"
+ FAIL_IF_SIGNAL $ret
+ if [ $ret != 0 ]; then
+ FAIL "Returned error code $ret"
+ fi
+}
+
diff --git a/src/dtc/tests/testutils.c b/src/dtc/tests/testutils.c
new file mode 100644
index 0000000..f185133
--- /dev/null
+++ b/src/dtc/tests/testutils.c
@@ -0,0 +1,203 @@
+/*
+ * 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 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <limits.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+
+int verbose_test = 1;
+char *test_name;
+
+void __attribute__((weak)) cleanup(void)
+{
+}
+
+static void sigint_handler(int signum, siginfo_t *si, void *uc)
+{
+ cleanup();
+ fprintf(stderr, "%s: %s (pid=%d)\n", test_name,
+ strsignal(signum), getpid());
+ exit(RC_BUG);
+}
+
+void test_init(int argc, char *argv[])
+{
+ int err;
+ struct sigaction sa_int = {
+ .sa_sigaction = sigint_handler,
+ };
+
+ test_name = argv[0];
+
+ err = sigaction(SIGINT, &sa_int, NULL);
+ if (err)
+ FAIL("Can't install SIGINT handler");
+
+ if (getenv("QUIET_TEST"))
+ verbose_test = 0;
+
+ verbose_printf("Starting testcase \"%s\", pid %d\n",
+ test_name, getpid());
+}
+
+void check_mem_rsv(void *fdt, int n, uint64_t addr, uint64_t size)
+{
+ int err;
+ uint64_t addr_v, size_v;
+
+ err = fdt_get_mem_rsv(fdt, n, &addr_v, &size_v);
+ if (err < 0)
+ FAIL("fdt_get_mem_rsv(%d): %s", n, fdt_strerror(err));
+ if ((addr_v != addr) || (size_v != size))
+ FAIL("fdt_get_mem_rsv() returned (0x%llx,0x%llx) "
+ "instead of (0x%llx,0x%llx)",
+ (unsigned long long)addr_v, (unsigned long long)size_v,
+ (unsigned long long)addr, (unsigned long long)size);
+}
+
+void check_property(void *fdt, int nodeoffset, const char *name,
+ int len, const void *val)
+{
+ const struct fdt_property *prop;
+ int retlen;
+ uint32_t tag, nameoff, proplen;
+ const char *propname;
+
+ verbose_printf("Checking property \"%s\"...", name);
+ prop = fdt_get_property(fdt, nodeoffset, name, &retlen);
+ verbose_printf("pointer %p\n", prop);
+ if (! prop)
+ FAIL("Error retreiving \"%s\" pointer: %s", name,
+ fdt_strerror(retlen));
+
+ tag = fdt32_to_cpu(prop->tag);
+ nameoff = fdt32_to_cpu(prop->nameoff);
+ proplen = fdt32_to_cpu(prop->len);
+
+ if (tag != FDT_PROP)
+ FAIL("Incorrect tag 0x%08x on property \"%s\"", tag, name);
+
+ propname = fdt_string(fdt, nameoff);
+ if (!propname || !streq(propname, name))
+ FAIL("Property name mismatch \"%s\" instead of \"%s\"",
+ propname, name);
+ if (proplen != retlen)
+ FAIL("Length retrieved for \"%s\" by fdt_get_property()"
+ " differs from stored length (%d != %d)",
+ name, retlen, proplen);
+ if (proplen != len)
+ FAIL("Size mismatch on property \"%s\": %d insead of %d",
+ name, proplen, len);
+ if (memcmp(val, prop->data, len) != 0)
+ FAIL("Data mismatch on property \"%s\"", name);
+}
+
+const void *check_getprop(void *fdt, int nodeoffset, const char *name,
+ int len, const void *val)
+{
+ const void *propval;
+ int proplen;
+
+ propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
+ if (! propval)
+ FAIL("fdt_getprop(\"%s\"): %s", name, fdt_strerror(proplen));
+
+ if (proplen != len)
+ FAIL("Size mismatch on property \"%s\": %d insead of %d",
+ name, proplen, len);
+ if (memcmp(val, propval, len) != 0)
+ FAIL("Data mismatch on property \"%s\"", name);
+
+ return propval;
+}
+
+int nodename_eq(const char *s1, const char *s2)
+{
+ int len = strlen(s2);
+
+ len = strlen(s2);
+ if (strncmp(s1, s2, len) != 0)
+ return 0;
+ if (s1[len] == '\0')
+ return 1;
+ else if (!memchr(s2, '@', len) && (s1[len] == '@'))
+ return 1;
+ else
+ return 0;
+}
+
+#define CHUNKSIZE 128
+
+void *load_blob(const char *filename)
+{
+ char *blob;
+ int ret = utilfdt_read_err(filename, &blob);
+
+ if (ret)
+ CONFIG("Couldn't open blob from \"%s\": %s", filename,
+ strerror(ret));
+ return blob;
+}
+
+void *load_blob_arg(int argc, char *argv[])
+{
+ if (argc != 2)
+ CONFIG("Usage: %s <dtb file>", argv[0]);
+ return load_blob(argv[1]);
+}
+
+void save_blob(const char *filename, void *fdt)
+{
+ int ret = utilfdt_write_err(filename, fdt);
+
+ if (ret)
+ CONFIG("Couldn't write blob to \"%s\": %s", filename,
+ strerror(ret));
+}
+
+void *open_blob_rw(void *blob)
+{
+ int err;
+ void *buf = blob;
+
+ err = fdt_open_into(blob, buf, fdt_totalsize(blob));
+ if (err == -FDT_ERR_NOSPACE) {
+ /* Ran out of space converting to v17 */
+ int newsize = fdt_totalsize(blob) + 8;
+
+ buf = xmalloc(newsize);
+ err = fdt_open_into(blob, buf, newsize);
+ }
+ if (err)
+ FAIL("fdt_open_into(): %s", fdt_strerror(err));
+ return buf;
+}
diff --git a/src/dtc/tests/trees.S b/src/dtc/tests/trees.S
new file mode 100644
index 0000000..cae0187
--- /dev/null
+++ b/src/dtc/tests/trees.S
@@ -0,0 +1,201 @@
+#include <fdt.h>
+#include "testdata.h"
+
+#define FDTLONG(val) \
+ .byte ((val) >> 24) & 0xff ; \
+ .byte ((val) >> 16) & 0xff ; \
+ .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: \
+tree: \
+ FDTLONG(FDT_MAGIC) ; \
+ FDTLONG(tree##_end - tree) ; \
+ FDTLONG(tree##_struct - tree) ; \
+ FDTLONG(tree##_strings - tree) ; \
+ FDTLONG(tree##_rsvmap - tree) ; \
+ FDTLONG(0x11) ; \
+ FDTLONG(0x10) ; \
+ FDTLONG(0) ; \
+ FDTLONG(tree##_strings_end - tree##_strings) ; \
+ FDTLONG(tree##_struct_end - tree##_struct) ;
+
+#define RSVMAP_ENTRY(addr, len) \
+ FDTQUAD(addr) ; \
+ FDTQUAD(len) ; \
+
+#define EMPTY_RSVMAP(tree) \
+ .balign 8 ; \
+tree##_rsvmap: ; \
+ RSVMAP_ENTRY(0, 0) \
+tree##_rsvmap_end: ;
+
+#define PROPHDR(tree, name, len) \
+ FDTLONG(FDT_PROP) ; \
+ FDTLONG(len) ; \
+ FDTLONG(tree##_##name - tree##_strings) ;
+
+#define PROP_INT(tree, name, val) \
+ PROPHDR(tree, name, 4) \
+ FDTLONG(val) ;
+
+#define PROP_INT64(tree, name, val) \
+ PROPHDR(tree, name, 8) \
+ FDTQUAD(val) ;
+
+#define PROP_STR(tree, name, str) \
+ PROPHDR(tree, name, 55f - 54f) \
+54: \
+ .string str ; \
+55: \
+ .balign 4 ;
+
+#define BEGIN_NODE(name) \
+ FDTLONG(FDT_BEGIN_NODE) ; \
+ .string name ; \
+ .balign 4 ;
+
+#define END_NODE \
+ FDTLONG(FDT_END_NODE) ;
+
+#define STRING(tree, name, str) \
+tree##_##name: ; \
+ .string str ;
+
+ .data
+
+ TREE_HDR(test_tree1)
+
+ .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)
+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_STR(test_tree1, prop_str, TEST_STRING_1)
+
+ BEGIN_NODE("subnode@1")
+ PROP_STR(test_tree1, compatible, "subnode1")
+ PROP_INT(test_tree1, prop_int, TEST_VALUE_1)
+
+ BEGIN_NODE("subsubnode")
+ PROP_STR(test_tree1, compatible, "subsubnode1\0subsubnode")
+ PROP_INT(test_tree1, prop_int, TEST_VALUE_1)
+ END_NODE
+
+ BEGIN_NODE("ss1")
+ END_NODE
+
+ END_NODE
+
+ BEGIN_NODE("subnode@2")
+ PROP_INT(test_tree1, linux_phandle, PHANDLE_1)
+ PROP_INT(test_tree1, prop_int, TEST_VALUE_2)
+
+ BEGIN_NODE("subsubnode@0")
+ PROP_INT(test_tree1, phandle, PHANDLE_2)
+ PROP_STR(test_tree1, compatible, "subsubnode2\0subsubnode")
+ PROP_INT(test_tree1, prop_int, TEST_VALUE_2)
+ END_NODE
+
+ BEGIN_NODE("ss2")
+ END_NODE
+
+ END_NODE
+
+ END_NODE
+ FDTLONG(FDT_END)
+test_tree1_struct_end:
+
+test_tree1_strings:
+ STRING(test_tree1, compatible, "compatible")
+ STRING(test_tree1, prop_int, "prop-int")
+ STRING(test_tree1, prop_int64, "prop-int64")
+ STRING(test_tree1, prop_str, "prop-str")
+ STRING(test_tree1, linux_phandle, "linux,phandle")
+ STRING(test_tree1, phandle, "phandle")
+test_tree1_strings_end:
+test_tree1_end:
+
+
+ TREE_HDR(truncated_property)
+ EMPTY_RSVMAP(truncated_property)
+
+truncated_property_struct:
+ BEGIN_NODE("")
+ PROPHDR(truncated_property, prop_truncated, 4)
+ /* Oops, no actual property data here */
+truncated_property_struct_end:
+
+truncated_property_strings:
+ STRING(truncated_property, prop_truncated, "truncated")
+truncated_property_strings_end:
+
+truncated_property_end:
+
+
+ TREE_HDR(bad_node_char)
+ EMPTY_RSVMAP(bad_node_char)
+
+bad_node_char_struct:
+ BEGIN_NODE("")
+ BEGIN_NODE("sub$node")
+ END_NODE
+ END_NODE
+ FDTLONG(FDT_END)
+bad_node_char_struct_end:
+
+bad_node_char_strings:
+bad_node_char_strings_end:
+bad_node_char_end:
+
+
+ TREE_HDR(bad_node_format)
+ EMPTY_RSVMAP(bad_node_format)
+
+bad_node_format_struct:
+ BEGIN_NODE("")
+ BEGIN_NODE("subnode@1@2")
+ END_NODE
+ END_NODE
+ FDTLONG(FDT_END)
+bad_node_format_struct_end:
+
+bad_node_format_strings:
+bad_node_format_strings_end:
+bad_node_format_end:
+
+
+ TREE_HDR(bad_prop_char)
+ EMPTY_RSVMAP(bad_prop_char)
+
+bad_prop_char_struct:
+ BEGIN_NODE("")
+ PROP_INT(bad_prop_char, prop, TEST_VALUE_1)
+ END_NODE
+ FDTLONG(FDT_END)
+bad_prop_char_struct_end:
+
+bad_prop_char_strings:
+ STRING(bad_prop_char, prop, "prop$erty")
+bad_prop_char_strings_end:
+bad_prop_char_end:
diff --git a/src/dtc/tests/truncated_property.c b/src/dtc/tests/truncated_property.c
new file mode 100644
index 0000000..f820d99
--- /dev/null
+++ b/src/dtc/tests/truncated_property.c
@@ -0,0 +1,47 @@
+/*
+ * 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>
+#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_property;
+ const void *prop;
+ int len;
+
+ test_init(argc, argv);
+
+ prop = fdt_getprop(fdt, 0, "truncated", &len);
+ if (prop)
+ FAIL("fdt_getprop() succeeded on truncated property");
+ if (len != -FDT_ERR_BADSTRUCTURE)
+ FAIL("fdt_getprop() failed with \"%s\" instead of \"%s\"",
+ fdt_strerror(len), fdt_strerror(-FDT_ERR_BADSTRUCTURE));
+
+ PASS();
+}
diff --git a/src/dtc/tests/utilfdt_test.c b/src/dtc/tests/utilfdt_test.c
new file mode 100644
index 0000000..274c3d6
--- /dev/null
+++ b/src/dtc/tests/utilfdt_test.c
@@ -0,0 +1,127 @@
+/*
+ * 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>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdarg.h>
+
+#include <libfdt.h>
+#include <util.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+static void check(const char *fmt, int expect_type, int expect_size)
+{
+ int type;
+ int size;
+
+ if (utilfdt_decode_type(fmt, &type, &size))
+ FAIL("format '%s': valid format string returned failure", fmt);
+ if (expect_type != type)
+ FAIL("format '%s': expected type='%c', got type='%c'", fmt,
+ expect_type, type);
+ if (expect_size != size)
+ FAIL("format '%s': expected size=%d, got size=%d", fmt,
+ expect_size, size);
+}
+
+static void checkfail(const char *fmt)
+{
+ int type;
+ int size;
+
+ if (!utilfdt_decode_type(fmt, &type, &size))
+ FAIL("format '%s': invalid format string returned success",
+ fmt);
+}
+
+/**
+ * Add the given modifier to each of the valid sizes, and check that we get
+ * correct values.
+ *
+ * \param modifier Modifer string to use as a prefix
+ * \param expected_size The size (in bytes) that we expect (ignored for
+ * strings)
+ */
+static void check_sizes(char *modifier, int expected_size)
+{
+ char fmt[10], *ptr;
+
+ /* set up a string with a hole in it for the format character */
+ if (strlen(modifier) + 2 >= sizeof(fmt))
+ FAIL("modifier string '%s' too long", modifier);
+ strcpy(fmt, modifier);
+ ptr = fmt + strlen(fmt);
+ ptr[1] = '\0';
+
+ /* now try each format character in turn */
+ *ptr = 'i';
+ check(fmt, 'i', expected_size);
+
+ *ptr = 'u';
+ check(fmt, 'u', expected_size);
+
+ *ptr = 'x';
+ check(fmt, 'x', expected_size);
+
+ *ptr = 's';
+ check(fmt, 's', -1);
+}
+
+static void test_utilfdt_decode_type(void)
+{
+ char fmt[10];
+ int ch;
+
+ /* check all the valid modifiers and sizes */
+ check_sizes("", -1);
+ check_sizes("b", 1);
+ check_sizes("hh", 1);
+ check_sizes("h", 2);
+ check_sizes("l", 4);
+
+ /* try every other character */
+ checkfail("");
+ for (ch = ' '; ch < 127; ch++) {
+ if (!strchr("iuxs", ch)) {
+ *fmt = ch;
+ fmt[1] = '\0';
+ checkfail(fmt);
+ }
+ }
+
+ /* try a few modifiers at the end */
+ checkfail("sx");
+ checkfail("ihh");
+ checkfail("xb");
+
+ /* and one for the doomsday archives */
+ checkfail("He has all the virtues I dislike and none of the vices "
+ "I admire.");
+}
+
+int main(int argc, char *argv[])
+{
+ test_utilfdt_decode_type();
+ PASS();
+}
diff --git a/src/dtc/tests/value-labels.c b/src/dtc/tests/value-labels.c
new file mode 100644
index 0000000..dcf2059
--- /dev/null
+++ b/src/dtc/tests/value-labels.c
@@ -0,0 +1,127 @@
+/*
+ * 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>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <dlfcn.h>
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+struct val_label {
+ const char *labelname;
+ int propoff;
+};
+
+struct val_label labels1[] = {
+ { "start1", 0 },
+ { "mid1", 2 },
+ { "end1", -1 },
+};
+
+struct val_label labels2[] = {
+ { "start2", 0 },
+ { "innerstart2", 0 },
+ { "innermid2", 4 },
+ { "innerend2", -1 },
+ { "end2", -1 },
+};
+
+struct val_label labels3[] = {
+ { "start3", 0 },
+ { "innerstart3", 0 },
+ { "innermid3", 1 },
+ { "innerend3", -1 },
+ { "end3", -1 },
+};
+
+static void check_prop_labels(void *sohandle, void *fdt, const char *name,
+ const struct val_label* labels, int n)
+{
+ const struct fdt_property *prop;
+ const char *p;
+ int len;
+ int i;
+
+ prop = fdt_get_property(fdt, 0, name, &len);
+ if (!prop)
+ FAIL("Couldn't locate property \"%s\"", name);
+
+ p = dlsym(sohandle, name);
+ if (!p)
+ FAIL("Couldn't locate label symbol \"%s\"", name);
+
+ if (p != (const char *)prop)
+ FAIL("Label \"%s\" does not point to correct property", name);
+
+ for (i = 0; i < n; i++) {
+ int off = labels[i].propoff;
+
+ if (off == -1)
+ off = len;
+
+ p = dlsym(sohandle, labels[i].labelname);
+ if (!p)
+ FAIL("Couldn't locate label symbol \"%s\"", name);
+
+ if ((p - prop->data) != off)
+ FAIL("Label \"%s\" points to offset %ld instead of %d"
+ "in property \"%s\"", labels[i].labelname,
+ (long)(p - prop->data), off, name);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ void *sohandle;
+ void *fdt;
+ int err;
+
+ test_init(argc, argv);
+ if (argc != 2)
+ CONFIG("Usage: %s <so file>", argv[0]);
+
+ sohandle = dlopen(argv[1], RTLD_NOW);
+ if (!sohandle)
+ FAIL("Couldn't dlopen() %s", argv[1]);
+
+ fdt = dlsym(sohandle, "dt_blob_start");
+ if (!fdt)
+ FAIL("Couldn't locate \"dt_blob_start\" symbol in %s",
+ argv[1]);
+
+ err = fdt_check_header(fdt);
+ if (err != 0)
+ FAIL("%s contains invalid tree: %s", argv[1],
+ fdt_strerror(err));
+
+
+ check_prop_labels(sohandle, fdt, "prop1", labels1, ARRAY_SIZE(labels1));
+ check_prop_labels(sohandle, fdt, "prop2", labels2, ARRAY_SIZE(labels2));
+ check_prop_labels(sohandle, fdt, "prop3", labels3, ARRAY_SIZE(labels3));
+
+ PASS();
+}
diff --git a/src/dtc/tests/value-labels.dts b/src/dtc/tests/value-labels.dts
new file mode 100644
index 0000000..490c609
--- /dev/null
+++ b/src/dtc/tests/value-labels.dts
@@ -0,0 +1,8 @@
+/dts-v1/;
+
+/ {
+ prop1: prop1 = start1: "a", mid1: "b" end1:;
+ prop2: prop2 = start2: < innerstart2: 0xdeadbeef innermid2: 0xabcd1234 innerend2: > end2:;
+ prop3: prop3 = start3: [ innerstart3: ab innermid3: cd innerend3: ] end3:;
+};
+
diff --git a/src/dtc/tests/zero-phandle.dts b/src/dtc/tests/zero-phandle.dts
new file mode 100644
index 0000000..7997d98
--- /dev/null
+++ b/src/dtc/tests/zero-phandle.dts
@@ -0,0 +1,7 @@
+/dts-v1/;
+
+/ {
+ node {
+ linux,phandle = <0>;
+ };
+};
diff --git a/src/dtc/treesource.c b/src/dtc/treesource.c
new file mode 100644
index 0000000..33eeba5
--- /dev/null
+++ b/src/dtc/treesource.c
@@ -0,0 +1,284 @@
+/*
+ * (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"
+
+extern FILE *yyin;
+extern int yyparse(void);
+extern YYLTYPE yylloc;
+
+struct boot_info *the_boot_info;
+int treesource_error;
+
+struct boot_info *dt_from_source(const char *fname)
+{
+ the_boot_info = NULL;
+ treesource_error = 0;
+
+ srcfile_push(fname);
+ yyin = current_srcfile->f;
+ yylloc.file = current_srcfile;
+
+ if (yyparse() != 0)
+ die("Unable to parse input tree\n");
+
+ if (treesource_error)
+ die("Syntax error parsing input tree\n");
+
+ return the_boot_info;
+}
+
+static void write_prefix(FILE *f, int level)
+{
+ int i;
+
+ for (i = 0; i < level; i++)
+ fputc('\t', f);
+}
+
+static int isstring(char c)
+{
+ return (isprint(c)
+ || (c == '\0')
+ || strchr("\a\b\t\n\v\f\r", c));
+}
+
+static void write_propval_string(FILE *f, struct data val)
+{
+ const char *str = val.val;
+ int i;
+ struct marker *m = val.markers;
+
+ assert(str[val.len-1] == '\0');
+
+ while (m && (m->offset == 0)) {
+ if (m->type == LABEL)
+ fprintf(f, "%s: ", m->ref);
+ m = m->next;
+ }
+ fprintf(f, "\"");
+
+ for (i = 0; i < (val.len-1); i++) {
+ char c = str[i];
+
+ switch (c) {
+ case '\a':
+ fprintf(f, "\\a");
+ break;
+ case '\b':
+ fprintf(f, "\\b");
+ break;
+ case '\t':
+ fprintf(f, "\\t");
+ break;
+ case '\n':
+ fprintf(f, "\\n");
+ break;
+ case '\v':
+ fprintf(f, "\\v");
+ break;
+ case '\f':
+ fprintf(f, "\\f");
+ break;
+ case '\r':
+ fprintf(f, "\\r");
+ break;
+ case '\\':
+ fprintf(f, "\\\\");
+ break;
+ case '\"':
+ fprintf(f, "\\\"");
+ break;
+ case '\0':
+ fprintf(f, "\", ");
+ while (m && (m->offset < i)) {
+ if (m->type == LABEL) {
+ assert(m->offset == (i+1));
+ fprintf(f, "%s: ", m->ref);
+ }
+ m = m->next;
+ }
+ fprintf(f, "\"");
+ break;
+ default:
+ if (isprint(c))
+ fprintf(f, "%c", c);
+ else
+ fprintf(f, "\\x%02hhx", 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)
+{
+ void *propend = val.val + val.len;
+ cell_t *cp = (cell_t *)val.val;
+ struct marker *m = val.markers;
+
+ 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)
+ 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, ">");
+}
+
+static void write_propval_bytes(FILE *f, struct data val)
+{
+ 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", *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, "]");
+}
+
+static void write_propval(FILE *f, struct property *prop)
+{
+ int len = prop->val.len;
+ const char *p = prop->val.val;
+ struct marker *m = prop->val.markers;
+ int nnotstring = 0, nnul = 0;
+ 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++;
+ if (p[i] == '\0')
+ nnul++;
+ }
+
+ for_each_marker_of_type(m, LABEL) {
+ if ((m->offset > 0) && (prop->val.val[m->offset - 1] != '\0'))
+ nnotstringlbl++;
+ if ((m->offset % sizeof(cell_t)) != 0)
+ nnotcelllbl++;
+ }
+
+ fprintf(f, " = ");
+ if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul < (len-nnul))
+ && (nnotstringlbl == 0)) {
+ write_propval_string(f, prop->val);
+ } else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) {
+ write_propval_cells(f, prop->val);
+ } else {
+ write_propval_bytes(f, prop->val);
+ }
+
+ fprintf(f, ";\n");
+}
+
+static void write_tree_source_node(FILE *f, struct node *tree, int level)
+{
+ struct property *prop;
+ struct node *child;
+ struct label *l;
+
+ 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);
+ else
+ fprintf(f, "/ {\n");
+
+ for_each_property(tree, prop) {
+ write_prefix(f, level+1);
+ for_each_label(prop->labels, l)
+ fprintf(f, "%s: ", l->label);
+ fprintf(f, "%s", prop->name);
+ write_propval(f, prop);
+ }
+ for_each_child(tree, child) {
+ fprintf(f, "\n");
+ write_tree_source_node(f, child, level+1);
+ }
+ write_prefix(f, level);
+ fprintf(f, "};\n");
+}
+
+
+void dt_to_source(FILE *f, struct boot_info *bi)
+{
+ struct reserve_info *re;
+
+ fprintf(f, "/dts-v1/;\n\n");
+
+ for (re = bi->reservelist; re; re = re->next) {
+ struct label *l;
+
+ for_each_label(re->labels, l)
+ fprintf(f, "%s: ", l->label);
+ fprintf(f, "/memreserve/\t0x%016llx 0x%016llx;\n",
+ (unsigned long long)re->re.address,
+ (unsigned long long)re->re.size);
+ }
+
+ write_tree_source_node(f, bi->dt, 0);
+}
+
diff --git a/src/dtc/util.c b/src/dtc/util.c
new file mode 100644
index 0000000..3055c16
--- /dev/null
+++ b/src/dtc/util.c
@@ -0,0 +1,448 @@
+/*
+ * 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>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <assert.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "libfdt.h"
+#include "util.h"
+#include "version_gen.h"
+
+char *xstrdup(const char *s)
+{
+ int len = strlen(s) + 1;
+ char *dup = xmalloc(len);
+
+ memcpy(dup, s, len);
+
+ return dup;
+}
+
+char *join_path(const char *path, const char *name)
+{
+ int lenp = strlen(path);
+ int lenn = strlen(name);
+ int len;
+ int needslash = 1;
+ char *str;
+
+ len = lenp + lenn + 2;
+ if ((lenp > 0) && (path[lenp-1] == '/')) {
+ needslash = 0;
+ len--;
+ }
+
+ str = xmalloc(len);
+ memcpy(str, path, lenp);
+ if (needslash) {
+ str[lenp] = '/';
+ lenp++;
+ }
+ memcpy(str+lenp, name, lenn+1);
+ return str;
+}
+
+int util_is_printable_string(const void *data, int len)
+{
+ const char *s = data;
+ const char *ss, *se;
+
+ /* zero length is not */
+ if (len == 0)
+ return 0;
+
+ /* must terminate with zero */
+ if (s[len - 1] != '\0')
+ return 0;
+
+ se = s + len;
+
+ while (s < se) {
+ ss = s;
+ while (s < se && *s && isprint(*s))
+ s++;
+
+ /* not zero, or not done yet */
+ if (*s != '\0' || s == ss)
+ return 0;
+
+ s++;
+ }
+
+ return 1;
+}
+
+/*
+ * Parse a octal encoded character starting at index i in string s. The
+ * resulting character will be returned and the index i will be updated to
+ * point at the character directly after the end of the encoding, this may be
+ * the '\0' terminator of the string.
+ */
+static char get_oct_char(const char *s, int *i)
+{
+ char x[4];
+ char *endx;
+ long val;
+
+ x[3] = '\0';
+ strncpy(x, s + *i, 3);
+
+ val = strtol(x, &endx, 8);
+
+ assert(endx > x);
+
+ (*i) += endx - x;
+ return val;
+}
+
+/*
+ * Parse a hexadecimal encoded character starting at index i in string s. The
+ * resulting character will be returned and the index i will be updated to
+ * point at the character directly after the end of the encoding, this may be
+ * the '\0' terminator of the string.
+ */
+static char get_hex_char(const char *s, int *i)
+{
+ char x[3];
+ char *endx;
+ long val;
+
+ x[2] = '\0';
+ strncpy(x, s + *i, 2);
+
+ val = strtol(x, &endx, 16);
+ if (!(endx > x))
+ die("\\x used with no following hex digits\n");
+
+ (*i) += endx - x;
+ return val;
+}
+
+char get_escape_char(const char *s, int *i)
+{
+ char c = s[*i];
+ int j = *i + 1;
+ char val;
+
+ assert(c);
+ switch (c) {
+ case 'a':
+ val = '\a';
+ break;
+ case 'b':
+ val = '\b';
+ break;
+ case 't':
+ val = '\t';
+ break;
+ case 'n':
+ val = '\n';
+ break;
+ case 'v':
+ val = '\v';
+ break;
+ case 'f':
+ val = '\f';
+ break;
+ case 'r':
+ val = '\r';
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ j--; /* need to re-read the first digit as
+ * part of the octal value */
+ val = get_oct_char(s, &j);
+ break;
+ case 'x':
+ val = get_hex_char(s, &j);
+ break;
+ default:
+ val = c;
+ }
+
+ (*i) = j;
+ return val;
+}
+
+int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len)
+{
+ int fd = 0; /* assume stdin */
+ char *buf = NULL;
+ off_t bufsize = 1024, offset = 0;
+ int ret = 0;
+
+ *buffp = NULL;
+ if (strcmp(filename, "-") != 0) {
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return errno;
+ }
+
+ /* Loop until we have read everything */
+ buf = xmalloc(bufsize);
+ do {
+ /* Expand the buffer to hold the next chunk */
+ if (offset == bufsize) {
+ bufsize *= 2;
+ buf = xrealloc(buf, bufsize);
+ if (!buf) {
+ ret = ENOMEM;
+ break;
+ }
+ }
+
+ ret = read(fd, &buf[offset], bufsize - offset);
+ if (ret < 0) {
+ ret = errno;
+ break;
+ }
+ offset += ret;
+ } while (ret != 0);
+
+ /* Clean up, including closing stdin; return errno on error */
+ close(fd);
+ if (ret)
+ free(buf);
+ else
+ *buffp = buf;
+ *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 *buff;
+ int ret = utilfdt_read_err_len(filename, &buff, len);
+
+ if (ret) {
+ fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
+ strerror(ret));
+ return NULL;
+ }
+ /* Successful read */
+ 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 */
+ int totalsize;
+ int offset;
+ int ret = 0;
+ const char *ptr = blob;
+
+ if (strcmp(filename, "-") != 0) {
+ fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (fd < 0)
+ return errno;
+ }
+
+ totalsize = fdt_totalsize(blob);
+ offset = 0;
+
+ while (offset < totalsize) {
+ ret = write(fd, ptr + offset, totalsize - offset);
+ if (ret < 0) {
+ ret = -errno;
+ break;
+ }
+ offset += ret;
+ }
+ /* Close the file/stdin; return errno on error */
+ if (fd != 1)
+ close(fd);
+ return ret < 0 ? -ret : 0;
+}
+
+
+int utilfdt_write(const char *filename, const void *blob)
+{
+ int ret = utilfdt_write_err(filename, blob);
+
+ if (ret) {
+ fprintf(stderr, "Couldn't write blob to '%s': %s\n", filename,
+ strerror(ret));
+ }
+ return ret ? -1 : 0;
+}
+
+int utilfdt_decode_type(const char *fmt, int *type, int *size)
+{
+ int qualifier = 0;
+
+ if (!*fmt)
+ return -1;
+
+ /* get the conversion qualifier */
+ *size = -1;
+ if (strchr("hlLb", *fmt)) {
+ qualifier = *fmt++;
+ if (qualifier == *fmt) {
+ switch (*fmt++) {
+/* TODO: case 'l': qualifier = 'L'; break;*/
+ case 'h':
+ qualifier = 'b';
+ break;
+ }
+ }
+ }
+
+ /* we should now have a type */
+ if ((*fmt == '\0') || !strchr("iuxs", *fmt))
+ return -1;
+
+ /* convert qualifier (bhL) to byte size */
+ if (*fmt != 's')
+ *size = qualifier == 'b' ? 1 :
+ qualifier == 'h' ? 2 :
+ qualifier == 'l' ? 4 : -1;
+ *type = *fmt++;
+
+ /* that should be it! */
+ if (*fmt)
+ return -1;
+ return 0;
+}
+
+void utilfdt_print_data(const char *data, int len)
+{
+ int i;
+ const char *p = data;
+ const char *s;
+
+ /* no data, don't print */
+ if (len == 0)
+ return;
+
+ if (util_is_printable_string(data, len)) {
+ printf(" = ");
+
+ s = data;
+ do {
+ printf("\"%s\"", s);
+ s += strlen(s) + 1;
+ if (s < data + len)
+ printf(", ");
+ } while (s < data + len);
+
+ } else if ((len % 4) == 0) {
+ const uint32_t *cell = (const uint32_t *)data;
+
+ printf(" = <");
+ for (i = 0; i < len; i += 4)
+ printf("0x%08x%s", fdt32_to_cpu(cell[i]),
+ i < (len - 4) ? " " : "");
+ printf(">");
+ } else {
+ printf(" = [");
+ for (i = 0; i < len; i++)
+ printf("%02x%s", *p++, i < len - 1 ? " " : "");
+ printf("]");
+ }
+}
+
+void util_version(void)
+{
+ printf("Version: %s\n", DTC_VERSION);
+ exit(0);
+}
+
+void util_usage(const char *errmsg, const char *synopsis,
+ const char *short_opts, struct option const long_opts[],
+ const char * const opts_help[])
+{
+ FILE *fp = errmsg ? stderr : stdout;
+ const char a_arg[] = "<arg>";
+ size_t a_arg_len = strlen(a_arg) + 1;
+ size_t i;
+ int optlen;
+
+ fprintf(fp,
+ "Usage: %s\n"
+ "\n"
+ "Options: -[%s]\n", synopsis, short_opts);
+
+ /* prescan the --long opt length to auto-align */
+ optlen = 0;
+ for (i = 0; long_opts[i].name; ++i) {
+ /* +1 is for space between --opt and help text */
+ int l = strlen(long_opts[i].name) + 1;
+ if (long_opts[i].has_arg == a_argument)
+ l += a_arg_len;
+ if (optlen < l)
+ optlen = l;
+ }
+
+ for (i = 0; long_opts[i].name; ++i) {
+ /* helps when adding new applets or options */
+ assert(opts_help[i] != NULL);
+
+ /* first output the short flag if it has one */
+ if (long_opts[i].val > '~')
+ fprintf(fp, " ");
+ else
+ fprintf(fp, " -%c, ", long_opts[i].val);
+
+ /* then the long flag */
+ if (long_opts[i].has_arg == no_argument)
+ fprintf(fp, "--%-*s", optlen, long_opts[i].name);
+ else
+ fprintf(fp, "--%s %s%*s", long_opts[i].name, a_arg,
+ (int)(optlen - strlen(long_opts[i].name) - a_arg_len), "");
+
+ /* finally the help text */
+ fprintf(fp, "%s\n", opts_help[i]);
+ }
+
+ if (errmsg) {
+ fprintf(fp, "\nError: %s\n", errmsg);
+ exit(EXIT_FAILURE);
+ } else
+ exit(EXIT_SUCCESS);
+}
diff --git a/src/dtc/util.h b/src/dtc/util.h
new file mode 100644
index 0000000..8f40b44
--- /dev/null
+++ b/src/dtc/util.h
@@ -0,0 +1,250 @@
+#ifndef _UTIL_H
+#define _UTIL_H
+
+#include <stdarg.h>
+#include <getopt.h>
+
+/*
+ * 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
+ */
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+static inline void __attribute__((noreturn)) die(const char *str, ...)
+{
+ va_list ap;
+
+ va_start(ap, str);
+ fprintf(stderr, "FATAL ERROR: ");
+ vfprintf(stderr, str, ap);
+ exit(1);
+}
+
+static inline void *xmalloc(size_t len)
+{
+ void *new = malloc(len);
+
+ if (!new)
+ die("malloc() failed\n");
+
+ return new;
+}
+
+static inline void *xrealloc(void *p, size_t len)
+{
+ void *new = realloc(p, len);
+
+ if (!new)
+ die("realloc() failed (len=%d)\n", len);
+
+ return new;
+}
+
+extern char *xstrdup(const char *s);
+extern char *join_path(const char *path, const char *name);
+
+/**
+ * Check a property of a given length to see if it is all printable and
+ * has a valid terminator. The property can contain either a single string,
+ * or multiple strings each of non-zero length.
+ *
+ * @param data The string to check
+ * @param len The string length including terminator
+ * @return 1 if a valid printable string, 0 if not
+ */
+int util_is_printable_string(const void *data, int len);
+
+/*
+ * Parse an escaped character starting at index i in string s. The resulting
+ * character will be returned and the index i will be updated to point at the
+ * character directly after the end of the encoding, this may be the '\0'
+ * terminator of the string.
+ */
+char get_escape_char(const char *s, int *i);
+
+/**
+ * Read a device tree file into a buffer. This will report any errors on
+ * stderr.
+ *
+ * @param filename The filename to read, or - for stdin
+ * @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);
+
+/**
+ * Read a device tree file into a buffer. Does not report errors, but only
+ * returns them. The value returned can be passed to strerror() to obtain
+ * an error message for the user.
+ *
+ * @param filename The filename to read, or - for stdin
+ * @param buffp Returns pointer to buffer containing fdt
+ * @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);
+
+/**
+ * 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
+ * @return 0 if ok, -1 on error
+ */
+int utilfdt_write(const char *filename, const void *blob);
+
+/**
+ * Write a device tree buffer to a file. Does not report errors, but only
+ * returns them. The value returned can be passed to strerror() to obtain
+ * an error message for the user.
+ *
+ * @param filename The filename to write, or - for stdout
+ * @param blob Poiner 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);
+
+/**
+ * Decode a data type string. The purpose of this string
+ *
+ * The string consists of an optional character followed by the type:
+ * Modifier characters:
+ * hh or b 1 byte
+ * h 2 byte
+ * l 4 byte, default
+ *
+ * Type character:
+ * s string
+ * i signed integer
+ * u unsigned integer
+ * x hex
+ *
+ * TODO: Implement ll modifier (8 bytes)
+ * TODO: Implement o type (octal)
+ *
+ * @param fmt Format string to process
+ * @param type Returns type found(s/d/u/x), or 0 if none
+ * @param size Returns size found(1,2,4,8) or 4 if none
+ * @return 0 if ok, -1 on error (no type given, or other invalid format)
+ */
+int utilfdt_decode_type(const char *fmt, int *type, int *size);
+
+/*
+ * This is a usage message fragment for the -t option. It is the format
+ * supported by utilfdt_decode_type.
+ */
+
+#define USAGE_TYPE_MSG \
+ "<type>\ts=string, i=int, u=unsigned, x=hex\n" \
+ "\tOptional modifier prefix:\n" \
+ "\t\thh or b=byte, h=2 byte, l=4 byte (default)";
+
+/**
+ * Print property data in a readable format to stdout
+ *
+ * Properties that look like strings will be printed as strings. Otherwise
+ * the data will be displayed either as cells (if len is a multiple of 4
+ * bytes) or bytes.
+ *
+ * If len is 0 then this function does nothing.
+ *
+ * @param data Pointers to property data
+ * @param len Length of property data
+ */
+void utilfdt_print_data(const char *data, int len);
+
+/**
+ * Show source version and exit
+ */
+void util_version(void) __attribute__((noreturn));
+
+/**
+ * Show usage and exit
+ *
+ * This helps standardize the output of various utils. You most likely want
+ * to use the usage() helper below rather than call this.
+ *
+ * @param errmsg If non-NULL, an error message to display
+ * @param synopsis The initial example usage text (and possible examples)
+ * @param short_opts The string of short options
+ * @param long_opts The structure of long options
+ * @param opts_help An array of help strings (should align with long_opts)
+ */
+void util_usage(const char *errmsg, const char *synopsis,
+ const char *short_opts, struct option const long_opts[],
+ const char * const opts_help[]) __attribute__((noreturn));
+
+/**
+ * Show usage and exit
+ *
+ * If you name all your usage variables with usage_xxx, then you can call this
+ * help macro rather than expanding all arguments yourself.
+ *
+ * @param errmsg If non-NULL, an error message to display
+ */
+#define usage(errmsg) \
+ util_usage(errmsg, usage_synopsis, usage_short_opts, \
+ usage_long_opts, usage_opts_help)
+
+/**
+ * Call getopt_long() with standard options
+ *
+ * Since all util code runs getopt in the same way, provide a helper.
+ */
+#define util_getopt_long() getopt_long(argc, argv, usage_short_opts, \
+ usage_long_opts, NULL)
+
+/* Helper for aligning long_opts array */
+#define a_argument required_argument
+
+/* Helper for usage_short_opts string constant */
+#define USAGE_COMMON_SHORT_OPTS "hV"
+
+/* Helper for usage_long_opts option array */
+#define USAGE_COMMON_LONG_OPTS \
+ {"help", no_argument, NULL, 'h'}, \
+ {"version", no_argument, NULL, 'V'}, \
+ {NULL, no_argument, NULL, 0x0}
+
+/* Helper for usage_opts_help array */
+#define USAGE_COMMON_OPTS_HELP \
+ "Print this help and exit", \
+ "Print version and exit", \
+ NULL
+
+/* Helper for getopt case statements */
+#define case_USAGE_COMMON_FLAGS \
+ case 'h': usage(NULL); \
+ case 'V': util_version(); \
+ case '?': usage("unknown option");
+
+#endif /* _UTIL_H */
OpenPOWER on IntegriCloud