NanoPi Neo2 Porting Mender to Openwrt

Thinking that P1 starting at 1MB (2048 sectors) is OK if I alter CONFIG_ENV_OFFSET’s :

u-boot bin size: 0x91F2C
flash layout (bytes):
0x0 partition table
0x200 u-boot binary (last address: 0x9212C)
0xFC000-$MENDER_BOOTENV_SIZE(0x4000)=0xF8000 = MENDER_UBOOT_ENV_STORAGE_DEVICE_OFFSET_1
0x100000-$MENDER_BOOTENV_SIZE(0x4000)=0xFC000 = MENDER_UBOOT_ENV_STORAGE_DEVICE_OFFSET_2

before P1, summarized:
0x0 partition table
0x200 u-boot binary (last address: 0x9212C - room to grow)
0xF8000 ENV_STORAGE_DEVICE_OFFSET_1
0xFC000 ENV_STORAGE_DEVICE_OFFSET_2

less wasteful of flash, looks OK?

Regards;
Bill

Looks good, what was the ENV_SIZE?

MENDER_BOOTENV_SIZE=0x4000

  • Can now survive saveenv (u-boot) and re-boot by taking above approach.
  • Also note that the openwrt version of fw_printenv / fw_setenv appears to work OK, so long as fw_env.config is valid. To be safe, I replace fw_*env with the (mender config’d) u-boot version during mender package installation.

Questions:

  • If I do not do saveenv (using u-boot) and have a valid fw_env.config,
fw_printenv
Warning: Bad CRC, using default environment
bootcmd=bootp; setenv bootargs root=/dev/nfs nfsroot=${serverip}:${rootpath} ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}::off; bootm
bootdelay=5
baudrate=115200

…which is not the complete default environment. This appears to require a manual u-boot step to save the environment to raw flash, which I would like to avoid. It seems like the best solution is for u-boot to do a saveenv when a bad CRC is detected @ boot. Is there a “bad CRC” variable? Another approach is to (dd) write the default environment to flash during build. Do you think this is a good idea for mender (in general) default behavior?

  • mount points?:
    /boot contains boot.scr, dtb, uImage for booting selected partition
    /uboot has boot partition (/dev/mmcblk0p1) mounted for mender purposes
    /data is mender (and general) persistent storage, survives updates. /dev/mmcblk0p4 mount point.
  • I note (kernel command line) that root=/dev/nfs, which does not exist. What should root= for /dev/mmcblk0pX and, do I need to (somehow) specify /boot?

Regards;
Bill

To be safe, I replace fw_*env with the (mender config’d) u-boot version during mender package installation.

It is a bit odd that if you do this, that you do not get a matching default environment when you run fw_printenv.

Is there a “bad CRC” variable?

Not that I am aware of. Note that “bad CRC” is also equal to “empty” environment.

This is why I suggested to create a such a variable that is not part of the default environment, and is only available when the environment has been saved.

Another approach is to (dd) write the default environment to flash during build. Do you think this is a good idea for mender (in general) default behavior?

This has always been a pain point, the need to synchronize U-boot and the tools. But for now anything goes, we make sure that U-boot and fw_setenv/fw_getenv environment have the same default built-in in Yocto and then it is not a problem and there is no need to “pre flash” it.

There are some solutions that are in the works that should remedy this, e.g this one (still early stage but the idea is to solve this problem)

https://groups.google.com/forum/#!searchin/swupdate/libubootenv|sort:date/swupdate/2wcIyfexOro/iADiuQRtBQAJ

/boot contains boot.scr, dtb, uImage for booting selected partition

You normally put boot.scr on the boot partition (if it required by your board), that is /uboot or /dev/mmcblk0p1

/uboot has boot partition (/dev/mmcblk0p1) mounted for mender purposes

Mender has no purposes with above and this is only needed if your board requires this.

/data is mender (and general) persistent storage, survives updates. /dev/mmcblk0p4 mount point.

Yes

  • I note (kernel command line) that root=/dev/nfs, which does not exist. What should root= for /dev/mmcblk0pX

You want the root= argument to be,

  root=${mender_kernel_root}

This way mender_setup makes sure that the correct partition is booted.

and, do I need to (somehow) specify /boot?

Unclear what you mean with this.

specify /boot? answered it myself, from env: boot_prefixes=/ /boot/, which I assume are subdirs of $root that u-boot looks

I also noticed (u-boot prompt) that:
=> run mender_setup
Saving Environment to MMC… Writing to redundant MMC(0)… OK

and…
mender_saveenv_canary undefined until mender_setup run

mender_setup=if test "${mender_saveenv_canary}" != "1"; then setenv mender_savee
nv_canary 1; saveenv; fi; if test "${mender_pre_setup_commands}" != ""; then run
 mender_pre_setup_commands; fi; setenv mender_kernel_root /dev/mmcblk0${mender_b
oot_part}; if test ${mender_boot_part} = 2; then setenv mender_boot_part_name /d
ev/mmcblk0p2; else setenv mender_boot_part_name /dev/mmcblk0p3; fi; setenv mende
r_kernel_root_name ${mender_boot_part_name}; setenv mender_uboot_root mmc 0:${me
nder_boot_part_hex}; setenv mender_uboot_root_name ${mender_boot_part_name}; set
env expand_bootargs "setenv bootargs \\"${bootargs}\\""; run expand_bootargs; se
tenv expand_bootargs; if test "${mender_post_setup_commands}" != ""; then run me
nder_post_setup_commands; fi

So, if I alter the u-boot script to “run mender_setup” at boot, saveenv is run.

Is this a viable solution to initial saveenv?

Is this a viable solution to initial saveenv?

I thought that it would not do that because of this line,

Do you have that in your patch as well?

Also you will need to add mender_setup to your bootcmd to get a full integration, see

https://docs.mender.io/1.7/devices/yocto-project/bootloader-support/u-boot/manual-u-boot-integration#integration-points

Aah now I see it.

Yes, then mender_setup will take care of initializing the environment with a saveenv on first boot once you have integrated mender_setup in your bootcmd

Not clear to me what I should be doing to dtb to patch the integration points, here’s the dtb source:

setenv loaddtb fatload mmc 0 \$fdt_addr_r dtb
setenv bootargs console=ttyS0,115200 earlyprintk root=/dev/mmcblk0p2 rootwait earlycon=uart,mmio32,0x01c28000
setenv uenvcmd run loadkernel \&\& run loaddtb \&\& booti \$kernel_addr_r - \$fdt_addr_r
run uenvcmd

I can find no reference to bootcmd, apart from: the output of fw_printenv, above.

Do you have the NEO2, dtb source (uEnv-a64.txt?) from yocto build?

here’s what’s available:

=> printenv distro_bootcmd
distro_bootcmd=for target in ${boot_targets}; do run bootcmd_${target}; done
=> printenv boot_targets
boot_targets=fel mmc0 usb0 pxe dhcp
=> printenv bootcmd_mmc0
bootcmd_mmc0=setenv devnum 0; run mmc_boot
=> printenv mmc_boot
mmc_boot=if mmc dev ${devnum}; then setenv devtype mmc; run scan_dev_for_boot_part; fi

Think it needs a total re-write…

I case of distro_bootcmd is used you simply create a boot.scr with something like this,

setenv bootargs 'root=${mender_kernel_root} rw rootwait'
run mender_setup;

# Boot the board
load ${mender_uboot_root} ${kernel_addr_r} /boot/zImage
load ${mender_uboot_root} ${fdt_addr_r} /boot/<name of dtb>.dtb

bootz ${kernel_addr_r} - ${fdt_addr_r}

going to try this (merge yours, nanopi)

setenv bootargs 'console=ttyS0,115200 earlyprintk root=${mender_kernel_root} rootwait earlycon=uart,mmio32,0x01c28000'
run mender_setup;
# Boot the board
load ${mender_uboot_root} ${kernel_addr_r} /boot/uImage
load ${mender_uboot_root} ${fdt_addr_r} /boot/dtb
bootz ${kernel_addr_r} - ${fdt_addr_r}

