So you’ve got a shiny new Raspberry Pi 4 and you need to compile a fresh and custom Linux kernel on Raspbian. You might need some features, some kernel modules, or you just want to compile the latest version from source.
I’m doing various projects (and blog posts) and with one of the projects, I found I needed to compile and enable a kernel module that wasn’t built in to the latest Raspbian image for the Pi 4.
This guide is also great if you just want to learn how to compile the kernel yourself!
Instructions
You may find that this guide is slightly different that the guide on the Raspberry Pi website and other sites. I like to append a unique name to the kernel version so I don’t have to touch the existing kernels. This allows me to revert or run multiple different custom kernels and switch back and forth.
Please note: You must be using a 32-bit kernel (or the default Raspbian kernel) to compile a new 32-bit kernel. You will not be able to compile a new kernel (32-bit or 64-bit) if you have booted in to the 64-bit kernel using the “arm_64bit=1” switch in “config.txt”. I’ve tried to compile a 64-bit kernel on Raspbian, but have not yet been able to do so. I’ll update with a new post once I figure it out.
And don’t forget, this can take some time and is CPU intensive. I installed a fan to help cool the temperatures while compilling!
This guide will compile a 32-bit kernel.
- Install some packages required to building and compiling.
apt install raspberrypi-kernel-headers build-essential bc git wget bison flex libssl-dev make libncurses-dev
- Create a directory for us to work in.
mkdir kernel
cd kernel - Clone the latest kernel sources using GIT.
git clone --depth=1 https://github.com/raspberrypi/linux
- Setup the kernel configuration for compiling.
cd linux
KERNEL=kernel7l
make bcm2711_defconfig - Make any changes you want to the kernel configuration and append a friendly local version name by using make menuconfig.
make menuconfig
To change the friendly name, navigate to “General Setup” and select/modify “Local Version – append to kernel release”.(-v7lstephen) Local version - append to kernel release
- Compile the kernel, modules, and device tree blobs.
make -j4 zImage modules dtbs
- Install compiled modules.
make modules_install
- Copy the kernel, modules, and other files to the boot filesystem.
cp arch/arm/boot/dts/*.dtb /boot/
cp arch/arm/boot/dts/overlays/*.dtb* /boot/overlays/
cp arch/arm/boot/dts/overlays/README /boot/overlays/
cp arch/arm/boot/zImage /boot/kernel-stephen.img - Configure the PI to boot using the new kernel by modifying and adding the below line to “/boot/config.txt”.
kernel=kernel-stephen.img
- Reboot!
Bam! You’re now using your shiny new Linux kernel on the Raspberry Pi 4!
To rescue a failed build or if the Pi won’t boot
If for some reason the Pi won’t boot, you can recover the previous kernel since we used a new name with the new kernel.
To rescue the image you’ll need another Linux computer that can read the Micro-SD card.
- Insert the Micro-SD Card in the computer.
- Mount the /boot/ filesystem on the Micro SD card to a local directory.
- Edit the “config.txt” file and remove the “kernel=kernel-name.img” line we made above, or alternatively comment it out by inserting a “#” before the line.
#kernel=kernel-stephen.img
- Save the file.
- Unmount the partition.
- Insert in the Raspberry Pi and boot!
You should now be back up and running and should be able to try again!
Leave some feedback and let me know if it worked for you. In the future I’ll be doing another post on compiling a 64-bit kernel for the Raspberry Pi 4 on Raspbian.
[…] running Raspbian, you need to compile a custom kernel and build the iSCSI Target Core Modules. Please follow my instructions (click here) to compile a custom kernel on Raspbian or Raspberry Pi. When you’re following my custom kernel build guide, in addition after running “make […]
Thanks for the instructions. I has to compile my own kernel to add a line to the hid-ids.h and hid-quirks.c files to get a Mayflash Sega Saturn adaptor to work on my RetroPie. For some reason following the instructions on the Raspberry Pi website didn’t work for me, but following your instructions worked great!
Hello
i am trying to disable r8152 built-in driver and compile kernel again, and following your guide step-by-step.
can you please tell me how long does it take to compile the kernel after this command ?
make -j4 zImage modules dtbs
Hi Batu,
All parts of the kernel can take an extremely long time to build. It could be many hours.
Stephen
Hey Stephen,
What sort of problems did you run into with trying to compile the 64bit kernel? I am trying to add iSCSI support to Volumio distro (based on Raspian) for my RiP4. Did you ever find a way forward and finish compiling a 64bit kernel?
Steve
Thank you for the great guide! Needed to recompile only media-tree for my USB Sat-Tv Tuner Card (to apply a patch), but messed up all sorts of things while trying to use linuxtv.org ‘s tutorial.
With your tutorial I realized that it is smarter, easier and way easier to recompile the whole Linux kernel with my patch attached, now everything is working great!
Glad the post helped!
Worked great 🙂
Now, I’m on to the iscsi target tutorial that you made.
Thanks a bunch.
Regards,
Jim
Jim! I’m glad to hear it’s working and thanks for leaving a comment! 🙂
Hi. Question for you.
We make a Kernel Pack (as we call it) which is for our products, which supports all of the Raspberry Pi’s, So Pi1, Pi2/Pi3, Pi4 and the 64bit one. After building the kernels all to the same folders, we tar.gz them up and distribute, and then our customers untar over top of their install (provided kernel versions match etc) and they are off and away.
Is there a way to do the above process (we actually do cross compile – but same difference) where you don’t have to do menuconfig each time?
We enable a few of our own modules, and disable 1 default module in menuconfig. Have to do this each time for each kernel before rebuild the kernel, so we have to do the same things in menuconfig 4 times.
Is there a way this can be done only a single time?
Would save a bunch of manual work, as the changes in Menuconfig are identical for each one.
Thanks
Hi James,
When “make manuconfig” is ran, it generates a “.config” file for the kernel source.
If you were to save and copy this, and the copy it back on other systems, you wouldn’t need to run the “make menuconfig”, and it would use that file.
Hope that helps!
Cheers,
Stephen
Thanks Stephen, but not exactly what I was asking. Saving the Config is all fine and good, its not about doing it on multiple machines, its about doing it for the 4 different Pi kernels, and then doing the same again when an update happens to the OS or the Kernels. The first part is having to do Menuconfig for Pi1, then Pi2/3 and then Pi4 and then the 64bit one. That is 4 times. Then in a few weeks or so when an update happens, we have to repeat the process. Simply copying the config I dont think will be good enough, as if the update added something new, then our config would exclude that.
I was trying to find a way if we can do the menuconfig once, which covers all Pi1/Pi2/Pi3/Pi4/64bit in one hit, and then each time there is an update, do something which only modifies the default settings in menuconfig to suit the changes we want (enabling 2 new things, making modules of 3 new things, and disabling one default thing).
Thank you for your helpful & detail document. I successfully built my own kernel.
Why are some drivers not compiled, when compiling the kernel? I am looking for the driver for the OV2740 Mipi-Camera (https://github.com/raspberrypi/linux/blob/rpi-5.15.y/drivers/media/i2c/ov2740.c).
When compiling the kernel, there is a default list of drivers that are built in to the kernel, or as modules. If you need to add driver support, you’ll need to enable the driver you’d like to be built in to the kernel, or as a kernel module.
Once turning the switch on for it, you should be able to build it.
Cheers,
Stephen
Thanks for your reply. Unfortunately, this was not the case for the OV2740. The detailed explenation is in this issue:
https://github.com/raspberrypi/linux/issues/5170
According to that link, it appears that driver isn’t compatible with the Raspberry Pi.
Hi Stephen, excellent tutorial!
I just wondering current Kernel version is 5.15.68, how could I compile 5.14.21-v7 version?
Thanks, Archie
Hi Archie,
I think there’s a way to clone a specific source tree for a specific version when using git. I just don’t know exactly what that command is.
Hi Stephen,
Thanks for those very succinct instructions, worked a treat. I have a problem though which I can’t find an answer to on Google. I added the lines CONFIG_SND_DYNAMIC_MINORS=y & CONFIG_SND_MAX_CARDS=16 in .config in order to be able to address more audio devices. That part works fine and I now have 16 entries in cat /sys/module/snd_usb_audio/parameters/index
However ALSA aconnect -l now hangs immediately 🙁 Any idea where to look please. Thanks again for such a useful post.
Hi Stephen,
I am running the latest raspbian 11 bullseye (default image from the raspberry pi imager software).
I am trying to modify the kernel to enable the i2c to hid driver as I have an i2c cap touch (as an HID) I’m trying to use for my system
.
I tried following your steps but for some reason when I enter “make -j4 zImage modules dtbs I get the following errors:
SYNC include/config/auto.conf.cmd
make: *** No rule to make target ‘zImage’. Stop.
Perhaps you can help?
@ Austin Barlis
You need to use ‘Image’ not ‘zImage
cool but can you do 64 from a raspberry pi for Debian please….