How I Shrunk the Kernel

Many developers and users of the Linux operating system sometimes look for small kernels that can boot up properly in their systems and not hamper their work.
Many embedded devices also need to be booted up using a kernel that takes minimal space and performs all the functionalities since there is a memory constraint in these devices.
The Linux kernel provides a way to customize our own kernels the way we want to. The kernel that comes with an Ubuntu installation is only 9.9 megabits. As a beginner in Linux kernel, one of my assignments in an internship was to customize the Linux kernel, bring its size down and boot it up on my machine.
When you look properly at its config file and the modules installed, though, you’ll see that most of the memory is filled with modules and object files that we do not require at all. For example, we might not require driver modules for wireless devices that we do not use.
We can exclude these types of driver modules in our kernel compilation to bring down the kernel size further.
Sometimes users or developers might also not need debugging facilities that the kernel provides. Things like debugging symbols and modules take up a lot of kernel space that can be eliminated by just disabling them.
Use of the Kernel
Although tiny kernels are mostly used in embedded devices, given their storage constraint, my customized kernel can be used on personal laptops also but with limited functionalities.
These functionalities include basic browsing, using basic Linux commands on the terminal, saving files, and seeing battery settings and time settings in broad categories.
A normal user can use it to do normal, basic tasks and also have the advantage of saving memory space.
Sophisticated tasks like debugging and using advanced Linux commands cannot be done since the modules required for those haven’t been included.
As a beginner, I did this project more to learn about the Linux kernel, its parts and how it works.
The future prospects of this project can be to modify the same specifically as per particular embedded systems or Android systems.
What Is the Benefit of a Small Kernel?
As new features were added in the Linux kernel, its size has also grown over the years. But the need for a small kernel that can do tasks, specifically for certain systems, has risen.
A tiny kernel becomes extremely useful in embedded devices, reducing power consumption, maximizing performance and reducing security concerns.
Kernel Tinyfication
For some time I have been working on trying to bring down the Linux kernel size from 9.9 MB to 3 MB and successfully boot it up on my computer with an x86_64 architecture AMD processor. I downloaded the kernel version 6.1.2 stable release.
For this customized kernel, I focused on the working of the basic functionalities
Changing a lot of options in General Setup is sometimes risky, since most of them are required for the computer to boot up. However, I have tried tinkering with some of them. For instance, I made the kernel compression mode LZMA, because its compression ratio is the best, although it is slow. Compiler Optimization Level has been set to “Optimize for size,” keeping in mind the aim of the project and not thinking much about performance. Some of the options in the standard kernel features configuration have also been disabled, because I felt they were not required for normal use.
I’ve made other changes with processor type and features.
Since I have an AMD machine, most of the options for Intel processor support have been disabled except for those my computer requires. It’s important to note that although your processor might be from a particular vendor, it still might use devices or drivers from another vendor.
I’ve disabled options like late microcode loading, MPS table support, cluster scheduler support and five-level page table support that my machine does not need for better performance or general work.
In memory management, since I won’t need extra CPU performance with fewer translation lookaside buffer (TLB) misses and for huge TLB transparency, I also disabled those options.
Since I don’t plan on using virtual machines on my system, I also have not included the option for VMs and virtio devices.
Device drivers was one of the sections that took the most time. Along with general drivers that are absolutely required, there are driver options for devices not included with the system.
These unused driver modules can take up a good chunk of memory.
My customized kernel doesn’t have support for those devices that I do not have and do not plan to get like PCI (peripheral component interconnect) devices, USB devices, SCSI (Small Computer System Interface) support needed for particular machines, which can be found using lspci
, lsusb
and lsscsi
commands.
Looking at the outputs for these commands, most of the options given in the Device Drivers have been decided upon.
A chapter from Greg Kroah-Hartman’s book “Linux Kernel in a Nutshell” can help you understand which modules your system requires and which can be safely disabled.
Since I won’t be doing some tasks that need high security, I have disabled the option for mitigating speculative execution vulnerabilities, securityfs
file system, different security models, support for calculating Diffie-Hellman public keys and other kernel hardening options.
Most developers might find config options related to kernel debugging very useful. But these options mostly contain symbols, Kernel Sanitizer, fuzzing support, etc., which take up huge amounts of space. However, these options are not required for normal booting up of the system. Hence, these can be excluded from the kernel build to save space and can be included just by making changes in the config file or through make menuconfig
later whenever they are required.
As I do not plan on doing kernel debugging using this particular kernel, I have disabled most of the kernel debugging options like tracers, support for KASAN, fuzzing, debugfs
, stack backtrace support, etc.
While I only need support for etx4
file system, I have disabled all the other major file system options. Some of the pseudo file system options were not changed since they are required for the smooth working of devices and drivers. I do not plan on ext4
debugging, so that option was also disabled.
For networking support, since I do not want to work much on networking and security using this kernel, many of the options are disabled here except for those that are necessary, like wireless support and support for its networking stack and configuration API.
There wasn’t much that could be changed in the Cryptographic API and Library routines sections as most of the already-selected options are required for smooth working of the system.
Since my computer is not that old and I do not use legacy applications, some of the options given for older applications and hardware to work have been completely disabled.
These were the major areas that I focused on. Apart from these, there are many other options that were also changed to bring down the size of the kernel.
Building the Kernel
To build the kernel, I used make -j4
to do the task faster and parallelly. Then I used make modules_install
to install the modules, followed by make install
. At the end, I updated the grub menu by ‘sudo update-grub`.
Size
Project Link
The config file for my custom kernel can be found here.