I Need to Build a Custom Kernel

Created by RalphAngenendt. Currently maintained by AlanBartlett and AkemiYagi.

/!\ This page is currently being revised to incorporate the appropriate details for CentOS 7.

There are two ways to build a custom kernel for CentOS. One is to build a kernel with custom options from the CentOS sources and the other is to build a mainline kernel using sources obtained from The Linux Kernel Archive.

This tutorial will cover the building of a kernel from the CentOS sources with your own options or modifications. It is written for CentOS-6. Look out for the <!> sign, for notes regarding the building of kernels for the earlier version of CentOS.

(If you wish to build a mainline kernel, do not follow How To Compile A Kernel. That site is not endorsed, as it details building as root which is unsafe and flawed in its approach. See Building Source RPM as non-root under CentOS for the detailed reasoning. A good reference for building a mainline kernel is the book Linux Kernel in a Nutshell.)

These actions are for your own personal use. Custom kernels are not supported by the development team as they have no control over your build environment, the options chosen, etc. If you choose to build your own kernel, you will be responsible for continuing to maintain it for security updates, new releases, the second coming of $DEITY and any other possible scenario which may warrant such maintenance.


NOTE: If you would like to see a real world example of a custom kernel, get one of the srpm packages for the centosplus kernel. For example, you can find one for CentOS 6.6 here.

1. Build preparations

To be able to perform a successful kernel build, you will need to install the following packages:

Whist running the above yum commands note if there are any exclude references. If there are any 'exclude' lines referring to the kernel and related packages in the yum configuration files, they will also need to be removed. One should understand that while the CentOS project does not endorse using such excludes, some vendors do not permit user modified kernels to run in their supported environment. For more details on this topic, see Section 3, Broken Virtual Server CentOS wiki article. Note that it is always wise to have a current and tested backup of any content which you are not willing to lose.

If you have any kernel patches to add, copy them to your ~/rpmbuild/SOURCES/ directory now.

2. Configuring the kernel

<!> If building a custom kernel for CentOS-5, replace 2.6.32 with 2.6.18 throughout the rest of this tutorial.

If you you do not intend to modify the distributed kernel configuration file you may omit this section, as long as you perform the equivalent of the final step:

[user@host] $ cp ~/rpmbuild/BUILD/kernel-*/linux-*/configs/* ~/rpmbuild/SOURCES/

Change directory to ~/rpmbuild/BUILD/kernel-*/linux-*/ and copy into this directory, as .config, one of two files:

Either the appropriate type of configuration file, from the configs/ directory:

Or the currently running kernel's configuration file, from the /boot/ directory.

See the example below:

[user@host]$ cd ~/rpmbuild/BUILD/kernel-*/linux-*/

Either -

[user@host]$ cp configs/kernel-2.6.32-`uname -m`[-type].config .config

- or -

[user@host]$ cp /boot/config-`uname -r` .config

First run make oldconfig. Now you should run either make menuconfig, make gconfig or make xconfig to customize the kernel configuration. Once complete, remember to save your changes.

If you have installed the full kernel source to build a kernel module, you should stop at this point. Now please refer to the Build Your Own Kernel Modules tutorial.

Next, add a line that contains the commented out equivalent of the hardware platform to the top of the configuration file (equivalent to the output returned by a uname -i command) just before you copy it back to the configs/ directory. This will either be i386 for the 32-bit architecture or x86_64 for the 64-bit architecture. It needs to be commented out with a # and must be the first line of the file. Note that there must be a space between the hash symbol and the hardware platform descriptor.

Add, as the first line of the .config file, either:

# i386

- or -

# x86_64

Copy the .config file back to the configs/ directory. This is basically the opposite of the earlier copy command:

[user@host]$ cp .config configs/kernel-2.6.32-`uname -m`[-type].config

The final step is to copy the entire contents of the configs/ directory to the ~/rpmbuild/SOURCES/ directory.

