Raspberry Pi 5 QNX 8 QSTI preview

The official Mender documentation explains how Mender works. This is a board-specific complement to the official documentation.

Device description

Raspberry Pi 5 running the QNX Quick Start Target Image (tested on the 2GB variant).

Support level

Only basic functionality of the Mender Client was tested, in particular generation of an authentication key, connection and authentication to a Mender Server (hosted.mender.io), inventory reporting, and deployment of single-file and directory Mender Artifacts.

Getting started

Here is an APK for aarch64le (ARM8) QNX shipping the Mender Client and pulling in all the required dependencies. It’s enough to run sudo apk add --allow-untrusted ./mender-5.1.0-r0.apk and then follow setup instructions from the /usr/share/doc/mender/README_setup.md file.

Note: --allow-untrusted is required because there is no stable and published signing key for (QNX) APKs from Northern.tech (yet).

References

The QNX QSTI for Raspberry Pi 5 can be downloaded using a QNX Everywhere license.

Known issues

The build only ships one binary – mender-update, with the authentication functionality built-in. There is no mender-auth and thus no DBus API and no HTTP proxy functionality for connections to a Mender Server.

There is no rootfs-image Update Module, no boot loader integration and thus no full-system OTA updates functionality.

2 Likes

Would be nice if it did support NVMe boot! Tried it with the current image, but it’s not coming up.

Hi @jclsn,

Judging from the QNX documentation, there should be a path towards it: Using NVMe SSD on Raspberry Pi 5 using QNX. I can’t tell right off the bat how involved the changes would be though, it’s an interesting question. Will try to find out :crossed_fingers:

Greetz,
Josef

Thanks, the guide seems to be intended for mounting an NVMe drive into an already running system. This is definitely going into the right direction. The NVMe shows up after executing

$ export PCI_CAP_MODULE_DIR=/proc/boot
$ sudo -E devb-nvme disk name=nvme
$ ls /dev/nvme*
/dev/nvme0 /dev/nvme0t12 /dev/nvme0t178 /dev/nvme0t179

I suppose I also need to patch this component section in the SLM config at /proc/boot/slm.cfg to make it load the driver at boot

<SLM:component name="devb">
SLM:dependpci-server-patchup</SLM:depend>
SLM:commanddevb-sdmmc-bcm2712</SLM:command>
SLM:argscam cam user=20:20 blk cache=64M,auto=partition,vnode=2000,ncache=2000,commit=low sdio addr=0x1000fff000,irq=305 disk name=hd</SLM:args>
<SLM:waitfor wait="pathname">/dev/hd0</SLM:waitfor>

</SLM:component>
1 Like

I tried copying over the devb-nvme driver to NVMe containining the same system image. Seems like the partitions are not expanded yet and it returns no space left on device.

Guess this won’t work unless the drivers and slm.cfg get baked into the image beforehand. Gonna have a go at this

and the build is failing of course :smiley: I guess it’s because I am on Arch and the guide is for Ubuntu. Tried building in a ubuntu:24.04 container, but no luck either.

1 Like

I managed to get the build working on my Fedora system (for the RPi5 target). What are the issues you are facing when trying to run a CTI build?

There were a lot of weird errors an Arch. Too many to count. I gave up on that and set up a Ubuntu 24.04 VM with Qemu. Build worked now and I am trying to find out how to install the drivers into the target image. That part isn’t documented in the guide unfortunately.

1 Like

Cool, great to hear! And yup, it’s very much DIY unless you want to do something from the couple customization options they explicitly support.

I managed to boot the image from an NVMe. Here is the diff

diff --git a/mkqnximage/rpi5/rpi/snippets/boot_files.99.type_rpi5 b/mkqnximage/rpi5/rpi/snippets/boot_files.99.type_rpi5
index 7599e23..0b7db06 100644
--- a/mkqnximage/rpi5/rpi/snippets/boot_files.99.type_rpi5
+++ b/mkqnximage/rpi5/rpi/snippets/boot_files.99.type_rpi5
@@ -55,6 +55,15 @@ cmdline=startup.txt
 enable_uart=1
 kernel=qnx_sdp.ifs
 kernel_address=0x8000000
+
+dtparam=pciex1
+dtparam=nvme
+dtparam=pciex1_gen=3
+
+
 }
 qnx_sdp.ifs=output/ifs.bin
 
diff --git a/mkqnximage/rpi5/rpi/snippets/definitions.type_rpi5 b/mkqnximage/rpi5/rpi/snippets/definitions.type_rpi5
index 4805d78..2c71e75 100644
--- a/mkqnximage/rpi5/rpi/snippets/definitions.type_rpi5
+++ b/mkqnximage/rpi5/rpi/snippets/definitions.type_rpi5
@@ -7,11 +7,11 @@
 
 # Start kernel with watchdog? Requires "wdtkick -W0x24:0x5A028E4C -W0x1c:0x5A000020"
 # to be executed shortly after slog2 is started
-# #define __STARTUP__ startup-bcm2712-rpi5 -u reg -a -W 5000 
+# #define __STARTUP__ startup-bcm2712-rpi5 -u reg -a -W 5000
 
-# SD/MMC driver related
-#define __DEVB_NAME__ devb-sdmmc-bcm2712
-#define __DEVB_OPTS__ sdio addr=0x1000fff000,irq=305 disk name=hd
+# NVMe driver related
+#define __DEVB_NAME__ devb-nvme
+#define __DEVB_OPTS__ disk name=hd
 
 # Debug console serial driver
 #define __DEVC_NAME__ devc-serpl011-rpi5
diff --git a/targets/rpi5/rules.mk b/targets/rpi5/rules.mk
index 5de2571..7d7185f 100644
--- a/targets/rpi5/rules.mk
+++ b/targets/rpi5/rules.mk
@@ -13,6 +13,8 @@ $(BUILD)/built_bsp: $(BUILD)/bsp
 	/bin/bash -c "set -a && source $(STAGE_QNX_SDP)/qnxsdp-env.sh && make -C$(BUILD)/bsp/src hinstall install"
 	rm -f $(BUILD)/bsp/prebuilt/aarch64le/sbin/devb-sdmmc-bcm2712
 	cp $(BUILD)/bsp/install/aarch64le/sbin/devb-sdmmc-bcm2712 $(BUILD)/bsp/prebuilt/aarch64le/sbin/devb-sdmmc-bcm2712
+	rm -f $(BUILD)/bsp/prebuilt/aarch64le/sbin/devb-nvme
+	cp $(BUILD)/../../qnx800/target/qnx/aarch64le/sbin/devb-nvme $(BUILD)/bsp/prebuilt/aarch64le/sbin/devb-nvme
 	rm -f $(BUILD)/bsp/prebuilt/aarch64le/bin/msix-rp1
 	cp $(BUILD)/bsp/src/hardware/support/bcm2712/msix-rp1/aarch64/le/msix-rp1 $(BUILD)/bsp/prebuilt/aarch64le/bin/msix-rp1
 	/bin/bash -c "set -a && source $(STAGE_QNX_SDP)/qnxsdp-env.sh && make -C$(BUILD)/bsp all install"
diff --git a/targets/rpi5/snippets/ifs_files.custom b/targets/rpi5/snippets/ifs_files.custom
index bb4ea10..c60f6d3 100644
--- a/targets/rpi5/snippets/ifs_files.custom
+++ b/targets/rpi5/snippets/ifs_files.custom
@@ -3,6 +3,8 @@ msix-rp1=bin/msix-rp1
 wdtkick=bin/wdtkick
 devc-serpl011-rpi5=sbin/devc-serpl011-rpi5
 devb-sdmmc-bcm2712=sbin/devb-sdmmc-bcm2712
+devb-nvme=sbin/devb-nvme
 toybox=usr/bin/toybox
 sbin/getty

The NVMe is still enumerated as hd0 though. I tried fixing it with the following patch, but it did not work. Could not find any other entries to change from hd to nvme in the tree. Do you have ideas how to fix this?

diff --git a/mkqnximage/cti/rpi5-mount_fs.sh.diff b/mkqnximage/cti/rpi5-mount_fs.sh.diff
index ef2dab6..4cd913e 100644
--- a/mkqnximage/cti/rpi5-mount_fs.sh.diff
+++ b/mkqnximage/cti/rpi5-mount_fs.sh.diff
@@ -11,28 +11,28 @@ index 19edaf0..7783ba9 100644
  	exit 0
  fi
  
-@@ -36,32 +36,32 @@ if [ -e /dev/hd0t185 ]; then
+@@ -36,32 +36,32 @@ if [ -e /dev/nvme0t185 ]; then
  	# container and then the file system contained within
- 	mount -t qtd -o key=/proc/boot/qtd_public_key.pem  /dev/hd0t185 /dev/hd0t185-fs
- 	if check_magic /dev/hd0t185-fs 8192 "\0042\0021\0031\0150"; then
--		mount -t qnx6 -o noatime  /dev/hd0t185-fs /system
-+		mount -t qnx6 -o noatime  /dev/hd0t185-fs /usr
- 	elif check_magic /dev/hd0t185-fs 0 "\0377\0272\0377\0261"; then
--		mount -t qcfs  /dev/hd0t185-fs /system
-+		mount -t qcfs  /dev/hd0t185-fs /usr
+ 	mount -t qtd -o key=/proc/boot/qtd_public_key.pem  /dev/nvme0t185 /dev/nvme0t185-fs
+ 	if check_magic /dev/nvme0t185-fs 8192 "\0042\0021\0031\0150"; then
+-		mount -t qnx6 -o noatime  /dev/nvme0t185-fs /system
++		mount -t qnx6 -o noatime  /dev/nvme0t185-fs /usr
+ 	elif check_magic /dev/nvme0t185-fs 0 "\0377\0272\0377\0261"; then
+-		mount -t qcfs  /dev/nvme0t185-fs /system
++		mount -t qcfs  /dev/nvme0t185-fs /usr
  	else
  		echo "Don't recognise the filesystem"
  	fi
  	rm -f /dev/shmem/fs-magic*
- elif [ -e /dev/hd0t186 ]; then
--    qtsafefsd -o key=/proc/boot/qtsafefs_public_key.pem  /dev/hd0t186 /system
-+    qtsafefsd -o key=/proc/boot/qtsafefs_public_key.pem  /dev/hd0t186 /usr
- elif [ -e /dev/hd0t181 ]; then
--	mount -t qcfs  /dev/hd0t181 /system
-+	mount -t qcfs  /dev/hd0t181 /usr
+ elif [ -e /dev/nvme0t186 ]; then
+-    qtsafefsd -o key=/proc/boot/qtsafefs_public_key.pem  /dev/nvme0t186 /system
++    qtsafefsd -o key=/proc/boot/qtsafefs_public_key.pem  /dev/nvme0t186 /usr
+ elif [ -e /dev/nvme0t181 ]; then
+-	mount -t qcfs  /dev/nvme0t181 /system
++	mount -t qcfs  /dev/nvme0t181 /usr
  else # QNX6
--	mount -t qnx6 -o noatime  /dev/hd0t178 /system 2>/dev/null
-+	mount -t qnx6 -o noatime  /dev/hd0t178 /usr 2>/dev/null
+-	mount -t qnx6 -o noatime  /dev/nvme0t178 /system 2>/dev/null
++	mount -t qnx6 -o noatime  /dev/nvme0t178 /usr 2>/dev/null
  	# We've mounted the system file system opportunistically. If it appears that
  	# it was in need of expansion, unmount, expand and remount.
 -	if [ ! -e /system/etc/build.date -o -e /system/needs_expansion ]; then
@@ -40,10 +40,10 @@ index 19edaf0..7783ba9 100644
 +	if [ ! -e /usr/etc/build.date -o -e /usr/needs_expansion ]; then
 +		umount /usr 2>/dev/null
  		expandfs.sh
--		mount -t qnx6 -o noatime  /dev/hd0t178 /system 2>/dev/null
+-		mount -t qnx6 -o noatime  /dev/nvme0t178 /system 2>/dev/null
 -		rm -f /system/needs_expansion
 -		touch /system/etc/build.date
-+		mount -t qnx6 -o noatime  /dev/hd0t178 /usr 2>/dev/null
++		mount -t qnx6 -o noatime  /dev/nvme0t178 /usr 2>/dev/null
 +		rm -f /usr/needs_expansion
 +		touch /usr/etc/build.date
  		FS_EXPANDED=1
diff --git a/mkqnximage/cti/slm.cfg.diff b/mkqnximage/cti/slm.cfg.diff
index 29673e1..107d1bd 100644
--- a/mkqnximage/cti/slm.cfg.diff
+++ b/mkqnximage/cti/slm.cfg.diff
@@ -1,21 +1,32 @@
---- ../../build/qemu/output/build/slm.cfg.orig	2025-08-31 20:37:41.481159095 -0400
+---- a/../../build/rpi5/output/build/slm.cfg.orig
++++ b/../../build/rpi5/output/build/slm.cfg
+@@ -26,7 +26,7 @@
+     <SLM:depend>pci-server-patchup</SLM:depend>
+     <SLM:command>devb-nvme</SLM:command>
+     <SLM:args>cam cam user=20:20 blk cache=64M,auto=partition,vnode=2000,ncache=2000,commit=low disk name=nvme</SLM:args>
+-    <SLM:waitfor wait="pathname">/dev/hd0</SLM:waitfor>
++    <SLM:waitfor wait="pathname">/dev/nvme0</SLM:waitfor>
+
+   </SLM:component>
+
+-- ../../build/qemu/output/build/slm.cfg.orig	2025-08-31 20:37:41.481159095 -0400
 +++ ../../build/qemu/output/build/slm.cfg	2025-08-31 21:10:32.024728298 -0400
 @@ -97,10 +97,8 @@
    </SLM:component>
- 
+
    <SLM:component name="ssh">
 -    <SLM:depend>network-init</SLM:depend>
 -    <SLM:command launch="pathname">/system/bin/sshd</SLM:command>
 -    <SLM:args>-f /system/etc/ssh/sshd_config -D</SLM:args>
--    
+-
 +    <SLM:depend>pam</SLM:depend>
 +    <SLM:command launch="pathname">/usr/etc/startup/startup_ssh.sh</SLM:command>
    </SLM:component>
- 
+
    <SLM:component name="qconn">
 @@ -110,8 +108,8 @@
    </SLM:component>
- 
+
    <SLM:component name="console">
 -    <SLM:depend>devc</SLM:depend>
 -    <SLM:command launch="session">/proc/boot/ksh</SLM:command>
@@ -23,9 +34,9 @@
 +    <SLM:command launch="session">/system/libexec/qnx/tty-login.sh</SLM:command>
      <SLM:args>-l</SLM:args>
      <SLM:tty>/dev/ser1</SLM:tty>
-     
+
 @@ -126,7 +124,7 @@
- 
+
    <SLM:component name="post_start">
      <SLM:depend state="stateless">root-fs</SLM:depend>
 -    <SLM:depend state="stateless">ssh</SLM:depend>
diff --git a/mkqnximage/rpi5/rpi/snippets/definitions.type_rpi5 b/mkqnximage/rpi5/rpi/snippets/definitions.type_rpi5
index 2c71e75..971641d 100644
--- a/mkqnximage/rpi5/rpi/snippets/definitions.type_rpi5
+++ b/mkqnximage/rpi5/rpi/snippets/definitions.type_rpi5
@@ -11,7 +11,7 @@
 
 # NVMe driver related
 #define __DEVB_NAME__ devb-nvme
-#define __DEVB_OPTS__ disk name=hd
+#define __DEVB_OPTS__ disk name=nvme
 
 # Debug console serial driver
 #define __DEVC_NAME__ devc-serpl011-rpi5
diff --git a/mkqnximage/rpi5/rpi/snippets/secpolgen.type_rpi5 b/mkqnximage/rpi5/rpi/snippets/secpolgen.type_rpi5
index 232d447..5bf9699 100644
--- a/mkqnximage/rpi5/rpi/snippets/secpolgen.type_rpi5
+++ b/mkqnximage/rpi5/rpi/snippets/secpolgen.type_rpi5
@@ -1,4 +1,4 @@
-mount -t dos /dev/hd0t12 /boot
+mount -t dos /dev/nvme0t12 /boot
 if [ -e /boot/onboot ]; then
     echo Running onboot script
     ksh /boot/onboot
1 Like