Saturday, May 14, 2016

Linux Distribution Kernel Upgrade

In this post I want to write some steps to upgrade Distribution's Linux kernel from the source (yeah, not by specific distribution package manager), this assuming all required build tools has been installed and configured properly, consult to the distribution's resources to build a kernel from source.

I'm using Linux Mint 13 32bit (codename Maya, a Ubuntu 12.04 LTS derivative) as the host, running kernel version 3.13.0 which I steal from Linux Lite 2.4. Here I upgrade it to kernel version 4.4.10 (LTS). These steps here are not limited to Ubuntu derivate distributions, it can be for other distribution such as Debian, Fedora, Arc Linux and the others.

Get the kernel source

Firstly, download and unpack the kernel source, here I download it directly from kernel.org and pick an XZ archive version. We use /project/linux as our base working directory.

$ cd /project/linux
$ wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.4.10.tar.xz
$ tar xJf linux-4.4.10.tar.xz


Apply current kernel configuration

To match the current kernel configuration and to avoid too much dives in kernel configuration, we will reuse a configuration file that is very likely shipped by the distribution we are using, usually it is located inside the /boot directory, copy this file into our kernel source tree as .config

$ cd linux-4.4.10 
$ make mrproper
$ cp /boot/config-`uname -r` .config 

Building the kernel

Issue this to enter the kernel build configuration, for any errors that may occurred, again please refer to distribution documentation describing a system preparation to build kernel from source.

$ make menuconfig

The text based (ncurses) configuration menu appears, since we already have a .config file, we don't *really* care to configure some options again but let the configuration it self adjust and adapt against our existing configuration file. Exit from the configuration menu and confirm to save the configuration. Now we are ready to build the kernel by issuing

$ make

The build system should now begin to compile, various build messages or compiler warnings appear. The build time depends on hardware speed (CPU, RAM, disk I/O) and how many kernel's components we enabled in configuration. When the build has been finished, install all kernel's modules with superuser privilege

$ sudo make modules_install
$ cp arch/x86/boot/bzImage /project/linux/vmlinuz-4.4.10
$ cp .config /project/linux/config-4.4.10

This will install kernel modules inside /lib/modules/4.4.10 directory and copy the new kernel image as vmlinuz-4.4.10-generic inside our base working directory. For reference, we ought to copy configuration file for our future reference, of course like what we are doing now.

Rebuild initial ramdisk image

Since our distribution uses an initial ramdisk or so called initrd then we need to rebuild it to contain our new kernel's modules, we will use the existing initrd as our base.

Anyway, this is the most interesting part of upgrading process, the initrd file is a cpio archive and was gz compressed so we will use zcat and cpio utilities to extract and uncompress it. Assuming cpio and zcat are installed, issue these following commands

$ cd /project/linux
$ mkdir initrd
$ cd initrd
$ zcat /boot/initrd.img-`uname -r` | cpio -i

In above commands, we've created a directory named initrd as our initrd's files location after the extraction, we only need to replace old (current) kernel modules to our new modules. Ideally, by initrd nature which only provide basic init system, utilities and kernel modules need to boot, we only need to replace each module that are inside the old kernel, but since I'm too lazy to pick each one, I just copy full module directory here. Make it is easy, the downsize is just getting the final initrd file much bigger, don't worry about that. Issue these following commands to copy.

$ cd lib/modules
$ rm -rf `uname -r`
$ cp -r /lib/modules/4.4.10 .

And its time to rebuild the initial ramdisk image, first we back to our initrd base directory and optionally make sure all initrd files are owned by Linux's UID 0 (root) then archive and compress it into a new initrd image. Switch to root and issue

# cd /project/linux/initrd
# chown -R root:root *
# find . | cpio -o -H newc | gzip -9 > /project/linux/initrd.img-4.4.10

Now, we should have these files in the base working directory

vmlinuz-4.4.10
initrd.img-4.4.10
config-4.4.10

We may need to copy or move these files into /boot directory if we like. And that's all, we can now test to boot the new kernel by modifying the GRUB boot loader configuration that usually in /boot/grub/grub.cfg (GRUB v2), see GRUB manual for that.