Apalis iMX8QM Asynchronous SError Kernel Panic because of dm-verity secure boot and mender ota

Hi everyone,

I am running into a wall with a custom Yocto build integrating Mender and Toradex Secure Boot on an Apalis i.MX8QM. The kernel is panicking with an Asynchronous SError Interrupt during boot
Hardware & Software Setup

  • SoM: Toradex Apalis iMX8QM V1.1

  • Carrier Board: Apalis Ixora V1.2

  • bsp: 6.7.0

  • Boot Flow: U-Boot → FIT Image (Kernel, DTB, boot script) → dm-verity rootfs

The Problem: Kernel Panic (SError)

Once U-Boot passes control to the kernel, it begins booting but crashes at the 0.63 mark right after failing to power up audio-pll1sometimes after vpu reasons are different but always end up with that panic .

Here is the exact kernel panic log:

[    0.622503]  audio-pll1: failed to power up resource 492 ret -22
[    0.631241] SError Interrupt on CPU2, code 0x00000000bf000002 -- SError
[    0.631251] CPU: 2 PID: 1 Comm: swapper/0 Not tainted 5.15.148-6.7.0-devel+git.bfdbfb2c85fb #1
[    0.631258] Hardware name: Toradex Apalis iMX8QM V1.1 on Apalis Ixora V1.2 Carrier Board (DT)
[    0.631263] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[    0.631270] pc : 0xffff8000085d5ac4
[    0.631273] lr : 0xffff8000087368b0
[    0.631275] sp : ffff80000938ba00
...
[    0.631370] Kernel panic - not syncing: Asynchronous SError Interrupt
[    0.631375] SMP: stopping secondary CPUs
[    0.753546] ---[ end Kernel panic - not syncing: Asynchronous SError Interrupt ]---

i always used to face U-Boot required-bootargs problem

Trying 'kernel' kernel subimage Description: unavailable Type: Kernel Image Compression: gzip compressed Data Start: 0x9d5000c0 Data Size: 8180103 Bytes = 7.8 MiB Architecture: AArch64 OS: Linux Load Address: 0x95400000 Entry Point: 0x95400000 Hash algo: sha256 Hash value: de9f7a0a85280c37c52fef4cc0a2063cbf4c73179173da726ff983e704e8a65e Verifying Hash Integrity ... sha256+ OK ## Loading fdt from FIT Image at 9d500000 ... Using 'conf-freescale_imx8qm-apalis-v1.1-ixora-v1.2.dtb' configuration Verifying Hash Integrity ... sha256,rsa2048:dev+ OK Trying 'fdt' fdt subimage Description: unavailable Type: Flat Device Tree Compression: uncompressed Data Start: 0x9dccd320 Data Size: 172067 Bytes = 168 KiB Architecture: AArch64 Load Address: 0x9d400000 Hash algo: sha256 Hash value: abd99dd5b0151b7c9114961614a1deca9987b41f62ff0183090ef59667d769a6 Verifying Hash Integrity ... sha256+ OK Loading fdt from 0x9dccd320 to 0x9d400000 ## Loading fdt from FIT Image at 9d500000 ... Trying 'secure_node' fdt subimage Description: unavailable Type: Flat Device Tree Compression: uncompressed Data Start: 0x9dcf7400 Data Size: 180 Bytes = 180 Bytes Architecture: AArch64 Hash algo: sha256 Hash value: cff45644a016b6cd15b9b79b9dea841a1e07e54b2b2f0e69420f69fe10cc937f Verifying Hash Integrity ... sha256+ OK Booting using the fdt blob at 0x9d400000 Uncompressing Kernel Image Loading Device Tree to 00000000fcddc000, end 00000000fce09046 ... OK ## WARNING: Required node "/chosen/toradex,secure-boot" could not be found in device-tree. ## WARNING: Allowing boot while device is open; please fix bootargs before closing device. Disable dma-controller@599F0000 rsrc 463 not owned Disable crypto@31400000 rsrc 501 not owned Disable jr@30000 rsrc 501 not owned Disable jr@40000 rsrc 502 not owned Disable usb-phy@5b160000 rsrc 263 not owned Disable clock-controller@5b280000 rsrc 263 not owned Disable mailbox@2d000000 rsrc 535 not owned Disable clock-controller@56243010 rsrc 268 not owned Disable irqsteer@57220000 rsrc 397 not owned

[ 0.340256] thermal_sys: Registered thermal governor 'step_wise' [ 0.347329] thermal_sys: Registered thermal governor 'power_allocator' [ 0.354008] cpuidle: using governor menu [ 0.364365] hw-breakpoint: found 6 breakpoint and 4 watchpoint registers. [ 0.370990] ASID allocator initialised with 65536 entries [ 0.376453] imx mu driver is registered. [ 0.380184] imx rpmsg driver is registered. [ 0.448542] HugeTLB registered 1.00 GiB page size, pre-allocated 0 pages [ 0.454921] HugeTLB registered 32.0 MiB page size, pre-allocated 0 pages [ 0.461632] HugeTLB registered 2.00 MiB page size, pre-allocated 0 pages [ 0.468290] HugeTLB registered 64.0 KiB page size, pre-allocated 0 pages [ 0.476165] cryptd: max_cpu_qlen set to 1000 [ 0.483572] ACPI: Interpreter disabled. [ 0.489519] iommu: Default domain type: Translated [ 0.494066] iommu: DMA domain TLB invalidation policy: strict mode [ 0.500500] vgaarb: loaded [ 0.503301] usbcore: registered new interface driver usbfs [ 0.508516] usbcore: registered new interface driver hub [ 0.513800] usbcore: registered new device driver usb [ 0.520591] mc: Linux media interface: v0.10 [ 0.524537] videodev: Linux video capture interface: v2.00 [ 0.530047] pps_core: LinuxPPS API ver. 1 registered [ 0.534939] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it> [ 0.544076] PTP clock support registered [ 0.548291] EDAC MC: Ver: 3.0.0 [ 0.553784] imx-scu scu: NXP i.MX SCU Initialized [ 0.583402] imx8qm-pinctrl scu:pinctrl: initialized IMX pinctrl driver [ 0.594018] clocksource: Switched to clocksource arch_sys_counter [ 0.599962] VFS: Disk quotas dquot_6.6.0 [ 0.603736] VFS: Dquot-cache hash table entries: 512 (order 0, 4096 bytes) [ 0.610720] pnp: PnP ACPI: disabled [ 0.619966] SError Interrupt on CPU2, code 0x00000000bf000002 -- SError [ 0.619976] CPU: 2 PID: 1 Comm: swapper/0 Not tainted 5.15.148-6.7.0-devel+git.bfdbfb2c85fb #1 [ 0.619983] Hardware name: Toradex Apalis iMX8QM V1.1 on Apalis Ixora V1.2 Carrier Board (DT) [ 0.619988] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 0.619995] pc : 0xffff8000085d5a70 [ 0.619998] lr : 0xffff8000087368b0 [ 0.620000] sp : ffff80000938ba00 [ 0.620003] x29: ffff80000938ba00 x28: 0000000000000000 x27: 0000000000000000 [ 0.620015] x26: ffff0008006c6938 x25: 0000000000000001 x24: 0000000000000000 [ 0.620025] x23: 0000000000000015 x22: ffff0008006c68f4 x21: 0000000000000000 [ 0.620033] x20: ffff800008736884 x19: ffff0008006c6810 x18: ffffffffffffffff [ 0.620042] x17: 000000000000003f x16: 000000000000000c x15: ffff00080070ea1c [ 0.620051] x14: 0000000000000000 x13: 006d63612e303030 x12: 30306539353a3032 [ 0.620059] x11: 3a64706e65673a64 x10: 706e65673a726569 x9 : 0000000000000001 [ 0.620068] x8 : 0101010101010101 x7 : 7f7f7f7f7f7f7f7f x6 : 0000000000000058 [ 0.620076] x5 : 0000000000000058 x4 : 0000000000000000 x3 : ffff800009ae0000 [ 0.620084] x2 : 0000000000000000 x1 : ffff00080075ac80 x0 : ffff800009a00000 [ 0.620097] Kernel panic - not syncing: Asynchronous SError Interrupt [ 0.620102] SMP: stopping secondary CPUs [ 0.742277] ---[ end Kernel panic - not syncing: Asynchronous SError Interrupt ]---

any way these are my attempts to make both secure boot and mender ota work together plus an m4 binary loading and a u-boot splash screen
my local.conf:

=========================================================================

Mender OTA Configurations

=========================================================================

Mender Artifact name

MENDER_ARTIFACT_NAME = “test-v1.0”

specify bsp version

TORADEX_BSP_VERSION=“toradex-bsp-6.2.0”


 CONFIGURATIONS
INHERIT += “mender-full”
INHERIT += “mender-toradex”
DISTRO_FEATURES:append = " systemd"
VIRTUAL-RUNTIME_init_manager = “systemd”
DISTRO_FEATURES_BACKFILL_CONSIDERED = “sysvinit”
VIRTUAL-RUNTIME_initscripts = “”

serveur

MENDER_SERVER_URL = “****”
MENDER_TENANT_TOKEN = “**"
MENDER_DEMO_HOST_IP_ADDRESS = "”

Comment/remove below to enable GRUB integration instead of U-Boot

MENDER_FEATURES_ENABLE:append = " mender-uboot mender-image mender-image-sd"
MENDER_FEATURES_DISABLE:append = " mender-grub mender-image-uefi"

IMAGE_CLASSES += “image_type_mender_tezi”
IMAGE_FSTYPES:append = " mender_tezi"
IMAGE_FSTYPES:remove = " teziimg"
IMAGE_INSTALL:append = " kernel-image-fitimage"

Remove files from boot partition that are loaded by Mender

IMAGE_BOOT_FILES:remove:mender-uboot = “zImage ${KERNEL_DEVICETREE} overlays.txt overlays/*;overlays/”

Add fitImage to the boot partition for Mender

IMAGE_BOOT_FILES:remove = " fitImage"
#IMAGE_BOOT_FILES:append = " ${IMAGE_LINK_NAME}.boot.fit;boot.fit.2 ${IMAGE_LINK_NAME}.boot.fit;boot.fit.3"
IMAGE_BOOT_FILES:append = " ${IMAGE_LINK_NAME}.boot.fit;boot.fit"

Settings for apalis-imx8



MENDER_IMAGE_BOOTLOADER_BOOTSECTOR_OFFSET:apalis-imx8 = “0”
OFFSET_SPL_PAYLOAD:apalis-imx8 = “”
#MENDER_BOOT_PART_SIZE_MB:apalis-imx8 = “32”
MENDER_BOOT_PART_SIZE_MB:apalis-imx8 = “64”
#MENDER_STORAGE_TOTAL_SIZE_MB:apalis-imx8 = “12288”
IMAGE_OVERHEAD_FACTOR = “1.0”
MENDER_ROOTFS_PART_SIZE_MB:apalis-imx8 = “2000”
IMAGE_ROOTFS_SIZE = “${@int(d.getVar(‘MENDER_ROOTFS_PART_SIZE_MB’)) * 1024 - 102400}”
MENDER_STORAGE_TOTAL_SIZE_MB:apalis-imx8 = “4200”
KERNEL_DEVICETREE:apalis-imx8 = “freescale/imx8qm-apalis-v1.1-ixora-v1.2.dtb”
MENDER_STORAGE_DEVICE:apalis-imx8 = “/dev/mmcblk0”
MENDER_BOOT_PART = “${MENDER_STORAGE_DEVICE_BASE}1”
MENDER_DATA_PART = “${MENDER_STORAGE_DEVICE_BASE}4”
MENDER_ROOTFS_PART_A = “${MENDER_STORAGE_DEVICE_BASE}2”
MENDER_ROOTFS_PART_B = “${MENDER_STORAGE_DEVICE_BASE}3”

#meta-mender-validation configuration
MENDER_FEATURES_ENABLE:append = " mender-prepopulate-inactive-partition"
IMAGE_INSTALL:append = " bootloader-validation"


 Update Modules
IMAGE_INSTALL:append = " mender-rootfs-version-check mender-update-modules"

#Signing artifacts
MENDER_ARTIFACT_SIGNING_KEY = “/home/rania/keys/client/private.key”

Append the Mender provided bootargs to tdxargs

MENDER_UBOOT_POST_SETUP_COMMANDS:append = " ; setenv tdxargs ${tdxargs} ${bootargs}; "

7b. FIT image carries the DTB internally — disable all separate DTB/overlay loading

MENDER_UBOOT_POST_SETUP_COMMANDS:append = " ; 
setenv skip_fdt_overlays 1 ; 
setenv fdtfile ; 
setenv bootcmd_dtb true ; 
setenv bootcmd_overlays true ; 
setenv bootcmd_kernel true ; 
setenv bootcmd_unzip true ; 
"

M4 Boot Configuration

MENDER_UBOOT_POST_SETUP_COMMANDS:append = " ; 
setenv m4_load_addr 0x88000000 ; 
setenv m4_0_image /home/pixii/Cortex_M4/pixii_lls.bin ; 
setenv m4boot ‘ext4load ${mender_uboot_root} ${m4_load_addr} ${m4_0_image} && dcache flush && bootaux ${m4_load_addr} 0’ ; 
"

Boot command configuration

#MENDER_UBOOT_POST_SETUP_COMMANDS:append = " ; \

setenv bootcmd_boot 'echo Bootargs: ${bootargs} \

&& bootm ${kernel_addr_load}#conf-freescale_imx8qm-apalis-v1.1-ixora-v1.2.dtb’ ; \

#"

MENDER_UBOOT_POST_SETUP_COMMANDS:append = " ; setenv bootcmd_boot ‘fatload mmc 0:1 ${kernel_addr_load} boot.fit && source ${kernel_addr_load}:script-part${mender_boot_part} && bootm ${kernel_addr_load}#conf-part${mender_boot_part}’ ; "

=========================================================================

Secure Boot Configurations

=========================================================================

INHERIT += “tdx-signed”
TDX_IMX_HAB_ENABLE = “1”
TDX_IMX_HAB_CST_DIR = “/home/rania/cst-4.0.1”
TDX_IMX_HAB_CST_BIN = “${TDX_IMX_HAB_CST_DIR}/linux64/bin/cst”
TDX_IMX_HAB_CST_CERTS_DIR = “/home/rania/cst-4.0.1/crts”
TDX_IMX_HAB_CST_SRK_CA = “0”
TDX_IMX_HAB_CST_CRYPTO = “ecdsa”
TDX_IMX_HAB_CST_KEY_SIZE = “secp384r1”
TDX_IMX_HAB_CST_DIG_ALGO = “sha384”
TDX_IMX_HAB_CST_SRK_INDEX = “1”
TDX_IMX_HAB_CST_SRK_REVOKE_MASK = “0x0”
TDX_IMX_HAB_CST_SRK_CERT = “/home/rania/cst-4.0.1/crts/SRK1_sha384_secp384r1_v3_usr_crt.pem”

UBOOT_SIGN_ENABLE = “1”
FIT_GENERATE_KEYS = “0”
UBOOT_SIGN_KEYNAME = “dev”
UBOOT_SIGN_KEYDIR = “/home/rania/fit-keys”
UBOOT_MKIMAGE_DTCOPTS = “-I dts -O dtb -p 2000”

DM-Verity Image Generation

IMAGE_CLASSES += “dm-verity-img boot-fit-verity”
DM_VERITY_IMAGE = “tdx-reference-multimedia-image”
DM_VERITY_IMAGE_TYPE = “ext4”
DM_VERITY_IMAGE_DATA_BLOCK_SIZE = “4096”
DM_VERITY_IMAGE_HASH_BLOCK_SIZE = “4096”
KERNEL_IMAGETYPES:append = " Image.gz"



i also added a custom u-boot-distro-boot

KERNEL_BOOTCMD:aarch64 = "bootm"

DTB_PREFIX = "${@d.getVar('KERNEL_DTB_PREFIX').replace('/', '_') if d.getVar('KERNEL_DTB_PREFIX') else ''}"




do_compile:prepend() {

cd ${WORKDIR}

if [ -f boot.cmd.in ]; then

sed -e "s/@@KERNEL_BOOTCMD@@/${KERNEL_BOOTCMD}/g" \

            -e "s/@@KERNEL_IMAGETYPE@@/${KERNEL_IMAGETYPE}/g" \

            -e "s/@@KERNEL_DTB_PREFIX@@/${DTB_PREFIX}/g" \

boot.cmd.in > boot.cmd




sed -i 's/env set rootfsargs root/env set rootfsargs "root/g' boot.cmd

sed -i 's/ro rootwait/ro rootwait"/g' boot.cmd




echo "meta-custom: boot.cmd pre-generated and formatted OK"

else

bbfatal "meta-custom: boot.cmd.in missing"

fi

}




do_deploy:prepend() {

cd ${WORKDIR}

if [ -f boot.cmd ]; then

cp boot.cmd boot.cmd.amended

echo "meta-custom: saved amended boot.cmd"

fi

}




do_deploy:append() {

cd ${WORKDIR}

if [ -f boot.cmd.amended ]; then

echo "meta-custom: restoring amended boot.cmd -> regenerating boot.scr"

cp boot.cmd.amended boot.cmd

mkimage -T script -C none -n "Distro boot script" \

            -d boot.cmd ${DEPLOYDIR}/boot.scr-${MACHINE}

echo "meta-custom: boot.scr regenerated from amended boot.cmd ✓"

fi

}

and a custom class boot-fit-verity.bbclass

DEPENDS += "u-boot-tools-native dtc-native"




BOOT_FIT_DTB ?= "${KERNEL_DEVICETREE}"

BOOT_FIT_KERNEL_LOAD ?= "0x95400000"

BOOT_FIT_FDT_LOAD    ?= "0x9d400000"




python __anonymous () {

verity_image = d.getVar('DM_VERITY_IMAGE') or ""

verity_type = d.getVar('DM_VERITY_IMAGE_TYPE') or ""

pn = d.getVar('PN') or ""




if not verity_image or verity_image != pn or not verity_type:

return

dep = ' %s:do_image_%s' % (pn, verity_type.replace('-', '_'))

d.appendVarFlag('do_generate_boot_fit', 'depends', dep)

}




do_generate_boot_fit() {

set -e

    [ "${DM_VERITY_IMAGE}" = "${PN}" ] || exit 0




VENV="${STAGING_VERITY_DIR}/${IMAGE_BASENAME}.${DM_VERITY_IMAGE_TYPE}.verity.env"

    [ -f "$VENV" ] || bbfatal "boot-fit-verity: $VENV not found."

. "$VENV"




NUM_SECTORS=$(expr $DATA_SIZE / 512)

HASH_START_BLOCK=$(expr $DATA_SIZE / $HASH_BLOCK_SIZE)




WORKFIT="${WORKDIR}/boot-fit"

mkdir -p "$WORKFIT"

KERNEL_RAW="${DEPLOY_DIR_IMAGE}/Image.gz"

DTB_RAW="${DEPLOY_DIR_IMAGE}/$(basename ${BOOT_FIT_DTB})"

cp "$KERNEL_RAW" "$WORKFIT/kernel.bin.gz"




VERITY_BASE="vroot,,,ro,0 ${NUM_SECTORS} verity 1"

ARGS_BASE="ro rootwait console=tty1 console=ttyLP1,115200 root=/dev/dm-0"




dtc -I dtb -O dts -o "$WORKFIT/base.dts" "$DTB_RAW"




# PARTITION 2 CONFIGURATION 

VBT_PART2="${ARGS_BASE} dm-mod.waitfor=/dev/mmcblk0p2 dm-mod.create=\\\"${VERITY_BASE} /dev/mmcblk0p2 /dev/mmcblk0p2 ${DATA_BLOCK_SIZE} ${HASH_BLOCK_SIZE} ${DATA_BLOCKS} ${HASH_START_BLOCK} ${HASH_ALGORITHM} ${ROOT_HASH} ${SALT} 1 ignore_zero_blocks\\\""

cp "$WORKFIT/base.dts" "$WORKFIT/part2.dts"

cat >> "$WORKFIT/part2.dts" <<EOF

/ { chosen { toradex,secure-boot { required-bootargs = "${VBT_PART2}"; }; }; };

EOF

dtc -I dts -O dtb -o "$WORKFIT/fdt-part2.dtb" "$WORKFIT/part2.dts"

cat > "$WORKFIT/script-part2.txt" <<EOF

setenv bootargs "${VBT_PART2} \${tdxargs}"

EOF




# PARTITION 3 CONFIGURATION 

VBT_PART3="${ARGS_BASE} dm-mod.waitfor=/dev/mmcblk0p3 dm-mod.create=\\\"${VERITY_BASE} /dev/mmcblk0p3 /dev/mmcblk0p3 ${DATA_BLOCK_SIZE} ${HASH_BLOCK_SIZE} ${DATA_BLOCKS} ${HASH_START_BLOCK} ${HASH_ALGORITHM} ${ROOT_HASH} ${SALT} 1 ignore_zero_blocks\\\""

cp "$WORKFIT/base.dts" "$WORKFIT/part3.dts"

cat >> "$WORKFIT/part3.dts" <<EOF

/ { chosen { toradex,secure-boot { required-bootargs = "${VBT_PART3}"; }; }; };

EOF

dtc -I dts -O dtb -o "$WORKFIT/fdt-part3.dtb" "$WORKFIT/part3.dts"

cat > "$WORKFIT/script-part3.txt" <<EOF

setenv bootargs "${VBT_PART3} \${tdxargs}"

EOF




cat > "$WORKFIT/boot.its" <<ITS_EOF

/dts-v1/;

/ {

description = "Dual-Slot Hardened Mender FIT";

#address-cells = <1>;

images {

kernel {

data = /incbin/("$WORKFIT/kernel.bin.gz");

type = "kernel"; arch = "arm64"; os = "linux"; compression = "gzip";

load = <${BOOT_FIT_KERNEL_LOAD}>; entry = <${BOOT_FIT_KERNEL_LOAD}>;

hash-1 { algo = "sha256"; };

        };

fdt-part2 {

data = /incbin/("$WORKFIT/fdt-part2.dtb");

type = "flat_dt"; arch = "arm64"; compression = "none";

load = <${BOOT_FIT_FDT_LOAD}>;

hash-1 { algo = "sha256"; };

        };

fdt-part3 {

data = /incbin/("$WORKFIT/fdt-part3.dtb");

type = "flat_dt"; arch = "arm64"; compression = "none";

load = <${BOOT_FIT_FDT_LOAD}>;

hash-1 { algo = "sha256"; };

        };

script-part2 {

data = /incbin/("$WORKFIT/script-part2.txt");

type = "script"; arch = "arm64"; compression = "none";

hash-1 { algo = "sha256"; };

        };

script-part3 {

data = /incbin/("$WORKFIT/script-part3.txt");

type = "script"; arch = "arm64"; compression = "none";

hash-1 { algo = "sha256"; };

        };

    };

configurations {

default = "conf-part2";

conf-part2 {

kernel = "kernel"; fdt = "fdt-part2"; script = "script-part2";

hash-1 { algo = "sha256"; };

signature-1 { algo = "sha256,rsa2048"; key-name-hint = "${UBOOT_SIGN_KEYNAME}"; sign-images = "kernel", "fdt", "script"; };

        };

conf-part3 {

kernel = "kernel"; fdt = "fdt-part3"; script = "script-part3";

hash-1 { algo = "sha256"; };

signature-1 { algo = "sha256,rsa2048"; key-name-hint = "${UBOOT_SIGN_KEYNAME}"; sign-images = "kernel", "fdt", "script"; };

        };

    };

};

ITS_EOF




mkimage -f "$WORKFIT/boot.its" -k "${UBOOT_SIGN_KEYDIR}" -r "$WORKFIT/boot.fit"

install -d "${DEPLOY_DIR_IMAGE}"

install -m 0644 "$WORKFIT/boot.fit" "${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.boot.fit"

ln -sf "${IMAGE_NAME}.boot.fit" "${DEPLOY_DIR_IMAGE}/${IMAGE_LINK_NAME}.boot.fit"

}




swap_ext4_for_verity() {

if [ -f "${IMGDEPLOYDIR}/${IMAGE_LINK_NAME}.ext4.verity" ]; then

cp -f "${IMGDEPLOYDIR}/${IMAGE_LINK_NAME}.ext4.verity" "${IMGDEPLOYDIR}/${IMAGE_LINK_NAME}.ext4"

fi

}




addtask do_generate_boot_fit after do_image_ext4 before do_image_bootimg do_image_mender_tezi do_image_teziimg do_image_wic

do_generate_boot_fit[dirs] = "${WORKDIR}"

do_generate_boot_fit[cleandirs] = "${WORKDIR}/boot-fit"

do_image_sdimg[prefuncs] += "swap_ext4_for_verity"

do_image_mender[prefuncs] += "swap_ext4_for_verity"

do_image_mender_tezi[prefuncs] += "swap_ext4_for_verity"

and a custom mender module which didn’t even get the chance to test yet

#!/bin/sh

# Mender Update Module: dm-verity-rootfs




STATE="$1"

FILES="$2"




case "$STATE" in

NeedsArtifactReboot)

echo "Yes"

        ;;

SupportsRollback)

echo "Yes"

        ;;

ArtifactInstall)

# Explicitly calculate the inactive slot to avoid missing variable errors

ACTIVE_NUM=$(fw_printenv mender_boot_part 2>/dev/null | cut -d= -f2)

if [ "$ACTIVE_NUM" = "2" ]; then

INACTIVE_DEV="/dev/mmcblk0p3"

TARGET_PART_NUM="3"

else

INACTIVE_DEV="/dev/mmcblk0p2"

TARGET_PART_NUM="2"

fi

# Flash the verity rootfs

dd if="$FILES/image.ext4.verity" of="$INACTIVE_DEV" bs=1M || exit 1

# Mount and update the active FIT in the boot partition

mkdir -p /tmp/boot_mnt

mount /dev/mmcblk0p1 /tmp/boot_mnt || exit 1

cp "$FILES/boot.fit" "/tmp/boot_mnt/boot.fit.${TARGET_PART_NUM}" || { umount /tmp/boot_mnt; exit 1; }

sync

umount /tmp/boot_mnt

        ;;

esac

exit 0

this last bbclass isn’t tested yet cause the secure boot is causing me serious problems once flashed with version the board no longer goes under recovery mode unless wiping its emmc
mmc dev 0 1
mmc erase 0 2000
mmc dev 0 2
mmc erase 0 2000
reset

till i ended up with a blank console and the module is no even loger flashable it’s completely ruined depite not efusing yet !!!

one last thing my configurations were inspired from here
https://hub.mender.io/t/mender-cm4-dm-verity/8260/7

Hi, I’m the Toradex AI Assistant.

I might make mistakes or occasionally get you wrong. Our support team will step in if needed.


I can see you’re working with a complex integration of Mender OTA, dm-verity, and Secure Boot on the Apalis iMX8QM. Your setup involves multiple advanced features, and the SError you’re encountering suggests a low-level hardware access issue during early boot.

Key Observations

1. The SError and Resource Ownership

The logs show several resources are “not owned” by the Linux partition:

Disable dma-controller@599F0000 rsrc 463 not owned
Disable crypto@31400000 rsrc 501 not owned
...

This is typical on iMX8QM when the System Controller Unit (SCU) hasn’t granted Linux access to certain hardware blocks(1). The SError at audio-pll1: failed to power up resource 492 ret -22 suggests the kernel is trying to access hardware it doesn’t have permission for(1).

2. The Required Bootargs Warning

## WARNING: Required node "/chosen/toradex,secure-boot" could not be found in device-tree.

This is critical. When Secure Boot is enabled on iMX8, U-Boot expects a /chosen/toradex,secure-boot node with required-bootargs in the device tree(2). Your FIT image must include this node with the correct dm-verity parameters.

3. Device Tree and FIT Configuration Issues

Looking at your boot-fit-verity.bbclass, you’re generating separate DTBs for partition 2 and 3 with dm-verity parameters. However, the warning suggests U-Boot isn’t finding the secure boot node properly.

In your boot-fit-verity.bbclass, you have:

cat >> "$WORKFIT/part2.dts" <<EOF
/ { chosen { toradex,secure-boot { required-bootargs = "${VBT_PART2}"; }; }; };
EOF

This should work, but ensure the node structure matches what U-Boot expects. According to the Toradex Secure Boot implementation for iMX8(2), the device tree must include this node at the /chosen level.

Recommendations

1. Verify Device Tree Structure

Check that your generated FIT image DTB actually contains the /chosen/toradex,secure-boot/required-bootargs node. You can extract and inspect it:

dumpimage -T flat_dt -p 0 -o extracted.dtb boot.fit
dtc -I dtb -O dts extracted.dtb

2. U-Boot Environment Variables

Your U-Boot configuration disables several boot commands:

setenv bootcmd_dtb true ; 
setenv bootcmd_overlays true ; 
setenv bootcmd_kernel true ; 
setenv bootcmd_unzip true ;

This might interfere with the Secure Boot flow. The Toradex U-Boot implementation expects certain environment variables to be set correctly(3). Consider reviewing whether these should remain as true (no-op) or if they need actual commands.

3. Resource Ownership and SCU Configuration

The “not owned” resources suggest the SCU partition assignment might need adjustment. On iMX8QM, resources must be explicitly assigned to the Linux partition. Check your SCFW (System Controller Firmware) configuration(1).

4. Recovery from Bricked State

You mentioned the module is “completely ruined” after erasing the eMMC boot partitions. To recover:

  1. Enter recovery mode by following the Toradex Easy Installer recovery procedure
  2. If the module won’t enter recovery, you may need to use the serial download protocol (SDP) via USB OTG
  3. Use NXP’s UUU (Universal Update Utility) tool to reflash the bootloader

For detailed recovery steps, refer to the Toradex Easy Installer documentation.

5. Simplify and Test Incrementally

Your configuration combines many features simultaneously. I recommend:

  • First, get Secure Boot working with a simple signed FIT image (no Mender, no dm-verity)
  • Then add dm-verity
  • Finally, integrate Mender OTA

This incremental approach will help isolate the issue.

Critical Configuration Check

Your local.conf has:

MENDER_UBOOT_POST_SETUP_COMMANDS:append = " ; setenv bootcmd_boot 'fatload mmc 0:1 ${kernel_addr_load} boot.fit && source ${kernel_addr_load}:script-part${mender_boot_part} && bootm ${kernel_addr_load}#conf-part${mender_boot_part}' ; "

This boot command loads the FIT image and sources a script from it, then boots a specific configuration. Ensure:

  • The FIT image is accessible at the specified location
  • The script parts (script-part2, script-part3) are correctly embedded
  • The configuration names match (conf-part2, conf-part3)

Additional Resources

For Secure Boot on iMX8 modules, the Chinese blog post on the Toradex website provides detailed steps for AHAB (Advanced High Assurance Boot) configuration(2). While it’s in Chinese, the code examples and configuration snippets are universal.

The community forum threads on Secure Boot(4)(5) also contain valuable troubleshooting steps from other users facing similar issues.

Next Steps

  1. Verify your FIT image contains the correct /chosen/toradex,secure-boot node
  2. Test with a minimal Secure Boot configuration first
  3. Review SCU resource assignments
  4. If the module is truly unrecoverable via standard methods, contact Toradex support for RMA options

Best regards,
Toradex AI Assistant


Did you like my answer? :+1: :-1:

If I answered your question, please tick the “Solution” checkbox.

For follow-up questions to me, please use @ToradexAI in your post.

the problem that am not able to flash a working image since the board refuses to enter recovery mode am literally stuck at this point and the uart console still blank

I understand this is a critical situation. If the module won’t enter recovery mode and the UART console is completely blank, this suggests the bootloader may be corrupted or the module is in a locked state.

Recovery Mode Entry for Apalis iMX8QM

Based on the Apalis iMX8X documentation (which shares similar recovery procedures with iMX8QM), here’s what you need to do(1):

Hardware Recovery Method

  1. Locate the recovery mode pads on the bottom of the Apalis iMX8QM module(1)
  2. Power off the module completely
  3. Short the recovery mode pads using tweezers, scissors, or a jumper wire(1)
  4. While keeping the pads shorted, power on the module(1)
  5. Hold the short for 1-2 seconds after power-on, then release(1)

Important: The recovery mode pads must be shorted during the initial power-on (cold boot) of the module(1). Using reset won’t work.

Alternative Recovery Method (If Supported)

On some Apalis modules, you can also enter recovery mode by pulling up pin 63 (type-specific area) with a 1kΩ resistor while booting(1). However, this is not guaranteed to work on all modules.

USB Connection

Ensure you have the USBO1 interface (USB OTG) connected to your PC(1)(2). This is the interface used for recovery mode flashing.

Troubleshooting Your Specific Issue

Based on your screenshot showing the module is detected but not entering recovery properly, and the community experience with similar issues(3):

1. Verify Hardware Version

Check your Apalis iMX8QM hardware revision. According to a community report, hardware version 1.0B is not officially supported(3). You mentioned you have V1.1, which should be fine, but verify this on the module label.

2. Try Linux Host Instead of Windows

Multiple users have reported that Windows 10 does not work reliably with recovery mode on iMX8 modules(3). Try using a Linux machine instead:

./recovery-linux.sh

3. Check for SD Card

Ensure there is no SD card inserted in the carrier board(1). The presence of an SD card can prevent proper recovery mode entry.

4. Verify USB Connection

  • Use the correct USB port (USBO1/OTG on Ixora carrier board)
  • Try a different USB cable
  • Try a different USB port on your PC
  • Ensure the USB connection is USB 2.0 High-Speed compatible

5. Power Cycle Completely

Since you erased the eMMC boot partitions, the module may be in an undefined state. Try:

  1. Disconnect all power (including USB)
  2. Wait 30 seconds
  3. Short the recovery pads
  4. Connect power via the main power supply (not just USB)
  5. Then connect USB
  6. Release the recovery pads after 2 seconds

If Recovery Mode Still Fails

If the module absolutely won’t enter recovery mode and the UART is blank, this suggests:

  1. The SCFW (System Controller Firmware) may be corrupted - This is the lowest-level firmware and if damaged, the module won’t boot at all
  2. The module may be in a locked state - Though you mentioned you haven’t fused yet, some secure boot operations can lock the module

Last Resort Options

  1. Contact Toradex Support directly - They may have specialized recovery tools for completely bricked modules
  2. Check if RMA (Return Merchandise Authorization) is necessary - If the module is truly unrecoverable, Toradex support can evaluate replacement options

Critical Reminder

For future development with Secure Boot and dm-verity, always test on a separate development module first before deploying to production hardware. Keep at least one module in a known-good state for recovery purposes.

Could you confirm:

  • Which exact hardware revision is printed on your Apalis iMX8QM module?
  • Are you using a Linux or Windows host for recovery?
  • Do you see any LED activity on the module when you attempt recovery mode?
  • Is the UART console completely silent, or do you see any output at all during power-on?

Best regards,
Toradex AI Assistant


Did you like my answer? :+1: :-1:

If I answered your question, please tick the “Solution” checkbox.

For follow-up questions to me, please use @ToradexAI in your post.

Hello Rania,

To get the module working again, let’s load the Toradex Easy Installer through U-Boot from a USB stick, bypassing eMMC entirely:

  1. Format a USB stick as FAT32.

  2. Download the Toradex Easy Installer package for your module and extract it to the root of the stick.

  3. With the stick inserted and the serial console connected, power on the board.

  4. Interrupt the boot countdown to reach the U-Boot prompt.

  5. Run:

run bootcmd_usb0

This loads Tezi directly from the USB stick into RAM, independent of what is currently on the eMMC. Once Tezi comes up, you can flash a plain reference image to get a known-good baseline.

Please confirm once this works, or send the console output if it does not.

I’m investigating the SError in parallel, particularly whether it relates to the SCU resource ownership messages or the U-Boot bootcmd overrides in your configuration. I’ll follow up once I have concrete findings.

Best Regards,

Thank you for the suggestion. Unfortunately, I cannot interrupt the U-Boot countdown because the serial console is completely blank upon powering on the board.

The eMMC boot partitions were accidentally erased earlier. The board currently falls back directly to Serial Downloader (USB Recovery) Mode.

I have tried pushing Toradex Easy Installer (both 6.8.1 and 5.7.6) via uuu to recover it. In both cases, uuu reaches 100% on the SDPS: boot -f stage, but the board instantly halts in RAM and the serial console remains completely dead.

Interestingly, if I push my custom Yocto imx-boot via uuu, I get SDPS: done (meaning it executes), but since it is a production bootloader, it still leaves the console blank as it fails to find the eMMC.

Hello Rania,

The eMMC erase explains the automatic drop into SDP, that part is expected fallback behavior, not damage.

The SDP handoff is the actual blocker. Your custom imx-boot reaches SDPS: done, so ROM/SECO accepted it. The reference Tezi install stalls at step 1 of 3 and never re-enumerates. That difference points to an SRK mismatch on the reference image, not confirmed yet.

Can you send uuu -v from both attempts, and if you still have the CST/SRK files used for the custom build, try signing a Tezi SPL/U-Boot with them and pushing it through the installer script.

If that clears step 1, the module just needs a signed image, a normal install will rewrite boot0 and boot1 on its own.

Best Regards,

Hello Diego,

Thank you for the detailed analysis. I appreciate the help, but I can confidently say that I have never run the fuse prog command or blown any fuses on this board. The module should still be in the factory “Open” state.

Despite this, the board is now completely unresponsive to USB recovery. I am using a native Linux host with no USB hubs. Even when performing a strict cold-boot hardware sequence (disconnecting all power, shorting JP4, applying power, and releasing JP4), the board fails to enumerate on the USB bus. lsusb shows nothing, and running sudo ./recovery/uuu -v with my custom bootloader (or the TEZI bootloader) just hangs endlessly here:

Plaintext

uuu (Universal Update Utility) for nxp imx chips -- libuuu_1.5.165-0-g7347a80
Build in config:
    Pctl     Chip         Vid     Pid     BcdVersion
    ==================================================
    ...[snip]...
Wait for Known USB Device Appear...

I also want to highlight a critical symptom I experienced before the board died: Even when I tested the very basic Secure Boot configuration by itself (without dm-verity ), the board booted Linux perfectly to the end, but it completely refused to enter USB recovery mode. The only way I could flash a new image was by dropping into the U-Boot console, manually erasing the eMMC, and rebooting to physically force the ROM to fall back to Serial Download Mode. Why would merely enabling basic Secure Boot on an “Open” board break the TEZI USB handoff?

Since it seems this specific module has now suffered a hard hardware lockup, I am ready to move to a brand new Apalis iMX8QM board. However, I am terrified of bricking a second module.

My final project requires combining four things:

  1. Secure Boot (HAB) using meta-toradex-security

  2. dm-verity for rootfs verification

  3. Mender OTA (using an A/B fitImage architecture)

  4. Cortex-M4 Firmware (loaded into RAM at 0x88000000)

On the previous board, booting this full combination resulted in an immediate Asynchronous SError Kernel Panic and a black screen, which ultimately trapped the board.

Before I flash the new board, could you review this combination?

  • Is dm-verity causing a memory footprint collision with the M4 at 0x88000000?

  • Is the CAAM crypto engine initialization for dm-verity/Secure Boot fighting the M4 power domains?

  • What is the officially recommended Yocto architecture to make Secure Boot, dm-verity, and the M4 coexist without triggering the RDC/SCU hardware firewall or breaking USB recovery?

I want to make sure my configuration is safe before I apply power to the new silicon. Thank you!