diff --git a/.cirrus.yml b/.cirrus.yml new file mode 100644 index 0000000..825aeb7 --- /dev/null +++ b/.cirrus.yml @@ -0,0 +1,39 @@ +# 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 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b788558..b6e0a9c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,8 +8,6 @@ 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 @@ -18,93 +16,78 @@ concurrency: cancel-in-progress: true jobs: - build-linux: + build-make: runs-on: ubuntu-latest strategy: fail-fast: false matrix: - os: [ "alpine", "archlinux", "fedora", "ubuntu" ] - build: [ "make", "meson" ] + os: [ "alpine", "archlinux", "fedora", "ubuntu" ] container: image: ${{ matrix.os }} steps: - name: Checkout - 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 + uses: actions/checkout@v4 - name: Install Dependencies run: | ./scripts/install-deps.sh - - name: Build (Make) - if: matrix.build == 'make' + - name: Build run: | make - - name: Setup (Meson) - if: matrix.build == 'meson' - run: meson setup -D python=enabled -D yaml=enabled -D tests=false build + - name: Run check + run: | + make check - - name: Build (Meson) - if: matrix.build == 'meson' + 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, swig: false } - - { sys: mingw64, swig: true } - - { sys: ucrt64, swig: true } - - { sys: clang64, swig: true } + - { sys: mingw32 } + - { sys: mingw64 } + - { sys: ucrt64 } + - { sys: clang64 } name: ${{ matrix.sys }} defaults: run: shell: msys2 {0} steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: fetch-depth: 0 @@ -122,60 +105,10 @@ jobs: meson:p ninja:p libyaml:p - ${{ matrix.swig && 'swig:p python-setuptools-scm:p' || '' }} + 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 diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index 2f0264f..0000000 --- a/AGENTS.md +++ /dev/null @@ -1,138 +0,0 @@ -# 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) diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 2b87faa..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,17 +0,0 @@ -# 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. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9742dc3..48c8efd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -77,51 +77,3 @@ 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 -``` diff --git a/Makefile b/Makefile index 9110d17..83d8220 100644 --- a/Makefile +++ b/Makefile @@ -153,11 +153,6 @@ 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 @@ -260,6 +255,29 @@ 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 \ diff --git a/VERSION.txt b/VERSION.txt index a8fdfda..f8a696c 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -1.8.1 +1.7.2 diff --git a/checks.c b/checks.c index a6037ed..45d0213 100644 --- a/checks.c +++ b/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) { - size_t n = strspn(node->name, c->data); + int 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, NULL, &phandle_references); +WARNING(interrupts_property, check_interrupts_property, &phandle_references); static const struct bus_type graph_port_bus = { .name = "graph-port", diff --git a/dtc-lexer.l b/dtc-lexer.l index 1b129b1..15d585c 100644 --- a/dtc-lexer.l +++ b/dtc-lexer.l @@ -39,6 +39,8 @@ extern bool treesource_error; #define DPRINT(fmt, ...) do { } while (0) #endif +static int dts_version = 1; + #define BEGIN_DEFAULT() DPRINT("\n"); \ BEGIN(V1); \ @@ -99,6 +101,7 @@ 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; } diff --git a/dtc.h b/dtc.h index 473552e..7231200 100644 --- a/dtc.h +++ b/dtc.h @@ -227,7 +227,7 @@ struct node { struct node *next_sibling; char *fullpath; - size_t basenamelen; + int basenamelen; cell_t phandle; int addr_cells, size_cells; diff --git a/fdtdump.c b/fdtdump.c index 0e7a265..0260609 100644 --- a/fdtdump.c +++ b/fdtdump.c @@ -146,7 +146,8 @@ static void dump_blob(void *blob, bool debug) continue; } - die("** Unknown tag 0x%08"PRIx32"\n", tag); + fprintf(stderr, "%*s ** Unknown tag 0x%08"PRIx32"\n", depth * shift, "", tag); + break; } } @@ -168,6 +169,7 @@ 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 || diff --git a/libfdt/fdt.c b/libfdt/fdt.c index 56d4dcb..95f644c 100644 --- a/libfdt/fdt.c +++ b/libfdt/fdt.c @@ -110,14 +110,6 @@ 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))) diff --git a/libfdt/fdt_check.c b/libfdt/fdt_check.c index 2fd5b61..a21ebbc 100644 --- a/libfdt/fdt_check.c +++ b/libfdt/fdt_check.c @@ -21,8 +21,6 @@ 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)) @@ -45,7 +43,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 && tag != FDT_NOP) + if (expect_end && tag != FDT_END) return -FDT_ERR_BADSTRUCTURE; switch (tag) { diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c index 11f2e2e..63494fb 100644 --- a/libfdt/fdt_ro.c +++ b/libfdt/fdt_ro.c @@ -191,8 +191,6 @@ 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; diff --git a/libfdt/fdt_rw.c b/libfdt/fdt_rw.c index 850aafe..7475caf 100644 --- a/libfdt/fdt_rw.c +++ b/libfdt/fdt_rw.c @@ -22,12 +22,6 @@ 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)) @@ -39,8 +33,9 @@ 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; } @@ -166,11 +161,7 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) FDT_RW_PROBE(fdt); - err = fdt_num_mem_rsv(fdt); - if (err < 0) - return err; - - re = fdt_mem_rsv_w_(fdt, err); + re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt)); err = fdt_splice_mem_rsv_(fdt, re, 0, 1); if (err) return err; @@ -183,15 +174,10 @@ 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); - num = fdt_num_mem_rsv(fdt); - if (num < 0) - return num; - - if (n >= num) + if (n >= fdt_num_mem_rsv(fdt)) return -FDT_ERR_NOTFOUND; return fdt_splice_mem_rsv_(fdt, re, 1, 0); @@ -292,13 +278,6 @@ 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) { @@ -315,13 +294,6 @@ 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) { @@ -462,10 +434,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) FDT_RO_PROBE(fdt); - err = fdt_num_mem_rsv(fdt); - if (err < 0) - return err; - mem_rsv_size = (err + 1) * sizeof(struct fdt_reserve_entry); + mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) + * sizeof(struct fdt_reserve_entry); if (can_assume(LATEST) || fdt_version(fdt) >= 17) { struct_size = fdt_size_dt_struct(fdt); @@ -523,14 +493,12 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) int fdt_pack(void *fdt) { - int err, mem_rsv_size; + int mem_rsv_size; FDT_RW_PROBE(fdt); - err = fdt_num_mem_rsv(fdt); - if (err < 0) - return err; - mem_rsv_size = (err+1) * sizeof(struct fdt_reserve_entry); + 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)); diff --git a/libfdt/fdt_sw.c b/libfdt/fdt_sw.c index 96d4cf5..4c569ee 100644 --- a/libfdt/fdt_sw.c +++ b/libfdt/fdt_sw.c @@ -330,8 +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); + memcpy(ptr, val, len); return 0; } diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h index c69a18e..7a10f66 100644 --- a/libfdt/libfdt.h +++ b/libfdt/libfdt.h @@ -225,7 +225,7 @@ int fdt_next_node(const void *fdt, int offset, int *depth); * @fdt: FDT blob * @offset: Offset of node to check * - * returns: offset of first subnode, or -FDT_ERR_NOTFOUND if there is none + * Return: offset of first subnode, or -FDT_ERR_NOTFOUND if there is none */ int fdt_first_subnode(const void *fdt, int offset); @@ -237,8 +237,8 @@ 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. * - * returns: offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more - * subnodes + * Return: 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 * - * returns: size of DTB header in bytes + * Return: 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 * - * returns: size of DTB header in bytes + * Return: 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. * - * returns: 0 on success or a negative error-code on failure + * Return: 0 on success or a negative error-code on failure */ int fdt_generate_phandle(const void *fdt, uint32_t *phandle); @@ -475,12 +475,7 @@ int fdt_generate_phandle(const void *fdt, uint32_t *phandle); * or any other (0,0) entries reserved for expansion. * * returns: - * the number of entries, on success - * -FDT_ERR_ALIGNMENT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_TRUNCATED, standard meanings + * the number of entries */ int fdt_num_mem_rsv(const void *fdt); @@ -515,7 +510,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. * - * returns: offset of the subnode or -FDT_ERR_NOTFOUND if name not found. + * Return: 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, @@ -556,7 +551,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. * - * returns: offset of the node or negative libfdt error value otherwise + * Return: 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); @@ -754,7 +749,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. * - * returns: pointer to the structure representing the property, or NULL + * Return: pointer to the structure representing the property, or NULL * if not found */ #ifndef SWIG /* Not available in Python */ @@ -856,7 +851,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. * - * returns: pointer to the property's value or NULL on error + * Return: 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, @@ -929,8 +924,8 @@ 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. * - * returns: a pointer to the expansion of the alias named @name, if it exists, - * NULL otherwise + * Return: a pointer to the expansion of the alias named @name, if it exists, + * NULL otherwise */ #ifndef SWIG /* Not available in Python */ const char *fdt_get_alias_namelen(const void *fdt, @@ -960,8 +955,8 @@ 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. * - * returns: a pointer to the expansion of the symbol named @name, if it exists, - * NULL otherwise + * Return: a pointer to the expansion of the symbol named @name, if it exists, + * NULL otherwise */ #ifndef SWIG /* Not available in Python */ const char *fdt_get_symbol_namelen(const void *fdt, @@ -1225,7 +1220,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. * - * returns: 1 if the string is found in the list, 0 not found, or invalid list + * Return: 1 if the string is found in the list, 0 not found, or invalid list */ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str); @@ -1235,7 +1230,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 * - * returns: + * Return: * 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 @@ -1279,7 +1274,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. * - * returns: + * Return: * 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 @@ -1369,7 +1364,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. * - * returns: 0 on success, negative libfdt error value otherwise + * Return: 0 on success, negative libfdt error value otherwise */ #ifndef SWIG /* Not available in Python */ int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, @@ -1489,7 +1484,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() - * returns: 0 on success, negative libfdt error number otherwise. + * Return: 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) @@ -1935,8 +1930,12 @@ int fdt_setprop_namelen(void *fdt, int nodeoffset, const char *name, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ -int fdt_setprop(void *fdt, int nodeoffset, const char *name, - const void *val, int len); +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); +} /** * fdt_setprop_placeholder_namelen - allocate space for a property @@ -1998,8 +1997,13 @@ int fdt_setprop_placeholder_namelen(void *fdt, int nodeoffset, const char *name, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ -int fdt_setprop_placeholder(void *fdt, int nodeoffset, - const char *name, int len, void **prop_data); +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); +} /** * fdt_setprop_u32 - set a property to a 32-bit integer @@ -2080,7 +2084,7 @@ static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name, * * This is an alternative name for fdt_setprop_u32() * - * returns: 0 on success, negative libfdt error value otherwise. + * Return: 0 on success, negative libfdt error value otherwise. */ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, uint32_t val) @@ -2290,7 +2294,7 @@ static inline int fdt_appendprop_u64(void *fdt, int nodeoffset, * * This is an alternative name for fdt_appendprop_u32() * - * returns: 0 on success, negative libfdt error value otherwise. + * Return: 0 on success, negative libfdt error value otherwise. */ static inline int fdt_appendprop_cell(void *fdt, int nodeoffset, const char *name, uint32_t val) @@ -2401,8 +2405,8 @@ 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. * - * returns: structure block offset of the created subnode (>=0), - * negative libfdt error value otherwise + * Return: structure block offset of the created subnode (>=0), + * negative libfdt error value otherwise */ #ifndef SWIG /* Not available in Python */ int fdt_add_subnode_namelen(void *fdt, int parentoffset, diff --git a/livetree.c b/livetree.c index 8baed1f..5d72abc 100644 --- a/livetree.c +++ b/livetree.c @@ -1234,7 +1234,7 @@ void fixup_phandles(struct dt_info *dti, const char *name) continue; offset = strtol(soffset, NULL, 0); - if (offset < 0 || (unsigned int)offset + 4 > p->val.len) { + if (offset < 0 || offset + 4 > p->val.len) { if (quiet < 1) fprintf(stderr, "Warning: Label %s contains invalid offset for property %s in node %s\n", diff --git a/scripts/finalize-release b/scripts/finalize-release deleted file mode 100755 index 89008f2..0000000 --- a/scripts/finalize-release +++ /dev/null @@ -1,98 +0,0 @@ -#!/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 " >&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" <" >&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 </dev/null +$(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_clean: @$(VECHO) CLEAN "(tests)" diff --git a/tests/dumptrees.c b/tests/dumptrees.c new file mode 100644 index 0000000..08967b3 --- /dev/null +++ b/tests/dumptrees.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * dumptrees - utility for libfdt testing + * + * (C) Copyright David Gibson , IBM Corporation. 2006. + */ +#include +#include +#include +#include +#include + +#include + +#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); +} diff --git a/tests/fs_tree1.c b/tests/fs_tree1.c index 27eea55..978f6a3 100644 --- a/tests/fs_tree1.c +++ b/tests/fs_tree1.c @@ -24,11 +24,7 @@ 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)); diff --git a/tests/integer-expressions.c b/tests/integer-expressions.c index fe12eb3..2f164d9 100644 --- a/tests/integer-expressions.c +++ b/tests/integer-expressions.c @@ -17,14 +17,6 @@ #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; @@ -59,7 +51,6 @@ 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])) diff --git a/tests/meson.build b/tests/meson.build index c6ac2d7..37bfd47 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -1,10 +1,14 @@ -treegen = executable('treegen', files('treegen.c'), - build_by_default: false, - dependencies: [util_dep]) +trees = static_library('trees', files('trees.S'), + build_by_default: false, + include_directories: libfdt_inc) -treegen_dtb = custom_target( - 'treegen_dtb', - command: [treegen, meson.current_build_dir()], +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()], output: [ 'test_tree1.dtb', 'bad_node_char.dtb', @@ -14,13 +18,10 @@ treegen_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']) +testutil_dep = declare_dependency(sources: ['testutils.c'], link_with: trees) tests = [ 'add_subnode_with_nops', @@ -88,11 +89,13 @@ 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] @@ -137,10 +140,10 @@ run_test_types = [ 'fdtget', 'fdtput', 'fdtdump', - 'fdtoverlay', + 'fdtoverlay' ] run_test_deps = [ - dtc_tools, treegen_dtb, tests_exe, + dtc_tools, dumptrees_dtb, tests_exe ] if pylibfdt_enabled run_test_types += 'pylibfdt' diff --git a/tests/pylibfdt_tests.py b/tests/pylibfdt_tests.py index 6af11f2..a4f73ed 100644 --- a/tests/pylibfdt_tests.py +++ b/tests/pylibfdt_tests.py @@ -13,15 +13,26 @@ 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_1 = 0x0000000000100000 -TEST_ADDR_2 = 123456789 -TEST_SIZE_2 = 0o10000 +TEST_SIZE_1H = 0x00000000 +TEST_SIZE_1L = 0x00100000 +TEST_SIZE_1 = (TEST_SIZE_1H << 32) | TEST_SIZE_1L +TEST_ADDR_2H = 0 +TEST_ADDR_2L = 123456789 +TEST_ADDR_2 = (TEST_ADDR_2H << 32) | TEST_ADDR_2L +TEST_SIZE_2H = 0 +TEST_SIZE_2L = 0o10000 +TEST_SIZE_2 = (TEST_SIZE_2H << 32) | TEST_SIZE_2L TEST_VALUE_1 = 0xdeadbeef TEST_VALUE_2 = 123456789 -TEST_VALUE64_1 = 0xdeadbeef01abcdef +TEST_VALUE64_1H = 0xdeadbeef +TEST_VALUE64_1L = 0x01abcdef +TEST_VALUE64_1 = (TEST_VALUE64_1H << 32) | TEST_VALUE64_1L PHANDLE_1 = 0x2000 PHANDLE_2 = 0x2001 diff --git a/tests/run_tests.sh b/tests/run_tests.sh index 842b543..f07092b 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -492,10 +492,9 @@ 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 truncated_property.dtb - run_test truncated_string truncated_string.dtb - run_test truncated_memrsv truncated_memrsv.dtb - run_test unterminated_memrsv unterminated_memrsv.dtb + run_test truncated_property + run_test truncated_string + run_test truncated_memrsv # Check aliases support in fdt_path_offset run_dtc_test -I dts -O dtb -o aliases.dtb "$SRCDIR/aliases.dts" diff --git a/tests/testdata.h b/tests/testdata.h index c1eac10..fcebc2c 100644 --- a/tests/testdata.h +++ b/tests/testdata.h @@ -1,12 +1,28 @@ -#define TEST_ADDR_1 0xdeadbeef00000000ULL -#define TEST_SIZE_1 0x0000000000100000ULL -#define TEST_ADDR_2 123456789ULL -#define TEST_SIZE_2 010000ULL +#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_VALUE_1 0xdeadbeef #define TEST_VALUE_2 123456789 -#define TEST_VALUE64_1 0xdeadbeef01abcdefULL +#define TEST_VALUE64_1H ASM_CONST_LL(0xdeadbeef) +#define TEST_VALUE64_1L ASM_CONST_LL(0x01abcdef) +#define TEST_VALUE64_1 ((TEST_VALUE64_1H << 32) | TEST_VALUE64_1L) #define PHANDLE_1 0x2000 #define PHANDLE_2 0x2001 @@ -29,3 +45,16 @@ #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__ */ diff --git a/tests/tests.h b/tests/tests.h index 578d8c1..7c1b6c0 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -25,6 +25,9 @@ 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__); \ @@ -36,18 +39,21 @@ void test_init(int argc, char *argv[]); #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) @@ -55,18 +61,21 @@ void test_init(int argc, char *argv[]); /* 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) diff --git a/tests/testutils.c b/tests/testutils.c index 6d69e87..54da2e4 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -42,21 +42,29 @@ static inline void VALGRIND_MAKE_MEM_DEFINED(void *p, size_t len) int verbose_test = 1; char *test_name; -static void sigint_handler(int signum) +void __attribute__((weak)) cleanup(void) { - fprintf(stderr, "%s: signal %d (pid=%d)\n", test_name, - signum, getpid()); +} + +static void sigint_handler(int signum, siginfo_t *si, void *uc) +{ + cleanup(); + fprintf(stderr, "%s: %s (pid=%d)\n", test_name, + strsignal(signum), getpid()); exit(RC_BUG); } void test_init(int argc, char *argv[]) { + int err; + struct sigaction sa_int = { + .sa_sigaction = sigint_handler, + }; + test_name = argv[0]; - /* Use signal(), not sigaction() because it also works on the Windows / - * mingw environments we support. - */ - if (signal(SIGINT, sigint_handler) == SIG_ERR) + err = sigaction(SIGINT, &sa_int, NULL); + if (err) FAIL("Can't install SIGINT handler"); if (getenv("QUIET_TEST")) diff --git a/tests/treegen.c b/tests/treegen.c deleted file mode 100644 index 6891bfd..0000000 --- a/tests/treegen.c +++ /dev/null @@ -1,756 +0,0 @@ -// 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 -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#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 \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; -} diff --git a/tests/trees.S b/tests/trees.S new file mode 100644 index 0000000..d69f7f1 --- /dev/null +++ b/tests/trees.S @@ -0,0 +1,326 @@ +#include +#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: diff --git a/tests/truncated_memrsv.c b/tests/truncated_memrsv.c index e9b18cc..d78036c 100644 --- a/tests/truncated_memrsv.c +++ b/tests/truncated_memrsv.c @@ -15,17 +15,13 @@ #include "tests.h" #include "testdata.h" -#define SPACE 65536 - int main(int argc, char *argv[]) { - void *fdt; - void *buf; + void *fdt = &truncated_memrsv; int err; uint64_t addr, size; test_init(argc, argv); - fdt = load_blob_arg(argc, argv); err = fdt_check_header(fdt); if (err != 0) @@ -50,11 +46,5 @@ 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(); } diff --git a/tests/truncated_property.c b/tests/truncated_property.c index eb09aa4..d9d52b2 100644 --- a/tests/truncated_property.c +++ b/tests/truncated_property.c @@ -13,15 +13,17 @@ #include #include "tests.h" +#include "testdata.h" int main(int argc, char *argv[]) { - void *fdt; + void *fdt = &truncated_property; const void *prop; int len; test_init(argc, argv); - fdt = load_blob_arg(argc, argv); + + vg_prepare_blob(fdt, fdt_totalsize(fdt)); prop = fdt_getprop(fdt, 0, "truncated", &len); if (prop) diff --git a/tests/truncated_string.c b/tests/truncated_string.c index 45e6cd3..d745414 100644 --- a/tests/truncated_string.c +++ b/tests/truncated_string.c @@ -13,16 +13,18 @@ #include #include "tests.h" +#include "testdata.h" int main(int argc, char *argv[]) { - void *fdt; + void *fdt = &truncated_string; const struct fdt_property *good, *bad; int off, len; const char *name; test_init(argc, argv); - fdt = load_blob_arg(argc, argv); + + vg_prepare_blob(fdt, fdt_totalsize(fdt)); off = fdt_first_property_offset(fdt, 0); good = fdt_get_property_by_offset(fdt, off, NULL); diff --git a/tests/unterminated_memrsv.c b/tests/unterminated_memrsv.c deleted file mode 100644 index a19dc2d..0000000 --- a/tests/unterminated_memrsv.c +++ /dev/null @@ -1,68 +0,0 @@ -// 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 - */ - -#include -#include -#include -#include - -#include - -#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(); -}