This environment can be used to cross-compile the Raspberry Pi OS kernel from a Linux, Windows, or Mac workstation using Docker.
This build configuration has only been tested with the Raspberry Pi 4, CM4, and Pi 400, and run on macOS.
Modified from Jeff Geerling's cross-compile environment
-
Install Podman (and podman-compose).
-
Bring up the cross-compile environment:
podman-compose up -d
-
Log into the running container:
podman attach cross-compile
You will be dropped into a shell inside the container's /build
directory. From here you can work on compiling the kernel.
Note
After you exit
out of that shell, the container will stop, but will not be removed. If you want to jump back into it, you can run podman start -a cross-compile
.
-
Clone the linux repo (or clone a fork or a different branch):
git clone --depth=1 https://github.com/raspberrypi/linux
-
Run the following commands to make the .config file:
cd linux make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcm2711_defconfig
-
(Optionally) Either edit the .config file by hand or use menuconfig:
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig
-
Compile the Kernel:
make -j8 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- Image modules dtbs
Note
For 32-bit Pi OS, use ARCH=arm
, CROSS_COMPILE=arm-linux-gnueabihf-
, and zImage
instead of Image
.
Tip
I set the jobs argument (-j8
) based on a bit of benchmarking. For different types of processors you may want to use more (or fewer) jobs depending on architecture and how many cores you have.
-
mount container file system to host (prints mount location):
podman mount cross-compile
Note
if running podman in rootless mode, run podman unshare
first.
The best option is to use the Automated script. Within the container, run the command:
PI_ADDRESS=10.0.100.170 copykernel
Note
Change the PI_ADDRESS
here to the IP address of the Pi you're managing.
The script will reboot Pi, and once rebooted, your new kernel should be in place!
Or, if you want to run the process manually, run:
mkdir -p /mnt/pi-ext4
mkdir -p /mnt/pi-fat32
sshfs root@10.0.100.119:/ /mnt/pi-ext4
sshfs root@10.0.100.119:/boot /mnt/pi-fat32
Install all the kernel modules:
env PATH=$PATH make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- INSTALL_MOD_PATH=/mnt/pi-ext4 modules_install
Copy the kernel and DTBs onto the drive:
cp arch/arm64/boot/Image /mnt/pi-fat32/kernel8.img
cp arch/arm64/boot/dts/broadcom/*.dtb /mnt/pi-fat32/
cp arch/arm64/boot/dts/overlays/*.dtb* /mnt/pi-fat32/overlays/
cp arch/arm64/boot/dts/overlays/README /mnt/pi-fat32/overlays/
Unmount the filesystems:
umount /mnt/pi-ext4
umount /mnt/pi-fat32
Reboot the Pi and voila!, you're done!
Note
For 32-bit Pi OS, use ARCH=arm
, CROSS_COMPILE=arm-linux-gnueabihf-
, zImage
instead of Image
, kernel7l
instead of kernel8
, and arm
instead of arm64
.
If you get a fatal kernel panic that doesn't get caught cleanly (which I do, quite often, when debugging PCI Express devices), you can quickly reset the CM4 IO Board by jumping pins 12 and 14 on J2 (GLOBAL_EN
to GND
).
You can also 'boot' a shutdown CM4 by jumping pins 13 and 14 on J2 (GLOBAL_EN
to RUN_PG
).
If you also need the kernel headers and source available, you can do the following (before unmounting the filesystems):
# Get the kernel version (usually the last in the listing):
sudo ls -lah /mnt/pi-ext4/lib/modules
# Create a directory and copy the sources into it:
sudo mkdir /mnt/pi-ext4/usr/src/linux-headers-5.10.14-v8+
sudo rsync -avz --exclude .git /home/vagrant/linux/ root@10.0.100.119:/usr/src/linux-headers-5.10.14-v8+
# Update the symlinks in the modules directory on the Pi:
sudo rm -rf /mnt/pi-ext4/lib/modules/5.10.14-v8+/build
sudo rm -rf /mnt/pi-ext4/lib/modules/5.10.14-v8+/source
sudo ln -s /usr/src/linux-headers-5.10.14-v8+ /mnt/pi-ext4/lib/modules/5.10.14-v8+/build
sudo ln -s /usr/src/linux-headers-5.10.14-v8+ /mnt/pi-ext4/lib/modules/5.10.14-v8+/source
This is sometimes necessary if you're compiling modules on the Pi that require kernel headers.
Note
This... doesn't work. I opened this issue to see if I could figure out the way: Getting headers for custom cross-compiled kernel?.
The other option is to shut down the Pi, pull it's card or USB boot drive, and connect it to your computer so it can attach to the VM.
Mount the FAT and ext4 partitions of the USB card to the system. First, insert your microSD card into the reader you attached to the VM earlier, then run the following commands:
mkdir -p mnt/fat32
mkdir -p mnt/ext4
sudo mount /dev/sdb1 mnt/fat32
sudo mount /dev/sdb2 mnt/ext4
Copy the kernel and DTBs onto the drive:
sudo cp arch/arm64/boot/Image mnt/fat32/kernel8.img
sudo cp arch/arm64/boot/dts/broadcom/*.dtb mnt/fat32/
sudo cp arch/arm64/boot/dts/overlays/*.dtb* mnt/fat32/overlays/
sudo cp arch/arm64/boot/dts/overlays/README mnt/fat32/overlays/
Install the kernel modules onto the drive:
sudo env PATH=$PATH make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- INSTALL_MOD_PATH=mnt/ext4 modules_install
Note
For 32-bit Pi OS, use sudo env PATH=$PATH make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=mnt/ext4 modules_install
Copy the kernel and DTBs onto the drive:
sudo cp arch/arm64/boot/Image mnt/fat32/kernel8.img
sudo cp arch/arm64/boot/dts/broadcom/*.dtb mnt/fat32/
sudo cp arch/arm64/boot/dts/overlays/*.dtb* mnt/fat32/overlays/
sudo cp arch/arm64/boot/dts/overlays/README mnt/fat32/overlays/
Note
For 32-bit Pi OS, use kernel7l
instead of kernel8
.
Unmount the disk before you remove it from the card reader or unplug it.
sudo umount mnt/fat32
sudo umount mnt/ext4
If you want to reset things without wiping out the VM or re-cloning the source, run:
git reset --hard
git clean -f -d -X