Compare commits

..

No commits in common. "master" and "v1.4.1" have entirely different histories.

251 changed files with 3536 additions and 16184 deletions

View File

@ -1,39 +0,0 @@
# FreeBSD build with multiple versions
freebsd_versions_task:
name: FreeBSD $FREEBSD_VERSION make build
freebsd_instance:
image_family: $FREEBSD_IMAGE
matrix:
- env:
FREEBSD_VERSION: "13.5"
FREEBSD_IMAGE: freebsd-13-5
- env:
FREEBSD_VERSION: "14.3"
FREEBSD_IMAGE: freebsd-14-3
install_script:
- pkg install -y git gmake flex bison python3 py312-setuptools swig libyaml pkgconf
build_script:
- gmake
check_script:
- gmake check

# FreeBSD meson builds with multiple versions
freebsd_meson_versions_task:
name: FreeBSD $FREEBSD_VERSION meson build
freebsd_instance:
image_family: $FREEBSD_IMAGE
matrix:
- env:
FREEBSD_VERSION: "13.5"
FREEBSD_IMAGE: freebsd-13-5
- env:
FREEBSD_VERSION: "14.3"
FREEBSD_IMAGE: freebsd-14-3
install_script:
- pkg install -y git meson ninja flex bison python3 py312-setuptools swig libyaml pkgconf
setup_script:
- meson setup -D python=enabled -D yaml=enabled build
build_script:
- meson compile -C build
test_script:
- if ! meson test -C build; then cat build/meson-logs/testlog.txt; false; fi

View File

@ -1,135 +0,0 @@
# SPDX-License-Identifier: GPL-2.0
#
# clang-format configuration file. Intended for clang-format >= 11.
#
# For more information, see:
#
# Documentation/dev-tools/clang-format.rst
# https://clang.llvm.org/docs/ClangFormat.html
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
#
---
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: false
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: false

# Taken from:
# git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' \
# | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \
# | LC_ALL=C sort -u
ForEachMacros:
- 'fdt_for_each_property_offset'
- 'fdt_for_each_subnode'
- 'for_each_child'
- 'for_each_child_withdel'
- 'for_each_label'
- 'for_each_label_withdel'
- 'for_each_marker'
- 'for_each_marker_of_type'
- 'for_each_property'
- 'for_each_property_withdel'

IncludeBlocks: Preserve
IncludeCategories:
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
IndentGotoLabels: false
IndentPPDirectives: None
IndentWidth: 8
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 8
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true

# Taken from git's rules
PenaltyBreakAssignment: 10
PenaltyBreakBeforeFirstCallParameter: 30
PenaltyBreakComment: 10
PenaltyBreakFirstLessLess: 0
PenaltyBreakString: 10
PenaltyExcessCharacter: 100
PenaltyReturnTypeOnItsOwnLine: 60

PointerAlignment: Right
ReflowComments: false
SortIncludes: false
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatementsExceptForEachMacros
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp03
TabWidth: 8
UseTab: Always
...

View File

@ -1,33 +0,0 @@
# EditorConfig is a file format and collection of text editor plugins
# for maintaining consistent coding styles between different editors
# and IDEs. Most popular editors support this either natively or via
# plugin.
#
# Check https://editorconfig.org for details.

root = true

[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
indent_style = space

[Makefile*]
indent_style = tab
indent_size = 8
file_type_emacs = makefile

[*.[ch]]
indent_style = tab
indent_size = 8

[*.py]
indent_size = 4

[meson.build]
indent_style = space
indent_size = 2

[*.lds]
indent_style = tab

View File

@ -1,114 +0,0 @@
---
name: Build test
'on':
push:
branches:
- main
- ci
pull_request:
branches:
- main

# ensure that the workflow is only triggered once per PR, subsequent pushes to the PR will cancel
# and restart the workflow. See https://docs.github.com/en/actions/using-jobs/using-concurrency
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

jobs:
build-make:
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
os: [ "alpine", "archlinux", "fedora", "ubuntu" ]

container:
image: ${{ matrix.os }}

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install Dependencies
run: |
./scripts/install-deps.sh

- name: Build
run: |
make

- name: Run check
run: |
make check

build-meson:
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
os: [ "alpine", "archlinux", "fedora", "ubuntu" ]

container:
image: ${{ matrix.os }}

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install Dependencies
run: |
./scripts/install-deps.sh

- name: Setup
run: meson setup -D python=enabled -D yaml=enabled build

- name: Build
run: meson compile -C build

- name: Run check
run: if ! meson test -C build; then cat build/meson-logs/testlog.txt; false; fi

build-windows:
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include:
- { sys: mingw32 }
- { sys: mingw64 }
- { sys: ucrt64 }
- { sys: clang64 }
name: ${{ matrix.sys }}
defaults:
run:
shell: msys2 {0}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: ${{matrix.sys}}
update: true
install: >-
git
flex
bison
pacboy: >-
toolchain:p
meson:p
ninja:p
libyaml:p
swig:p
python-setuptools-scm:p

- name: 'đźš§ Build'
run: |
meson setup -Dtools=true -Dtests=false build
meson compile -C build

13
.gitignore vendored
View File

@ -3,28 +3,15 @@
*.a
*.patch
*.so
*.so.*
*~
*.bak
*.tab.[ch]
lex.yy.c
*.lex.c
.*.swp
/dtc
/fdtdump
/convert-dtsv0
/version_gen.h
/fdtget
/fdtput
/fdtoverlay
/patches
/.pc

# cscope files
cscope.*
ncscope.*

.eggs/
build/
dist/
*.egg-info/

View File

@ -1,65 +0,0 @@
stages:
- build

variables:
GIT_DEPTH: 1

workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "main"
- if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "ci"
- if: $CI_PIPELINE_SOURCE == "merge_request_event"

# Linux builds with make
.build-make-template: &build-make-template
stage: build
before_script:
- ./scripts/install-deps.sh
script:
- make
- make check
interruptible: true

build-make-alpine:
<<: *build-make-template
image: alpine:latest

build-make-archlinux:
<<: *build-make-template
image: archlinux:latest

build-make-fedora:
<<: *build-make-template
image: fedora:latest

build-make-ubuntu:
<<: *build-make-template
image: ubuntu:latest

# Linux builds with meson
.build-meson-template: &build-meson-template
stage: build
before_script:
- ./scripts/install-deps.sh
script:
- meson setup -D python=enabled -D yaml=enabled build
- meson compile -C build
- if ! meson test -C build; then cat build/meson-logs/testlog.txt; false; fi
interruptible: true

build-meson-alpine:
<<: *build-meson-template
image: alpine:latest

build-meson-archlinux:
<<: *build-meson-template
image: archlinux:latest

build-meson-fedora:
<<: *build-meson-template
image: fedora:latest

build-meson-ubuntu:
<<: *build-meson-template
image: ubuntu:latest

View File

@ -1,32 +0,0 @@
Valid-License-Identifier: BSD-2-Clause
SPDX-URL: https://spdx.org/licenses/BSD-2-Clause.html
Usage-Guide:
To use the BSD 2-clause "Simplified" License put the following SPDX
tag/value pair into a comment according to the placement guidelines in
the licensing rules documentation:
SPDX-License-Identifier: BSD-2-Clause
License-Text:

Copyright (c) <year> <owner> . All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,79 +0,0 @@
# Contributing to dtc or libfdt

There are two ways to submit changes for dtc or libfdt:

* Post patches directly to the
[devicetree-compiler](mailto:devicetree-compiler@vger.kernel.org)
mailing list.
* Submit pull requests via
[Github](https://github.com/dgibson/dtc/pulls)

## Adding a new function to libfdt.h

The shared library uses `libfdt/version.lds` to list the exported
functions, so add your new function there. Check that your function
works with pylibfdt. If it cannot be supported, put the declaration in
`libfdt.h` behind `#ifndef SWIG` so that swig ignores it.

## Tests

Test files are kept in the `tests/` directory. Use `make check` to build and run
all tests.

If you want to adjust a test file, be aware that `tree_tree1.dts` is compiled
and checked against a binary tree from assembler macros in `trees.S`. So
if you change that file you must change `tree.S` also.

## Developer's Certificate of Origin

Like many other projects, dtc and libfdt have adopted the "Developer's
Certificate of Origin" (Signed-off-by) process created by the Linux
kernel community to improve tracking of who did what. Here's how it
works (this is a very slight modification of the description from
`Documentation/process/submitting-patches.rst` in the kernel tree):

The sign-off is a simple line at the end of the explanation for the
patch, which certifies that you wrote it or otherwise have the right
to pass it on as an open-source patch. The rules are pretty simple:
if you can certify the below:

Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or

(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or

(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.

(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.

then you just add a line saying::

Signed-off-by: Random J Developer <random@developer.example.org>

using your real name (sorry, no pseudonyms or anonymous
contributions.) This will be done for you automatically if you use
`git commit -s`. Reverts should also include "Signed-off-by". `git
revert -s` does that for you.

Any further SoBs (Signed-off-by:'s) following the author's SoB are
from people handling and transporting the patch, but were not involved
in its development. SoB chains should reflect the **real** route a
patch took as it was propagated to the maintainers, with the first SoB
entry signalling primary authorship of a single author.

View File

@ -1,310 +0,0 @@
Device Tree Dynamic Object format internals
-------------------------------------------

The Device Tree for most platforms is a static representation of
the hardware capabilities. This is insufficient for platforms
that need to dynamically insert Device Tree fragments into the
live tree.

This document explains the Device Tree object format and
modifications made to the Device Tree compiler, which make it possible.

1. Simplified Problem Definition
--------------------------------

Assume we have a platform which boots using following simplified Device Tree.

---- foo.dts -----------------------------------------------------------------
/* FOO platform */
/ {
compatible = "corp,foo";

/* shared resources */
res: res {
};

/* On chip peripherals */
ocp: ocp {
/* peripherals that are always instantiated */
peripheral1 { ... };
};
};
---- foo.dts -----------------------------------------------------------------

We have a number of peripherals that after probing (using some undefined method)
should result in different Device Tree configuration.

We cannot boot with this static tree because due to the configuration of the
foo platform there exist multiple conflicting peripherals DT fragments.

So for the bar peripheral we would have this:

---- foo+bar.dts -------------------------------------------------------------
/* FOO platform + bar peripheral */
/ {
compatible = "corp,foo";

/* shared resources */
res: res {
};

/* On chip peripherals */
ocp: ocp {
/* peripherals that are always instantiated */
peripheral1 { ... };

/* bar peripheral */
bar {
compatible = "corp,bar";
... /* various properties and child nodes */
};
};
};
---- foo+bar.dts -------------------------------------------------------------

While for the baz peripheral we would have this:

---- foo+baz.dts -------------------------------------------------------------
/* FOO platform + baz peripheral */
/ {
compatible = "corp,foo";

/* shared resources */
res: res {
/* baz resources */
baz_res: res_baz { ... };
};

/* On chip peripherals */
ocp: ocp {
/* peripherals that are always instantiated */
peripheral1 { ... };

/* baz peripheral */
baz {
compatible = "corp,baz";
/* reference to another point in the tree */
ref-to-res = <&baz_res>;
... /* various properties and child nodes */
};
};
};
---- foo+baz.dts -------------------------------------------------------------

We note that the baz case is more complicated, since the baz peripheral needs to
reference another node in the DT tree.

2. Device Tree Object Format Requirements
-----------------------------------------

Since the Device Tree is used for booting a number of very different hardware
platforms it is imperative that we tread very carefully.

2.a) No changes to the Device Tree binary format for the base tree. We cannot
modify the tree format at all and all the information we require should be
encoded using Device Tree itself. We can add nodes that can be safely ignored
by both bootloaders and the kernel. The plugin dtbs are optionally tagged
with a different magic number in the header but otherwise they're simple
blobs.

2.b) Changes to the DTS source format should be absolutely minimal, and should
only be needed for the DT fragment definitions, and not the base boot DT.

2.c) An explicit option should be used to instruct DTC to generate the required
information needed for object resolution. Platforms that don't use the
dynamic object format can safely ignore it.

2.d) Finally, DT syntax changes should be kept to a minimum. It should be
possible to express everything using the existing DT syntax.

3. Implementation
-----------------

The basic unit of addressing in Device Tree is the phandle. Turns out it's
relatively simple to extend the way phandles are generated and referenced
so that it's possible to dynamically convert symbolic references (labels)
to phandle values. This is a valid assumption as long as the author uses
reference syntax and does not assign phandle values manually (which might
be a problem with decompiled source files).

We can roughly divide the operation into two steps.

3.a) Compilation of the base board DTS file using the '-@' option
generates a valid DT blob with an added __symbols__ node at the root node,
containing a list of all nodes that are marked with a label.

Using the foo.dts file above the following node will be generated;

$ dtc -@ -O dtb -o foo.dtb -b 0 foo.dts
$ fdtdump foo.dtb
...
/ {
...
res {
...
phandle = <0x00000001>;
...
};
ocp {
...
phandle = <0x00000002>;
...
};
__symbols__ {
res="/res";
ocp="/ocp";
};
};

Notice that all the nodes that had a label have been recorded, and that
phandles have been generated for them.

This blob can be used to boot the board normally, the __symbols__ node will
be safely ignored both by the bootloader and the kernel (the only loss will
be a few bytes of memory and disk space).

We generate a __symbols__ node to record nodes that had labels in the base
tree (or subsequent loaded overlays) so that they can be matched up with
references made to them in Device Tree objects.

3.b) The Device Tree fragments must be compiled with the same option but they
must also have a tag (/plugin/) that allows undefined references to nodes
that are not present at compilation time to be recorded so that the runtime
loader can fix them.

So the bar peripheral's DTS format would be of the form:

/dts-v1/;
/plugin/; /* allow undefined references and record them */
/ {
.... /* various properties for loader use; i.e. part id etc. */
fragment@0 {
target = <&ocp>;
__overlay__ {
/* bar peripheral */
bar {
compatible = "corp,bar";
... /* various properties and child nodes */
}
};
};
};

Note that there's a target property that specifies the location where the
contents of the overlay node will be placed, and it references the node
in the foo.dts file.

$ dtc -@ -O dtb -o bar.dtbo -b 0 bar.dts
$ fdtdump bar.dtbo
...
/ {
... /* properties */
fragment@0 {
target = <0xffffffff>;
__overlay__ {
bar {
compatible = "corp,bar";
... /* various properties and child nodes */
}
};
};
__fixups__ {
ocp = "/fragment@0:target:0";
};
};

No __symbols__ node has been generated (no label in bar.dts).
Note that the target's ocp label is undefined, so the phandle
value is filled with the illegal value '0xffffffff', while a __fixups__
node has been generated, which marks the location in the tree where
the label lookup should store the runtime phandle value of the ocp node.

The format of the __fixups__ node entry is

<label> = "<local-full-path>:<property-name>:<offset>"
[, "<local-full-path>:<property-name>:<offset>"...];

<label> Is the label we're referring
<local-full-path> Is the full path of the node the reference is
<property-name> Is the name of the property containing the
reference
<offset> The offset (in bytes) of where the property's
phandle value is located.

Doing the same with the baz peripheral's DTS format is a little bit more
involved, since baz contains references to local labels which require
local fixups.

/dts-v1/;
/plugin/; /* allow undefined label references and record them */
/ {
.... /* various properties for loader use; i.e. part id etc. */
fragment@0 {
target = <&res>;
__overlay__ {
/* baz resources */
baz_res: res_baz { ... };
};
};
fragment@1 {
target = <&ocp>;
__overlay__ {
/* baz peripheral */
baz {
compatible = "corp,baz";
/* reference to another point in the tree */
ref-to-res = <&baz_res>;
... /* various properties and child nodes */
}
};
};
};

Note that &bar_res reference.

$ dtc -@ -O dtb -o baz.dtbo -b 0 baz.dts
$ fdtdump baz.dtbo
...
/ {
... /* properties */
fragment@0 {
target = <0xffffffff>;
__overlay__ {
res_baz {
....
phandle = <0x00000001>;
};
};
};
fragment@1 {
target = <0xffffffff>;
__overlay__ {
baz {
compatible = "corp,baz";
... /* various properties and child nodes */
ref-to-res = <0x00000001>;
}
};
};
__fixups__ {
res = "/fragment@0:target:0";
ocp = "/fragment@1:target:0";
};
__local_fixups__ {
fragment@1 {
__overlay__ {
baz {
ref-to-res = <0>;
};
};
};
};
};

This is similar to the bar case, but the reference of a local label by the
baz node generates a __local_fixups__ entry that records the place that the
local reference is being made. No matter how phandles are allocated from dtc
the run time loader must apply an offset to each phandle in every dynamic
DT object loaded. The __local_fixups__ node records the offset relative to the
start of every local reference within that property so that the loader can apply
the offset.

View File

@ -37,14 +37,15 @@ The upstream repository is here:
git://git.kernel.org/pub/scm/utils/dtc/dtc.git
https://git.kernel.org/pub/scm/utils/dtc/dtc.git

The gitweb interface for the upstream repository is:
The gitweb interface for the upstream respository is:

https://git.kernel.org/cgit/utils/dtc/dtc.git/

1.1) Submitting Patches

Patches should be sent to the maintainer:
Patches should be sent to the maintainers:
David Gibson <david@gibson.dropbear.id.au>
Jon Loeliger <jdl@jdl.com>
and CCed to <devicetree-compiler@vger.kernel.org>.

2) Description
@ -77,9 +78,6 @@ The currently supported Output Formats are:
then simply be added to your Makefile. Additionally, the
assembly file exports some symbols that can be used.

- "yaml": DT encoded in YAML format. This representation is an
intermediate format used for validation tools.


3) Command Line

@ -121,32 +119,6 @@ Options:
Make space for <number> reserve map entries
Relevant for dtb and asm output only.

-@
Generates a __symbols__ node at the root node. This node contains a
property for each label. The property's name is the label name and the
value is the path of the labeled node.

-L
Possibly generates a __local_fixups__ and a __fixups__ node at the root node.
For each property that contains a phandle reference using a locally
defined phandle, the __local_fixups__ node contains a property (at path
/__local_fixups__/$a if $a is the path of the node). Its value is a list
of offsets that are phandle values. If there are no such properties, no
__local_fixups__ node is generated.
For each undefined label used in at least one reference, the __fixups__
node contains a property. Its name is the label name, its value is a
list of locations where the label is used in a reference in the format
"path:property:offset". If there is no undefined label, no __fixups__
nodes is generated.
Enabled by default for compiling overlays (i.e. dts files with a
/plugin/ tag).

-A
Generate automatically aliases for all node labels. This is similar to
the -@ option (the __symbols__ node contain identical information) but
the semantics are slightly different since no phandles are automatically
generated for labeled nodes.

-S <bytes>
Ensure the blob at least <bytes> long, adding additional
space if needed.
@ -174,18 +146,13 @@ Additionally, dtc performs various sanity checks on the tree.
Here is a very rough overview of the layout of a DTS source file:


sourcefile: versioninfo plugindecl list_of_memreserve devicetree
sourcefile: list_of_memreserve devicetree

memreserve: label 'memreserve' ADDR ADDR ';'
| label 'memreserve' ADDR '-' ADDR ';'

devicetree: '/' nodedef

versioninfo: '/' 'dts-v1' '/' ';'

plugindecl: '/' 'plugin' '/' ';'
| /* empty */

nodedef: '{' list_of_property list_of_subnode '}' ';'

property: label PROPNAME '=' propdata ';'
@ -242,10 +209,10 @@ 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 in turn has a string property
"childnode at address". It it turn has a string property
called "childprop".

childnode@address {
childnode@addresss {
childprop = "hello\n";
};

@ -264,7 +231,7 @@ 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 example, a node is labeled "mpic" and then referenced:
In this exmaple, a node is labled "mpic" and then referenced:

mpic: interrupt-controller@40000 {
...
@ -275,7 +242,7 @@ In this example, a node is labeled "mpic" and then referenced:
...
};

And used in properties, labels may appear before or after any value:
And used in properties, lables may appear before or after any value:

randomnode {
prop: string = data: "mystring\n" data_end: ;
@ -429,7 +396,7 @@ value of r3.
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 information on the required
point (see further chapters for more informations on the required
device-tree contents)

- size_dt_strings
@ -595,7 +562,7 @@ looks like in practice.

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 information at the root, the CPUs, and the
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).
@ -688,86 +655,4 @@ The fdtdump program prints a readable version of a flat device tree file.

The syntax of the fdtdump command line is:

fdtdump [options] <DTB-file-name>

Where options are:
-d,--debug Dump debug information while decoding the file
-s,--scan Scan for an embedded fdt in given file

3) fdtoverlay -- Flat Device Tree overlay applicator

The fdtoverlay applies an arbitrary number of FDT overlays to a base FDT blob
to a given output file.

The syntax of the fdtoverlay command line is:

fdtoverlay -i <base-blob> -o <output-blob> <overlay-blob0> [<overlay-blob1> ...]

Where options are:
-i, --input Input base DT blob
-o, --output Output DT blob
-v, --verbose Verbose message output

4 ) fdtget -- Read properties from device tree

This command can be used to obtain individual values from the device tree in a
nicely formatted way. You can specify multiple nodes to display (when using -p)
or multiple node/property pairs (when not using -p). For the latter, each
property is displayed on its own line, with a space between each cell within
the property.

The syntax of the fdtget command is:

fdtget <options> <dt file> [<node> <property>]...
fdtget -p <options> <dt file> [<node> ]...

where options are:

<type> s=string, i=int, u=unsigned, x=hex, r=raw
Optional modifier prefix:
hh or b=byte, h=2 byte, l=4 byte (default)

Options: -[t:pld:hV]
-t, --type <arg> Type of data
-p, --properties List properties for each node
-l, --list List subnodes for each node
-d, --default <arg> Default value to display when the property is missing
-h, --help Print this help and exit
-V, --version Print version and exit

If -t is not provided, fdtget will try to figure out the type, trying to detect
strings, string lists and the size of each value in the property. This is
similar to how fdtdump works, and uses the same heuristics.


5 ) fdtput - Write properties to a device tree

The syntax of the fdtput command is:

fdtput <options> <dt file> <node> <property> [<value>...]
fdtput -c <options> <dt file> [<node>...]
fdtput -r <options> <dt file> [<node>...]
fdtput -d <options> <dt file> <node> [<property>...]

Options are:

<type> s=string, i=int, u=unsigned, x=hex
Optional modifier prefix:
hh or b=byte, h=2 byte, l=4 byte (default)

-c, --create Create nodes if they don't already exist
-r, --remove Delete nodes (and any subnodes) if they already exist
-d, --delete Delete properties if they already exist
-p, --auto-path Automatically create nodes as needed for the node path
-t, --type <arg> Type of data
-v, --verbose Display each value decoded from command line
-h, --help Print this help and exit
-V, --version Print version and exit

The option determines which usage is selected and therefore the operation that
is performed. The first usage adds or updates properties; the rest are used to
create/delete nodes and delete properties.

For the first usage, the command line arguments are joined together into a
single value which is written to the property. The -t option is required so
that fdtput knows how to decode its arguments.
fdtdump <DTB-file-name>

25
GPL
View File

@ -1,8 +1,8 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991

Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
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.

@ -15,7 +15,7 @@ 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 Lesser General Public License instead.) You can apply it to
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
@ -55,7 +55,7 @@ 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

@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)

These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
@ -168,7 +168,7 @@ access to copy 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
@ -225,7 +225,7 @@ 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
@ -278,7 +278,7 @@ 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
@ -303,9 +303,10 @@ the "copyright" line and a pointer to where the full notice is found.
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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA


Also add information on how to contact you by electronic and paper mail.

@ -335,5 +336,5 @@ necessary. Here is a sample; alter the names:
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 Lesser General
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

187
Makefile
View File

@ -1,45 +1,29 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Device Tree Compiler
#

$(warning WARNING: Building dtc using make is deprecated, in favour of using Meson (https://mesonbuild.com))
$(warning )
$(warning Use `meson setup builddir/ && meson compile -C builddir/` to build, `meson test -C builddir/` to test, or `meson configure` to see build options.)

#
# Version information will be constructed in this order:
# DTC_VERSION release version as MAJOR.MINOR.PATCH
# EXTRAVERSION might be "-rc", for example.
# LOCAL_VERSION is likely from command line.
# CONFIG_LOCALVERSION from some future config system.
#
DTC_VERSION = $(shell cat VERSION.txt)
VERSION = 1
PATCHLEVEL = 4
SUBLEVEL = 1
EXTRAVERSION =
LOCAL_VERSION =
CONFIG_LOCALVERSION =

# Control the assumptions made (e.g. risking security issues) in the code.
# See libfdt_internal.h for details
ASSUME_MASK ?= 0

CPPFLAGS = -I libfdt -I . -DFDT_ASSUME_MASK=$(ASSUME_MASK)
WARNINGS = -Wall -Wpointer-arith -Wcast-qual -Wnested-externs -Wsign-compare \
-Wstrict-prototypes -Wmissing-prototypes -Wredundant-decls -Wshadow \
-Wwrite-strings
ifeq ($(shell $(CC) --version | grep -q gcc && echo gcc),gcc)
WARNINGS += -Wsuggest-attribute=format
endif
CFLAGS = -g -Os $(SHAREDLIB_CFLAGS) -Werror $(WARNINGS) $(EXTRA_CFLAGS)
CPPFLAGS = -I libfdt -I .
WARNINGS = -Werror -Wall -Wpointer-arith -Wcast-qual -Wnested-externs \
-Wstrict-prototypes -Wmissing-prototypes -Wredundant-decls -Wshadow
CFLAGS = -g -Os -fPIC -Werror $(WARNINGS)

BISON = bison
LEX = flex
SWIG = swig
PKG_CONFIG ?= pkg-config

INSTALL = install
INSTALL_PROGRAM = $(INSTALL)
INSTALL_LIB = $(INSTALL)
INSTALL_DATA = $(INSTALL) -m 644
INSTALL_SCRIPT = $(INSTALL)
INSTALL = /usr/bin/install
DESTDIR =
PREFIX = $(HOME)
BINDIR = $(PREFIX)/bin
@ -47,45 +31,14 @@ LIBDIR = $(PREFIX)/lib
INCLUDEDIR = $(PREFIX)/include

HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
sed -e 's/\(cygwin\|msys\).*/\1/')

NO_VALGRIND := $(shell $(PKG_CONFIG) --exists valgrind; echo $$?)
ifeq ($(NO_VALGRIND),1)
CPPFLAGS += -DNO_VALGRIND
else
CFLAGS += $(shell $(PKG_CONFIG) --cflags valgrind)
endif

# libyaml before version 0.2.3 expects non-const string parameters. Supporting
# both variants would require either cpp magic or passing
# -Wno-error=discarded-qualifiers to the compiler. For the sake of simplicity
# just support libyaml >= 0.2.3.
NO_YAML := $(shell $(PKG_CONFIG) --atleast-version 0.2.3 yaml-0.1; echo $$?)
ifeq ($(NO_YAML),1)
CFLAGS += -DNO_YAML
else
LDLIBS_dtc += $(shell $(PKG_CONFIG) --libs yaml-0.1)
CFLAGS += $(shell $(PKG_CONFIG) --cflags yaml-0.1)
endif

HAS_VERSION_SCRIPT := $(shell echo 'int main(){}' | $(CC) -Wl,--version-script=/dev/null -x c - -o /dev/null 2>/dev/null && echo y)
sed -e 's/\(cygwin\).*/cygwin/')

ifeq ($(HOSTOS),darwin)
SHAREDLIB_EXT = dylib
SHAREDLIB_CFLAGS = -fPIC
SHAREDLIB_LDFLAGS = -fPIC -dynamiclib -Wl,-install_name -Wl,
else ifeq ($(HOSTOS),$(filter $(HOSTOS),msys cygwin))
SHAREDLIB_EXT = so
SHAREDLIB_CFLAGS =
SHAREDLIB_LDFLAGS = -shared -Wl,-soname,
SHAREDLIB_EXT=dylib
SHAREDLIB_LINK_OPTIONS=-dynamiclib -Wl,-install_name -Wl,
else
SHAREDLIB_EXT = so
SHAREDLIB_CFLAGS = -fPIC
SHAREDLIB_LDFLAGS = -fPIC -shared -Wl,-soname,
endif

ifeq ($(HAS_VERSION_SCRIPT),y)
SHAREDLIB_LDFLAGS += -Wl,--version-script=$(LIBFDT_version)
SHAREDLIB_EXT=so
SHAREDLIB_LINK_OPTIONS=-shared -Wl,--version-script=$(LIBFDT_version) -Wl,-soname,
endif

#
@ -110,6 +63,7 @@ endif
# Rules for versioning
#

DTC_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
VERSION_FILE = version_gen.h

CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
@ -158,21 +112,18 @@ BIN += dtc
BIN += fdtdump
BIN += fdtget
BIN += fdtput
BIN += fdtoverlay

SCRIPTS = dtdiff

all: $(BIN) libfdt


ifneq ($(DEPTARGETS),)
ifneq ($(MAKECMDGOALS),libfdt)
-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)
-include $(FDTOVERLAY_OBJS:%.o=%.d)
endif
endif


@ -180,35 +131,28 @@ endif
#
# Rules for libfdt
#
LIBFDT_dir = libfdt
LIBFDT_archive = $(LIBFDT_dir)/libfdt.a
LIBFDT_lib = $(LIBFDT_dir)/$(LIBFDT_LIB)
LIBFDT_include = $(addprefix $(LIBFDT_dir)/,$(LIBFDT_INCLUDES))
LIBFDT_version = $(addprefix $(LIBFDT_dir)/,$(LIBFDT_VERSION))
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))

