KernelConfiguration

Overview

This page talks about how to compile your own Linux kernel on a Debian system.


References

http://kernel-handbook.alioth.debian.org/ 
The Debian Linux Kernel Handbook
http://qref.sourceforge.net/Debian/reference/ch-kernel.en.html 
Debian Reference, chapter "The Linux kernel under Debian"
Kernel source README 
The README file that comes with every Linux kernel source tree that describes the standard procedure for building a Linux kernel (e.g. /usr/share/doc/linux-source-2.6.21/README.gz)
/usr/share/doc/kernel-package/README.gz 
README file from the Debian package kernel-package


Where to get the kernel sources

You can always download the pristine kernel source tree from http://www.kernel.org/, however I prefer to get them in a Debian package via aptitude (or apt-get).

Until kernel version 2.6.8, the Debian packages for the Linux kernel sources are named with the prefix "kernel-source". Later versions are packaged with the prefix "linux-source". The reason for this seems to be that other kernels than Linux (e.g. the Hurd) are going to be packaged for Debian.

At the time of writing, the most recent kernel that I have built was from the Debian package named

linux-source-2.6.21


Other Debian packages

To build a Linux kernel requires that you install a couple of other packages first. Notable are the following ones:

kernel-package 
Because it makes everything so easy on Debian, this package should be considered a must
initramfs-tools 
This package is required to prepare an initial RAM filesystem (initramfs, aka "initrd" which is short for initial RAM disk)
module-init-tools 
I forgot why, but I stumbled over this package when I tried to build a 2.6.3 kernel


Privileges

Building a Linux kernel does not require that you have root privileges, but installing the newly built kernel does. Because I am lazy and I usually do both of these tasks in succession, I prefer to do everything while logged in as root.

The following examples always assume that you are already root, or have the means (and know when) to become root. Often quoted is "fakeroot", but other possibilities are "sudo" or "su".


Quick guide in 10 steps

These are the 10 commands I had to execute in order to build and install a new Linux kernel 2.6.21 on my system. As you may guess, my system is named "osgiliath", and I was building the 8th revision of a kernel on my system.

# apt-get install linux-source-2.6.21
# cd /usr/src
# tar xfvj linux-source-2.6.21.tar.bz2
# cd linux-source-2.6.21
# make menuconfig
# make-kpkg clean
# make-kpkg --append_to_version -osgiliath --revision=rev.09 kernel_image modules_image
# cd ..
# dpkg -i linux-image-2.6.21-osgiliath_rev.09_i386.deb
# init 6

Read on if you want to know more...


More details

Location of the sources

apt-get drops the tar ball with the kernel sources in

/usr/src

You may wish to extract the tar ball to a different location, but being lazy I prefer to stay in /usr/src.


Configuring the kernel

There are several user interfaces for configuring the kernel:

  • "make xconfig" launches a QT based, graphical configuration tool; you need to have a running X session
  • "make gconfig" launches a GTK based, graphical configuration tool; you also need X for this
  • "make menuconfig" launches a configuration tool based on ncurses; no X is required for this, a simple terminal is sufficient


A note about "make xconfig": A bad thing once happened to me when I tried "make xconfig" to configure a kernel in the early 2.6.x series. What happened was that the graphical configuration tool didn't show all the available configuration options. I only noticed this because I couldn't find an option that I rememberd seeing when I last used "make menuconfig". This thoroughly destroyed my confidence in "make xconfig", and since that time I always use (and recommend to others to use) "make menuconfig", assuming that this is the interface best tested and best supported.


Re-using an old configuration

The result of the kernel configuration process is stored in the file .config in the kernel sources base directory. For instance, this could be

/usr/src/linux-source-2.6.21/.config

You can re-use this file when you want to configure a new kernel so that you don't have to re-enter all your choices again.

When you install a kernel .deb package, the .config file matching that kernel is copied into the /boot directory along with the kernel image itself. For instance, this could be

/boot/config-2.6.21-osgiliath

After you have extracted the kernel sources, but before you start the configuration process, copy the file from the /boot directory to the kernel sources base directory. For instance:

cd linux-source-2.6.22
cp /boot/config-2.6.21-osgiliath .config

