Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,7 @@ include/target.h: $(TARGET_H_TEMPLATE) FORCE
sed -e "s/@WOLFBOOT_DTS_UPDATE_ADDRESS@/$(WOLFBOOT_DTS_UPDATE_ADDRESS)/g" | \
sed -e "s/@WOLFBOOT_LOAD_ADDRESS@/$(WOLFBOOT_LOAD_ADDRESS)/g" | \
sed -e "s/@WOLFBOOT_LOAD_DTS_ADDRESS@/$(WOLFBOOT_LOAD_DTS_ADDRESS)/g" | \
sed -e "s/@WOLFBOOT_LOAD_RAMDISK_ADDRESS@/$(WOLFBOOT_LOAD_RAMDISK_ADDRESS)/g" | \
sed -e "s|@WOLFBOOT_RAMBOOT_MAX_SIZE_DEFINE@|$(if $(strip $(WOLFBOOT_RAMBOOT_MAX_SIZE)),#define WOLFBOOT_RAMBOOT_MAX_SIZE $(WOLFBOOT_RAMBOOT_MAX_SIZE),/* WOLFBOOT_RAMBOOT_MAX_SIZE undefined */)|g" | \
sed -e "s/@WOLFBOOT_PARTITION_SELF_HEADER_ADDRESS@/$(WOLFBOOT_PARTITION_SELF_HEADER_ADDRESS)/g" \
> $@
Expand Down
3 changes: 3 additions & 0 deletions config/examples/polarfire_mpfs250.config
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ WOLFTPM?=0
ELF?=1
#DEBUG_ELF?=1

# Native gzip decompression for FIT subimages (set GZIP=0 to disable)
GZIP?=1

# Use RISC-V assembly version of ECDSA and SHA
NO_ASM?=0

Expand Down
3 changes: 3 additions & 0 deletions config/examples/polarfire_mpfs250_qspi.config
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ WOLFTPM?=0
ELF?=1
#DEBUG_ELF?=1

# Native gzip decompression for FIT subimages (set GZIP=0 to disable)
GZIP?=1

# Use RISC-V assembly version of ECDSA and SHA
NO_ASM?=0

Expand Down
3 changes: 3 additions & 0 deletions config/examples/versal_vmk180.config
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ NO_XIP=1
# ELF loading support
ELF?=1

# Native gzip decompression for FIT subimages (set GZIP=0 to disable)
GZIP?=1

# Toolchain
USE_GCC=1
CROSS_COMPILE=aarch64-none-elf-
Expand Down
3 changes: 3 additions & 0 deletions config/examples/versal_vmk180_sdcard.config
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ NO_XIP=1
# ELF loading support
ELF?=1

# Native gzip decompression for FIT subimages (set GZIP=0 to disable)
GZIP?=1

# Boot Benchmarking (optional)
BOOT_BENCHMARK?=1

Expand Down
3 changes: 3 additions & 0 deletions config/examples/zynqmp.config
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ USE_GCC=1
ELF?=1
#DEBUG_ELF?=1

# Native gzip decompression for FIT subimages (set GZIP=0 to disable)
GZIP?=1

# Flash Sector Size
WOLFBOOT_SECTOR_SIZE=0x20000
# Application Partition Size
Expand Down
18 changes: 18 additions & 0 deletions config/examples/zynqmp_sdcard.config
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ NO_XIP=1
ELF?=1
#DEBUG_ELF?=1

# Native gzip decompression for FIT subimages (set GZIP=0 to disable)
GZIP?=1

# Boot Exception Level: leave wolfBoot at EL2 for handoff to Linux (matches
# the standard PetaLinux U-Boot flow and preserves KVM/hypervisor use of
# EL2). The EL2 Linux-cleanup path in do_boot() will clean dcache/disable
Expand Down Expand Up @@ -100,6 +103,21 @@ CFLAGS_EXTRA+=-DDISK_BLOCK_SIZE=0x80000
# Check `ls /sys/class/mmc_host/` on your running target to confirm.
CFLAGS_EXTRA+=-DLINUX_BOOTARGS_ROOT=\"/dev/mmcblk0p4\"

# ============================================================================
# Optional: FIT-bundled initramfs (ramdisk) instead of an on-disk rootfs
# ============================================================================
# Expects the PetaLinux INITRAMFS_IMAGE_BUNDLE=0 layout (FIT contains kernel
# + DTB + ramdisk). wolfBoot extracts the ramdisk to
# WOLFBOOT_LOAD_RAMDISK_ADDRESS and patches the loaded DTB with
# /chosen/linux,initrd-{start,end} so the kernel can find it. Compressed
# (gzip) ramdisks decompress automatically when GZIP=1.
#
# To enable: uncomment the three lines below and comment out the
# LINUX_BOOTARGS_ROOT line above (root= is supplied by the cpio's /init).
#FIT_RAMDISK?=1
#WOLFBOOT_LOAD_RAMDISK_ADDRESS?=0x40000000
#CFLAGS_EXTRA+=-DLINUX_BOOTARGS='"earlycon console=ttyPS0,115200 init_fatal_sh=1"'

# ============================================================================
# Boot Memory Layout
# ============================================================================
Expand Down
195 changes: 192 additions & 3 deletions docs/Targets.md
Original file line number Diff line number Diff line change
Expand Up @@ -1257,7 +1257,45 @@ MACHINE=mpfs-video-kit bitbake mchp-base-image-sdk

Build images are output to: `./tmp-glibc/deploy/images/mpfs-video-kit/`

#### Custom FIT image, signing and coping to SDCard
#### Custom FIT image, signing and copying to SDCard

wolfBoot can either decompress a gzipped kernel at boot time (`GZIP=1`,
the default for `polarfire_mpfs250.config` and `polarfire_mpfs250_qspi.config`)
or accept a pre-decompressed kernel inside the FIT (`GZIP=0`). Pick one path.

##### Option A - Compressed FIT (`GZIP=1`, default)

Set `compression = "gzip"` and point `data` at the gzipped kernel directly
in `hal/mpfs250.its`:

```dts
images {
kernel-1 {
data = /incbin/("../yocto-dev-polarfire/build/tmp-glibc/work/mpfs_video_kit-oe-linux/linux-mchp/6.12.22+git/build/linux.bin.gz");
compression = "gzip";
load = <0x80200000>;
entry = <0x80200000>;
hash-1 { algo = "sha256"; };
...
};
};
```

Then build the FIT directly - no manual `gzip -cdvk` step:

```sh
sudo dd if=wolfboot.bin of=/dev/sdc1 bs=512 && sudo cmp wolfboot.bin /dev/sdc1
mkimage -f hal/mpfs250.its fitImage
```

At boot, wolfBoot decompresses the kernel into `0x80200000` directly out of
the FIT `data` blob and verifies the FIT `hash-1` SHA-256 against the
decompressed bytes (defense-in-depth on top of the outer wolfBoot signature).

##### Option B - Uncompressed FIT (`GZIP=0`)

Build wolfBoot with `GZIP=0` and pre-decompress the kernel on the host.
Keep `compression = "none"` in `hal/mpfs250.its`:

```sh
# Copy wolfBoot to "BIOS" partition
Expand Down Expand Up @@ -3390,6 +3428,112 @@ Application running successfully!
Entering idle loop...
```

**Booting Linux via FIT image**

wolfBoot is a drop-in replacement for U-Boot's FIT image loader: it parses
the same `mkimage`-produced multi-component FIT (kernel + DTB + optional
ramdisk), honors per-subimage `load`/`entry`/`compression` properties, and
hands off to the kernel the same way - with the added value of
authenticating the entire FIT against a wolfBoot signature before any
subimage is touched.

ZynqMP can chain into a Linux kernel (PetaLinux, Yocto, or any other
producer) using the same FIT mechanism as the Versal target. wolfBoot's
FIT-using configs (`zynqmp.config` and `zynqmp_sdcard.config`) default to
`GZIP=1`, which lets you point the FIT at a gzipped kernel (`Image.gz`)
directly:

```dts
images {
kernel-1 {
data = /incbin/("Image.gz");
compression = "gzip";
load = <0x10000000>;
entry = <0x10000000>;
hash-1 { algo = "sha256"; };
};
};
```

`mkimage -f your-zynqmp.its fitImage` then produces a single signed FIT
that wolfBoot decompresses straight to the kernel load address at boot.
See the [Versal "Booting Linux via FIT image"](#versal-gen-1-vmk180)
section for a full walkthrough - the flow is identical apart from the
load addresses and the `bl31`/`fsbl` versus `bl31`/`plm` boot chain. Set
`GZIP=0` in
`.config` if you want to keep using an uncompressed `Image` plus
`compression = "none"`.

The decompressed-output bound for any single FIT subimage defaults to
`WOLFBOOT_FIT_MAX_DECOMP = 256 MB`. Override per target via
`CFLAGS+=-DWOLFBOOT_FIT_MAX_DECOMP=...` if a kernel/ramdisk legitimately
expands beyond that. The outer wolfBoot signature still authenticates the
entire FIT; this cap is defense-in-depth against a malformed-but-signed
stream.

**FIT ramdisk (initramfs)**

When PetaLinux is built with `INITRAMFS_IMAGE_BUNDLE = "0"` the rootfs cpio
ships as a separate `ramdisk` node in the FIT alongside the kernel and DTB.
wolfBoot can extract it, copy it to a configurable RAM address, and patch the
loaded DTB with `/chosen/linux,initrd-{start,end}` so the kernel finds it.
Enable this with `FIT_RAMDISK=1`:

```sh
cp config/examples/zynqmp_sdcard.config .config
# Uncomment the FIT_RAMDISK / WOLFBOOT_LOAD_RAMDISK_ADDRESS / LINUX_BOOTARGS
# block under "Optional: FIT-bundled initramfs" and comment out the
# LINUX_BOOTARGS_ROOT line above it.
make
```

Key options (in `config/examples/zynqmp_sdcard.config`):
- `FIT_RAMDISK=1` - enables FIT ramdisk extraction (`-DWOLFBOOT_FIT_RAMDISK`).
- `WOLFBOOT_LOAD_RAMDISK_ADDRESS=0x40000000` - destination address. Pick a
region clear of the kernel image (`~0x80000` + tens of MB) and clear of
FIT staging (`WOLFBOOT_LOAD_ADDRESS=0x10000000` + FIT size). The default
`0x40000000` leaves ~1 GB of headroom on a 4 GB ZCU102. Set to `0` to
honor the FIT's own `load = <...>` property verbatim instead.
- `LINUX_BOOTARGS` should drop `root=...` since the ramdisk is the rootfs.

Compressed (gzip) ramdisks are supported transparently when `GZIP=1` is set
(the same gzip path used for the kernel handles `compression = "gzip"` on
the ramdisk node). The outer wolfBoot signature already authenticates the
entire FIT, so the ramdisk inherits authentication without per-image
hashing - though if the FIT does include a `hash-1` subnode under the
ramdisk image, wolfBoot will verify it after decompression.

Example FIT layout:

```dts
images {
kernel-1 { ... };
fdt-1 { ... };
ramdisk-1 {
data = /incbin/("rootfs.cpio.gz");
type = "ramdisk";
compression = "gzip"; /* or "none" */
load = <0x40000000>; /* required for decompression / relocation */
hash-1 { algo = "sha256"; };
};
Comment thread
dgarske marked this conversation as resolved.
};
configurations {
default = "conf-zcu102";
conf-zcu102 {
kernel = "kernel-1";
fdt = "fdt-1";
ramdisk = "ramdisk-1";
};
};
```

Successful boot prints:
```
Loading ramdisk: 0x... -> 0x40000000 (N bytes)
FDT: Set chosen (...), linux,initrd-start=1073741824
FDT: Set chosen (...), linux,initrd-end=...
```


## Versal Gen 1 VMK180

Expand Down Expand Up @@ -3544,14 +3688,15 @@ Application running successfully!
Entering idle loop...
```

**Booting PetaLinux (QSPI)**
**Booting Linux via FIT image (QSPI)**

wolfBoot can boot a signed Linux kernel on the Versal VMK180, replacing U-Boot entirely for a secure boot chain.

Prerequisites:
1. **PetaLinux 2024.2** (or compatible version) built for VMK180
2. **Pre-built Linux images** from your PetaLinux build:
- `Image` - Uncompressed Linux kernel (ARM64)
- `Image.gz` - gzip-compressed kernel (used with `GZIP=1`, see below)
- `system-default.dtb` - Device tree blob for VMK180
3. **SD card** with root filesystem (PetaLinux rootfs.ext4 written to partition 2)

Expand All @@ -3560,7 +3705,51 @@ wolfBoot uses a FIT (Flattened Image Tree) image containing the kernel and devic
- DTB load address: `0x00001000`
- SHA256 hashes for integrity

Create and sign the FIT image, then flash to QSPI:
`config/examples/versal_vmk180.config` and `config/examples/versal_vmk180_sdcard.config`
default to `GZIP=1`, so wolfBoot can decompress a gzipped kernel at boot
time. Pick one of the two flows below.

##### Option A - Compressed kernel (`GZIP=1`, default)

Edit `hal/versal.its` to point the kernel `data` at the gzipped kernel
and set `compression = "gzip"`:

```dts
images {
kernel-1 {
data = /incbin/("Image.gz");
compression = "gzip";
load = <0x00200000>;
entry = <0x00200000>;
hash-1 { algo = "sha256"; };
...
};
};
```

Then build and flash the FIT directly - no manual `gunzip` step:

```sh
cp /path/to/petalinux/images/linux/Image.gz .
cp /path/to/petalinux/images/linux/system-default.dtb .
mkimage -f hal/versal.its fitImage
./tools/keytools/sign --ecc384 --sha384 fitImage wolfboot_signing_private_key.der 1

tftp ${loadaddr} fitImage_v1_signed.bin
sf probe 0
sf erase 0x800000 +${filesize}
sf write ${loadaddr} 0x800000 ${filesize}
```

The compressed FIT is roughly half the size of the uncompressed equivalent
on a typical PetaLinux ARM64 kernel, which lets a larger kernel fit in the
existing 44 MB QSPI partition. wolfBoot decompresses to `0x00200000` at boot
and verifies the FIT `hash-1` SHA-256 against the decompressed bytes.

##### Option B - Uncompressed kernel (`GZIP=0`)

Build wolfBoot with `GZIP=0` and use the uncompressed `Image` directly.
Keep `compression = "none"` in `hal/versal.its`:

```sh
cp /path/to/petalinux/images/linux/Image .
Expand Down
6 changes: 4 additions & 2 deletions hal/mpfs250.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,8 +327,10 @@ int hal_dts_fixup(void* dts_addr)
wolfBoot_printf("FDT: Version %d, Size %d\n",
fdt_version(fdt), fdt_totalsize(fdt));

/* Expand total size to allow adding/modifying properties */
fdt_set_totalsize(fdt, fdt_totalsize(fdt) + 512);
/* Expand total size to allow adding/modifying properties.
* Sizing comes from WOLFBOOT_FDT_FIXUP_HEADROOM in include/fdt.h. */
fdt_set_totalsize(fdt,
fdt_totalsize(fdt) + WOLFBOOT_FDT_FIXUP_HEADROOM);

/* Find /chosen node */
off = fdt_find_node_offset(fdt, -1, "chosen");
Expand Down
7 changes: 5 additions & 2 deletions hal/versal.c
Original file line number Diff line number Diff line change
Expand Up @@ -1276,8 +1276,11 @@ int hal_dts_fixup(void* dts_addr)
wolfBoot_printf("FDT: Version %d, Size %d\n",
fdt_version(fdt), fdt_totalsize(fdt));

/* Expand total size to allow adding/modifying properties */
fdt_set_totalsize(fdt, fdt_totalsize(fdt) + 512);
/* Expand total size to allow adding/modifying properties (bootargs and,
* when WOLFBOOT_FIT_RAMDISK is in play, linux,initrd-{start,end}).
* Sizing comes from WOLFBOOT_FDT_FIXUP_HEADROOM in include/fdt.h. */
fdt_set_totalsize(fdt,
fdt_totalsize(fdt) + WOLFBOOT_FDT_FIXUP_HEADROOM);

/* Find /chosen node; create it only if genuinely missing. Any other
* negative return (malformed FDT, etc.) is surfaced directly rather
Expand Down
13 changes: 8 additions & 5 deletions hal/zynq.c
Original file line number Diff line number Diff line change
Expand Up @@ -1927,11 +1927,14 @@ int hal_dts_fixup(void* dts_addr)
fdt_version(fdt), fdt_totalsize(fdt));

/* Expand totalsize so fdt_setprop() has in-blob free space to place
* a new/larger bootargs property. Physical headroom is already
* guaranteed by the load-address layout (DTB at WOLFBOOT_LOAD_DTS_ADDRESS,
* kernel loaded much higher), so growing the header is safe. Matches
* the pattern used in hal/versal.c:hal_dts_fixup. */
fdt_set_totalsize(fdt, fdt_totalsize(fdt) + 512);
* a new/larger bootargs property and (when WOLFBOOT_FIT_RAMDISK is in
* play) the linux,initrd-{start,end} properties. Physical headroom is
* already guaranteed by the load-address layout (DTB at
* WOLFBOOT_LOAD_DTS_ADDRESS, kernel loaded much higher), so growing
* the header is safe. Sizing comes from WOLFBOOT_FDT_FIXUP_HEADROOM
* in include/fdt.h - same constant as hal/versal.c. */
fdt_set_totalsize(fdt,
fdt_totalsize(fdt) + WOLFBOOT_FDT_FIXUP_HEADROOM);

/* Find /chosen node; create it only if genuinely missing. Any other
* negative return (malformed FDT, etc.) is surfaced directly rather
Expand Down
Loading
Loading