This is a quick guide to building a custom 2.6 kernel, patching the kernel, and adding loadable kernel modules. You'll find detailed recipes in Linux Cookbook(O'Reilly) in Chapter 10, "Patching, Customizing, and Upgrading Kernels," and Chapter 12, "Managing the Bootloader and Multi-Booting," which tells how to customize your GRUB or LILO boot menus for different kernels.
Why would you want to build a custom kernel? To add features or remove unnecessary features. On routers and firewalls, it adds a bit of security to use kernels that have had all the unnecessary features removed, and you can reduce the size considerably to fit on devices with limited storage.
Many distributions have their own distribution-specific tools for building kernels. You don't need these for building vanilla kernels from kernel.org. But, it's a different story when you're using distribution-specific kernel sources. Red Hat and Fedora package theirs as source RPMs, so you can't just build the kernel, but must also build an RPM. Fear not, for this appendix reveals how. Red Hat/Fedora kernels are heavily patched, to the point that a vanilla kernel may not even work, so you need to know the Red Hat Way of customizing kernels.
Debian, on the other hand, does very little modification to Linux kernels. They remove any bits that don't meet their policies, and that's all. So, vanilla kernels work fine on Debian systems.
You'll need a build environment, kernel source code for your distribution, and at least 2 GB of free disk space. You can build a kernel on any system, then copy it to other systems. If you like to modify kernels a lot, you might set up an old PC as a dedicated kernel-building station. Then, you'll only have to maintain source trees and utilities on a single box.
Most documentation tells you to unpack kernel sources into /usr/src/linux. Don't do this. As the kernel README says:
Do NOT use the /usr/src/linux area! This area has a (usually incomplete) set of kernel headers that are used by the library header files. They should match the library, and not get messed up by whatever the kernel-du-jour happens to be.
You may store binaries and source trees anywhere, and execute almost every step as an unprivileged user. Only the final steps require superuser privileges.
You may install as many kernels as you like, selecting the one you want to use at boot.
You need a build environment and some helpful utilities. You
should have the lshw and
lspci commands installed in case you need to look
up hardware information. Run the update-pciids
command first to bring them up-to-date. Run cat /proc/ cpuinfo
to display your CPU
specs.
Next, on Fedora, install these packages to get a basic build environment:
# yum groupinstall 'Development Tools'
# yum install qt-devel
On Debian, install these packages:
# aptitude install build-essential libqt3-mt-dev qt3-dev-tools
Obtaining a kernel that has not been altered by distribution vendors is easy—go to http://kernel.org/, the mothership of the Linux kernel. Download and unpack it into a folder in your own home directory; for example ~/kernel:
[carla@windbag:~/kernel]$ wget http://kernel.org/pub/linux/kernel/v2.6/linux-2.6.20.1
[carla@windbag:~/kernel]$ tar zxvf linux-2.6.20.1
This is about a 40 MB download that will unpack to about 240 MB.
Change to the top-level directory of your new source tree. All of the following commands will be run from here:
$ cd linux-2.6.20.1
Read the Documentation/Changes file to make sure you have the correct gcc version and other necessary utilities. Read the README for installation tips and other useful information.
Edit the new kernel makefile
(~/kernel/linux-2.6.20.1/Makefile) to give a
custom value to EXTRAVERSION
, such
as EXTRAVERSION =-test
. Or, in the
kernel configuration, enter your custom value in General Setup → Local
version → append to kernel release.
Let's see what options the make command has:
$ make help
Even though this is a brand-new source tree, run a cleanup first:
$ make mrproper
At this point, you may copy your own custom config file to this directory, or just let make take care of it for you. If you don't provide one, it will use your /boot/config-* file. You can change everything anyway, so it doesn't matter all that much.
Now, run these commands:
$ make xconfig
$ make
$ su
# make modules_install
# mkinitrd -o /boot/initrd-linux-2.6.20.1
# cp linux-2.6.20.1/arch/i386/boot/bzImage /boot/vmlinuz-linux-2.6.20.1
# cp linux-2.6.20.1/System.map /boot/System.map-linux-2.6.20.1
Save a copy of your new config file in a directory outside of the build tree. Add the new kernel to your GRUB bootloader menu:
# /boot/grub/menu.lst title new test kernel root (hd0,0) kernel /boot/vmlinuz-2.6.20.1 root=UUID=b099f554-db0b-45d4-843e-0d6a1c43ba44 ro initrd /boot/initrd-2.6.20.1
Where does the UUID come from? From running the blkid command:
$ blkid
/dev/sda1: UUID="b099f554-db0b-45d4-843e-0d6a1c43ba44" SEC_TYPE="ext2" TYPE="ext3"
/dev/hda1: UUID="1a5408ad-7d1d-4e24-b9db-d132d76e9e8e" SEC_TYPE="ext2" TYPE="ext3"
Remember that GRUB counts from zero, so hd0, 0
means /dev/hda1,
or the first partition of the first block device. In this era of mixed
PATA and SATA drives, this depends on the BIOS order of your hard
drives, so you may need to dig around in your BIOS settings to see
which drive the BIOS recognizes as the first, second, and so
forth.
Reboot to your new kernel and enjoy. If it doesn't work, simply reboot to your old kernel, and try again.
You should use UUIDs to identify your block devices because /dev names are no longer static, but at the mercy of udev. You need to create an initrd image because the /dev directory is not populated until after boot, so there is no way to build the boot device into the kernel anymore.
make xconfig
is
time-consuming, but very important. If you leave out anything
important, some things won't work, or it might not boot at all. Every
configuration item has a Help entry. The kernel source tree has reams of help in the
Documentation/directory.
You have three options for each configuration item: leave it out, build it into the kernel, or build it as a loadable module. These things should be built-in to the kernel:
Module support and kmod, for automatic module loading
a.out binaries, ELF binaries, and MISC binaries
VGA text console
All filesystems you'll be using, such as ext2/3, ReiserFS, JFS, XFS, loopback, VFAT, NTFS, UDF, etc.
Any hardware support related to boot devices should be built into the kernel:
IDE, ATA, and ATAPI block devices
SCSI support (note that the 2.6 kernel does not need IDE-SCSI, so if you have no SCSI devices, you can omit this)
USB support
Any on-board controllers
ACPI power management
These are fine to have as loadable modules:
NIC drivers
Netfilter/iptables
USB drivers
Sound card drivers
PCI hotplug
Video drivers
It doesn't matter if you prefer a large statically built kernel, or a lean kernel with lots of loadable modules. Don't obsess over building the leanest possible kernel because it doesn't matter—performance is the same either way. Just be sure to enable loadable module support so that you can add additional modules as needed; this is a lot quicker and easier than rebuilding a kernel. Your best chance of improving performance is to select support for your particular CPU, rather than generic i386.
Change to the directory that contains the build tree, like ~/kernel/linux-2.6.20.1. Then, you'll need a good up-to-date config file. Copy it to the top level of your build tree, then run:
$ make oldconfig
This takes your existing configuration, and lets you add new features. As you go through the configuration, find the driver you need, and select it as a module. For example, the tulip module is a common driver for many Ethernet cards. Then, run these commands:
$ make dep
$ make modules
# make modules_install
# depmod -av
Load the module with modprobe:
# modprobe tulip
If you remembered to enable kmod in the kernel configuration, the kernel will try to find and load all necessary modules at boot. If it doesn't, add them to /etc/modules (Debian) or /etc/modules.conf (most other Linux distributions).
Vendor-supplied modules come with their own installation instructions. For example, Nvidia provides a script that does everything for you. Others have different methods, so it all depends on the vendor.
If you wish to apply patches to your new kernel, this must be done before building it. The patch must be in the next-highest directory upstream from your build tree; for example:
$ ls ~/kernel
linux-2.6.20.1 patch-2.6.22.1.bz2
Now, change to the top level of your build tree, then unpack and apply the patch:
$ cd linux-2.6.20.1
$ bzip2 -dc ../patch-2.6.22.1.bz2 | patch -s -p1
Or, you can do a test-drive first with the --dry-run
option:
$ bzip2 -dc ../patch-2.6.22.1.bz2 | patch -s -p1 --dry-run
Now, configure and build your kernel, and away you go.
Your kernel build tree includes a script to handle applying patches for you, in scripts/patch-kernel. This is a great little script when you have several patches to apply because it automatically applies them in the correct order. Have all of your patches in the correct directory; then, from your top-level source directory, run this command:
[carla@windbag:~/kernel/linux-2.6.20.1]$ scripts/patch-kernel
Patches must be applied in order, and you must have all of them. For example, to use patch-2.6.22.1-pre3.bz2, you also need the first two in the series, unless you downloaded a kernel that already includes the first set of patches.
Fedora patches kernels heavily; a vanilla kernel from kernel.org may or may not work. So, let's do this the 100 percent Fedora way.
Fedora supplies only source RPMs, so you'll have to customize your kernel and then package it into an RPM. Download your kernel SRPM from your favorite Fedora mirror, such as:
$ wget http://mirrors.kernel.org/fedora/core/development/source/SRPMS/kernel-2.6.21
1.3194.fc7.src.rpm
Then, make sure you have all the build tools you need:
# yum install rpmdevtools
Now, set up a build tree in your home directory, and make sure to do this as yourself and not as the root user:
$ fedora-buildrpmtree
This creates an rpmbuildtree directory populated with BUILD, RPMS, SOURCES, SPECS, and SRPMS directories.
Now, install the source RPM. This will unpack files into your new rpmbuildtree directory:
$ rpm -ivh 2.6.21-1.3194.fc7.src.rpm
Ignore any warnings about "group kojibuilder does not exist."
Next, run the %prep stage of the RPM
rebuild. Make the --target
option
match your CPU type:
$ rpmbuild -bp --target=i686 ~/rpmbuild/SPECS/kernel-2.6.spec
The kernel tarball has been extracted, and all the Fedora patches applied. Change to the source directory of your new build tree:
$ cd ~/rpmbuild/BUILD/kernel-2.6.21/linux-2.6.21-1.3194.i686/
Do housecleaning:
$ make mrproper
$
Now, let's get started with configuring the new kernel:
$ make xconfig
And, finally:
$ rpmbuild --target i686 -ba ~/rpmbuild/SPECS/kernel-2.6.spec
Again, make the --target
option match your CPU type.
This builds the kernel.rpm, the kernel-devel.rpm, and rebuilds the kernel.src.rpm with your custom config included. The new binary kernel RPM is in ~/rpmbuild/RPMS/i686/. Grab your new kernel.rpm, and install it just like any other RPM:
# rpm -ivh kernel-2.6.21-1.3194.i686.rpm
Then, reboot and enjoy your new kernel.
Debian users can employ either vanilla kernels, or have the option to fetch official Debian kernel sources with aptitude. You should also install kernel-package and fakeroot:
# aptitude install linux-source-2.6.22 kernel-package fakeroot
This downloads the source tarball into /usr/src/, so you need to move it to your personal kernel-building directory:
# mv /usr/src/linux-source-2.6.20.tar.bz2 ~/kernel
Remember that dpkg-L [package
name]
shows you all the installed files in a package if you
can't find them.
Change to your ordinary user, change to your kernel directory, and unpack the tarball:
$ su carla
$ cd ~/kernel
$ tar zxvf linux-source-2.6.20.tar.bz2
Then, change to the top-level source directory, and start configuring your new kernel:
$ cd linux-source-2.6.20
$ make mrproper
$ make xconfig
When you're done slogging through configuration, run these commands:
$ make-kpkg clean
$ make-kpkg -rootcmd fakeroot -rev test.1 linux_image
This produces a .deb package named linux-image-2.6.20_test.1_i686.deb, which you can install in the usual way with dpkg:
# dpkg -i linux-image-2.6.20_test.1_i686.deb
This should put everything where it belongs and create a GRUB menu entry.
fakeroot fools the system into thinking you are the root user when you're not. It won't let you run commands that need genuine root privileges, but it's good enough for kernel-building.
Debian's binary kernel packages are named linux-image-*, and the kernel source packages are named linux-source-*. It has been this way since the 2.6.12 kernel; before then, they were called kernel-image-* and kernel-source-*. The new naming convention is in hopes of allowing other kernels to be used with Debian in addition to the Linux kernel.
The Red Hat manuals also apply to Fedora; find them at: https://www.redhat.com/docs/manuals/enterprise/
Fedora's own documentation is getting more thorough:http://docs.fedoraproject.org/
The Debian Reference Manual has everything you need to know about Debian, including kernel building:http://www.debian.org/doc/manuals/reference/