ifeq ($(STATIC_BUILD),1)
CFLAGS += -static
LIBFDT_dep = $(LIBFDT_archive)
else
LIBFDT_dep = $(LIBFDT_lib)
endif

include $(LIBFDT_dir)/Makefile.libfdt
include $(LIBFDT_srcdir)/Makefile.libfdt

.PHONY: libfdt
libfdt: $(LIBFDT_archive) $(LIBFDT_lib)

$(LIBFDT_archive): $(addprefix $(LIBFDT_dir)/,$(LIBFDT_OBJS))
$(LIBFDT_archive): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS))
$(LIBFDT_lib): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS))

$(LIBFDT_lib): $(addprefix $(LIBFDT_dir)/,$(LIBFDT_OBJS)) $(LIBFDT_version)
@$(VECHO) LD $@
$(CC) $(LDFLAGS) $(SHAREDLIB_LDFLAGS)$(LIBFDT_soname) -o $(LIBFDT_lib) \
$(addprefix $(LIBFDT_dir)/,$(LIBFDT_OBJS))
ln -sf $(LIBFDT_LIB) $(LIBFDT_dir)/$(LIBFDT_soname)
ln -sf $(LIBFDT_soname) $(LIBFDT_dir)/$(LIBFDT_so)
libfdt_clean:
@$(VECHO) CLEAN "(libfdt)"
rm -f $(addprefix $(LIBFDT_objdir)/,$(STD_CLEANFILES))
rm -f $(LIBFDT_objdir)/*.so

ifneq ($(DEPTARGETS),)
-include $(LIBFDT_OBJS:%.o=$(LIBFDT_dir)/%.d)
-include $(LIBFDT_OBJS:%.o=$(LIBFDT_objdir)/%.d)
endif

# This stops make from generating the lex and bison output during
@ -219,21 +163,20 @@ endif
install-bin: all $(SCRIPTS)
@$(VECHO) INSTALL-BIN
$(INSTALL) -d $(DESTDIR)$(BINDIR)
$(INSTALL_PROGRAM) $(BIN) $(DESTDIR)$(BINDIR)
$(INSTALL_SCRIPT) $(SCRIPTS) $(DESTDIR)$(BINDIR)
$(INSTALL) $(BIN) $(SCRIPTS) $(DESTDIR)$(BINDIR)

install-lib: libfdt
install-lib: all
@$(VECHO) INSTALL-LIB
$(INSTALL) -d $(DESTDIR)$(LIBDIR)
$(INSTALL_LIB) $(LIBFDT_lib) $(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_DATA) $(LIBFDT_archive) $(DESTDIR)$(LIBDIR)
$(INSTALL) -m 644 $(LIBFDT_archive) $(DESTDIR)$(LIBDIR)

install-includes:
@$(VECHO) INSTALL-INC
$(INSTALL) -d $(DESTDIR)$(INCLUDEDIR)
$(INSTALL_DATA) $(LIBFDT_include) $(DESTDIR)$(INCLUDEDIR)
$(INSTALL) -m 644 $(LIBFDT_include) $(DESTDIR)$(INCLUDEDIR)

install: install-bin install-lib install-includes

@ -249,40 +192,15 @@ convert-dtsv0: $(CONVERT_OBJS)

fdtdump: $(FDTDUMP_OBJS)

fdtget: $(FDTGET_OBJS) $(LIBFDT_dep)
fdtget: $(FDTGET_OBJS) $(LIBFDT_archive)

fdtput: $(FDTPUT_OBJS) $(LIBFDT_dep)

fdtoverlay: $(FDTOVERLAY_OBJS) $(LIBFDT_dep)
fdtput: $(FDTPUT_OBJS) $(LIBFDT_archive)

dist:
git archive --format=tar --prefix=dtc-$(dtc_version)/ HEAD \
> ../dtc-$(dtc_version).tar
cat ../dtc-$(dtc_version).tar | \
gzip -9 > ../dtc-$(dtc_version).tar.gz


#
# Release signing and uploading
# This is for maintainer convenience, don't try this at home.
#
ifeq ($(MAINTAINER),y)
GPG = gpg2
KUP = kup
KUPDIR = /pub/software/utils/dtc

kup: dist
$(GPG) --detach-sign --armor -o ../dtc-$(dtc_version).tar.sign \
../dtc-$(dtc_version).tar
$(KUP) put ../dtc-$(dtc_version).tar.gz ../dtc-$(dtc_version).tar.sign \
$(KUPDIR)/dtc-$(dtc_version).tar.gz
endif

tags: FORCE
rm -f tags
find . \( -name tests -type d -prune \) -o \
\( ! -name '*.tab.[ch]' ! -name '*.lex.c' \
-name '*.[chly]' -type f -print \) | xargs ctags -a
git archive --format=tar --prefix=dtc-v$(dtc_version)/ HEAD \
> ../dtc-v$(dtc_version).tar
cat ../dtc-v$(dtc_version).tar | \
gzip -9 > ../dtc-v$(dtc_version).tgz

#
# Testsuite rules
@ -294,11 +212,8 @@ TESTS_BIN += convert-dtsv0
TESTS_BIN += fdtput
TESTS_BIN += fdtget
TESTS_BIN += fdtdump
TESTS_BIN += fdtoverlay

ifneq ($(MAKECMDGOALS),libfdt)
include tests/Makefile.tests
endif

#
# Clean rules
@ -318,7 +233,7 @@ clean: libfdt_clean tests_clean
#
%: %.o
@$(VECHO) LD $@
$(LINK.c) -o $@ $^ $(LDLIBS_$*)
$(LINK.c) -o $@ $^

%.o: %.c
@$(VECHO) CC $@
@ -326,11 +241,11 @@ clean: libfdt_clean tests_clean

%.o: %.S
@$(VECHO) AS $@
$(CC) $(CPPFLAGS) $(AFLAGS) -o $@ -c $<
$(CC) $(CPPFLAGS) $(AFLAGS) -D__ASSEMBLY__ -o $@ -c $<

%.d: %.c
@$(VECHO) DEP $<
$(CC) $(CPPFLAGS) $(CFLAGS) -MM -MG -MT "$*.o $@" $< > $@
$(CC) $(CPPFLAGS) -MM -MG -MT "$*.o $@" $< > $@

%.d: %.S
@$(VECHO) DEP $<
@ -348,16 +263,16 @@ clean: libfdt_clean tests_clean
@$(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: %.y
%.tab.c %.tab.h %.output: %.y
@$(VECHO) BISON $@
$(BISON) -b $(basename $(basename $@)) -d $<
$(BISON) -d $<

FORCE:

ifeq ($(MAKE_RESTARTS),10)
$(error "Make re-executed itself $(MAKE_RESTARTS) times. Infinite recursion?")
endif

View File

@ -1,4 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# This is not a complete Makefile of itself.
# Instead, it is designed to be easily embeddable

View File

@ -1,4 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# Makefile.dtc
#
# This is not a complete Makefile of itself. Instead, it is designed to
@ -15,9 +14,5 @@ DTC_SRCS = \
treesource.c \
util.c

ifneq ($(NO_YAML),1)
DTC_SRCS += yamltree.c
endif

DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c
DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o)

View File

@ -1,4 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# This is not a complete Makefile of itself. Instead, it is designed to
# be easily embeddable into other systems of Makefiles.
@ -23,9 +22,3 @@ FDTPUT_SRCS = \
util.c

FDTPUT_OBJS = $(FDTPUT_SRCS:%.c=%.o)

FDTOVERLAY_SRCS = \
fdtoverlay.c \
util.c

FDTOVERLAY_OBJS = $(FDTOVERLAY_SRCS:%.c=%.o)

20
README Normal file
View File

@ -0,0 +1,20 @@
The source tree contains the Device Tree Compiler (dtc) toolchain for
working with device tree source and binary files and also libfdt, a
utility library for reading and manipulating the binary format.

DTC and LIBFDT are maintained by:

David Gibson <david@gibson.dropbear.id.au>
Jon Loeliger <jdl@jdl.com>

Mailing list
------------
The following list is for discussion about dtc and libfdt implementation
mailto:devicetree-compiler@vger.kernel.org

Core device tree bindings are discussed on the devicetree-spec list:
mailto:devicetree-spec@vger.kernel.org

Home Page
---------
http://devicetree.org/Device_Tree_Compiler

View File

@ -4,11 +4,11 @@ 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 incorporate or rely on libfdt for its operation, nor vice
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 SPDX license tags in each source file attest, dtc is licensed
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
@ -16,10 +16,10 @@ 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 can
be found are in the file entitled 'BSD-2-Clause'. This is, in
practice, equivalent to being BSD licensed, since the terms of the BSD
license are strictly more permissive than the GPL.
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,
@ -28,12 +28,12 @@ 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 firmware and extended without contributing those extensions
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 thereby is not dire.
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

100
README.md
View File

@ -1,100 +0,0 @@
# Device Tree Compiler and libfdt

The source tree contains the Device Tree Compiler (dtc) toolchain for
working with device tree source and binary files and also libfdt, a
utility library for reading and manipulating the binary format.

dtc and libfdt are maintained by:

* [David Gibson `<david@gibson.dropbear.id.au>`](mailto:david@gibson.dropbear.id.au)

## Python library

A Python library wrapping libfdt is also available. To build this you
will need to install `swig` and Python development files. On Debian
distributions:

```
$ sudo apt-get install swig python3-dev
```

The library provides an `Fdt` class which you can use like this:

```
$ PYTHONPATH=../pylibfdt python3
>>> import libfdt
>>> fdt = libfdt.Fdt(open('test_tree1.dtb', mode='rb').read())
>>> node = fdt.path_offset('/subnode@1')
>>> print(node)
124
>>> prop_offset = fdt.first_property_offset(node)
>>> prop = fdt.get_property_by_offset(prop_offset)
>>> print('%s=%s' % (prop.name, prop.as_str()))
compatible=subnode1
>>> node2 = fdt.path_offset('/')
>>> print(fdt.getprop(node2, 'compatible').as_str())
test_tree1
```

You will find tests in `tests/pylibfdt_tests.py` showing how to use each
method. Help is available using the Python help command, e.g.:

```
$ cd pylibfdt
$ python3 -c "import libfdt; help(libfdt)"
```

If you add new features, please check code coverage:

```
$ sudo apt-get install python3-coverage
$ cd tests
# It's just 'coverage' on most other distributions
$ python3-coverage run pylibfdt_tests.py
$ python3-coverage html
# Open 'htmlcov/index.html' in your browser
```

The library can be installed with pip from a local source tree:

```
$ pip install . [--user|--prefix=/path/to/install_dir]
```

Or directly from a remote git repo:

```
$ pip install git+git://git.kernel.org/pub/scm/utils/dtc/dtc.git@main
```

The install depends on libfdt shared library being installed on the
host system first. Generally, using `--user` or `--prefix` is not
necessary and pip will use the default location for the Python
installation which varies if the user is root or not.

You can also install everything via make if you like, but pip is
recommended.

To install both libfdt and pylibfdt you can use:

```
$ make install [PREFIX=/path/to/install_dir]
```

To disable building the python library, even if swig and Python are available,
use:

```
$ make NO_PYTHON=1
```

More work remains to support all of libfdt, including access to numeric
values.

## Mailing lists

* The [devicetree-compiler](mailto:devicetree-compiler@vger.kernel.org)
list is for discussion about dtc and libfdt implementation.
* Core device tree bindings are discussed on the
[devicetree-spec](mailto:devicetree-spec@vger.kernel.org) list.

View File

@ -1 +0,0 @@
1.7.2

1761
checks.c

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005, 2008.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/

%option noyywrap nounput noinput never-interactive
@ -35,7 +49,7 @@ static int saw_hyphen; /* = 0 */
static unsigned long long last_val;
static char *last_name; /* = NULL */

static const struct {
const struct {
const char *pattern;
int obase, width;
} guess_table[] = {
@ -94,7 +108,7 @@ static const struct {
<INITIAL>[0-9a-fA-F]+ {
unsigned long long val;
int obase = 16, width = 0;
unsigned int i;
int i;

val = strtoull(yytext, NULL, cbase);

@ -209,8 +223,6 @@ static void convert_file(const char *fname)

while(yylex())
;

free(newname);
}

int main(int argc, char *argv[])

90
data.c
View File

@ -1,6 +1,21 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/

#include "dtc.h"
@ -21,10 +36,10 @@ void data_free(struct data d)
free(d.val);
}

struct data data_grow_for(struct data d, unsigned int xlen)
struct data data_grow_for(struct data d, int xlen)
{
struct data nd;
unsigned int newsize;
int newsize;

if (xlen == 0)
return d;
@ -59,8 +74,7 @@ struct data data_copy_escape_string(const char *s, int len)
struct data d;
char *q;

d = data_add_marker(empty_data, TYPE_STRING, NULL);
d = data_grow_for(d, len + 1);
d = data_grow_for(empty_data, len + 1);

q = d.val;
while (i < len) {
@ -80,11 +94,10 @@ struct data data_copy_file(FILE *f, size_t maxlen)
{
struct data d = empty_data;

d = data_add_marker(d, TYPE_NONE, NULL);
while (!feof(f) && (d.len < maxlen)) {
size_t chunksize, ret;

if (maxlen == (size_t)-1)
if (maxlen == -1)
chunksize = 4096;
else
chunksize = maxlen - d.len;
@ -158,9 +171,9 @@ struct data data_merge(struct data d1, struct data d2)
struct data data_append_integer(struct data d, uint64_t value, int bits)
{
uint8_t value_8;
fdt16_t value_16;
fdt32_t value_32;
fdt64_t value_64;
uint16_t value_16;
uint32_t value_32;
uint64_t value_64;

switch (bits) {
case 8:
@ -184,14 +197,14 @@ struct data data_append_integer(struct data d, uint64_t value, int bits)
}
}

struct data data_append_re(struct data d, uint64_t address, uint64_t size)
struct data data_append_re(struct data d, const struct fdt_reserve_entry *re)
{
struct fdt_reserve_entry re;
struct fdt_reserve_entry bere;

re.address = cpu_to_fdt64(address);
re.size = cpu_to_fdt64(size);
bere.address = cpu_to_fdt64(re->address);
bere.size = cpu_to_fdt64(re->size);

return data_append_data(d, &re, sizeof(re));
return data_append_data(d, &bere, sizeof(bere));
}

struct data data_append_cell(struct data d, cell_t word)
@ -228,7 +241,11 @@ struct data data_add_marker(struct data d, enum markertype type, char *ref)
{
struct marker *m;

m = alloc_marker(d.len, type, ref);
m = xmalloc(sizeof(*m));
m->offset = d.len;
m->type = type;
m->ref = ref;
m->next = NULL;

return data_append_markers(d, m);
}
@ -250,44 +267,3 @@ bool data_is_one_string(struct data d)

return true;
}

struct data data_insert_data(struct data d, struct marker *m, struct data old)
{
unsigned int offset = m->offset;
struct marker *next = m->next;
struct marker *marker;
struct data new_data;
char *ref;

new_data = data_insert_at_marker(d, m, old.val, old.len);

/* Copy all markers from old value */
marker = old.markers;
for_each_marker(marker) {
ref = NULL;

if (marker->ref)
ref = xstrdup(marker->ref);

m->next = alloc_marker(marker->offset + offset, marker->type,
ref);
m = m->next;
}
m->next = next;

return new_data;
}

struct marker *alloc_marker(unsigned int offset, enum markertype type,
char *ref)
{
struct marker *m;

m = xmalloc(sizeof(*m));
m->offset = offset;
m->type = type;
m->ref = ref;
m->next = NULL;

return m;
}

View File

@ -1,6 +1,21 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/

%option noyywrap nounput noinput never-interactive
@ -23,6 +38,7 @@ LINECOMMENT "//".*\n
#include "srcpos.h"
#include "dtc-parser.tab.h"

YYLTYPE yylloc;
extern bool treesource_error;

/* CAUTION: this will stop working if we ever use yyless() or yyunput() */
@ -46,8 +62,7 @@ static int dts_version = 1;

static void push_input_file(const char *filename);
static bool pop_input_file(void);
static void PRINTF(1, 2) lexical_error(const char *fmt, ...);

static void lexical_error(const char *fmt, ...);
%}

%%
@ -57,33 +72,25 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
push_input_file(name);
}

<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)* {
char *line, *fnstart, *fnend;
struct data fn;
<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)? {
char *line, *tmp, *fn;
/* skip text before line # */
line = yytext;
while (!isdigit((unsigned char)*line))
line++;

/* regexp ensures that first and list "
* in the whole yytext are those at
* beginning and end of the filename string */
fnstart = memchr(yytext, '"', yyleng);
for (fnend = yytext + yyleng - 1;
*fnend != '"'; fnend--)
;
assert(fnstart && fnend && (fnend > fnstart));

fn = data_copy_escape_string(fnstart + 1,
fnend - fnstart - 1);

/* Don't allow nuls in filenames */
if (memchr(fn.val, '\0', fn.len - 1))
lexical_error("nul in line number directive");

/* skip digits in line # */
tmp = line;
while (!isspace((unsigned char)*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.val), atoi(line) - 1);
data_free(fn);
srcpos_set_line(xstrdup(fn), atoi(line) - 1);
}

<*><<EOF>> {
@ -106,11 +113,6 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
return DT_V1;
}

<*>"/plugin/" {
DPRINT("Keyword: /plugin/\n");
return DT_PLUGIN;
}

<*>"/memreserve/" {
DPRINT("Keyword: /memreserve/\n");
BEGIN_DEFAULT();
@ -137,13 +139,6 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
return DT_DEL_NODE;
}

<*>"/omit-if-no-ref/" {
DPRINT("Keyword: /omit-if-no-ref/\n");
DPRINT("<PROPNODENAME>\n");
BEGIN(PROPNODENAME);
return DT_OMIT_NO_REF;
}

<*>{LABEL}: {
DPRINT("Label: %s\n", yytext);
yylval.labelref = xstrdup(yytext);
@ -151,21 +146,6 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
return DT_LABEL;
}

<V1>{LABEL} {
/* Missed includes or macro definitions while
* preprocessing can lead to unexpected identifiers in
* the input. Report a slightly more informative error
* in this case */

lexical_error("Unexpected '%s'", yytext);

/* Treat it as a literal which often generates further
* useful error messages */

yylval.integer = 0;
return DT_LITERAL;
}

<V1>([0-9]+|0[xX][0-9a-fA-F]+)(U|L|UL|LL|ULL)? {
char *e;
DPRINT("Integer Literal: '%s'\n", yytext);
@ -173,10 +153,7 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
errno = 0;
yylval.integer = strtoull(yytext, &e, 0);

if (*e && e[strspn(e, "UL")]) {
lexical_error("Bad integer literal '%s'",
yytext);
}
assert(!(*e) || !e[strspn(e, "UL")]);

if (errno == ERANGE)
lexical_error("Integer literal '%s' out of range",
@ -196,30 +173,30 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
if (d.len == 1) {
lexical_error("Empty character literal");
yylval.integer = 0;
} else {
return DT_CHAR_LITERAL;
}

yylval.integer = (unsigned char)d.val[0];

if (d.len > 2)
lexical_error("Character literal has %d"
" characters instead of 1",
d.len - 1);
}

data_free(d);
return DT_CHAR_LITERAL;
}

<*>\&{LABEL} { /* label reference */
DPRINT("Ref: %s\n", yytext+1);
yylval.labelref = xstrdup(yytext+1);
return DT_LABEL_REF;
return DT_REF;
}

<*>"&{"{PATHCHAR}*\} { /* new-style path reference */
<*>"&{/"{PATHCHAR}*\} { /* new-style path reference */
yytext[yyleng-1] = '\0';
DPRINT("Ref: %s\n", yytext+2);
yylval.labelref = xstrdup(yytext+2);
return DT_PATH_REF;
return DT_REF;
}

<BYTESTRING>[0-9a-fA-F]{2} {

View File

@ -1,12 +1,24 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
%locations

%{
#include <stdio.h>
#include <inttypes.h>

#include "dtc.h"
#include "srcpos.h"
@ -19,16 +31,8 @@ extern void yyerror(char const *s);
treesource_error = true; \
} while (0)

#define YYERROR_CALL(msg) yyerror(msg)

extern struct dt_info *parser_output;
extern struct boot_info *the_boot_info;
extern bool treesource_error;

static bool is_ref_relative(const char *ref)
{
return ref[0] != '/' && strchr(&ref[1], '/');
}

%}

%union {
@ -48,38 +52,31 @@ static bool is_ref_relative(const char *ref)
struct node *nodelist;
struct reserve_info *re;
uint64_t integer;
unsigned int flags;
}

%token DT_V1
%token DT_PLUGIN
%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 DT_OMIT_NO_REF
%token <propnodename> DT_PROPNODENAME
%token <integer> DT_LITERAL
%token <integer> DT_CHAR_LITERAL
%token <byte> DT_BYTE
%token <data> DT_STRING
%token <labelref> DT_LABEL
%token <labelref> DT_LABEL_REF
%token <labelref> DT_PATH_REF
%token <labelref> DT_REF
%token DT_INCBIN

%type <data> propdata
%type <data> propdataprefix
%type <flags> header
%type <flags> headers
%type <re> memreserve
%type <re> memreserves
%type <array> arrayprefix
%type <data> bytestring
%type <prop> propdef
%type <proplist> proplist
%type <labelref> dt_ref

%type <node> devicetree
%type <node> nodedef
@ -104,31 +101,10 @@ static bool is_ref_relative(const char *ref)
%%

sourcefile:
headers memreserves devicetree
DT_V1 ';' memreserves devicetree
{
parser_output = build_dt_info($1, $2, $3,
guess_boot_cpuid($3));
}
;

header:
DT_V1 ';'
{
$$ = DTSF_V1;
}
| DT_V1 ';' DT_PLUGIN ';'
{
$$ = DTSF_V1 | DTSF_PLUGIN;
}
;

headers:
header
| header headers
{
if ($2 != $1)
ERROR(&@2, "Header flags don't match earlier ones");
$$ = $1;
the_boot_info = build_boot_info($3, $4,
guess_boot_cpuid($4));
}
;

@ -155,8 +131,6 @@ memreserve:
}
;

dt_ref: DT_LABEL_REF | DT_PATH_REF;

devicetree:
'/' nodedef
{
@ -166,77 +140,17 @@ devicetree:
{
$$ = merge_nodes($1, $3);
}
| dt_ref nodedef
| devicetree DT_REF nodedef
{
/*
* We rely on the rule being always:
* versioninfo plugindecl memreserves devicetree
* so $-1 is what we want (plugindecl)
*/
if (!($<flags>-1 & DTSF_PLUGIN))
ERROR(&@2, "Label or path %s not found", $1);
else if (is_ref_relative($1))
ERROR(&@2, "Label-relative reference %s not supported in plugin", $1);
$$ = add_orphan_node(
name_node(build_node(NULL, NULL, NULL),
""),
$2, $1);
}
| devicetree DT_LABEL dt_ref nodedef
{
struct node *target = get_node_by_ref($1, $3);

if (($<flags>-1 & DTSF_PLUGIN) && is_ref_relative($3))
ERROR(&@2, "Label-relative reference %s not supported in plugin", $3);

if (target) {
add_label(&target->labels, $2);
merge_nodes(target, $4);
} else
ERROR(&@3, "Label or path %s not found", $3);
$$ = $1;
}
| devicetree DT_PATH_REF nodedef
{
/*
* We rely on the rule being always:
* versioninfo plugindecl memreserves devicetree
* so $-1 is what we want (plugindecl)
*/
if ($<flags>-1 & DTSF_PLUGIN) {
if (is_ref_relative($2))
ERROR(&@2, "Label-relative reference %s not supported in plugin", $2);
add_orphan_node($1, $3, $2);
} else {
struct node *target = get_node_by_ref($1, $2);

if (target)
merge_nodes(target, $3);
else
ERROR(&@2, "Label or path %s not found", $2);
}
$$ = $1;
}
| devicetree DT_LABEL_REF nodedef
{
struct node *target = get_node_by_ref($1, $2);

if (target) {
merge_nodes(target, $3);
} else {
/*
* We rely on the rule being always:
* versioninfo plugindecl memreserves devicetree
* so $-1 is what we want (plugindecl)
*/
if ($<flags>-1 & DTSF_PLUGIN)
add_orphan_node($1, $3, $2);
else
ERROR(&@2, "Label or path %s not found", $2);
}
$$ = $1;
}
| devicetree DT_DEL_NODE dt_ref ';'
| devicetree DT_DEL_NODE DT_REF ';'
{
struct node *target = get_node_by_ref($1, $3);

@ -246,18 +160,6 @@ devicetree:
ERROR(&@3, "Label or path %s not found", $3);


$$ = $1;
}
| devicetree DT_OMIT_NO_REF dt_ref ';'
{
struct node *target = get_node_by_ref($1, $3);

if (target)
omit_node_if_unused(target);
else
ERROR(&@3, "Label or path %s not found", $3);


$$ = $1;
}
;
@ -265,7 +167,7 @@ devicetree:
nodedef:
'{' proplist subnodes '}' ';'
{
$$ = build_node($2, $3, &@$);
$$ = build_node($2, $3);
}
;

@ -283,18 +185,15 @@ proplist:
propdef:
DT_PROPNODENAME '=' propdata ';'
{
$$ = build_property($1, $3, &@$);
free($1);
$$ = build_property($1, $3);
}
| DT_PROPNODENAME ';'
{
$$ = build_property($1, empty_data, &@$);
free($1);
$$ = build_property($1, empty_data);
}
| DT_DEL_PROP DT_PROPNODENAME ';'
{
$$ = build_property_delete($2);
free($2);
}
| DT_LABEL propdef
{
@ -316,9 +215,8 @@ propdata:
{
$$ = data_merge($1, $3);
}
| propdataprefix dt_ref
| propdataprefix DT_REF
{
$1 = data_add_marker($1, TYPE_STRING, $2);
$$ = data_add_marker($1, REF_PATH, $2);
}
| propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
@ -372,27 +270,22 @@ arrayprefix:
DT_BITS DT_LITERAL '<'
{
unsigned long long bits;
enum markertype type = TYPE_UINT32;

bits = $2;

switch (bits) {
case 8: type = TYPE_UINT8; break;
case 16: type = TYPE_UINT16; break;
case 32: type = TYPE_UINT32; break;
case 64: type = TYPE_UINT64; break;
default:
if ((bits != 8) && (bits != 16) &&
(bits != 32) && (bits != 64)) {
ERROR(&@2, "Array elements must be"
" 8, 16, 32 or 64-bits");
bits = 32;
}

$$.data = data_add_marker(empty_data, type, NULL);
$$.data = empty_data;
$$.bits = bits;
}
| '<'
{
$$.data = data_add_marker(empty_data, TYPE_UINT32, NULL);
$$.data = empty_data;
$$.bits = 32;
}
| arrayprefix integer_prim
@ -407,19 +300,14 @@ arrayprefix:
* within the mask to one (i.e. | in the
* mask), all bits are one.
*/
if (($2 > mask) && (($2 | mask) != -1ULL)) {
char *loc = srcpos_string(&@2);
fprintf(stderr,
"WARNING: %s: Value 0x%016" PRIx64
" truncated to 0x%0*" PRIx64 "\n",
loc, $2, $1.bits / 4, ($2 & mask));
free(loc);
}
if (($2 > mask) && (($2 | mask) != -1ULL))
ERROR(&@2, "Value out of range for"
" %d-bit array element", $1.bits);
}

$$.data = data_append_integer($1.data, $2, $1.bits);
}
| arrayprefix dt_ref
| arrayprefix DT_REF
{
uint64_t val = ~0ULL >> (64 - $1.bits);

@ -497,8 +385,8 @@ integer_rela:
;

integer_shift:
integer_shift DT_LSHIFT integer_add { $$ = ($3 < 64) ? ($1 << $3) : 0; }
| integer_shift DT_RSHIFT integer_add { $$ = ($3 < 64) ? ($1 >> $3) : 0; }
integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; }
| integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; }
| integer_add
;

@ -510,24 +398,8 @@ integer_add:

integer_mul:
integer_mul '*' integer_unary { $$ = $1 * $3; }
| integer_mul '/' integer_unary
{
if ($3 != 0) {
$$ = $1 / $3;
} else {
ERROR(&@$, "Division by zero");
$$ = 0;
}
}
| integer_mul '%' integer_unary
{
if ($3 != 0) {
$$ = $1 % $3;
} else {
ERROR(&@$, "Division by zero");
$$ = 0;
}
}
| integer_mul '/' integer_unary { $$ = $1 / $3; }
| integer_mul '%' integer_unary { $$ = $1 % $3; }
| integer_unary
;

@ -541,7 +413,7 @@ integer_unary:
bytestring:
/* empty */
{
$$ = data_add_marker(empty_data, TYPE_UINT8, NULL);
$$ = empty_data;
}
| bytestring DT_BYTE
{
@ -573,16 +445,10 @@ subnode:
DT_PROPNODENAME nodedef
{
$$ = name_node($2, $1);
free($1);
}
| DT_DEL_NODE DT_PROPNODENAME ';'
{
$$ = name_node(build_node_delete(&@$), $2);
free($2);
}
| DT_OMIT_NO_REF subnode
{
$$ = omit_node_if_unused($2);
$$ = name_node(build_node_delete(), $2);
}
| DT_LABEL subnode
{

193
dtc.c
View File

@ -1,10 +1,23 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/

#include <sys/stat.h>

#include "dtc.h"
#include "srcpos.h"

@ -12,21 +25,10 @@
* Command line options
*/
int quiet; /* Level of quietness */
unsigned int reservenum;/* Number of memory reservation slots */
int reservenum; /* Number of memory reservation slots */
int minsize; /* Minimum blob size */
int padsize; /* Additional padding to blob */
int alignsize; /* Additional padding to blob according to the alignsize */
int phandle_format = PHANDLE_EPAPR; /* Use linux,phandle or phandle properties */
int generate_symbols; /* enable symbols & fixup support */
int generate_fixups; /* suppress generation of fixups on symbol support */
int auto_label_aliases; /* auto generate labels -> aliases */
int annotate; /* Level of annotation: 1 for input source location
>1 for full input source location. */

static int is_power_of_2(int x)
{
return (x > 0) && ((x & (x - 1)) == 0);
}
int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */

static void fill_fullpaths(struct node *tree, const char *prefix)
{
@ -46,8 +48,10 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
}

/* Usage related data. */
#define FDT_VERSION(version) _FDT_VERSION(version)
#define _FDT_VERSION(version) #version
static const char usage_synopsis[] = "dtc [options] <input file>";
static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@LAThv";
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'},
@ -58,7 +62,6 @@ static struct option const usage_long_opts[] = {
{"reserve", a_argument, NULL, 'R'},
{"space", a_argument, NULL, 'S'},
{"pad", a_argument, NULL, 'p'},
{"align", a_argument, NULL, 'a'},
{"boot-cpu", a_argument, NULL, 'b'},
{"force", no_argument, NULL, 'f'},
{"include", a_argument, NULL, 'i'},
@ -66,10 +69,6 @@ static struct option const usage_long_opts[] = {
{"phandle", a_argument, NULL, 'H'},
{"warning", a_argument, NULL, 'W'},
{"error", a_argument, NULL, 'E'},
{"symbols", no_argument, NULL, '@'},
{"local-fixups", no_argument, NULL, 'L'},
{"auto-alias", no_argument, NULL, 'A'},
{"annotate", no_argument, NULL, 'T'},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'v'},
{NULL, no_argument, NULL, 0x0},
@ -84,16 +83,12 @@ static const char * const usage_opts_help[] = {
"\n\tOutput formats are:\n"
"\t\tdts - device tree source text\n"
"\t\tdtb - device tree blob\n"
#ifndef NO_YAML
"\t\tyaml - device tree encoded as YAML\n"
#endif
"\t\tasm - assembler source",
"\n\tBlob version to produce, defaults to "stringify(DEFAULT_FDT_VERSION)" (for dtb and asm output)",
"\n\tBlob version to produce, defaults to "FDT_VERSION(DEFAULT_FDT_VERSION)" (for dtb and asm output)",
"\n\tOutput dependency file",
"\n\tMake space for <number> reserve map entries (for dtb and asm output)",
"\n\tMake the blob at least <bytes> long (extra space)",
"\n\tAdd padding to the blob of <bytes> long (extra space)",
"\n\tMake the blob align to the <bytes> (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",
@ -104,68 +99,16 @@ static const char * const usage_opts_help[] = {
"\t\tboth - Both \"linux,phandle\" and \"phandle\" properties",
"\n\tEnable/disable warnings (prefix with \"no-\")",
"\n\tEnable/disable errors (prefix with \"no-\")",
"\n\tEnable generation of symbols",
"\n\tPossibly generates a __local_fixups__ and a __fixups__ node at the root node",
"\n\tEnable auto-alias of labels",
"\n\tAnnotate output .dts with input source file and line (-T -T for more details)",
"\n\tPrint this help and exit",
"\n\tPrint version and exit",
NULL,
};

static const char *guess_type_by_name(const char *fname, const char *fallback)
{
const char *s;

s = strrchr(fname, '.');
if (s == NULL)
return fallback;
if (!strcasecmp(s, ".dts"))
return "dts";
if (!strcasecmp(s, ".yaml"))
return "yaml";
if (!strcasecmp(s, ".dtbo"))
return "dtb";
if (!strcasecmp(s, ".dtb"))
return "dtb";
return fallback;
}

static const char *guess_input_format(const char *fname, const char *fallback)
{
struct stat statbuf;
fdt32_t magic;
FILE *f;

if (stat(fname, &statbuf) != 0)
return fallback;

if (S_ISDIR(statbuf.st_mode))
return "fs";

if (!S_ISREG(statbuf.st_mode))
return fallback;

f = fopen(fname, "r");
if (f == NULL)
return fallback;
if (fread(&magic, 4, 1, f) != 1) {
fclose(f);
return fallback;
}
fclose(f);

if (fdt32_to_cpu(magic) == FDT_MAGIC)
return "dtb";

return guess_type_by_name(fname, fallback);
}

int main(int argc, char *argv[])
{
struct dt_info *dti;
const char *inform = NULL;
const char *outform = NULL;
struct boot_info *bi;
const char *inform = "dts";
const char *outform = "dts";
const char *outname = "-";
const char *depname = NULL;
bool force = false, sort = false;
@ -179,7 +122,6 @@ int main(int argc, char *argv[])
reservenum = 0;
minsize = 0;
padsize = 0;
alignsize = 0;

while ((opt = util_getopt_long()) != EOF) {
switch (opt) {
@ -199,7 +141,7 @@ int main(int argc, char *argv[])
depname = optarg;
break;
case 'R':
reservenum = strtoul(optarg, NULL, 0);
reservenum = strtol(optarg, NULL, 0);
break;
case 'S':
minsize = strtol(optarg, NULL, 0);
@ -207,12 +149,6 @@ int main(int argc, char *argv[])
case 'p':
padsize = strtol(optarg, NULL, 0);
break;
case 'a':
alignsize = strtol(optarg, NULL, 0);
if (!is_power_of_2(alignsize))
die("Invalid argument \"%d\" to -a option\n",
alignsize);
break;
case 'f':
force = true;
break;
@ -251,21 +187,6 @@ int main(int argc, char *argv[])
parse_checks_option(false, true, optarg);
break;

case '@':
generate_symbols = 1;
break;

case 'L':
generate_fixups = 1;
break;

case 'A':
auto_label_aliases = 1;
break;
case 'T':
annotate++;
break;

case 'h':
usage(NULL);
default:
@ -289,65 +210,31 @@ int main(int argc, char *argv[])
if (!depfile)
die("Couldn't open dependency file %s: %s\n", depname,
strerror(errno));

fprint_path_escaped(depfile, outname);
fputc(':', depfile);
fprintf(depfile, "%s:", outname);
}

if (inform == NULL)
inform = guess_input_format(arg, "dts");
if (outform == NULL) {
outform = guess_type_by_name(outname, NULL);
if (outform == NULL) {
if (streq(inform, "dts"))
outform = "dtb";
else
outform = "dts";
}
}
if (annotate && (!streq(inform, "dts") || !streq(outform, "dts")))
die("--annotate requires -I dts -O dts\n");
if (streq(inform, "dts"))
dti = dt_from_source(arg);
bi = dt_from_source(arg);
else if (streq(inform, "fs"))
dti = dt_from_fs(arg);
bi = dt_from_fs(arg);
else if(streq(inform, "dtb"))
dti = dt_from_blob(arg);
bi = dt_from_blob(arg);
else
die("Unknown input format \"%s\"\n", inform);

dti->outname = outname;

if (depfile) {
fputc('\n', depfile);
fclose(depfile);
}

if (cmdline_boot_cpuid != -1)
dti->boot_cpuid_phys = cmdline_boot_cpuid;
bi->boot_cpuid_phys = cmdline_boot_cpuid;

fill_fullpaths(dti->dt, "");

/* on a plugin, generate by default */
if (dti->dtsflags & DTSF_PLUGIN) {
generate_fixups = 1;
}

process_checks(force, dti);

if (auto_label_aliases)
generate_label_tree(dti, "aliases", false);

if (generate_symbols)
generate_label_tree(dti, "__symbols__", true);

if (generate_fixups) {
generate_fixups_tree(dti, "__fixups__");
generate_local_fixups_tree(dti, "__local_fixups__");
}
fill_fullpaths(bi->dt, "");
process_checks(force, bi);

if (sort)
sort_tree(dti);
sort_tree(bi);

if (streq(outname, "-")) {
outf = stdout;
@ -359,17 +246,11 @@ int main(int argc, char *argv[])
}

if (streq(outform, "dts")) {
dt_to_source(outf, dti);
#ifndef NO_YAML
} else if (streq(outform, "yaml")) {
if (!streq(inform, "dts"))
die("YAML output format requires dts input format\n");
dt_to_yaml(outf, dti);
#endif
dt_to_source(outf, bi);
} else if (streq(outform, "dtb")) {
dt_to_blob(outf, dti, outversion);
dt_to_blob(outf, bi, outversion);
} else if (streq(outform, "asm")) {
dt_to_asm(outf, dti, outversion);
dt_to_asm(outf, bi, outversion);
} else if (streq(outform, "null")) {
/* do nothing */
} else {

188
dtc.h
View File

@ -1,9 +1,24 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef DTC_H
#define DTC_H
#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>
@ -16,7 +31,6 @@
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
#include <inttypes.h>

#include <libfdt_env.h>
#include <fdt.h>
@ -29,21 +43,17 @@
#define debug(...)
#endif


#define DEFAULT_FDT_VERSION 17

/*
* Command line options
*/
extern int quiet; /* Level of quietness */
extern unsigned int reservenum; /* Number of memory reservation slots */
extern int reservenum; /* Number of memory reservation slots */
extern int minsize; /* Minimum blob size */
extern int padsize; /* Additional padding to blob */
extern int alignsize; /* Additional padding to blob according to the alignsize */
extern int phandle_format; /* Use linux,phandle or phandle properties */
extern int generate_symbols; /* generate symbols for nodes with labels */
extern int generate_fixups; /* generate fixups */
extern int auto_label_aliases; /* auto generate labels -> aliases */
extern int annotate; /* annotate .dts with input source location */

#define PHANDLE_LEGACY 0x1
#define PHANDLE_EPAPR 0x2
@ -51,88 +61,28 @@ extern int annotate; /* annotate .dts with input source location */

typedef uint32_t cell_t;

static inline bool phandle_is_valid(cell_t phandle)
{
return phandle != 0 && phandle != ~0U;
}

static inline uint16_t dtb_ld16(const void *p)
{
const uint8_t *bp = (const uint8_t *)p;

return ((uint16_t)bp[0] << 8)
| bp[1];
}

static inline uint32_t dtb_ld32(const void *p)
{
const uint8_t *bp = (const uint8_t *)p;

return ((uint32_t)bp[0] << 24)
| ((uint32_t)bp[1] << 16)
| ((uint32_t)bp[2] << 8)
| bp[3];
}

static inline uint64_t dtb_ld64(const void *p)
{
const uint8_t *bp = (const uint8_t *)p;

return ((uint64_t)bp[0] << 56)
| ((uint64_t)bp[1] << 48)
| ((uint64_t)bp[2] << 40)
| ((uint64_t)bp[3] << 32)
| ((uint64_t)bp[4] << 24)
| ((uint64_t)bp[5] << 16)
| ((uint64_t)bp[6] << 8)
| bp[7];
}

#define streq(a, b) (strcmp((a), (b)) == 0)
#define strstarts(s, prefix) (strncmp((s), (prefix), strlen(prefix)) == 0)
#define strprefixeq(a, n, b) (strlen(b) == (n) && (memcmp(a, b, n) == 0))
static inline bool strends(const char *str, const char *suffix)
{
unsigned int len, suffix_len;

len = strlen(str);
suffix_len = strlen(suffix);
if (len < suffix_len)
return false;
return streq(str + len - suffix_len, suffix);
}
#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)

#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))

/* Data blobs */
enum markertype {
TYPE_NONE,
REF_PHANDLE,
REF_PATH,
LABEL,
TYPE_UINT8,
TYPE_UINT16,
TYPE_UINT32,
TYPE_UINT64,
TYPE_STRING,
};

static inline bool is_type_marker(enum markertype type)
{
return type >= TYPE_UINT8;
}

extern const char *markername(enum markertype markertype);

struct marker {
enum markertype type;
unsigned int offset;
int offset;
char *ref;
struct marker *next;
};

struct data {
unsigned int len;
int len;
char *val;
struct marker *markers;
};
@ -146,26 +96,9 @@ struct data {
for_each_marker(m) \
if ((m)->type == (t))

static inline struct marker *next_type_marker(struct marker *m)
{
for_each_marker(m)
if (is_type_marker(m->type))
break;
return m;
}

static inline size_t type_marker_length(struct marker *m)
{
struct marker *next = next_type_marker(m->next);

if (next)
return next->offset - m->offset;
return 0;
}

void data_free(struct data d);

struct data data_grow_for(struct data d, unsigned int xlen);
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);
@ -177,15 +110,12 @@ struct data data_insert_at_marker(struct data d, struct marker *m,
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, uint64_t address, uint64_t size);
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_insert_data(struct data d, struct marker *m, struct data old);

struct marker *alloc_marker(unsigned int offset, enum markertype type,
char *ref);
struct data data_add_marker(struct data d, enum markertype type, char *ref);

bool data_is_one_string(struct data d);
@ -202,10 +132,6 @@ struct label {
struct label *next;
};

struct bus_type {
const char *name;
};

struct property {
bool deleted;
char *name;
@ -214,7 +140,6 @@ struct property {
struct property *next;

struct label *labels;
struct srcpos *srcpos;
};

struct node {
@ -233,10 +158,6 @@ struct node {
int addr_cells, size_cells;

struct label *labels;
const struct bus_type *bus;
struct srcpos *srcpos;

bool omit_if_unused, is_referenced;
};

#define for_each_label_withdel(l0, l) \
@ -263,21 +184,16 @@ struct node {
void add_label(struct label **labels, char *label);
void delete_labels(struct label **labels);

struct property *build_property(const char *name, struct data val,
struct srcpos *srcpos);
struct property *build_property_delete(const char *name);
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 srcpos *srcpos);
struct node *build_node_delete(struct srcpos *srcpos);
struct node *name_node(struct node *node, const char *name);
struct node *omit_node_if_unused(struct node *node);
struct node *reference_node(struct node *node);
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);
struct node *add_orphan_node(struct node *old_node, struct node *new_node, char *ref);

void add_property(struct node *node, struct property *prop);
void delete_property_by_name(struct node *node, char *name);
@ -285,14 +201,10 @@ 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);
void append_to_property(struct node *node,
char *name, const void *data, int len,
enum markertype type);

const char *get_unitname(struct node *node);
struct property *get_property(struct node *node, const char *propname);
cell_t propval_cell(struct property *prop);
cell_t propval_cell_n(struct property *prop, unsigned int n);
struct property *get_property_by_label(struct node *tree, const char *label,
struct node **node);
struct marker *get_marker_label(struct node *tree, const char *label,
@ -309,7 +221,7 @@ uint32_t guess_boot_cpuid(struct node *tree);
/* Boot info (tree plus memreserve information */

struct reserve_info {
uint64_t address, size;
struct fdt_reserve_entry re;

struct reserve_info *next;

@ -323,49 +235,35 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
struct reserve_info *new);


struct dt_info {
unsigned int dtsflags;
struct boot_info {
struct reserve_info *reservelist;
uint32_t boot_cpuid_phys;
struct node *dt; /* the device tree */
const char *outname; /* filename being written to, "-" for stdout */
uint32_t boot_cpuid_phys;
};

/* DTS version flags definitions */
#define DTSF_V1 0x0001 /* /dts-v1/ */
#define DTSF_PLUGIN 0x0002 /* /plugin/ */

struct dt_info *build_dt_info(unsigned int dtsflags,
struct reserve_info *reservelist,
struct boot_info *build_boot_info(struct reserve_info *reservelist,
struct node *tree, uint32_t boot_cpuid_phys);
void sort_tree(struct dt_info *dti);
void generate_label_tree(struct dt_info *dti, const char *name, bool allocph);
void generate_fixups_tree(struct dt_info *dti, const char *name);
void generate_local_fixups_tree(struct dt_info *dti, const char *name);
void sort_tree(struct boot_info *bi);

/* Checks */

void parse_checks_option(bool warn, bool error, const char *arg);
void process_checks(bool force, struct dt_info *dti);
void process_checks(bool force, struct boot_info *bi);

/* Flattened trees */

void dt_to_blob(FILE *f, struct dt_info *dti, int version);
void dt_to_asm(FILE *f, struct dt_info *dti, int version);
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 dt_info *dt_from_blob(const char *fname);
struct boot_info *dt_from_blob(const char *fname);

/* Tree source */

void dt_to_source(FILE *f, struct dt_info *dti);
struct dt_info *dt_from_source(const char *f);

/* YAML source */

void dt_to_yaml(FILE *f, struct dt_info *dti);
void dt_to_source(FILE *f, struct boot_info *bi);
struct boot_info *dt_from_source(const char *f);

/* FS trees */

struct dt_info *dt_from_fs(const char *dirname);
struct boot_info *dt_from_fs(const char *dirname);

#endif /* DTC_H */
#endif /* _DTC_H */

3
dtdiff
View File

@ -1,5 +1,4 @@
#! /bin/bash
# SPDX-License-Identifier: GPL-2.0-or-later

# This script uses the bash <(...) extension.
# If you want to change this to work with a generic /bin/sh, make sure
@ -17,7 +16,7 @@ source_and_sort () {
*.dts)
IFORMAT=dts
;;
*.dtb|*.dtbo)
*.dtb)
IFORMAT=dtb
;;
esac

View File

@ -1,4 +1,3 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* fdtdump.c - Contributed by Pantelis Antoniou <pantelis.antoniou AT gmail.com>
*/
@ -9,7 +8,6 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <inttypes.h>

#include <libfdt.h>
#include <libfdt_env.h>
@ -17,12 +15,9 @@

#include "util.h"

#define FDT_MAGIC_SIZE 4
#define MAX_VERSION 17U

#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
#define PALIGN(p, a) ((void *)(ALIGN((uintptr_t)(p), (a))))
#define GET_CELL(p) (p += 4, *((const fdt32_t *)(p-4)))
#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)
{
@ -67,24 +62,23 @@ static void dump_blob(void *blob, bool debug)
shift = 4;

printf("/dts-v1/;\n");
printf("// magic:\t\t0x%"PRIx32"\n", fdt32_to_cpu(bph->magic));
printf("// totalsize:\t\t0x%"PRIx32" (%"PRIu32")\n",
totalsize, totalsize);
printf("// off_dt_struct:\t0x%"PRIx32"\n", off_dt);
printf("// off_dt_strings:\t0x%"PRIx32"\n", off_str);
printf("// off_mem_rsvmap:\t0x%"PRIx32"\n", off_mem_rsvmap);
printf("// version:\t\t%"PRIu32"\n", version);
printf("// last_comp_version:\t%"PRIu32"\n",
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%"PRIx32"\n",
printf("// boot_cpuid_phys:\t0x%x\n",
fdt32_to_cpu(bph->boot_cpuid_phys));

if (version >= 3)
printf("// size_dt_strings:\t0x%"PRIx32"\n",
printf("// size_dt_strings:\t0x%x\n",
fdt32_to_cpu(bph->size_dt_strings));
if (version >= 17)
printf("// size_dt_struct:\t0x%"PRIx32"\n",
printf("// size_dt_struct:\t0x%x\n",
fdt32_to_cpu(bph->size_dt_struct));
printf("\n");

@ -94,14 +88,14 @@ static void dump_blob(void *blob, bool debug)
if (addr == 0 && size == 0)
break;

printf("/memreserve/ %#"PRIx64" %#"PRIx64";\n",
addr, size);
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("%04"PRIxPTR": tag: 0x%08"PRIx32" (%s)\n",
dumpf("%04zx: tag: 0x%08x (%s)\n",
(uintptr_t)p - blob_off - 4, tag, tagname(tag));

if (tag == FDT_BEGIN_NODE) {
@ -130,7 +124,7 @@ static void dump_blob(void *blob, bool debug)
}

if (tag != FDT_PROP) {
fprintf(stderr, "%*s ** Unknown tag 0x%08"PRIx32"\n", depth * shift, "", tag);
fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", depth * shift, "", tag);
break;
}
sz = fdt32_to_cpu(GET_CELL(p));
@ -141,8 +135,8 @@ static void dump_blob(void *blob, bool debug)

p = PALIGN(p + sz, 4);

dumpf("%04"PRIxPTR": string: %s\n", (uintptr_t)s - blob_off, s);
dumpf("%04"PRIxPTR": value\n", (uintptr_t)t - blob_off);
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");
@ -163,20 +157,6 @@ static const char * const usage_opts_help[] = {
USAGE_COMMON_OPTS_HELP
};

static bool valid_header(char *p, size_t len)
{
if (len < sizeof(struct fdt_header) ||
fdt_magic(p) != FDT_MAGIC ||
fdt_version(p) > MAX_VERSION ||
fdt_last_comp_version(p) > MAX_VERSION ||
fdt_totalsize(p) >= len ||
fdt_off_dt_struct(p) >= len ||
fdt_off_dt_strings(p) >= len)
return 0;
else
return 1;
}

int main(int argc, char *argv[])
{
int opt;
@ -184,13 +164,8 @@ int main(int argc, char *argv[])
char *buf;
bool debug = false;
bool scan = false;
size_t len;
off_t len;

fprintf(stderr, "\n"
"**** fdtdump is a low-level debugging tool, not meant for general use.\n"
"**** If you want to decompile a dtb, you probably want\n"
"**** dtc -I dtb -O dts <filename>\n\n"
);
while ((opt = util_getopt_long()) != EOF) {
switch (opt) {
case_USAGE_COMMON_FLAGS
@ -207,40 +182,44 @@ int main(int argc, char *argv[])
usage("missing input filename");
file = argv[optind];

buf = utilfdt_read(file, &len);
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[FDT_MAGIC_SIZE];
unsigned char smagic[4];
char *p = buf;
char *endp = buf + len;

fdt32_st(smagic, FDT_MAGIC);
fdt_set_magic(smagic, FDT_MAGIC);

/* poor man's memmem */
while ((endp - p) >= FDT_MAGIC_SIZE) {
p = memchr(p, smagic[0], endp - p - FDT_MAGIC_SIZE);
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;
if (valid_header(p, this_len))
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 %#tx\n",
printf("%s: skipping fdt magic at offset %#zx\n",
file, p - buf);
}
++p;
}
if (!p || (size_t)(endp - p) < sizeof(struct fdt_header))
if (!p)
die("%s: could not locate fdt magic\n", file);
printf("%s: found fdt at offset %#tx\n", file, p - buf);
printf("%s: found fdt at offset %#zx\n", file, p - buf);
buf = p;
} else if (!valid_header(buf, len))
die("%s: header is not valid\n", file);
}

dump_blob(buf, debug);


View File

@ -1,4 +1,3 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
*
@ -7,6 +6,21 @@
* 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>
@ -39,43 +53,6 @@ static void report_error(const char *where, int err)
fprintf(stderr, "Error at '%s': %s\n", where, fdt_strerror(err));
}

/**
* Shows a list of cells in the requested format
*
* @param disp Display information / options
* @param data Data to display
* @param len Maximum length of buffer
* @param size Data size to use for display (e.g. 4 for 32-bit)
* @return 0 if ok, -1 on error
*/
static int show_cell_list(struct display_info *disp, const char *data, int len,
int size)
{
const uint8_t *p = (const uint8_t *)data;
char fmt[3];
int value;
int i;

fmt[0] = '%';
fmt[1] = disp->type ? disp->type : 'd';
fmt[2] = '\0';
for (i = 0; i < len; i += size, p += size) {
if (i)
printf(" ");
switch (size) {
case 4: value = fdt32_ld((const fdt32_t *)p); break;
case 2: value = fdt16_ld((const fdt16_t *)p); break;
case 1:
default:
value = *p;
break;
}
printf(fmt, value);
}

return 0;
}

/**
* Displays data of a given length according to selected options
*
@ -89,19 +66,17 @@ static int show_cell_list(struct display_info *disp, const char *data, int len,
*/
static int show_data(struct display_info *disp, const char *data, int len)
{
int size;
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;

if (disp->type == 'r') {
fwrite(data, 1, len, stdout);
return 0;
}

is_string = (disp->type) == 's' ||
(!disp->type && util_is_printable_string(data, len));
if (is_string) {
@ -124,8 +99,17 @@ static int show_data(struct display_info *disp, const char *data, int len)
"selected data size\n");
return -1;
}

return show_cell_list(disp, data, len, size);
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;
}

/**
@ -137,6 +121,7 @@ static int show_data(struct display_info *disp, const char *data, int len)
*/
static int list_properties(const void *blob, int node)
{
const struct fdt_property *data;
const char *name;
int prop;

@ -145,7 +130,8 @@ static int list_properties(const void *blob, int node)
/* Stop silently when there are no more properties */
if (prop < 0)
return prop == -FDT_ERR_NOTFOUND ? 0 : prop;
fdt_getprop_by_offset(blob, prop, &name, NULL);
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);
@ -259,7 +245,7 @@ static int show_data_for_item(const void *blob, struct display_info *disp,
* @param filename Filename of blob file
* @param arg List of arguments to process
* @param arg_count Number of arguments
* @return 0 if ok, -ve on error
* @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)
@ -268,7 +254,7 @@ static int do_fdtget(struct display_info *disp, const char *filename,
const char *prop;
int i, node;

blob = utilfdt_read(filename, NULL);
blob = utilfdt_read(filename);
if (!blob)
return -1;

@ -280,20 +266,14 @@ static int do_fdtget(struct display_info *disp, const char *filename,
continue;
} else {
report_error(arg[i], node);
free(blob);
return -1;
}
}
prop = args_per_step == 1 ? NULL : arg[i + 1];

if (show_data_for_item(blob, disp, node, prop)) {
free(blob);
if (show_data_for_item(blob, disp, node, prop))
return -1;
}
}

free(blob);

return 0;
}


View File

@ -1,214 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2017 Konsulko Group Inc. All rights reserved.
*
* Author:
* Pantelis Antoniou <pantelis.antoniou@konsulko.com>
*/

#include <assert.h>
#include <ctype.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>

#include <libfdt.h>

#include "util.h"

#define BUF_INCREMENT 65536

/* Usage related data. */
static const char usage_synopsis[] =
"apply a number of overlays to a base blob\n"
" fdtoverlay <options> [<overlay.dtbo> [<overlay.dtbo>]]";
static const char usage_short_opts[] = "i:o:v" USAGE_COMMON_SHORT_OPTS;
static struct option const usage_long_opts[] = {
{"input", required_argument, NULL, 'i'},
{"output", required_argument, NULL, 'o'},
{"verbose", no_argument, NULL, 'v'},
USAGE_COMMON_LONG_OPTS,
};
static const char * const usage_opts_help[] = {
"Input base DT blob",
"Output DT blob",
"Verbose messages",
USAGE_COMMON_OPTS_HELP
};

int verbose = 0;

static void *apply_one(char *base, const char *overlay, size_t *buf_len,
const char *name)
{
char *tmp = NULL;
char *tmpo;
int ret;
bool has_symbols;

/*
* We take copies first, because a failed apply can trash
* both the base blob and the overlay
*/
tmpo = xmalloc(fdt_totalsize(overlay));

do {
tmp = xrealloc(tmp, *buf_len);
ret = fdt_open_into(base, tmp, *buf_len);
if (ret) {
fprintf(stderr,
"\nFailed to make temporary copy: %s\n",
fdt_strerror(ret));
goto fail;
}
ret = fdt_path_offset(tmp, "/__symbols__");
has_symbols = ret >= 0;

memcpy(tmpo, overlay, fdt_totalsize(overlay));

ret = fdt_overlay_apply(tmp, tmpo);
if (ret == -FDT_ERR_NOSPACE) {
*buf_len += BUF_INCREMENT;
}
} while (ret == -FDT_ERR_NOSPACE);

if (ret) {
fprintf(stderr, "\nFailed to apply '%s': %s\n",
name, fdt_strerror(ret));
if (!has_symbols) {
fprintf(stderr,
"base blob does not have a '/__symbols__' node, "
"make sure you have compiled the base blob with '-@' option\n");
}
goto fail;
}

free(base);
free(tmpo);
return tmp;

fail:
free(tmpo);
if (tmp)
free(tmp);

return NULL;
}
static int do_fdtoverlay(const char *input_filename,
const char *output_filename,
int argc, char *argv[])
{
char *blob = NULL;
char **ovblob = NULL;
size_t buf_len;
int i, ret = -1;

blob = utilfdt_read(input_filename, &buf_len);
if (!blob) {
fprintf(stderr, "\nFailed to read '%s'\n", input_filename);
goto out_err;
}
if (fdt_totalsize(blob) > buf_len) {
fprintf(stderr,
"\nBase blob is incomplete (%lu / %" PRIu32 " bytes read)\n",
(unsigned long)buf_len, fdt_totalsize(blob));
goto out_err;
}

/* allocate blob pointer array */
ovblob = xmalloc(sizeof(*ovblob) * argc);
memset(ovblob, 0, sizeof(*ovblob) * argc);

/* read and keep track of the overlay blobs */
for (i = 0; i < argc; i++) {
size_t ov_len;
ovblob[i] = utilfdt_read(argv[i], &ov_len);
if (!ovblob[i]) {
fprintf(stderr, "\nFailed to read '%s'\n", argv[i]);
goto out_err;
}
if (fdt_totalsize(ovblob[i]) > ov_len) {
fprintf(stderr,
"\nOverlay '%s' is incomplete (%lu / %" PRIu32 " bytes read)\n",
argv[i], (unsigned long)ov_len,
fdt_totalsize(ovblob[i]));
goto out_err;
}
}

buf_len = fdt_totalsize(blob);

/* apply the overlays in sequence */
for (i = 0; i < argc; i++) {
blob = apply_one(blob, ovblob[i], &buf_len, argv[i]);
if (!blob)
goto out_err;
}

fdt_pack(blob);
ret = utilfdt_write(output_filename, blob);
if (ret)
fprintf(stderr, "\nFailed to write '%s'\n",
output_filename);

out_err:
if (ovblob) {
for (i = 0; i < argc; i++) {
if (ovblob[i])
free(ovblob[i]);
}
free(ovblob);
}
free(blob);

return ret;
}

int main(int argc, char *argv[])
{
int opt, i;
char *input_filename = NULL;
char *output_filename = NULL;

while ((opt = util_getopt_long()) != EOF) {
switch (opt) {
case_USAGE_COMMON_FLAGS

case 'i':
input_filename = optarg;
break;
case 'o':
output_filename = optarg;
break;
case 'v':
verbose = 1;
break;
}
}

if (!input_filename)
usage("missing input file");

if (!output_filename)
usage("missing output file");

argv += optind;
argc -= optind;

if (argc <= 0)
usage("missing overlay file(s)");

if (verbose) {
printf("input = %s\n", input_filename);
printf("output = %s\n", output_filename);
for (i = 0; i < argc; i++)
printf("overlay[%d] = %s\n", i, argv[i]);
}

if (do_fdtoverlay(input_filename, output_filename, argc, argv))
return 1;

return 0;
}

158
fdtput.c
View File

@ -1,6 +1,20 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/

#include <assert.h>
@ -9,7 +23,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <libfdt.h>

@ -19,8 +32,6 @@
enum oper_type {
OPER_WRITE_PROP, /* Write a property in a node */
OPER_CREATE_NODE, /* Create a new node */
OPER_REMOVE_NODE, /* Delete a node */
OPER_DELETE_PROP, /* Delete a property in a node */
};

struct display_info {
@ -54,7 +65,7 @@ static void report_error(const char *name, int namelen, int err)
* @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
* @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)
@ -65,12 +76,16 @@ static int encode_value(struct display_info *disp, char **arg, int arg_count,
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')
@ -90,35 +105,8 @@ static int encode_value(struct display_info *disp, char **arg, int arg_count,
if (disp->verbose)
fprintf(stderr, "\tstring: '%s'\n", ptr);
} else {
fdt32_t *iptr = (fdt32_t *)ptr;
char *endptr;

errno = 0;
switch (disp->type) {
case 'x':
ival = strtoul(*arg, &endptr, 16);
break;
case 'o':
ival = strtoul(*arg, &endptr, 8);
break;
case 'i':
ival = strtol(*arg, &endptr, 0);
break;
case 'u':
ival = strtoul(*arg, &endptr, 0);
break;
default: /* 0 or 'd' */
ival = strtol(*arg, &endptr, 10);
}

if (*endptr != '\0' || errno) {
if (disp->verbose) {
fprintf(stderr,
"Couldn't parse \"%s\" as an integer\n",
*arg);
}
return -1;
}
int *iptr = (int *)ptr;
sscanf(*arg, fmt, &ival);
if (len == 4)
*iptr = cpu_to_fdt32(ival);
else
@ -140,7 +128,7 @@ static int encode_value(struct display_info *disp, char **arg, int arg_count,

#define ALIGN(x) (((x) + (FDT_TAGSIZE) - 1) & ~((FDT_TAGSIZE) - 1))

static char *realloc_fdt(char *fdt, int delta)
static char *_realloc_fdt(char *fdt, int delta)
{
int new_sz = fdt_totalsize(fdt) + delta;
fdt = xrealloc(fdt, new_sz);
@ -154,7 +142,7 @@ static char *realloc_node(char *fdt, const char *name)
/* FDT_BEGIN_NODE, node name in off_struct and FDT_END_NODE */
delta = sizeof(struct fdt_node_header) + ALIGN(strlen(name) + 1)
+ FDT_TAGSIZE;
return realloc_fdt(fdt, delta);
return _realloc_fdt(fdt, delta);
}

static char *realloc_property(char *fdt, int nodeoffset,
@ -171,7 +159,7 @@ static char *realloc_property(char *fdt, int nodeoffset,
/* actual value in off_struct */
delta += ALIGN(newlen) - ALIGN(oldlen);

return realloc_fdt(fdt, delta);
return _realloc_fdt(fdt, delta);
}

static int store_key_value(char **blob, const char *node_name,
@ -282,68 +270,14 @@ static int create_node(char **blob, const char *node_name)
return 0;
}

/**
* Delete a property of a node in the fdt.
*
* @param blob FDT blob to write into
* @param node_name Path to node containing the property to delete
* @param prop_name Name of property to delete
* @return 0 on success, or -1 on failure
*/
static int delete_prop(char *blob, const char *node_name, const char *prop_name)
{
int node = 0;

node = fdt_path_offset(blob, node_name);
if (node < 0) {
report_error(node_name, -1, node);
return -1;
}

node = fdt_delprop(blob, node, prop_name);
if (node < 0) {
report_error(node_name, -1, node);
return -1;
}

return 0;
}

/**
* Delete a node in the fdt.
*
* @param blob FDT blob to write into
* @param node_name Name of node to delete
* @return 0 on success, or -1 on failure
*/
static int delete_node(char *blob, const char *node_name)
{
int node = 0;

node = fdt_path_offset(blob, node_name);
if (node < 0) {
report_error(node_name, -1, node);
return -1;
}

node = fdt_del_node(blob, node);
if (node < 0) {
report_error(node_name, -1, node);
return -1;
}

return 0;
}

static int do_fdtput(struct display_info *disp, const char *filename,
char **arg, int arg_count)
{
char *value = NULL;
char *value;
char *blob;
char *node;
int len, ret = 0;

blob = utilfdt_read(filename, NULL);
blob = utilfdt_read(filename);
if (!blob)
return -1;

@ -368,15 +302,6 @@ static int do_fdtput(struct display_info *disp, const char *filename,
ret = create_node(&blob, *arg);
}
break;
case OPER_REMOVE_NODE:
for (; ret >= 0 && arg_count--; arg++)
ret = delete_node(blob, *arg);
break;
case OPER_DELETE_PROP:
node = *arg;
for (arg++; ret >= 0 && arg_count-- > 1; arg++)
ret = delete_prop(blob, node, *arg);
break;
}
if (ret >= 0) {
fdt_pack(blob);
@ -384,11 +309,6 @@ static int do_fdtput(struct display_info *disp, const char *filename,
}

free(blob);

if (value) {
free(value);
}

return ret;
}

@ -397,25 +317,19 @@ 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"
" fdtput -r <options> <dt file> [<node>...]\n"
" fdtput -d <options> <dt file> <node> [<property>...]\n"
"\n"
"The command line arguments are joined together into a single value.\n"
USAGE_TYPE_MSG;
static const char usage_short_opts[] = "crdpt:v" USAGE_COMMON_SHORT_OPTS;
static const char usage_short_opts[] = "cpt:v" USAGE_COMMON_SHORT_OPTS;
static struct option const usage_long_opts[] = {
{"create", no_argument, NULL, 'c'},
{"remove", no_argument, NULL, 'r'},
{"delete", no_argument, NULL, 'd'},
{"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",
"Delete nodes (and any subnodes)",
"Delete properties if they already exist",
"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",
@ -434,6 +348,8 @@ int main(int argc, char *argv[])
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
@ -444,12 +360,6 @@ int main(int argc, char *argv[])
case 'c':
disp.oper = OPER_CREATE_NODE;
break;
case 'r':
disp.oper = OPER_REMOVE_NODE;
break;
case 'd':
disp.oper = OPER_DELETE_PROP;
break;
case 'p':
disp.auto_path = 1;
break;
@ -457,8 +367,6 @@ int main(int argc, char *argv[])
if (utilfdt_decode_type(optarg, &disp.type,
&disp.size))
usage("Invalid type string");
if (disp.type == 'r')
usage("Unsupported raw data type");
break;

case 'v':
@ -482,10 +390,6 @@ int main(int argc, char *argv[])
usage("missing property");
}

if (disp.oper == OPER_DELETE_PROP)
if (argc < 1)
usage("missing node");

if (do_fdtput(&disp, filename, argv, argc))
return 1;
return 0;

View File

@ -1,6 +1,21 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/

#include "dtc.h"
@ -34,7 +49,7 @@ static struct version_info {

struct emitter {
void (*cell)(void *, cell_t);
void (*string)(void *, const char *, int);
void (*string)(void *, char *, int);
void (*align)(void *, int);
void (*data)(void *, struct data);
void (*beginnode)(void *, struct label *labels);
@ -49,7 +64,7 @@ static void bin_emit_cell(void *e, cell_t val)
*dtbuf = data_append_cell(*dtbuf, val);
}

static void bin_emit_string(void *e, const char *str, int len)
static void bin_emit_string(void *e, char *str, int len)
{
struct data *dtbuf = e;

@ -124,20 +139,27 @@ static void asm_emit_cell(void *e, cell_t val)
{
FILE *f = e;

fprintf(f, "\t.byte\t0x%02x\n" "\t.byte\t0x%02x\n"
"\t.byte\t0x%02x\n" "\t.byte\t0x%02x\n",
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, const char *str, int len)
static void asm_emit_string(void *e, char *str, int len)
{
FILE *f = e;
char c = 0;

if (len != 0)
fprintf(f, "\t.asciz\t\"%.*s\"\n", len, str);
else
fprintf(f, "\t.asciz\t\"%s\"\n", str);
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)
@ -150,14 +172,14 @@ static void asm_emit_align(void *e, int a)
static void asm_emit_data(void *e, struct data d)
{
FILE *f = e;
unsigned int off = 0;
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, dtb_ld32(d.val + off));
asm_emit_cell(e, fdt32_to_cpu(*((uint32_t *)(d.val+off))));
off += sizeof(uint32_t);
}

@ -220,7 +242,7 @@ static struct emitter asm_emitter = {

static int stringtable_insert(struct data *d, const char *str)
{
unsigned int i;
int i;

/* FIXME: do this more efficiently? */

@ -296,16 +318,17 @@ static struct data flatten_reserve_list(struct reserve_info *reservelist,
{
struct reserve_info *re;
struct data d = empty_data;
unsigned int j;
static struct fdt_reserve_entry null_re = {0,0};
int j;

for (re = reservelist; re; re = re->next) {
d = data_append_re(d, re->address, re->size);
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, 0, 0);
d = data_append_re(d, &null_re);
}

return d;
@ -343,10 +366,10 @@ static void make_fdt_header(struct fdt_header *fdt,
fdt->size_dt_struct = cpu_to_fdt32(dtsize);
}

void dt_to_blob(FILE *f, struct dt_info *dti, int version)
void dt_to_blob(FILE *f, struct boot_info *bi, int version)
{
struct version_info *vi = NULL;
unsigned int i;
int i;
struct data blob = empty_data;
struct data reservebuf = empty_data;
struct data dtbuf = empty_data;
@ -361,36 +384,29 @@ void dt_to_blob(FILE *f, struct dt_info *dti, int version)
if (!vi)
die("Unknown device tree blob version %d\n", version);

flatten_tree(dti->dt, &bin_emitter, &dtbuf, &strbuf, vi);
flatten_tree(bi->dt, &bin_emitter, &dtbuf, &strbuf, vi);
bin_emit_cell(&dtbuf, FDT_END);

reservebuf = flatten_reserve_list(dti->reservelist, vi);
reservebuf = flatten_reserve_list(bi->reservelist, vi);

/* Make header */
make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
dti->boot_cpuid_phys);
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) {
padlen = 0;
if (quiet < 1)
if ((padlen < 0) && (quiet < 1))
fprintf(stderr,
"Warning: blob size %"PRIu32" >= minimum size %d\n",
"Warning: blob size %d >= minimum size %d\n",
fdt32_to_cpu(fdt.totalsize), minsize);
}
}

if (padsize > 0)
padlen = padsize;

if (alignsize > 0)
padlen = ALIGN(fdt32_to_cpu(fdt.totalsize) + padlen, alignsize)
- fdt32_to_cpu(fdt.totalsize);

if (padlen > 0) {
int tsize = fdt32_to_cpu(fdt.totalsize);
tsize += padlen;
@ -439,15 +455,15 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf)

while (p < (strbuf.val + strbuf.len)) {
len = strlen(p);
fprintf(f, "\t.asciz \"%s\"\n", p);
fprintf(f, "\t.string \"%s\"\n", p);
p += len+1;
}
}

void dt_to_asm(FILE *f, struct dt_info *dti, int version)
void dt_to_asm(FILE *f, struct boot_info *bi, int version)
{
struct version_info *vi = NULL;
unsigned int i;
int i;
struct data strbuf = empty_data;
struct reserve_info *re;
const char *symprefix = "dt";
@ -484,7 +500,7 @@ void dt_to_asm(FILE *f, struct dt_info *dti, int version)

if (vi->flags & FTF_BOOTCPUID) {
fprintf(f, "\t/* boot_cpuid_phys */\n");
asm_emit_cell(f, dti->boot_cpuid_phys);
asm_emit_cell(f, bi->boot_cpuid_phys);
}

if (vi->flags & FTF_STRTABSIZE) {
@ -503,7 +519,7 @@ void dt_to_asm(FILE *f, struct dt_info *dti, int version)
* 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 termination entry.
* Always supply a zero-sized temination entry.
*/
asm_emit_align(f, 8);
emit_label(f, symprefix, "reserve_map");
@ -511,21 +527,21 @@ void dt_to_asm(FILE *f, struct dt_info *dti, int version)
fprintf(f, "/* Memory reserve map from source file */\n");

/*
* Use .long on high and low halves of u64s to avoid .quad
* Use .long on high and low halfs of u64s to avoid .quad
* as it appears .quad isn't available in some assemblers.
*/
for (re = dti->reservelist; re; re = re->next) {
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->address >> 32));
ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.address >> 32));
ASM_EMIT_BELONG(f, "0x%08x",
(unsigned int)(re->address & 0xffffffff));
ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->size >> 32));
ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->size & 0xffffffff));
(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");
@ -534,7 +550,7 @@ void dt_to_asm(FILE *f, struct dt_info *dti, int version)
fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");

emit_label(f, symprefix, "struct_start");
flatten_tree(dti->dt, &asm_emitter, f, &strbuf, vi);
flatten_tree(bi->dt, &asm_emitter, f, &strbuf, vi);

fprintf(f, "\t/* FDT_END */\n");
asm_emit_cell(f, FDT_END);
@ -556,8 +572,6 @@ void dt_to_asm(FILE *f, struct dt_info *dti, int version)
if (padsize > 0) {
fprintf(f, "\t.space\t%d, 0\n", padsize);
}
if (alignsize > 0)
asm_emit_align(f, alignsize);
emit_label(f, symprefix, "blob_abs_end");

data_free(strbuf);
@ -586,7 +600,7 @@ static void flat_read_chunk(struct inbuf *inb, void *p, int len)

static uint32_t flat_read_word(struct inbuf *inb)
{
fdt32_t val;
uint32_t val;

assert(((inb->ptr - inb->base) % sizeof(val)) == 0);

@ -604,11 +618,11 @@ static void flat_realign(struct inbuf *inb, int align)
die("Premature end of data parsing flat device tree\n");
}

static const char *flat_read_string(struct inbuf *inb)
static char *flat_read_string(struct inbuf *inb)
{
int len = 0;
const char *p = inb->ptr;
const char *str;
char *str;

do {
if (p >= inb->limit)
@ -616,7 +630,7 @@ static const char *flat_read_string(struct inbuf *inb)
len++;
} while ((*p++) != '\0');

str = inb->ptr;
str = xstrdup(inb->ptr);

inb->ptr += len;

@ -678,7 +692,7 @@ static struct property *flat_read_property(struct inbuf *dtbuf,

val = flat_read_data(dtbuf, proplen);

return build_property(name, val, NULL);
return build_property(name, val);
}


@ -695,15 +709,13 @@ static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
* First pass, count entries.
*/
while (1) {
uint64_t address, size;

flat_read_chunk(inb, &re, sizeof(re));
address = fdt64_to_cpu(re.address);
size = fdt64_to_cpu(re.size);
if (size == 0)
re.address = fdt64_to_cpu(re.address);
re.size = fdt64_to_cpu(re.size);
if (re.size == 0)
break;

new = build_reserve_entry(address, size);
new = build_reserve_entry(re.address, re.size);
reservelist = add_reserve_entry(reservelist, new);
}

@ -711,13 +723,13 @@ static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
}


static const char *nodename_from_path(const char *ppath, const char *cpath)
static char *nodename_from_path(const char *ppath, const char *cpath)
{
int plen;

plen = strlen(ppath);

if (!strstarts(cpath, ppath))
if (!strneq(ppath, cpath, plen))
die("Path \"%s\" is not valid as a child of \"%s\"\n",
cpath, ppath);

@ -725,7 +737,7 @@ static const char *nodename_from_path(const char *ppath, const char *cpath)
if (!streq(ppath, "/"))
plen++;

return cpath + plen;
return xstrdup(cpath + plen);
}

static struct node *unflatten_tree(struct inbuf *dtbuf,
@ -733,18 +745,17 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
const char *parent_flatname, int flags)
{
struct node *node;
const char *flatname;
char *flatname;
uint32_t val;

node = build_node(NULL, NULL, NULL);
node = build_node(NULL, NULL);

flatname = flat_read_string(dtbuf);

if (flags & FTF_FULLPATH)
node->name = xstrdup(nodename_from_path(parent_flatname,
flatname));
node->name = nodename_from_path(parent_flatname, flatname);
else
node->name = xstrdup(flatname);
node->name = flatname;

do {
struct property *prop;
@ -790,10 +801,9 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
}


struct dt_info *dt_from_blob(const char *fname)
struct boot_info *dt_from_blob(const char *fname)
{
FILE *f;
fdt32_t magic_buf, totalsize_buf;
uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys;
uint32_t off_dt, off_str, off_mem_rsvmap;
int rc;
@ -810,7 +820,7 @@ struct dt_info *dt_from_blob(const char *fname)

f = srcfile_relative_open(fname, NULL);

rc = fread(&magic_buf, sizeof(magic_buf), 1, f);
rc = fread(&magic, sizeof(magic), 1, f);
if (ferror(f))
die("Error reading DT blob magic number: %s\n",
strerror(errno));
@ -821,11 +831,11 @@ struct dt_info *dt_from_blob(const char *fname)
die("Mysterious short read reading magic number\n");
}

magic = fdt32_to_cpu(magic_buf);
magic = fdt32_to_cpu(magic);
if (magic != FDT_MAGIC)
die("Blob has incorrect magic number\n");

rc = fread(&totalsize_buf, sizeof(totalsize_buf), 1, f);
rc = fread(&totalsize, sizeof(totalsize), 1, f);
if (ferror(f))
die("Error reading DT blob size: %s\n", strerror(errno));
if (rc < 1) {
@ -835,7 +845,7 @@ struct dt_info *dt_from_blob(const char *fname)
die("Mysterious short read reading blob size\n");
}

totalsize = fdt32_to_cpu(totalsize_buf);
totalsize = fdt32_to_cpu(totalsize);
if (totalsize < FDT_V1_SIZE)
die("DT blob size (%d) is too small\n", totalsize);

@ -879,7 +889,7 @@ struct dt_info *dt_from_blob(const char *fname)

if (version >= 3) {
uint32_t size_str = fdt32_to_cpu(fdt->size_dt_strings);
if ((off_str+size_str < off_str) || (off_str+size_str > totalsize))
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 {
@ -888,7 +898,7 @@ struct dt_info *dt_from_blob(const char *fname)

if (version >= 17) {
size_dt = fdt32_to_cpu(fdt->size_dt_struct);
if ((off_dt+size_dt < off_dt) || (off_dt+size_dt > totalsize))
if (off_dt+size_dt > totalsize)
die("Structure block extends past total size\n");
}

@ -919,5 +929,5 @@ struct dt_info *dt_from_blob(const char *fname)

fclose(f);

return build_dt_info(DTSF_V1, reservelist, tree, boot_cpuid_phys);
return build_boot_info(reservelist, tree, boot_cpuid_phys);
}

View File

@ -1,6 +1,21 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/

#include "dtc.h"
@ -19,7 +34,7 @@ static struct node *read_fstree(const char *dirname)
if (!d)
die("Couldn't opendir() \"%s\": %s\n", dirname, strerror(errno));

tree = build_node(NULL, NULL, NULL);
tree = build_node(NULL, NULL);

while ((de = readdir(d)) != NULL) {
char *tmpname;
@ -30,7 +45,7 @@ static struct node *read_fstree(const char *dirname)

tmpname = join_path(dirname, de->d_name);

if (stat(tmpname, &st) < 0)
if (lstat(tmpname, &st) < 0)
die("stat(%s): %s\n", tmpname, strerror(errno));

if (S_ISREG(st.st_mode)) {
@ -43,10 +58,9 @@ static struct node *read_fstree(const char *dirname)
"WARNING: Cannot open %s: %s\n",
tmpname, strerror(errno));
} else {
prop = build_property(de->d_name,
prop = build_property(xstrdup(de->d_name),
data_copy_file(pfile,
st.st_size),
NULL);
st.st_size));
add_property(tree, prop);
fclose(pfile);
}
@ -65,12 +79,13 @@ static struct node *read_fstree(const char *dirname)
return tree;
}

struct dt_info *dt_from_fs(const char *dirname)
struct boot_info *dt_from_fs(const char *dirname)
{
struct node *tree;

tree = read_fstree(dirname);
tree = name_node(tree, "");

return build_dt_info(DTSF_V1, NULL, tree, guess_boot_cpuid(tree));
return build_boot_info(NULL, tree, guess_boot_cpuid(tree));
}


1
libfdt/.gitignore vendored
View File

@ -1 +0,0 @@
libfdt.so.1

View File

@ -1,22 +1,11 @@
# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
# Makefile.libfdt
#
# This is not a complete Makefile of itself. Instead, it is designed to
# be easily embeddable into other systems of Makefiles.
#

LIBFDT_so = libfdt.$(SHAREDLIB_EXT)
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 \
fdt_addresses.c fdt_overlay.c fdt_check.c
fdt_addresses.c
LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
LIBFDT_LIB = libfdt.$(SHAREDLIB_EXT).$(DTC_VERSION)

libfdt_clean:
@$(VECHO) CLEAN "(libfdt)"
rm -f $(STD_CLEANFILES:%=$(LIBFDT_dir)/%)
rm -f $(LIBFDT_dir)/$(LIBFDT_so)
rm -f $(LIBFDT_dir)/$(LIBFDT_soname)
rm -f $(LIBFDT_dir)/$(LIBFDT_LIB)

View File

@ -1,2 +1,3 @@
- Tree traversal functions
- Graft function
- Complete libfdt.h documenting comments

View File

@ -1,7 +1,52 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"

@ -10,165 +55,51 @@

#include "libfdt_internal.h"

/*
* Minimal sanity check for a read-only tree. fdt_ro_probe_() checks
* that the given buffer contains what appears to be a flattened
* device tree with sane information in its header.
*/
int32_t fdt_ro_probe_(const void *fdt)
int fdt_check_header(const void *fdt)
{
uint32_t totalsize = fdt_totalsize(fdt);

if (can_assume(VALID_DTB))
return totalsize;

/* The device tree must be at an 8-byte aligned address */
if ((uintptr_t)fdt & 7)
return -FDT_ERR_ALIGNMENT;

if (fdt_magic(fdt) == FDT_MAGIC) {
/* Complete tree */
if (!can_assume(LATEST)) {
if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
return -FDT_ERR_BADVERSION;
if (fdt_last_comp_version(fdt) >
FDT_LAST_SUPPORTED_VERSION)
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 (!can_assume(VALID_INPUT) && fdt_size_dt_struct(fdt) == 0)
if (fdt_size_dt_struct(fdt) == 0)
return -FDT_ERR_BADSTATE;
} else {
return -FDT_ERR_BADMAGIC;
}

if (totalsize < INT32_MAX)
return totalsize;
else
return -FDT_ERR_TRUNCATED;
}

static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off)
{
return (off >= hdrsize) && (off <= totalsize);
}

static int check_block_(uint32_t hdrsize, uint32_t totalsize,
uint32_t base, uint32_t size)
{
if (!check_off_(hdrsize, totalsize, base))
return 0; /* block start out of bounds */
if ((base + size) < base)
return 0; /* overflow */
if (!check_off_(hdrsize, totalsize, base + size))
return 0; /* block end out of bounds */
return 1;
}

size_t fdt_header_size_(uint32_t version)
{
if (version <= 1)
return FDT_V1_SIZE;
else if (version <= 2)
return FDT_V2_SIZE;
else if (version <= 3)
return FDT_V3_SIZE;
else if (version <= 16)
return FDT_V16_SIZE;
else
return FDT_V17_SIZE;
}

size_t fdt_header_size(const void *fdt)
{
return can_assume(LATEST) ? FDT_V17_SIZE :
fdt_header_size_(fdt_version(fdt));
}

int fdt_check_header(const void *fdt)
{
size_t hdrsize;

/* The device tree must be at an 8-byte aligned address */
if ((uintptr_t)fdt & 7)
return -FDT_ERR_ALIGNMENT;

if (fdt_magic(fdt) != FDT_MAGIC)
return -FDT_ERR_BADMAGIC;
if (!can_assume(LATEST)) {
if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
|| (fdt_last_comp_version(fdt) >
FDT_LAST_SUPPORTED_VERSION))
return -FDT_ERR_BADVERSION;
if (fdt_version(fdt) < fdt_last_comp_version(fdt))
return -FDT_ERR_BADVERSION;
}
hdrsize = fdt_header_size(fdt);
if (!can_assume(VALID_DTB)) {
if ((fdt_totalsize(fdt) < hdrsize)
|| (fdt_totalsize(fdt) > INT_MAX))
return -FDT_ERR_TRUNCATED;

/* Bounds check memrsv block */
if (!check_off_(hdrsize, fdt_totalsize(fdt),
fdt_off_mem_rsvmap(fdt)))
return -FDT_ERR_TRUNCATED;

/* Bounds check structure block */
if (!can_assume(LATEST) && fdt_version(fdt) < 17) {
if (!check_off_(hdrsize, fdt_totalsize(fdt),
fdt_off_dt_struct(fdt)))
return -FDT_ERR_TRUNCATED;
} else {
if (!check_block_(hdrsize, fdt_totalsize(fdt),
fdt_off_dt_struct(fdt),
fdt_size_dt_struct(fdt)))
return -FDT_ERR_TRUNCATED;
}

/* Bounds check strings block */
if (!check_block_(hdrsize, fdt_totalsize(fdt),
fdt_off_dt_strings(fdt),
fdt_size_dt_strings(fdt)))
return -FDT_ERR_TRUNCATED;
}

return 0;
}

const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
{
unsigned int uoffset = offset;
unsigned int absoffset = offset + fdt_off_dt_struct(fdt);
const char *p;

if (offset < 0)
return NULL;

if (!can_assume(VALID_INPUT))
if ((absoffset < uoffset)
|| ((absoffset + len) < absoffset)
|| (absoffset + len) > fdt_totalsize(fdt))
return NULL;

if (can_assume(LATEST) || fdt_version(fdt) >= 0x11)
if (((uoffset + len) < uoffset)
if (fdt_version(fdt) >= 0x11)
if (((offset + len) < offset)
|| ((offset + len) > fdt_size_dt_struct(fdt)))
return NULL;

return fdt_offset_ptr_(fdt, offset);
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, len, sum;
uint32_t tag;
int offset = startoffset;
const char *p;

*nextoffset = -FDT_ERR_TRUNCATED;
tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
if (!can_assume(VALID_DTB) && !tagp)
if (!tagp)
return FDT_END; /* premature end */
tag = fdt32_to_cpu(*tagp);
offset += FDT_TAGSIZE;
@ -180,28 +111,17 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
do {
p = fdt_offset_ptr(fdt, offset++, 1);
} while (p && (*p != '\0'));
if (!can_assume(VALID_DTB) && !p)
if (!p)
return FDT_END; /* premature end */
break;

case FDT_PROP:
lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
if (!can_assume(VALID_DTB) && !lenp)
if (!lenp)
return FDT_END; /* premature end */

len = fdt32_to_cpu(*lenp);
sum = len + offset;
if (!can_assume(VALID_DTB) &&
(INT_MAX <= sum || sum < (uint32_t) offset))
return FDT_END; /* premature end */

/* skip-name offset, length and value */
offset += sizeof(struct fdt_property) - FDT_TAGSIZE + len;

if (!can_assume(LATEST) &&
fdt_version(fdt) < 0x10 && len >= 8 &&
((offset - len) % 8) != 0)
offset += 4;
offset += sizeof(struct fdt_property) - FDT_TAGSIZE
+ fdt32_to_cpu(*lenp);
break;

case FDT_END:
@ -220,25 +140,19 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
return tag;
}

int fdt_check_node_offset_(const void *fdt, int offset)
int _fdt_check_node_offset(const void *fdt, int offset)
{
if (!can_assume(VALID_INPUT)
&& ((offset < 0) || (offset % FDT_TAGSIZE)))
return -FDT_ERR_BADOFFSET;

if (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)
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)
int _fdt_check_prop_offset(const void *fdt, int offset)
{
if (!can_assume(VALID_INPUT)
&& ((offset < 0) || (offset % FDT_TAGSIZE)))
return -FDT_ERR_BADOFFSET;

if (fdt_next_tag(fdt, offset, &offset) != FDT_PROP)
if ((offset < 0) || (offset % FDT_TAGSIZE)
|| (fdt_next_tag(fdt, offset, &offset) != FDT_PROP))
return -FDT_ERR_BADOFFSET;

return offset;
@ -250,7 +164,7 @@ int fdt_next_node(const void *fdt, int offset, int *depth)
uint32_t tag;

if (offset >= 0)
if ((nextoffset = fdt_check_node_offset_(fdt, offset)) < 0)
if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0)
return nextoffset;

do {
@ -312,26 +226,23 @@ int fdt_next_subnode(const void *fdt, int offset)
return offset;
}

const char *fdt_find_string_len_(const char *strtab, int tabsize, const char *s,
int slen)
const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
{
const char *last = strtab + tabsize - (slen + 1);
int len = strlen(s) + 1;
const char *last = strtab + tabsize - len;
const char *p;

for (p = strtab; p <= last; p++)
if (memcmp(p, s, slen) == 0 && p[slen] == '\0')
if (memcmp(p, s, len) == 0)
return p;
return NULL;
}

int fdt_move(const void *fdt, void *buf, int bufsize)
{
if (!can_assume(VALID_INPUT) && bufsize < 0)
return -FDT_ERR_NOSPACE;
FDT_CHECK_HEADER(fdt);

FDT_RO_PROBE(fdt);

if (fdt_totalsize(fdt) > (unsigned int)bufsize)
if (fdt_totalsize(fdt) > bufsize)
return -FDT_ERR_NOSPACE;

memmove(buf, fdt, fdt_totalsize(fdt));

View File

@ -1,13 +1,58 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
#ifndef FDT_H
#define FDT_H
#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 __ASSEMBLER__
#ifndef __ASSEMBLY__

struct fdt_header {
fdt32_t magic; /* magic word FDT_MAGIC */
@ -35,17 +80,17 @@ struct fdt_reserve_entry {

struct fdt_node_header {
fdt32_t tag;
char name[];
char name[0];
};

struct fdt_property {
fdt32_t tag;
fdt32_t len;
fdt32_t nameoff;
char data[];
char data[0];
};

#endif /* !__ASSEMBLER__ */
#endif /* !__ASSEMBLY */

#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */
#define FDT_TAGSIZE sizeof(fdt32_t)
@ -63,4 +108,4 @@ struct fdt_property {
#define FDT_V16_SIZE FDT_V3_SIZE
#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t))

#endif /* FDT_H */
#endif /* _FDT_H */

View File

@ -1,8 +1,52 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au>
* Copyright (C) 2018 embedded brains GmbH
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* 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"

@ -11,91 +55,42 @@

#include "libfdt_internal.h"

static int fdt_cells(const void *fdt, int nodeoffset, const char *name)
{
const fdt32_t *c;
uint32_t val;
int len;

c = fdt_getprop(fdt, nodeoffset, name, &len);
if (!c)
return len;

if (len != sizeof(*c))
return -FDT_ERR_BADNCELLS;

val = fdt32_to_cpu(*c);
if (val > FDT_MAX_NCELLS)
return -FDT_ERR_BADNCELLS;

return (int)val;
}

int fdt_address_cells(const void *fdt, int nodeoffset)
{
const fdt32_t *ac;
int val;
int len;

val = fdt_cells(fdt, nodeoffset, "#address-cells");
if (val == 0)
return -FDT_ERR_BADNCELLS;
if (val == -FDT_ERR_NOTFOUND)
ac = fdt_getprop(fdt, nodeoffset, "#address-cells", &len);
if (!ac)
return 2;

if (len != sizeof(*ac))
return -FDT_ERR_BADNCELLS;

val = fdt32_to_cpu(*ac);
if ((val <= 0) || (val > FDT_MAX_NCELLS))
return -FDT_ERR_BADNCELLS;

return val;
}

int fdt_size_cells(const void *fdt, int nodeoffset)
{
const fdt32_t *sc;
int val;
int len;

sc = fdt_getprop(fdt, nodeoffset, "#size-cells", &len);
if (!sc)
return 2;

if (len != sizeof(*sc))
return -FDT_ERR_BADNCELLS;

val = fdt32_to_cpu(*sc);
if ((val < 0) || (val > FDT_MAX_NCELLS))
return -FDT_ERR_BADNCELLS;

val = fdt_cells(fdt, nodeoffset, "#size-cells");
if (val == -FDT_ERR_NOTFOUND)
return 1;
return val;
}

/* This function assumes that [address|size]_cells is 1 or 2 */
int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
const char *name, uint64_t addr, uint64_t size)
{
int addr_cells, size_cells, ret;
uint8_t data[sizeof(fdt64_t) * 2], *prop;

ret = fdt_address_cells(fdt, parent);
if (ret < 0)
return ret;
addr_cells = ret;

ret = fdt_size_cells(fdt, parent);
if (ret < 0)
return ret;
size_cells = ret;

/* check validity of address */
prop = data;
if (addr_cells == 1) {
if ((addr > UINT32_MAX) || (((uint64_t) UINT32_MAX + 1 - addr) < size))
return -FDT_ERR_BADVALUE;

fdt32_st(prop, (uint32_t)addr);
} else if (addr_cells == 2) {
fdt64_st(prop, addr);
} else {
return -FDT_ERR_BADNCELLS;
}

/* check validity of size */
prop += addr_cells * sizeof(fdt32_t);
if (size_cells == 1) {
if (size > UINT32_MAX)
return -FDT_ERR_BADVALUE;

fdt32_st(prop, (uint32_t)size);
} else if (size_cells == 2) {
fdt64_st(prop, size);
} else {
return -FDT_ERR_BADNCELLS;
}

return fdt_appendprop(fdt, nodeoffset, name, data,
(addr_cells + size_cells) * sizeof(fdt32_t));
}

View File

@ -1,96 +0,0 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*/
#include "libfdt_env.h"

#include <fdt.h>
#include <libfdt.h>

#include "libfdt_internal.h"

int fdt_check_full(const void *fdt, size_t bufsize)
{
int err;
int num_memrsv;
int offset, nextoffset = 0;
uint32_t tag;
unsigned int depth = 0;
const void *prop;
const char *propname;
bool expect_end = false;

if (bufsize < FDT_V1_SIZE)
return -FDT_ERR_TRUNCATED;
if (bufsize < fdt_header_size(fdt))
return -FDT_ERR_TRUNCATED;
err = fdt_check_header(fdt);
if (err != 0)
return err;
if (bufsize < fdt_totalsize(fdt))
return -FDT_ERR_TRUNCATED;

num_memrsv = fdt_num_mem_rsv(fdt);
if (num_memrsv < 0)
return num_memrsv;

while (1) {
offset = nextoffset;
tag = fdt_next_tag(fdt, offset, &nextoffset);

if (nextoffset < 0)
return nextoffset;

/* If we see two root nodes, something is wrong */
if (expect_end && tag != FDT_END)
return -FDT_ERR_BADSTRUCTURE;

switch (tag) {
case FDT_NOP:
break;

case FDT_END:
if (depth != 0)
return -FDT_ERR_BADSTRUCTURE;
return 0;

case FDT_BEGIN_NODE:
depth++;
if (depth > INT_MAX)
return -FDT_ERR_BADSTRUCTURE;

/* The root node must have an empty name */
if (depth == 1) {
const char *name;
int len;

name = fdt_get_name(fdt, offset, &len);
if (!name)
return len;

if (*name || len)
return -FDT_ERR_BADSTRUCTURE;
}
break;

case FDT_END_NODE:
if (depth == 0)
return -FDT_ERR_BADSTRUCTURE;
depth--;
if (depth == 0)
expect_end = true;
break;

case FDT_PROP:
prop = fdt_getprop_by_offset(fdt, offset, &propname,
&err);
if (!prop)
return err;
break;

default:
return -FDT_ERR_INTERNAL;
}
}
}

View File

@ -1,7 +1,52 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2012 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"

@ -36,3 +81,4 @@ int fdt_create_empty_tree(void *buf, int bufsize)

return fdt_open_into(buf, buf, bufsize);
}


File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,52 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"

@ -10,13 +55,12 @@

#include "libfdt_internal.h"

static int fdt_nodename_eq_(const void *fdt, int offset,
static int _fdt_nodename_eq(const void *fdt, int offset,
const char *s, int len)
{
int olen;
const char *p = fdt_get_name(fdt, offset, &olen);
const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);

if (!p || olen < len)
if (! p)
/* short match */
return 0;

@ -31,174 +75,37 @@ static int fdt_nodename_eq_(const void *fdt, int offset,
return 0;
}

const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
{
int32_t totalsize;
uint32_t absoffset;
size_t len;
int err;
const char *s, *n;

if (can_assume(VALID_INPUT)) {
s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;

if (lenp)
*lenp = strlen(s);
return s;
}
totalsize = fdt_ro_probe_(fdt);
err = totalsize;
if (totalsize < 0)
goto fail;

err = -FDT_ERR_BADOFFSET;
absoffset = stroffset + fdt_off_dt_strings(fdt);
if (absoffset >= (unsigned)totalsize)
goto fail;
len = totalsize - absoffset;

if (fdt_magic(fdt) == FDT_MAGIC) {
if (stroffset < 0)
goto fail;
if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
if ((unsigned)stroffset >= fdt_size_dt_strings(fdt))
goto fail;
if ((fdt_size_dt_strings(fdt) - stroffset) < len)
len = fdt_size_dt_strings(fdt) - stroffset;
}
} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
unsigned int sw_stroffset = -stroffset;

if ((stroffset >= 0) ||
(sw_stroffset > fdt_size_dt_strings(fdt)))
goto fail;
if (sw_stroffset < len)
len = sw_stroffset;
} else {
err = -FDT_ERR_INTERNAL;
goto fail;
}

s = (const char *)fdt + absoffset;
n = memchr(s, '\0', len);
if (!n) {
/* missing terminating NULL */
err = -FDT_ERR_TRUNCATED;
goto fail;
}

if (lenp)
*lenp = n - s;
return s;

fail:
if (lenp)
*lenp = err;
return NULL;
}

const char *fdt_string(const void *fdt, int stroffset)
{
return fdt_get_string(fdt, stroffset, NULL);
return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
}

static int fdt_string_eq_(const void *fdt, int stroffset,
static int _fdt_string_eq(const void *fdt, int stroffset,
const char *s, int len)
{
int slen;
const char *p = fdt_get_string(fdt, stroffset, &slen);
const char *p = fdt_string(fdt, stroffset);

return p && (slen == len) && (memcmp(p, s, len) == 0);
}

int fdt_find_max_phandle(const void *fdt, uint32_t *phandle)
{
uint32_t max = 0;
int offset = -1;

while (true) {
uint32_t value;

offset = fdt_next_node(fdt, offset, NULL);
if (offset < 0) {
if (offset == -FDT_ERR_NOTFOUND)
break;

return offset;
}

value = fdt_get_phandle(fdt, offset);

if (value > max)
max = value;
}

if (phandle)
*phandle = max;

return 0;
}

int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
{
uint32_t max;
int err;

err = fdt_find_max_phandle(fdt, &max);
if (err < 0)
return err;

if (max == FDT_MAX_PHANDLE)
return -FDT_ERR_NOPHANDLES;

if (phandle)
*phandle = max + 1;

return 0;
}

static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
{
unsigned int offset = n * sizeof(struct fdt_reserve_entry);
unsigned int absoffset = fdt_off_mem_rsvmap(fdt) + offset;

if (!can_assume(VALID_INPUT)) {
if (absoffset < fdt_off_mem_rsvmap(fdt))
return NULL;
if (absoffset > fdt_totalsize(fdt) -
sizeof(struct fdt_reserve_entry))
return NULL;
}
return fdt_mem_rsv_(fdt, n);
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)
{
const struct fdt_reserve_entry *re;

FDT_RO_PROBE(fdt);
re = fdt_mem_rsv(fdt, n);
if (!can_assume(VALID_INPUT) && !re)
return -FDT_ERR_BADOFFSET;

*address = fdt64_ld_(&re->address);
*size = fdt64_ld_(&re->size);
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;
const struct fdt_reserve_entry *re;
int i = 0;

for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
if (fdt64_ld_(&re->size) == 0)
while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
i++;
return i;
}
return -FDT_ERR_TRUNCATED;
}

static int nextprop_(const void *fdt, int offset)
static int _nextprop(const void *fdt, int offset)
{
uint32_t tag;
int nextoffset;
@ -227,13 +134,13 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset,
{
int depth;

FDT_RO_PROBE(fdt);
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))
&& _fdt_nodename_eq(fdt, offset, name, namelen))
return offset;

if (depth < 0)
@ -247,20 +154,17 @@ int fdt_subnode_offset(const void *fdt, int parentoffset,
return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
}

int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
int fdt_path_offset(const void *fdt, const char *path)
{
const char *end = path + namelen;
const char *end = path + strlen(path);
const char *p = path;
int offset = 0;

FDT_RO_PROBE(fdt);

if (!can_assume(VALID_INPUT) && namelen <= 0)
return -FDT_ERR_BADPATH;
FDT_CHECK_HEADER(fdt);

/* see if we have an alias */
if (*path != '/') {
const char *q = memchr(path, '/', end - p);
const char *q = strchr(path, '/');

if (!q)
q = end;
@ -273,15 +177,14 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
p = q;
}

while (p < end) {
while (*p) {
const char *q;

while (*p == '/') {
while (*p == '/')
p++;
if (p == end)
if (! *p)
return offset;
}
q = memchr(p, '/', end - p);
q = strchr(p, '/');
if (! q)
q = end;

@ -295,42 +198,19 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
return offset;
}

int fdt_path_offset(const void *fdt, const char *path)
{
return fdt_path_offset_namelen(fdt, path, strlen(path));
}

const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
{
const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset);
const char *nameptr;
const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
int err;

if (((err = fdt_ro_probe_(fdt)) < 0)
|| ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
if (((err = fdt_check_header(fdt)) != 0)
|| ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
goto fail;

nameptr = nh->name;

if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
/*
* For old FDT versions, match the naming conventions of V16:
* give only the leaf name (after all /). The actual tree
* contents are loosely checked.
*/
const char *leaf;
leaf = strrchr(nameptr, '/');
if (leaf == NULL) {
err = -FDT_ERR_BADSTRUCTURE;
goto fail;
}
nameptr = leaf+1;
}

if (len)
*len = strlen(nameptr);
*len = strlen(nh->name);

return nameptr;
return nh->name;

fail:
if (len)
@ -342,107 +222,65 @@ int fdt_first_property_offset(const void *fdt, int nodeoffset)
{
int offset;

if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
return offset;

return nextprop_(fdt, offset);
return _nextprop(fdt, offset);
}

int fdt_next_property_offset(const void *fdt, int offset)
{
if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0)
if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0)
return offset;

return nextprop_(fdt, offset);
}

static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
int offset,
int *lenp)
{
int err;
const struct fdt_property *prop;

if (!can_assume(VALID_INPUT) &&
(err = fdt_check_prop_offset_(fdt, offset)) < 0) {
if (lenp)
*lenp = err;
return NULL;
}

prop = fdt_offset_ptr_(fdt, offset);

if (lenp)
*lenp = fdt32_ld_(&prop->len);

return prop;
return _nextprop(fdt, offset);
}

const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
int offset,
int *lenp)
{
/* Prior to version 16, properties may need realignment
* and this API does not work. fdt_getprop_*() will, however. */

if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
if (lenp)
*lenp = -FDT_ERR_BADVERSION;
return NULL;
}

return fdt_get_property_by_offset_(fdt, offset, lenp);
}

static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
int offset,
const char *name,
int namelen,
int *lenp,
int *poffset)
{
for (offset = fdt_first_property_offset(fdt, offset);
(offset >= 0);
(offset = fdt_next_property_offset(fdt, offset))) {
int err;
const struct fdt_property *prop;

prop = fdt_get_property_by_offset_(fdt, offset, lenp);
if (!can_assume(LIBFDT_FLAWLESS) && !prop) {
offset = -FDT_ERR_INTERNAL;
break;
}
if (fdt_string_eq_(fdt, fdt32_ld_(&prop->nameoff),
name, namelen)) {
if (poffset)
*poffset = offset;
return 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 = offset;
return NULL;
}
*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)
{
/* Prior to version 16, properties may need realignment
* and this API does not work. fdt_getprop_*() will, however. */
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
if (lenp)
*lenp = -FDT_ERR_BADVERSION;
return NULL;
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;
}

return fdt_get_property_namelen_(fdt, offset, name, namelen, lenp,
NULL);
if (lenp)
*lenp = offset;
return NULL;
}


const struct fdt_property *fdt_get_property(const void *fdt,
int nodeoffset,
const char *name, int *lenp)
@ -454,18 +292,12 @@ const struct fdt_property *fdt_get_property(const void *fdt,
const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
const char *name, int namelen, int *lenp)
{
int poffset;
const struct fdt_property *prop;

prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp,
&poffset);
if (!prop)
prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
if (! prop)
return NULL;

/* Handle realignment */
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
(poffset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8)
return prop->data + 4;
return prop->data;
}

@ -474,31 +306,11 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
{
const struct fdt_property *prop;

prop = fdt_get_property_by_offset_(fdt, offset, lenp);
prop = fdt_get_property_by_offset(fdt, offset, lenp);
if (!prop)
return NULL;
if (namep) {
const char *name;
int namelen;

if (!can_assume(VALID_INPUT)) {
name = fdt_get_string(fdt, fdt32_ld_(&prop->nameoff),
&namelen);
*namep = name;
if (!name) {
if (lenp)
*lenp = namelen;
return NULL;
}
} else {
*namep = fdt_string(fdt, fdt32_ld_(&prop->nameoff));
}
}

/* Handle realignment */
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
(offset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8)
return prop->data + 4;
if (namep)
*namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
return prop->data;
}

@ -522,34 +334,19 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
return 0;
}

return fdt32_ld_(php);
}

static const void *fdt_path_getprop_namelen(const void *fdt, const char *path,
const char *propname, int propnamelen,
int *lenp)
{
int offset = fdt_path_offset(fdt, path);

if (offset < 0)
return NULL;

return fdt_getprop_namelen(fdt, offset, propname, propnamelen, lenp);
return fdt32_to_cpu(*php);
}

const char *fdt_get_alias_namelen(const void *fdt,
const char *name, int namelen)
{
int len;
const char *alias;
int aliasoffset;

alias = fdt_path_getprop_namelen(fdt, "/aliases", name, namelen, &len);

if (!can_assume(VALID_DTB) &&
!(alias && len > 0 && alias[len - 1] == '\0' && *alias == '/'))
aliasoffset = fdt_path_offset(fdt, "/aliases");
if (aliasoffset < 0)
return NULL;

return alias;
return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
}

const char *fdt_get_alias(const void *fdt, const char *name)
@ -557,24 +354,13 @@ const char *fdt_get_alias(const void *fdt, const char *name)
return fdt_get_alias_namelen(fdt, name, strlen(name));
}

const char *fdt_get_symbol_namelen(const void *fdt,
const char *name, int namelen)
{
return fdt_path_getprop_namelen(fdt, "/__symbols__", name, namelen, NULL);
}

const char *fdt_get_symbol(const void *fdt, const char *name)
{
return fdt_get_symbol_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_RO_PROBE(fdt);
FDT_CHECK_HEADER(fdt);

if (buflen < 2)
return -FDT_ERR_NOSPACE;
@ -626,7 +412,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
int offset, depth;
int supernodeoffset = -FDT_ERR_INTERNAL;

FDT_RO_PROBE(fdt);
FDT_CHECK_HEADER(fdt);

if (supernodedepth < 0)
return -FDT_ERR_NOTFOUND;
@ -648,12 +434,10 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
}
}

if (!can_assume(VALID_INPUT)) {
if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
return -FDT_ERR_BADOFFSET;
else if (offset == -FDT_ERR_BADOFFSET)
return -FDT_ERR_BADSTRUCTURE;
}

return offset; /* error from fdt_next_node() */
}
@ -665,8 +449,7 @@ int fdt_node_depth(const void *fdt, int nodeoffset)

err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
if (err)
return (can_assume(LIBFDT_FLAWLESS) || err < 0) ? err :
-FDT_ERR_INTERNAL;
return (err < 0) ? err : -FDT_ERR_INTERNAL;
return nodedepth;
}

@ -688,7 +471,7 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
const void *val;
int len;

FDT_RO_PROBE(fdt);
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
@ -711,10 +494,10 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
{
int offset;

if ((phandle == 0) || (phandle == ~0U))
if ((phandle == 0) || (phandle == -1))
return -FDT_ERR_BADPHANDLE;

FDT_RO_PROBE(fdt);
FDT_CHECK_HEADER(fdt);

/* FIXME: The algorithm here is pretty horrible: we
* potentially scan each property of a node in
@ -749,106 +532,6 @@ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str)
return 0;
}

int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
{
const char *list, *end;
int length, count = 0;

list = fdt_getprop(fdt, nodeoffset, property, &length);
if (!list)
return length;

end = list + length;

while (list < end) {
length = strnlen(list, end - list) + 1;

/* Abort if the last string isn't properly NUL-terminated. */
if (list + length > end)
return -FDT_ERR_BADVALUE;

list += length;
count++;
}

return count;
}

int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
const char *string)
{
int length, len, idx = 0;
const char *list, *end;

list = fdt_getprop(fdt, nodeoffset, property, &length);
if (!list)
return length;

len = strlen(string) + 1;
end = list + length;

while (list < end) {
length = strnlen(list, end - list) + 1;

/* Abort if the last string isn't properly NUL-terminated. */
if (list + length > end)
return -FDT_ERR_BADVALUE;

if (length == len && memcmp(list, string, length) == 0)
return idx;

list += length;
idx++;
}

return -FDT_ERR_NOTFOUND;
}

