QNX System Building & IFS
About 1260 wordsAbout 4 min
2026-03-25
What Is an IFS?
An IFS (Image File System) is a bootable filesystem image that contains everything needed to start a QNX Neutrino system:
- The kernel (
procnto-smp-instr) - Startup code (
startup-boardname) - Essential device drivers
- System utilities
- Initial configuration scripts
- Optionally: application binaries and data
The IFS is produced by the mkifs tool from a build script (.build file). The resulting *.ifs binary is written to flash, SD card boot partition, or served via TFTP.
Boot Image Structure
QNX IFS Image
┌────────────────────────────────────────────────────┐
│ Image Header │
│ (magic, size, checksum, entry point) │
├────────────────────────────────────────────────────┤
│ Startup Section (startup-boardname) │
│ • Hardware init: DRAM, clocks, PLLs, WDT │
│ • Fills the syspage (hardware description) │
│ • Jumps to procnto entry point │
├────────────────────────────────────────────────────┤
│ Rampatch (optional, board-specific errata fixes) │
├────────────────────────────────────────────────────┤
│ Filesystem Section │
│ ├── procnto-smp-instr (kernel + process manager) │
│ ├── slogger2 (system logger) │
│ ├── pipe (POSIX pipe server) │
│ ├── devc-ser8250 (serial console driver) │
│ ├── devb-sdmmc (SD/eMMC driver) │
│ ├── io-pkt-v6-hc (TCP/IP stack) │
│ ├── libc.so.x (C library) │
│ ├── libm.so.x (math library) │
│ ├── cmd/sh (shell) │
│ ├── myapp (application binary) │
│ └── .script (startup script) │
└────────────────────────────────────────────────────┘Build Script Structure
The build script (conventionally named system.build or *.build) has three sections:
[virtual=x86_64,elf] .bootstrap = {
startup-x86
PATH=/proc/boot procnto-smp-instr
}
[+script] .script = {
# Initialization commands run by procnto
procmgr_symlink ../../proc/boot/libc.so.6 /usr/lib/ldqnx-64.so.2
slogger2 &
pipe &
...
}
# Files to include in the IFS filesystem section
[uid=0 gid=0 perms=0755] /proc/boot/myapp = myapp
[uid=0 gid=0 perms=0644] /etc/myapp.cfg = myapp.cfgAnnotated Build Script Example
# system.build — QNX IFS build script for a custom ARM board
# Produced by: mkifs -r $QNX_TARGET system.build system.ifs
# ── Global attributes ────────────────────────────────────────────────────
[image=0x81000000] # Load address in RAM
[virtual=aarch64le,elf] # Architecture
[page_size=0x1000] # 4 KB pages
# ── Bootstrap section: brings up the hardware ────────────────────────────
.bootstrap = {
# 1. Board startup: clocks, DRAM init, fills syspage
startup-myboard -D 115200,-u 1 -v
# 2. Kernel — must be first after startup
PATH=/proc/boot procnto-smp-instr -v
}
# ── Script section: runs after kernel starts ─────────────────────────────
[+script] .script = {
# Set up dynamic linker symlink
procmgr_symlink ../../proc/boot/libc.so.6 /usr/lib/ldqnx-64.so.2
# Start system logger (receives slog2 messages)
PATH=/proc/boot LD_LIBRARY_PATH=/proc/boot slogger2 &
# Start pipe server (POSIX pipes)
PATH=/proc/boot pipe &
# Start console (UART1)
PATH=/proc/boot devc-ser8250 -e -b115200 -c96000000 0x3F8,4 &
waitfor /dev/ser1 4
reopen /dev/ser1
# Start SD/eMMC driver
PATH=/proc/boot devb-sdmmc blk automount=sd0 sdio &
waitfor /dev/sd0 5
# Mount root filesystem from SD card partition 1 (QNX6)
mount -t qnx6 /dev/sd0t12 /
waitfor / 5
# Start network stack
PATH=/proc/boot io-pkt-v6-hc &
waitfor /dev/io-net 5
ifconfig en0 192.168.1.100 netmask 255.255.255.0 up
route add default 192.168.1.1
# Start SSH daemon
/usr/sbin/sshd &
# Application startup
myapp &
# Drop to shell if app fails
[+session] sh
}
# ── Files included in /proc/boot (initial RAM filesystem) ────────────────
# Kernel and startup (auto-included from above, listed for clarity)
procnto-smp-instr
# Core runtime libraries
libc.so.6
libm.so.3
libz.so.2
libstdc++.so.6
# Drivers
devc-ser8250
devb-sdmmc
io-pkt-v6-hc
# System utilities
[type=link] /proc/boot/libc.so.6=/usr/lib/ldqnx-64.so.2
sh
ls
cat
cp
mv
rm
mkdir
mount
ifconfig
route
slogger2
slog2info
pipe
pidin
# Application with assets
[uid=0 gid=0 perms=0755] /proc/boot/myapp = ${WORKSPACE}/release/myapp
[uid=0 gid=0 perms=0644] /proc/boot/myapp.conf = ${WORKSPACE}/config/myapp.conf
# Libraries required by myapp (use ldd on host to find them)
libmylib.so.1mkifs: Building the Image
# Basic build
mkifs system.build system.ifs
# With verbose output
mkifs -v system.build system.ifs
# Specify target path for library lookups
mkifs -r $QNX_TARGET system.build system.ifs
# Debug: list image contents
mkifs -l system.build system.ifs
# Verify existing image contents
dumpifs system.ifs
# Extract a file from the image
dumpifs -x procnto-smp-instr system.ifsdumpifs: Inspecting an Image
# List all files in the image
dumpifs system.ifs
# Example output:
# Offset Size Attr Name
# 0 4136 ---- .bootstrap
# 1028 438272 -r-x procnto-smp-instr
# 440296 24576 -r-x startup-myboard
# 464872 512 ---- .script
# 465384 16384 -r-x devc-ser8250
# 481768 ...
# Show image header
dumpifs -i system.ifs
# Extract a specific binary
dumpifs -x myapp system.ifs
# Dump full symbol table
dumpifs -s system.ifsBuild Script Attributes
Attributes modify files or sections of the build script:
| Attribute | Description |
|---|---|
uid=N | File UID in the IFS |
gid=N | File GID |
perms=0NNN | File permissions |
+script | This section is the init script |
+compress | Compress included file (uses deflate) |
+raw | Include file as raw binary (no ELF processing) |
+bigendian / +littleendian | Byte order |
physical=0xADDR | Place this file at a specific physical address |
virtual=0xADDR | Virtual address for this section |
virtual=arch,elf | Specify target architecture |
keep | Do not compress this section |
type=link | In-IFS symbolic link |
align=N | Alignment requirement |
# Compressed application (reduces IFS size, decompressed on load)
[+compress perms=0755] /proc/boot/myapp = myapp
# Place at specific physical address (e.g., for DMA buffer)
[physical=0x30000000 virtual=0x30000000 +raw perms=0644]
/proc/boot/firmware.bin = firmware.bin
# Internal symbolic link
[type=link] /proc/boot/libfoo.so.1 = libfoo.so.1.2.3The .script Section In Depth
The .script section is executed by procnto as a minimal shell. Available commands:
| Command | Description |
|---|---|
display_msg | Print a message to console |
waitfor | Wait for a file/device to appear |
reopen | Close stdin/stdout/stderr, reopen on specified device |
procmgr_symlink | Create a symbolic link in the namespace |
mount | Mount a filesystem |
[+session] | Start a foreground session (shell) |
| Standard sh | &, if, for, sleep, environment variables |
[+script] .script = {
# Print startup message
display_msg "Starting QNX on MyBoard v2.0"
# Wait up to 5 seconds for /dev/ser1 to appear
waitfor /dev/ser1 5
# Redirect console to serial port
reopen /dev/ser1
# Mount extra filesystems
mount -t qnx6 /dev/sd0t79 /usr
mount -t tmpfs tmpfs /tmp
mount -t tmpfs tmpfs /var/run
# Start all services
io-pkt-v6-hc &
waitfor /dev/io-net 3
dhclient en0 &
# Run init script from disk (after / is mounted)
/etc/rc.d/rc.local &
# Interactive shell as fallback
[+session] sh
}BSP (Board Support Package) Structure
A QNX BSP provides the board-specific startup code and drivers:
bsp-myboard/
├── Makefile
├── prebuilt/
│ └── nto/
│ └── aarch64le/
│ └── boot/
│ └── sys/
│ └── startup-myboard ← prebuilt startup binary
├── src/
│ ├── hardware/
│ │ ├── startup/
│ │ │ └── boards/
│ │ │ └── myboard/
│ │ │ ├── main.c ← startup entry point
│ │ │ ├── init_board.c ← clocks, PLL, DDR init
│ │ │ ├── callout_*.s ← interrupt callouts (ASM)
│ │ │ └── Makefile
│ │ └── devi/
│ │ └── myboard-gpio/ ← GPIO driver
│ └── lib/
│ └── libhw-i2c-myboard/ ← I2C HAL library
├── images/
│ └── system.build ← IFS build script
└── prebuilt/
└── nto/
└── aarch64le/
└── lib/
└── dll/
└── devnp-myboard.so ← board-specific NIC driverStartup Code Internals
The startup-boardname binary runs before the kernel. It:
- Initializes DDR (SDRAM controller, PHY training)
- Configures PLLs and clocks
- Sets up UART for early console output
- Initializes the syspage — a kernel data structure describing hardware
- Calls
cpu_startup()→ sets up MMU, exception vectors - Calls
main()instartup/boards/boardname/main.c - Jumps to
procntoentry point
/* startup-myboard/main.c */
#include <startup.h>
void board_startup(void) {
/* Initialize clocks */
init_clocks();
/* Initialize DRAM controller */
init_ddr();
/* Add UART for syspage */
add_typed_string(_CS_MACHINE, "MyBoard v2.0");
hwi_add_device(HWI_ITEM_BUS_UNKNOWN, HWI_ITEM_DEVCLASS_SERIAL,
"8250", 0);
hwi_add_inputclk(96000000, 1);
hwi_add_location(UART_BASE, 0x1000, hwi_find_as(UART_BASE, 1), 0);
hwi_add_irq(UART_IRQ);
/* Add memory regions to syspage */
as_add(0x40000000, 0x7FFFFFFF, AS_ATTR_RAM, "ram", "memory");
}Deploying and Flashing the IFS
Flashing to SPI NOR Flash
# On the host: write system.ifs to SPI flash via programmer
# On the target: write via flashctl
flashctl -p /dev/fs0 -ev # erase
dd if=system.ifs of=/dev/fs0 # writeBooting via TFTP
Configure U-Boot or QNXIPL to load the IFS via TFTP:
# U-Boot environment
setenv serverip 192.168.1.1
setenv ipaddr 192.168.1.100
tftp 0x81000000 system.ifs
go 0x81000000SD Card Boot
# Write IFS to first partition of SD card (raw, no filesystem)
dd if=system.ifs of=/dev/mmcblk0p1 bs=512Build Automation with Makefiles
# Makefile for IFS build
QNX_TARGET ?= /path/to/qnx800/target/qnx
PROCESSOR = aarch64le
IMAGE = system.ifs
BUILDFILE = system.build
$(IMAGE): $(BUILDFILE) $(DEPS)
mkifs -r $(QNX_TARGET) -p $(PROCESSOR) $(BUILDFILE) $(IMAGE)
clean:
rm -f $(IMAGE)
deploy: $(IMAGE)
scp $(IMAGE) root@192.168.1.100:/tmp/
ssh root@192.168.1.100 "dinit -x /tmp/$(IMAGE) /dev/sd0"
.PHONY: clean deploy