Real-time kernel (PREEMPT_RT)#

Why#

A standard Linux kernel isn’t designed to guarantee a maximum reaction delay: a critical kernel section can delay interrupt handling by several milliseconds under load. Invisible for most use cases; unacceptable for capturing a PPS signal at nanosecond precision. The PREEMPT_RT patch makes the kernel’s own critical sections preemptible, bringing worst-case interrupt latency down from several milliseconds to a few tens of microseconds.

How#

Installation#

apt update
apt install -y linux-image-rpi-v8-rt linux-headers-rpi-v8-rt

apt list --installed 2>/dev/null | grep rpi-v8-rt
ls -lh /boot/firmware/kernel8_rt.img

On Raspberry Pi 5, the model-specific package linux-image-rpi-2712-rt does not exist in the official repositories at the time of writing. The generic package linux-image-rpi-v8-rt (generic ARMv8, 4 KiB pages) is the officially reproducible path, without Pi 5-specific Cortex-A76 optimizations, but fully functional.

Selecting it at boot#

The Pi 5 firmware loads the standard kernel by default, not the freshly installed RT kernel: it needs to be explicitly redirected in /boot/firmware/config.txt:

[pi5]
kernel=kernel8_rt.img

Pitfalls to avoid#

A typo in the filename is silently ignored. The package produces kernel8_rt.img (underscore), not kernel8-rt.img (hyphen). An invalid kernel= directive produces no boot error, the firmware simply falls back to the default kernel, creating the illusion of running RT when that is not the case. Same trap as config.txt in general (see the Firmware chapter): always verify the result, never assume no error means success.

  • Relying on /sys/kernel/realtime to confirm the install. This sysfs attribute is specific to an out-of-mainline patch (used by LinuxCNC), and is absent on a perfectly functional RPi v8-rt kernel. It’s not a reliable test, see the Verify section below for the correct method.
  • Expecting nohz_full/rcu_nocbs from the next chapter to work. The linux-image-rpi-v8-rt kernel is not built with CONFIG_NO_HZ_FULL. The nohz_full= and rcu_nocbs= boot parameters are accepted without error but have no real effect, only isolcpus= works on this kernel (details in the Firmware chapter).

Verify#

reboot
# … reconnect …

uname -a
# Should contain: …-v8-rt … #1 SMP PREEMPT_RT … aarch64
# BEFORE fix: 6.12.75+rpt-rpi-2712 #1 SMP PREEMPT       (standard kernel)
# AFTER fix:  6.12.75+rpt-rpi-v8-rt #1 SMP PREEMPT_RT   (RT kernel)

dmesg | grep -E '\bPREEMPT_RT\b'
# Should show the boot banner line with PREEMPT_RT

dmesg | grep -i "Preemptible hierarchical RCU"
# Should return: "rcu: Preemptible hierarchical RCU implementation."

If uname -r still shows the -rpi-2712 suffix instead of -v8-rt, three causes in order of observed frequency: a typo in the filename, a misplaced [pi5] section in config.txt (must precede [all]), or the kernel8_rt.img file simply missing. vcgencmd get_config kernel confirms which file the firmware actually loaded.


📚 Going further

The PREEMPT_RT patch, maintained by Thomas Gleixner and the community since 2004, was merged into the mainline Linux kernel in version 6.12 (November 2024), this project benefits from that directly. It acts on three levels: converting kernel spinlocks into preemptible rt_mutex with priority inheritance, converting softirqs into schedulable threads, and threaded interrupt handlers (each IRQ becomes an individually schedulable thread with its own priority, which is what lets the next chapter give the PPS IRQ a SCHED_FIFO 99 priority, the highest possible).