const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
const char *property, int idx,
int *lenp)
{
const char *list, *end;
int length;

list = fdt_getprop(fdt, nodeoffset, property, &length);
if (!list) {
if (lenp)
*lenp = length;

return NULL;
}

end = list + length;

while (list < end) {
length = strnlen(list, end - list) + 1;

/* Abort if the last string isn't properly NUL-terminated. */
if (list + length > end) {
if (lenp)
*lenp = -FDT_ERR_BADVALUE;

return NULL;
}

if (idx == 0) {
if (lenp)
*lenp = length - 1;

return list;
}

list += length;
idx--;
}

if (lenp)
*lenp = -FDT_ERR_NOTFOUND;

return NULL;
}

int fdt_node_check_compatible(const void *fdt, int nodeoffset,
const char *compatible)
{
@ -858,8 +541,10 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset,
prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
if (!prop)
return len;

return !fdt_stringlist_contains(prop, len, compatible);
if (fdt_stringlist_contains(prop, len, compatible))
return 0;
else
return 1;
}

int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
@ -867,7 +552,7 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
{
int offset, err;

FDT_RO_PROBE(fdt);
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

View File

@ -1,7 +1,52 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"

@ -10,7 +55,7 @@

#include "libfdt_internal.h"

static int fdt_blocks_misordered_(const void *fdt,
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))
@ -22,57 +67,52 @@ static int fdt_blocks_misordered_(const void *fdt,
(fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
}

static int fdt_rw_probe_(void *fdt)
static int _fdt_rw_check_header(void *fdt)
{
if (can_assume(VALID_DTB))
return 0;
FDT_RO_PROBE(fdt);
FDT_CHECK_HEADER(fdt);

if (!can_assume(LATEST) && fdt_version(fdt) < 17)
if (fdt_version(fdt) < 17)
return -FDT_ERR_BADVERSION;
if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry),
if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
fdt_size_dt_struct(fdt)))
return -FDT_ERR_BADLAYOUT;
if (!can_assume(LATEST) && fdt_version(fdt) > 17)
if (fdt_version(fdt) > 17)
fdt_set_version(fdt, 17);