is bootz correct for uImage format?

If it is an uImage then you have to use bootm.

sunxi must be different, suggestion didn’t work, had to alter the sunxi dtb.

original:

setenv loadkernel fatload mmc 0 \$kernel_addr_r uImage
setenv loaddtb fatload mmc 0 \$fdt_addr_r dtb
setenv bootargs console=ttyS0,115200 earlyprintk root=/dev/mmcblk0p2 rootwait earlycon=uart,mmio32,0x01c28000
setenv uenvcmd run loadkernel \&\& run loaddtb \&\& booti \$kernel_addr_r - \$fdt_addr_r
run uenvcmd

new (works):

run mender_setup
setenv loadkernel load  \${mender_uboot_root}  \${kernel_addr_r} /boot/uImage
setenv loaddtb  load \${mender_uboot_root}  \${fdt_addr_r} /boot/dtb
setenv bootargs console=ttyS0,115200 earlyprintk root=${mender_kernel_root_name} rootwait earlycon=uart,mmio32,0x01c28000
setenv uenvcmd run loadkernel \&\& run loaddtb \&\& booti \${kernel_addr_r} - \${fdt_addr_r}
run uenvcmd

howzit look?

Regards;
Bill

Looks good, as long as it works :slight_smile:

Will find out if mender boot partition select works at integration test. Right now, boots from mender default - P2

Yeah, you are aware of this one right?

https://docs.mender.io/1.7/devices/yocto-project/bootloader-support/u-boot/integration-checklist

DeviceType: non zero value required

root@phero-neo2-openwrt_mender:~# ERRO[0000] Error receiving scheduled update data: (request_id: ): Invalid response received from server server error message: DeviceType: non zero value required; module=mender

Server:
image

root@phero-neo2-openwrt_mender:~# cat /data/mender/device_type
phero-neo2-openwrt_mender

why is Mender server not collecting device_type? Is it not from above file?

Also, would like to run client mender non-daemon (foreground) under procd (no systemd). Is there a way? Should I submit feature request?

Regards;
Bill

Well actually mender reads that information from /var/lib/mender/device_type, and we normally link /var/lib/mender -> /data/mender. So might not have that link.

Also, would like to run client mender non-daemon (foreground) under procd (no systemd). Is there a way? Should I submit feature request?

Even if the flag mender -daemon would hint that it runs in background but it does not. It always runs in foreground so should work with procd.

I actually have a procd service laying around (see below), no idea if it is any good :slight_smile:

#!/bin/sh /etc/rc.common


START=99
USE_PROCD=1

boot()
{
    # Need to re-create this as /var is tmpfs on OpenWRT
    /bin/mkdir -p /var/lib
    /bin/ln -sf /data/mender /var/lib/mender

    mender_boot=1
    rc_procd start_service
}

start_service() {
    if [ -n "${mender_boot}" ]; then
            return 0
    fi

    procd_open_instance

    procd_set_param command /usr/bin/mender -daemon

    procd_set_param respawn

    # forward stdout of the command to logd
    procd_set_param stdout 1

    # forward stderr of the command to logd
    procd_set_param stderr 1

    # write a pid file on instance start and remote it on stop
    procd_set_param pidfile /var/run/mender.pid

    procd_close_instance
}

root@phero-neo2-openwrt_mender:~# ls -la /var/lib/mender/device_type
-rw-r–r-- 1 root root 26 Mar 26 12:18 /var/lib/mender/device_type
root@phero-neo2-openwrt_mender:~# cat /var/lib/mender/device_type
phero-neo2-openwrt_mender

for procd, tried something similar to above. Problem is -daemon forks & returns, telling procd to try to restart, until it gives up. Without daemon, error message stating -daemon required. So, procd requires foreground run mode.

Hmmm, missed your runs in foreground comment, so, will retry procd and give more resolution on error