🔗Building the Raspberry Pi Kernel from Source
“From source?” you say. “But Tristan, we can totally just build a module as long as we have the headers.” Yes, yes. That’s true. But we’re on a learnin’ adventure here today, so we’re going to start by building the kernel from source. Plus, building the kernel from source and then building kernel modules off of that is a great way to ensure the module is compiled against the same version as the kernel is running, which is Very Important.
First, I clone the sources and run a build, to make sure I have everything I need.
We need to make the config file that controls the kernel build process. Because we’re doing this on my (much more capable) machine instead of on the target, we include some extra parameters to specify how to cross-compile.
KERNEL=kernel
I put my laptop into “High performace” mode for whatever that does and run the following:
Now it’s time to deploy our changes. Plug in that SD card and let’s get down to it. This step is a little involved, so I wrote up a script to do it for me.
deploy.sh
:
#!/usr/bin/env bash
DESTINATION_ROOT="/media/tristan/rootfs"
DESTINATION_BOOT="/media/tristan/boot"
KERNEL=""
if !
then
fi
if !
then
fi
# Install kernel modules to SD card
# Backup old img
# Install new kernel and device tree files
Now we’ll slide that SD card in the Pi Zero W and boot ‘er up.
Success! It still boots. That’s good news. Now let’s make some oh-so-satisfying changes.
🔗Let’s Make a Kernel Module
These first few “learning” modules won’t do anything serious, so I don’t feel inclined to put them in their own git repo(s). Instead, let’s make a new git branch and a new directory in the kernel repo.
Then, let’s add our beginners’ kernel module and a Makefile. As you can see, I am a fan of silly messages for test printouts. It makes it more fun.
Now for helloworld.c
:
;
static int
static void
;
;
And the Makefile:
CR_C := KERNEL_DIR :=
obj-m +=
:
:
The Makefile has two targets: all
and clean
. Let me break down the make
commands for you.
ARCH=arm
sets the architecture to arm. Important for cross-compiling.CROSS_COMPILER=$(CR_C)
: Sets the cross-compiler binary prefix. Whenmake
callsgcc
now, it will callarm-linux-gnueabihf-gcc
instead.-C $(KERNEL_DIR)
: This hasmake
change directory toKERNEL_DIR
before it does anything else. We do this so all the headers and other kernel-ly goodness is in place before we make.M=$(shell pwd)
This sets the variableM
, which is typically used in kernel Makefiles to represent the directory of an external module to build.modules
: The actual target to build. All the logic for how this is executed is defined in the main kernel Makefile.
So now we have a bunch of files in our custom_modules
directory. Let’s copy one over to our Raspberry Pi Zero W and load it up to see the fruits of our labor! We need to copy it to somewhere in /lib/modules/
Now we’ll run some commands on the Pi Zero. First we copy the kernel module to an appropriate directory. Then, we’ll run depmod
and modprobe
, to load our module into the kernel. Then, we’ll check to make sure it’s loaded with lsmod
. Finally, we look at the message we wanted our module to print using journalctl
.
On the Pi:
|
There it is! That’s our message. When we unload the module, we will see the other message as well. That was a lot of fun! Tune in next time for a less trivial kernel module as we work our way towards building drivers.