# Build Linux Kernel Image for Raspberry Pi from Source [Ubuntu Server] ###### tags: `linux2021 jserv 1-on-1` # Raspberry Pi Ubuntu server ## [Steps](https://askubuntu.com/questions/1238261/customizing-the-kernel-arm64-using-ubuntu-20-04-lts-on-a-raspberry-pi-4) * [Official debian build doc](https://wiki.ubuntu.com/Kernel/BuildYourOwnKernel) * Since we are using ubuntu (which has the debian build system), the way to build for Desktop and raspberry pi is the same * Install cross compiler (if you want to cross compile) * `sudo apt install crossbuild-essential-arm64` * if you just want the compiler, `sudo apt install gcc-aarch64-linux-gnu` should be enough * you can also get the compiler [here](https://github.com/DLTcollab/toolchain-arm) * install `git-lfs` (since the file is too large, you need to use [git lfs](https://www.atlassian.com/git/tutorials/git-lfs) to pull the files) * extact by `tar -xvJf [filename]` * add `export PATH=$PATH:/home/henry/toolchain-arm/gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu/bin` to you `bashrc` file * Export env variables ``` export CC=aarch64-linux-gnu-gcc export $(dpkg-architecture -aarm64) export CROSS_COMPILE=aarch64-linux-gnu- ``` * Install build packages ``` sudo apt update sudo apt build-dep linux linux-image-$(uname -r) sudo apt install libncurses-dev linux-tools-common fakeroot ``` ### Using good old `make` * Get mainline source code `wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.14.tar.xz` and unzip `tar -xvJf linux-5.14.tar.xz` * Patch the kernel * (*for cacULE*) * Follow the instructions down below * During runtime, use `dmesg | grep -i "cacule cpu"` to check * [Building from source](https://www.raspberrypi.org/documentation/computers/linux_kernel.html) * `make distclean` * patches stays, so if the patches are intended to be removed, use git * `make ARCH=arm64 CROSS_COMPILE=aarch64-none-linux-gnu- defconfig` * Make sure your `CROSS_COMPILE` name is set according to your compiler invocation prefix! * `sed -i 's/CONFIG_LOCALVERSION_AUTO=y/CONFIG_LOCALVERSION_AUTO=n/' .config` * In `.config` and search for `CONFIG_LOCALVERSION_AUTO=y` -> change it to `CONFIG_LOCALVERSION_AUTO=n` * Disable adding `-gxxxx` string to the end of the uname. [Source](https://unix.stackexchange.com/questions/194129/linux-kernel-version-suffix-config-localversion) * This will affect if the deb file can proper trigger the `/etc/kernel`'s post installation script to properly configure the boot loader. [Source](https://askubuntu.com/questions/1207467/raspberry-pi-4-custom-kernel-will-not-install-in-ubuntu-19-10) * You can use `dpkg -x [deb package name]` to see the run scripts! * `time make ARCH=arm64 CROSS_COMPILE=aarch64-none-linux-gnu- LOCALVERSION="-cfs-raspi" -j$(nproc) deb-pkg` * Make sure your `LOCALVERSION` is set accordingly * make sure your `CROSS_COMPILE` name is set according to your compiler invocation prefix! * `LOCALVERSION` can only be lower case * start with `-` is recommended, otherwise the name will follow directly behind the numeric version number with separation * ending with `-raspi` is required for the auto installation to work (as mentioned above) * Use `bindeb-pkg` to [build just binary package](https://patchwork.kernel.org/project/linux-kbuild/patch/1432804275-13187-3-git-send-email-riku.voipio@linaro.org/) * Remove is done using `sudo apt autoremove --purge linux-image-5.14.0-cfs-raspi linux-headers-5.14.0-cfs-raspi` * `sudo apt list --installed | grep "linux*"` * Make sure a backup kernel is reinstalled tso the reboot will work * `sudo apt install linux-image-5.4.0-1042-raspi` #### All-in-one build command ```bash make distclean make ARCH=arm64 CROSS_COMPILE=aarch64-none-linux-gnu- defconfig # run the cacULE script here is required sed -i 's/CONFIG_LOCALVERSION_AUTO=y/CONFIG_LOCALVERSION_AUTO=n/' .config # to avoid the random string time make ARCH=arm64 CROSS_COMPILE=aarch64-none-linux-gnu- LOCALVERSION="-cfs-raspi" -j$(nproc) deb-pkg # notice the lowercase restriction on LOCALVERSION (and the -raspi ending) ``` ### For Raspberry Pi 5.4 kernel - using debian `debian/rules` tool * Get the ubuntu linux for raspberry pi's kernel source code (kenrle version will be 5.4) ``` mkdir ~/kbuild cd ~/kbuild git clone --depth=1 git://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux-raspi/+git/focal ``` * (*Only when you compile natively on raspberry pi*) uncomment the following 2 lines in `/etc/apt/sources.list` so you can fetch the source with `sudo apt-get source linux-image-unsigned-$(uname -r)` * `deb-src http://ports.ubuntu.com/ubuntu-ports focal main restricted` * `deb-src http://ports.ubuntu.com/ubuntu-ports focal-updates main restricted` * Patch the kernel * Follow the instructions down below * Building (on rpi, from scratch: ~200min, creates 7 .deb files in ~/kbuild) * Customizing uname * (*doesn't work, unfortunately*) `fakeroot debian/rules editconfigs` * [Update kernel name](https://stackoverflow.com/questions/28684811/how-to-change-version-string-of-the-kernel) -> `General Setup -> Local version - append to kernel release` * If you check the build rule, it will tell you that this move will break the module generation script (you can try it yourself!) * Update `debian.raspi/changelog` with things like `+CFS` ``` In order to make your kernel "newer" than the stock Ubuntu kernel from which you are based you should add a local version modifier. Add something like "+test1" to the end of the first version number in the debian.master/changelog file, before building. This will help identify your kernel when running as it also appears in uname -a. Note that when a new Ubuntu kernel is released that will be newer than your kernel (which needs regenerating), so care is needed when upgrading. NOTE: do not attempt to use CONFIG_LOCALVERSION as this _will_ break the build. ``` * `time fakeroot debian/rules clean` * `time fakeroot debian/rules binary-headers binary binary-perarch` * cacULE patch will have changes in the config file, that you will need to respond to during compilation if would haven't run `fakeroot debian/rules editconfigs` before building from source * Replacing the kernel ``` # sudo apt install libunwind8 linux-tools-common libdw1 sudo dpkg -i *.deb sync; sudo reboot ``` * Re-compile * `time fakeroot debian/rules binary binary-perarch binary-headers` * If `time fakeroot debian/rules clean` is run (e.g. kernel version changes) * Use git to clean up * `git clean -df` * `git reset --hard HEAD` * Use `rm` to clean up ``` rm debian/stamps/stamp-build* rm -rf debian/linux-libc-dev/usr/include/aarch64-linux-gnu rm -rf debian/build/build-raspi/_____________________________________________dkms ``` ## Changing kernel on Raspberry pi * Since the installed version might be older than the current one, it might fail some how. So we have to [remove the current kernel and then reinstall the new one](https://askubuntu.com/questions/1316409/what-is-the-correct-way-to-select-an-older-installed-kernel-on-pi) ``` # getting rid of auto-updated kernel # review installed kernels apt list "linux-image*raspi" # get detail on an installed kernel apt show linux-image-5.4.0-1041-raspi # remove the "wrong" new version # NOTE YOU WILL GET A WARNING ABOUT REMOVING THE BOOT KERNEL (make sure you select NO lol, basically READ CAREFULLY on what the prmopt says) sudo apt autoremove --purge linux-image-5.4.0-1041-raspi # DO NOT REBOOT # cd to location of my compiled kernel .deb files # reference: kernel compile for ubuntu on pi # https://askubuntu.com/questions/1238261/customizing-the-kernel-arm64-using-ubuntu-20-04-lts-on-a-raspberry-pi-4 cd ~/kbuild # install my previously compiled custom kernel as per instruction for installing a newly compiled or recompiled kernel: sudo dpkg -i *.deb && sync sudo reboot # put my kernel on "hold" status to prevent auto-update echo "linux-image-5.4.0-1041-raspi hold" | sudo dpkg --set-selections # review dpkg status setting for linux-image: dpkg --get-selections | grep "linux-image" ``` ### Issues * `rmdir: failed to remove '/lib/modules/5.4.0-1042-raspi': Directory not empty` * For some reason, it just can't, and **don't do it yourself, since it will break your device's ability to boot again**. See [this issue](https://answers.launchpad.net/ubuntu/+question/37009). # Patch * (*for cacULE*) * `wget https://raw.githubusercontent.com/hamadmarri/cacule-cpu-scheduler/master/patches/CacULE/v5.14/cacule-5.14.patch` * `wget https://raw.githubusercontent.com/hamadmarri/cacule-cpu-scheduler/master/scripts/apply_suggested_configs.sh` * `patch -p1 < cacule-5.14.patch` * ignore 1 level of depth * `patch` and `git am` is might produce different results * 3-way merge * (*for muQSS*): 5.12 is the last version that muQSS has patch for * patch * several errors to resolve * https://github.com/zen-kernel/zen-kernel/commit/59473b1177948ea41df9340c9010ab958008c880 * https://github.com/zen-kernel/zen-kernel/blob/5.13/master/kernel/sched/MuQSS.c * http://ck-hack.blogspot.com/2019/11/linux-54-ck1-muqss-version-0196-for.html * http://ck-hack.blogspot.com/2019/11/linux-54-ck1-muqss-version-0196-for.html # For Raspbian ```bash make distclean KERNEL=kernel8 make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcm2711_defconfig time make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc) Image modules dtbs sudo env PATH=$PATH make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- INSTALL_MOD_PATH=/media/home-tw/rootfs modules_install sudo cp /media/home-tw/boot/$KERNEL.img /media/home-tw/boot/$KERNEL-backup.img sudo cp arch/arm64/boot/Image /media/home-tw/boot/$KERNEL.img sudo cp arch/arm64/boot/dts/broadcom/*.dtb /media/home-tw/boot/ sudo cp arch/arm64/boot/dts/overlays/*.dtb* /media/home-tw/boot/overlays/ sudo cp arch/arm64/boot/dts/overlays/README /media/home-tw/boot/overlays/ ``` # Deprecated stuff ## Replacing the kernel When the kernel is not properly ended with `-raspi`, the installation will need to pretty manual -> installation is fine, more like the removal will be pain in the ass * install deb `sudo dpkg -i *.deb` * `sudo flash-kernel 5.14.0-00577-g46f4945e2b39` * ~~`cp arch/arm64/boot/dts/broadcom/*.dtb /boot/overlays`~~ * go to `/boot`, and manually change the soft links of `vmlinux` and `initrd.img`, also in the `firmware` folder, replace those to files * [update `/boot`](https://wiki.ubuntu.com/ARM/RaspberryPi)