Skip to content

FIT: gzip-compressed kernel + ramdisk (initramfs) support#763

Open
dgarske wants to merge 4 commits intowolfSSL:masterfrom
dgarske:fit_compressed
Open

FIT: gzip-compressed kernel + ramdisk (initramfs) support#763
dgarske wants to merge 4 commits intowolfSSL:masterfrom
dgarske:fit_compressed

Conversation

@dgarske
Copy link
Copy Markdown
Member

@dgarske dgarske commented Apr 29, 2026

Summary

Adds an in-tree DEFLATE/gzip inflater and wires it into the FIT image path so
wolfBoot can boot compressed Linux kernels and ramdisks directly out of a FIT
container, with per-subimage hash verification on top of the outer wolfBoot
signature. Also adds initramfs (ramdisk) extraction and DTB /chosen fixup so
the kernel can find the loaded ramdisk.

Default-on (GZIP=1) for the FIT-using example targets: ZynqMP (eMMC + SD),
Versal VMK180 (eMMC + SD), PolarFire MPFS250 (SD + QSPI). Builds on the
existing master configs are byte-identical to before this branch.

What's in here

gzip inflater (src/gzip.c, include/gzip.h)

  • Clean-room RFC 1951 (DEFLATE) + RFC 1952 (gzip wrapper) implementation.
  • Single pass, no heap allocations — output buffer doubles as the LZ77 window.
  • CRC32 + ISIZE trailer verified; gated by WOLFBOOT_GZIP.
  • wolfBoot C style: declarations at top of function, single return per
    function, /* … */ comments, every callee return code checked.

FIT integration (src/fdt.c, include/fdt.h)

  • New fit_load_image_ex(out_max); fit_load_image() kept as a wrapper so
    existing callers don't change.
  • When WOLFBOOT_GZIP is on and a subimage carries compression = "gzip",
    the inflater writes straight to the FIT-declared load address.
  • After load (compressed or not), fit_verify_hash checks the hash-1
    subnode against the loaded bytes. SHA-256 / SHA-384 return codes from
    wc_InitSha*, wc_Sha*Update, wc_Sha*Final are now propagated — a
    misbehaving crypto backend can't silently degrade to a no-op.

Ramdisk / initramfs support

  • fit_find_images() gains a ramdisk out-arg.
  • New fdt_fixup_initrd() writes /chosen/linux,initrd-start and
    linux,initrd-end as 64-bit big-endian cells.
  • src/update_disk.c and src/update_ram.c load the FIT ramdisk node
    (under WOLFBOOT_FIT_RAMDISK) and patch the DTB.
  • Compressed ramdisks reuse the same fit_load_image_ex() decompress path.
  • RAMDISK=1 build switch + WOLFBOOT_LOAD_RAMDISK_ADDRESS plumbed
    through tools/config.mkMakefile sed → include/target.h.in.
    WOLFBOOT_LOAD_RAMDISK_ADDRESS=0 (the default) keeps the ramdisk
    wherever fit_load_image returned it (FIT load addr or in-FIT pointer).
  • hal/zynq.c and hal/versal.c fdt_totalsize headroom bumped
    512 → 768 bytes to fit the new linux,initrd-{start,end} entries.

Example configs

  • New config/examples/zynqmp_sdcard_ramdisk.config
    (load address 0x40000000).
  • GZIP=1 flipped on by default in: zynqmp.config,
    zynqmp_sdcard.config, polarfire_mpfs250.config,
    polarfire_mpfs250_qspi.config, versal_vmk180.config,
    versal_vmk180_sdcard.config. Pass GZIP=0 to opt out and keep the
    pre-branch host-side gzip workflow.

Unit tests (tools/unit-tests/unit-gzip.c)

  • 6 round-trip corpora (empty, short text, all-zeros, structured text,
    pseudo-random, ~2 MB kernel-sized) — host gzip(1)wolfBoot_gunzip.
  • 9 negative cases: bad magic, bad CM, reserved FLG bits, truncated
    header, truncated DEFLATE body, CRC32 mismatch, ISIZE mismatch, output
    overflow, NULL parameters.
  • All 15 cases pass under libcheck.

Docs (docs/Targets.md)

  • Versal PetaLinux walkthrough now documents both GZIP=1 (default,
    compression="gzip" + Image.gz) and GZIP=0 (plain Image) flows.
  • New ZynqMP "Booting PetaLinux" subsection covering the same mechanism
    plus the RAMDISK=1 / WOLFBOOT_LOAD_RAMDISK_ADDRESS setup and a
    sample ITS layout for kernel + DTB + initramfs.
  • PolarFire MPFS250 SD-card section now describes Option A (default,
    compression="gzip", mkimage builds the FIT directly) and Option B
    (host-side gzip -cdvk, compression="none").

