mirror of
https://github.com/dgibson/dtc.git
synced 2026-07-10 13:29:48 -04:00
Compare commits
35 commits
a26ef6400b
...
66e1201c37
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66e1201c37 | ||
|
|
214372a273 | ||
|
|
4df9ca4c8d | ||
|
|
f116f4800e | ||
|
|
9b53b9a4c2 | ||
|
|
5f919a25d7 | ||
|
|
6c1426dfa9 | ||
|
|
23fd89bc8e | ||
|
|
3ad5ebbdd9 | ||
|
|
4ad496846a | ||
|
|
c0e1d0fd58 | ||
|
|
d245851f06 | ||
|
|
a74b952f94 | ||
|
|
d320877b07 | ||
|
|
84d13508d5 | ||
|
|
8f48565e5c | ||
|
|
25a368100a | ||
|
|
040c1f7e29 | ||
|
|
b1337df195 | ||
|
|
83cdc93ca9 | ||
|
|
1aaa44849b | ||
|
|
dd1c7f1a91 | ||
|
|
7fdf750154 | ||
|
|
5c35036b2c | ||
|
|
f57e7df35d | ||
|
|
2164019f84 | ||
|
|
47d7c01ba8 | ||
|
|
f551be7b39 | ||
|
|
53373d1355 | ||
|
|
caf7465c5d | ||
|
|
5976c4a660 | ||
|
|
5bb5bedd34 | ||
|
|
68b960e299 | ||
|
|
adba02caf5 | ||
|
|
8d15a63e84 |
38 changed files with 1490 additions and 675 deletions
39
.cirrus.yml
39
.cirrus.yml
|
|
@ -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
|
||||
145
.github/workflows/build.yml
vendored
145
.github/workflows/build.yml
vendored
|
|
@ -8,6 +8,8 @@ name: Build test
|
|||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# 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
|
||||
|
|
@ -16,78 +18,93 @@ concurrency:
|
|||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-make:
|
||||
build-linux:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ "alpine", "archlinux", "fedora", "ubuntu" ]
|
||||
build: [ "make", "meson" ]
|
||||
|
||||
container:
|
||||
image: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Install Dependencies
|
||||
run: ./scripts/install-deps.sh
|
||||
|
||||
- name: Build (Make)
|
||||
if: matrix.build == 'make'
|
||||
run: make
|
||||
|
||||
- name: Run check (Make)
|
||||
if: matrix.build == 'make'
|
||||
run: make check
|
||||
|
||||
- name: Setup (Meson)
|
||||
if: matrix.build == 'meson'
|
||||
run: meson setup -D python=enabled -D yaml=enabled build
|
||||
|
||||
- name: Build (Meson)
|
||||
if: matrix.build == 'meson'
|
||||
run: meson compile -C build
|
||||
|
||||
- name: Run check (Meson)
|
||||
if: matrix.build == 'meson'
|
||||
run: if ! meson test -C build; then cat build/meson-logs/testlog.txt; false; fi
|
||||
|
||||
build-macos:
|
||||
runs-on: macos-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
build: [ "make", "meson" ]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
./scripts/install-deps.sh
|
||||
|
||||
- name: Build
|
||||
- name: Build (Make)
|
||||
if: matrix.build == 'make'
|
||||
run: |
|
||||
make
|
||||
|
||||
- name: Run check
|
||||
run: |
|
||||
make check
|
||||
- name: Setup (Meson)
|
||||
if: matrix.build == 'meson'
|
||||
run: meson setup -D python=enabled -D yaml=enabled -D tests=false build
|
||||
|
||||
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
|
||||
- name: Build (Meson)
|
||||
if: matrix.build == 'meson'
|
||||
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 }
|
||||
- { sys: mingw32, swig: false }
|
||||
- { sys: mingw64, swig: true }
|
||||
- { sys: ucrt64, swig: true }
|
||||
- { sys: clang64, swig: true }
|
||||
name: ${{ matrix.sys }}
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
|
@ -105,10 +122,60 @@ jobs:
|
|||
meson:p
|
||||
ninja:p
|
||||
libyaml:p
|
||||
swig:p
|
||||
python-setuptools-scm:p
|
||||
${{ matrix.swig && 'swig:p python-setuptools-scm:p' || '' }}
|
||||
|
||||
- name: '🚧 Build'
|
||||
run: |
|
||||
meson setup -Dtools=true -Dtests=false build
|
||||
meson compile -C build
|
||||
|
||||
build-freebsd:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
version: [ "13.5", "14.3" ]
|
||||
build: [ "make", "meson" ]
|
||||
|
||||
name: FreeBSD ${{ matrix.version }} ${{ matrix.build }} build
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Start VM
|
||||
uses: cross-platform-actions/action@v1
|
||||
with:
|
||||
operating_system: freebsd
|
||||
version: ${{ matrix.version }}
|
||||
shell: sh
|
||||
|
||||
- name: Install Dependencies
|
||||
shell: cpa.sh {0}
|
||||
run: sudo ./scripts/install-deps.sh
|
||||
|
||||
- name: Build (Make)
|
||||
if: matrix.build == 'make'
|
||||
shell: cpa.sh {0}
|
||||
run: gmake
|
||||
|
||||
- name: Run check (Make)
|
||||
if: matrix.build == 'make'
|
||||
shell: cpa.sh {0}
|
||||
run: gmake check
|
||||
|
||||
- name: Setup (Meson)
|
||||
if: matrix.build == 'meson'
|
||||
shell: cpa.sh {0}
|
||||
run: meson setup -D python=enabled -D yaml=enabled build
|
||||
|
||||
- name: Build (Meson)
|
||||
if: matrix.build == 'meson'
|
||||
shell: cpa.sh {0}
|
||||
run: meson compile -C build
|
||||
|
||||
- name: Run check (Meson)
|
||||
if: matrix.build == 'meson'
|
||||
shell: cpa.sh {0}
|
||||
run: if ! meson test -C build; then cat build/meson-logs/testlog.txt; false; fi
|
||||
|
|
|
|||
138
AGENTS.md
Normal file
138
AGENTS.md
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
# AGENTS.md
|
||||
|
||||
This file provides guidance to AI coding assistants when working with
|
||||
code in this repository.
|
||||
|
||||
## Build and Test
|
||||
|
||||
The build system is Meson (the legacy Makefile still works but is
|
||||
deprecated).
|
||||
|
||||
```sh
|
||||
# Configure and build
|
||||
meson setup build
|
||||
meson compile -C build
|
||||
|
||||
# Run all tests
|
||||
meson test -C build
|
||||
|
||||
# Run a specific test suite (libfdt, dtc, fdtget, fdtput, fdtdump, fdtoverlay, pylibfdt, utilfdt, dtbs_equal)
|
||||
meson test -C build dtc
|
||||
meson test -C build libfdt
|
||||
|
||||
# Legacy make (deprecated, still functional)
|
||||
make
|
||||
make check # all tests
|
||||
make checkm # tests under valgrind
|
||||
```
|
||||
|
||||
Optional build dependencies: libyaml (>= 0.2.3) for YAML output,
|
||||
valgrind for memory checking, swig + python3-dev for pylibfdt.
|
||||
|
||||
## Architecture
|
||||
|
||||
The repo contains three main components:
|
||||
|
||||
### dtc (Device Tree Compiler)
|
||||
|
||||
Compiles device tree source (.dts) to binary (.dtb) and vice versa. The pipeline is: parse source → live tree → flatten to blob (or reverse).
|
||||
|
||||
- **Parsing**: `dtc-lexer.l` (flex) + `dtc-parser.y` (bison) produce a live tree from .dts source. `flattree.c` reads .dtb blobs. `fstree.c` reads /proc/device-tree style filesystem trees. `yamltree.c` writes YAML output.
|
||||
|
||||
- **Live tree** (`livetree.c`, `dtc.h`): In-memory representation as `struct node` / `struct property` trees with labels, phandles, and source position tracking. The `struct data` type carries property values with type markers and cross-reference markers.
|
||||
- **Checks** (`checks.c`): ~50 semantic checks registered via `WARNING()`, `ERROR()`, and `CHECK()` macros into a `check_table[]`. Each check declares prerequisite checks, forming a DAG. Checks validate DT conventions (node naming, property types, interrupt structures, etc.). Use `-W`/`-E` flags to promote/demote.
|
||||
- **Output**: `flattree.c` writes .dtb blobs and assembler output. `treesource.c` writes .dts source.
|
||||
|
||||
### libfdt (Flat Device Tree library)
|
||||
|
||||
C library for reading/writing .dtb blobs in-place, dual-licensed
|
||||
GPL-2.0-or-later OR BSD-2-Clause. Used in bootloaders, kernels, and
|
||||
hypervisors where the full compiler isn't available.
|
||||
|
||||
- `fdt_ro.c` — read-only access (property lookup, node traversal)
|
||||
- `fdt_rw.c` — read-write modification of existing blobs
|
||||
- `fdt_sw.c` — sequential-write creation of new blobs
|
||||
- `fdt_wip.c` — "write in place" operations (in-place modification)
|
||||
- `fdt_overlay.c` — device tree overlay application
|
||||
- `fdt_check.c` — blob validation (`fdt_check_full`)
|
||||
- `fdt_addresses.c` — address/size cell helpers
|
||||
- `version.lds` — exported symbol list; new public functions must be added here
|
||||
|
||||
libfdt is designed to be embeddable: `Makefile.libfdt` can be included
|
||||
by external build systems. The `FDT_ASSUME_MASK` controls safety
|
||||
vs. performance tradeoffs (see `libfdt_internal.h`).
|
||||
|
||||
### pylibfdt
|
||||
|
||||
SWIG-generated Python bindings for libfdt
|
||||
(`pylibfdt/libfdt.i`). Functions not supportable by SWIG should be
|
||||
behind `#ifndef SWIG` in `libfdt.h`.
|
||||
|
||||
## Tests
|
||||
|
||||
Tests live in `tests/`. The test runner is `tests/run_tests.sh` which
|
||||
defines test groups: `libfdt_tests`, `dtc_tests`, `fdtget_tests`,
|
||||
`fdtput_tests`, `fdtoverlay_tests`, `pylibfdt_tests`, etc.
|
||||
|
||||
Individual C test programs link against libfdt and use helpers from
|
||||
`tests/testutils.c`. Binary test trees are built from assembler macros
|
||||
in `tests/trees.S` via `tests/dumptrees.c` — if you modify
|
||||
`tests/test_tree1.dts`, you must also update `tests/trees.S`.
|
||||
|
||||
## AI Contribution Policy
|
||||
|
||||
See the "AI Coding Assistants" section in CONTRIBUTING.md. Key rules:
|
||||
|
||||
- **Do not** add `Signed-off-by` tags — only humans can certify the DCO
|
||||
- Use `Assisted-by: AGENT_NAME:MODEL_VERSION [TOOL1] [TOOL2]` for attribution in commit messages
|
||||
- The human submitter is responsible for reviewing all AI-generated code and ensuring license compliance
|
||||
- Do not add `Co-authored-by` tags.
|
||||
|
||||
## Tagging a New Release
|
||||
|
||||
Releases use the `vMAJOR.MINOR.PATCH` tag format (e.g., `v1.7.2`).
|
||||
|
||||
An AI agent can prepare the release; the human maintainer reviews,
|
||||
adds `Signed-off-by`, and signs the tag.
|
||||
|
||||
1. **Update `VERSION.txt` and commit** — run the prepare script:
|
||||
```sh
|
||||
scripts/prepare-release X.Y.Z
|
||||
```
|
||||
This updates `VERSION.txt` and creates the version bump commit
|
||||
(without `Signed-off-by`, per the AI contribution policy).
|
||||
|
||||
2. **Draft the tag message** — write it to a temporary file (e.g.,
|
||||
`tag-message.txt`) for the maintainer to review. The format is:
|
||||
```
|
||||
DTC X.Y.Z
|
||||
|
||||
Changes since vPREV include:
|
||||
* Component
|
||||
- Change description
|
||||
- ...
|
||||
```
|
||||
Group changes by component (dtc, libfdt, pylibfdt, fdtget,
|
||||
fdtoverlay, Build, General, etc.) with a bullet per notable change.
|
||||
Generate the changelog from `git log vPREV..HEAD`.
|
||||
|
||||
3. **Human review** — the maintainer reviews the commit and tag
|
||||
message, then runs the finalize script which amends the commit to
|
||||
add `Signed-off-by`, creates the signed annotated tag, pushes the
|
||||
release commit and tag to origin, and optionally uploads to
|
||||
kernel.org via kup:
|
||||
```sh
|
||||
scripts/finalize-release tag-message.txt
|
||||
```
|
||||
|
||||
Agents must **never** run `scripts/finalize-release` or
|
||||
`scripts/kup-dtc`. These perform signing, push, and upload operations
|
||||
that only a human maintainer may execute.
|
||||
|
||||
## Coding Conventions
|
||||
|
||||
- License: GPL-2.0-or-later for dtc tools; (GPL-2.0-or-later OR BSD-2-Clause) for libfdt
|
||||
- SPDX identifiers on every file
|
||||
- C style follows kernel conventions: tabs for indentation, `lower_case` names
|
||||
- Compiler warnings are errors (`-Werror`)
|
||||
- libfdt functions return negative `FDT_ERR_*` codes on failure (never errno)
|
||||
17
CLAUDE.md
Normal file
17
CLAUDE.md
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# CLAUDE.md
|
||||
|
||||
Read and follow AGENTS.md — it has build instructions, architecture
|
||||
notes, coding conventions, and the AI contribution policy for this
|
||||
project.
|
||||
|
||||
## Claude Code Specifics
|
||||
|
||||
When writing `Assisted-by` commit trailers, use `Claude` as the agent
|
||||
name and the model's short ID as the version. For example:
|
||||
|
||||
```
|
||||
Assisted-by: Claude:claude-opus-4-6
|
||||
```
|
||||
|
||||
Do not use `claude-code`, `Claude Code`, or other variations as the
|
||||
agent name.
|
||||
|
|
@ -77,3 +77,51 @@ 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.
|
||||
|
||||
## AI Coding Assistants
|
||||
|
||||
AI tools helping with dtc/libfdt development must follow the standard
|
||||
contribution process described in this document.
|
||||
|
||||
### Licensing and Legal Requirements
|
||||
|
||||
All contributions must comply with the project's licensing requirements:
|
||||
|
||||
* All code must be compatible with GPL-2.0-or-later
|
||||
* All libfdt code must also be compatible with BSD-2-Clause
|
||||
* Use appropriate SPDX license identifiers
|
||||
|
||||
### Signed-off-by and Developer Certificate of Origin
|
||||
|
||||
AI agents MUST NOT add Signed-off-by tags. Only humans can legally
|
||||
certify the Developer Certificate of Origin (DCO). The human submitter
|
||||
is responsible for:
|
||||
|
||||
* Reviewing all AI-generated code
|
||||
* Ensuring compliance with licensing requirements
|
||||
* Adding their own Signed-off-by tag to certify the DCO
|
||||
* Taking full responsibility for the contribution
|
||||
|
||||
### Attribution
|
||||
|
||||
When AI tools contribute to development, proper attribution helps track
|
||||
the evolving role of AI in the development process. Contributions
|
||||
should include an `Assisted-by` tag in the following format:
|
||||
|
||||
```
|
||||
Assisted-by: AGENT_NAME:MODEL_VERSION [TOOL1] [TOOL2]
|
||||
```
|
||||
|
||||
Where:
|
||||
|
||||
* `AGENT_NAME` is the name of the AI tool or framework
|
||||
* `MODEL_VERSION` is the specific model version used
|
||||
* `[TOOL1] [TOOL2]` are optional specialized analysis tools used
|
||||
(e.g., coccinelle, sparse, smatch, clang-tidy)
|
||||
|
||||
Basic development tools (git, gcc, make, editors) should not be listed.
|
||||
|
||||
Example:
|
||||
```
|
||||
Assisted-by: Claude:claude-3-opus coccinelle sparse
|
||||
```
|
||||
|
|
|
|||
28
Makefile
28
Makefile
|
|
@ -153,6 +153,11 @@ include Makefile.convert-dtsv0
|
|||
include Makefile.dtc
|
||||
include Makefile.utils
|
||||
|
||||
# Flex-generated source triggers -Wsign-compare in its templates
|
||||
dtc-lexer.lex.o: CFLAGS += -Wno-sign-compare
|
||||
convert-dtsv0-lexer.lex.o: CFLAGS += -Wno-sign-compare
|
||||
|
||||
|
||||
BIN += convert-dtsv0
|
||||
BIN += dtc
|
||||
BIN += fdtdump
|
||||
|
|
@ -255,29 +260,6 @@ fdtput: $(FDTPUT_OBJS) $(LIBFDT_dep)
|
|||
|
||||
fdtoverlay: $(FDTOVERLAY_OBJS) $(LIBFDT_dep)
|
||||
|
||||
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 \
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
1.7.2
|
||||
1.8.1
|
||||
|
|
|
|||
4
checks.c
4
checks.c
|
|
@ -324,7 +324,7 @@ ERROR(node_name_chars, check_node_name_chars, NODECHARS);
|
|||
static void check_node_name_chars_strict(struct check *c, struct dt_info *dti,
|
||||
struct node *node)
|
||||
{
|
||||
int n = strspn(node->name, c->data);
|
||||
size_t n = strspn(node->name, c->data);
|
||||
|
||||
if (n < node->basenamelen)
|
||||
FAIL(c, dti, node, "Character '%c' not recommended in node name",
|
||||
|
|
@ -1769,7 +1769,7 @@ static void check_interrupts_property(struct check *c,
|
|||
irq_prop->val.len, (int)(irq_cells * sizeof(cell_t)));
|
||||
}
|
||||
}
|
||||
WARNING(interrupts_property, check_interrupts_property, &phandle_references);
|
||||
WARNING(interrupts_property, check_interrupts_property, NULL, &phandle_references);
|
||||
|
||||
static const struct bus_type graph_port_bus = {
|
||||
.name = "graph-port",
|
||||
|
|
|
|||
|
|
@ -39,8 +39,6 @@ extern bool treesource_error;
|
|||
#define DPRINT(fmt, ...) do { } while (0)
|
||||
#endif
|
||||
|
||||
static int dts_version = 1;
|
||||
|
||||
#define BEGIN_DEFAULT() DPRINT("<V1>\n"); \
|
||||
BEGIN(V1); \
|
||||
|
||||
|
|
@ -101,7 +99,6 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
|
|||
|
||||
<*>"/dts-v1/" {
|
||||
DPRINT("Keyword: /dts-v1/\n");
|
||||
dts_version = 1;
|
||||
BEGIN_DEFAULT();
|
||||
return DT_V1;
|
||||
}
|
||||
|
|
|
|||
2
dtc.h
2
dtc.h
|
|
@ -227,7 +227,7 @@ struct node {
|
|||
struct node *next_sibling;
|
||||
|
||||
char *fullpath;
|
||||
int basenamelen;
|
||||
size_t basenamelen;
|
||||
|
||||
cell_t phandle;
|
||||
int addr_cells, size_cells;
|
||||
|
|
|
|||
|
|
@ -146,8 +146,7 @@ static void dump_blob(void *blob, bool debug)
|
|||
continue;
|
||||
}
|
||||
|
||||
fprintf(stderr, "%*s ** Unknown tag 0x%08"PRIx32"\n", depth * shift, "", tag);
|
||||
break;
|
||||
die("** Unknown tag 0x%08"PRIx32"\n", tag);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -169,7 +168,6 @@ 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 ||
|
||||
|
|
|
|||
|
|
@ -110,6 +110,14 @@ int fdt_check_header(const void *fdt)
|
|||
|| (fdt_totalsize(fdt) > INT_MAX))
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
|
||||
/* memrsv block must be 8 byte aligned */
|
||||
if (fdt_off_mem_rsvmap(fdt) % sizeof(uint64_t))
|
||||
return -FDT_ERR_ALIGNMENT;
|
||||
|
||||
/* Structure block must be 4 byte aligned */
|
||||
if (fdt_off_dt_struct(fdt) % FDT_TAGSIZE)
|
||||
return -FDT_ERR_ALIGNMENT;
|
||||
|
||||
/* Bounds check memrsv block */
|
||||
if (!check_off_(hdrsize, fdt_totalsize(fdt),
|
||||
fdt_off_mem_rsvmap(fdt)))
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ int fdt_check_full(const void *fdt, size_t bufsize)
|
|||
const char *propname;
|
||||
bool expect_end = false;
|
||||
|
||||
if (can_assume(PERFECT))
|
||||
return 0;
|
||||
if (bufsize < FDT_V1_SIZE)
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
if (bufsize < fdt_header_size(fdt))
|
||||
|
|
@ -43,7 +45,7 @@ int fdt_check_full(const void *fdt, size_t bufsize)
|
|||
return nextoffset;
|
||||
|
||||
/* If we see two root nodes, something is wrong */
|
||||
if (expect_end && tag != FDT_END)
|
||||
if (expect_end && tag != FDT_END && tag != FDT_NOP)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
|
||||
switch (tag) {
|
||||
|
|
|
|||
|
|
@ -191,6 +191,8 @@ int fdt_num_mem_rsv(const void *fdt)
|
|||
int i;
|
||||
const struct fdt_reserve_entry *re;
|
||||
|
||||
FDT_RO_PROBE(fdt);
|
||||
|
||||
for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
|
||||
if (fdt64_ld_(&re->size) == 0)
|
||||
return i;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,12 @@ static int fdt_blocks_misordered_(const void *fdt,
|
|||
(fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
|
||||
}
|
||||
|
||||
static void fdt_downgrade_version(void *fdt)
|
||||
{
|
||||
if (!can_assume(LATEST) && fdt_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
|
||||
fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
|
||||
}
|
||||
|
||||
static int fdt_rw_probe_(void *fdt)
|
||||
{
|
||||
if (can_assume(VALID_DTB))
|
||||
|
|
@ -33,9 +39,8 @@ static int fdt_rw_probe_(void *fdt)
|
|||
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)
|
||||
fdt_set_version(fdt, 17);
|
||||
|
||||
fdt_downgrade_version(fdt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -161,7 +166,11 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
|
|||
|
||||
FDT_RW_PROBE(fdt);
|
||||
|
||||
re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt));
|
||||
err = fdt_num_mem_rsv(fdt);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
re = fdt_mem_rsv_w_(fdt, err);
|
||||
err = fdt_splice_mem_rsv_(fdt, re, 0, 1);
|
||||
if (err)
|
||||
return err;
|
||||
|
|
@ -174,10 +183,15 @@ 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);
|
||||
int num;
|
||||
|
||||
FDT_RW_PROBE(fdt);
|
||||
|
||||
if (n >= fdt_num_mem_rsv(fdt))
|
||||
num = fdt_num_mem_rsv(fdt);
|
||||
if (num < 0)
|
||||
return num;
|
||||
|
||||
if (n >= num)
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
|
||||
return fdt_splice_mem_rsv_(fdt, re, 1, 0);
|
||||
|
|
@ -278,6 +292,13 @@ int fdt_setprop_placeholder_namelen(void *fdt, int nodeoffset, const char *name,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int fdt_setprop_placeholder(void *fdt, int nodeoffset,
|
||||
const char *name, int len, void **prop_data)
|
||||
{
|
||||
return fdt_setprop_placeholder_namelen(fdt, nodeoffset, name,
|
||||
strlen(name), len, prop_data);
|
||||
}
|
||||
|
||||
int fdt_setprop_namelen(void *fdt, int nodeoffset, const char *name,
|
||||
int namelen, const void *val, int len)
|
||||
{
|
||||
|
|
@ -294,6 +315,13 @@ int fdt_setprop_namelen(void *fdt, int nodeoffset, const char *name,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int fdt_setprop(void *fdt, int nodeoffset, const char *name,
|
||||
const void *val, int len)
|
||||
{
|
||||
return fdt_setprop_namelen(fdt, nodeoffset, name, strlen(name), val,
|
||||
len);
|
||||
}
|
||||
|
||||
int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
|
||||
const void *val, int len)
|
||||
{
|
||||
|
|
@ -434,8 +462,10 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
|
|||
|
||||
FDT_RO_PROBE(fdt);
|
||||
|
||||
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
|
||||
* sizeof(struct fdt_reserve_entry);
|
||||
err = fdt_num_mem_rsv(fdt);
|
||||
if (err < 0)
|
||||
return err;
|
||||
mem_rsv_size = (err + 1) * sizeof(struct fdt_reserve_entry);
|
||||
|
||||
if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
|
||||
struct_size = fdt_size_dt_struct(fdt);
|
||||
|
|
@ -493,12 +523,14 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
|
|||
|
||||
int fdt_pack(void *fdt)
|
||||
{
|
||||
int mem_rsv_size;
|
||||
int err, mem_rsv_size;
|
||||
|
||||
FDT_RW_PROBE(fdt);
|
||||
|
||||
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
|
||||
* sizeof(struct fdt_reserve_entry);
|
||||
err = fdt_num_mem_rsv(fdt);
|
||||
if (err < 0)
|
||||
return err;
|
||||
mem_rsv_size = (err+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));
|
||||
|
|
|
|||
|
|
@ -330,6 +330,7 @@ int fdt_property(void *fdt, const char *name, const void *val, int len)
|
|||
ret = fdt_property_placeholder(fdt, name, len, &ptr);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (len)
|
||||
memcpy(ptr, val, len);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ int fdt_next_node(const void *fdt, int offset, int *depth);
|
|||
* @fdt: FDT blob
|
||||
* @offset: Offset of node to check
|
||||
*
|
||||
* Return: offset of first subnode, or -FDT_ERR_NOTFOUND if there is none
|
||||
* returns: offset of first subnode, or -FDT_ERR_NOTFOUND if there is none
|
||||
*/
|
||||
int fdt_first_subnode(const void *fdt, int offset);
|
||||
|
||||
|
|
@ -237,7 +237,7 @@ int fdt_first_subnode(const void *fdt, int offset);
|
|||
* After first calling fdt_first_subnode(), call this function repeatedly to
|
||||
* get direct subnodes of a parent node.
|
||||
*
|
||||
* Return: offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more
|
||||
* returns: offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more
|
||||
* subnodes
|
||||
*/
|
||||
int fdt_next_subnode(const void *fdt, int offset);
|
||||
|
|
@ -307,7 +307,7 @@ fdt_set_hdr_(size_dt_struct)
|
|||
* fdt_header_size - return the size of the tree's header
|
||||
* @fdt: pointer to a flattened device tree
|
||||
*
|
||||
* Return: size of DTB header in bytes
|
||||
* returns: size of DTB header in bytes
|
||||
*/
|
||||
size_t fdt_header_size(const void *fdt);
|
||||
|
||||
|
|
@ -315,7 +315,7 @@ size_t fdt_header_size(const void *fdt);
|
|||
* fdt_header_size_ - internal function to get header size from a version number
|
||||
* @version: device tree version number
|
||||
*
|
||||
* Return: size of DTB header in bytes
|
||||
* returns: size of DTB header in bytes
|
||||
*/
|
||||
size_t fdt_header_size_(uint32_t version);
|
||||
|
||||
|
|
@ -462,7 +462,7 @@ static inline uint32_t fdt_get_max_phandle(const void *fdt)
|
|||
* highest phandle value in the device tree blob) will be returned in the
|
||||
* @phandle parameter.
|
||||
*
|
||||
* Return: 0 on success or a negative error-code on failure
|
||||
* returns: 0 on success or a negative error-code on failure
|
||||
*/
|
||||
int fdt_generate_phandle(const void *fdt, uint32_t *phandle);
|
||||
|
||||
|
|
@ -475,7 +475,12 @@ int fdt_generate_phandle(const void *fdt, uint32_t *phandle);
|
|||
* or any other (0,0) entries reserved for expansion.
|
||||
*
|
||||
* returns:
|
||||
* the number of entries
|
||||
* the number of entries, on success
|
||||
* -FDT_ERR_ALIGNMENT,
|
||||
* -FDT_ERR_BADMAGIC,
|
||||
* -FDT_ERR_BADVERSION,
|
||||
* -FDT_ERR_BADSTATE,
|
||||
* -FDT_ERR_TRUNCATED, standard meanings
|
||||
*/
|
||||
int fdt_num_mem_rsv(const void *fdt);
|
||||
|
||||
|
|
@ -510,7 +515,7 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size);
|
|||
* useful for finding subnodes based on a portion of a larger string,
|
||||
* such as a full path.
|
||||
*
|
||||
* Return: offset of the subnode or -FDT_ERR_NOTFOUND if name not found.
|
||||
* returns: offset of the subnode or -FDT_ERR_NOTFOUND if name not found.
|
||||
*/
|
||||
#ifndef SWIG /* Not available in Python */
|
||||
int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
|
||||
|
|
@ -551,7 +556,7 @@ int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name);
|
|||
* Identical to fdt_path_offset(), but only consider the first namelen
|
||||
* characters of path as the path name.
|
||||
*
|
||||
* Return: offset of the node or negative libfdt error value otherwise
|
||||
* returns: offset of the node or negative libfdt error value otherwise
|
||||
*/
|
||||
#ifndef SWIG /* Not available in Python */
|
||||
int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen);
|
||||
|
|
@ -749,7 +754,7 @@ static inline struct fdt_property *fdt_get_property_by_offset_w(void *fdt,
|
|||
* Identical to fdt_get_property(), but only examine the first namelen
|
||||
* characters of name for matching the property name.
|
||||
*
|
||||
* Return: pointer to the structure representing the property, or NULL
|
||||
* returns: pointer to the structure representing the property, or NULL
|
||||
* if not found
|
||||
*/
|
||||
#ifndef SWIG /* Not available in Python */
|
||||
|
|
@ -851,7 +856,7 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
|
|||
* Identical to fdt_getprop(), but only examine the first namelen
|
||||
* characters of name for matching the property name.
|
||||
*
|
||||
* Return: pointer to the property's value or NULL on error
|
||||
* returns: pointer to the property's value or NULL on error
|
||||
*/
|
||||
#ifndef SWIG /* Not available in Python */
|
||||
const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
|
||||
|
|
@ -924,7 +929,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset);
|
|||
* Identical to fdt_get_alias(), but only examine the first @namelen
|
||||
* characters of @name for matching the alias name.
|
||||
*
|
||||
* Return: a pointer to the expansion of the alias named @name, if it exists,
|
||||
* returns: a pointer to the expansion of the alias named @name, if it exists,
|
||||
* NULL otherwise
|
||||
*/
|
||||
#ifndef SWIG /* Not available in Python */
|
||||
|
|
@ -955,7 +960,7 @@ const char *fdt_get_alias(const void *fdt, const char *name);
|
|||
* Identical to fdt_get_symbol(), but only examine the first @namelen
|
||||
* characters of @name for matching the symbol name.
|
||||
*
|
||||
* Return: a pointer to the expansion of the symbol named @name, if it exists,
|
||||
* returns: a pointer to the expansion of the symbol named @name, if it exists,
|
||||
* NULL otherwise
|
||||
*/
|
||||
#ifndef SWIG /* Not available in Python */
|
||||
|
|
@ -1220,7 +1225,7 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
|
|||
* one or more strings, each terminated by \0, as is found in a device tree
|
||||
* "compatible" property.
|
||||
*
|
||||
* Return: 1 if the string is found in the list, 0 not found, or invalid list
|
||||
* returns: 1 if the string is found in the list, 0 not found, or invalid list
|
||||
*/
|
||||
int fdt_stringlist_contains(const char *strlist, int listlen, const char *str);
|
||||
|
||||
|
|
@ -1230,7 +1235,7 @@ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str);
|
|||
* @nodeoffset: offset of a tree node
|
||||
* @property: name of the property containing the string list
|
||||
*
|
||||
* Return:
|
||||
* returns:
|
||||
* the number of strings in the given property
|
||||
* -FDT_ERR_BADVALUE if the property value is not NUL-terminated
|
||||
* -FDT_ERR_NOTFOUND if the property does not exist
|
||||
|
|
@ -1274,7 +1279,7 @@ int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
|
|||
* If non-NULL, the length of the string (on success) or a negative error-code
|
||||
* (on failure) will be stored in the integer pointer to by lenp.
|
||||
*
|
||||
* Return:
|
||||
* returns:
|
||||
* A pointer to the string at the given index in the string list or NULL on
|
||||
* failure. On success the length of the string will be stored in the memory
|
||||
* location pointed to by the lenp parameter, if non-NULL. On failure one of
|
||||
|
|
@ -1364,7 +1369,7 @@ int fdt_size_cells(const void *fdt, int nodeoffset);
|
|||
* of the name. It is useful when you want to manipulate only one value of
|
||||
* an array and you have a string that doesn't end with \0.
|
||||
*
|
||||
* Return: 0 on success, negative libfdt error value otherwise
|
||||
* returns: 0 on success, negative libfdt error value otherwise
|
||||
*/
|
||||
#ifndef SWIG /* Not available in Python */
|
||||
int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
|
||||
|
|
@ -1484,7 +1489,7 @@ static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset,
|
|||
* @val: new value of the 32-bit cell
|
||||
*
|
||||
* This is an alternative name for fdt_setprop_inplace_u32()
|
||||
* Return: 0 on success, negative libfdt error number otherwise.
|
||||
* returns: 0 on success, negative libfdt error number otherwise.
|
||||
*/
|
||||
static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset,
|
||||
const char *name, uint32_t val)
|
||||
|
|
@ -1930,12 +1935,8 @@ int fdt_setprop_namelen(void *fdt, int nodeoffset, const char *name,
|
|||
* -FDT_ERR_BADLAYOUT,
|
||||
* -FDT_ERR_TRUNCATED, standard meanings
|
||||
*/
|
||||
static inline int fdt_setprop(void *fdt, int nodeoffset, const char *name,
|
||||
const void *val, int len)
|
||||
{
|
||||
return fdt_setprop_namelen(fdt, nodeoffset, name, strlen(name), val,
|
||||
len);
|
||||
}
|
||||
int fdt_setprop(void *fdt, int nodeoffset, const char *name,
|
||||
const void *val, int len);
|
||||
|
||||
/**
|
||||
* fdt_setprop_placeholder_namelen - allocate space for a property
|
||||
|
|
@ -1997,13 +1998,8 @@ int fdt_setprop_placeholder_namelen(void *fdt, int nodeoffset, const char *name,
|
|||
* -FDT_ERR_BADLAYOUT,
|
||||
* -FDT_ERR_TRUNCATED, standard meanings
|
||||
*/
|
||||
static inline int fdt_setprop_placeholder(void *fdt, int nodeoffset,
|
||||
const char *name, int len,
|
||||
void **prop_data)
|
||||
{
|
||||
return fdt_setprop_placeholder_namelen(fdt, nodeoffset, name,
|
||||
strlen(name), len, prop_data);
|
||||
}
|
||||
int fdt_setprop_placeholder(void *fdt, int nodeoffset,
|
||||
const char *name, int len, void **prop_data);
|
||||
|
||||
/**
|
||||
* fdt_setprop_u32 - set a property to a 32-bit integer
|
||||
|
|
@ -2084,7 +2080,7 @@ static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name,
|
|||
*
|
||||
* This is an alternative name for fdt_setprop_u32()
|
||||
*
|
||||
* Return: 0 on success, negative libfdt error value otherwise.
|
||||
* returns: 0 on success, negative libfdt error value otherwise.
|
||||
*/
|
||||
static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
|
||||
uint32_t val)
|
||||
|
|
@ -2294,7 +2290,7 @@ static inline int fdt_appendprop_u64(void *fdt, int nodeoffset,
|
|||
*
|
||||
* This is an alternative name for fdt_appendprop_u32()
|
||||
*
|
||||
* Return: 0 on success, negative libfdt error value otherwise.
|
||||
* returns: 0 on success, negative libfdt error value otherwise.
|
||||
*/
|
||||
static inline int fdt_appendprop_cell(void *fdt, int nodeoffset,
|
||||
const char *name, uint32_t val)
|
||||
|
|
@ -2405,7 +2401,7 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name);
|
|||
* creating subnodes based on a portion of a larger string, such as a
|
||||
* full path.
|
||||
*
|
||||
* Return: structure block offset of the created subnode (>=0),
|
||||
* returns: structure block offset of the created subnode (>=0),
|
||||
* negative libfdt error value otherwise
|
||||
*/
|
||||
#ifndef SWIG /* Not available in Python */
|
||||
|
|
|
|||
|
|
@ -1234,7 +1234,7 @@ void fixup_phandles(struct dt_info *dti, const char *name)
|
|||
continue;
|
||||
|
||||
offset = strtol(soffset, NULL, 0);
|
||||
if (offset < 0 || offset + 4 > p->val.len) {
|
||||
if (offset < 0 || (unsigned int)offset + 4 > p->val.len) {
|
||||
if (quiet < 1)
|
||||
fprintf(stderr,
|
||||
"Warning: Label %s contains invalid offset for property %s in node %s\n",
|
||||
|
|
|
|||
98
scripts/finalize-release
Executable file
98
scripts/finalize-release
Executable file
|
|
@ -0,0 +1,98 @@
|
|||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# Finalize a release (possibly prepared with AI agent assistance)
|
||||
# Amends the version bump commit to add Signed-off-by, then creates a
|
||||
# signed annotated tag from the drafted tag message.
|
||||
|
||||
set -e
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 <tag-message-file>" >&2
|
||||
echo "" >&2
|
||||
echo "Run this from the repository root with VERSION.txt updated" >&2
|
||||
echo "and a draft tag message in given file." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
TAG_MSG_FILE="$1"
|
||||
if [ -z "$TAG_MSG_FILE" ] || [ ! -f "$TAG_MSG_FILE" ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
VERSION=$(cat VERSION.txt)
|
||||
TAG="v${VERSION}"
|
||||
|
||||
if git rev-parse "$TAG" >/dev/null 2>&1; then
|
||||
echo "Error: tag $TAG already exists" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
HEAD_SUBJECT=$(git log -1 --format=%s)
|
||||
EXPECTED="Bump version to $TAG"
|
||||
if [ "$HEAD_SUBJECT" != "$EXPECTED" ]; then
|
||||
echo "Error: HEAD commit subject is:" >&2
|
||||
echo " $HEAD_SUBJECT" >&2
|
||||
echo "Expected:" >&2
|
||||
echo " $EXPECTED" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Version: $VERSION"
|
||||
echo "Tag: $TAG"
|
||||
echo ""
|
||||
echo "--- Tag message ---"
|
||||
cat "$TAG_MSG_FILE"
|
||||
echo "--- End tag message ---"
|
||||
echo ""
|
||||
|
||||
printf "Proceed? [y/N] "
|
||||
read answer
|
||||
case "$answer" in
|
||||
y|Y) ;;
|
||||
*) echo "Aborted."; exit 1 ;;
|
||||
esac
|
||||
|
||||
git commit --amend -s --no-edit
|
||||
git tag -s "$TAG" -F "$TAG_MSG_FILE"
|
||||
|
||||
echo ""
|
||||
echo "Created signed tag $TAG."
|
||||
echo "Review with: git show $TAG"
|
||||
echo ""
|
||||
|
||||
git push origin main "$TAG"
|
||||
git push github main "$TAG"
|
||||
git push gitlab main "$TAG"
|
||||
|
||||
SCRIPTDIR=$(dirname "$0")
|
||||
|
||||
printf "Upload to kernel.org via kup? [y/N] "
|
||||
read answer
|
||||
case "$answer" in
|
||||
y|Y) "$SCRIPTDIR/kup-dtc" "$VERSION" ;;
|
||||
*) echo "Skipping kup upload." ;;
|
||||
esac
|
||||
|
||||
TAG_BODY=$(git tag -l --format='%(contents:body)' "$TAG")
|
||||
|
||||
ANNOUNCE="announce-${TAG}.txt"
|
||||
cat > "$ANNOUNCE" <<MAIL
|
||||
To: devicetree-compiler@vger.kernel.org
|
||||
Subject: DTC $VERSION released
|
||||
|
||||
DTC $VERSION is now available.
|
||||
|
||||
Git tree:
|
||||
https://git.kernel.org/pub/scm/utils/dtc/dtc.git
|
||||
|
||||
Tagged release ($TAG):
|
||||
https://git.kernel.org/pub/scm/utils/dtc/dtc.git/tag/?h=$TAG
|
||||
|
||||
Tarball:
|
||||
https://kernel.org/pub/software/utils/dtc/dtc-${VERSION}.tar.gz
|
||||
|
||||
$TAG_BODY
|
||||
MAIL
|
||||
|
||||
echo "Announcement draft written to $ANNOUNCE"
|
||||
|
|
@ -1,6 +1,19 @@
|
|||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
if [ "$(uname -s)" = "Darwin" ]
|
||||
then
|
||||
brew install --quiet libyaml swig meson ninja pkg-config
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$(uname -s)" = "FreeBSD" ]
|
||||
then
|
||||
pkg install -y git gmake flex bison meson ninja \
|
||||
python3 py312-setuptools swig libyaml pkgconf
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -f /etc/os-release ]
|
||||
then
|
||||
. /etc/os-release
|
||||
|
|
|
|||
70
scripts/prepare-release
Executable file
70
scripts/prepare-release
Executable file
|
|
@ -0,0 +1,70 @@
|
|||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# Prepare a release: update VERSION.txt and create the version bump
|
||||
# commit. This handles steps 1 and 2 of the release procedure in
|
||||
# AGENTS.md. Step 3 (drafting the tag message) requires judgement to
|
||||
# categorise and summarise changes, so is left to the caller.
|
||||
|
||||
set -e
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 <version>" >&2
|
||||
echo "" >&2
|
||||
echo " version X.Y.Z or vX.Y.Z" >&2
|
||||
echo "" >&2
|
||||
echo "Example: $0 1.8.1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
RAW="$1"
|
||||
if [ -z "$RAW" ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
VERSION="${RAW#v}"
|
||||
|
||||
case "$VERSION" in
|
||||
[0-9]*.[0-9]*.[0-9]*)
|
||||
;;
|
||||
*)
|
||||
echo "Error: version '$VERSION' does not look like X.Y.Z" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
TAG="v${VERSION}"
|
||||
|
||||
if git rev-parse "$TAG" >/dev/null 2>&1; then
|
||||
echo "Error: tag $TAG already exists" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! git diff-index --quiet HEAD; then
|
||||
echo "Error: working tree is dirty; commit or stash first" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "$VERSION" > VERSION.txt
|
||||
git add VERSION.txt
|
||||
git commit -m "$(cat <<EOF
|
||||
Bump version to $TAG
|
||||
|
||||
Prepare for a new release.
|
||||
EOF
|
||||
)"
|
||||
|
||||
echo "Building with make..."
|
||||
git clean -fdx
|
||||
make check
|
||||
|
||||
echo ""
|
||||
echo "Building with meson..."
|
||||
git clean -fdx
|
||||
meson setup build
|
||||
meson test -C build
|
||||
|
||||
echo ""
|
||||
echo "All builds and tests passed."
|
||||
echo "Next: draft the tag message to tag-message.txt, then run:"
|
||||
echo " scripts/finalize-release tag-message.txt"
|
||||
2
tests/.gitignore
vendored
2
tests/.gitignore
vendored
|
|
@ -69,9 +69,11 @@ tmp.*
|
|||
/supernode_atdepth_offset
|
||||
/sw_tree1
|
||||
/sw_states
|
||||
/treegen
|
||||
/truncated_property
|
||||
/truncated_string
|
||||
/truncated_memrsv
|
||||
/unterminated_memrsv
|
||||
/utilfdt_test
|
||||
/value-labels
|
||||
/get_next_tag_invalid_prop_len
|
||||
|
|
|
|||
|
|
@ -29,33 +29,32 @@ LIB_TESTS_L = get_mem_rsv \
|
|||
subnode_iterate \
|
||||
overlay overlay_bad_fixup \
|
||||
check_path check_header check_full \
|
||||
fs_tree1
|
||||
fs_tree1 \
|
||||
truncated_property truncated_string \
|
||||
truncated_memrsv unterminated_memrsv
|
||||
LIB_TESTS = $(LIB_TESTS_L:%=$(TESTS_PREFIX)%)
|
||||
|
||||
LIBTREE_TESTS_L = truncated_property truncated_string truncated_memrsv
|
||||
|
||||
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
|
||||
|
||||
TESTS = $(LIB_TESTS) $(LIBTREE_TESTS) $(DL_LIB_TESTS)
|
||||
TESTS = $(LIB_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
|
||||
truncated_string.dtb truncated_memrsv.dtb unterminated_memrsv.dtb \
|
||||
two_roots.dtb named_root.dtb
|
||||
TESTS_TREES = $(TESTS_TREES_L:%=$(TESTS_PREFIX)%)
|
||||
|
||||
TESTS_TARGETS = $(TESTS) $(TESTS_TREES)
|
||||
|
||||
TESTS_DEPFILES = $(TESTS:%=%.d) \
|
||||
$(addprefix $(TESTS_PREFIX),testutils.d trees.d dumptrees.d)
|
||||
$(addprefix $(TESTS_PREFIX),testutils.d)
|
||||
|
||||
TESTS_CLEANFILES_L = $(STD_CLEANFILES) \
|
||||
*.dtb *.test.dts *.test.dt.yaml *.dtsv1 tmp.* *.bak \
|
||||
dumptrees
|
||||
treegen
|
||||
TESTS_CLEANFILES = $(TESTS) $(TESTS_CLEANFILES_L:%=$(TESTS_PREFIX)%)
|
||||
TESTS_CLEANDIRS_L = fs
|
||||
TESTS_CLEANDIRS = $(TESTS_CLEANDIRS_L:%=$(TESTS_PREFIX)%)
|
||||
|
|
@ -72,14 +71,9 @@ $(DL_LIB_TESTS): %: %.o $(TESTS_PREFIX)testutils.o util.o $(LIBFDT_dep)
|
|||
@$(VECHO) LD [libdl] $@
|
||||
$(LINK.c) -o $@ $^ $(LIBDL)
|
||||
|
||||
$(LIBTREE_TESTS): %: $(TESTS_PREFIX)testutils.o $(TESTS_PREFIX)trees.o \
|
||||
util.o $(LIBFDT_dep)
|
||||
|
||||
$(TESTS_PREFIX)dumptrees: $(TESTS_PREFIX)trees.o
|
||||
|
||||
$(TESTS_TREES): $(TESTS_PREFIX)dumptrees
|
||||
@$(VECHO) DUMPTREES
|
||||
cd $(TESTS_PREFIX); ./dumptrees . >/dev/null
|
||||
$(TESTS_TREES): $(TESTS_PREFIX)treegen
|
||||
@$(VECHO) TREEGEN
|
||||
cd $(TESTS_PREFIX); ./treegen . >/dev/null
|
||||
|
||||
tests_clean:
|
||||
@$(VECHO) CLEAN "(tests)"
|
||||
|
|
|
|||
|
|
@ -1,69 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* dumptrees - utility for libfdt testing
|
||||
*
|
||||
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2006.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "testdata.h"
|
||||
|
||||
static struct {
|
||||
void *blob;
|
||||
const char *filename;
|
||||
} trees[] = {
|
||||
#define TREE(name) { &name, #name ".dtb" }
|
||||
TREE(test_tree1),
|
||||
TREE(bad_node_char), TREE(bad_node_format), TREE(bad_prop_char),
|
||||
TREE(ovf_size_strings),
|
||||
TREE(truncated_property), TREE(truncated_string),
|
||||
TREE(truncated_memrsv),
|
||||
TREE(two_roots),
|
||||
TREE(named_root)
|
||||
};
|
||||
|
||||
#define NUM_TREES (sizeof(trees) / sizeof(trees[0]))
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Missing output directory argument\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (chdir(argv[1]) != 0) {
|
||||
perror("chdir()");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_TREES; i++) {
|
||||
void *blob = trees[i].blob;
|
||||
const char *filename = trees[i].filename;
|
||||
int size;
|
||||
int fd;
|
||||
int ret;
|
||||
|
||||
size = fdt_totalsize(blob);
|
||||
|
||||
printf("Tree \"%s\", %d bytes\n", filename, size);
|
||||
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||
if (fd < 0)
|
||||
perror("open()");
|
||||
|
||||
ret = write(fd, blob, size);
|
||||
if (ret != size)
|
||||
perror("write()");
|
||||
|
||||
close(fd);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
|
@ -24,7 +24,11 @@ static void start_dir(const char *name)
|
|||
{
|
||||
int rc;
|
||||
|
||||
#ifndef _WIN32
|
||||
rc = mkdir(name, 0777);
|
||||
#else
|
||||
rc = mkdir(name);
|
||||
#endif
|
||||
if (rc != 0)
|
||||
FAIL("mkdir(\"%s\"): %s", name, strerror(errno));
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,14 @@
|
|||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
/*
|
||||
* Some of these trip the -Wconstant-logical-operand warning introduced in gcc
|
||||
* 17. Disable it temporarily, we also have to disable -Wpragmas for the
|
||||
* benefit of older compiler versions that don't know about that warning.
|
||||
*/
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpragmas"
|
||||
#pragma GCC diagnostic ignored "-Wconstant-logical-operand"
|
||||
static struct test_expr {
|
||||
const char *expr;
|
||||
uint32_t result;
|
||||
|
|
@ -51,6 +59,7 @@ static struct test_expr {
|
|||
TE(11 * 257 * 1321517ULL),
|
||||
TE(123456790 - 4/2 + 17%4),
|
||||
};
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,10 @@
|
|||
trees = static_library('trees', files('trees.S'),
|
||||
treegen = executable('treegen', files('treegen.c'),
|
||||
build_by_default: false,
|
||||
include_directories: libfdt_inc)
|
||||
dependencies: [util_dep])
|
||||
|
||||
dumptrees = executable('dumptrees', files('dumptrees.c'),
|
||||
build_by_default: false,
|
||||
link_with: trees, dependencies: libfdt_dep)
|
||||
|
||||
dumptrees_dtb = custom_target(
|
||||
'dumptrees',
|
||||
command: [dumptrees, meson.current_build_dir()],
|
||||
treegen_dtb = custom_target(
|
||||
'treegen_dtb',
|
||||
command: [treegen, meson.current_build_dir()],
|
||||
output: [
|
||||
'test_tree1.dtb',
|
||||
'bad_node_char.dtb',
|
||||
|
|
@ -18,10 +14,13 @@ dumptrees_dtb = custom_target(
|
|||
'truncated_property.dtb',
|
||||
'truncated_string.dtb',
|
||||
'truncated_memrsv.dtb',
|
||||
'unterminated_memrsv.dtb',
|
||||
'two_roots.dtb',
|
||||
'named_root.dtb',
|
||||
]
|
||||
)
|
||||
|
||||
testutil_dep = declare_dependency(sources: ['testutils.c'], link_with: trees)
|
||||
testutil_dep = declare_dependency(sources: ['testutils.c'])
|
||||
|
||||
tests = [
|
||||
'add_subnode_with_nops',
|
||||
|
|
@ -89,13 +88,11 @@ tests = [
|
|||
'supernode_atdepth_offset',
|
||||
'sw_states',
|
||||
'sw_tree1',
|
||||
'utilfdt_test',
|
||||
]
|
||||
|
||||
tests += [
|
||||
'truncated_memrsv',
|
||||
'truncated_property',
|
||||
'truncated_string',
|
||||
'unterminated_memrsv',
|
||||
'utilfdt_test',
|
||||
]
|
||||
|
||||
test_deps = [testutil_dep, util_dep, libfdt_dep]
|
||||
|
|
@ -140,10 +137,10 @@ run_test_types = [
|
|||
'fdtget',
|
||||
'fdtput',
|
||||
'fdtdump',
|
||||
'fdtoverlay'
|
||||
'fdtoverlay',
|
||||
]
|
||||
run_test_deps = [
|
||||
dtc_tools, dumptrees_dtb, tests_exe
|
||||
dtc_tools, treegen_dtb, tests_exe,
|
||||
]
|
||||
if pylibfdt_enabled
|
||||
run_test_types += 'pylibfdt'
|
||||
|
|
|
|||
|
|
@ -13,26 +13,15 @@ sys.path.insert(0, '../pylibfdt')
|
|||
import libfdt
|
||||
from libfdt import Fdt, FdtSw, FdtException, QUIET_NOTFOUND, QUIET_ALL
|
||||
|
||||
TEST_ADDR_1H = 0xdeadbeef
|
||||
TEST_ADDR_1L = 0x00000000
|
||||
TEST_ADDR_1 = (TEST_ADDR_1H << 32) | TEST_ADDR_1L
|
||||
TEST_ADDR_1 = 0x8000000000000000
|
||||
TEST_SIZE_1H = 0x00000000
|
||||
TEST_SIZE_1L = 0x00100000
|
||||
TEST_SIZE_1 = (TEST_SIZE_1H << 32) | TEST_SIZE_1L
|
||||
TEST_ADDR_2H = 0
|
||||
TEST_ADDR_2L = 123456789
|
||||
TEST_ADDR_2 = (TEST_ADDR_2H << 32) | TEST_ADDR_2L
|
||||
TEST_SIZE_2H = 0
|
||||
TEST_SIZE_2L = 0o10000
|
||||
TEST_SIZE_2 = (TEST_SIZE_2H << 32) | TEST_SIZE_2L
|
||||
TEST_SIZE_1 = 0x0000000000100000
|
||||
TEST_ADDR_2 = 123456789
|
||||
TEST_SIZE_2 = 0o10000
|
||||
|
||||
TEST_VALUE_1 = 0xdeadbeef
|
||||
TEST_VALUE_2 = 123456789
|
||||
|
||||
TEST_VALUE64_1H = 0xdeadbeef
|
||||
TEST_VALUE64_1L = 0x01abcdef
|
||||
TEST_VALUE64_1 = (TEST_VALUE64_1H << 32) | TEST_VALUE64_1L
|
||||
TEST_VALUE64_1 = 0xdeadbeef01abcdef
|
||||
|
||||
PHANDLE_1 = 0x2000
|
||||
PHANDLE_2 = 0x2001
|
||||
|
|
|
|||
|
|
@ -492,9 +492,10 @@ libfdt_tests () {
|
|||
run_test appendprop_addrrange unit-addr-without-reg.dtb 2 1 3
|
||||
|
||||
# Tests for behaviour on various sorts of corrupted trees
|
||||
run_test truncated_property
|
||||
run_test truncated_string
|
||||
run_test truncated_memrsv
|
||||
run_test truncated_property truncated_property.dtb
|
||||
run_test truncated_string truncated_string.dtb
|
||||
run_test truncated_memrsv truncated_memrsv.dtb
|
||||
run_test unterminated_memrsv unterminated_memrsv.dtb
|
||||
|
||||
# Check aliases support in fdt_path_offset
|
||||
run_dtc_test -I dts -O dtb -o aliases.dtb "$SRCDIR/aliases.dts"
|
||||
|
|
|
|||
|
|
@ -1,28 +1,12 @@
|
|||
#ifdef __ASSEMBLER__
|
||||
#define ASM_CONST_LL(x) (x)
|
||||
#else
|
||||
#define ASM_CONST_LL(x) (x##ULL)
|
||||
#endif
|
||||
|
||||
#define TEST_ADDR_1H ASM_CONST_LL(0xdeadbeef)
|
||||
#define TEST_ADDR_1L ASM_CONST_LL(0x00000000)
|
||||
#define TEST_ADDR_1 ((TEST_ADDR_1H << 32) | TEST_ADDR_1L)
|
||||
#define TEST_SIZE_1H ASM_CONST_LL(0x00000000)
|
||||
#define TEST_SIZE_1L ASM_CONST_LL(0x00100000)
|
||||
#define TEST_SIZE_1 ((TEST_SIZE_1H << 32) | TEST_SIZE_1L)
|
||||
#define TEST_ADDR_2H ASM_CONST_LL(0)
|
||||
#define TEST_ADDR_2L ASM_CONST_LL(123456789)
|
||||
#define TEST_ADDR_2 ((TEST_ADDR_2H << 32) | TEST_ADDR_2L)
|
||||
#define TEST_SIZE_2H ASM_CONST_LL(0)
|
||||
#define TEST_SIZE_2L ASM_CONST_LL(010000)
|
||||
#define TEST_SIZE_2 ((TEST_SIZE_2H << 32) | TEST_SIZE_2L)
|
||||
#define TEST_ADDR_1 0xdeadbeef00000000ULL
|
||||
#define TEST_SIZE_1 0x0000000000100000ULL
|
||||
#define TEST_ADDR_2 123456789ULL
|
||||
#define TEST_SIZE_2 010000ULL
|
||||
|
||||
#define TEST_VALUE_1 0xdeadbeef
|
||||
#define TEST_VALUE_2 123456789
|
||||
|
||||
#define TEST_VALUE64_1H ASM_CONST_LL(0xdeadbeef)
|
||||
#define TEST_VALUE64_1L ASM_CONST_LL(0x01abcdef)
|
||||
#define TEST_VALUE64_1 ((TEST_VALUE64_1H << 32) | TEST_VALUE64_1L)
|
||||
#define TEST_VALUE64_1 0xdeadbeef01abcdefULL
|
||||
|
||||
#define PHANDLE_1 0x2000
|
||||
#define PHANDLE_2 0x2001
|
||||
|
|
@ -45,16 +29,3 @@
|
|||
#define TEST_MEMREGION_SIZE 0x9abcdef0
|
||||
#define TEST_MEMREGION_SIZE_HI 0x0fedcba900000000
|
||||
#define TEST_MEMREGION_SIZE_INC 0x1000
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
extern struct fdt_header test_tree1;
|
||||
extern struct fdt_header truncated_property;
|
||||
extern struct fdt_header bad_node_char;
|
||||
extern struct fdt_header bad_node_format;
|
||||
extern struct fdt_header bad_prop_char;
|
||||
extern struct fdt_header ovf_size_strings;
|
||||
extern struct fdt_header truncated_string;
|
||||
extern struct fdt_header truncated_memrsv;
|
||||
extern struct fdt_header two_roots;
|
||||
extern struct fdt_header named_root;
|
||||
#endif /* ! __ASSEMBLER__ */
|
||||
|
|
|
|||
|
|
@ -25,9 +25,6 @@ void test_init(int argc, char *argv[]);
|
|||
|
||||
#define streq(s1, s2) (strcmp((s1),(s2)) == 0)
|
||||
|
||||
/* Each test case must define this function */
|
||||
void cleanup(void);
|
||||
|
||||
#define verbose_printf(...) \
|
||||
if (verbose_test) { \
|
||||
printf(__VA_ARGS__); \
|
||||
|
|
@ -39,21 +36,18 @@ void cleanup(void);
|
|||
|
||||
#define PASS() \
|
||||
do { \
|
||||
cleanup(); \
|
||||
printf("PASS\n"); \
|
||||
exit(RC_PASS); \
|
||||
} while (0)
|
||||
|
||||
#define PASS_INCONCLUSIVE() \
|
||||
do { \
|
||||
cleanup(); \
|
||||
printf("PASS (inconclusive)\n"); \
|
||||
exit(RC_PASS); \
|
||||
} while (0)
|
||||
|
||||
#define IRRELEVANT() \
|
||||
do { \
|
||||
cleanup(); \
|
||||
printf("PASS (irrelevant)\n"); \
|
||||
exit(RC_PASS); \
|
||||
} while (0)
|
||||
|
|
@ -61,21 +55,18 @@ void cleanup(void);
|
|||
/* Look out, gcc extension below... */
|
||||
#define FAIL(fmt, ...) \
|
||||
do { \
|
||||
cleanup(); \
|
||||
printf("FAIL\t" fmt "\n", ##__VA_ARGS__); \
|
||||
exit(RC_FAIL); \
|
||||
} while (0)
|
||||
|
||||
#define CONFIG(fmt, ...) \
|
||||
do { \
|
||||
cleanup(); \
|
||||
printf("Bad configuration: " fmt "\n", ##__VA_ARGS__); \
|
||||
exit(RC_CONFIG); \
|
||||
} while (0)
|
||||
|
||||
#define TEST_BUG(fmt, ...) \
|
||||
do { \
|
||||
cleanup(); \
|
||||
printf("BUG in testsuite: " fmt "\n", ##__VA_ARGS__); \
|
||||
exit(RC_BUG); \
|
||||
} while (0)
|
||||
|
|
|
|||
|
|
@ -42,29 +42,21 @@ static inline void VALGRIND_MAKE_MEM_DEFINED(void *p, size_t len)
|
|||
int verbose_test = 1;
|
||||
char *test_name;
|
||||
|
||||
void __attribute__((weak)) cleanup(void)
|
||||
static void sigint_handler(int signum)
|
||||
{
|
||||
}
|
||||
|
||||
static void sigint_handler(int signum, siginfo_t *si, void *uc)
|
||||
{
|
||||
cleanup();
|
||||
fprintf(stderr, "%s: %s (pid=%d)\n", test_name,
|
||||
strsignal(signum), getpid());
|
||||
fprintf(stderr, "%s: signal %d (pid=%d)\n", test_name,
|
||||
signum, getpid());
|
||||
exit(RC_BUG);
|
||||
}
|
||||
|
||||
void test_init(int argc, char *argv[])
|
||||
{
|
||||
int err;
|
||||
struct sigaction sa_int = {
|
||||
.sa_sigaction = sigint_handler,
|
||||
};
|
||||
|
||||
test_name = argv[0];
|
||||
|
||||
err = sigaction(SIGINT, &sa_int, NULL);
|
||||
if (err)
|
||||
/* Use signal(), not sigaction() because it also works on the Windows /
|
||||
* mingw environments we support.
|
||||
*/
|
||||
if (signal(SIGINT, sigint_handler) == SIG_ERR)
|
||||
FAIL("Can't install SIGINT handler");
|
||||
|
||||
if (getenv("QUIET_TEST"))
|
||||
|
|
|
|||
756
tests/treegen.c
Normal file
756
tests/treegen.c
Normal file
|
|
@ -0,0 +1,756 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* treegen - generate test device tree blobs
|
||||
*
|
||||
* Build example device tree blobs for test. Note that some of the generated
|
||||
* blobs are deliberately malformed, in order to test error conditions.
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <libfdt_env.h>
|
||||
#include <fdt.h>
|
||||
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
/*
|
||||
* Buffer with write cursor. Emit helpers write at the cursor, advance it, and
|
||||
* return the offset at which data was written.
|
||||
*/
|
||||
struct buf {
|
||||
char *data;
|
||||
size_t size, cursor;
|
||||
};
|
||||
|
||||
#define CHUNKSIZE 1024
|
||||
|
||||
static struct buf buf_init(void)
|
||||
{
|
||||
struct buf b = { NULL, 0, 0 };
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
/* Low-level helpers */
|
||||
|
||||
static size_t emit_bytes(struct buf *b, const void *data, int len)
|
||||
{
|
||||
size_t off = b->cursor;
|
||||
|
||||
if (!len)
|
||||
return off;
|
||||
|
||||
if (b->cursor + len > b->size) {
|
||||
size_t newsize = b->cursor + len + CHUNKSIZE;
|
||||
|
||||
b->data = xrealloc(b->data, newsize);
|
||||
memset(b->data + b->size, 0, newsize - b->size);
|
||||
b->size = newsize;
|
||||
}
|
||||
memcpy(b->data + b->cursor, data, len);
|
||||
b->cursor += len;
|
||||
return off;
|
||||
}
|
||||
|
||||
static size_t emit_u32(struct buf *b, uint32_t val)
|
||||
{
|
||||
fdt32_t beval = cpu_to_fdt32(val);
|
||||
|
||||
return emit_bytes(b, &beval, sizeof(beval));
|
||||
}
|
||||
|
||||
static size_t emit_u64(struct buf *b, uint64_t val)
|
||||
{
|
||||
fdt64_t beval = cpu_to_fdt64(val);
|
||||
|
||||
return emit_bytes(b, &beval, sizeof(beval));
|
||||
}
|
||||
|
||||
static size_t emit_string(struct buf *b, const char *str)
|
||||
{
|
||||
return emit_bytes(b, str, strlen(str) + 1);
|
||||
}
|
||||
|
||||
#define MAX_ALIGNMENT 8
|
||||
|
||||
static size_t emit_align(struct buf *b, size_t alignment)
|
||||
{
|
||||
size_t pad = ((b->cursor + alignment - 1) & ~(alignment - 1)) - b->cursor;
|
||||
static const char zeros[MAX_ALIGNMENT];
|
||||
|
||||
assert(alignment <= MAX_ALIGNMENT);
|
||||
assert(pad < alignment);
|
||||
|
||||
return emit_bytes(b, zeros, pad);
|
||||
}
|
||||
|
||||
static size_t start_block(struct buf *b)
|
||||
{
|
||||
return b->cursor;
|
||||
}
|
||||
|
||||
static void fill_prop_name(struct buf *b, size_t strs, size_t prop, size_t stroff)
|
||||
{
|
||||
struct fdt_property *fp = (struct fdt_property *)(b->data + prop);
|
||||
|
||||
fp->nameoff = cpu_to_fdt32(stroff - strs);
|
||||
}
|
||||
|
||||
/* FDT structure helpers */
|
||||
|
||||
static size_t emit_fdt_header(struct buf *b)
|
||||
{
|
||||
size_t off = emit_u32(b, FDT_MAGIC);
|
||||
|
||||
emit_u32(b, 0); /* totalsize */
|
||||
emit_u32(b, 0); /* off_dt_struct */
|
||||
emit_u32(b, 0); /* off_dt_strings */
|
||||
emit_u32(b, 0); /* off_mem_rsvmap */
|
||||
emit_u32(b, 0x11); /* version */
|
||||
emit_u32(b, 0x10); /* last_comp_version */
|
||||
emit_u32(b, 0); /* boot_cpuid_phys */
|
||||
emit_u32(b, 0); /* size_dt_strings */
|
||||
emit_u32(b, 0); /* size_dt_struct */
|
||||
return off;
|
||||
}
|
||||
|
||||
static void finish_rsvmap(struct buf *b, size_t hdr, size_t rsvmap)
|
||||
{
|
||||
struct fdt_header *fh = (struct fdt_header *)(b->data + hdr);
|
||||
|
||||
fh->off_mem_rsvmap = cpu_to_fdt32(rsvmap - hdr);
|
||||
}
|
||||
|
||||
static void finish_struct_block(struct buf *b, size_t hdr, size_t start)
|
||||
{
|
||||
struct fdt_header *fh = (struct fdt_header *)(b->data + hdr);
|
||||
|
||||
fh->off_dt_struct = cpu_to_fdt32(start - hdr);
|
||||
fh->size_dt_struct = cpu_to_fdt32(b->cursor - start);
|
||||
}
|
||||
|
||||
static void finish_strings_block(struct buf *b, size_t hdr, size_t start)
|
||||
{
|
||||
struct fdt_header *fh = (struct fdt_header *)(b->data + hdr);
|
||||
|
||||
fh->off_dt_strings = cpu_to_fdt32(start - hdr);
|
||||
fh->size_dt_strings = cpu_to_fdt32(b->cursor - start);
|
||||
}
|
||||
|
||||
static void finish_totalsize(struct buf *b, size_t hdr)
|
||||
{
|
||||
struct fdt_header *fh = (struct fdt_header *)(b->data + hdr);
|
||||
|
||||
fh->totalsize = cpu_to_fdt32(b->cursor - hdr);
|
||||
}
|
||||
|
||||
static size_t emit_rsvmap_entry(struct buf *b, uint64_t addr, uint64_t size)
|
||||
{
|
||||
size_t off = emit_u64(b, addr);
|
||||
|
||||
emit_u64(b, size);
|
||||
return off;
|
||||
}
|
||||
|
||||
static size_t emit_rsvmap_term(struct buf *b)
|
||||
{
|
||||
return emit_rsvmap_entry(b, 0, 0);
|
||||
}
|
||||
|
||||
static void emit_rsvmap_empty(struct buf *b, size_t hdr)
|
||||
{
|
||||
size_t rsvmap = start_block(b);
|
||||
|
||||
emit_rsvmap_term(b);
|
||||
finish_rsvmap(b, hdr, rsvmap);
|
||||
}
|
||||
|
||||
static size_t emit_begin_node(struct buf *b, const char *name)
|
||||
{
|
||||
size_t off = emit_u32(b, FDT_BEGIN_NODE);
|
||||
|
||||
emit_string(b, name);
|
||||
emit_align(b, FDT_TAGSIZE);
|
||||
return off;
|
||||
}
|
||||
|
||||
static size_t emit_end_node(struct buf *b)
|
||||
{
|
||||
return emit_u32(b, FDT_END_NODE);
|
||||
}
|
||||
|
||||
static size_t emit_fdt_end(struct buf *b)
|
||||
{
|
||||
return emit_u32(b, FDT_END);
|
||||
}
|
||||
|
||||
static size_t emit_prop_header(struct buf *b, int nameoff, int len)
|
||||
{
|
||||
size_t off = emit_u32(b, FDT_PROP);
|
||||
|
||||
emit_u32(b, len);
|
||||
emit_u32(b, nameoff);
|
||||
return off;
|
||||
}
|
||||
|
||||
static size_t emit_prop_nil(struct buf *b, int nameoff)
|
||||
{
|
||||
return emit_prop_header(b, nameoff, 0);
|
||||
}
|
||||
|
||||
static size_t emit_prop_u32(struct buf *b, int nameoff, uint32_t val)
|
||||
{
|
||||
size_t off = emit_prop_header(b, nameoff, 4);
|
||||
|
||||
emit_u32(b, val);
|
||||
return off;
|
||||
}
|
||||
|
||||
static size_t emit_prop_u64(struct buf *b, int nameoff, uint64_t val)
|
||||
{
|
||||
size_t off = emit_prop_header(b, nameoff, 8);
|
||||
|
||||
emit_u64(b, val);
|
||||
return off;
|
||||
}
|
||||
|
||||
static size_t emit_prop_str(struct buf *b, int nameoff, const char *str)
|
||||
{
|
||||
int len = strlen(str) + 1;
|
||||
size_t off = emit_prop_header(b, nameoff, len);
|
||||
|
||||
emit_bytes(b, str, len);
|
||||
emit_align(b, FDT_TAGSIZE);
|
||||
return off;
|
||||
}
|
||||
|
||||
#define emit_prop_strings(b, nameoff, ...) \
|
||||
emit_prop_strings_(b, nameoff, __VA_ARGS__, NULL)
|
||||
|
||||
static size_t emit_prop_strings_(struct buf *b, int nameoff, ...)
|
||||
{
|
||||
size_t off = emit_prop_header(b, nameoff, 0);
|
||||
size_t start = b->cursor;
|
||||
va_list ap;
|
||||
const char *s;
|
||||
|
||||
va_start(ap, nameoff);
|
||||
while ((s = va_arg(ap, const char *)) != NULL)
|
||||
emit_string(b, s);
|
||||
va_end(ap);
|
||||
|
||||
((struct fdt_property *)(b->data + off))->len =
|
||||
cpu_to_fdt32(b->cursor - start);
|
||||
emit_align(b, FDT_TAGSIZE);
|
||||
return off;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tree generators
|
||||
*
|
||||
* Each function builds a complete DTB in a buffer.
|
||||
*/
|
||||
|
||||
static struct buf make_test_tree1(void)
|
||||
{
|
||||
struct buf b = buf_init();
|
||||
size_t hdr;
|
||||
size_t p_compatible, p_prop_int, p_prop_int64, p_prop_str,
|
||||
p_address_cells, p_size_cells;
|
||||
size_t p_s1_compatible, p_s1_reg, p_s1_prop_int;
|
||||
size_t p_s1ss_compatible, p_s1ss_placeholder, p_s1ss_prop_int;
|
||||
size_t p_s2_reg, p_s2_linux_phandle, p_s2_prop_int,
|
||||
p_s2_address_cells, p_s2_size_cells;
|
||||
size_t p_s2ss0_reg, p_s2ss0_phandle, p_s2ss0_compatible,
|
||||
p_s2ss0_prop_int;
|
||||
|
||||
hdr = emit_fdt_header(&b);
|
||||
emit_align(&b, 8);
|
||||
|
||||
{
|
||||
size_t rsvmap = start_block(&b);
|
||||
|
||||
emit_rsvmap_entry(&b, TEST_ADDR_1, TEST_SIZE_1);
|
||||
emit_rsvmap_entry(&b, TEST_ADDR_2, TEST_SIZE_2);
|
||||
emit_rsvmap_term(&b);
|
||||
finish_rsvmap(&b, hdr, rsvmap);
|
||||
}
|
||||
|
||||
{
|
||||
size_t ss = start_block(&b);
|
||||
|
||||
emit_begin_node(&b, "");
|
||||
p_compatible = emit_prop_str(&b, 0, "test_tree1");
|
||||
p_prop_int = emit_prop_u32(&b, 0, TEST_VALUE_1);
|
||||
p_prop_int64 = emit_prop_u64(&b, 0, TEST_VALUE64_1);
|
||||
p_prop_str = emit_prop_str(&b, 0, TEST_STRING_1);
|
||||
p_address_cells = emit_prop_u32(&b, 0, 1);
|
||||
p_size_cells = emit_prop_u32(&b, 0, 0);
|
||||
|
||||
emit_begin_node(&b, "subnode@1");
|
||||
p_s1_compatible = emit_prop_str(&b, 0, "subnode1");
|
||||
p_s1_reg = emit_prop_u32(&b, 0, 1);
|
||||
p_s1_prop_int = emit_prop_u32(&b, 0, TEST_VALUE_1);
|
||||
|
||||
emit_begin_node(&b, "subsubnode");
|
||||
p_s1ss_compatible = emit_prop_strings(&b, 0,
|
||||
"subsubnode1", "subsubnode");
|
||||
p_s1ss_placeholder = emit_prop_strings(&b, 0,
|
||||
"this is a placeholder string",
|
||||
"string2");
|
||||
p_s1ss_prop_int = emit_prop_u32(&b, 0, TEST_VALUE_1);
|
||||
emit_end_node(&b);
|
||||
|
||||
emit_begin_node(&b, "ss1");
|
||||
emit_end_node(&b);
|
||||
|
||||
emit_end_node(&b);
|
||||
|
||||
emit_begin_node(&b, "subnode@2");
|
||||
p_s2_reg = emit_prop_u32(&b, 0, 2);
|
||||
p_s2_linux_phandle = emit_prop_u32(&b, 0, PHANDLE_1);
|
||||
p_s2_prop_int = emit_prop_u32(&b, 0, TEST_VALUE_2);
|
||||
p_s2_address_cells = emit_prop_u32(&b, 0, 1);
|
||||
p_s2_size_cells = emit_prop_u32(&b, 0, 0);
|
||||
|
||||
emit_begin_node(&b, "subsubnode@0");
|
||||
p_s2ss0_reg = emit_prop_u32(&b, 0, 0);
|
||||
p_s2ss0_phandle = emit_prop_u32(&b, 0, PHANDLE_2);
|
||||
p_s2ss0_compatible = emit_prop_strings(&b, 0,
|
||||
"subsubnode2", "subsubnode");
|
||||
p_s2ss0_prop_int = emit_prop_u32(&b, 0, TEST_VALUE_2);
|
||||
emit_end_node(&b);
|
||||
|
||||
emit_begin_node(&b, "ss2");
|
||||
emit_end_node(&b);
|
||||
|
||||
emit_end_node(&b);
|
||||
|
||||
emit_end_node(&b);
|
||||
emit_fdt_end(&b);
|
||||
finish_struct_block(&b, hdr, ss);
|
||||
}
|
||||
|
||||
{
|
||||
size_t strs = start_block(&b);
|
||||
size_t s;
|
||||
|
||||
s = emit_string(&b, "compatible");
|
||||
fill_prop_name(&b, strs, p_compatible, s);
|
||||
fill_prop_name(&b, strs, p_s1_compatible, s);
|
||||
fill_prop_name(&b, strs, p_s1ss_compatible, s);
|
||||
fill_prop_name(&b, strs, p_s2ss0_compatible, s);
|
||||
|
||||
s = emit_string(&b, "prop-int");
|
||||
fill_prop_name(&b, strs, p_prop_int, s);
|
||||
fill_prop_name(&b, strs, p_s1_prop_int, s);
|
||||
fill_prop_name(&b, strs, p_s1ss_prop_int, s);
|
||||
fill_prop_name(&b, strs, p_s2_prop_int, s);
|
||||
fill_prop_name(&b, strs, p_s2ss0_prop_int, s);
|
||||
|
||||
fill_prop_name(&b, strs, p_prop_int64,
|
||||
emit_string(&b, "prop-int64"));
|
||||
|
||||
fill_prop_name(&b, strs, p_prop_str,
|
||||
emit_string(&b, "prop-str"));
|
||||
|
||||
fill_prop_name(&b, strs, p_s2_linux_phandle,
|
||||
emit_string(&b, "linux,phandle"));
|
||||
|
||||
fill_prop_name(&b, strs, p_s2ss0_phandle,
|
||||
emit_string(&b, "phandle"));
|
||||
|
||||
s = emit_string(&b, "reg");
|
||||
fill_prop_name(&b, strs, p_s1_reg, s);
|
||||
fill_prop_name(&b, strs, p_s2_reg, s);
|
||||
fill_prop_name(&b, strs, p_s2ss0_reg, s);
|
||||
|
||||
fill_prop_name(&b, strs, p_s1ss_placeholder,
|
||||
emit_string(&b, "placeholder"));
|
||||
|
||||
s = emit_string(&b, "#address-cells");
|
||||
fill_prop_name(&b, strs, p_address_cells, s);
|
||||
fill_prop_name(&b, strs, p_s2_address_cells, s);
|
||||
|
||||
s = emit_string(&b, "#size-cells");
|
||||
fill_prop_name(&b, strs, p_size_cells, s);
|
||||
fill_prop_name(&b, strs, p_s2_size_cells, s);
|
||||
|
||||
finish_strings_block(&b, hdr, strs);
|
||||
}
|
||||
|
||||
finish_totalsize(&b, hdr);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
static struct buf make_truncated_property(void)
|
||||
{
|
||||
struct buf b = buf_init();
|
||||
size_t hdr;
|
||||
size_t p;
|
||||
|
||||
hdr = emit_fdt_header(&b);
|
||||
emit_align(&b, 8);
|
||||
|
||||
emit_rsvmap_empty(&b, hdr);
|
||||
|
||||
{
|
||||
size_t ss = start_block(&b);
|
||||
|
||||
emit_begin_node(&b, "");
|
||||
p = emit_prop_header(&b, 0, 4);
|
||||
finish_struct_block(&b, hdr, ss);
|
||||
}
|
||||
|
||||
{
|
||||
size_t strs = start_block(&b);
|
||||
|
||||
emit_string(&b, "truncated");
|
||||
fill_prop_name(&b, strs, p, strs);
|
||||
finish_strings_block(&b, hdr, strs);
|
||||
}
|
||||
|
||||
finish_totalsize(&b, hdr);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
static struct buf make_bad_node_char(void)
|
||||
{
|
||||
struct buf b = buf_init();
|
||||
size_t hdr;
|
||||
|
||||
hdr = emit_fdt_header(&b);
|
||||
emit_align(&b, 8);
|
||||
|
||||
emit_rsvmap_empty(&b, hdr);
|
||||
|
||||
{
|
||||
size_t ss = start_block(&b);
|
||||
|
||||
emit_begin_node(&b, "");
|
||||
emit_begin_node(&b, "sub$node");
|
||||
emit_end_node(&b);
|
||||
emit_end_node(&b);
|
||||
emit_fdt_end(&b);
|
||||
finish_struct_block(&b, hdr, ss);
|
||||
}
|
||||
|
||||
finish_strings_block(&b, hdr, start_block(&b));
|
||||
|
||||
finish_totalsize(&b, hdr);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
static struct buf make_bad_node_format(void)
|
||||
{
|
||||
struct buf b = buf_init();
|
||||
size_t hdr;
|
||||
|
||||
hdr = emit_fdt_header(&b);
|
||||
emit_align(&b, 8);
|
||||
|
||||
emit_rsvmap_empty(&b, hdr);
|
||||
|
||||
{
|
||||
size_t ss = start_block(&b);
|
||||
|
||||
emit_begin_node(&b, "");
|
||||
emit_begin_node(&b, "subnode@1@2");
|
||||
emit_end_node(&b);
|
||||
emit_end_node(&b);
|
||||
emit_fdt_end(&b);
|
||||
finish_struct_block(&b, hdr, ss);
|
||||
}
|
||||
|
||||
finish_strings_block(&b, hdr, start_block(&b));
|
||||
|
||||
finish_totalsize(&b, hdr);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
static struct buf make_bad_prop_char(void)
|
||||
{
|
||||
struct buf b = buf_init();
|
||||
size_t hdr;
|
||||
size_t p;
|
||||
|
||||
hdr = emit_fdt_header(&b);
|
||||
emit_align(&b, 8);
|
||||
|
||||
emit_rsvmap_empty(&b, hdr);
|
||||
|
||||
{
|
||||
size_t ss = start_block(&b);
|
||||
|
||||
emit_begin_node(&b, "");
|
||||
p = emit_prop_u32(&b, 0, TEST_VALUE_1);
|
||||
emit_end_node(&b);
|
||||
emit_fdt_end(&b);
|
||||
finish_struct_block(&b, hdr, ss);
|
||||
}
|
||||
|
||||
{
|
||||
size_t strs = start_block(&b);
|
||||
|
||||
fill_prop_name(&b, strs, p,
|
||||
emit_string(&b, "prop$erty"));
|
||||
finish_strings_block(&b, hdr, strs);
|
||||
}
|
||||
|
||||
finish_totalsize(&b, hdr);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
static struct buf make_ovf_size_strings(void)
|
||||
{
|
||||
struct buf b = buf_init();
|
||||
size_t hdr;
|
||||
|
||||
hdr = emit_fdt_header(&b);
|
||||
emit_align(&b, 8);
|
||||
|
||||
emit_rsvmap_empty(&b, hdr);
|
||||
|
||||
{
|
||||
size_t ss = start_block(&b);
|
||||
|
||||
emit_begin_node(&b, "");
|
||||
emit_prop_u32(&b, 0x10000000, 0);
|
||||
emit_end_node(&b);
|
||||
emit_fdt_end(&b);
|
||||
finish_struct_block(&b, hdr, ss);
|
||||
}
|
||||
|
||||
{
|
||||
size_t strs = start_block(&b);
|
||||
|
||||
emit_string(&b, "x");
|
||||
finish_strings_block(&b, hdr, strs);
|
||||
}
|
||||
|
||||
((struct fdt_header *)(b.data + hdr))->size_dt_strings =
|
||||
cpu_to_fdt32(0xffffffff);
|
||||
|
||||
finish_totalsize(&b, hdr);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
static struct buf make_truncated_string(void)
|
||||
{
|
||||
struct buf b = buf_init();
|
||||
size_t hdr;
|
||||
size_t p_good, p_bad;
|
||||
|
||||
hdr = emit_fdt_header(&b);
|
||||
emit_align(&b, 8);
|
||||
|
||||
emit_rsvmap_empty(&b, hdr);
|
||||
|
||||
{
|
||||
size_t ss = start_block(&b);
|
||||
|
||||
emit_begin_node(&b, "");
|
||||
p_good = emit_prop_nil(&b, 0);
|
||||
p_bad = emit_prop_nil(&b, 0);
|
||||
emit_end_node(&b);
|
||||
emit_fdt_end(&b);
|
||||
finish_struct_block(&b, hdr, ss);
|
||||
}
|
||||
|
||||
{
|
||||
size_t strs = start_block(&b);
|
||||
|
||||
fill_prop_name(&b, strs, p_good, emit_string(&b, "good"));
|
||||
fill_prop_name(&b, strs, p_bad, emit_bytes(&b, "bad", 3));
|
||||
finish_strings_block(&b, hdr, strs);
|
||||
}
|
||||
|
||||
finish_totalsize(&b, hdr);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
static struct buf make_truncated_memrsv(void)
|
||||
{
|
||||
struct buf b = buf_init();
|
||||
size_t hdr;
|
||||
|
||||
hdr = emit_fdt_header(&b);
|
||||
|
||||
{
|
||||
size_t ss = start_block(&b);
|
||||
|
||||
emit_begin_node(&b, "");
|
||||
emit_end_node(&b);
|
||||
emit_fdt_end(&b);
|
||||
finish_struct_block(&b, hdr, ss);
|
||||
}
|
||||
|
||||
finish_strings_block(&b, hdr, start_block(&b));
|
||||
|
||||
{
|
||||
size_t rsvmap;
|
||||
|
||||
emit_align(&b, 8);
|
||||
rsvmap = start_block(&b);
|
||||
emit_rsvmap_entry(&b, TEST_ADDR_1, TEST_SIZE_1);
|
||||
finish_rsvmap(&b, hdr, rsvmap);
|
||||
}
|
||||
|
||||
finish_totalsize(&b, hdr);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
static struct buf make_unterminated_memrsv(void)
|
||||
{
|
||||
struct buf b = buf_init();
|
||||
size_t hdr;
|
||||
|
||||
hdr = emit_fdt_header(&b);
|
||||
|
||||
{
|
||||
size_t rsvmap;
|
||||
|
||||
emit_align(&b, 8);
|
||||
rsvmap = start_block(&b);
|
||||
emit_rsvmap_entry(&b, TEST_ADDR_1, TEST_SIZE_1);
|
||||
finish_rsvmap(&b, hdr, rsvmap);
|
||||
}
|
||||
|
||||
{
|
||||
size_t ss = start_block(&b);
|
||||
|
||||
emit_begin_node(&b, "");
|
||||
emit_end_node(&b);
|
||||
emit_fdt_end(&b);
|
||||
finish_struct_block(&b, hdr, ss);
|
||||
}
|
||||
|
||||
finish_strings_block(&b, hdr, start_block(&b));
|
||||
|
||||
finish_totalsize(&b, hdr);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
static struct buf make_two_roots(void)
|
||||
{
|
||||
struct buf b = buf_init();
|
||||
size_t hdr;
|
||||
|
||||
hdr = emit_fdt_header(&b);
|
||||
emit_align(&b, 8);
|
||||
|
||||
emit_rsvmap_empty(&b, hdr);
|
||||
|
||||
{
|
||||
size_t ss = start_block(&b);
|
||||
|
||||
emit_begin_node(&b, "");
|
||||
emit_end_node(&b);
|
||||
emit_begin_node(&b, "");
|
||||
emit_end_node(&b);
|
||||
emit_fdt_end(&b);
|
||||
finish_struct_block(&b, hdr, ss);
|
||||
}
|
||||
|
||||
finish_strings_block(&b, hdr, start_block(&b));
|
||||
|
||||
finish_totalsize(&b, hdr);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
static struct buf make_named_root(void)
|
||||
{
|
||||
struct buf b = buf_init();
|
||||
size_t hdr;
|
||||
|
||||
hdr = emit_fdt_header(&b);
|
||||
emit_align(&b, 8);
|
||||
|
||||
emit_rsvmap_empty(&b, hdr);
|
||||
|
||||
{
|
||||
size_t ss = start_block(&b);
|
||||
|
||||
emit_begin_node(&b, "fake");
|
||||
emit_end_node(&b);
|
||||
emit_fdt_end(&b);
|
||||
finish_struct_block(&b, hdr, ss);
|
||||
}
|
||||
|
||||
finish_strings_block(&b, hdr, start_block(&b));
|
||||
|
||||
finish_totalsize(&b, hdr);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
/* Tree table and main */
|
||||
|
||||
static struct {
|
||||
struct buf (*generator)(void);
|
||||
const char *filename;
|
||||
} trees[] = {
|
||||
#define TREE(name) { make_##name, #name ".dtb" }
|
||||
TREE(test_tree1),
|
||||
TREE(bad_node_char), TREE(bad_node_format), TREE(bad_prop_char),
|
||||
TREE(ovf_size_strings),
|
||||
TREE(truncated_property), TREE(truncated_string),
|
||||
TREE(truncated_memrsv),
|
||||
TREE(unterminated_memrsv),
|
||||
TREE(two_roots),
|
||||
TREE(named_root),
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s <output-dir>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (chdir(argv[1]) != 0) {
|
||||
perror("chdir()");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(trees); i++) {
|
||||
struct buf b = trees[i].generator();
|
||||
const char *filename = trees[i].filename;
|
||||
int fd;
|
||||
ssize_t ret;
|
||||
|
||||
printf("Tree \"%s\", %zu bytes\n", filename, b.cursor);
|
||||
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||
if (fd < 0)
|
||||
perror("open()");
|
||||
|
||||
ret = write(fd, b.data, b.cursor);
|
||||
if (ret < 0 || (size_t)ret != b.cursor)
|
||||
perror("write()");
|
||||
|
||||
close(fd);
|
||||
free(b.data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
326
tests/trees.S
326
tests/trees.S
|
|
@ -1,326 +0,0 @@
|
|||
#include <fdt.h>
|
||||
#include "testdata.h"
|
||||
|
||||
.macro fdtlong val
|
||||
.byte ((\val) >> 24) & 0xff
|
||||
.byte ((\val) >> 16) & 0xff
|
||||
.byte ((\val) >> 8) & 0xff
|
||||
.byte (\val) & 0xff
|
||||
.endm
|
||||
|
||||
.macro treehdr tree
|
||||
.balign 8
|
||||
.globl \tree
|
||||
\tree :
|
||||
fdtlong FDT_MAGIC
|
||||
fdtlong (\tree\()_end - \tree)
|
||||
fdtlong (\tree\()_struct - \tree)
|
||||
fdtlong (\tree\()_strings - \tree)
|
||||
fdtlong (\tree\()_rsvmap - \tree)
|
||||
fdtlong 0x11
|
||||
fdtlong 0x10
|
||||
fdtlong 0
|
||||
fdtlong (\tree\()_strings_end - \tree\()_strings)
|
||||
fdtlong (\tree\()_struct_end - \tree\()_struct)
|
||||
.endm
|
||||
|
||||
.macro rsvmape addrh, addrl, lenh, lenl
|
||||
fdtlong \addrh
|
||||
fdtlong \addrl
|
||||
fdtlong \lenh
|
||||
fdtlong \lenl
|
||||
.endm
|
||||
|
||||
.macro empty_rsvmap tree
|
||||
.balign 8
|
||||
\tree\()_rsvmap:
|
||||
rsvmape 0, 0, 0, 0
|
||||
\tree\()_rsvmap_end:
|
||||
.endm
|
||||
|
||||
.macro prophdr tree, name, len
|
||||
fdtlong FDT_PROP
|
||||
fdtlong \len
|
||||
fdtlong (\tree\()_\name - \tree\()_strings)
|
||||
.endm
|
||||
|
||||
.macro propnil tree, name
|
||||
prophdr \tree, \name, 0
|
||||
.endm
|
||||
|
||||
.macro propu32 tree, name, val
|
||||
prophdr \tree, \name, 4
|
||||
fdtlong \val
|
||||
.endm
|
||||
|
||||
.macro propu64 tree, name, valh, vall
|
||||
prophdr \tree, \name, 8
|
||||
fdtlong \valh
|
||||
fdtlong \vall
|
||||
.endm
|
||||
|
||||
.macro propstr tree, name, str:vararg
|
||||
prophdr \tree, \name, (55f - 54f)
|
||||
54:
|
||||
.asciz \str
|
||||
55:
|
||||
.balign 4
|
||||
.endm
|
||||
|
||||
.macro beginn name:vararg
|
||||
fdtlong FDT_BEGIN_NODE
|
||||
.asciz \name
|
||||
.balign 4
|
||||
.endm
|
||||
|
||||
.macro endn
|
||||
fdtlong FDT_END_NODE
|
||||
.endm
|
||||
|
||||
.macro string tree, name, str:vararg
|
||||
\tree\()_\name :
|
||||
.asciz \str
|
||||
.endm
|
||||
|
||||
|
||||
.data
|
||||
|
||||
treehdr test_tree1
|
||||
|
||||
.balign 8
|
||||
test_tree1_rsvmap:
|
||||
rsvmape TEST_ADDR_1H, TEST_ADDR_1L, TEST_SIZE_1H, TEST_SIZE_1L
|
||||
rsvmape TEST_ADDR_2H, TEST_ADDR_2L, TEST_SIZE_2H, TEST_SIZE_2L
|
||||
rsvmape 0, 0, 0, 0
|
||||
test_tree1_rsvmap_end:
|
||||
|
||||
test_tree1_struct:
|
||||
beginn ""
|
||||
propstr test_tree1, compatible, "test_tree1"
|
||||
propu32 test_tree1, prop_int, TEST_VALUE_1
|
||||
propu64 test_tree1, prop_int64, TEST_VALUE64_1H, TEST_VALUE64_1L
|
||||
propstr test_tree1, prop_str, TEST_STRING_1
|
||||
propu32 test_tree1, address_cells, 1
|
||||
propu32 test_tree1, size_cells, 0
|
||||
|
||||
beginn "subnode@1"
|
||||
propstr test_tree1, compatible, "subnode1"
|
||||
propu32 test_tree1, reg, 1
|
||||
propu32 test_tree1, prop_int, TEST_VALUE_1
|
||||
|
||||
beginn "subsubnode"
|
||||
propstr test_tree1, compatible, "subsubnode1\0subsubnode"
|
||||
propstr test_tree1, placeholder, "this is a placeholder string\0string2"
|
||||
propu32 test_tree1, prop_int, TEST_VALUE_1
|
||||
endn
|
||||
|
||||
beginn "ss1"
|
||||
endn
|
||||
|
||||
endn
|
||||
|
||||
beginn "subnode@2"
|
||||
propu32 test_tree1, reg, 2
|
||||
propu32 test_tree1, linux_phandle, PHANDLE_1
|
||||
propu32 test_tree1, prop_int, TEST_VALUE_2
|
||||
propu32 test_tree1, address_cells, 1
|
||||
propu32 test_tree1, size_cells, 0
|
||||
|
||||
beginn "subsubnode@0"
|
||||
propu32 test_tree1, reg, 0
|
||||
propu32 test_tree1, phandle, PHANDLE_2
|
||||
propstr test_tree1, compatible, "subsubnode2\0subsubnode"
|
||||
propu32 test_tree1, prop_int, TEST_VALUE_2
|
||||
endn
|
||||
|
||||
beginn "ss2"
|
||||
endn
|
||||
|
||||
endn
|
||||
|
||||
endn
|
||||
fdtlong FDT_END
|
||||
test_tree1_struct_end:
|
||||
|
||||
test_tree1_strings:
|
||||
string test_tree1, compatible, "compatible"
|
||||
string test_tree1, prop_int, "prop-int"
|
||||
string test_tree1, prop_int64, "prop-int64"
|
||||
string test_tree1, prop_str, "prop-str"
|
||||
string test_tree1, linux_phandle, "linux,phandle"
|
||||
string test_tree1, phandle, "phandle"
|
||||
string test_tree1, reg, "reg"
|
||||
string test_tree1, placeholder, "placeholder"
|
||||
string test_tree1, address_cells, "#address-cells"
|
||||
string test_tree1, size_cells, "#size-cells"
|
||||
test_tree1_strings_end:
|
||||
test_tree1_end:
|
||||
|
||||
|
||||
treehdr truncated_property
|
||||
empty_rsvmap truncated_property
|
||||
|
||||
truncated_property_struct:
|
||||
beginn ""
|
||||
prophdr truncated_property, prop_truncated, 4
|
||||
/* Oops, no actual property data here */
|
||||
truncated_property_struct_end:
|
||||
|
||||
truncated_property_strings:
|
||||
string truncated_property, prop_truncated, "truncated"
|
||||
truncated_property_strings_end:
|
||||
|
||||
truncated_property_end:
|
||||
|
||||
|
||||
treehdr bad_node_char
|
||||
empty_rsvmap bad_node_char
|
||||
|
||||
bad_node_char_struct:
|
||||
beginn ""
|
||||
beginn "sub$node"
|
||||
endn
|
||||
endn
|
||||
fdtlong FDT_END
|
||||
bad_node_char_struct_end:
|
||||
|
||||
bad_node_char_strings:
|
||||
bad_node_char_strings_end:
|
||||
bad_node_char_end:
|
||||
|
||||
|
||||
treehdr bad_node_format
|
||||
empty_rsvmap bad_node_format
|
||||
|
||||
bad_node_format_struct:
|
||||
beginn ""
|
||||
beginn "subnode@1@2"
|
||||
endn
|
||||
endn
|
||||
fdtlong FDT_END
|
||||
bad_node_format_struct_end:
|
||||
|
||||
bad_node_format_strings:
|
||||
bad_node_format_strings_end:
|
||||
bad_node_format_end:
|
||||
|
||||
|
||||
treehdr bad_prop_char
|
||||
empty_rsvmap bad_prop_char
|
||||
|
||||
bad_prop_char_struct:
|
||||
beginn ""
|
||||
propu32 bad_prop_char, prop, TEST_VALUE_1
|
||||
endn
|
||||
fdtlong FDT_END
|
||||
bad_prop_char_struct_end:
|
||||
|
||||
bad_prop_char_strings:
|
||||
string bad_prop_char, prop, "prop$erty"
|
||||
bad_prop_char_strings_end:
|
||||
bad_prop_char_end:
|
||||
|
||||
|
||||
/* overflow_size_strings */
|
||||
.balign 8
|
||||
.globl ovf_size_strings
|
||||
ovf_size_strings:
|
||||
fdtlong FDT_MAGIC
|
||||
fdtlong (ovf_size_strings_end - ovf_size_strings)
|
||||
fdtlong (ovf_size_strings_struct - ovf_size_strings)
|
||||
fdtlong (ovf_size_strings_strings - ovf_size_strings)
|
||||
fdtlong (ovf_size_strings_rsvmap - ovf_size_strings)
|
||||
fdtlong 0x11
|
||||
fdtlong 0x10
|
||||
fdtlong 0
|
||||
fdtlong 0xffffffff
|
||||
fdtlong (ovf_size_strings_struct_end - ovf_size_strings_struct)
|
||||
empty_rsvmap ovf_size_strings
|
||||
|
||||
ovf_size_strings_struct:
|
||||
beginn ""
|
||||
propu32 ovf_size_strings, bad_string, 0
|
||||
endn
|
||||
fdtlong FDT_END
|
||||
ovf_size_strings_struct_end:
|
||||
|
||||
ovf_size_strings_strings:
|
||||
string ovf_size_strings, x, "x"
|
||||
ovf_size_strings_bad_string = ovf_size_strings_strings + 0x10000000
|
||||
ovf_size_strings_strings_end:
|
||||
ovf_size_strings_end:
|
||||
|
||||
|
||||
/* truncated_string */
|
||||
treehdr truncated_string
|
||||
empty_rsvmap truncated_string
|
||||
|
||||
truncated_string_struct:
|
||||
beginn ""
|
||||
propnil truncated_string, good_string
|
||||
propnil truncated_string, bad_string
|
||||
endn
|
||||
fdtlong FDT_END
|
||||
truncated_string_struct_end:
|
||||
|
||||
truncated_string_strings:
|
||||
string truncated_string, good_string, "good"
|
||||
truncated_string_bad_string:
|
||||
.ascii "bad"
|
||||
/* NOTE: terminating \0 deliberately missing */
|
||||
truncated_string_strings_end:
|
||||
truncated_string_end:
|
||||
|
||||
|
||||
/* truncated_memrsv */
|
||||
treehdr truncated_memrsv
|
||||
|
||||
truncated_memrsv_struct:
|
||||
beginn ""
|
||||
endn
|
||||
fdtlong FDT_END
|
||||
truncated_memrsv_struct_end:
|
||||
|
||||
truncated_memrsv_strings:
|
||||
truncated_memrsv_strings_end:
|
||||
|
||||
.balign 8
|
||||
truncated_memrsv_rsvmap:
|
||||
rsvmape TEST_ADDR_1H, TEST_ADDR_1L, TEST_SIZE_1H, TEST_SIZE_1L
|
||||
truncated_memrsv_rsvmap_end:
|
||||
|
||||
truncated_memrsv_end:
|
||||
|
||||
|
||||
/* two root nodes */
|
||||
treehdr two_roots
|
||||
empty_rsvmap two_roots
|
||||
|
||||
two_roots_struct:
|
||||
beginn ""
|
||||
endn
|
||||
beginn ""
|
||||
endn
|
||||
fdtlong FDT_END
|
||||
two_roots_struct_end:
|
||||
|
||||
two_roots_strings:
|
||||
two_roots_strings_end:
|
||||
|
||||
two_roots_end:
|
||||
|
||||
|
||||
/* root node with a non-empty name */
|
||||
treehdr named_root
|
||||
empty_rsvmap named_root
|
||||
|
||||
named_root_struct:
|
||||
beginn "fake"
|
||||
endn
|
||||
fdtlong FDT_END
|
||||
named_root_struct_end:
|
||||
|
||||
named_root_strings:
|
||||
named_root_strings_end:
|
||||
|
||||
named_root_end:
|
||||
|
|
@ -15,13 +15,17 @@
|
|||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
#define SPACE 65536
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
void *fdt = &truncated_memrsv;
|
||||
void *fdt;
|
||||
void *buf;
|
||||
int err;
|
||||
uint64_t addr, size;
|
||||
|
||||
test_init(argc, argv);
|
||||
fdt = load_blob_arg(argc, argv);
|
||||
|
||||
err = fdt_check_header(fdt);
|
||||
if (err != 0)
|
||||
|
|
@ -46,5 +50,11 @@ int main(int argc, char *argv[])
|
|||
FAIL("fdt_get_mem_rsv(1) returned %d instead of -FDT_ERR_BADOFFSET",
|
||||
err);
|
||||
|
||||
buf = xmalloc(SPACE);
|
||||
err = fdt_open_into(fdt, buf, SPACE);
|
||||
if (err != -FDT_ERR_TRUNCATED)
|
||||
FAIL("fdt_open_into() returned %d instead of -FDT_ERR_TRUNCATED",
|
||||
err);
|
||||
|
||||
PASS();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,17 +13,15 @@
|
|||
#include <libfdt.h>
|
||||
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
void *fdt = &truncated_property;
|
||||
void *fdt;
|
||||
const void *prop;
|
||||
int len;
|
||||
|
||||
test_init(argc, argv);
|
||||
|
||||
vg_prepare_blob(fdt, fdt_totalsize(fdt));
|
||||
fdt = load_blob_arg(argc, argv);
|
||||
|
||||
prop = fdt_getprop(fdt, 0, "truncated", &len);
|
||||
if (prop)
|
||||
|
|
|
|||
|
|
@ -13,18 +13,16 @@
|
|||
#include <libfdt.h>
|
||||
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
void *fdt = &truncated_string;
|
||||
void *fdt;
|
||||
const struct fdt_property *good, *bad;
|
||||
int off, len;
|
||||
const char *name;
|
||||
|
||||
test_init(argc, argv);
|
||||
|
||||
vg_prepare_blob(fdt, fdt_totalsize(fdt));
|
||||
fdt = load_blob_arg(argc, argv);
|
||||
|
||||
off = fdt_first_property_offset(fdt, 0);
|
||||
good = fdt_get_property_by_offset(fdt, off, NULL);
|
||||
|
|
|
|||
68
tests/unterminated_memrsv.c
Normal file
68
tests/unterminated_memrsv.c
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Testcase for misbehaviour on an unterminated memrsv map
|
||||
* Copyright Red Hat
|
||||
*
|
||||
* Based on a proof of concept report from:
|
||||
* Moshe Strauss <moshestrauss10@gmail.com>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
#define SPACE 65536
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
void *fdt;
|
||||
void *buf;
|
||||
int err;
|
||||
uint64_t addr, size;
|
||||
|
||||
test_init(argc, argv);
|
||||
fdt = load_blob_arg(argc, argv);
|
||||
|
||||
err = fdt_check_header(fdt);
|
||||
if (err != 0)
|
||||
FAIL("Bad header: %s", fdt_strerror(err));
|
||||
|
||||
err = fdt_num_mem_rsv(fdt);
|
||||
if (err != -FDT_ERR_TRUNCATED)
|
||||
FAIL("fdt_num_mem_rsv() returned %d instead of -FDT_ERR_TRUNCATED",
|
||||
err);
|
||||
|
||||
err = fdt_get_mem_rsv(fdt, 0, &addr, &size);
|
||||
if (err != 0)
|
||||
FAIL("fdt_get_mem_rsv() failed on first entry: %s",
|
||||
fdt_strerror(err));
|
||||
if ((addr != TEST_ADDR_1) || (size != TEST_SIZE_1))
|
||||
FAIL("Entry doesn't match: (0x%llx, 0x%llx) != (0x%llx, 0x%llx)",
|
||||
(unsigned long long)addr, (unsigned long long)size,
|
||||
TEST_ADDR_1, TEST_SIZE_1);
|
||||
|
||||
err = fdt_add_mem_rsv(fdt, TEST_ADDR_2, TEST_SIZE_2);
|
||||
if (err != -FDT_ERR_TRUNCATED)
|
||||
FAIL("fdt_add_mem_rsv() returned %d instead of -FDT_ERR_TRUNCATED",
|
||||
err);
|
||||
|
||||
err = fdt_del_mem_rsv(fdt, 0);
|
||||
if (err != -FDT_ERR_TRUNCATED)
|
||||
FAIL("fdt_del_mem_rsv() returned %d instead of -FDT_ERR_TRUNCATED",
|
||||
err);
|
||||
|
||||
buf = xmalloc(SPACE);
|
||||
err = fdt_open_into(fdt, buf, SPACE);
|
||||
if (err != -FDT_ERR_TRUNCATED)
|
||||
FAIL("fdt_open_into() returned %d instead of -FDT_ERR_TRUNCATED",
|
||||
err);
|
||||
|
||||
PASS();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue