Issue integrating Mender on Verdin iMX8MP (Scarthgap branch)

Hello Mender team,

I’m encountering an issue while integrating Mender on a Toradex Verdin iMX8MP board using a Yocto build based on the Scarthgap branch.


Problem description

When attempting an OTA update, Mender returns the following error:

2025-11-08 14:41:13.639 +0000 UTC info: Running Mender client 5.0.2
2025-11-08 14:41:13.64 +0000 UTC info: Deployment with ID 2d57a34a-568c-4337-9f62-b4d775b6e2e5 started.
2025-11-08 14:41:13.85 +0000 UTC info: Installing artifact...
2025-11-08 14:41:14.026 +0000 UTC info: Update Module output (stderr): Cannot read environment, using default
2025-11-08 14:41:14.026 +0000 UTC info: Update Module output (stderr): Cannot read default environment from file
2025-11-08 14:41:14.027 +0000 UTC error: Process returned non-zero exit status: Download: Update Module returned non-zero status: Process exited with status 243
2025-11-08 14:41:14.028 +0000 UTC error: Operation canceled: GET https://s3.docker.mender.io/mender/... HTTP request cancelled

U-Boot configuration

By configuring the /etc/fw_env.config file as follows:

/dev/mmcblk2boot0 -0x2200 0x2000

I can correctly read U-Boot environment variables:

rroot@verdin-imx8mp-08626446:/# fw_printenv
arch=arm
baudrate=115200
board=verdin-imx8mp
board_name=verdin-imx8mp
boot_a_script=load ${devtype} ${devnum}:${distro_bootpart} ${scriptaddr} ${prefix}${script}; source ${scriptaddr}
boot_efi_binary=load ${devtype} ${devnum}:${distro_bootpart} ${kernel_addr_r} efi/boot/bootaa64.efi; if fdt addr -q ${fdt_addr_r}; then bootefi ${kernel_addr_r} ${fdt_addr_r};else bootefi ${kernel_addr_r} ${fdtcontroladdr};fi
boot_efi_bootmgr=if fdt addr -q ${fdt_addr_r}; then bootefi bootmgr ${fdt_addr_r};else bootefi bootmgr;fi
boot_extlinux=sysboot ${devtype} ${devnum}:${distro_bootpart} any ${scriptaddr} ${prefix}${boot_syslinux_conf}
boot_net_usb_start=usb start
boot_pci_enum=pci enum
boot_prefixes=/ /boot/
boot_script_dhcp=boot.scr
boot_scripts=boot.scr.uimg boot.scr
boot_syslinux_conf=extlinux/extlinux.conf
boot_targets=mmc1 mmc2 dhcp 
bootcmd=run distro_bootcmd
bootcmd_dhcp=devtype=dhcp; run boot_net_usb_start; run boot_pci_enum; if dhcp ${scriptaddr} ${boot_script_dhcp}; then source ${scriptaddr}; fi;setenv efi_fdtfile ${fdtfile}; setenv efi_old_vci ${bootp_vci};setenv efi_old_arch ${bootp_arch};setenv bootp_vci PXEClient:Arch:00011:UNDI:003000;setenv bootp_arch 0xb;if dhcp ${kernel_addr_r}; then tftpboot ${fdt_addr_r} dtb/${efi_fdtfile};if fdt addr -q ${fdt_addr_r}; then bootefi ${kernel_addr_r} ${fdt_addr_r}; else bootefi ${kernel_addr_r} ${fdtcontroladdr};fi;fi;setenv bootp_vci ${efi_old_vci};setenv bootp_arch ${efi_old_arch};setenv efi_fdtfile;setenv efi_old_arch;setenv efi_old_vci;
bootcmd_mmc1=devnum=1; run mmc_boot
bootcmd_mmc2=devnum=2; run mmc_boot
bootcount=1
bootdelay=1
carrier_serial#=11490742
console=ttymxc2
cpu=armv8
distro_bootcmd=setenv nvme_need_init; for target in ${boot_targets}; do run bootcmd_${target}; done
efi_dtb_prefixes=/ /dtb/ /dtb/current/
eth1addr=00:14:2d:93:a1:0e
ethact=ethernet@30bf0000
ethaddr=00:14:2d:83:a1:0e
ethprime=eth0
fdt_addr_r=0x50200000
fdt_board=dev
fdtcontroladdr=ffacf940
fdtfile=imx8mp-verdin-wifi-dev.dtb
foo=bar
initrd_addr=0x43800000
initrd_high=0xffffffffffffffff
kernel_addr_r=0x48200000
kernel_comp_addr_r=0x40200000
kernel_comp_size=0x08000000
load_efi_dtb=load ${devtype} ${devnum}:${distro_bootpart} ${fdt_addr_r} ${prefix}${efi_fdtfile}
loadaddr=0x48200000
mmc_boot=if mmc dev ${devnum}; then devtype=mmc; run scan_dev_for_boot_part; fi
nvme_boot=run boot_pci_enum; run nvme_init; if nvme dev ${devnum}; then devtype=nvme; run scan_dev_for_boot_part; fi
nvme_init=if ${nvme_need_init}; then setenv nvme_need_init false; nvme scan; fi
preboot=test -n ${fdtfile} || setenv fdtfile imx8mp-verdin-${variant}-${fdt_board}.dtb
ramdisk_addr_r=0x50300000
scan_dev_for_boot=echo Scanning ${devtype} ${devnum}:${distro_bootpart}...; for prefix in ${boot_prefixes}; do run scan_dev_for_extlinux; run scan_dev_for_scripts; done;run scan_dev_for_efi;
scan_dev_for_boot_part=part list ${devtype} ${devnum} -bootable devplist; env exists devplist || setenv devplist 1; for distro_bootpart in ${devplist}; do if fstype ${devtype} ${devnum}:${distro_bootpart} bootfstype; then part uuid ${devtype} ${devnum}:${distro_bootpart} distro_bootpart_uuid ; run scan_dev_for_boot; fi; done; setenv devplist
scan_dev_for_efi=setenv efi_fdtfile ${fdtfile}; for prefix in ${efi_dtb_prefixes}; do if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${efi_fdtfile}; then run load_efi_dtb; fi;done;run boot_efi_bootmgr;if test -e ${devtype} ${devnum}:${distro_bootpart} efi/boot/bootaa64.efi; then echo Found EFI removable media binary efi/boot/bootaa64.efi; run boot_efi_binary; echo EFI LOAD FAILED: continuing...; fi; setenv efi_fdtfile
scan_dev_for_extlinux=if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${boot_syslinux_conf}; then echo Found ${prefix}${boot_syslinux_conf}; run boot_extlinux; echo EXTLINUX FAILED: continuing...; fi
scan_dev_for_scripts=for script in ${boot_scripts}; do if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${script}; then echo Found U-Boot script ${prefix}${script}; run boot_a_script; echo SCRIPT FAILED: continuing...; fi; done
scriptaddr=0x50280000
serial#=08626446
soc=imx8m
stderr=serial@30880000
stdin=serial@30880000
stdout=serial@30880000
test_var=123
update_uboot=askenv confirm Did you load flash.bin (y/N)?; if test "$confirm" = "y"; then setexpr blkcnt ${filesize} + 0x1ff && setexpr blkcnt ${blkcnt} / 0x200; mmc dev 2 1; mmc write ${loadaddr} 0x0 ${blkcnt}; fi
usb_boot=usb start; if usb dev ${devnum}; then devtype=usb; run scan_dev_for_boot_part; fi
usb_ignorelist=0x1050:*,
variant=wifi
vendor=toradex
ver=U-Boot 2024.07-7.5.0-devel+git.3f772959501c (Jul 01 2024 - 18:07:18 +0000)

However, no Mender-related environment variables (such as mender_boot_part, mender_boot_part_hex, etc.) are present.


New OTA error

After fixing the environment reading issue, the following error occurs during an OTA update:

2025-11-10 09:08:48.493 +0000 UTC info: Running Mender client 5.0.2
2025-11-10 09:08:49.318 +0000 UTC info: Update Module output (stderr): sh: bad number
2025-11-10 09:08:49.318 +0000 UTC info: Update Module output (stderr): sh: invalid number ''
2025-11-10 09:08:49.319 +0000 UTC error: Process returned non-zero exit status: Download: Update Module returned non-zero status: Process exited with status 1
2025-11-10 09:08:49.32 +0000 UTC error: Operation canceled: HTTP request cancelled

I suspect this error is due to the absence of Mender-specific environment variables required for the OTA installation and rollback process.


Main question

It seems that these environment variables should be provided by the meta-mender-toradex-nxp layer, but this layer is only available on the Kirkstone branch.

How can I properly integrate Mender on the Scarthgap branch for the Verdin iMX8MP so that the required U-Boot environment variables are implemented?
Is it possible to backport or adapt the Toradex/NXP integration layer, and if so, what would be the correct approach?


Context

  • Board: Toradex Verdin iMX8MP (NXP i.MX8M Plus)
  • Yocto branch: Scarthgap
  • Mender client: 5.0.2
  • Goal: Integrate and test OTA updates with Mender (A/B rootfs setup)
  • Issue: OTA updates fail due to missing or unreadable Mender environment variables in U-Boot

Thank you in advance for your help and advice.
I can provide more details (U-Boot logs, build configuration, etc.) if needed.


Hi @Stan,

There is in-flight support for a number of Toradex boards on scarthgap at [Toradex] Verdin IMX8MM, IMX8MP & Colibri IMX8X by MuchoLucho · Pull Request #466 · mendersoftware/meta-mender-community · GitHub.

It will definitely still need a bit of polishing, but I can’t test it as I do not have such hardware available. Maybe you can use it as a starting point and once you confirm it’s working, it can be merged.

Greetz,
Josef

Great, I’ll take a look at it!

Just for clarification — does this patch apply to the U-Boot built through Yocto, or would it also work if I use the preinstalled U-Boot that comes with the Toradex board?
And if it doesn’t apply to the preinstalled U-Boot, is there a way to perform some initial tests while still using the existing Toradex U-Boot?

Thanks again for your help!

Hi Josef,

I’m currently trying to integrate the meta-mender-toradex-nxp layer (from this branch) into my Yocto build for a Verdin iMX8MP using Toradex BSP 7.5.0.
However, I’m encountering the following error during the build:

ERROR: u-boot-distro-boot-1.0-r0 do_patch: Applying patch '0001-Adapt-boot.cmd.in-to-Mender.patch' on target directory '/workdir/build-imx8mp/tmp/work/verdin_imx8mp-tdx-linux/u-boot-distro-boot/1.0'
CmdError('quilt --quiltrc /workdir/build-imx8mp/tmp/work/verdin_imx8mp-tdx-linux/u-boot-distro-boot/1.0/recipe-sysroot-native/etc/quiltrc push', 0, 'stdout: Applying patch 0001-Adapt-boot.cmd.in-to-Mender.patch
patching file boot.cmd.in
Hunk #1 FAILED at 3.
Hunk #2 FAILED at 38.
Hunk #3 FAILED at 89.
Hunk #4 succeeded at 105 (offset -16 lines).
3 out of 4 hunks FAILED -- rejects in file boot.cmd.in
Patch 0001-Adapt-boot.cmd.in-to-Mender.patch does not apply (enforce with -f)
stderr: ')
ERROR: Logfile of failure stored in: /workdir/build-imx8mp/tmp/work/verdin_imx8mp-tdx-linux/u-boot-distro-boot/1.0/temp/log.do_patch.4872

After checking, it looks like the patch 0001-Adapt-boot.cmd.in-to-Mender.patch (found in
meta-mender-toradex-nxp/recipes-bsp/u-boot-distro-boot/files/toradex-bsp-7.1.0/) no longer matches the current boot.cmd.in file from the BSP:

meta-toradex-bsp-common/recipes-bsp/u-boot/u-boot-distro-boot/boot.cmd.in

There are indeed several differences between the Toradex version and the one expected by the patch.


Environment details:

  • Machine: verdin-imx8mp
  • BSP: toradex-bsp-7.5.0
  • Branch: scarthgap
  • Using Toradex-provided U-Boot (preloaded on the board)

Would it be better to adapt the patch manually to the current boot.cmd.in, or is there an updated branch of the Mender Toradex integration compatible with this BSP version?

Thanks a lot in advance for any guidance!
Stanley

Hi @Stan,

Right, the integration in u-boot is mandatory. You can’t test the A/B updates without the required logic AND features in u-boot.

So you definitely have to build a patched version of u-boot, which has:

  • the Mender logic in the environment, specifically the mender_setup command, and passing the resulting root filesystems to the kernel
  • has the environment in flash
  • has the boot count logic enabled.

boot.cmd.in is usually the stage before all of this gets executed, as in many cases it selects the storage device to boot from. If that applies, it needs to be adjusted too.

The process is described in more depth at Manual U-Boot integration | Mender documentation.

Greetz,
Josef

Hi @TheYoctoJester,

Thank you for your reply. In the meantime, I tried to implement a boot chain where the preinstalled Toradex U-Boot loads my custom boot.scr:

# SPDX-License-Identifier: GPL-2.0+ OR MIT
#
# Copyright 2020 Toradex
#
# Toradex boot script.
#
echo "Running custom boot script..."

# Path to the custom U-Boot binary
setenv custom_uboot "/flash.bin-verdin-imx8mp-sd"

# Load the custom U-Boot from SD card into RAM
fatload mmc 1:1 ${loadaddr} ${custom_uboot}

echo "Jumping to custom U-Boot at ${loadaddr}"

# Execute the custom U-Boot
go ${loadaddr}

The script successfully loads my custom U-Boot, but I get the following error:

Jumping to custom U-Boot at 0x48200000
## Starting application at 0x48200000 ...
"Synchronous Abort" handler, esr 0x02000000
elr: ffffffff8851c000 lr : 000000004020b6fc (reloc)
...
Code: 00000000 00000000 00000000 00000000 (412000d1) 
Resetting CPU ...
resetting ...

Do you know if this kind of U-Boot chain is even possible on the Verdin iMX8MP?
If not, could you advise the best way to properly flash my custom U-Boot to the board and how to know the correct location to flash it?

Sorry, I’m quite new to this area, so any guidance would be greatly appreciated.

Thanks in advance!

Hi @Stan,

Chaining u-boot is maybe possibly, but certainly a very advanced topic as you need to be very careful about which hardware gets initialized, what gets loaded where, and so on. Definitely not a viable route for this situation.

What is keeping you from creating a patched u-boot and flashing it? The recovery options of the Toradex boards, in case something goes wrong, are very good.

Greetz,
Josfe