QNX OS on the Raspberry Pi
This section explains how the following mechanisms work on the QNX OS on the Raspberry Pi. An understanding of these mechanisms will contribute to your success when building applications on the QNX OS:
The shell
Once you've logged in with SSH, you should see the system's shell prompt:
qnxuser@qnxpi:~$
The shell is an interactive command interpreter. When you type in various commands, the shell executes them, typically by creating new processes.
The default shell on QNX systems is a variant of the Korn shell (pdksh), but the QNX OS quick start image uses bash.
Toybox is a program that provides many shell utilities, and the system uses symbolic links from various utility names to toybox. This allows the user to use standard shell commands. For example, you can use ls
to list files:
qnxuser@qnxpi:~$ ls /tmp
keep_files
qnxuser@qnxpi:~$ which ls
/proc/boot/ls
qnxuser@qnxpi:~$ ls -l /proc/boot/ls
lrwxrwxrwx 1 root root 6 2023-10-14 15:18 /proc/boot/ls -> toybox
The sequence above shows that ls
is a symbolic link under /proc/boot to toybox.
The filesystem
A filesystem is a collection of files, typically organized hierarchically into directories, that can be stored on some medium (e.g., a hard drive, SD card, network storage, or even RAM). There are different formats for file systems, some of the more common ones being FAT and NTFS from Microsoft and ext4 from Linux.
QNX primarily supports the native QNX6 power-safe filesystem and also supports the filesystems listed in the "Filesystems" chapter of the System Architecture guide.
Almost all QNX-based systems employ more than one filesystem. These different filesystems are provided by different server processes. Any request to access a file queries the path manager for the server that provides the path to be opened, and then asks that server for the file.
Filesystems on the QNX OS quick start image
The df
command reports free disk space, allowing you to see which filesystems the image includes and where each filesystem is mounted:
qnxuser@qnxpi:~$ df
ifs 24424 24424 0 100% /
/dev/hd0t178 6291424 1342072 4949352 22% /system/
/dev/hd0t12 143264 29664 113600 21% /boot/
/dev/hd0t179 27262944 1476296 25786648 6% /data/
/dev/hd0 62333952 62333952 0 100%
/dev/shmem 0 0 0 100% (/dev/shmem)
We can gather the following information from each filesystem entry:
ifs
The image filesystem (IFS), which is a read-only filesystem that is loaded into memory early during boot and remains resident in memory.
/dev/hd0t178 and /dev/hd0t179
The QNX6 filesystems mounted at /system and /data, respectively. This separation allows for the system partition to be mounted as read-only, while the data partition remains writeable. In the QNX OS quick start image, both partitions are writable if you're root. This allows you to add executables and libraries later and edit configuration files.
/dev/hd0t12
The FAT filesystem mounted at /boot, which the Raspberry Pi firmware uses to boot the system. This filesystem also holds a few configuration files that you can edit before booting the system for the first time.
/dev/hd0
The entire SD card. This entry doesn't represent a filesystem.
/dev/shmem
A path where shared memory objects appear. It's possible to to write files under /dev/shmem, which stay in memory until you shut down the system or remove the file. However, this isn't a full filesystem, and you shouldn't treat it as such.
For more information, refer to the /dev/shmem RAM "filesystem" section in the QNX OS User's Guide.
Processes
A process is a running instance of a program. Each process contains one or more threads, where each thread represents a stream of execution within that program. All QNX-based systems run multiple processes at any given time. The first process in these systems hosts the kernel, which is called procnto-smp-instr
. The program for this process consists of the QNX OS microkernel and a set of basic services, including the process manager (creates new processes), memory manager (manages virtual memory), and path manager (resolves pathnames to the servers that host them).
You can use the pidin
command to list all the processes and threads in a system. The example below shows a snippet of a pidin
listing:
qnxuser@qnxpi:~$ su root -c pidin
pid tid name prio STATE Blocked
1 1 /proc/boot/procnto-smp-instr 0f READY
1 2 /proc/boot/procnto-smp-instr 0f READY
1 3 /proc/boot/procnto-smp-instr 0f RUNNING
1 4 /proc/boot/procnto-smp-instr 0f RUNNING
1 5 /proc/boot/procnto-smp-instr 255i INTR
1 6 /proc/boot/procnto-smp-instr 255i INTR
...
12298 16 proc/boot/devb-sdmmc-bcm2711 21r RECEIVE 4
36875 1 proc/boot/pci-server 10r RECEIVE 1
36875 2 proc/boot/pci-server 10r RECEIVE 1
36875 3 proc/boot/pci-server 10r RECEIVE 1
49166 1 proc/boot/rpi_frame_buffer 10r RECEIVE 1
61455 1 proc/boot/devc-bootcon 10r RECEIVE 1
61455 2 proc/boot/devc-bootcon 10r CONDVAR (0x50d562a3cc)
73744 1 proc/boot/rpi_thermal 10r RECEIVE 1
86033 1 proc/boot/rpi_gpio 10r RECEIVE 1
86033 2 proc/boot/rpi_gpio 200r INTR
118802 1 proc/boot/io-usb-otg 10r SIGWAITINFO
118802 2 proc/boot/io-usb-otg 10r CONDVAR (0x5970918880)
118802 3 proc/boot/io-usb-otg 10r CONDVAR (0x59709193a0)
...
Each process has its own process ID (pid), and each thread within a process has its own thread ID (tid).
You can also display more information about each process by passing different options to pidin
. For more information, refer to pidin
in the Utilities Reference.
Memory
All processes in a system compete for memory, and it's up to the system to divide and provide memory to each process. In the QNX OS, the virtual memory manager, which is part of the procnto-smp-instr
process, controls memory.
A common problem with memory is that the system can run out of it, either due to misbehaving processes, or to poor design that doesn't account for the requirements of the system. Therefore, you should always be aware of how much memory your system uses and how much memory each process contributes to total system use.
How much memory does your system use?
To find out how much memory your system uses, run the pidin
command, as shown below:
qnxuser@qnxpi:~$ pidin info
CPU:AARCH64 Release:8.0.0 FreeMem:3689MB/4032MB BootTime: ...
Processes: 0, Threads: 0
Processor1: 1091555459 Cortex-A72 1500MHz FPU
Processor2: 1091555459 Cortex-A72 1500MHz FPU
Processor3: 1091555459 Cortex-A72 1500MHz FPU
Processor4: 1091555459 Cortex-A72 1500MHz FPU
If you run pidin info
as root, the system also displays the number of processes and threads that are running.
The first line shows the amount of RAM your system has. You should have 2GB, 4GB, or 8GB of RAM, depending on the Raspberry Pi model you chose. The example above reveals that there is 3689MB out of 4032MB available for the system to use.
You can view the proc/vm/stats pseudo-file for a more detailed view. You need to access this file as the root user:
qnxuser@qnxpi:~$ su -c cat /proc/vm/stats
The output provides a considerable amount of information, but the points of interest are as follows:
- page_count=0xfc000
The number of 4K RAM pages available to the memory manager. The total amount of memory in the pidin info output should match this value.
- vmem_avail=0xe2677
The number of pages that haven't been reserved by allocations, and are thus available for new allocations. This value corresponds to the free memory number provided by pidin info.
- vm_aspace=33
The number of address spaces in the system, which corresponds to the number of active processes.
- pages_kernel-0x358d
The number of pages that the kernel uses for its own purposes. Note that the value includes the page-table pages allocated for processes.
- pages_reserved=0x5831
The number of pages that the memory manager knows about, but cannot allocate to processes as regular memory. These ranges are typically the result of the startup program, which runs before the kernel, reserving memory for special-purpose pools, or as a way to reduce boot time (in which case the memory can be added to the system later).
The remaining pages_*
lines represent allocated pages in different internal states.
You can also run the following command to observe the breakup of physical memory into various areas:
qnxuser@qnxpi:~$ pidin syspage=asinfo
All entries that end with sysram
are available for the memory manager to use when servicing normal allocation requests from processes. Entries that are part of RAM but outside the sysram
ranges can be allocated using a special interface known as typed memory.
To learn more about how the QNX OS manages memory, refer to the "Memory management" chapter in the System Architecture guide.
Resource managers
A resource manager is a process that registers one or more paths in the path space, then services requests that open files under these paths.
An example of a resource manager on the QNX OS quick start image is the GPIO server, rpi_gpio
. To see the GPIO server running on the system, use the pidin
command, as shown below:
qnxuser@qnxpi:~$ su root -c pidin -p rpi_gpio
pid tid name prio STATE Blocked
86033 1 proc/boot/rpi_gpio 10r RECEIVE 1
86033 2 proc/boot/rpi_gpio 200r INTR
The process manages the 40-pin GPIO header on the Raspberry Pi by memory mapping the hardware registers that control the header, then handling requests from various client programs to control GPIOs (e.g., turn an output GPIO pin on or off). The advantage of this design is that it allows only one process to have access to the hardware registers, preventing GPIO users from interfering with each other.
The rpi_gpio
resource manager registers the path /dev/gpio (you may configure the resource manager to register to a different path using a command line argument). Under this path, the resource manager creates a file for each GPIO pin, with a name matching that of the GPIO number, along with a single msg file:
qnxuser@qnxpi:~$ ls /dev/gpio
0 10 12 14 16 18 2 21 23 25 27 29 30 32
34 36 38 4 41 43 45 47 49 50 52 6 8 msg
1 11 13 15 17 19 20 22 24 26 28 3 31 33
35 37 39 40 42 44 46 48 5 51 53 7 9
You can read and write the numbered files, which means that the resource manager handles message types of _IO_READ and _IO_WRITE on these files. Therefore, you can use shell utilities such as echo
and cat
on these files.
You can use the msg file to send ad-hoc messages, which provide better control of GPIOs without the need for the resource manager to parse text. These messages are easier to handle and are less error prone. The structure of each message is defined in a header file that client programs can incorporate into their code.
For more information on how the write resource managers, refer to the "Resource Managers" chapter of Getting Started with the QNX OS: A Guide for Realtime Programmers and the Writing a Resource Manager guide.