In-depth HOWTO on Linux kernel configuration
While we talked before about kernel compilation and configuration, we focused on the general idea. This time we want to dig deeper into the configuration part, giving you useful advice you will need when tailoring a kernel to perfectly match your hardware.
The main idea behind this is that you will need to know your hardware extremely well in order to have a kernel built exactly for it. At the beginning we will cover what you will need in order to compile your kernel and after that we move into Linux kernel configuration, compilation and installation. Please note that this time it's not very important if you compile a vanilla kernel or a distribution kernel. We will however, recommend a "modus operandi", which of course does not mean that you have to follow. After reading this guide you will be able to decide what suits you best. We expect some moderate knowledge about Linux system internals and development tools. If you still have some questions after reading this article please try our new LinuxCareer Forum.
1. What you will need
From now on, as stated before, we will show you how we do this, so everything you'll read will be specific to our system, unless stated otherwise. Typing 'du -h' in our kernel source tree shows 1.1G. This is after we typed 'make clean'. In short, we'd say you better have at least 2.5G available for the kernel tree, since code gets added constantly and object files take quite some space. Also /lib/modules/ will use a lot of disk as time passes, and, if you have a separate /boot partition, that may get crowded too.
Of course, after you configure the kernel, you'll want to compile it, so the usual suspects must be present : make, git, gcc, the readline library for menuconfig... Speaking of git, you might have heard about the recent break of kernel.org, so if you try to clone the usual location or try to pull, you will get
$ git pull fatal: Unable to look up git.kernel.org (port 9418) (Name or service not known)
What you can do is use the new, temporary location of the git tree as announced by Linus Torvalds :
$ git pull git://github.com/torvalds/linux.git
Of course, replace pull with clone if you want to set up a new Linux kernel source tree. Some folks still recommend storing the source tree in /usr/src, however we and many others go against it : use your home folder and issue commands as root only when needed.
Even though we will make the kernel smaller in our tutorial, it will still need some horsepower in order to get compiled in a decent time. So, while on a modern, multi-core system it will take ~15 minutes, on an older, slower system it might take even a day or so. Compiling large projects puts a lot of stress on the machine, especially memory. If you see random "Signal 11" errors that appear in different places in the code every time you try, re-seat the memory, clean the slots or change the RAM. It's dirt cheap nowadays and you will probably get a speedier memory than the one you had, provided your motherboard supports it.
Let's get to the "getting to know your hardware" part. If you already feel confident you know what lies under the hood of your computer, you may skip this part. If not, or have some doubts, read on. Take your time with this part because it's crucial to getting a kernel made especially for your machine. On our Debian box, running
# lspci -vv > lspcioutput
creates a file named 'lspcioutput' (change the name if you want, of course) and fills it with the info from the command lspci, ran verbosely for more details. Open the created file with your favorite editor and keep it handy. Read it all to get a general idea about your hardware components. Going further with our example, here's what appears in our lspci output at the Ethernet controller part :
00:06.0 Ethernet controller: nVidia Corporation MCP65 Ethernet (rev a3) Subsystem: Giga-byte Technology Device e000 Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+ Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0 (250ns min, 5000ns max)
Interrupt: pin A routed to IRQ 42
Region 0: Memory at f6007000 (32-bit, non-prefetchable) [size=4K]
Region 1: I/O ports at c800 [size=8]
Capabilities:  Power Management version 2
Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA PME(D0+,D1+,D2+,D3hot+,D3cold+)
Status: D0 NoSoftRst- PME-Enable+ DSel=0 DScale=0 PME-
Capabilities:  MSI: Enable+ Count=1/8 Maskable+ 64bit+
Address: 00000000fee0300c Data: 4171
Masking: 000000fe Pending: 00000000
Capabilities: [6c] HyperTransport: MSI Mapping Enable- Fixed+
Kernel driver in use: forcedeth
As you can see, you get a lot of information about the hardware, information that we might need to sort in order to get what we need. What we need in this case is the name (nVidia Ethernet MCP65) and the driver in use, that is forcedeth. If you want to find out what option you need to enable in the kernel config in order to get the forcedeth module, Google for "forcedeth kernel config" and you will find out that what we are looking for is CONFIG_FORCEDETH. Easy.
lspci is not a one-stop shop, as the name implies. As a general rule , /proc and /sys will give you lots of info about your hardware. What you will not find in the lspci output is, for example, CPU info. /proc/cpuinfo helps with exactly the information you needed. If you have external USB-connected devices you wanna support, lsusb is your buddy. If you don't know for sure what drivers you'll need for a specific piece of hardware and Google won't help, try to leave all the options that seem related enabled. The overhead will be insignificant and after you get some experience you will know better what to leave enabled and what to disable. Don't expect to get a perfect kernel from the start, practice makes perfect.
After you think you got all the bases covered, sit down and think again : what will you possibly need in the future? An external card reader? An iPod? Enable the drivers and you will avoid future issues with missing hardware support. We suggest you use the classic pen and paper to write down a list with your hardware configuration, in detail with the kernel modules used, etc. Files come and go, hard disks too, but a piece of paper stuck to the case somewhere will help you and maybe others. What do you do with the computer? Do you use virtualization? Enable Xen and/or KVM support. Does your distribution enforce SELinux or Tomoyo or other security framework? Do you need it? Enable the respective parts.
Now that we are set, let's get to the configuration part.
We said earlier that we'll describe our method : well, here it is. We use the distribution's configuration, of course if we see it works with our hardware, which usually happens, since we have nothing exotic.
$ cp /boot/config-$version $location_of_kernel_source_tree/.config
Use the version that's as close version-wise as possible to the kernel you're about to compile. Thus you will ensure that you'll get no compatibility issues. If you want to just use the config file as it is, just issue
$ make oldconfig
and then proceed with the compilation. However, we don't want that, so we will just do
$ make menuconfig
and we will see a curses-based, easy to use menu. Go to "Load an alternate configuration file" and enter the name of your config file (.config, in our example, and recommended). You can now proceed to alter options and save the configuration file in the end.
In "General setup" we usually leave things as they are, but you, of course, are free to change anything you like. The usual warning applies : do not change what you don't know. Remember that this type of configuration is dependency-based : if you disable/enable an item, those items that depend on it will also be affected. So, for example, if you disable networking, all network-related options will also be disabled automatically. "Processor type and features" must be altered to reflect your target processor : we have an AMD K8-based CPU, so we selected "Processor family -> Opteron/Athlon64/Hammer/K8". In "Networking support", since this is a desktop/workstation with a simple Ethernet connection, we disabled Amateur Radio, Infrared, Bluetooth, Wireless and other options that don't apply. Of course your mileage may and will vary. Remember that each item has an associated Help menu, accessible through the "Help" button in the bottom part of the screen, and you'll find out what the driver does, what hardware coverage it does have, etc. Going further to "Device drivers", here you'll probably have a lot to disable, since here is the bulk of the hardware drivers that Linux supports. Keep the hardware configuration sheet handy and make sane choices. If at first your new kernel doesn't boot, boot a working kernel (set your boot loader's timeout to something like 10 seconds so you can have time to choose) and see what went wrong. Use the in-tree documentation and the Internet.
Going further to "Kernel hacking", if you want to be(come) a kernel developer, here you'll find options to help you isolate and document bugs. Otherwise, leave these as they are, as debugging options tend to bloat and slow down your system. After you're through, select "Save an alternate configuration file" and enter '.config' (recommended again), then Exit. You are now ready to compile your kernel. A last word of advice, though : start by playing it safe, then gradually eliminate unneeded drivers until you get a slim, working kernel. It's easier going from big to smaller than the other way around.
3. Building and installing
We described building and installing kernels on Debian-based systems in an earlier article. Building is actually the same on any systems :
will build the kernel image you will install later. You can use -jn as a make argument, where n will be the number of CPU cores in your system + 1 in order to enable parallel building which, of course, will speed up the process. The next step,
# make modules_install
is also universal. What follows is different between distros : Fedora, OpenSUSE, Mandriva, Slackware and Debian (among others) need also 'make install'. Arch, for example, does not as you are required to install the kernel by hand with good ol' cp. Honestly, we did not try all the distributions, but these are some of the most popular and we hope that our experience will help you. You will find every distro's way to install a custom kernel online, or you'll want to create a kernel package and simply install it with the usual package management tools. However it will be, remember that the distribution's documentation takes precedence here.
Referring again to our Debian/Ubuntu kernel article, the steps described there for installation apply to RPM-based distros as well, with only small differences like the bootloader config update command. We recommend you create a package so you'll be more organized. If you choose not to and will want to remove a kernel, go to /boot and as root remove config-$version, initrd.img-$version (if applicable), System.map-$version and vmlinuz-$version, plus /lib/modules/$version/ .
And now...you have a fresh kernel installed, let's test it! Reboot and select the new kernel for booting. If it's a vanilla kernel and you find a bug, like some oops or panic, read the documentation (REPORTING-BUGS in the root of the kernel tree) and document your bug as thoroughly as possible. If it's a distro-patched kernel, use that distro's bug reporting tools, of course, and the maintainers will talk to upstream to solve the issue. Always keep a good working kernel and config file handy in order to save yourself some time and energy. A good custom kernel will often give you a more responsive system, especially if you use a general purpose distro that includes almost every kernel driver conceivable. Good luck.