A few notes I took while building my first custom kernel a year back.
Building and installing a custom Linux kernel on Debian
$ cp /boot/config-$(uname -r) .config
$ sudo make -j 4 && sudo make modules_install -j 4 && sudo make install -j 4
$ update-initramfs -c -k $(VERSION)
$ update-grub
make -j4
builds the kernel and the kernel modules. 4 is the number of threads
used for the build, adjust it to match your hardware. Build time: about 1-2
hours on a decent machine
make modules_install
installs the kernel modules to /lib/modules or
/lib/modules/<version>. make install
installs the newly built kernel to
/vmlinuz.
update-initramfs
creates initramfs for the new kernel.
update-grub
updates GRUB's config files to take the new kernel in account.
What is initramfs ?
initramfs is a tiny rootfs loaded by the kernel at startup. It is responsible for mounting the actual root filesystem.
A rootfs is a ramfs (or a tmpfs, depending on your kernel configuration) which is always present in > 2.6 systems. A ramfs is basically the kernel's caching mechanisms exported as a ram-based filesystem. The ramfs implementation is very simple (the code base is actually so small that it's always enabled in the kernel) but this comes with a few drawbacks: ramfs memory can't be freed (a ramfs grows indefinitely) nor limited (it will fill up the ram until the system goes oom).
tmpfs addresses most of these issues at the cost of increased complexity.
Why not directly mount the actual /root ?
If the system you're booting on is clearly defined during kernel build, that is it is possible to statically build the kernel modules into the kernel, it isn't needed, no. However, GNU/Linux distributions like Debian distribute generic kernels where all drivers are distributed as modules (statically compiling them into the kernel would produce way too big kernel images), and in this case modules have to be selected and loaded from /lib at boot time.
This is the "main" reason why systems like Debian typically need to mount initramfs before mounting the actual /root.
That said, there are other reasons to use initramfs, even with statically compiled drivers.
For example, in the case where the HDD is encrypted, user-space binaries are needed to decrypt the disk (along with an interface to retrieve the passphrase, etc). All of this is not handled by the kernel, meaning that it has to be included in a minimal user-space environment in the initramfs.
Similarily, booting from the network requires networking tools not provided by the kernel itself, so they have to be included in the initramfs.
What's the difference with initrd ?
-
initrd was compressed filesystem image mounted by the kernel.
-
initramfs is a set of compressed files decompressed into a temporary cache fs into the kernel.
It is quite common to call initramfs initrd nowadays. initramfs is kind of the modern way to implement initrd.
Why updating the GRUB config ?
The GRUB displays a list of available kernels to boot from at startup. This list
has to be updated somehow. Back in the days you had to enter them manually in
the configuration files, but now there are scripts capable of scanning the root
filesystem and generating these config files for you. That's exactly what
grub-mkconfig
does, and update-grub
is nothing more than a wrapper for
grub-mkconfig -o /boot/grub/grub.cfg
.
Sources, further reading
- @sreehari: How to build and install the latest Linux kernel from source
- @rob (kernel.org): ramfs, rootfs and initramfs