Now when you start "make menuconfig", all the choices that you made for the old 2.6.21 kernel are already repeated for you in the new 2.6.22 kernel, and you only have to decide about the options that have been newly added to the 2.6.22 kernel.

If you don't know what the new options are, you may wish to try

make oldconfig

This lets you enter choices only for the new options.


.config support in the kernel

Under the "General setup" heading, there is an interesting kernel configuration option named ".config support". If you enable this option, the kernel exports the configuration options it was built with in the file

/proc/config.gz

Simply take the .config file from there if you want to configure a new kernel. The trade-off for this convenience is that your kernel image becomes a couple of KB larger (both on disk and in RAM, once it is running).

Update: When configuring the 2.6.12 kernel, I noticed that "make menuconfig" automatically imports the configuration of the old kernel - without me having to copy the .config file into the kernel sources base directory! I was not able to google any information about where the old .config is taken from, but since the old kernel was built with ".config support" turned on, I can only assume that "make menuconfig" is clever enough to find and import /proc/config.gz.

Update 2: Actually, the old configuration is taken from /boot/config-$UNAME_RELEASE, where $UNAME_RELEASE probably refers to the output of the uname -r command. You can experimentally confirm this by launching "make menuconfig", once with the config file present in the /boot directory, and once with the config file moved away: You will get different default values for options in both cases. Note: It seems as if the configuration file is imported by init/Kconfig, at least this is the case with the kernel source package linux-source-2.6.21-6.


Building the kernel

After you are satisfied with your kernel configuration, the kernel can be built with the help of the "make-kpkg" utility.

The first step is the command

make-kpgk clean

This removes any traces of an old kernel build and lets you start a fresh build.

Note: you always have to clean first and re-build the entire kernel, even if you only changed one little option in the configuration since your last build. I have tried to skip the clean step, which made the kernel build go much faster (obviously, because all the old object files were still around), but the resulting kernel still did not do what it was supposed to do. I cannot explain why this is so - until I have made further investigation, I simply have to accept the fact that skipping the clean step is a no-no.


After cleaning up, the kernel can be built. The resulting kernel image and its associated modules are placed into a .deb package. The name of the package is stitched together from the kernel version and some command line arguments given to make-kpkg. Consider the following command line:

make-kpkg --append_to_version -osgiliath --revision=rev.09 kernel_image modules_image

This builds both the kernel and the modules image. In the case of a 2.6.21 kernel, the resulting package name is

kernel-image-2.6.21-osgiliath_rev.09_i386.deb

As you can see, make-kpkg automatically used the kernel version and the architecture in the package name. In addition, the package name is expanded by

  • the string "-osgiliath", which could be anything, but in my case is signifying the name of the machine the kernel was built for
  • the string "rev.09", which, again, could be anything, but in my case I use a number that increases for every kernel that I build for a given machine; note that the revision string must not contain an underscore character ("_")


Installing the kernel

Installing the kernel is as easy as calling "dpkg -i" on the .deb file resulting from the build. You will be asked a number of questions by dpkg, which depend on the configuration of your system (e.g. do you have lilo or grub?), and the answers to which you should know best for yourself.

BTW: You should consider archiving the kernel image (i.e. the .deb file) in a safe location. Even if you are able to accurately reconstruct the exact configuration options for a given kernel build, the time for re-building a kernel is still wasted. On my machine, I have measured build times as follows:

  • kernel 2.6.3 = 25 minutes
  • kernel 2.6.6 = 32 minutes
  • kernel 2.6.12 = 38 minutes
  • kernel 2.6.21 = 20 minutes (gcc 4.1.3)


Creating an initrd image

I never thought about initrd until I was caught by a non-booting kernel due to some problem with udev (try googling for "unable to open an initial console"). I found good instructions for creating an initrd image in Debian's Kernel Handbook.

The following prerequisites have to be met:

  • Kernel must be compiled with initrd support
  • The package initramfs-tools must be installed

Once initramfs-tools is installed, whenever a new kernel is compiled, an initrd image is supposed to be created automatically. In my case, I already had a kernel that I didn't want to recompile, therefore I followed the instructions in the Kernel Handbook to create an image for an already existing kernel:

dpkg-reconfigure linux-image-2.6.21-osgiliath

(the package name obviously changes with different kernel sources and machines)


