Use Altera's libfcs recipes and document the wolfSSL master pin for Agilex 5

pull/176/head
Aidan Garske 2026-10-20 08:31:46 -07:00
parent 774b1c2f61
commit 854d48cb0a
7 changed files with 112 additions and 128 deletions

View File

@ -55,13 +55,13 @@ BBFILES += "${LAYERDIR}/recipes-wolfssl/wolfssl/*.bb \
# xilinx-bootbin bbappend requires meta-xilinx-tools layer
BBFILES_DYNAMIC += "xilinx-tools:${LAYERDIR}/recipes-bsp/bootbin/*.bbappend"
# Enable with WOLFSSL_ALTERA_FCS = "1" in the build configuration.
# Enable with WOLFSSL_ALTERA_FCS = "1" in the build configuration. libfcs comes
# from an Altera layer (gsrd-intel-fcs-lib or socfpga-intel-fcs-lib) or the user.
WOLFSSL_ALTERA_FCS ?= "0"
WOLFSSL_FCS_PROVIDER ?= "libfcs"
WOLFSSL_FCS_PROVIDER ?= "gsrd-intel-fcs-lib"
WOLFSSL_ALTERA_FCS_BBFILES = \
"${LAYERDIR}/recipes-support/libfcs/libfcs_git.bb \
${LAYERDIR}/recipes-support/libfcs/wolfssl_%.bbappend \
${@'${LAYERDIR}/recipes-support/libfcs/gsrd-intel-fcs-lib_%.bbappend' if d.getVar('WOLFSSL_FCS_PROVIDER') == 'gsrd-intel-fcs-lib' else ''}"
"${LAYERDIR}/recipes-support/libfcs/wolfssl_%.bbappend \
${LAYERDIR}/recipes-support/libfcs/${WOLFSSL_FCS_PROVIDER}_%.bbappend"
BBFILES += "${@d.getVar('WOLFSSL_ALTERA_FCS_BBFILES') if d.getVar('WOLFSSL_ALTERA_FCS') == '1' else ''}"
# Uncomment if building bind with wolfSSL.

View File

@ -8,7 +8,15 @@ packaged wolfCrypt test on the board.
- An Agilex 5 GSRD Yocto build configured for the exact board and release.
- This `meta-wolfssl` layer in `BBLAYERS`.
- A kernel exposing `/sys/kernel/fcs_sysfs`.
- A layer that builds Altera's libfcs. The 26.1 GSRD's `meta-altera-fpga`
provides `gsrd-intel-fcs-lib`, and `meta-intel-fpga-refdes` provides
`socfpga-intel-fcs-lib`. A user recipe that installs the libfcs headers and
`libFCS.so` also works.
- A wolfSSL revision that contains the Agilex 5 port. wolfSSL 5.9.4 predates
it; see [Use a wolfSSL revision with the Agilex 5 port](#use-a-wolfssl-revision-with-the-agilex-5-port).
- A kernel exposing `/sys/kernel/fcs_sysfs/platform`. libfcs reads that file
during initialization. Older Altera kernels such as linux-socfpga 6.12.19
create `/sys/kernel/fcs_sysfs` without it, and libfcs then fails to start.
- An owner root key hash provisioned in the SDM.
Provisioning is outside this layer's scope. Follow Altera's device-security
@ -67,6 +75,9 @@ local_conf_header:
WOLFSSL_ALTERA_FCS = "1"
WOLFSSL_FCS_PROVIDER = "gsrd-intel-fcs-lib"
IMAGE_INSTALL:append = " wolfssl wolfcrypttest wolfcryptbenchmark "
# Remove after the first wolfSSL release that contains the Agilex 5 port.
SRC_URI:pn-wolfssl = "git://github.com/wolfssl/wolfssl.git;nobranch=1;protocol=https"
SRCREV:pn-wolfssl = "c177f861d0ecba3a998e1cae3d18d21103572aed"
```
Save the fragment as `wolfssl-fcs.yml`. Kas configurations can be combined
@ -82,17 +93,39 @@ repository URL and branch with:
.:
```
The 26.1 GSRD already provides the required headers and versioned runtime
library through `gsrd-intel-fcs-lib`. This layer adds the unversioned
`libFCS.so` linker name required by dependent recipes. Selecting the GSRD
provider prevents two recipes from installing the same library. A non-GSRD
build can omit the override and use meta-wolfssl's `libfcs` recipe instead.
meta-wolfssl does not build libfcs itself. `WOLFSSL_FCS_PROVIDER` names the
recipe that does, and defaults to the 26.1 GSRD's `gsrd-intel-fcs-lib`. Altera's
recipes install only the versioned runtime library, so this layer appends the
unversioned `libFCS.so` linker name to `gsrd-intel-fcs-lib` and
`socfpga-intel-fcs-lib`. Builds using `meta-intel-fpga-refdes` select its
recipe instead:
```bitbake
WOLFSSL_FCS_PROVIDER = "gsrd-intel-fcs-lib"
WOLFSSL_FCS_PROVIDER = "socfpga-intel-fcs-lib"
```
Use only one provider for `libFCS.so`.
A user supplied recipe must install `libFCS.so` itself. The port has been
validated with libfcs 3.01, the revision built by the 26.1 GSRD.
## Use a wolfSSL revision with the Agilex 5 port
The `--enable-alterafcs` option this layer passes exists only in wolfSSL
releases after 5.9.4. Until the next release, add a bbappend to your own layer,
for example `recipes-wolfssl/wolfssl/wolfssl_%.bbappend`, that builds a wolfSSL
master commit containing the port:
```bitbake
# Remove after the first wolfSSL release that contains the Agilex 5 port.
SRC_URI = "git://github.com/wolfssl/wolfssl.git;nobranch=1;protocol=https"
SRCREV = "c177f861d0ecba3a998e1cae3d18d21103572aed"
```
Keep the revision in `SRCREV`, not as `rev=` in the URL. The `%` append also
matches meta-openembedded's `wolfssl` recipe, which sets its own `SRCREV`, and a
`rev=` parameter would then conflict with it during parsing. The same two
assignments can be placed in `local.conf` or a Kas `local_conf_header` as
`SRC_URI:pn-wolfssl` and `SRCREV:pn-wolfssl`. Without them, `do_configure`
fails on the unrecognized option.
## Build the Agilex 5 image
@ -113,76 +146,65 @@ docker run --rm --user "$(id -u):$(id -g)" \
build kas.yml:wolfssl-fcs.yml gsrd-console-image
```
The expected SD card image is:
```text
build/tmp/deploy/images/agilex5e_013b/gsrd-console-image-agilex5e_013b.rootfs.wic
```
Fail the validation if that file is absent or empty:
```sh
test -s build/tmp/deploy/images/agilex5e_013b/\
gsrd-console-image-agilex5e_013b.rootfs.wic
sha256sum build/tmp/deploy/images/agilex5e_013b/\
gsrd-console-image-agilex5e_013b.rootfs.wic
```
Inspect the partition table and the installed test from an initialized
OpenEmbedded shell:
The SD card image is written to BitBake's `DEPLOY_DIR_IMAGE`. Its parent
`TMPDIR` depends on the distribution: Kas 4.x selects `poky` and uses
`build/tmp`, while Kas 5.x defaults to `nodistro` and uses `build/tmp-glibc`.
Ask BitBake for the directory instead of assuming either. From the same
`software/yocto_linux` directory, inspect the image and the installed test in an
initialized OpenEmbedded shell:
```sh
(
source poky/oe-init-build-env build
image=tmp/deploy/images/agilex5e_013b/\
gsrd-console-image-agilex5e_013b.rootfs.wic
native="$(find "$PWD/tmp/work" -type d \
-path '*/gsrd-console-image/*/recipe-sysroot-native' \
-print -quit)"
test -n "$native"
set -e
source poky/oe-init-build-env build >/dev/null
deploy="$(bitbake-getvar --value DEPLOY_DIR_IMAGE)"
image="$deploy/gsrd-console-image-agilex5e_013b.rootfs.wic"
test -s "$image"
sha256sum "$image"
native="$(bitbake-getvar -r gsrd-console-image --value RECIPE_SYSROOT_NATIVE)"
test -d "$native"
wic ls -n "$native" "$image"
wolfcrypt_bins="$(wic ls -n "$native" "$image:2/usr/bin/")"
printf '%s\n' "$wolfcrypt_bins"
printf '%s\n' "$wolfcrypt_bins" | grep -q 'wolfcrypttest'
printf '%s\n' "$wolfcrypt_bins" | grep -q 'wolfcryptbenchmark'
oe-pkgdata-util find-path /usr/bin/wolfcrypttest
printf 'image=%s\n' "$image"
)
```
When the image was built with the Kas container, run the same checks through
`kas shell` so Yocto's native tools retain the `/work` path used at build time:
When the image was built with the Kas container, run the same commands, without
the `source` line, through `kas shell` so Yocto's native tools retain the
`/work` path used at build time:
```sh
docker run --rm --user "$(id -u):$(id -g)" \
-e HOME=/work -v "$PWD:/work" -w /work \
ghcr.io/siemens/kas/kas:4.8 \
shell kas.yml:wolfssl-fcs.yml -c '
image=tmp/deploy/images/agilex5e_013b/\
gsrd-console-image-agilex5e_013b.rootfs.wic
native="$(find "$PWD/tmp/work" -type d \
-path "*/gsrd-console-image/*/recipe-sysroot-native" \
-print -quit)"
test -n "$native"
set -e
deploy="$(bitbake-getvar --value DEPLOY_DIR_IMAGE)"
image="$deploy/gsrd-console-image-agilex5e_013b.rootfs.wic"
test -s "$image"
sha256sum "$image"
native="$(bitbake-getvar -r gsrd-console-image \
--value RECIPE_SYSROOT_NATIVE)"
test -d "$native"
wic ls -n "$native" "$image"
wolfcrypt_bins="$(wic ls -n "$native" "$image:2/usr/bin/")"
printf "%s\n" "$wolfcrypt_bins"
printf "%s\n" "$wolfcrypt_bins" | grep -q wolfcrypttest
printf "%s\n" "$wolfcrypt_bins" | grep -q wolfcryptbenchmark
oe-pkgdata-util find-path /usr/bin/wolfcrypttest
printf "image=%s\n" "$image"
'
```
The image must contain a FAT boot partition and an ext4 root partition. The
second `wic ls` command must show both `wolfcrypttest` and
`wolfcryptbenchmark`, and the package lookup must report `wolfssl`.
Confirm that BitBake also staged the packaged test:
```sh
test -n "$(find build/tmp/work \
-path '*/wolfssl/*/packages-split/*/usr/bin/wolfcrypttest' \
-print -quit)"
```
The container reports paths under `/work`, which is the current directory on
the host. Either block must exit with status 0. The image must contain a FAT
boot partition and an ext4 root partition, the second `wic ls` command must
show both `wolfcrypttest` and `wolfcryptbenchmark`, and the package lookup must
report `wolfssl`. Keep the printed `image` path and SHA-256 for deployment.
## Deploy the image
@ -190,11 +212,11 @@ Power off the board and remove its microSD card. Attach the card to the build
server, identify the whole device by its capacity, and unmount any mounted
partitions. Device names vary: USB readers commonly appear as `/dev/sdX`, while
built-in readers may appear as `/dev/mmcblkN`. The example below uses the
device observed on the build server; replace it only after checking `lsblk`:
device observed on the build server; replace it only after checking `lsblk`.
Set `image` to the absolute path printed by the inspection step:
```sh
image=build/tmp/deploy/images/agilex5e_013b/\
gsrd-console-image-agilex5e_013b.rootfs.wic
image=/path/printed/by/inspection/gsrd-console-image-agilex5e_013b.rootfs.wic
card=/dev/mmcblk0
lsblk -o NAME,SIZE,TYPE,TRAN,RM,MODEL,MOUNTPOINTS
@ -240,9 +262,13 @@ Boot the deployed image and confirm that its packaged files are present:
```sh
test -x /usr/bin/wolfcrypttest
/lib/ld-linux-aarch64.so.1 --list /usr/bin/wolfcrypttest
test -e /sys/kernel/fcs_sysfs
test -r /sys/kernel/fcs_sysfs/platform
```
If `/sys/kernel/fcs_sysfs/platform` is missing, the kernel is too old for the
libfcs build in the image. libfcs fails to initialize and `wolfcrypttest`
skips the hardware test, so a zero exit status alone does not prove offload.
The DHCP address can change after booting a replacement image. Use the serial
console, the DHCP server's leases, or a local subnet scan to find the target
rather than assuming its previous address is retained.
@ -267,7 +293,8 @@ The Altera subtests require successful hardware operations for RNG, SHA-256,
and AES. They cannot pass solely through wolfSSL software fallback. Device
resident ECDSA and ECDH keys and HMAC verification are also exercised.
If only the Altera test fails, check SDM provisioning status `0x85`. Status
If the marker is missing, first confirm `/sys/kernel/fcs_sysfs/platform`
exists. If only the Altera test fails, check SDM provisioning status `0x85`. Status
`0x84` indicates session exhaustion and requires a board power cycle.
## Developer-only smoke test

View File

@ -1,13 +1 @@
# The Agilex 5 GSRD recipe installs only the versioned runtime library. Add the
# development linker name so dependent recipes can use -lFCS from their
# recipe-specific sysroots.
do_install:append() {
if [ -e ${D}${prefix}/lib/libFCS.so.3 ]; then
install -d ${D}${libdir}
if [ "${libdir}" = "${prefix}/lib" ]; then
ln -sfn libFCS.so.3 ${D}${libdir}/libFCS.so
else
ln -sfn ../lib/libFCS.so.3 ${D}${libdir}/libFCS.so
fi
fi
}
require libfcs-linker-name.inc

View File

@ -0,0 +1,15 @@
# Altera's libfcs recipes install only the versioned runtime library. Add the
# linker name so dependent recipes can use -lFCS from their sysroots.
do_install:append() {
for lib in ${D}${prefix}/lib/libFCS.so.[0-9]*; do
[ -e "$lib" ] || continue
name="$(basename "$lib")"
install -d ${D}${libdir}
if [ "${libdir}" = "${prefix}/lib" ]; then
ln -sfn "$name" ${D}${libdir}/libFCS.so
else
ln -sfn "../lib/$name" ${D}${libdir}/libFCS.so
fi
break
done
}

View File

@ -1,48 +0,0 @@
SUMMARY = "Altera FPGA Crypto Services library"
DESCRIPTION = "Userspace library for the FPGA Crypto Services of Altera \
SoCFPGA devices, exposing the Secure Device Manager crypto mailbox through \
/sys/kernel/fcs_sysfs."
HOMEPAGE = "https://github.com/altera-fpga/libfcs"
LICENSE = "MIT-0"
LIC_FILES_CHKSUM = "file://LICENSE;md5=6f25b4c3a6d23285f956387ab54830ad"
SRC_URI = "git://github.com/altera-fpga/libfcs.git;protocol=https;branch=main"
SRCREV = "87b4b726f4981be102fc8f09feab051fe3578334"
PV = "3.01+git"
DEPENDS = "dtc"
COMPATIBLE_HOST = "aarch64.*-linux"
python () {
if d.getVar('UNPACKDIR', False):
d.setVar('S', '${UNPACKDIR}/${BP}')
else:
d.setVar('S', '${WORKDIR}/git')
}
inherit cmake
EXTRA_OECMAKE = "-DARCH=linux_aarch64"
# upstream install() destinations are relative, so they nest under ${prefix}
wolfssl_fcs_fixup_install() {
if [ -d ${D}${prefix}${prefix} ]; then
cp -a ${D}${prefix}${prefix}/. ${D}${prefix}/
rm -rf ${D}${prefix}${prefix}
fi
# libfcs hardcodes /usr/lib. Move the library to Yocto's configured libdir,
# then supply the linker name expected by consumers such as wolfSSL.
if [ "${prefix}/lib" != "${libdir}" ] && \
[ -e ${D}${prefix}/lib/libFCS.so.3 ]; then
install -d ${D}${libdir}
mv ${D}${prefix}/lib/libFCS.so.3 ${D}${libdir}/
rmdir ${D}${prefix}/lib
fi
if [ -e ${D}${libdir}/libFCS.so.3 ]; then
ln -sfn libFCS.so.3 ${D}${libdir}/libFCS.so
fi
}
do_install[postfuncs] += "wolfssl_fcs_fixup_install"

View File

@ -0,0 +1 @@
require libfcs-linker-name.inc

View File

@ -1,10 +1,10 @@
# Altera Agilex 5 SDM crypto offload; needs an FCS provisioned device at
# runtime. GSRD stacks that already build the library can point this at
# their own recipe, e.g. WOLFSSL_FCS_PROVIDER = "gsrd-intel-fcs-lib".
# runtime. WOLFSSL_FCS_PROVIDER names the recipe that supplies libfcs.
def wolfssl_fcs_is_target(d):
return (d.getVar('CLASSOVERRIDE') == 'class-target' and
(d.getVar('HOST_SYS') or '').startswith('aarch64-'))
return (d.getVar('WOLFSSL_ALTERA_FCS') == '1' and
'class-target' in (d.getVar('OVERRIDES') or '').split(':') and
(d.getVar('TARGET_ARCH') or '') == 'aarch64')
WOLFSSL_FCS_CONFIGURE = "${@'--enable-alterafcs --enable-aesctr' if wolfssl_fcs_is_target(d) else ''}"
WOLFSSL_FCS_DEPENDS = "${@d.getVar('WOLFSSL_FCS_PROVIDER') if wolfssl_fcs_is_target(d) else ''}"
@ -13,8 +13,9 @@ EXTRA_OECONF += "${WOLFSSL_FCS_CONFIGURE}"
DEPENDS += "${WOLFSSL_FCS_DEPENDS}"
python () {
if (d.getVar('CLASSOVERRIDE') == 'class-target' and
if (d.getVar('WOLFSSL_ALTERA_FCS') == '1' and
'class-target' in (d.getVar('OVERRIDES') or '').split(':') and
not d.getVar('MLPREFIX') and
not (d.getVar('HOST_SYS') or '').startswith('aarch64-')):
(d.getVar('TARGET_ARCH') or '') != 'aarch64'):
bb.fatal('WOLFSSL_ALTERA_FCS requires an AArch64 target')
}