Notes for reviewers

  • The gzip inflater is the only new crypto-adjacent code path; defense in
    depth is provided by the existing wolfBoot signature on the outer FIT
    plus the per-subimage hash-1 verify. CRC32 in the gzip trailer is a
    data-integrity check, not a security boundary.
  • No public API signatures changed. fit_load_image keeps its old
    prototype; the new behavior is reached via fit_load_image_ex.
  • WOLFBOOT_LOAD_RAMDISK_ADDRESS=0 is the safe default — when unset the
    ramdisk stays wherever the FIT/loader put it.

@dgarske dgarske self-assigned this Apr 29, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds native gzip/DEFLATE decompression to wolfBoot’s FIT image loading path, plus optional FIT ramdisk extraction with DTB /chosen initrd fixups, along with build/config toggles, documentation updates, and unit tests.

Changes:

  • Introduces an in-tree gzip inflater (src/gzip.c, include/gzip.h) with host-side unit tests.
  • Extends FIT parsing/loading to support compression = "gzip", per-subimage hash-1 verification, and optional ramdisk discovery + DTB initrd fixups.
  • Wires new GZIP/RAMDISK build switches and load-address configuration through the build system and example configs/docs.

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
tools/unit-tests/unit-gzip.c Adds host unit tests for the gzip inflater (round-trip + negative cases).
tools/unit-tests/Makefile Adds unit-gzip target to the unit test suite list and build rules.
tools/fdt-parser/fdt-parser.c Updates FIT parsing tool to display an optional ramdisk image.
tools/config.mk Plumbs WOLFBOOT_LOAD_RAMDISK_ADDRESS, GZIP, and RAMDISK through config variables.
src/update_ram.c Loads FIT ramdisk (optional) and applies DTB initrd fixups in RAM-boot path.
src/update_disk.c Loads FIT ramdisk (optional) and applies DTB initrd fixups in disk-boot path.
src/gzip.c Implements RFC1951/RFC1952 decompression behind WOLFBOOT_GZIP.
src/fdt.c Extends FIT loader for gzip decompression, hash verification, ramdisk discovery, and initrd fixups.
options.mk Adds build switches GZIP and RAMDISK and wires in gzip object/CFLAGS.
include/target.h.in Adds WOLFBOOT_LOAD_RAMDISK_ADDRESS template define.
include/gzip.h Declares gzip API and constants/error codes for wolfBoot gunzip.
include/fdt.h Updates FIT APIs and adds fdt_fixup_initrd() declaration.
hal/zynq.c Increases DTB totalsize headroom for new /chosen properties.
hal/versal.c Increases DTB totalsize headroom for new /chosen properties.
docs/Targets.md Documents gzip FIT flow + ramdisk/initramfs flow for multiple targets.
config/examples/zynqmp_sdcard.config Enables GZIP=1 by default and documents optional RAMDISK settings.
config/examples/zynqmp.config Enables GZIP=1 by default.
config/examples/versal_vmk180_sdcard.config Enables GZIP=1 by default.
config/examples/versal_vmk180.config Enables GZIP=1 by default.
config/examples/polarfire_mpfs250_qspi.config Enables GZIP=1 by default.
config/examples/polarfire_mpfs250.config Enables GZIP=1 by default.
Makefile Ensures WOLFBOOT_LOAD_RAMDISK_ADDRESS is substituted into include/target.h.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tools/unit-tests/unit-gzip.c Outdated
Comment thread tools/unit-tests/unit-gzip.c Outdated
Comment thread tools/unit-tests/unit-gzip.c Outdated
Comment thread tools/unit-tests/unit-gzip.c
Comment thread tools/unit-tests/unit-gzip.c Outdated
Comment thread src/fdt.c
Comment thread src/fdt.c
Comment thread src/fdt.c
Comment thread docs/Targets.md
Comment thread docs/Targets.md Outdated
dgarske added 3 commits April 29, 2026 11:29
New src/gzip.c implements DEFLATE (RFC 1951) plus the gzip wrapper
(RFC 1952) from the RFC text only. Single-pass inflate, no allocations:
the output buffer doubles as the LZ77 sliding window, so back-references
read from out[out_pos - distance]. Canonical Huffman decode using
counts[] / symbols[] tables, ~10x smaller code than fast lookup tables
which matters in the bootloader. CRC32 + ISIZE verified against the
gzip trailer. Gated by WOLFBOOT_GZIP.