[user@host]$ cp configs/* ~/rpmbuild/SOURCES/

3. The kernel ABI

One feature of the CentOS kernel is that its ABI will be preserved for the entire life of the product and an advantage of having a consistent ABI is that external kernel modules can be built which are independent of the kernel version -- hence they do not need to be rebuilt for each new kernel released. This is the basis of the kABI tracking kmod package -- to provide updated device drivers and other file system support, for example.

To maintain this ABI consistency, the original kernel's ABI was recorded and stored in a file. This file is used during the kABI checking step for each new kernel being built. If the new kernel has been configured or modified in such a way that it is at variance with the published ABI, the build will fail with a message indicating that kABI breakage has occurred. The kernel builder will then have two choices: (a) re-configure the new kernel so that it does agree with the published ABI and, hence, continue to enjoy the benefits that a consistent ABI provides or (b) disable kABI checking during the build process. Of the two choices, the former is desired but, just occasionally, the latter is the only way to proceed.

Disabling the kernel ABI checking is a simple process of supplying a flag and its argument on the rpmbuild command line:

--without kabichk

4. Modifying the kernel specification file

The kernel specification file should now be modified.

The line numbers mentioned in this section relate to the current CentOS kernel specification files only.

[user@host]$ cd ~/rpmbuild/SPECS/
[user@host SPECS]$ cp kernel.spec kernel.spec.distro
[user@host SPECS]$ vi kernel.spec

At line 18, the definition of buildid is commented out. <!> At line 74, for CentOS-5.

This must be uncommented and given a value to avoid a conflict with your currently installed kernel. Change the line in a similar manner to the example below:

%define buildid .your_identifier

There should be no space between the "%" and the word "define".

If you have any patches to apply, you need to make reference to them in two places.

Firstly, just before line 613 (which reads "# empty final patch file to facilitate testing of kernel patches"), add your declaration starting with the number 40000, so that your patch is not in any danger of conflicting with the RHEL/CentOS kernel patch space. For example:

Patch40000: my-custom-kernel.patch

<!> Just before line 428, for CentOS-5.

Secondly, just before line 935 (which reads, "ApplyOptionalPatch linux-kernel-test.patch"), add a line to apply your patch. For example:

ApplyOptionalPatch my-custom-kernel.patch

<!> Just before line 685, for CentOS-5, add a line to apply your patch. For example:

%patch40000 -p1

Replace line 929:

cp $RPM_SOURCE_DIR/config-* .

with:

cp $RPM_SOURCE_DIR/kernel-*.config .

<!> The above is not applicable for CentOS-5.

Comment out line 933:

#make -f %{SOURCE20} VERSION=%{version} configs

<!> The above is not applicable for CentOS-5.

<!> The following modification is necessary for CentOS-5. After line 698, there is a block of 25 lines of code that needs to be commented out:

#if a rhel kernel, apply the rhel config options
#%if 0%{?rhel}
#  for i in %{all_arch_configs}
#  do
#    mv $i $i.tmp
#    $RPM_SOURCE_DIR/merge.pl $RPM_SOURCE_DIR/config-rhel-generic $i.tmp > $i
#    rm $i.tmp
#  done
#%ifarch x86_64 noarch
#  for i in kernel-%{kversion}-x86_64*.config
#  do
#    mv $i $i.tmp
#    $RPM_SOURCE_DIR/merge.pl $RPM_SOURCE_DIR/config-rhel-x86_64-generic $i.tmp > $i
#    rm $i.tmp
#  done
#%endif
#%ifarch ppc64 noarch
#  #CONFIG_FB_MATROX is disabled for rhel generic but needed for ppc64 rhel
#  for i in kernel-%{kversion}-ppc64.config
#  do
#    mv $i $i.tmp
#    $RPM_SOURCE_DIR/merge.pl $RPM_SOURCE_DIR/config-rhel-ppc64-generic $i.tmp > $i
#    rm $i.tmp
#  done
#%endif
#%endif

5. Building the new kernel

Start the build:

[user@host SPECS]$ rpmbuild -bb --target=`uname -m` kernel.spec 2> build-err.log | tee build-out.log

For kernels >= 2.6.18-53.el5, you can add some useful options to the rpmbuild command by using the --with and/or --without flags and associated arguments. The main options to note are:

--with baseonly
--with xenonly
--without up
--without xen
--without debug
--without debuginfo
--without fips
--without kabichk

For example, to build just the base kernel packages use:

--with baseonly --without debug --without debuginfo

<!> For CentOS-5 only. To build just the xen kernel packages use:

--with xenonly --without debug --without debuginfo

<!> For CentOS-5 only. To build just the PAE kernel packages use:

--without up --without xen --without debug --without debuginfo

When the build completes, your custom kernel rpm files will be found in the ~/rpmbuild/RPMS/`uname -m`/ directory. Make sure that you install those files, as root, using an rpm -ivh kernel-*.rpm command. Note: If you have built a kernel version that is older than a currently installed version you will also have to use the --oldpackage flag with the rpm command.

UNDER NO CIRCUMSTANCES use an rpm -Uvh command to install your kernel as this will update (overwrite) the currently installed version. Hence if you have a problem with your custom kernel, you will not be able to revert to the previous, working, version.

HowTos/Custom Kernel (last edited 2014-12-15 22:46:38 by AlanBartlett)