Building the Linux Kernel for Raspberry Pi 5

Building the Linux Kernel for Raspberry Pi 5

The Raspberry Pi 5, powered by the Broadcom BCM2712 (quad-core Cortex-A76 at 2.4GHz), represents a significant leap in ARM SBC performance. Building a custom kernel unlocks hardware-specific optimizations, debugging capabilities, and the ability to patch or extend kernel functionality.

This guide covers cross-compilation from an x86_64 host, kernel configuration for debugging, and deployment to a running Pi 5.

Hardware Context

The BCM2712 SoC features:

  • CPU: Quad Cortex-A76 (ARMv8.2-A) @ 2.4GHz
  • GPU: VideoCore VII
  • PCIe: Gen 2.0 x1 (exposed via RP1 southbridge)
  • Memory: LPDDR4X (4GB/8GB variants)

The RP1 southbridge is a new addition that handles GPIO, USB, Ethernet, and other I/O—requiring specific kernel support via rp1 drivers.

Development Environment Setup

Cross-Compilation Toolchain

Cross-compiling on an x86_64 host is significantly faster than native compilation on the Pi.

# Debian/Ubuntu - Install ARM64 cross-compiler
sudo apt update
sudo apt install -y \
    crossbuild-essential-arm64 \
    gcc-aarch64-linux-gnu \
    binutils-aarch64-linux-gnu \
    libncurses-dev \
    bison \
    flex \
    libssl-dev \
    libelf-dev \
    bc \
    git \
    make

# Verify toolchain
aarch64-linux-gnu-gcc --version

Kernel Source

The Raspberry Pi Foundation maintains a fork with BCM2712 and RP1 support:

# Clone the Pi kernel (use depth=1 for faster clone)
git clone --depth=1 --branch rpi-6.6.y \
    https://github.com/raspberrypi/linux.git rpi-linux
cd rpi-linux

# Check available Pi 5 branches
git branch -r | grep rpi-6

The rpi-6.6.y branch is the current LTS with full Pi 5 support. For bleeding-edge features, use rpi-6.8.y or later.

Kernel Configuration

Base Configuration for Pi 5

Start with the official Pi 5 defconfig:

# Set cross-compile environment
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-

# Generate Pi 5 default config
make bcm2712_defconfig

# View the generated config
head -50 .config

The bcm2712_defconfig enables:

  • BCM2712 SoC support
  • RP1 southbridge drivers
  • VideoCore VII GPU
  • PCIe controller
  • LPDDR4X memory controller

Interactive Configuration

make menuconfig

Navigate using arrow keys, Enter to select, Space to toggle. Key sections:

General Setup

General setup --->
    [*] Kernel .config support
    [*]   Enable access to .config through /proc/config.gz
    (-rpi5-custom) Local version - append to kernel release

Processor Features

Kernel Features --->
    Preemption Model (Voluntary Kernel Preemption)  --->
        (X) Preemptible Kernel (Low-Latency Desktop)
    Timer frequency (1000 HZ)  --->

For real-time workloads, enable PREEMPT_RT if available in your branch.

Debug Configuration

Kernel debugging is essential for driver development and crash analysis.

Enable Core Debug Options

# Apply debug config fragment
cat >> .config << 'EOF'
# Debug Information
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_INFO_DWARF5=y
CONFIG_DEBUG_INFO_BTF=y
CONFIG_GDB_SCRIPTS=y

# Kernel Address Sanitizer (KASAN)
CONFIG_KASAN=y
CONFIG_KASAN_GENERIC=y
CONFIG_KASAN_INLINE=y

# Lock Debugging
CONFIG_DEBUG_SPINLOCK=y
CONFIG_DEBUG_MUTEXES=y
CONFIG_DEBUG_LOCK_ALLOC=y
CONFIG_PROVE_LOCKING=y
CONFIG_LOCKDEP=y

# Memory Debugging
CONFIG_DEBUG_SLAB=y
CONFIG_DEBUG_VM=y
CONFIG_DEBUG_MEMORY_INIT=y

# Stack Protection
CONFIG_STACKPROTECTOR=y
CONFIG_STACKPROTECTOR_STRONG=y

# Function Tracing
CONFIG_FTRACE=y
CONFIG_FUNCTION_TRACER=y
CONFIG_FUNCTION_GRAPH_TRACER=y
CONFIG_DYNAMIC_FTRACE=y
CONFIG_STACK_TRACER=y

# Kernel Crash Dumps
CONFIG_KEXEC=y
CONFIG_CRASH_DUMP=y

# Magic SysRq (emergency debugging)
CONFIG_MAGIC_SYSRQ=y
CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
EOF

# Merge and validate config
make olddefconfig

KGDB: Kernel Debugger

Enable remote debugging via serial:

cat >> .config << 'EOF'
# KGDB Configuration
CONFIG_KGDB=y
CONFIG_KGDB_SERIAL_CONSOLE=y
CONFIG_KGDB_KDB=y
CONFIG_KDB_KEYBOARD=y
CONFIG_FRAME_POINTER=y
EOF

make olddefconfig

Boot parameters for KGDB:

kgdboc=ttyAMA0,115200 kgdbwait

Kernel Symbols and Kallsyms

# Ensure symbol table is included
scripts/config --enable CONFIG_KALLSYMS
scripts/config --enable CONFIG_KALLSYMS_ALL

This enables /proc/kallsyms for symbol resolution in crash dumps and tracing.

Cross-Compilation

Build the Kernel

# Set environment (if not already set)
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-

# Clean build (optional, use for fresh builds)
make mrproper
make bcm2712_defconfig

# Build with parallel jobs
make -j$(nproc) Image.gz modules dtbs

# Build time: ~15-30 min on modern 8-core x86_64

Build artifacts:

  • arch/arm64/boot/Image.gz - Compressed kernel image
  • arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dtb - Device Tree Blob

Inspect Build Output

# Check kernel version
file arch/arm64/boot/Image.gz

# List built modules
find . -name "*.ko" | wc -l

# Verify DTB
fdtdump arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dtb | head -30

Deployment to Raspberry Pi 5

Prepare the Target

On the Pi 5, ensure SSH is enabled and note the boot partition:

# On the Pi - check current kernel
uname -r

# Identify boot partition (usually /boot/firmware on Bookworm)
mount | grep boot
ls /boot/firmware/

Install Modules

# On build host - create module staging directory
export INSTALL_MOD_PATH=./modules_install
make modules_install

# Package for transfer
tar czf modules.tar.gz -C modules_install lib

# Transfer to Pi
scp modules.tar.gz pi@raspberrypi.local:/tmp/

On the Pi:

# Backup existing modules
sudo cp -r /lib/modules/$(uname -r) /lib/modules/$(uname -r).bak

# Extract new modules
sudo tar xzf /tmp/modules.tar.gz -C /

Install Kernel and DTBs

From build host:

# Copy kernel
scp arch/arm64/boot/Image.gz pi@raspberrypi.local:/tmp/kernel8.img

# Copy DTBs
scp arch/arm64/boot/dts/broadcom/bcm2712*.dtb pi@raspberrypi.local:/tmp/

On the Pi:

# Backup current kernel
sudo cp /boot/firmware/kernel8.img /boot/firmware/kernel8.img.bak

# Install new kernel
sudo cp /tmp/kernel8.img /boot/firmware/kernel8.img

# Install DTBs
sudo cp /tmp/bcm2712*.dtb /boot/firmware/

# Update config.txt if needed
sudo nano /boot/firmware/config.txt

Ensure config.txt contains:

[pi5]
kernel=kernel8.img
arm_64bit=1

Reboot and Verify

sudo reboot

# After reboot
uname -r
# Should show: 6.6.x-rpi5-custom (or your local version string)

# Verify debug features
cat /proc/config.gz | gunzip | grep CONFIG_DEBUG_INFO

Using Debug Features

Function Tracer (ftrace)

# Mount debugfs if not mounted
sudo mount -t debugfs none /sys/kernel/debug

# Enable function tracing
cd /sys/kernel/debug/tracing
echo function > current_tracer
echo 1 > tracing_on

# Trace specific functions
echo 'bcm2712*' > set_ftrace_filter
cat trace

# Disable
echo 0 > tracing_on

KASAN Reports

When KASAN detects a memory error, it logs detailed reports to dmesg:

dmesg | grep -A20 "KASAN"

Example output:

BUG: KASAN: slab-out-of-bounds in some_function+0x42/0x100
Read of size 4 at addr ffff000012345678 by task test/1234

Kernel Crash Analysis

If the kernel panics, use crash tool with vmlinux:

# On build host - keep vmlinux for debugging
cp vmlinux /safe/location/vmlinux-$(make kernelrelease)

# Analyze crash dump
crash vmlinux /var/crash/vmcore

Performance Tuning Options

For production kernels, disable debug options and enable:

# Performance-oriented config
scripts/config --disable CONFIG_DEBUG_INFO
scripts/config --disable CONFIG_KASAN
scripts/config --enable CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE

# CPU frequency scaling
scripts/config --enable CONFIG_CPU_FREQ_GOV_PERFORMANCE
scripts/config --enable CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE

# Memory optimization
scripts/config --enable CONFIG_TRANSPARENT_HUGEPAGE
scripts/config --enable CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS

make olddefconfig

Troubleshooting

Boot Failures

If the Pi doesn't boot:

  1. Connect HDMI to see early boot messages
  2. Use serial console (GPIO 14/15 for UART)
  3. Restore backup kernel:
# From another machine, mount the SD card
sudo cp /mnt/boot/kernel8.img.bak /mnt/boot/kernel8.img

Missing Modules

If modules fail to load:

# Check module dependencies
depmod -a $(uname -r)

# Verify module path
ls /lib/modules/$(uname -r)/

Device Tree Issues

If hardware isn't detected:

# Check loaded DTB
cat /proc/device-tree/model

# Compare with expected
dtc -I fs /proc/device-tree | grep compatible

Automation Script

Save this as build-pi5-kernel.sh:

#!/bin/bash
set -e

KERNEL_DIR="${1:-rpi-linux}"
PI_HOST="${2:-raspberrypi.local}"

export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-

cd "$KERNEL_DIR"

echo "Building kernel..."
make -j$(nproc) Image.gz modules dtbs

echo "Installing modules locally..."
rm -rf ../modules_install
make INSTALL_MOD_PATH=../modules_install modules_install

echo "Packaging..."
tar czf ../kernel-package.tar.gz \
    arch/arm64/boot/Image.gz \
    arch/arm64/boot/dts/broadcom/bcm2712*.dtb \
    -C ../modules_install lib

echo "Deploying to $PI_HOST..."
scp ../kernel-package.tar.gz pi@$PI_HOST:/tmp/

ssh pi@$PI_HOST << 'REMOTE'
    sudo cp /boot/firmware/kernel8.img /boot/firmware/kernel8.img.bak
    cd /tmp && tar xzf kernel-package.tar.gz
    sudo cp Image.gz /boot/firmware/kernel8.img
    sudo cp bcm2712*.dtb /boot/firmware/
    sudo tar xzf kernel-package.tar.gz -C / lib
    sudo depmod -a
    echo "Kernel deployed. Reboot to activate."
REMOTE

echo "Done!"

Conclusion

Building a custom kernel for the Raspberry Pi 5 enables debugging capabilities unavailable in stock kernels, hardware-specific optimizations, and the foundation for driver development.

Key takeaways:

  • Use bcm2712_defconfig as the starting point
  • Enable KASAN, LOCKDEP, and ftrace for debugging
  • Cross-compile for faster iteration
  • Always keep backup kernels

Combined with kernel patching techniques, you can contribute fixes back to the Raspberry Pi kernel tree or the mainline Linux kernel.

Happy hacking!

← Back to Blog