Raspberry Pi 5 cross compile environment setup for building drivers

Raspberry Pi 5 Cross-Compile Environment Setup & Driver Development

This guide details how to set up a cross-compilation environment on an x86 Ubuntu host to build Linux kernel modules (drivers) for the Raspberry Pi 5 (ARM64).

Part 1: The Concepts

What is Cross-Compiling?

Cross-compiling is the process of creating executable code for a platform (the target) other than the one on which the compiler is running (the host).

In this scenario:
Host: Your powerful Ubuntu Computer (x86_64 architecture).
Target: Raspberry Pi 5 (ARM64/aarch64 architecture).

What you need

To succeed, you need four key components on your Host computer:

  1. Toolchain: The compiler (gcc), linker (ld), and other tools capable of generating ARM64 code.

  2. Build System: Usually make.

  3. Kernel Source Code: The specific Linux kernel source for the Raspberry Pi.

  4. Target Configuration:

    • Architecture: arm64

    • Triple: aarch64-linux-gnu- (Arch: 64-bit ARM, OS: Linux, ABI: GNU).

Part 2: Host Computer Setup

1. Install Dependencies & Toolchain

First, install the necessary build tools and the cross-compiler on your Ubuntu host.
$sudo apt update 
# Install build dependencies 
$sudo apt install bc bison flex libssl-dev make libc6-dev libncurses5-dev git 
 # Install the ARM64 cross-compilation toolchain 
$sudo apt install crossbuild-essential-arm64

2. Download Kernel Source

Clone the official Raspberry Pi Linux kernel. 
# Clone the repository- github. (this may take a while) 
$git clone --depth=1 https://github.com/raspberrypi/linux 
$cd linux

3. Configure and Build the Kernel

# 1. Set environment variables for Cross-Compilation
$export ARCH=arm64 
$export CROSS_COMPILE=aarch64-linux-gnu- 
# specific naming for your kernel version 
$export KERNEL=kernel_2712 
# 2. Generate the default configuration for Pi 5 (BCM2712) 
$make bcm2712_defconfig 
# 3. Build the Kernel, Modules, and Device Tree Blobs (DTBs)
# -j12 uses 12 CPU cores to speed up the build 
$make -j12 Image modules dtbs

4. Install the Kernel Modules, Kernel and Device Tree blobs

# Assume SD card partitions are mounted at mnt/boot and mnt/root
# 1. Install Kernel Modules to the SD card root filesystem
$sudo env PATH=$PATH make -j12 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- INSTALL_MOD_PATH=mnt/root modules_install
# 2. Install Kernel Image and Device Trees to the SD card boot partition
$sudo cp mnt/boot/$KERNEL.img mnt/boot/$KERNEL-backup.img
$sudo cp arch/arm64/boot/Image mnt/boot/$KERNEL.img
$sudo cp arch/arm64/boot/dts/broadcom/*.dtb mnt/boot/
$sudo cp arch/arm64/boot/dts/overlays/*.dtb* mnt/boot/overlays/
$sudo cp arch/arm64/boot/dts/overlays/README mnt/boot/overlays/
# 3. Unmount safely
$sudo umount mnt/boot
$sudo umount mnt/root

Part 3: Writing the "Hello World" Driver

Now that the environment is ready, let's write the driver on the Host Computer.

1. Create a file named helloworld.c

$vi hellowrold.c 

#include <linux/module.h>
#include <linux/init.h>

MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Linda");
MODULE_DESCRIPTION("Simple insert/remove helloworld driver without any other function");

static int helloworld_init(void)
{
        printk(KERN_ALERT "helloworld driver insert\n");
        return 0;
}
static void helloworld_exit(void)
{
        printk(KERN_ALERT "helloworld driver remove\n");
}

module_init(helloworld_init);
module_exit(helloworld_exit);

2. Create a file named Makefile

// create Makefile that tell make how to compile helloworld.ko (driver module)
$vi Makefile  

KDIR = /home/linda/fun/RB_Pi5/linux/   //the raspberry kernel source location

obj-m += helloworld.o
all:
        make -C $(KDIR) M=$(PWD) ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- modules

clean:
        make -C $(KDIR) M=$(PWD) clean

3. Compile

$make

4. Verify

This is the most common reason for failure. The "Version Magic" of your module must match the running kernel on the Pi.

//kernel header information have to be the same as the kernel you used to compile 
$modinfo helloworld.ko |grep vermagic
vermagic:       6.12.66-v8-16k+ SMP preempt mod_unload modversions aarch64     

Part 4: Testing on Raspberry Pi 5

1. Transfer the Driver

Copy the .ko file from Host to Target (Pi).
$scp helloworld.ko   linda@10.12.xx.xxx:/home/linda/

2. Boot the Pi

If you installed the new kernel in Part 2, verify it is running:
$uname -r
6.12.66-v8-16k+ //this have to be the same as the driver that will be build

3. Load the Module

# Insert the module
$sudo insmod helloworld.ko 
# Check the kernel log
$dmesg | tail
[  374.518816] helloworld driver insert

4. Unload the Module

# Remove the module
$sudo rmmod helloworld.ko 
# Check the kernel log
$dmesg | tail
[  477.965475] helloworld driver remove

Summary

Linux drivers have a specific lifecycle managed by the kernel.
  • insmod: Triggers the module_init function.
  • rmmod: Triggers the module_exit function.
  • dmesg: Shows the printk output (Kernel logs).




 

Comments