Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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).
#RAMDISK?=1
#WOLFBOOT_LOAD_RAMDISK_ADDRESS?=0x40000000
#CFLAGS_EXTRA+=-DLINUX_BOOTARGS='"earlycon console=ttyPS0,115200 init_fatal_sh=1"'
Comment thread
dgarske marked this conversation as resolved.

# ============================================================================
# Boot Memory Layout
# ============================================================================
Expand Down
184 changes: 182 additions & 2 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,103 @@ Application running successfully!
Entering idle loop...
```

**Booting PetaLinux**
Comment thread
dgarske marked this conversation as resolved.
Outdated

ZynqMP can chain into a PetaLinux kernel 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 PetaLinux"](#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 `RAMDISK=1`:

```sh
cp config/examples/zynqmp_sdcard.config .config
# Uncomment the 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`):
- `RAMDISK=1` - enables FIT ramdisk extraction (`-DWOLFBOOT_FIT_RAMDISK`).
Comment thread
dgarske marked this conversation as resolved.
Outdated
- `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 @@ -3552,6 +3687,7 @@ 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 +3696,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
5 changes: 3 additions & 2 deletions hal/versal.c
Original file line number Diff line number Diff line change
Expand Up @@ -1276,8 +1276,9 @@ 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}). */
fdt_set_totalsize(fdt, fdt_totalsize(fdt) + 768);
Comment thread
dgarske marked this conversation as resolved.
Outdated

/* Find /chosen node; create it only if genuinely missing. Any other
* negative return (malformed FDT, etc.) is surfaced directly rather
Expand Down
11 changes: 6 additions & 5 deletions hal/zynq.c
Original file line number Diff line number Diff line change
Expand Up @@ -1927,11 +1927,12 @@ 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. Matches the pattern in hal/versal.c. */
fdt_set_totalsize(fdt, fdt_totalsize(fdt) + 768);
Comment thread
dgarske marked this conversation as resolved.
Outdated

/* Find /chosen node; create it only if genuinely missing. Any other
* negative return (malformed FDT, etc.) is surfaced directly rather
Expand Down
9 changes: 8 additions & 1 deletion include/fdt.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,15 @@ int fdt_fixup_val64(void* fdt, int off, const char* node, const char* name, uint
int fdt_shrink(void* fdt);

/* FIT */
const char* fit_find_images(void* fdt, const char** pkernel, const char** pflat_dt);
const char* fit_find_images(void* fdt, const char** pkernel, const char** pflat_dt,
const char** pramdisk);
void* fit_load_image(void* fdt, const char* image, int* lenp);
void* fit_load_image_ex(void* fdt, const char* image, int* lenp, uint32_t out_max);

/* FDT initrd fixup: writes /chosen/linux,initrd-{start,end} as 64-bit
* big-endian properties. Creates /chosen if missing. Returns 0 on success
* or a negative FDT_ERR_*. */
int fdt_fixup_initrd(void* fdt, uint64_t start, uint64_t size);

#ifdef __cplusplus
}
Expand Down
Loading
Loading