return 0;
}

#define FDT_RW_PROBE(fdt) \
#define FDT_RW_CHECK_HEADER(fdt) \
{ \
int err_; \
if ((err_ = fdt_rw_probe_(fdt)) != 0) \
return err_; \
int __err; \
if ((__err = _fdt_rw_check_header(fdt)) != 0) \
return __err; \
}

static inline unsigned int fdt_data_size_(void *fdt)
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)
static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen)
{
char *p = splicepoint;
unsigned int dsize = fdt_data_size_(fdt);
size_t soff = p - (char *)fdt;
char *end = (char *)fdt + _fdt_data_size(fdt);

if ((oldlen < 0) || (soff + oldlen < soff) || (soff + oldlen > dsize))
if (((p + oldlen) < p) || ((p + oldlen) > end))
return -FDT_ERR_BADOFFSET;
if ((p < (char *)fdt) || (dsize + newlen < (unsigned)oldlen))
return -FDT_ERR_BADOFFSET;
if (dsize - oldlen + newlen > fdt_totalsize(fdt))
if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
return -FDT_ERR_NOSPACE;
memmove(p + newlen, p + oldlen, ((char *)fdt + dsize) - (p + oldlen));
memmove(p + newlen, p + oldlen, end - p - oldlen);
return 0;
}

static int fdt_splice_mem_rsv_(void *fdt, struct fdt_reserve_entry *p,
static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
int oldn, int newn)
{
int delta = (newn - oldn) * sizeof(*p);
int err;
err = fdt_splice_(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
if (err)
return err;
fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
@ -80,13 +120,13 @@ static int fdt_splice_mem_rsv_(void *fdt, struct fdt_reserve_entry *p,
return 0;
}

static int fdt_splice_struct_(void *fdt, void *p,
static int _fdt_splice_struct(void *fdt, void *p,
int oldlen, int newlen)
{
int delta = newlen - oldlen;
int err;

if ((err = fdt_splice_(fdt, p, oldlen, newlen)))
if ((err = _fdt_splice(fdt, p, oldlen, newlen)))
return err;

fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
@ -94,63 +134,38 @@ static int fdt_splice_struct_(void *fdt, void *p,
return 0;
}

/* Must only be used to roll back in case of error */
static void fdt_del_last_string_(void *fdt, const char *s)
{
int newlen = strlen(s) + 1;

fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) - newlen);
}

static int fdt_splice_string_(void *fdt, int newlen)
static int _fdt_splice_string(void *fdt, int newlen)
{
void *p = (char *)fdt
+ fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
int err;

if ((err = fdt_splice_(fdt, p, 0, newlen)))
if ((err = _fdt_splice(fdt, p, 0, newlen)))
return err;

fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
return 0;
}

/**
* fdt_find_add_string_() - Find or allocate a string
*
* @fdt: pointer to the device tree to check/adjust
* @s: string to find/add
* @allocated: Set to 0 if the string was found, 1 if not found and so
* allocated. Ignored if can_assume(NO_ROLLBACK)
* @return offset of string in the string table (whether found or added)
*/
static int fdt_find_add_string_(void *fdt, const char *s, int slen,
int *allocated)
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;

if (!can_assume(NO_ROLLBACK))
*allocated = 0;

p = fdt_find_string_len_(strtab, fdt_size_dt_strings(fdt), s, slen);
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, slen + 1);
err = _fdt_splice_string(fdt, len);
if (err)
return err;

if (!can_assume(NO_ROLLBACK))
*allocated = 1;

memcpy(new, s, slen);
new[slen] = '\0';

memcpy(new, s, len);
return (new - strtab);
}

@ -159,10 +174,10 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
struct fdt_reserve_entry *re;
int err;

FDT_RW_PROBE(fdt);
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);
re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
err = _fdt_splice_mem_rsv(fdt, re, 0, 1);
if (err)
return err;

@ -173,29 +188,31 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)

int fdt_del_mem_rsv(void *fdt, int n)
{
struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n);
struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
int err;

FDT_RW_PROBE(fdt);
FDT_RW_CHECK_HEADER(fdt);

if (n >= fdt_num_mem_rsv(fdt))
return -FDT_ERR_NOTFOUND;

return fdt_splice_mem_rsv_(fdt, re, 1, 0);
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 namelen,
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_namelen_w(fdt, nodeoffset, name, namelen,
&oldlen);
if (!*prop)
*prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
if (! (*prop))
return oldlen;

if ((err = fdt_splice_struct_(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
FDT_TAGALIGN(len))))
return err;

@ -203,32 +220,27 @@ static int fdt_resize_property_(void *fdt, int nodeoffset,
return 0;
}