include/gzip.h carries the public entry point plus the RFC-canonical
constants (magic bytes, CM=DEFLATE, fixed Huffman boundaries, EOB
symbol, dynamic block field widths, run-length repeat metadata, CRC32
init/final-XOR, header/trailer sizes, alphabet sizes) so future
maintainers can cross-reference the RFC sections by name instead of
chasing literal numbers.

Tests in tools/unit-tests/unit-gzip.c round-trip 6 corpora through host
gzip(1) and back through wolfBoot_gunzip (empty, short text, all-zeros,
structured text, pseudo-random, ~2 MB kernel-sized). 9 negative cases
cover bad magic, bad CM, reserved FLG bits, truncated header,
truncated DEFLATE body, CRC32 mismatch, ISIZE mismatch, output overflow,
and NULL parameters. All 15 pass under libcheck.
Wires the new wolfBoot_gunzip inflater into the FIT image-loading path
and adds initramfs (ramdisk) extraction with DTB /chosen fixup so a
single signed FIT can carry kernel, DTB, and rootfs.

GZIP path
---------
* fit_load_image_ex(out_max) added; fit_load_image kept as a wrapper.
* When a subimage carries compression="gzip", inflate straight to the
  FIT-declared load address, then verify the FIT hash-1 subnode
  (sha256 / sha384 if available) for defense in depth on top of the
  outer wolfBoot signature. The compression property is now read
  unconditionally so a build without WOLFBOOT_GZIP can warn and fail
  closed instead of silently memcpy-ing compressed bytes as if they
  were raw.
* fit_verify_hash propagates wc_InitSha256 / wc_Sha256Update /
  wc_Sha256Final return codes (and the SHA-384 equivalents) - any
  non-zero return is treated as a verification failure so a misbehaving
  backend cannot silently degrade to a no-op.
* GZIP=1 is the new default in the FIT-using example configs (zynqmp,
  zynqmp_sdcard, polarfire_mpfs250, polarfire_mpfs250_qspi,
  versal_vmk180, versal_vmk180_sdcard); set GZIP=0 to opt out.

Ramdisk path
------------
* fit_find_images() gains a ramdisk out-arg and fdt_fixup_initrd()
  writes /chosen/linux,initrd-{start,end} as 64-bit big-endian cells.
* update_disk.c and update_ram.c load the FIT ramdisk node (under
  WOLFBOOT_FIT_RAMDISK) and patch the loaded DTB. Compressed (gzip)
  ramdisks reuse the same fit_load_image_ex() decompress path.
* RAMDISK=1 build switch defines WOLFBOOT_FIT_RAMDISK;
  WOLFBOOT_LOAD_RAMDISK_ADDRESS is plumbed through tools/config.mk ->
  Makefile sed -> include/target.h.in. Defaults to 0; when 0 the
  ramdisk stays at whatever fit_load_image returned.
* hal/zynq.c and hal/versal.c bump fdt_totalsize headroom from 512 to
  768 bytes to fit the new linux,initrd-{start,end} entries.
* config/examples/zynqmp_sdcard.config gains a commented-out opt-in
  block (RAMDISK=1, WOLFBOOT_LOAD_RAMDISK_ADDRESS=0x40000000, alt
  LINUX_BOOTARGS) so a single config file covers both rootfs-on-disk
  and FIT-bundled-initramfs flows.

Builds against the existing master configs are byte-identical when
GZIP=0 and RAMDISK is unset.
…arFire

PolarFire MPFS250, Versal VMK180, and ZynqMP "Booting PetaLinux"
walkthroughs now describe both options for handing PetaLinux off through
the FIT image:

  * Option A (default GZIP=1): set compression="gzip" in the .its,
    point data at Image.gz / linux.bin.gz, and let mkimage build the
    FIT directly. wolfBoot decompresses straight to the kernel load
    address at boot and verifies hash-1.
  * Option B (GZIP=0): keep the existing host-side gzip -cdvk /
    gunzip step and compression="none" in the .its.

ZynqMP also gains a "FIT ramdisk (initramfs)" subsection covering
RAMDISK=1, WOLFBOOT_LOAD_RAMDISK_ADDRESS, the commented-out opt-in
block in zynqmp_sdcard.config, gzip ramdisk support, and a sample ITS
layout with kernel + DTB + ramdisk subimages.
Copy link
Copy Markdown

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fenrir Automated Review — PR #763

Scan targets checked: wolfboot-bugs, wolfboot-src

Findings: 3
3 finding(s) posted as inline comments (see file-level comments below)

This review was generated automatically by Fenrir. Findings are non-blocking.

Comment thread src/fdt.c Outdated
Comment thread src/fdt.c Outdated
Comment thread src/fdt.c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants