Skip to content
Merged
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
15 changes: 15 additions & 0 deletions files/wic/mpfs-wolfboot.wks
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# short-description: PolarFire SoC SD card for standalone M-mode wolfBoot
# long-description: Partitions 1 and 2 are wolfBoot's raw A/B slots
# (polarfire_mpfs250_m.config: BOOT_PART_A=0, BOOT_PART_B=1); partition 1 is
# filled with the signed FIT (image_signed.bin, the version-independent link
# wolfboot-signed-image deploys) and partition 2 is left empty for updates.
# The rootfs stays partition 3 as in the BSP layout. Partition 4 keeps the HSS
# payload, found by its GUID, so the same card still boots under HSS + U-Boot
# if the eNVM is reprogrammed.

part --source rawcopy --sourceparams="file=image_signed.bin" --ondisk mmcblk0 --part-name boot --fixed-size 65536K --align 4096
part --ondisk mmcblk0 --part-name update --fixed-size 65536K --align 4096
part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --label root --align 4096
part --source rawcopy --sourceparams="file=payload.bin" --ondisk mmcblk0 --part-name hssboot --fixed-size 8192K --align 1 --part-type 21686148-6449-6E6F-744E-656564454649

bootloader --ptable gpt
53 changes: 50 additions & 3 deletions recipes-wolfssl/wolfboot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ portable secure bootloader, as part of a Yocto / OpenEmbedded image.

| Recipe | Purpose |
|---|---|
| `wolfboot-keytools-native_git.bb` | Host-side `wolfboot-keygen` and `wolfboot-sign` utilities (RSA4096 key generation, RSA4096+SHA3-384 image signing). |
| `wolfboot-keytools-native_git.bb` | Host-side `wolfboot-keygen` and `wolfboot-sign` utilities (key generation and image signing: RSA4096+SHA3-384 by default, ECC384+SHA-384 for the PolarFire config). |
| `wolfboot_git.bb` | Cross-compiles `wolfboot.elf` (bare-metal, AArch64 / AArch32 / RISC-V). Picks a config from `${S}/config/examples/` per the `WOLFBOOT_CONFIG` variable. Consumes a user-supplied signing key via `WOLFBOOT_SIGNING_KEY` (see "Signing-key provisioning" below). |
| `wolfboot-signed-image.bb` | Signs the kernel FIT image (default `fitImage`) with RSA4096+SHA3-384 and emits `image_v${WOLFBOOT_IMAGE_VERSION}_signed.bin` into `DEPLOY_DIR_IMAGE`. |
| `wolfboot-signed-image.bb` | Signs the kernel FIT image (default `fitImage`) with `WOLFBOOT_SIGN_ALGO` + `WOLFBOOT_HASH_ALGO` (RSA4096+SHA3-384 by default) and emits `image_v${WOLFBOOT_IMAGE_VERSION}_signed.bin` into `DEPLOY_DIR_IMAGE`. |

A companion `recipes-bsp/bootbin/xilinx-bootbin_%.bbappend` overrides the
AMD/Xilinx `xilinx-bootbin` recipe to swap U-Boot for `wolfboot.elf` in
Expand All @@ -19,7 +19,9 @@ set in configuration (`local.conf` or a machine `.conf`).
## Signing-key provisioning (required)

`wolfboot_git.bb` and `wolfboot-signed-image.bb` both require you to
supply a pre-generated RSA4096 private key via `WOLFBOOT_SIGNING_KEY`.
supply a pre-generated private key via `WOLFBOOT_SIGNING_KEY` (RSA4096 by
default; ECC384 for the PolarFire config, see the PolarFire SoC quick start
below).
The recipes will **not** auto-generate one — that would leak the
private half through sstate and DEPLOY_DIR_IMAGE.

Expand Down Expand Up @@ -83,6 +85,51 @@ Artifacts deployed to `tmp/deploy/images/<MACHINE>/`:
Note: the private signing key is **not** deployed — it stays on the
workstation / secrets store you pointed `WOLFBOOT_SIGNING_KEY` at.

## Quick start (Microchip PolarFire SoC, standalone M-mode, SD-card boot)

On PolarFire SoC wolfBoot can replace the Hart Software Services (HSS) entirely: it boots from eNVM on the E51, initialises the PLL and LPDDR4, loads a signed Linux FIT from the SD card and hands off to S-mode (`polarfire_mpfs250_m.config`). The eNVM image is programmed with Microchip's `mpfsBootmodeProgrammer`, so the recipe deploys `wolfboot.elf` and leaves the eNVM programming to the user.

Three things differ from the ZynqMP flow:

- The M-mode build needs the Libero design's `fpga_design_config` header directory (DDR, clock and SEG settings). Pass it through `WOLFBOOT_EXTRA_MAKE_FLAGS`; the build has no way to generate it.
- The PolarFire example config signs with ECC384 / SHA-384, so the signing key is an ECC384 pair from `wolfboot-keygen --ecc384 -g <key>.der`. The private file keygen writes is `Qx || Qy || d`; the public half for `WOLFBOOT_PUBLIC_KEY` is its first 96 bytes (`head -c 96 <key>.der > <pub>.der`), which `keygen -i` reads as a raw public key.
- Partitions 1 and 2 of the SD card are the raw A/B slots (`BOOT_PART_A = 0`, `BOOT_PART_B = 1`); `files/wic/mpfs-wolfboot.wks` fills slot A with the signed FIT, leaves slot B empty, keeps the rootfs at partition 3 and moves the BSP's GUID-tagged HSS payload to partition 4, so the same card still boots under HSS + U-Boot if the eNVM is reprogrammed.
- The PolarFire config is in wolfBoot v2.10.0 and later, and the link flags the recipe adds need wolfBoot's `LDFLAGS_EXTRA` (wolfSSL/wolfBoot#921; on older revisions the recipe falls back to `CC` and `LD` overrides). Point `SRCREV_wolfboot` at a revision with both, as shown below.

```bitbake
WOLFBOOT_CONFIG = "polarfire_mpfs250_m.config"
WOLFBOOT_SIGNING_KEY = "/secure/path/wolfboot_signing_private_key.der"
WOLFBOOT_PUBLIC_KEY = "/secure/path/wolfboot_signing_public_key.der"
WOLFBOOT_EXTRA_MAKE_FLAGS = "LIBERO_FPGA_CONFIG_DIR=/path/to/boards/mpfs-video-kit/fpga_design_config"
# The M-mode image is soft-float lp64; the Linux toolchain's libgcc is lp64d
# and cannot be linked, and wolfBoot needs nothing from it on this target.
WOLFBOOT_NOSTDLIB = "1"
# The Microchip BSP builds its FIT with a gzip-compressed kernel.
WOLFBOOT_EXTRA_CONFIG_LINES = "GZIP=1"

# Match the config's SIGN / HASH.
WOLFBOOT_SIGN_ALGO = "ecc384"
WOLFBOOT_HASH_ALGO = "sha384"
KERNEL_PN:pn-wolfboot-signed-image = "linux-mchp"

EXTRA_IMAGEDEPENDS:append = " wolfboot wolfboot-signed-image"
WKS_FILE = "mpfs-wolfboot.wks"
WKS_FILE_DEPENDS:append = " wolfboot-signed-image"
# Releases before wrynose search <layer>/wic, not <layer>/files/wic, for .wks files.
WKS_SEARCH_PATH:prepend = "${WOLFSSL_LAYERDIR}/files/wic:"
```

Build with `MACHINE=mpfs-video-kit bitbake mchp-base-image`. The `.wic` is written to the SD card as-is; `wolfboot.elf` goes to eNVM with `mpfsBootmodeProgrammer.jar --bootmode 1`.

To build a wolfBoot branch that is not on `wolfssl/wolfBoot` master, point the fetcher at it instead of editing the recipe:

```bitbake
WOLFBOOT_GIT_URI = "git://github.com/<fork>/wolfBoot.git;protocol=https"
WOLFBOOT_GIT_BRANCH = "<branch>"
SRCREV_wolfboot = "<full commit sha on that branch>"
SRCREV_wolfssl = "<the branch's lib/wolfssl submodule commit>"
```

## Using an existing wolfSSL source tree

By default `wolfboot.inc` fetches a pinned wolfSSL (`SRCREV_wolfssl`) into
Expand Down
24 changes: 16 additions & 8 deletions recipes-wolfssl/wolfboot/wolfboot-signed-image.bb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
SUMMARY = "wolfBoot signed kernel FIT image"
DESCRIPTION = "Signs the kernel FIT image (fitImage / image.ub) with \
wolfBoot RSA4096+SHA3-384 for verified secure boot. The signed output is \
placed in DEPLOY_DIR_IMAGE as image_v<version>_signed.bin, ready for \
flashing to the OFP_A / OFP_B partitions of an A/B-enabled SD card or QSPI."
wolfBoot (RSA4096+SHA3-384 by default) for verified secure boot. The signed \
output is placed in DEPLOY_DIR_IMAGE as image_v<version>_signed.bin, ready \
for flashing to the OFP_A / OFP_B partitions of an A/B-enabled SD card or QSPI."

HOMEPAGE = "https://github.com/wolfssl/wolfBoot"
SECTION = "bootloaders"
Expand Down Expand Up @@ -44,6 +44,11 @@ WOLFBOOT_IMAGE_VERSION ?= "1"
# linux-xlnx on ZynqMP / Versal.
WOLFBOOT_FIT_IMAGE ?= "fitImage"

# wolfboot-sign algorithm options (no dashes); must match the config's
# SIGN / HASH and the key type.
WOLFBOOT_SIGN_ALGO ?= "rsa4096"
WOLFBOOT_HASH_ALGO ?= "sha3"

# Validate WOLFBOOT_SIGNING_KEY only when this recipe actually builds
# (see wolfboot_git.bb for the rationale re: parse-time vs task-time).
python check_wolfboot_signing_key() {
Expand Down Expand Up @@ -79,12 +84,12 @@ do_compile() {
# leaves publishing to do_deploy below.
cp "$fit_image" ${B}/${WOLFBOOT_FIT_IMAGE}

# Sign the FIT image with RSA4096 + SHA3-384 using the user-supplied
# signing key. wolfboot-sign emits the output NEXT TO the input file,
# naming it <input>_v<version>_signed.bin. Run from ${B} with a
# relative path so the output lands inside ${B} predictably.
# Sign the FIT image with the configured algorithms using the
# user-supplied signing key. wolfboot-sign emits the output NEXT TO the
# input file, naming it <input>_v<version>_signed.bin. Run from ${B}
# with a relative path so the output lands inside ${B} predictably.
cd ${B}
wolfboot-sign --rsa4096 --sha3 \
wolfboot-sign --${WOLFBOOT_SIGN_ALGO} --${WOLFBOOT_HASH_ALGO} \
${WOLFBOOT_FIT_IMAGE} \
${WOLFBOOT_SIGNING_KEY} \
${WOLFBOOT_IMAGE_VERSION}
Expand All @@ -96,6 +101,9 @@ do_deploy() {
install -d ${DEPLOYDIR}
install -m 0644 ${B}/${WOLFBOOT_FIT_IMAGE}_v${WOLFBOOT_IMAGE_VERSION}_signed.bin \
${DEPLOYDIR}/image_v${WOLFBOOT_IMAGE_VERSION}_signed.bin
# Version-independent name for wic layouts (WOLFBOOT_IMAGE_VERSION is not
# visible in the image recipe's datastore).
ln -sf image_v${WOLFBOOT_IMAGE_VERSION}_signed.bin ${DEPLOYDIR}/image_signed.bin
}

addtask deploy before do_build after do_compile
5 changes: 4 additions & 1 deletion recipes-wolfssl/wolfboot/wolfboot.inc
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,11 @@ WOLFBOOT_WOLFSSL_STAGED_SRC = "${WORKDIR}/wolfssl-external"
# upstream evolves. Downstream users can override via local.conf:
# SRCREV_wolfboot:pn-wolfboot = "<sha>"
# SRCREV_wolfboot:pn-wolfboot-keytools-native = "<sha>"
# Repository and branch; override in local.conf to build a fork or branch.
WOLFBOOT_GIT_URI ?= "git://github.com/wolfssl/wolfBoot.git;protocol=https"
WOLFBOOT_GIT_BRANCH ?= "master"
SRC_URI = " \
git://github.com/wolfssl/wolfBoot.git;protocol=https;branch=master;name=wolfboot;destsuffix=git \
${WOLFBOOT_GIT_URI};branch=${WOLFBOOT_GIT_BRANCH};name=wolfboot;destsuffix=git \
${@'' if d.getVar('WOLFBOOT_WOLFSSL_SRC') else 'git://github.com/wolfssl/wolfssl.git;protocol=https;branch=master;name=wolfssl;destsuffix=git/lib/wolfssl'} \
"
SRCREV_wolfboot ?= "9a667f2a7527da2b8e490ae7923665321af2d3ac"
Expand Down
75 changes: 61 additions & 14 deletions recipes-wolfssl/wolfboot/wolfboot_git.bb
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ WOLFBOOT_EXTRA_MAKE_FLAGS ?= ""
# coexist with the template's own CFLAGS_EXTRA lines.
WOLFBOOT_EXTRA_CONFIG_LINES ?= ""

# Link with -nostdlib: for configs built for an ABI the sysroot's libgcc does
# not match (PolarFire SoC M-mode is soft-float lp64 on an lp64d toolchain).
WOLFBOOT_NOSTDLIB ?= "0"

COMPATIBLE_MACHINE = ".*"
PACKAGE_ARCH = "${MACHINE_ARCH}"

Expand All @@ -80,15 +84,23 @@ python check_wolfboot_signing_key() {
pub = d.getVar('WOLFBOOT_PUBLIC_KEY') or ''
if not pub:
bb.fatal("WOLFBOOT_PUBLIC_KEY is not set. Extract the public half "
"from the private key with: openssl rsa -in <privkey>.der "
"-inform DER -pubout -outform DER -out <pubkey>.der")
"from the private key (RSA: openssl rsa -pubout; ECC: the "
"first Qx||Qy bytes, see recipes-wolfssl/wolfboot/README.md).")
if not os.path.isfile(pub):
bb.fatal("WOLFBOOT_PUBLIC_KEY='%s' does not exist or is not a "
"regular file." % pub)
}
do_compile[prefuncs] += "check_wolfboot_signing_key"

do_compile() {
# A re-run of do_compile keeps the tree; drop objects built with the
# previous .config (make tracks sources, not flags).
find ${S} \( -name '*.o' -o -name '*.d' \) -not -path '*/.git/*' -delete
if [ -n "${WOLFBOOT_WOLFSSL_SRC}" ] && [ -d "${WOLFBOOT_WOLFSSL_STAGED_SRC}" ]; then
find ${WOLFBOOT_WOLFSSL_STAGED_SRC} \( -name '*.o' -o -name '*.d' \) -delete
fi
rm -f ${S}/wolfboot.elf ${S}/wolfboot.map ${S}/src/keystore.c

# Seed wolfBoot's Makefile with the requested example .config.
if [ ! -f ${S}/config/examples/${WOLFBOOT_CONFIG} ]; then
bbfatal "WOLFBOOT_CONFIG='${WOLFBOOT_CONFIG}' not found under ${S}/config/examples/"
Expand All @@ -110,8 +122,8 @@ do_compile() {
# wolfBoot is a bare-metal bootloader (-nostdlib -ffreestanding), so we
# use raw make (not oe_runmake) to prevent Yocto's CC/CFLAGS/LDFLAGS
# from overriding wolfBoot's own toolchain settings. The Yocto cross
# compiler still needs --sysroot to find headers and libgcc; we embed
# it in CC so it applies to both compilation and linking.
# compiler still needs --sysroot to find headers and libgcc; it is
# appended to the .config below so it applies to compilation and linking.
#
# USER_PRIVATE_KEY + USER_PUBLIC_KEY tell wolfBoot's Makefile to use a
# pre-generated key pair instead of regenerating one inside the build
Expand All @@ -125,20 +137,54 @@ do_compile() {
# Both must be supplied by the user (generate via wolfboot-keygen).
if [ -z "${WOLFBOOT_PUBLIC_KEY}" ] || [ ! -f "${WOLFBOOT_PUBLIC_KEY}" ]; then
bbfatal "WOLFBOOT_PUBLIC_KEY is not set or the file does not exist. " \
"Generate both keys with 'wolfboot-keygen --rsa4096 -g <privkey>.der' " \
"then extract the public half with 'openssl rsa -in <privkey>.der " \
"-inform DER -pubout -outform DER -out <pubkey>.der'. Point both " \
"WOLFBOOT_SIGNING_KEY and WOLFBOOT_PUBLIC_KEY at the respective files."
"Generate the key pair with wolfboot-keygen and extract the public " \
"half (RSA: openssl rsa -pubout; ECC: the first Qx||Qy bytes), see " \
"recipes-wolfssl/wolfboot/README.md. Point WOLFBOOT_SIGNING_KEY and " \
"WOLFBOOT_PUBLIC_KEY at the respective files."
fi
PUBKEY_FOR_MAKE=${WOLFBOOT_PUBLIC_KEY}

unset CFLAGS CPPFLAGS CXXFLAGS LDFLAGS
SYSROOT_FLAG="--sysroot=${RECIPE_SYSROOT}"
# KEYGEN_TOOL override: wolfBoot's Makefile otherwise tries to build
# tools/keytools/keygen using the target cross-compiler and then run
# the resulting AArch64 binary on the x86_64 build host. Point it at
# the native keygen from wolfboot-keytools-native instead.

# glibc's <gnu/stubs.h> includes a per-ABI stubs-<abi>.h; when wolfBoot's
# -mabi differs from the sysroot's that file is missing. It only lists
# libc stubs, meaningless to a -nostdlib image, so supply empty ones.
LIBC_STUBS="${WORKDIR}/libc-stubs"
rm -rf "$LIBC_STUBS"; mkdir -p "$LIBC_STUBS/gnu"
for abi in lp64 lp64d ilp32 ilp32d 64 32 soft hard; do
if [ ! -e "${RECIPE_SYSROOT}/usr/include/gnu/stubs-$abi.h" ]; then
: > "$LIBC_STUBS/gnu/stubs-$abi.h"
fi
done
SYSROOT_FLAG="$SYSROOT_FLAG -isystem $LIBC_STUBS"

# Toolchain flags go through .config (CFLAGS_EXTRA / LDFLAGS_EXTRA are
# additive there); CC/LD on the make command line would leak the cross
# compiler into the sub-makes that build the host tools. No PIE and no
# build-id note: the image is linked at fixed addresses from its boot vector.
echo "CFLAGS_EXTRA+=$SYSROOT_FLAG -fno-pie" >> ${S}/.config
LD_EXTRA="$SYSROOT_FLAG -no-pie -Wl,--build-id=none"
if [ "${WOLFBOOT_NOSTDLIB}" = "1" ]; then
LD_EXTRA="$LD_EXTRA -nostdlib"
fi
# A wolfBoot without the LDFLAGS_EXTRA consumer (options.mk) gets the link
# flags the old way, as CC and LD overrides on the command line. Both,
# not just LD: such a wolfBoot also builds its in-tree keytools, whose
# sub-make inherits the command-line variables, and the host objects it
# compiles with its own CC do not link with the cross LD.
CC_ARG=""
LD_ARG=""
if grep -Eq 'LDFLAGS[[:space:]]*\+=[[:space:]]*\$\(LDFLAGS_EXTRA\)' ${S}/options.mk; then
echo "LDFLAGS_EXTRA+=$LD_EXTRA" >> ${S}/.config
else
CC_ARG="CC=${TARGET_PREFIX}gcc $SYSROOT_FLAG"
LD_ARG="LD=${TARGET_PREFIX}gcc $LD_EXTRA"
fi
Comment thread
night1rider marked this conversation as resolved.
Resolved

# Native keytools; with both given, wolfBoot skips its in-tree build.
NATIVE_KEYGEN="$(command -v wolfboot-keygen)"
NATIVE_SIGN="$(command -v wolfboot-sign)"

# Build wolfCrypt from a caller-supplied wolfSSL tree when asked.
# WOLFBOOT_LIB_WOLFSSL is wolfBoot's way to set an external wolfSSL source
Expand All @@ -156,11 +202,12 @@ do_compile() {

make wolfboot.elf \
CROSS_COMPILE=${TARGET_PREFIX} \
CC="${TARGET_PREFIX}gcc $SYSROOT_FLAG" \
LD="${TARGET_PREFIX}gcc $SYSROOT_FLAG" \
${CC_ARG:+"$CC_ARG"} \
${LD_ARG:+"$LD_ARG"} \
USER_PRIVATE_KEY="${WOLFBOOT_SIGNING_KEY}" \
USER_PUBLIC_KEY="$PUBKEY_FOR_MAKE" \
KEYGEN_TOOL="$NATIVE_KEYGEN" \
SIGN_TOOL="$NATIVE_SIGN" \
$WOLFSSL_LIB_ARG \
${WOLFBOOT_EXTRA_MAKE_FLAGS} \
V=1
Expand Down