static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
int namelen, int len, struct fdt_property **prop)
static int _fdt_add_property(void *fdt, int nodeoffset, const char *name,
int len, struct fdt_property **prop)
{
int proplen;
int nextoffset;
int namestroff;
int err;
int allocated;

if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
return nextoffset;

namestroff = fdt_find_add_string_(fdt, name, namelen, &allocated);
namestroff = _fdt_find_add_string(fdt, name);
if (namestroff < 0)
return namestroff;

*prop = fdt_offset_ptr_w_(fdt, nextoffset);
*prop = _fdt_offset_ptr_w(fdt, nextoffset);
proplen = sizeof(**prop) + FDT_TAGALIGN(len);

err = fdt_splice_struct_(fdt, *prop, 0, proplen);
if (err) {
/* Delete the string if we failed to add it */
if (!can_assume(NO_ROLLBACK) && allocated)
fdt_del_last_string_(fdt, name);
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);
@ -242,7 +254,7 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name)
int oldlen, newlen;
int err;

FDT_RW_PROBE(fdt);
FDT_RW_CHECK_HEADER(fdt);

namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
if (!namep)
@ -250,7 +262,7 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name)

newlen = strlen(name);

err = fdt_splice_struct_(fdt, namep, FDT_TAGALIGN(oldlen+1),
err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1),
FDT_TAGALIGN(newlen+1));
if (err)
return err;
@ -259,38 +271,21 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name)
return 0;
}

int fdt_setprop_placeholder_namelen(void *fdt, int nodeoffset, const char *name,
int namelen, int len, void **prop_data)
int fdt_setprop(void *fdt, int nodeoffset, const char *name,
const void *val, int len)
{
struct fdt_property *prop;
int err;

FDT_RW_PROBE(fdt);
FDT_RW_CHECK_HEADER(fdt);

err = fdt_resize_property_(fdt, nodeoffset, name, namelen, len, &prop);
err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop);
if (err == -FDT_ERR_NOTFOUND)
err = fdt_add_property_(fdt, nodeoffset, name, namelen, len,
&prop);
err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
if (err)
return err;

*prop_data = prop->data;
return 0;
}

int fdt_setprop_namelen(void *fdt, int nodeoffset, const char *name,
int namelen, const void *val, int len)
{
void *prop_data;
int err;

err = fdt_setprop_placeholder_namelen(fdt, nodeoffset, name, namelen,
len, &prop_data);
if (err)
return err;

if (len)
memcpy(prop_data, val, len);
memcpy(prop->data, val, len);
return 0;
}

@ -300,12 +295,12 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
struct fdt_property *prop;
int err, oldlen, newlen;

FDT_RW_PROBE(fdt);
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,
err = _fdt_splice_struct(fdt, prop->data,
FDT_TAGALIGN(oldlen),
FDT_TAGALIGN(newlen));
if (err)
@ -313,8 +308,7 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
prop->len = cpu_to_fdt32(newlen);
memcpy(prop->data + oldlen, val, len);
} else {
err = fdt_add_property_(fdt, nodeoffset, name, strlen(name),
len, &prop);
err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
if (err)
return err;
memcpy(prop->data, val, len);
@ -327,14 +321,14 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name)
struct fdt_property *prop;
int len, proplen;

FDT_RW_PROBE(fdt);
FDT_RW_CHECK_HEADER(fdt);

prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
if (!prop)
if (! prop)
return len;

proplen = sizeof(*prop) + FDT_TAGALIGN(len);
return fdt_splice_struct_(fdt, prop, proplen, 0);
return _fdt_splice_struct(fdt, prop, proplen, 0);
}

int fdt_add_subnode_namelen(void *fdt, int parentoffset,
@ -347,7 +341,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
uint32_t tag;
fdt32_t *endtag;

FDT_RW_PROBE(fdt);
FDT_RW_CHECK_HEADER(fdt);

offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
if (offset >= 0)
@ -356,19 +350,16 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
return offset;

/* Try to place the new node after the parent's properties */
tag = fdt_next_tag(fdt, parentoffset, &nextoffset);
/* the fdt_subnode_offset_namelen() should ensure this never hits */
if (!can_assume(LIBFDT_FLAWLESS) && (tag != FDT_BEGIN_NODE))
return -FDT_ERR_INTERNAL;
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);
nh = _fdt_offset_ptr_w(fdt, offset);
nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;

err = fdt_splice_struct_(fdt, nh, 0, nodelen);
err = _fdt_splice_struct(fdt, nh, 0, nodelen);
if (err)
return err;

@ -390,20 +381,18 @@ int fdt_del_node(void *fdt, int nodeoffset)
{
int endoffset;

FDT_RW_PROBE(fdt);
FDT_RW_CHECK_HEADER(fdt);

endoffset = fdt_node_end_offset_(fdt, nodeoffset);
endoffset = _fdt_node_end_offset(fdt, nodeoffset);
if (endoffset < 0)
return endoffset;

return fdt_splice_struct_(fdt, fdt_offset_ptr_w_(fdt, nodeoffset),
return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
endoffset - nodeoffset, 0);
}

static void fdt_packblocks_(const char *old, char *new,
int mem_rsv_size,
int struct_size,
int strings_size)
static void _fdt_packblocks(const char *old, char *new,
int mem_rsv_size, int struct_size)
{
int mem_rsv_off, struct_off, strings_off;

@ -418,7 +407,8 @@ static void fdt_packblocks_(const char *old, char *new,
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), strings_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));
}
@ -432,25 +422,22 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
const char *fdtend = fdtstart + fdt_totalsize(fdt);
char *tmp;

FDT_RO_PROBE(fdt);
FDT_CHECK_HEADER(fdt);

mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry);

if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
if (fdt_version(fdt) >= 17) {
struct_size = fdt_size_dt_struct(fdt);
} else if (fdt_version(fdt) == 16) {
} else {
struct_size = 0;
while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
;
if (struct_size < 0)
return struct_size;
} else {
return -FDT_ERR_BADVERSION;
}

if (can_assume(LIBFDT_ORDER) ||
!fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) {
if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
/* no further work necessary */
err = fdt_move(fdt, buf, bufsize);
if (err)
@ -478,8 +465,7 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
return -FDT_ERR_NOSPACE;
}

fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size,
fdt_size_dt_strings(fdt));
_fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size);
memmove(buf, tmp, newsize);

fdt_set_magic(buf, FDT_MAGIC);
@ -495,13 +481,12 @@ int fdt_pack(void *fdt)
{
int mem_rsv_size;

FDT_RW_PROBE(fdt);
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_size_dt_strings(fdt));
fdt_set_totalsize(fdt, fdt_data_size_(fdt));
_fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
fdt_set_totalsize(fdt, _fdt_data_size(fdt));

return 0;
}

View File

@ -1,7 +1,51 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
@ -25,7 +69,6 @@ static struct fdt_errtabent fdt_errtable[] = {

FDT_ERRTABENT(FDT_ERR_BADOFFSET),
FDT_ERRTABENT(FDT_ERR_BADPATH),
FDT_ERRTABENT(FDT_ERR_BADPHANDLE),
FDT_ERRTABENT(FDT_ERR_BADSTATE),

FDT_ERRTABENT(FDT_ERR_TRUNCATED),
@ -33,15 +76,8 @@ static struct fdt_errtabent fdt_errtable[] = {
FDT_ERRTABENT(FDT_ERR_BADVERSION),
FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE),
FDT_ERRTABENT(FDT_ERR_BADLAYOUT),
FDT_ERRTABENT(FDT_ERR_INTERNAL),
FDT_ERRTABENT(FDT_ERR_BADNCELLS),
FDT_ERRTABENT(FDT_ERR_BADVALUE),
FDT_ERRTABENT(FDT_ERR_BADOVERLAY),
FDT_ERRTABENT(FDT_ERR_NOPHANDLES),
FDT_ERRTABENT(FDT_ERR_BADFLAGS),
FDT_ERRTABENT(FDT_ERR_ALIGNMENT),
};
#define FDT_ERRTABSIZE ((int)(sizeof(fdt_errtable) / sizeof(fdt_errtable[0])))
#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))

const char *fdt_strerror(int errval)
{
@ -49,7 +85,7 @@ const char *fdt_strerror(int errval)
return "<valid offset/length>";
else if (errval == 0)
return "<no error>";
else if (-errval < FDT_ERRTABSIZE) {
else if (errval > -FDT_ERRTABSIZE) {
const char *s = fdt_errtable[-errval].str;

if (s)

View File

@ -1,7 +1,52 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"

@ -10,91 +55,25 @@

#include "libfdt_internal.h"

static int fdt_sw_probe_(void *fdt)
static int _fdt_sw_check_header(void *fdt)
{
if (!can_assume(VALID_INPUT)) {
if (fdt_magic(fdt) == FDT_MAGIC)
return -FDT_ERR_BADSTATE;
else if (fdt_magic(fdt) != FDT_SW_MAGIC)
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_PROBE(fdt) \
#define FDT_SW_CHECK_HEADER(fdt) \
{ \
int err; \
if ((err = fdt_sw_probe_(fdt)) != 0) \
if ((err = _fdt_sw_check_header(fdt)) != 0) \
return err; \
}

/* 'memrsv' state: Initial state after fdt_create()
*
* Allowed functions:
* fdt_add_reservemap_entry()
* fdt_finish_reservemap() [moves to 'struct' state]
*/
static int fdt_sw_probe_memrsv_(void *fdt)
static void *_fdt_grab_space(void *fdt, size_t len)
{
int err = fdt_sw_probe_(fdt);
if (err)
return err;

if (!can_assume(VALID_INPUT) && fdt_off_dt_strings(fdt) != 0)
return -FDT_ERR_BADSTATE;
return 0;
}

#define FDT_SW_PROBE_MEMRSV(fdt) \
{ \
int err; \
if ((err = fdt_sw_probe_memrsv_(fdt)) != 0) \
return err; \
}

/* 'struct' state: Enter this state after fdt_finish_reservemap()
*
* Allowed functions:
* fdt_begin_node()
* fdt_end_node()
* fdt_property*()
* fdt_finish() [moves to 'complete' state]
*/
static int fdt_sw_probe_struct_(void *fdt)
{
int err = fdt_sw_probe_(fdt);
if (err)
return err;

if (!can_assume(VALID_INPUT) &&
fdt_off_dt_strings(fdt) != fdt_totalsize(fdt))
return -FDT_ERR_BADSTATE;
return 0;
}

#define FDT_SW_PROBE_STRUCT(fdt) \
{ \
int err; \
if ((err = fdt_sw_probe_struct_(fdt)) != 0) \
return err; \
}

static inline uint32_t sw_flags(void *fdt)
{
/* assert: (fdt_magic(fdt) == FDT_SW_MAGIC) */
return fdt_last_comp_version(fdt);
}

/* 'complete' state: Enter this state after fdt_finish()
*
* Allowed functions: none
*/

static void *fdt_grab_space_(void *fdt, size_t len)
{
unsigned int offset = fdt_size_dt_struct(fdt);
unsigned int spaceleft;
int offset = fdt_size_dt_struct(fdt);
int spaceleft;

spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
- fdt_size_dt_strings(fdt);
@ -103,46 +82,29 @@ static void *fdt_grab_space_(void *fdt, size_t len)
return NULL;

fdt_set_size_dt_struct(fdt, offset + len);
return fdt_offset_ptr_w_(fdt, offset);
}

int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags)
{
const int hdrsize = FDT_ALIGN(sizeof(struct fdt_header),
sizeof(struct fdt_reserve_entry));
void *fdt = buf;

if (bufsize < hdrsize)
return -FDT_ERR_NOSPACE;

if (flags & ~FDT_CREATE_FLAGS_ALL)
return -FDT_ERR_BADFLAGS;

memset(buf, 0, bufsize);

/*
* magic and last_comp_version keep intermediate state during the fdt
* creation process, which is replaced with the proper FDT format by
* fdt_finish().
*
* flags should be accessed with sw_flags().
*/
fdt_set_magic(fdt, FDT_SW_MAGIC);
fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
fdt_set_last_comp_version(fdt, flags);

fdt_set_totalsize(fdt, bufsize);

fdt_set_off_mem_rsvmap(fdt, hdrsize);
fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
fdt_set_off_dt_strings(fdt, 0);

return 0;
return _fdt_offset_ptr_w(fdt, offset);
}

int fdt_create(void *buf, int bufsize)
{
return fdt_create_with_flags(buf, bufsize, 0);
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_resize(void *fdt, void *buf, int bufsize)
@ -150,19 +112,12 @@ int fdt_resize(void *fdt, void *buf, int bufsize)
size_t headsize, tailsize;
char *oldtail, *newtail;

FDT_SW_PROBE(fdt);
FDT_SW_CHECK_HEADER(fdt);

if (bufsize < 0)
return -FDT_ERR_NOSPACE;

headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
headsize = fdt_off_dt_struct(fdt);
tailsize = fdt_size_dt_strings(fdt);

if (!can_assume(VALID_DTB) &&
headsize + tailsize > fdt_totalsize(fdt))
return -FDT_ERR_INTERNAL;

if ((headsize + tailsize) > (unsigned)bufsize)
if ((headsize + tailsize) > bufsize)
return -FDT_ERR_NOSPACE;

oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize;
@ -178,9 +133,8 @@ int fdt_resize(void *fdt, void *buf, int bufsize)
memmove(buf, fdt, headsize);
}

fdt_set_totalsize(buf, bufsize);
if (fdt_off_dt_strings(buf))
fdt_set_off_dt_strings(buf, bufsize);
fdt_set_totalsize(buf, bufsize);

return 0;
}
@ -190,7 +144,10 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
struct fdt_reserve_entry *re;
int offset;

FDT_SW_PROBE_MEMRSV(fdt);
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))
@ -207,24 +164,17 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)

int fdt_finish_reservemap(void *fdt)
{
int err = fdt_add_reservemap_entry(fdt, 0, 0);

if (err)
return err;

fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt));
return 0;
return fdt_add_reservemap_entry(fdt, 0, 0);
}

int fdt_begin_node(void *fdt, const char *name)
{
struct fdt_node_header *nh;
int namelen;
int namelen = strlen(name) + 1;

FDT_SW_PROBE_STRUCT(fdt);
FDT_SW_CHECK_HEADER(fdt);

namelen = strlen(name) + 1;
nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
if (! nh)
return -FDT_ERR_NOSPACE;

@ -237,9 +187,9 @@ int fdt_end_node(void *fdt)
{
fdt32_t *en;

FDT_SW_PROBE_STRUCT(fdt);
FDT_SW_CHECK_HEADER(fdt);

en = fdt_grab_space_(fdt, FDT_TAGSIZE);
en = _fdt_grab_space(fdt, FDT_TAGSIZE);
if (! en)
return -FDT_ERR_NOSPACE;

@ -247,90 +197,48 @@ int fdt_end_node(void *fdt)
return 0;
}

static int fdt_add_string_(void *fdt, const char *s)
static int _fdt_find_add_string(void *fdt, const char *s)
{
char *strtab = (char *)fdt + fdt_totalsize(fdt);
unsigned int strtabsize = fdt_size_dt_strings(fdt);
unsigned int len = strlen(s) + 1;
unsigned int struct_top, offset;

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;
}

/* Must only be used to roll back in case of error */
static void fdt_del_last_string_(void *fdt, const char *s)
{
const char *p;
int strtabsize = fdt_size_dt_strings(fdt);
int len = strlen(s) + 1;
int struct_top, offset;

fdt_set_size_dt_strings(fdt, strtabsize - len);
}

static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
{
char *strtab = (char *)fdt + fdt_totalsize(fdt);
int strtabsize = fdt_size_dt_strings(fdt);
const char *p;

*allocated = 0;

p = fdt_find_string_(strtab - strtabsize, strtabsize, s);
p = _fdt_find_string(strtab - strtabsize, strtabsize, s);
if (p)
return p - strtab;

*allocated = 1;
/* 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 :( */

return fdt_add_string_(fdt, s);
}

int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)
{
struct fdt_property *prop;
int nameoff;
int allocated;

FDT_SW_PROBE_STRUCT(fdt);

/* String de-duplication can be slow, _NO_NAME_DEDUP skips it */
if (sw_flags(fdt) & FDT_CREATE_FLAG_NO_NAME_DEDUP) {
allocated = 1;
nameoff = fdt_add_string_(fdt, name);
} else {
nameoff = fdt_find_add_string_(fdt, name, &allocated);
}
if (nameoff == 0)
return -FDT_ERR_NOSPACE;

prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
if (! prop) {
if (allocated)
fdt_del_last_string_(fdt, name);
return -FDT_ERR_NOSPACE;
}

prop->tag = cpu_to_fdt32(FDT_PROP);
prop->nameoff = cpu_to_fdt32(nameoff);
prop->len = cpu_to_fdt32(len);
*valp = prop->data;
return 0;
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)
{
void *ptr;
int ret;
struct fdt_property *prop;
int nameoff;

ret = fdt_property_placeholder(fdt, name, len, &ptr);
if (ret)
return ret;
memcpy(ptr, val, len);
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;
}

@ -342,10 +250,10 @@ int fdt_finish(void *fdt)
uint32_t tag;
int offset, nextoffset;

FDT_SW_PROBE_STRUCT(fdt);
FDT_SW_CHECK_HEADER(fdt);

/* Add terminator */
end = fdt_grab_space_(fdt, sizeof(*end));
end = _fdt_grab_space(fdt, sizeof(*end));
if (! end)
return -FDT_ERR_NOSPACE;
*end = cpu_to_fdt32(FDT_END);
@ -361,7 +269,7 @@ int fdt_finish(void *fdt)
while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
if (tag == FDT_PROP) {
struct fdt_property *prop =
fdt_offset_ptr_w_(fdt, offset);
_fdt_offset_ptr_w(fdt, offset);
int nameoff;

nameoff = fdt32_to_cpu(prop->nameoff);
@ -375,10 +283,6 @@ int fdt_finish(void *fdt)

/* Finally, adjust the header */
fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));

/* And fix up fields that were keeping intermediate state. */
fdt_set_last_comp_version(fdt, FDT_LAST_COMPATIBLE_VERSION);
fdt_set_magic(fdt, FDT_MAGIC);

return 0;
}

View File

@ -1,7 +1,52 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"

@ -10,45 +55,24 @@

#include "libfdt_internal.h"

int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
const char *name, int namelen,
uint32_t idx, const void *val,
int len)
int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
const void *val, int len)
{
void *propval;
int proplen;

propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen,
&proplen);
if (!propval)
return proplen;

if ((unsigned)proplen < (len + idx))
return -FDT_ERR_NOSPACE;

memcpy((char *)propval + idx, val, len);
return 0;
}

int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
const void *val, int len)
{
const void *propval;
int proplen;

propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
if (!propval)
propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen);
if (! propval)
return proplen;

if (proplen != len)
return -FDT_ERR_NOSPACE;

return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name,
strlen(name), 0,
val, len);
memcpy(propval, val, len);
return 0;
}

static void fdt_nop_region_(void *start, int len)
static void _fdt_nop_region(void *start, int len)
{
fdt32_t *p;

@ -62,15 +86,15 @@ int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
int len;

prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
if (!prop)
if (! prop)
return len;

fdt_nop_region_(prop, len + sizeof(*prop));
_fdt_nop_region(prop, len + sizeof(*prop));

return 0;
}

int fdt_node_end_offset_(void *fdt, int offset)
int _fdt_node_end_offset(void *fdt, int offset)
{
int depth = 0;

@ -84,11 +108,11 @@ int fdt_nop_node(void *fdt, int nodeoffset)
{
int endoffset;

endoffset = fdt_node_end_offset_(fdt, nodeoffset);
endoffset = _fdt_node_end_offset(fdt, nodeoffset);
if (endoffset < 0)
return endoffset;

fdt_nop_region_(fdt_offset_ptr_w(fdt, nodeoffset, 0),
_fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0),
endoffset - nodeoffset);
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,30 +1,72 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
#ifndef LIBFDT_ENV_H
#define LIBFDT_ENV_H
#ifndef _LIBFDT_ENV_H
#define _LIBFDT_ENV_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
* Copyright 2012 Kim Phillips, Freescale Semiconductor.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

#ifdef __CHECKER__
#define FDT_FORCE __attribute__((force))
#define FDT_BITWISE __attribute__((bitwise))
#define __force __attribute__((force))
#define __bitwise __attribute__((bitwise))
#else
#define FDT_FORCE
#define FDT_BITWISE
#define __force
#define __bitwise
#endif

typedef uint16_t FDT_BITWISE fdt16_t;
typedef uint32_t FDT_BITWISE fdt32_t;
typedef uint64_t FDT_BITWISE fdt64_t;
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))
@ -37,60 +79,33 @@ typedef uint64_t FDT_BITWISE fdt64_t;

static inline uint16_t fdt16_to_cpu(fdt16_t x)
{
return (FDT_FORCE uint16_t)CPU_TO_FDT16(x);
return (__force uint16_t)CPU_TO_FDT16(x);
}
static inline fdt16_t cpu_to_fdt16(uint16_t x)
{
return (FDT_FORCE fdt16_t)CPU_TO_FDT16(x);
return (__force fdt16_t)CPU_TO_FDT16(x);
}

static inline uint32_t fdt32_to_cpu(fdt32_t x)
{
return (FDT_FORCE uint32_t)CPU_TO_FDT32(x);
return (__force uint32_t)CPU_TO_FDT32(x);
}
static inline fdt32_t cpu_to_fdt32(uint32_t x)
{
return (FDT_FORCE fdt32_t)CPU_TO_FDT32(x);
return (__force fdt32_t)CPU_TO_FDT32(x);
}

static inline uint64_t fdt64_to_cpu(fdt64_t x)
{
return (FDT_FORCE uint64_t)CPU_TO_FDT64(x);
return (__force uint64_t)CPU_TO_FDT64(x);
}
static inline fdt64_t cpu_to_fdt64(uint64_t x)
{
return (FDT_FORCE fdt64_t)CPU_TO_FDT64(x);
return (__force fdt64_t)CPU_TO_FDT64(x);
}
#undef CPU_TO_FDT64
#undef CPU_TO_FDT32
#undef CPU_TO_FDT16
#undef EXTRACT_BYTE

#ifdef __APPLE__
#include <AvailabilityMacros.h>

/* strnlen() is not available on Mac OS < 10.7 */
# if !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED < \
MAC_OS_X_VERSION_10_7)

#define strnlen fdt_strnlen

/*
* fdt_strnlen: returns the length of a string or max_count - which ever is
* smallest.
* Input 1 string: the string whose size is to be determined
* Input 2 max_count: the maximum value returned by this function
* Output: length of the string or max_count (the smallest of the two)
*/
static inline size_t fdt_strnlen(const char *string, size_t max_count)
{
const char *p = memchr(string, 0, max_count);
return p ? p - string : max_count;
}

#endif /* !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED <
MAC_OS_X_VERSION_10_7) */

#endif /* __APPLE__ */

#endif /* LIBFDT_ENV_H */
#endif /* _LIBFDT_ENV_H */

View File

@ -1,47 +1,83 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
#ifndef LIBFDT_INTERNAL_H
#define LIBFDT_INTERNAL_H
#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))

int32_t fdt_ro_probe_(const void *fdt);
#define FDT_RO_PROBE(fdt) \
#define FDT_CHECK_HEADER(fdt) \
{ \
int32_t totalsize_; \
if ((totalsize_ = fdt_ro_probe_(fdt)) < 0) \
return totalsize_; \
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);
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);

const char *fdt_find_string_len_(const char *strtab, int tabsize, const char *s,
int s_len);
static inline const char *fdt_find_string_(const char *strtab, int tabsize,
const char *s)
{
return fdt_find_string_len_(strtab, tabsize, s, strlen(s));
}

int fdt_node_end_offset_(void *fdt, int nodeoffset);

static inline const void *fdt_offset_ptr_(const void *fdt, int offset)
static inline const void *_fdt_offset_ptr(const void *fdt, int offset)
{
return (const char *)fdt + fdt_off_dt_struct(fdt) + offset;
}

static inline void *fdt_offset_ptr_w_(void *fdt, int offset)
static inline void *_fdt_offset_ptr_w(void *fdt, int offset)
{
return (void *)(uintptr_t)fdt_offset_ptr_(fdt, offset);
return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset);
}

static inline const struct fdt_reserve_entry *fdt_mem_rsv_(const void *fdt, int n)
static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n)
{
const struct fdt_reserve_entry *rsv_table =
(const struct fdt_reserve_entry *)
@ -49,152 +85,11 @@ static inline const struct fdt_reserve_entry *fdt_mem_rsv_(const void *fdt, int

return rsv_table + n;
}
static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n)
static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n)
{
return (void *)(uintptr_t)fdt_mem_rsv_(fdt, n);
}

/*
* Internal helpers to access structural elements of the device tree
* blob (rather than for example reading integers from within property
* values). We assume that we are either given a naturally aligned
* address for the platform or if we are not, we are on a platform
* where unaligned memory reads will be handled in a graceful manner.
* If not the external helpers fdtXX_ld() from libfdt.h can be used
* instead.
*/
static inline uint32_t fdt32_ld_(const fdt32_t *p)
{
return fdt32_to_cpu(*p);
}

static inline uint64_t fdt64_ld_(const fdt64_t *p)
{
return fdt64_to_cpu(*p);
return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n);
}

#define FDT_SW_MAGIC (~FDT_MAGIC)

/**********************************************************************/
/* Checking controls */
/**********************************************************************/

#ifndef FDT_ASSUME_MASK
#define FDT_ASSUME_MASK 0
#endif

/*
* Defines assumptions which can be enabled. Each of these can be enabled
* individually. For maximum safety, don't enable any assumptions!
*
* For minimal code size and no safety, use ASSUME_PERFECT at your own risk.
* You should have another method of validating the device tree, such as a
* signature or hash check before using libfdt.
*
* For situations where security is not a concern it may be safe to enable
* ASSUME_SANE.
*/
enum {
/*
* This does essentially no checks. Only the latest device-tree
* version is correctly handled. Inconsistencies or errors in the device
* tree may cause undefined behaviour or crashes. Invalid parameters
* passed to libfdt may do the same.
*
* If an error occurs when modifying the tree it may leave the tree in
* an intermediate (but valid) state. As an example, adding a property
* where there is insufficient space may result in the property name
* being added to the string table even though the property itself is
* not added to the struct section.
*
* Only use this if you have a fully validated device tree with
* the latest supported version and wish to minimise code size.
*/
ASSUME_PERFECT = 0xff,

/*
* This assumes that the device tree is sane. i.e. header metadata
* and basic hierarchy are correct.
*
* With this assumption enabled, normal device trees produced by libfdt
* and the compiler should be handled safely. Malicious device trees and
* complete garbage may cause libfdt to behave badly or crash. Truncated
* device trees (e.g. those only partially loaded) can also cause
* problems.
*
* Note: Only checks that relate exclusively to the device tree itself
* (not the parameters passed to libfdt) are disabled by this
* assumption. This includes checking headers, tags and the like.
*/
ASSUME_VALID_DTB = 1 << 0,

/*
* This builds on ASSUME_VALID_DTB and further assumes that libfdt
* functions are called with valid parameters, i.e. not trigger
* FDT_ERR_BADOFFSET or offsets that are out of bounds. It disables any
* extensive checking of parameters and the device tree, making various
* assumptions about correctness.
*
* It doesn't make sense to enable this assumption unless
* ASSUME_VALID_DTB is also enabled.
*/
ASSUME_VALID_INPUT = 1 << 1,

/*
* This disables checks for device-tree version and removes all code
* which handles older versions.
*
* Only enable this if you know you have a device tree with the latest
* version.
*/
ASSUME_LATEST = 1 << 2,

/*
* This assumes that it is OK for a failed addition to the device tree,
* due to lack of space or some other problem, to skip any rollback
* steps (such as dropping the property name from the string table).
* This is safe to enable in most circumstances, even though it may
* leave the tree in a sub-optimal state.
*/
ASSUME_NO_ROLLBACK = 1 << 3,

/*
* This assumes that the device tree components appear in a 'convenient'
* order, i.e. the memory reservation block first, then the structure
* block and finally the string block.
*
* This order is not specified by the device-tree specification,
* but is expected by libfdt. The device-tree compiler always created
* device trees with this order.
*
* This assumption disables a check in fdt_open_into() and removes the
* ability to fix the problem there. This is safe if you know that the
* device tree is correctly ordered. See fdt_blocks_misordered_().
*/
ASSUME_LIBFDT_ORDER = 1 << 4,

/*
* This assumes that libfdt itself does not have any internal bugs. It
* drops certain checks that should never be needed unless libfdt has an
* undiscovered bug.
*
* This can generally be considered safe to enable.
*/
ASSUME_LIBFDT_FLAWLESS = 1 << 5,
};

/**
* can_assume_() - check if a particular assumption is enabled
*
* @mask: Mask to check (ASSUME_...)
* @return true if that assumption is enabled, else false
*/
static inline bool can_assume_(int mask)
{
return FDT_ASSUME_MASK & mask;
}

/** helper macros for checking assumptions */
#define can_assume(_assume) can_assume_(ASSUME_ ## _assume)

#endif /* LIBFDT_INTERNAL_H */
#endif /* _LIBFDT_INTERNAL_H */

View File

@ -1,63 +0,0 @@
version_script = '-Wl,--version-script=@0@'.format(meson.current_source_dir() / 'version.lds')
if not cc.has_link_argument(version_script)
version_script = []
endif

sources = files(
'fdt.c',
'fdt_addresses.c',
'fdt_check.c',
'fdt_empty_tree.c',
'fdt_overlay.c',
'fdt_ro.c',
'fdt_rw.c',
'fdt_strerror.c',
'fdt_sw.c',
'fdt_wip.c',
)

