More experiments with QNX and Qemu.
Here we create an SD image and QNX IFS image to be booted into an emulated raspberry pi4. We use a patched version of qemu. We also prepare to attach the debuggger in qemu.
As we now have access to QNX by the great program QNX everywhere, and I have managed to patch qemu enough to access the SD-card we can continue the experiments.
Downlaoad QNX, https://www.qnx.com/products/everywhere/
Clone and build qemu. https://github.com/Ebiroll/qemu-stm32 Hopefully qemu will be fixed one day, but for now this is good enough to get you started experimenting.
Setup and build the ifs image.
The build definition is located here, ${BSP_ROOT_DIR}/images/rpi4.build
Modify the block device driver options to match our emulated hardware,
# devb-sdmmc-bcm2711 sdio addr=0xfe340000,irq=158,bs=bmstr_base=0xc0000000 disk name=sd
devb-sdmmc-bcm2711 dos exe=all mem sdio addr=0xfe340000,irq=158 disk name=sd
waitfor /dev/sd0
mount -tdos /dev/sd0t12 /dos
waitfor /dos
SD card patch,
The qemu patch that got the SD-card working was mainly this:
void sdhci_attach_card(SDHCIState *s) {
SDState *card = get_my_card(&s->sdbus);
if (!card) {
BlockBackend *blk;
Error *err = NULL;
blk = blk_by_name("sdcard"); // Use the ID specified in the QEMU command line
if (!blk) {
fprintf(stderr, "No block backend named 'sdcard' found\n");
return;
}
DeviceState *sdcard_dev = qdev_new(TYPE_SD_CARD);
qdev_prop_set_drive(sdcard_dev, "drive", blk);
qdev_realize_and_unref(sdcard_dev, BUS(&s->sdbus), &err);
if (err) {
fprintf(stderr, "Failed to attach SD card: %s\n", error_get_pretty(err));
error_free(err);
return;
}
}
}
This means you have to add this command line option,
-drive id=sdcard,if=none,format=raw,file=sd.img
In previous version as well as main branch of qemu you can use
-sd sd.img
This is equvalent to
-drive id=sd-card,if=none,format=raw,file=sd.img
-device sd-card,drive=sd-card,bus=sd-bus
My patched version has a "hack" that connects the sd card to the correct bus and you only need
-drive id=sdcard,if=none,format=raw,file=sd.img
Create sd image
Script to create a dual partition image and copy files from the directory boot-files
#!/bin/bash
set -e # Exit immediately if a command exits with a non-zero status
IMAGE_SIZE_MB=2048
PART1_SIZE_MB=1024
IMAGE_FILE="sd.img"
MOUNT_POINT="/mnt/sdimg"
BOOT_FILES_DIR="boot-files"
# Create a 2GB empty image file
dd if=/dev/zero of=${IMAGE_FILE} bs=1M count=${IMAGE_SIZE_MB}
# Create partitions: 1GB FAT32 and the rest for QNX6
parted ${IMAGE_FILE} --script mklabel msdos \
mkpart primary fat32 1MiB ${PART1_SIZE_MB}MiB \
mkpart primary ${PART1_SIZE_MB}MiB 100%
# If you are running on LSW for windows you can stop here
# Map the partitions to loop devices
LOOP_DEVICE=$(sudo losetup --show -fP ${IMAGE_FILE})
LOOP_PART1=${LOOP_DEVICE}p1
LOOP_PART2=${LOOP_DEVICE}p2
# Format the first partition as FAT32
sudo mkfs.vfat -F 32 ${LOOP_PART1}
# Prepare the second partition for QNX6 (formatting can be done during QNX installation)
# sudo mkfs.qnx6 ${LOOP_PART2} # Uncomment if mkfs.qnx6 is available and desired
# Create mount point if it doesn't exist
sudo mkdir -p ${MOUNT_POINT}
# Mount the FAT32 partition
sudo mount ${LOOP_PART1} ${MOUNT_POINT}
# Copy boot files into the FAT32 partition
sudo cp -r ${BOOT_FILES_DIR}/* ${MOUNT_POINT}/
# Unmount and clean up
sudo umount ${MOUNT_POINT}
sudo losetup -d ${LOOP_DEVICE}
sudo rmdir ${MOUNT_POINT}
echo "${IMAGE_FILE} has been created and prepared successfully."
The copying of files is not necessary, but here I choose to put the boot partition of a ubuntu raspberry disk in order to do some tests with u-boot. https://github.com/Ebiroll/emulate-raspberry-in-qemu/tree/main/boot-files
If you want to create an image without root access this could be handy. https://github.com/Othernet-Project/dir2fat32
We will do the qnx6 formatting within the emulated environment.
qemu-system-aarch64 -M raspi4b -kernel ifs-rpi4.bin
-append "startup-bcm2711-rpi4 -vvv -D miniuart"
-drive id=sdcard,if=none,format=raw,file=sd.img
-d unimp -trace "bcm*" -trace file=trace_output.log
-s -serial tcp::12345,server,nowait -serial stdio
-serial tcp::12346,server,nowait
The -append is the command line options for QNX and I have removed -W 2500 as the watchdog generates a lot of noice in the emulated environent.
After booting with our image,
# df -h
/dev/sd0t12 1021M 26M 995M 3% /dos/
/dev/sd0 1.0G 1.0G 0 100% /dev/sd0t131
/dev/sd0 2.0G 2.0G 0 100%
# umount /dev/sd0t131
# ls /dev/sd0*
/dev/sd0 /dev/sd0t12
# mount -e /dev/sd0
# ls /dev/sd0*
/dev/sd0 /dev/sd0t12 /dev/sd0t131
# mkqnx6fs /dev/sd0t131
All files on /dev/sd0t131 will be lost!
Confirm filesystem re-format (y) or (n): y
Format fs-qnx6: 262140 blocks, 32768 inodes, 4 groups
# shutdown
Also investigate mkqnx6fs /dev/sd0t177
If you are having trouble, you can look here: https://forums.openqnx.com/t/topic/47438/6
After the disk is formatted, you can add this to your startup script
[perms=0755] /scripts/mount.sh = {
#!/bin/sh
waitfor /dev/sd0
if [ ! -e /dev/sd0t177 ]; then
echo "/dev/sd0t177 NOT found"
else
echo "found /dev/sd0t177 and mounted on /"
mount -tqnx6 /dev/sd0t177 /
waitfor /
fi
if [ ! -e /dev/sd0t12 ]; then
echo "/dev/sd0t12 NOT found"
else
echo "found /dev/sd0t12 and mounted on /dos"
mount -tdos /dev/sd0t12 /dos
waitfor /dos
fi
if [ ! -e /dev/sd0t131 ]; then
echo "/dev/sd0t131 NOT found"
else
echo "found /dev/sd0t131 and mounted on /"
mount -tqnx6 /dev/sd0t131 /
waitfor /
fi
}
This might look very weird to a linux user but the qnx filesystem is mounted on / and mixed with the ifs filesystem and mounted on /
Do not forget to call this sctipt
[+script] .script = {
...
/scripts/mount.sh
[+session] ksh &
}
When running the disks will now be mounted by /scripts/mount.sh
System page at phys:0000000000012000 user:ffffff8040206000 kern:ffffff8040204000
Starting next program at vffffff806005ab40
MMFLAGS=1
Welcome to QNX Neutrino on the Raspberry Pi 4 (Armv8-A Cortex-A72 core)
Starting random service...
Starting serial driver (/dev/ser1)
Starting serial driver (/dev/ser3)
Starting I2C driver (/dev/i2c1)...
Starting SPI 0 driver (/dev/spi0)...
Starting SDMMC driver for SD card (SDIO0)...
Starting PCI Server...
Starting Network driver...
Path=0 - bcm2711
target=0 lun=0 Direct-Access(0) - SDMMC: QEMU! Rev: a.d
/dev/sd0t177 NOT found
found /dev/sd0t12 and mounted on /dos
found /dev/sd0t131 and mounted on /
I have also removed audio and other drivers but added,
devc-serpl011 -b115200 -c48000000 -e -F -u2 0xfe201800,153
This character device driver supports an extra serial driver /dev/ser2
The network simulation also does not work so well but add this to allow easy debugging.
#######################################################################
## Remote debug
#######################################################################
#inetd
devc-pty
#qconn port=8000
/scripts/mount.sh
pdebug /dev/ser3,57600
Here is how to start the debugger,
$QNX_HOST/usr/bin/ntoaarch64-gdb -ex 'target qnx 127.0.0.1:12345'
GNU gdb
Remote debugging using 127.0.0.1:12345
Remote target is little-endian
(gdb) info pidlist
Uploading over simulated serial takes some time so I recomend
(gdb) set nto-executable /bin/mbox-bcm2711
(gdb) run cmdline
Starting program: cmdline
Remote: /bin/mbox-bcm2711
startup-bcm2711-rpi4 -vvv -D miniuart
[Inferior 1 (pid 73743) exited normally]
No inferior.
This runs
# mbox-bcm2711 cmdline
in the debugger
Other useful env variables,
(gdb) set nto-cwd /test/data
Read all about it here,
There is also the possibility to attach to the qemu debug stub listening at 127.0.0.1:1234 but when qnx loads a process the elf file must be mapped exactly as o the simuated target. (gdb) info meminfo gives some useful information.