Unfortunately dpkg-reconfigure didn't work for me. I don't know the reason, but after some investigation what was supposed to happen behind the scenes (see etc/kernel/postinst.d/initramfs-tools), I eventually succeeded with the following command:

update-initramfs -c -t -k 2.6.21-osgiliath

The result is the initrd image

/boot/initrd.img-2.6.21-osgiliath

After creating the image, I had to update /etc/lilo.conf with the following line:

initrd=initrd.img-2.6.21-osgiliath

(obviously, LILO needs to be run afterwards to make the change active)


To extract the content of an initrd image into a sub-directory of the current directory:

mkdir /tmp/foo
cd /tmp/foo
zcat /boot/initrd.img-2.6.21-osgiliath | cpio -i


Kernel Modules

References


Debian packages

  • module-init-tools: Provides lsmod, modinfo, insmod, rmmod, modprobe, depmod
  • module-assistant: Provides the utility module-assistant to build kernel modules


Filesystem location

Kernel modules are located in

/lib/modules

For instance

/lib/modules/2.6.38-2-686/kernel/drivers/net/usb/asix.ko


lsmod and /proc/modules

To see the kernel modules that are currently loaded:

lsmod

The output is pretty-printed from

/proc/modules

Example:

root@pelargir:~# lsmod | grep -i asix
asix                   39857  0 
mii                    12562  1 asix
usbcore                99058  6 asix,btusb,usbhid,ohci_hcd,ehci_hcd

Discussion:

  • The first column is the name of the module
  • The second column is the number of bytes in memory that the modules consumes
  • The third column is the "use count", i.e. how many "things" (e.g. open devices, mounted filesystems, etc.) currently make use of the module; the module cannot be unloaded unless this count is 0 (zero)
  • The fourth column is the module dependency list, i.e. which of the other kernel modules depend on the module


modinfo

The utility modinfo displays details about the specified kernel module (the information comes from the .modinfo section in a module's object file). Example:

root@pelargir:~# modinfo asix
filename:       /lib/modules/2.6.38-2-686/kernel/drivers/net/usb/asix.ko
license:        GPL
description:    ASIX AX8817X based USB 2.0 Ethernet Devices
author:         David Hollis
alias:          usb:v0B95p7E2Bd*dc*dsc*dp*ic*isc*ip*
alias:          usb:v0B95p772Bd*dc*dsc*dp*ic*isc*ip*
[...]
alias:          usb:v0B95p1780d*dc*dsc*dp*ic*isc*ip*
depends:        usbcore,mii
vermagic:       2.6.38-2-686 SMP mod_unload modversions 686 
parm:           msg_level:Override default message level (int)
parm:           bsize:Maximum transfer size per bulk (int)


insmod, rmmod, modprobe

insmod is used to insert (or load) a module into the kernel. rmmod removes the module (if its use count allows the module to be removed).

modprobe inserts or removes a kernel module, or set of kernel modules, intelligently. For example, if module A depends on module B, modprobe will automatically load B when you tell it to load A.


Build a kernel module using module-assistant

The Debian-specific utility module-assistant is a more or less user-friendly tool to build kernel modules whose source code exists as a Debian package. It may be invoked by its full name, or by its shortcut name

m-a

If invoked without any parameters, a nice dialog frontend pops up. Following is a pure command-line example:

m-a prepare  # configure the system to compile modules (this includes installing required packages
apt-get install foo-source
m-a build foo
dpkg -i /usr/src/newly-built-foo.deb

The last two steps (build and install) can be achieved with one command:

m-a auto-install foo


Build a kernel module without module-assistant

Before starting the actual build, module-assistant is useful to set up the system:

m-a prepare


When the system is ready:

cd /usr/src
tar xfvj /var/archive/kernel/AX88772B_772A_760_772_178_LINUX_Driver_v4.1.0_Source.tar.bz2
chown -R root:root AX88772B_772A_760_772_178_LINUX_Driver_v4.1.0_Source/
cd AX88772B_772A_760_772_178_LINUX_Driver_v4.1.0_Source/
modprobe -r asix   # remove an old version of the module
make
make install
modprobe asix   # load the newly installed module


Other kernel stuff

To find out what version of the kernel your system is currently running:

cat /proc/version