link_args = []
if cc.has_link_argument('-Wl,--no-undefined')
link_args += '-Wl,--no-undefined'
else
# -undefined error is the equivalent of --no-undefined for the macOS linker,
# but -undefined would also be understood as a valid argument for GNU ld!
link_args += cc.get_supported_link_arguments('-Wl,-undefined,error')
endif

link_args += version_script
libfdt = library(
'fdt', sources,
version: meson.project_version(),
link_args: link_args,
link_depends: 'version.lds',
install: get_option('default_library') != 'static' or not wheel_only,
)

libfdt_inc = include_directories('.')

libfdt_dep = declare_dependency(
include_directories: libfdt_inc,
link_with: libfdt,
)
meson.override_dependency('libfdt', libfdt_dep)

if not wheel_only
install_headers(
files(
'fdt.h',
'libfdt.h',
'libfdt_env.h',
)
)

pkgconfig = import('pkgconfig')

pkgconfig.generate(
libraries: libfdt,
version: meson.project_version(),
filebase: 'libfdt',
name: 'libfdt',
description: 'Flat Device Tree manipulation',
)
endif

View File

@ -1,43 +0,0 @@
{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"version": 1,
"metadata": {
"authors": [
{
"name": "@VCS_SBOM_AUTHORS@"
}
]
},
"components": [
{
"type": "library",
"bom-ref": "pkg:github/dgibson/libfdt@@VCS_TAG@",
"cpe": "cpe:2.3:a:dgibson:libfdt:@VCS_TAG@:*:*:*:*:*:*:*",
"name": "libfdt",
"version": "@VCS_VERSION@",
"description": "Utility library for reading and manipulating the FDT binary format",
"supplier": {
"name": "libfdt developers"
},
"licenses": [
{
"license": {
"id": "BSD-2-Clause"
}
},
{
"license": {
"id": "GPL-2.0-or-later"
}
}
],
"externalReferences": [
{
"type": "vcs",
"url": "https://github.com/dgibson/dtc"
}
]
}
]
}

View File

