Configuring the kernel [Vasb] is a costly process and requires extensive knowledge on the part of the person doing it, it is also one of the critical tasks on which the system's stability depends, given the nature of the kernel, which is the system's central component.
Example 4-7. Note
The process of obtaining a new personalised kernel involves obtaining the sources, adapting the configuration, and compiling and installing the obtained kernel on the system.
Any error in the procedure can cause instability or the loss of the system. Therefore, it is advisable to make a backup of user data, configurations we have tailored, or, if we have the required devices, to make a complete system backup. It is also advisable to have a start up diskette (or Live CD distribution with tools) to help us in the event of any problem, or a rescue disk which most distributions allow us to create from the distribution's CDs (or by directly providing a rescue CD for the distribution).
Without meaning to exaggerate, if the steps are followed correctly, we know what we are doing and take the necessary precautions, errors almost never occur.
Let's look at the process required to install and configure a Linux kernel. In the following sections, we look at:
1) The case of old 2.4.x versions.
2) Some considerations regarding migrating to 2.6.x
3) Specific details regarding versions 2.6.x.
4) A particular case with the Debian distribution, which has its own more flexible compilation system (debian way).
Versions 2.4.x are practically no longer offered by current distributions, but we should consider that on more than one occasion we may find ourselves obliged to migrate a specific system to new versions or to maintain it on the old ones, due to incompatibilities or the existence of old unsupported hardware.
The general concepts of the compilation and configuration process will be explained in the first section (2.4.x), since most of them are generic, and we will subsequently see the differences with regard to the new versions.
The instructions are specifically for the Intel x86 architecture, by root user (although part of the process can be done as a normal user):
1) Obtaining the kernel: for example, we can visit www.kernel.org (or its FTP server) and download the version we would like to test. There are mirrors for different countries. In most GNU/Linux distributions, such as Fedora/Red Hat or Debian, the kernel's source code is also offered as a package (normally with some modifications included), if we are dealing with the version of the kernel that we need, it may be preferable to use these (through the kernel-source packages or similar). If we want the latest kernels, perhaps they are not available in the distribution and we will have to go to kernel.org.
2) Unpack the kernel: the sources of the kernel were usually placed and unpacked from the directory /usr/src, although we advise using a separate directory so as not to mix with source files that the distribution may carry. For example, if the sources come in a compressed file of the bzip2 type:
bzip2 -dc linux-2.4.0.tar.bz2 | tar xvf -
If the sources come in a gz file, we will replace bzip2 with gzip. When we decompress the sources, we will have generated a directory linux-version_kernel that we will enter in order to configure the kernel.
Before taking the steps prior to compilation, we should make sure that we have the right tools, especially the gcc compiler, make and other complementary gnu utilities for the process. For example, the modutils, the different utilities for using and handling the dynamic kernel modules. Likewise, for the different configuration options we should take into account a number of pre-requirements in the form of libraries associated to the configuration interface used (for example ncurses for the menuconfig interface).
In general, we advise checking the kernel documentation (whether via the package or in the root directory of the sources) to know what pre-requirements and versions of the kernel source will be needed for the process. We advise studying the README files in this root directory of the kernel source, and Documentation/Changes or the documentation index of the kernel in Documentation/00-INDEX.
If we have made previous compilations in the same directory, we need to make sure that the directory we use is clear of previous compilations; we can clear it using make mrproper (from the "root" directory).
For the process of configuring the kernel [Vasb], we have several alternative methods, which offer us different interfaces for adjusting the various parameters of the kernel (which tend to be stored in a configuration file, normally .config in the "root" directory of the sources). The different alternatives are:
• make config: from the command line we are asked for each option, and we are asked for confirmation (y/n) – yes or no, the option, or we are asked for the required values. Or the long configuration, where we are asked for many answers, and depending on each version, we will likewise have to answer almost a hundred questions (or more depending on the version).
• make oldconfig: it is useful if we want to reuse an already used configuration (normally stored in a .config file, in the root directory of the sources), we need to take into account that it is only valid if we are compiling the same version of the kernel, since different kernel versions can have variable options.
• make menuconfig: configuration based on text menus, fairly convenient; we can enable or disable what we want and it is faster than make config.
• make xconfig: the most convenient, based on graphic dialogues in X Window. We need to have tcl/tk libraries installed, since this configuration is programmed in this language. The configuration is based on tables of dialogues and buttons/checkboxes, can be done fairly quickly and has help with comments on most options. But it has a defect, which is that some options may not appear (it depends on whether the configuration program is updated and sometimes it is not). In this last case, make config (or menuconfig) is the only one we can be sure will offer all the options we can choose; for the other types of configuration it depends on whether the programs have been adapted to the new options in time for the kernel being released. Although in general they try to do it at the same time.
Once the configuration process has been done, we need to save the file (.config), since the configuration requires a considerable amount of time. Also, it may be useful to have the configuration done if the plan is to do it on several similar or identical machines.
Another important issue concerning configuration options is that in many cases we will be asked if we want a specific characteristic integrated into the kernel or as a module (in the section on modules we will provide more details on them). This is a fairly important decision, since in certain cases our choice will influence the performance of the kernel (and therefore of the entire system).
The Linux kernel has become very large, due both to its complexity and to the device controllers (drivers) [AR01] that it includes. If we integrated everything, we could create a very large kernel file that would occupy a lot of memory and, therefore, slow down some functioning aspects. The modules of the kernel [Hen] are a method that makes it possible to divide part of the kernel into smaller sections, which will be loaded dynamically upon demand or when they are necessary for either explicit load or use of a feature.
The normal choice is to integrate what is considered fundamental for functioning or critical for performance within the kernel and to leave parts or controllers that will be used sporadically as modules for future extensions of the equipment.
• A clear case are the device controllers: if we are updating the machine, it may be that when it comes to creating the kernel we are not sure what hardware it will have: for example, what network card; but we do know that it will be connected to a network, so, the network support will be integrated into the kernel, but for the card controllers we can select a few (or all) of them and install them as modules. Then, when we have the card we can load the required module or if we need to change one card for another later, we will just have to change the module to be loaded. If just one controller were integrated into the kernel and we changed the card, we would be forced to reconfigure and recompile the kernel with the new card's controller.
• Another case that arises (although it is not very common) is when we have two devices that are incompatible with each other, or when one or the other is functioning (for example, this tends to happen with a parallel cable printer and hardware connected to the parallel port). Therefore, in this case, we need to put the controllers as modules and load or download the one we need.
• Another example is the case of file systems. Normally we would hope that our system would have access to some of them, like ext2 or ext3 (belonging to Linux), VFAT (belonging to Windows 95/98/ME), and we will enable them in configuring the kernel. If at some moment we have to read another unexpected type, for example data stored on a disk or partition of the Windows NT/XP NTFS system, we would not be able to: the kernel would not know how to or would not have support to do so. If we have foreseen that at some point (but not usually) we may need to access these systems, we could leave the other file systems as modules.
3) Compiling the kernel
We will start the compilation using make, first we will have to generate the possible dependencies between the code and then the type of image of the kernel that we want (in this case, a compressed image, which tends to be the normal case):
make dep make bzImage
When this process is completed, we will have the integrated part of the kernel; we are missing the parts that we have set as modules:
At this point we have done the configuring and compiling of the kernel. This part could be done by a normal user or by the root user, but now we will definitely need the root user, because we will move onto the installation part.
We'll start by installing the modules:
And the installation of the new kernel (from the directory /usr/src/linux-version or the one we have used as temporary):
cp arch/i386/boot/bzImage /boot/vmlinuz-2.4.0 cp System.map /boot/System.map-2.4.0
the file bzImage is the newly compiled kernel, which is placed in the /boot directory. Normally, we will find the old kernel in the same /boot directory with the name vmlinuz or vmlinuz-previous-version as a symbolic link to the old kernel. Once we have our kernel, it is better to keep the old one, in case any faults occur or the new one functions badly, so that we can recover the old one. The file System.map contains the symbols available for the kernel and is necessary for the processing of starting it up; it is also placed in the same directory.
On this point, we also need to consider that when the kernel starts up it may need to create initrd type files, which serve as a compound image of some basic drivers and is used when loading the system, if the system needs those drivers before booting certain components. In some cases, it is vital because in order to boot the rest of the system, certain drivers need to be loaded in a first phase; for example specific disk controllers such as RAID or volume controllers, which would be necessary so that in a second phase, the disk can be accessed for booting the rest of the system.
The kernel can be generated with or without an initrd image, depending on the needs of the hardware or system in question. In some cases, the distribution imposes the need to use an initrd image, in other cases it will depend on our hardware. It is also often used to control the size of the kernel, so that its basics can be loaded through the initrd image and later the rest in a second phase in the form of modules. In the case of requiring the initrd image, it would be created using the mkinitrd utility (see man, or chapter workshop), within the /boot directory.
5) The following step is to tell the system what kernel it needs to boot with, although this depends on the Linux booting system:
• From booting with lilo [Zan][Skoa], whether in the MBR (master boot record) or from an own partition, we need to add the following lines to the configuration file (in: /etc/lilo.conf):image = /boot/vmlinuz-2.4.0 label = 2.4.0
where image is the kernel to be booted, and label is the name that the option will appear with during booting. We cam add these lines or modify the ones of the old kernel. We recommend adding them and leaving the old kernel, in case any problems occur, so that the old one can be recovered. In the file /etc/lilo.conf we may have one or more start up configurations, for either Linux or other systems (such as Windows).
Every start up is identified by its line image and the label that appears in the boot menu. There is a line default = label that indicates the label that is booted by default. We can also add root = /dev/... to the preceding lines to indicate the disk partition where the main file system is located (the '/'), remembering that the disks have devices such as /dev/hda (1st disk ide) /dev/hdb (2 disk ide) or /dev/sdx for SCSI (or emulated) disks, and the partition would be indicated as root = /dev/hda2 if the '/' of our Linux were on the second partition of the first ide disk. Using "append =" we can also add parameters to the kernel start up [Gor]. If the system uses initrd, we will also have to indicate which is the file (which will also be located in /boot/initrd-versionkernel), with the option "initrd=". After changing the lilo configuration, we need to write it for it to boot:
We reboot and start up with the new kernel.
If we have problems, we can recover the old kernel, by selecting the option of the old kernel, and then, using the retouch lilo.conf, we can return to the old configuration or study the problem and reconfigure and recompile the kernel.
• Boot with grub [Kan01][Pro]. In this case, handling is simple, we need to add a new configuration consisting of the new kernel and adding it as another option to the grub file. Next, reboot in a similar way as with lilo, but remembering that in grub it is sufficient to edit the file (typically /boot/grub/menu.lst) and to reboot. It is also better to leave the old configuration in order to recover from potential errors.
In the case of having to update versions of old distributions, or changing the kernel generation using the source code, we will have to take some aspects into account, due to the novelties introduced into kernel branch 2.6.x.
Here is a list of some of the specific points to consider:
Some of the kernel modules have changed their name, and some may have disappeared, we need to check the situation of the dynamic modules that are loaded (for example, examine /etc/modules and/or /etc/modules.conf) and edit them to reflect the changes.
New options have been added to the initial configuration of the kernel: like make gconfig, a configuration based on gtk (Gnome). In this case, as a prerequisite, we will need to look out for Gnome libraries. The option make xconfig has now been implemented with the qt libraries (KDE).
The minimum required versions of various utilities needed for the compilation process are increased (consult Documentation/Changes in the kernel sources). Especially, the minimum gcc compiler version.
The default package for the module utilities has changed, becoming module-init-tools (instead of modutils used in 2.4.x). This package is a prerequisite for compiling kernels 2.6.x, since the modules loader is based on this new version.
The devfs system becomes obsolete in favour of udev, the system that controls the hotplug start up (connection) of devices (and their initial recognition, in fact simulating a hotplug start up when the system boots), dynamically creating inputs in the directory /dev, only for devices that are actually present.
In Debian as of certain versions of branch 2.6.x, for the binary images of the kernels, headers and source code, the name of the packages changes from kernel-images/source/headers to linux-image/source/headers.
In some cases, new technology devices (like SATA) may have moved from /dev/hdX to /dev/sdX. In these cases, we will have to edit the configurations of /etc/fstab and the bootloader (lilo or grub) in order to reflect the changes.
There may be some problems with specific input/output devices. The change in name of kernel modules has affected, among others, mouse devices, which likewise can affect the running of X-Window, until the required models are verified and the correct modules are loaded (for example psmouse). At the same time, the kernel integrates the Alsa sound drivers. If we have the old OSS, we will have to eliminate them from the loading of modules, since Alsa already takes care of emulating these.
Regarding the architectures that the kernel supports, we need to bear in mind that kernel 2.6.x, in its different revisions, has been increasing the supported architectures which will allow us to have the binary images of the kernel in the distributions (or the options for compiling the kernel) best suited to supporting our processors. Specifically, we can find architectures such as i386 (for Intel and AMD): supporting the compatibility of Intel in 32 bits for the entire family of processors (some distributions use the 486 as the general architecture), some distributions integrate differentiated versions for i686 (Intel from pentium pro thereafter), for k7 (AMD Athlon thereafter), and those specific to 64 bits, for AMD 64 bits, and Intel with em64t extensions of 64 bits such as Xeon, and multicores. At the same time, there is also the IA64 architecture for 64bit Intel Itanium models. In most cases, the architectures have SMP capabilities activated in the kernel image (unless the distribution supports versions with and without SMP, created independently, in this case, the suffix -smp is usually added to the image that supports it).
In Debian, to generate inirtrd images, as of certain versions of the kernel (>=2.6.12) the mkinitrd tools are considered obsolete, and are replaced with new utilities such as initramfs tools or yaird. Both allow the initrd image to be built, but the former is the recommended one (by Debian).
In versions 2.6.x, bearing in mind the abovementioned considerations, the compilation takes place in a similar way to the one described above:
Having downloaded the kernel 2.6.x (with x the number or pair of numbers of the kernel revision) to the directory that will be used for the compilation and checking the required versions of the basic utilities, we can proceed to the step of compiling and cleaning up previous compilations:
# make clean mrproper
configuration of parameters (remember that if we have a previous .config, we will not be able to start the configuration from zero). We do the configuration through the selected make option (depending on the interface we use):
# make menuconfig
construction of the kernel's binary image
# make dep # make bzImage
construction of the modules (those specified as such):
# make modules
installation of the created modules (/lib/modules/version)
# make modules_install
copying of the image to its final position (assuming i386 as the architecture):
# cp arch/i386/boot/bzimage /boot/vmlinuz-2.6.x.img
and finally, creating the initrd image that we consider necessary, with the necessary utilities according to the version (see subsequent comment). And adjustment of the lilo or grub bootloader depending on which one we use.
The final steps (vmlinuz, system.map and initrd) of moving files to /boot can normally also be done with the process:
# make install
but we need to take into account that it does the entire process and will update the bootloaders, removing or altering old configurations; at the same time, it may alter the default links in the /boot directory. We need to bear this in mind when it comes to thinking of past configurations that we wish to save.
Regarding the creation of the initrd, in Fedora/Red Hat it will be created automatically with the install option. In Debian we should either use the techniques of the following section or create it expressly using mkinitrd (versions <=2.6.12) or, subsequently, with mkinitramfs, or a utility known as update-initramfs, specifying the version of the kernel (it is assumed that it is called vmlinuz-version within the /boot directory):
# update-initramfs -c -k 'version'
In Debian, in addition to the examined methods, we need to add the configuration using the method known as Debian Way. A method that allows us to build the kernel in a fast and flexible manner.
For the process, we will need several utilities (install the packages or similar): kernel-package, ncurses-dev, fakeroot, wget, bzip2.
We can see the method from two perspectives, rebuilding a kernel equivalent to the one provided by the distribution or tailoring it and then using the method for building an equivalent personalised kernel.
In the first case, we initially obtain the version of the kernel sources provided by the distribution (meaning x the revision of the kernel 2.6):
Example 4-8. Note
We can see the Debian way process in a detailed manner in: http://kernel-handbook.alioth.debian.org/
# apt-get install linux-source-2.6.x $ tar -xvjf /usr/src/linux-source-2.6.x.tar.bz2
where we obtain the sources and decompress them (the package leaves the file in /usr/src).
Installing the basic tools:
# apt-get install build-essential fakeroot
Checking source dependencies
# apt-get build-dep linux-source-2.6.x
And construction of the binary, according to the pre-established package configuration (similar to that included in the official image packages of the kernel in Debian):
$ cd linux-source-2.6.x $ fakeroot debian/rules binary
There are some extra procedures for creating the kernels based on different patch levels provided by the distribution and possibilities of generating different final configurations (view the reference note to complement these aspects).
In the second, more common case, when we would like a personalised kernel, we will have to follow a similar process through a typical tailoring step (for example, using make menuconfig); the steps would be:
obtaining and preparing the directory (here we obtain the distribution's packages, but it is equivalent to obtaining the sources from kernel.org):
# apt-get install linux-source-2.6.x $ tar xjf /usr/src/linux-source-2.6.x.tar.bz2 $ cd linux-source-2.6.x
next, we configure the parameters, as always, we can base ourselves on .config files that we have used previously, to start from a known configuration (for tailoring we can also use any of the other methods, xconfig, gconfig...):
$ make menuconfig
final construction of the kernel depending on initrd or not, without initrd available (we need to take care with the version we use; as of a certain version of the kernel, the use of the initrd image can be mandatory):
$ make-kpkg clean $ fakeroot make-kpkg --revision=custom.1.0 kernel_image
or if we have initrd available (already built)
$ make-kpkg clean $ fakeroot make-kpkg --initrd --revision=custom.1.0 kernel_image
The process will end with adding the associated package to the kernel image, which we will finally be able to install:
# dpkg -i ../linux-image-2.6.x_custom.1.0_i386.deb
In this section, we will also add another peculiarity to be taken into consideration in Debian, which is the existence of utilities for adding dynamic kernel modules provided by third parties. In particular, the module-assistant utility helps to automate this process on the basis of the module sources.
We need to have the headers of the kernel installed (package linux-headers-version) or the sources we use for compiling the kernel. As of here, the module-assistant can be used interactively, allowing us to select from an extensive list of previously registered modules in the application, and it can be responsible for downloading the module, compiling it and installing it in the existing kernel.
Also from the command line, we can simply specify (m-a is equivalent to module-assistant):
# m-a prepare # m-a auto-install module_name
which prepares the system for possible dependencies, downloads the module sources, compiles them and, if there are no problems, installs them for the current kernel. We can see the name of the module on the interactive list of the module assistant.