@ -1,4 +1,3 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
LIBFDT_1.2 {
global:
fdt_next_node;
@ -9,7 +8,6 @@ LIBFDT_1.2 {
fdt_get_mem_rsv;
fdt_subnode_offset_namelen;
fdt_subnode_offset;
fdt_path_offset_namelen;
fdt_path_offset;
fdt_get_name;
fdt_get_property_namelen;
@ -20,7 +18,6 @@ LIBFDT_1.2 {
fdt_get_alias_namelen;
fdt_get_alias;
fdt_get_path;
fdt_header_size;
fdt_supernode_atdepth_offset;
fdt_node_depth;
fdt_parent_offset;
@ -43,7 +40,6 @@ LIBFDT_1.2 {
fdt_add_mem_rsv;
fdt_del_mem_rsv;
fdt_set_name;
fdt_setprop_namelen;
fdt_setprop;
fdt_delprop;
fdt_add_subnode_namelen;
@ -58,30 +54,7 @@ LIBFDT_1.2 {
fdt_get_property_by_offset;
fdt_getprop_by_offset;
fdt_next_property_offset;
fdt_first_subnode;
fdt_next_subnode;
fdt_address_cells;
fdt_size_cells;
fdt_stringlist_contains;
fdt_stringlist_count;
fdt_stringlist_search;
fdt_stringlist_get;
fdt_resize;
fdt_overlay_apply;
fdt_get_string;
fdt_find_max_phandle;
fdt_generate_phandle;
fdt_check_full;
fdt_setprop_placeholder_namelen;
fdt_setprop_placeholder;
fdt_property_placeholder;
fdt_header_size_;
fdt_appendprop_addrrange;
fdt_setprop_inplace_namelen_partial;
fdt_create_with_flags;
fdt_overlay_target_offset;
fdt_get_symbol;
fdt_get_symbol_namelen;

local:
*;
};

View File

@ -1,10 +1,24 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/

#include "dtc.h"
#include "srcpos.h"

/*
* Tree building functions
@ -36,27 +50,25 @@ void delete_labels(struct label **labels)
label->deleted = 1;
}

struct property *build_property(const char *name, struct data val,
struct srcpos *srcpos)
struct property *build_property(char *name, struct data val)
{
struct property *new = xmalloc(sizeof(*new));

memset(new, 0, sizeof(*new));

new->name = xstrdup(name);
new->name = name;
new->val = val;
new->srcpos = srcpos_copy(srcpos);

return new;
}

struct property *build_property_delete(const char *name)
struct property *build_property_delete(char *name)
{
struct property *new = xmalloc(sizeof(*new));

memset(new, 0, sizeof(*new));

new->name = xstrdup(name);
new->name = name;
new->deleted = 1;

return new;
@ -85,8 +97,7 @@ struct property *reverse_properties(struct property *first)
return head;
}

struct node *build_node(struct property *proplist, struct node *children,
struct srcpos *srcpos)
struct node *build_node(struct property *proplist, struct node *children)
{
struct node *new = xmalloc(sizeof(*new));
struct node *child;
@ -95,7 +106,6 @@ struct node *build_node(struct property *proplist, struct node *children,

new->proplist = reverse_properties(proplist);
new->children = children;
new->srcpos = srcpos_copy(srcpos);

for_each_child(new, child) {
child->parent = new;
@ -104,37 +114,22 @@ struct node *build_node(struct property *proplist, struct node *children,
return new;
}

struct node *build_node_delete(struct srcpos *srcpos)
struct node *build_node_delete(void)
{
struct node *new = xmalloc(sizeof(*new));

memset(new, 0, sizeof(*new));

new->deleted = 1;
new->srcpos = srcpos_copy(srcpos);

return new;
}

struct node *name_node(struct node *node, const char *name)
struct node *name_node(struct node *node, char *name)
{
assert(node->name == NULL);

node->name = xstrdup(name);

return node;
}

struct node *omit_node_if_unused(struct node *node)
{
node->omit_if_unused = 1;

return node;
}

struct node *reference_node(struct node *node)
{
node->is_referenced = 1;
node->name = name;

return node;
}
@ -174,8 +169,6 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)

old_prop->val = new_prop->val;
old_prop->deleted = 0;
srcpos_free(old_prop->srcpos);
old_prop->srcpos = new_prop->srcpos;
free(new_prop);
new_prop = NULL;
break;
@ -211,13 +204,11 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
}
}

/* if no collision occurred, add child to the old node. */
/* if no collision occured, add child to the old node. */
if (new_child)
add_child(old_node, new_child);
}

old_node->srcpos = srcpos_extend(old_node->srcpos, new_node->srcpos);

/* The new node contents are now merged into the old node. Free
* the new node. */
free(new_node);
@ -225,37 +216,6 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
return old_node;
}

struct node * add_orphan_node(struct node *dt, struct node *new_node, char *ref)
{
static unsigned int next_orphan_fragment = 0;
struct node *node;
struct property *p;
struct data d = empty_data;
char *name;

if (ref[0] == '/') {
d = data_add_marker(d, TYPE_STRING, ref);
d = data_append_data(d, ref, strlen(ref) + 1);

p = build_property("target-path", d, NULL);
} else {
d = data_add_marker(d, REF_PHANDLE, ref);
d = data_append_integer(d, 0xffffffff, 32);

p = build_property("target", d, NULL);
}

xasprintf(&name, "fragment@%u",
next_orphan_fragment++);
name_node(new_node, "__overlay__");
node = build_node(p, new_node, NULL);
name_node(node, name);
free(name);

add_child(dt, node);
return dt;
}

struct node *chain_node(struct node *first, struct node *list)
{
assert(first->next_sibling == NULL);
@ -282,7 +242,7 @@ void delete_property_by_name(struct node *node, char *name)
struct property *prop = node->proplist;

while (prop) {
if (streq(prop->name, name)) {
if (!strcmp(prop->name, name)) {
delete_property(prop);
return;
}
@ -315,7 +275,7 @@ void delete_node_by_name(struct node *parent, char *name)
struct node *node = parent->children;

while (node) {
if (streq(node->name, name)) {
if (!strcmp(node->name, name)) {
delete_node(node);
return;
}
@ -336,87 +296,14 @@ void delete_node(struct node *node)
delete_labels(&node->labels);
}

void append_to_property(struct node *node,
char *name, const void *data, int len,
enum markertype type)
{
struct property *p;

p = get_property(node, name);
if (!p) {
p = build_property(name, empty_data, NULL);
add_property(node, p);
}

p->val = data_add_marker(p->val, type, name);
p->val = data_append_data(p->val, data, len);
}

static int append_unique_str_to_property(struct node *node,
char *name, const char *data, int len)
{
struct property *p;

p = get_property(node, name);
if (p) {
const char *s;

if (p->val.len && p->val.val[p->val.len - 1] != '\0')
/* The current content doesn't look like a string */
return -1;

for (s = p->val.val; s < p->val.val + p->val.len; s = strchr(s, '\0') + 1) {
if (strcmp(data, s) == 0)
/* data already contained in node.name */
return 0;
}
} else {
p = build_property(name, empty_data, NULL);
add_property(node, p);
}

p->val = data_add_marker(p->val, TYPE_STRING, name);
p->val = data_append_data(p->val, data, len);

return 0;
}

static int append_unique_u32_to_property(struct node *node, char *name, fdt32_t value)
{
struct property *p;

p = get_property(node, name);
if (p) {
const fdt32_t *v, *val_end = (const fdt32_t *)p->val.val + p->val.len / 4;

if (p->val.len % 4 != 0)
/* The current content doesn't look like a u32 array */
return -1;

for (v = (const void *)p->val.val; v < val_end; v++) {
if (*v == value)
/* value already contained */
return 0;
}
} else {
p = build_property(name, empty_data, NULL);
add_property(node, p);
}

p->val = data_add_marker(p->val, TYPE_UINT32, name);
p->val = data_append_data(p->val, &value, 4);

return 0;
}

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->address = address;
new->size = size;
new->re.address = address;
new->re.size = size;

return new;
}
@ -448,19 +335,17 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
return list;
}

struct dt_info *build_dt_info(unsigned int dtsflags,
struct reserve_info *reservelist,
struct boot_info *build_boot_info(struct reserve_info *reservelist,
struct node *tree, uint32_t boot_cpuid_phys)
{
struct dt_info *dti;
struct boot_info *bi;

dti = xmalloc(sizeof(*dti));
dti->dtsflags = dtsflags;
dti->reservelist = reservelist;
dti->dt = tree;
dti->boot_cpuid_phys = boot_cpuid_phys;
bi = xmalloc(sizeof(*bi));
bi->reservelist = reservelist;
bi->dt = tree;
bi->boot_cpuid_phys = boot_cpuid_phys;

return dti;
return bi;
}

/*
@ -489,13 +374,7 @@ struct property *get_property(struct node *node, const char *propname)
cell_t propval_cell(struct property *prop)
{
assert(prop->val.len == sizeof(cell_t));
return fdt32_to_cpu(*((fdt32_t *)prop->val.val));
}

cell_t propval_cell_n(struct property *prop, unsigned int n)
{
assert(prop->val.len / sizeof(cell_t) > n);
return fdt32_to_cpu(*((fdt32_t *)prop->val.val + n));
return fdt32_to_cpu(*((cell_t *)prop->val.val));
}

struct property *get_property_by_label(struct node *tree, const char *label,
@ -557,7 +436,7 @@ struct node *get_subnode(struct node *node, const char *nodename)
struct node *child;

for_each_child(node, child)
if (streq(child->name, nodename) && !child->deleted)
if (streq(child->name, nodename))
return child;

return NULL;
@ -580,7 +459,7 @@ struct node *get_node_by_path(struct node *tree, const char *path)
p = strchr(path, '/');

for_each_child(tree, child) {
if (p && strprefixeq(path, (size_t)(p - path), child->name))
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;
@ -613,10 +492,7 @@ struct node *get_node_by_phandle(struct node *tree, cell_t phandle)
{
struct node *child, *node;

if (!phandle_is_valid(phandle)) {
assert(generate_fixups);
return NULL;
}
assert((phandle != 0) && (phandle != -1));

if (tree->phandle == phandle) {
if (tree->deleted)
@ -635,62 +511,19 @@ struct node *get_node_by_phandle(struct node *tree, cell_t phandle)

struct node *get_node_by_ref(struct node *tree, const char *ref)
{
struct node *target = tree;
const char *label = NULL, *path = NULL;

if (streq(ref, "/"))
return tree;

if (ref[0] == '/')
path = ref;
else if (ref[0] == '/')
return get_node_by_path(tree, ref);
else
label = ref;

if (label) {
const char *slash = strchr(label, '/');
char *buf = NULL;

if (slash) {
buf = xstrndup(label, slash - label);
label = buf;
path = slash + 1;
}

target = get_node_by_label(tree, label);

free(buf);

if (!target)
return NULL;
}

if (path)
target = get_node_by_path(target, path);

return target;
}

static void add_phandle_property(struct node *node,
const char *name, int format)
{
struct data d;

if (!(phandle_format & format))
return;
if (get_property(node, name))
return;

d = data_add_marker(empty_data, TYPE_UINT32, NULL);
d = data_append_cell(d, node->phandle);

add_property(node, build_property(name, d, NULL));
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 (phandle_is_valid(node->phandle))
if ((node->phandle != 0) && (node->phandle != -1))
return node->phandle;

while (get_node_by_phandle(root, phandle))
@ -698,8 +531,17 @@ cell_t get_node_phandle(struct node *root, struct node *node)

node->phandle = phandle;

add_phandle_property(node, "linux,phandle", PHANDLE_LEGACY);
add_phandle_property(node, "phandle", PHANDLE_EPAPR);
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
@ -738,24 +580,24 @@ static int cmp_reserve_info(const void *ax, const void *bx)
a = *((const struct reserve_info * const *)ax);
b = *((const struct reserve_info * const *)bx);

if (a->address < b->address)
if (a->re.address < b->re.address)
return -1;
else if (a->address > b->address)
else if (a->re.address > b->re.address)
return 1;
else if (a->size < b->size)
else if (a->re.size < b->re.size)
return -1;
else if (a->size > b->size)
else if (a->re.size > b->re.size)
return 1;
else
return 0;
}

static void sort_reserve_entries(struct dt_info *dti)
static void sort_reserve_entries(struct boot_info *bi)
{
struct reserve_info *ri, **tbl;
int n = 0, i = 0;

for (ri = dti->reservelist;
for (ri = bi->reservelist;
ri;
ri = ri->next)
n++;
@ -765,14 +607,14 @@ static void sort_reserve_entries(struct dt_info *dti)

tbl = xmalloc(n * sizeof(*tbl));

for (ri = dti->reservelist;
for (ri = bi->reservelist;
ri;
ri = ri->next)
tbl[i++] = ri;

qsort(tbl, n, sizeof(*tbl), cmp_reserve_info);

dti->reservelist = tbl[0];
bi->reservelist = tbl[0];
for (i = 0; i < (n-1); i++)
tbl[i]->next = tbl[i+1];
tbl[n-1]->next = NULL;
@ -862,280 +704,8 @@ static void sort_node(struct node *node)
sort_node(c);
}

void sort_tree(struct dt_info *dti)
void sort_tree(struct boot_info *bi)
{
sort_reserve_entries(dti);
sort_node(dti->dt);
}

/* utility helper to avoid code duplication */
static struct node *build_and_name_child_node(struct node *parent, const char *name)
{
struct node *node;

node = build_node(NULL, NULL, NULL);
name_node(node, name);
add_child(parent, node);

return node;
}

static struct node *build_root_node(struct node *dt, const char *name)
{
struct node *an;

an = get_subnode(dt, name);
if (!an)
an = build_and_name_child_node(dt, name);

if (!an)
die("Could not build root node /%s\n", name);

return an;
}

static bool any_label_tree(struct dt_info *dti, struct node *node)
{
struct node *c;

if (node->labels)
return true;

for_each_child(node, c)
if (any_label_tree(dti, c))
return true;

return false;
}

static void generate_label_tree_internal(struct dt_info *dti,
struct node *an, struct node *node,
bool allocph)
{
struct node *dt = dti->dt;
struct node *c;
struct property *p;
struct label *l;

/* if there are labels */
if (node->labels) {

/* now add the label in the node */
for_each_label(node->labels, l) {

/* check whether the label already exists */
p = get_property(an, l->label);
if (p) {
fprintf(stderr, "WARNING: label %s already"
" exists in /%s", l->label,
an->name);
continue;
}

/* insert it */
p = build_property(l->label,
data_copy_escape_string(node->fullpath,
strlen(node->fullpath)),
NULL);
add_property(an, p);
}

/* force allocation of a phandle for this node */
if (allocph)
(void)get_node_phandle(dt, node);
}

for_each_child(node, c)
generate_label_tree_internal(dti, an, c, allocph);
}

static bool any_fixup_tree(struct dt_info *dti, struct node *node)
{
struct node *c;
struct property *prop;
struct marker *m;

for_each_property(node, prop) {
m = prop->val.markers;
for_each_marker_of_type(m, REF_PHANDLE) {
if (!get_node_by_ref(dti->dt, m->ref))
return true;
}
}

for_each_child(node, c) {
if (any_fixup_tree(dti, c))
return true;
}

return false;
}

static int add_fixup_entry(struct dt_info *dti, struct node *fn,
struct node *node, struct property *prop,
struct marker *m)
{
char *entry;
int ret;

/* m->ref can only be a REF_PHANDLE, but check anyway */
assert(m->type == REF_PHANDLE);

/* The format only permits fixups for references to label, not
* references to path */
if (strchr(m->ref, '/'))
die("Can't generate fixup for reference to path &{%s}\n",
m->ref);

/* there shouldn't be any ':' in the arguments */
if (strchr(node->fullpath, ':') || strchr(prop->name, ':'))
die("arguments should not contain ':'\n");

xasprintf(&entry, "%s:%s:%u",
node->fullpath, prop->name, m->offset);
ret = append_unique_str_to_property(fn, m->ref, entry, strlen(entry) + 1);

free(entry);

return ret;
}

static int generate_fixups_tree_internal(struct dt_info *dti,
struct node *fn,
struct node *node)
{
struct node *dt = dti->dt;
struct node *c;
struct property *prop;
struct marker *m;
struct node *refnode;
int ret = 0;

for_each_property(node, prop) {
m = prop->val.markers;
for_each_marker_of_type(m, REF_PHANDLE) {
refnode = get_node_by_ref(dt, m->ref);
if (!refnode)
if (add_fixup_entry(dti, fn, node, prop, m))
ret = -1;
}
}

for_each_child(node, c)
if (generate_fixups_tree_internal(dti, fn, c))
ret = -1;

return ret;
}

static bool any_local_fixup_tree(struct dt_info *dti, struct node *node)
{
struct node *c;
struct property *prop;
struct marker *m;

for_each_property(node, prop) {
m = prop->val.markers;
for_each_marker_of_type(m, REF_PHANDLE) {
if (get_node_by_ref(dti->dt, m->ref))
return true;
}
}

for_each_child(node, c) {
if (any_local_fixup_tree(dti, c))
return true;
}

return false;
}

static int add_local_fixup_entry(struct dt_info *dti,
struct node *lfn, struct node *node,
struct property *prop, struct marker *m,
struct node *refnode)
{
struct node *wn, *nwn; /* local fixup node, walk node, new */
fdt32_t value_32;
char **compp;
int i, depth;

/* walk back retrieving depth */
depth = 0;
for (wn = node; wn; wn = wn->parent)
depth++;

/* allocate name array */
compp = xmalloc(sizeof(*compp) * depth);

/* store names in the array */
for (wn = node, i = depth - 1; wn; wn = wn->parent, i--)
compp[i] = wn->name;

/* walk the path components creating nodes if they don't exist */
for (wn = lfn, i = 1; i < depth; i++, wn = nwn) {
/* if no node exists, create it */
nwn = build_root_node(wn, compp[i]);
}

free(compp);

value_32 = cpu_to_fdt32(m->offset);
return append_unique_u32_to_property(wn, prop->name, value_32);
}

static int generate_local_fixups_tree_internal(struct dt_info *dti,
struct node *lfn,
struct node *node)
{
struct node *dt = dti->dt;
struct node *c;
struct property *prop;
struct marker *m;
struct node *refnode;
int ret = 0;

for_each_property(node, prop) {
m = prop->val.markers;
for_each_marker_of_type(m, REF_PHANDLE) {
refnode = get_node_by_ref(dt, m->ref);
if (refnode)
if (add_local_fixup_entry(dti, lfn, node, prop, m, refnode))
ret = -1;
}
}

for_each_child(node, c)
if (generate_local_fixups_tree_internal(dti, lfn, c))
ret = -1;

return ret;
}

void generate_label_tree(struct dt_info *dti, const char *name, bool allocph)
{
if (!any_label_tree(dti, dti->dt))
return;
generate_label_tree_internal(dti, build_root_node(dti->dt, name),
dti->dt, allocph);
}

void generate_fixups_tree(struct dt_info *dti, const char *name)
{
if (!any_fixup_tree(dti, dti->dt))
return;
if (generate_fixups_tree_internal(dti, build_root_node(dti->dt, name), dti->dt))
fprintf(stderr,
"Warning: Preexisting data in %s malformed, some content could not be added.\n",
name);
}

void generate_local_fixups_tree(struct dt_info *dti, const char *name)
{
if (!any_local_fixup_tree(dti, dti->dt))
return;
if (generate_local_fixups_tree_internal(dti, build_root_node(dti->dt, name), dti->dt))
fprintf(stderr,
"Warning: Preexisting data in %s malformed, some content could not be added.\n",
name);
sort_reserve_entries(bi);
sort_node(bi->dt);
}

View File

@ -1,131 +0,0 @@
project('dtc', 'c',
version: files('VERSION.txt'),
license: ['GPL2+', 'BSD-2'],
default_options: ['werror=true', 'default_library=both'],
meson_version: '>=0.57.0'
)

cc = meson.get_compiler('c')

add_project_arguments(
cc.get_supported_arguments([
'-Wpointer-arith',
'-Wcast-qual',
'-Wnested-externs',
'-Wstrict-prototypes',
'-Wmissing-prototypes',
'-Wredundant-decls',
'-Wshadow',
'-Wsuggest-attribute=format',
'-Wwrite-strings',
]),
language: 'c'
)

add_project_arguments(
'-DFDT_ASSUME_MASK=' + get_option('assume-mask').to_string(),
language: 'c'
)

yamltree = 'yamltree.c'
yaml = dependency('yaml-0.1', version: '>=0.2.3', required: get_option('yaml'))
if not yaml.found()
add_project_arguments('-DNO_YAML', language: 'c')
yamltree = []
endif

valgrind = dependency('valgrind', required: get_option('valgrind'))
if not valgrind.found()
add_project_arguments('-DNO_VALGRIND', language: 'c')
endif

py = import('python')
py = py.find_installation(required: get_option('python'))
swig = find_program('swig', required: get_option('python'))
pylibfdt_enabled = not meson.is_cross_build() and py.found() and swig.found() ? true : false
wheel_only = get_option('wheel-only')

version_gen_h = vcs_tag(
command: ['git', 'describe', '--dirty=+'],
input: 'version_gen.h.in',
output: 'version_gen.h',
)

subdir('libfdt')

dtc_tools = []
util_dep = declare_dependency(
sources: ['util.c', version_gen_h],
include_directories: '.',
dependencies: libfdt_dep
)

if get_option('tools') and not wheel_only
flex = find_program('flex', required: true)
bison = find_program('bison', required: true)

lgen = generator(
flex,
output: '@PLAINNAME@.lex.c',
arguments: ['-o', '@OUTPUT@', '@INPUT@'],
)

pgen = generator(
bison,
output: ['@BASENAME@.tab.c', '@BASENAME@.tab.h'],
arguments: ['@INPUT@', '--defines=@OUTPUT1@', '--output=@OUTPUT0@'],
)

if cc.check_header('fnmatch.h')
dtc_tools += executable(
'convert-dtsv0',
[
lgen.process('convert-dtsv0-lexer.l'),
'srcpos.c',
],
dependencies: util_dep,
install: true,
)
endif

dtc_tools += executable(
'dtc',
[
lgen.process('dtc-lexer.l'),
pgen.process('dtc-parser.y'),
'checks.c',
'data.c',
'dtc.c',
'flattree.c',
'fstree.c',
'livetree.c',
'srcpos.c',
'treesource.c',
yamltree,
],
dependencies: [util_dep, yaml],
install: true,
)

foreach e: ['fdtdump', 'fdtget', 'fdtput', 'fdtoverlay']
dtc_tools += executable(e, files(e + '.c'), dependencies: util_dep, install: true)
endforeach

install_data(
'dtdiff',
install_dir: get_option('bindir'),
install_mode: 'rwxr-xr-x',
)
endif

foreach e: dtc_tools
meson.override_find_program(e.name(), e)
endforeach

if pylibfdt_enabled
subdir('pylibfdt')
endif

if get_option('tests')
subdir('tests')
endif

View File

@ -1,14 +0,0 @@
option('tools', type: 'boolean', value: true,
description: 'Build tools')
option('assume-mask', type: 'integer', value: 0,
description: 'Control the assumptions made (e.g. risking security issues) in the code.')
option('yaml', type: 'feature', value: 'auto',
description: 'YAML support')
option('valgrind', type: 'feature', value: 'auto',
description: 'Valgrind support')
option('python', type: 'feature', value: 'auto',
description: 'Build pylibfdt Python library')
option('tests', type: 'boolean', value: true,
description: 'Build tests')
option('wheel-only', type: 'boolean', value: false,
description: 'building from meson-python')

3
pylibfdt/.gitignore vendored
View File

@ -1,3 +0,0 @@
libfdt.py
*.pyc
libfdt_wrap.c

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +0,0 @@
libfdt_c = custom_target(
'swig',
input: 'libfdt.i',
output: ['libfdt.c', 'libfdt.py'],
install: true,
install_dir: [false, py.get_install_dir(pure: false)],
command: [swig, '-python', '-I'+meson.current_source_dir() / '../libfdt', '-o', '@OUTPUT0@', '@INPUT@']
)

nowarn_gen = cc.get_supported_arguments(
'-Wno-cast-qual',
'-Wno-missing-prototypes',
'-Wno-redundant-decls',
)
pylibfdt = py.extension_module(
'_libfdt',
libfdt_c,
c_args: ['-DPY_SSIZE_T_CLEAN'] + nowarn_gen,
dependencies: [libfdt_dep, py.dependency()],
install: true,
)

View File

@ -1,33 +0,0 @@
[build-system]
build-backend = 'mesonpy'
requires = ['meson-python']

[project]
name = 'libfdt'
authors = [
{name = 'Simon Glass', email = 'sjg@chromium.org'},
]
classifiers = [
'Programming Language :: Python :: 3',
'License :: OSI Approved :: BSD License',
'License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)',
'Operating System :: OS Independent',
]
description = 'Python binding for libfdt'
readme = 'README.md'
requires-python = '>=3.8'
dynamic = ['version']

[project.urls]
'homepage' = 'https://git.kernel.org/pub/scm/utils/dtc/dtc.git'

# These arguments are applied only when building a redistributable binary wheel
# for uploading to PyPI. We don't want to install libraries (or headers /
# pkgconfig files / executables) that clash with system C installs, so we
# disable everything other than the python bindings themselves, and build the
# python C-API extension using static linkage to avoid juggling "libdir" /
# LD_LIBRARY_PATH / RPATH around. When building both the C library and the
# python bindings for a distro, `meson setup` will still default to shared
# libraries.
[tool.meson-python.args]
setup = ['-Ddefault_library=static', '-Dwheel-only=true']

View File

@ -1,32 +0,0 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0-or-later

if [ -f /etc/os-release ]
then
. /etc/os-release
else
echo "ERROR: OS name is not provided."
exit 1
fi

if [ "$NAME" = "Arch Linux" ]
then
pacman -Syu --needed --noconfirm bison diffutils flex gcc git libyaml \
make meson pkgconf python python-setuptools-scm swig
elif [ "$NAME" = "Alpine Linux" ]
then
apk add build-base bison flex git yaml yaml-dev python3-dev \
meson py3-setuptools_scm swig
elif [ "$NAME" = "Fedora Linux" ]
then
dnf install -y bison diffutils flex gcc git libyaml libyaml-devel \
make meson python3-devel python3-setuptools swig
elif [ "$NAME" = "Ubuntu" ]
then
apt update
apt install -yq build-essential bison flex git libyaml-dev pkg-config \
meson python3-dev python3-setuptools python3-setuptools-scm swig
else
echo "ERROR: OS name is not provided."
exit 1
fi

View File

@ -1,5 +1,4 @@
#! /bin/sh
# SPDX-License-Identifier: GPL-2.0-or-later

REMOTE_GIT=/pub/scm/utils/dtc/dtc.git
REMOTE_PATH=/pub/software/utils/dtc

View File

@ -1,5 +1,4 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0-or-later
# Print additional version information for non-release trees.

usage() {

232
srcpos.c
View File

@ -1,11 +1,23 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#include <stdio.h>

@ -21,9 +33,6 @@ struct search_path {
/* This is the list of directories that we search for source files */
static struct search_path *search_path_head, **search_path_tail;

/* Detect infinite include recursion. */
#define MAX_SRCFILE_DEPTH (200)
static int srcfile_depth; /* = 0 */

static char *get_dirname(const char *path)
{
@ -42,71 +51,11 @@ static char *get_dirname(const char *path)

FILE *depfile; /* = NULL */
struct srcfile_state *current_srcfile; /* = NULL */
static char *initial_path; /* = NULL */
static int initial_pathlen; /* = 0 */
static bool initial_cpp = true;

static void set_initial_path(char *fname)
{
int i, len = strlen(fname);
/* Detect infinite include recursion. */
#define MAX_SRCFILE_DEPTH (100)
static int srcfile_depth; /* = 0 */

xasprintf(&initial_path, "%s", fname);
initial_pathlen = 0;
for (i = 0; i != len; i++)
if (initial_path[i] == '/')
initial_pathlen++;
}

static char *shorten_to_initial_path(char *fname)
{
char *p1, *p2, *prevslash1 = NULL;
int slashes = 0;

for (p1 = fname, p2 = initial_path; *p1 && *p2; p1++, p2++) {
if (*p1 != *p2)
break;
if (*p1 == '/') {
prevslash1 = p1;
slashes++;
}
}
p1 = prevslash1 + 1;
if (prevslash1) {
int diff = initial_pathlen - slashes, i, j;
int restlen = strlen(fname) - (p1 - fname);
char *res;

res = xmalloc((3 * diff) + restlen + 1);
for (i = 0, j = 0; i != diff; i++) {
res[j++] = '.';
res[j++] = '.';
res[j++] = '/';
}
strcpy(res + j, p1);
return res;
}
return NULL;
}

/**
* Returns true if the given path is an absolute one.
*
* On Windows, it either needs to begin with a forward slash or with a drive
* letter (e.g. "C:").
* On all other operating systems, it must begin with a forward slash to be
* considered an absolute path.
*/
static bool is_absolute_path(const char *path)
{
#ifdef WIN32
return (
path[0] == '/' ||
(((path[0] >= 'A' && path[0] <= 'Z') || (path[0] >= 'a' && path[0] <= 'z')) && path[1] == ':')
);
#else
return (path[0] == '/');
#endif
}

/**
* Try to open a file in a given directory.
@ -123,7 +72,7 @@ static char *try_open(const char *dirname, const char *fname, FILE **fp)
{
char *fullname;

if (!dirname || is_absolute_path(fname))
if (!dirname || fname[0] == '/')
fullname = xstrdup(fname);
else
fullname = join_path(dirname, fname);
@ -180,10 +129,8 @@ FILE *srcfile_relative_open(const char *fname, char **fullnamep)
strerror(errno));
}

if (depfile) {
fputc(' ', depfile);
fprint_path_escaped(depfile, fullname);
}
if (depfile)
fprintf(depfile, " %s", fullname);

if (fullnamep)
*fullnamep = fullname;
@ -210,9 +157,6 @@ void srcfile_push(const char *fname)
srcfile->colno = 1;

current_srcfile = srcfile;

if (srcfile_depth == 1)
set_initial_path(srcfile->name);
}

bool srcfile_pop(void)
@ -253,6 +197,20 @@ void srcfile_add_search_path(const char *dirname)
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;
@ -266,6 +224,9 @@ void srcpos_update(struct srcpos *pos, const char *text, int len)
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++;
}
@ -278,133 +239,57 @@ struct srcpos *
srcpos_copy(struct srcpos *pos)
{
struct srcpos *pos_new;
struct srcfile_state *srcfile_state;

if (!pos)
return NULL;

pos_new = xmalloc(sizeof(struct srcpos));
assert(pos->next == NULL);
memcpy(pos_new, pos, sizeof(struct srcpos));

/* allocate without free */
srcfile_state = xmalloc(sizeof(struct srcfile_state));
memcpy(srcfile_state, pos->file, sizeof(struct srcfile_state));
pos_new->file = srcfile_state;

return pos_new;
}

struct srcpos *srcpos_extend(struct srcpos *pos, struct srcpos *newtail)


void
srcpos_dump(struct srcpos *pos)
{
struct srcpos *p;

if (!pos)
return newtail;

for (p = pos; p->next != NULL; p = p->next);
p->next = newtail;
return 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);
}

void srcpos_free(struct srcpos *pos)
{
struct srcpos *p_next;

while (pos) {
p_next = pos->next;
free(pos);
pos = p_next;
}
}

char *
srcpos_string(struct srcpos *pos)
{
const char *fname = "<no-file>";
char *pos_str;
int rc;

if (pos->file && pos->file->name)
if (pos)
fname = pos->file->name;


if (pos->first_line != pos->last_line)
xasprintf(&pos_str, "%s:%d.%d-%d.%d", fname,
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)
xasprintf(&pos_str, "%s:%d.%d-%d", fname,
rc = asprintf(&pos_str, "%s:%d.%d-%d", fname,
pos->first_line, pos->first_column,
pos->last_column);
else
xasprintf(&pos_str, "%s:%d.%d", fname,
rc = asprintf(&pos_str, "%s:%d.%d", fname,
pos->first_line, pos->first_column);

return pos_str;
}

static char *
srcpos_string_comment(struct srcpos *pos, bool first_line, int level)
{
char *pos_str, *fresh_fname = NULL, *first, *rest;
const char *fname;

if (!pos) {
if (level > 1) {
xasprintf(&pos_str, "<no-file>:<no-line>");
return pos_str;
} else {
return NULL;
}
}

if (!pos->file)
fname = "<no-file>";
else if (!pos->file->name)
fname = "<no-filename>";
else if (level > 1)
fname = pos->file->name;
else {
fresh_fname = shorten_to_initial_path(pos->file->name);
if (fresh_fname)
fname = fresh_fname;
else
fname = pos->file->name;
}

if (level > 1)
xasprintf(&first, "%s:%d:%d-%d:%d", fname,
pos->first_line, pos->first_column,
pos->last_line, pos->last_column);
else
xasprintf(&first, "%s:%d", fname,
first_line ? pos->first_line : pos->last_line);

if (fresh_fname)
free(fresh_fname);

if (pos->next != NULL) {
rest = srcpos_string_comment(pos->next, first_line, level);
xasprintf(&pos_str, "%s, %s", first, rest);
free(first);
free(rest);
} else {
pos_str = first;
}
if (rc == -1)
die("Couldn't allocate in srcpos string");

return pos_str;
}

char *srcpos_string_first(struct srcpos *pos, int level)
{
return srcpos_string_comment(pos, true, level);
}

char *srcpos_string_last(struct srcpos *pos, int level)
{
return srcpos_string_comment(pos, false, level);
}

void srcpos_verror(struct srcpos *pos, const char *prefix,
const char *fmt, va_list va)
{
@ -433,9 +318,4 @@ void srcpos_set_line(char *f, int l)
{
current_srcfile->name = f;
current_srcfile->lineno = l;

if (initial_cpp) {
initial_cpp = false;
set_initial_path(f);
}
}

View File

@ -1,14 +1,27 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/

#ifndef SRCPOS_H
#define SRCPOS_H
#ifndef _SRCPOS_H_
#define _SRCPOS_H_

#include <stdio.h>
#include <stdbool.h>
#include "util.h"

struct srcfile_state {
FILE *f;
@ -60,7 +73,6 @@ struct srcpos {
int last_line;
int last_column;
struct srcfile_state *file;
struct srcpos *next;
};

#define YYLTYPE struct srcpos
@ -80,25 +92,28 @@ struct srcpos {
YYRHSLOC(Rhs, 0).last_column; \
(Current).file = YYRHSLOC (Rhs, 0).file; \
} \
(Current).next = NULL; \
} while (0)


/*
* Fictional source position used for IR nodes that are
* created without otherwise knowing a true source position.
* For example,constant definitions from the command line.
*/
extern struct srcpos srcpos_empty;

extern void srcpos_update(struct srcpos *pos, const char *text, int len);
extern struct srcpos *srcpos_copy(struct srcpos *pos);
extern struct srcpos *srcpos_extend(struct srcpos *new_srcpos,
struct srcpos *old_srcpos);
extern void srcpos_free(struct srcpos *pos);
extern char *srcpos_string(struct srcpos *pos);
extern char *srcpos_string_first(struct srcpos *pos, int level);
extern char *srcpos_string_last(struct srcpos *pos, int level);
extern void srcpos_dump(struct srcpos *pos);


extern void PRINTF(3, 0) srcpos_verror(struct srcpos *pos, const char *prefix,
const char *fmt, va_list va);
extern void PRINTF(3, 4) srcpos_error(struct srcpos *pos, const char *prefix,
const char *fmt, ...);
extern void srcpos_verror(struct srcpos *pos, const char *prefix,
const char *fmt, va_list va)
__attribute__((format(printf, 3, 0)));
extern void srcpos_error(struct srcpos *pos, const char *prefix,
const char *fmt, ...)
__attribute__((format(printf, 3, 4)));

extern void srcpos_set_line(char *f, int l);

#endif /* SRCPOS_H */
#endif /* _SRCPOS_H_ */

19
tests/.gitignore vendored
View File

@ -1,20 +1,13 @@
*.dtb
*.dts.test.s
*.test.dts
*.test.dt.yaml
tmp.*
/fs/
/add_subnode_with_nops
/addr_size_cells
/addr_size_cells2
/appendprop[12]
/appendprop_addrrange
/asm_tree_dump
/boot-cpuid
/char_literal
/check_full
/check_header
/check_path
/del_node
/del_property
/dtbs_equal_ordered
@ -29,10 +22,8 @@ tmp.*
/get_path
/get_phandle
/getprop
/get_prop_offset
/incbin
/integer-expressions
/fs_tree1
/mangle-layout
/move_and_save
/node_check_compatible
@ -44,34 +35,24 @@ tmp.*
/nopulate
/notfound
/open_pack
/overlay
/overlay_bad_fixup
/parent_offset
/path-references
/path_offset
/path_offset_aliases
/phandle_format
/property_iterate
/propname_escapes
/references
/relref_merge
/root_node
/rw_tree1
/rw_oom
/set_name
/setprop
/setprop_inplace
/sized_cells
/string_escapes
/stringlist
/subnode_iterate
/subnode_offset
/supernode_atdepth_offset
/sw_tree1
/sw_states
/truncated_property
/truncated_string
/truncated_memrsv
/utilfdt_test
/value-labels
/get_next_tag_invalid_prop_len

View File

@ -1,51 +1,39 @@
LIB_TESTS_L = get_mem_rsv \
root_node find_property subnode_offset path_offset \
get_name getprop get_prop_offset get_phandle \
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 get_next_tag_invalid_prop_len \
get_alias \
char_literal \
sized_cells \
notfound \
addr_size_cells \
addr_size_cells2 \
appendprop_addrrange \
stringlist \
setprop_inplace nop_property nop_node \
sw_tree1 sw_states \
sw_tree1 \
move_and_save mangle-layout nopulate \
open_pack rw_tree1 rw_oom set_name setprop del_property del_node \
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 relref_merge \
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 \
property_iterate \
subnode_iterate \
overlay overlay_bad_fixup \
check_path check_header check_full \
fs_tree1
subnode_iterate
LIB_TESTS = $(LIB_TESTS_L:%=$(TESTS_PREFIX)%)

LIBTREE_TESTS_L = truncated_property truncated_string truncated_memrsv

LIBTREE_TESTS_L = truncated_property
LIBTREE_TESTS = $(LIBTREE_TESTS_L:%=$(TESTS_PREFIX)%)

ifneq ($(STATIC_BUILD),1)
DL_LIB_TESTS_L = asm_tree_dump value-labels
DL_LIB_TESTS = $(DL_LIB_TESTS_L:%=$(TESTS_PREFIX)%)
endif
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 bad_node_char.dtb bad_node_format.dtb \
bad_prop_char.dtb ovf_size_strings.dtb truncated_property.dtb \
truncated_string.dtb truncated_memrsv.dtb two_roots.dtb named_root.dtb
TESTS_TREES_L = test_tree1.dtb
TESTS_TREES = $(TESTS_TREES_L:%=$(TESTS_PREFIX)%)

TESTS_TARGETS = $(TESTS) $(TESTS_TREES)
@ -53,53 +41,43 @@ TESTS_TARGETS = $(TESTS) $(TESTS_TREES)
TESTS_DEPFILES = $(TESTS:%=%.d) \
$(addprefix $(TESTS_PREFIX),testutils.d trees.d dumptrees.d)

TESTS_CLEANFILES_L = $(STD_CLEANFILES) \
*.dtb *.test.dts *.test.dt.yaml *.dtsv1 tmp.* *.bak \
dumptrees
TESTS_CLEANFILES_L = *.output vglog.* vgcore.* *.dtb *.test.dts *.dtsv1 tmp.*
TESTS_CLEANFILES_L += dumptrees
TESTS_CLEANFILES = $(TESTS) $(TESTS_CLEANFILES_L:%=$(TESTS_PREFIX)%)
TESTS_CLEANDIRS_L = fs
TESTS_CLEANDIRS = $(TESTS_CLEANDIRS_L:%=$(TESTS_PREFIX)%)

.PHONY: tests
tests: $(TESTS) $(TESTS_TREES)

$(LIB_TESTS): %: $(TESTS_PREFIX)testutils.o util.o $(LIBFDT_dep)
$(LIB_TESTS): %: $(TESTS_PREFIX)testutils.o util.o $(LIBFDT_archive)

# Not necessary on all platforms; allow -ldl to be excluded instead of forcing
# other platforms to patch it out.
LIBDL = -ldl
$(DL_LIB_TESTS): %: %.o $(TESTS_PREFIX)testutils.o util.o $(LIBFDT_dep)
$(DL_LIB_TESTS): %: %.o $(TESTS_PREFIX)testutils.o util.o $(LIBFDT_archive)
@$(VECHO) LD [libdl] $@
$(LINK.c) -o $@ $^ $(LIBDL)
$(LINK.c) -o $@ $^ -ldl

$(LIBTREE_TESTS): %: $(TESTS_PREFIX)testutils.o $(TESTS_PREFIX)trees.o \
util.o $(LIBFDT_dep)
util.o $(LIBFDT_archive)

$(TESTS_PREFIX)dumptrees: $(TESTS_PREFIX)trees.o

$(TESTS_TREES): $(TESTS_PREFIX)dumptrees
@$(VECHO) DUMPTREES
cd $(TESTS_PREFIX); ./dumptrees . >/dev/null
cd $(TESTS_PREFIX); ./dumptrees >/dev/null

tests_clean:
@$(VECHO) CLEAN "(tests)"
rm -f $(STD_CLEANFILES:%=$(TESTS_PREFIX)%)
rm -f $(TESTS_CLEANFILES)
rm -rf $(TESTS_CLEANDIRS)

check: tests ${TESTS_BIN} $(TESTS_PYLIBFDT)
check: tests ${TESTS_BIN}
cd $(TESTS_PREFIX); ./run_tests.sh

ifeq ($(NO_VALGRIND),1)
checkm:
@echo "make checkm requires valgrind, but NO_VALGRIND=1"
else
checkm: tests ${TESTS_BIN} $(TESTS_PYLIBFDT)
cd $(TESTS_PREFIX); ./run_tests.sh -m
endif
checkm: tests ${TESTS_BIN}
cd $(TESTS_PREFIX); ./run_tests.sh -m 2>&1 | tee vglog.$$$$

checkv: tests ${TESTS_BIN} $(TESTS_PYLIBFDT)
checkv: tests ${TESTS_BIN}
cd $(TESTS_PREFIX); ./run_tests.sh -v

ifneq ($(DEPTARGETS),)
-include $(TESTS_DEPFILES)
endif


View File

@ -1,8 +1,21 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* libfdt - Flat Device Tree manipulation
* Testcase for fdt_nop_node()
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <stdlib.h>

View File

@ -1,8 +1,21 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* libfdt - Flat Device Tree manipulation
* Testcase for #address-cells and #size-cells handling
* Copyright (C) 2014 David Gibson, <david@gibson.dropbear.id.au>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <stdio.h>
@ -45,12 +58,7 @@ int main(int argc, char *argv[])
fdt = load_blob(argv[1]);

check_node(fdt, "/", 2, 2);
check_node(fdt, "/identity-bus@0", 2, 1);
check_node(fdt, "/identity-bus@0", 2, 2);
check_node(fdt, "/simple-bus@1000000", 2, 1);
check_node(fdt, "/discrete-bus@2000000", 1, 0);
check_node(fdt, "/c0", -FDT_ERR_BADNCELLS, -FDT_ERR_BADNCELLS);
check_node(fdt, "/c1", -FDT_ERR_BADNCELLS, -FDT_ERR_BADNCELLS);
check_node(fdt, "/c2", -FDT_ERR_BADNCELLS, -FDT_ERR_BADNCELLS);
check_node(fdt, "/c3", -FDT_ERR_BADNCELLS, 0);
PASS();
}

View File

@ -1,49 +0,0 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* libfdt - Flat Device Tree manipulation
* Testcase for #address-cells and #size-cells handling
* Copyright (C) 2014 David Gibson, <david@gibson.dropbear.id.au>
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>

#include <libfdt.h>

#include "tests.h"
#include "testdata.h"

static void check_node(const void *fdt, const char *path, int ac, int sc)
{
int offset;
int xac, xsc;

offset = fdt_path_offset(fdt, path);
if (offset < 0)
FAIL("Couldn't find path %s", path);

xac = fdt_address_cells(fdt, offset);
xsc = fdt_size_cells(fdt, offset);

if (xac != ac)
FAIL("Address cells for %s is %d instead of %d\n",
path, xac, ac);
if (xsc != sc)
FAIL("Size cells for %s is %d instead of %d\n",
path, xsc, sc);
}

int main(int argc, char *argv[])
{
void *fdt;

if (argc != 2)
CONFIG("Usage: %s <dtb file>\n", argv[0]);

test_init(argc, argv);
fdt = load_blob(argv[1]);

check_node(fdt, "/", 2, 1);
PASS();
}

View File

@ -12,29 +12,4 @@
#address-cells = <2>;
#size-cells = <1>;
};

discrete-bus@2000000 {
#address-cells = <1>;
#size-cells = <0>;
};

c0@0 {
#address-cells = <1 1>;
#size-cells = <1 1>;
};

c1@0 {
#address-cells = <0x80000000>;
#size-cells = <0x80000000>;
};

c2@0 {
#address-cells = <5>;
#size-cells = <5>;
};

c3@0 {
#address-cells = <0>;
#size-cells = <0>;
};
};

View File

@ -5,10 +5,6 @@
#size-cells = <0>;

aliases {
empty = "";
loop = "loop";
nonull = [626164];
relative = "s1/subsubnode";
s1 = &sub1;
ss1 = &subsub1;
sss1 = &subsubsub1;

View File

@ -1,8 +1,21 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* libfdt - Flat Device Tree manipulation
* Testcase for fdt_appendprop()
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <stdlib.h>

View File

@ -1,8 +1,21 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* libfdt - Flat Device Tree manipulation
* Testcase for fdt_appendprop()
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <stdlib.h>
@ -36,7 +49,6 @@ int main(int argc, char *argv[])

buf = xmalloc(SPACE);
CHECK(fdt_open_into(fdt, buf, SPACE));
free(fdt);
fdt = buf;

CHECK(fdt_appendprop(fdt, 0, "prop-bytes", bytes, sizeof(bytes)));

View File

@ -1,95 +0,0 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* libfdt - Flat Device Tree manipulation
* Testcase for fdt_appendprop_addrrange()
* Copyright (C) 2018 AKASHI Takahiro, Linaro Limited
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>

#include <libfdt.h>

#include "tests.h"
#include "testdata.h"

int main(int argc, char *argv[])
{
void *fdt, *buf;
int offset, xac, xsc, num, i, err;
uint64_t addr, size;

if (argc != 5)
CONFIG("Usage: %s <dtb file> <address-cells> <size-cells> <num>\n",
argv[0]);

test_init(argc, argv);
fdt = load_blob(argv[1]);
xac = strtol(argv[2], NULL, 10);
xsc = strtol(argv[3], NULL, 10);
num = strtol(argv[4], NULL, 10);

buf = xmalloc(0x1000);
if (!buf)
FAIL("Couldn't allocate temporary buffer");
err = fdt_open_into(fdt, buf, 0x1000);
if (err)
FAIL("fdt_open_into(): %s", fdt_strerror(err));
free(fdt);
fdt = buf;

/* Set up */
err = fdt_setprop_cell(fdt, 0, "#address-cells", xac);
if (err)
FAIL("fdt_setprop_cell(\"#address-cells\"): %s",
fdt_strerror(err));
err = fdt_setprop_cell(fdt, 0, "#size-cells", xsc);
if (err)
FAIL("fdt_setprop_cell(\"#size-cells\"): %s",
fdt_strerror(err));

offset = fdt_path_offset(fdt, "/node@1");
if (offset < 0)
FAIL("Couldn't find path %s", "/node@1");

addr = TEST_MEMREGION_ADDR;
if (xac > 1)
addr += TEST_MEMREGION_ADDR_HI;
size = TEST_MEMREGION_SIZE;
if (xsc > 1)
size += TEST_MEMREGION_SIZE_HI;

/*
* Do test
*/
/* 1. repeat append's */
for (i = 0; i < num; i++) {
err = fdt_appendprop_addrrange(fdt, 0, offset,
"prop-memregion", addr, size);
if (err)
FAIL("Failed to append[%d] \"prop-memregion\": %s",
i, fdt_strerror(err));

check_getprop_addrrange(fdt, 0, offset, "prop-memregion",
i + 1);

addr += size;
size += TEST_MEMREGION_SIZE_INC;
}

/* 2. default property name */
addr = TEST_MEMREGION_ADDR;
if (xac > 1)
addr += TEST_MEMREGION_ADDR_HI;
size = TEST_MEMREGION_SIZE;
if (xsc > 1)
size += TEST_MEMREGION_SIZE_HI;

err = fdt_appendprop_addrrange(fdt, 0, offset, "reg", addr, size);
if (err)
FAIL("Failed to set \"reg\": %s", fdt_strerror(err));
check_getprop_addrrange(fdt, 0, offset, "reg", 1);

PASS();
}

View File

@ -1,8 +1,21 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* libfdt - Flat Device Tree manipulation
* Tests if an asm tree built into a shared object matches a given dtb
* Copyright (C) 2008 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <stdlib.h>

View File

@ -1,10 +0,0 @@
/dts-v1/;

/ {
node2 {
chosen {
bootargs = <0xdeadbeef>;
stdout-path = <1>;
};
};
};

View File

@ -1,12 +0,0 @@
/dts-v1/;

/ {
#address-cells = <2>;
#size-cells = <2>;
node {
#address-cells = <1>;
#size-cells = <1>;
ranges;
dma-ranges = <0 0 0 0 0>;
};
};

View File

@ -1,13 +0,0 @@
/dts-v1/;

/ {
gpio: gpio-controller {
#gpio-cells = <3>;
};

node {
nr-gpios = <1>;
foo-gpios = <&gpio>;
bar-gpio = <&gpio 1 2 3>;
};
};

View File

@ -1,22 +0,0 @@
/dts-v1/;
/ {
bar: bar {
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
bar_con: endpoint {
remote-endpoint = <&foo_con>;
};
};
};
};
foo {
port {
foo_con: endpoint {
remote-endpoint = <&bar_con>;
};
};
};
};

View File

@ -1,36 +0,0 @@
/dts-v1/;
/ {
bar: bar {
ports {
#address-cells = <1>;
#size-cells = <1>; // should always be 0
port@1 {
reg = <1 2>; // should always contain only a single cell
bar_con: endpoint {
remote-endpoint = <&foo_con>;
};
};
port@2 {
reg = <2>;
bar_con2: endpoint {
remote-endpoint = <&foo_con2>;
};
};
};
};
foo {
port {
#address-cells = <1>;
#size-cells = <1>; // should always be 0
foo_con: endpoint@1 {
reg = <1 2>; // should always contain only a single cell
remote-endpoint = <&bar_con>;
};
foo_con2: endpoint@2 {
reg = <2>;
remote-endpoint = <&bar_con2>;
};
};

};
};

View File

@ -1,7 +0,0 @@
/dts-v1/;

/ {
foo {
remote-endpoint = <0xdeadbeef>;
};
};

View File

@ -1,2 +0,0 @@
/dts-v1/;
/ { endpoint {}; };

View File

@ -1,14 +0,0 @@
/dts-v1/;

/ {
bar: bar {
port {
bar_con: endpoint {
remote-endpoint = <&foo_con>;
};
};
};
foo_con: endpoint {
remote-endpoint = <&bar_con>;
};
};

View File

@ -1,19 +0,0 @@
/dts-v1/;

/ {

bar: bar {
port {
bar_con: endpoint {
remote-endpoint = <&foo_con>;
};
};
};
foo {
remote-endpoint = <&bar_con>; // misplaced remote-endpoint property
port {
foo_con: endpoint {
};
};
};
};

View File

@ -1,24 +0,0 @@
/dts-v1/;

/ {
ports {
#address-cells = <1>;
#size-cells = <0>;

bad_endpoint: port-a@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;

endpoint@d0 {
reg = <0>;
remote-endpoint = <0xdeadbeef>;
};

};

port@1 {
reg = <0>;
};
};
};

View File

@ -1,12 +0,0 @@
/dts-v1/;

/ {
interrupt-parent = <&intc>;
intc: interrupt-controller {
#interrupt-cells = <3>;
};

node {
interrupts = <1>;
};
};

View File

@ -1,7 +0,0 @@
/dts-v1/;

/ {
intc: interrupt-controller {
interrupt-controller;
};
};

View File

@ -1,20 +0,0 @@
/dts-v1/;

/ {
interrupt-parent = <&intc>;
intc: interrupt-controller {
#interrupt-cells = <3>;
interrupt-controller;
};

node {
#address-cells = <0>;
#interrupt-cells = <1>;
interrupt-map = <1 &intc 1 2 3>;
interrupt-map-mask = <0 0>;

child {
interrupts = <1>;
};
};
};

View File

@ -1,17 +0,0 @@
/dts-v1/;

/ {
interrupt-parent = <&intc>;
intc: interrupt-controller {
};

node {
#address-cells = <0>;
#interrupt-cells = <1>;
interrupt-map = <1 &intc 1 2 3>;

child {
interrupts = <1>;
};
};
};

View File

@ -1,19 +0,0 @@
/dts-v1/;

/ {
interrupt-parent = <&intc>;
intc: interrupt-controller {
#interrupt-cells = <3>;
interrupt-controller;
};

node {
/* Missing #address-cells = <0>; */
#interrupt-cells = <1>;
interrupt-map = <1 &intc 1 2 3>;

child {
interrupts = <1>;
};
};
};

View File

@ -1,5 +0,0 @@
/dts-v1/;

/ {
x = <09>;
};

View File

@ -1,11 +0,0 @@
/dts-v1/;

/ {
intc: interrupt-controller {
#interrupt-cells = <3>;
};

node {
interrupts-extended = <&intc>;
};
};

View File

@ -1,12 +0,0 @@
/dts-v1/;

/ {
mangled {
#address-cells = <0x0>;
#size-cells = <0x0>;

valid {
reg = <0x0 0x4000000>;
};
};
};

View File

@ -4,11 +4,4 @@
device_type = <0xdeadbeef>;
model = <0xdeadbeef>;
status = <0xdeadbeef>;
label = <0xdeadbeef>;

foobar-names = "foo", <1>;

node {
compatible = "good", <0xdeadbeef>;
};
};

View File

@ -32,7 +32,7 @@ _dt_reserve_map:
dt_struct_start:
_dt_struct_start:
.long OF_DT_BEGIN_NODE
.asciz ""
.string ""
.balign 4
.long OF_DT_PROP
.long 0xa
@ -58,7 +58,7 @@ _dt_struct_start:
.long 0x2
.balign 4
.long OF_DT_BEGIN_NODE
.asciz "memory@0"
.string "memory@0"
.balign 4
.long OF_DT_PROP
.long 0x7
@ -77,7 +77,7 @@ _dt_struct_start:
.balign 4
.long OF_DT_END_NODE
.long OF_DT_BEGIN_NODE
.asciz "cpus"
.string "cpus"
.balign 4
.long OF_DT_PROP
.long 0x4
@ -151,22 +151,22 @@ _dt_struct_end:
.globl dt_strings_start
dt_strings_start:
_dt_strings_start:
.asciz "model"
.asciz "compatible"
.asciz "#address-cells"
.asciz "#size-cells"
.asciz "device_type"
.asciz "reg"
.asciz "d10"
.asciz "d23"
.asciz "b101"
.asciz "o17"
.asciz "hd00d"
.asciz "stuff"
.asciz "bad-d-1"
.asciz "bad-d-2"
.asciz "bad-o-1"
.asciz "bad-o-2"
.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:

View File

@ -1,6 +1,19 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* Copyright (C) 2008 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <stdlib.h>

View File

@ -1,7 +0,0 @@
/dts-v1/;

/ {
prop1 = < 0 >;
prop2 = < 0xffffffff >;
prop3 = < 0 >;
};

View File

@ -1,7 +0,0 @@
/dts-v1/;

/ {
prop1 = < (-0xffffffff - 1) >;
prop2 = < (-0xffffffff - 2) >;
prop3 = < ((-0xffffffff - 1) * 2) >;
};

View File

@ -1,9 +1,22 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* libfdt - Flat Device Tree manipulation
* Testcase for character literals in dtc
* Copyright (C) 2006 David Gibson, IBM Corporation.
* Copyright (C) 2011 The Chromium Authors. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <stdio.h>
@ -18,7 +31,7 @@
int main(int argc, char *argv[])
{
void *fdt;
fdt32_t expected_cells[5];
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);

Some files were not shown because too many files have changed in this diff Show More