I Need to Build a Custom Kernel
Created by RalphAngenendt. Currently maintained by AlanBartlett and AkemiYagi.
Contents
- Are you sure? CentOS is designed to function as a complete environment. If you replace a critical component, it may very well affect how the rest of the system acts.
ARE YOU ABSOLUTELY SURE? Seriously, 99.9% of users no longer need to rebuild their own kernel. You may simply need to build a kernel module, in which case just see Build Your Own Kernel Modules.
- Is the functionality you need available as a separate module to the current kernel?
Is the functionality you need in the plus kernel located in The CentOSPlus Repository?
Last warning . . . If you break the kernel, or your system, you get to keep it and, as a bonus, you get to keep all the pieces & the associated crying about how your system doesn't boot.
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 primarily for CentOS-5. Look out for the
sign for notes regarding the building of other versions of CentOS kernels.
(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 maintainance. |
1. Build preparations
To be able to perform a successful kernel build, you will need to install the following packages:
yum groupinstall "Development Tools" # This will ensure that you have all the required tools for the build.
yum install hmaccalc # This is required to supply the tools which can calculate HMAC values for files.
yum install ncurses-devel # This is required to enable a make *config command to execute correctly.
yum install qt-devel # This is only necessary if you wish to use make xconfig instead of make gconfig or make menuconfig.
The full kernel source tree. Follow the instructions in Section 2 of I Need the Kernel Source.
If you have any kernel patches to add, copy them to the SOURCES directory now.
2. Configuring the kernel
If building a CentOS-4 kernel, replace 2.6.18 with 2.6.9 throughout the rest of this tutorial and omit the ".`uname -m`" component from the directory name in this section.
|
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-2.6.18/linux-2.6.18.`uname -m`/configs/* ~/rpmbuild/SOURCES |
|
With the buildroot correctly set up, it's time to modify the kernel configuration. Change directory to ~/rpmbuild/BUILD/kernel-2.6.18/linux-2.6.18.`uname -m`/ and copy either the appropriate type of configuration file (base, xen; if 32-bit architecture, PAE (for CentOS-5) or base, smp, xenU; if 32-bit architecture, hugemen; if 64-bit architecture, largesmp (for CentOS-4)) from the ./configs/ directory or that of the currently running kernel from /boot/config-`uname -r` to the .config file in this directory.
See the example below:
[user@host]$ cd ~/rpmbuild/BUILD/kernel-2.6.18/linux-2.6.18.`uname -m` [user@host]$ cp configs/kernel-2.6.18-`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 configuration 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. (
This step is not required for CentOS-4 kernels.)
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.18-`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 kABI 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 kABI 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
Or it should be a simple process. Unfortunately, for all kernels >= 2.6.18-92.el5, a modification to the kabitool file has exposed a latent error in the kernel specification file. This error has been acknowledged upstream (bz456765) and should eventually be corrected -- perhaps with the release of update five (CentOS 5.5).
Until that correction takes place, kernel builders who need to disable kABI checking will have to perform two extra steps when editing the kernel configuration file. Those two steps are clearly noted in the following section of this tutorial.
4. Modifying the kernel specification file
|
The line numbers mentioned in this section relate to the current CentOS-5 kernel specification file only. |
|
Now you will need to modify the kernel specification file.
[user@host]$ cd ~/rpmbuild/SPECS [user@host SPECS]$ cp kernel-2.6.spec kernel-2.6.spec.distro [user@host SPECS]$ vi kernel-2.6.spec
At line 73, the definition of buildid is commented out. This must be uncommented and given a value to avoid a conflict with your currently installed kernel. Change the line in similar manner to the example below:
%define buildid .your_identifier
|
There should be no space between the "%" and the word "define". |
|
Starting at line 8571, there is a block of code that has to be commented out. This block of code begins with the statement #if a rhel kernel, apply the rhel config options. Comment out the following 25 lines to build customised CentOS-5 kernels (
This step is not required to build customised CentOS-4 kernels.):
#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
Due to errors in the kernel specification file (that have yet to be corrected upstream), you will need to make the following two corrections. This is only necessary when kABI checking needs to be disabled with kernels >= 2.6.18-92.el5. Please see Section 3 for more details.
Go to line 8940 where you will see a block of code that begins with the statement # Create the kABI metadata for use in packing:
# Create the kABI metadata for use in packaging
echo "**** GENERATING kernel ABI metadata ****"
gzip -c9 < Module.symvers > $RPM_BUILD_ROOT/boot/symvers-$KernelVer.gz
chmod 0755 %_sourcedir/kabitool
if [ ! -e $RPM_SOURCE_DIR/kabi_whitelist_%{_target_cpu}$Flavour ]; then
echo "**** No KABI whitelist was available during build ****"
%_sourcedir/kabitool -b $RPM_BUILD_ROOT/$DevelDir -k $KernelVer -l $RPM_BUILD_ROOT/kabi_whitelist
else
cp $RPM_SOURCE_DIR/kabi_whitelist_%{_target_cpu}$Flavour $RPM_BUILD_ROOT/kabi_whitelist
fi
rm -f %{_tmppath}/kernel-$KernelVer-kabideps
%_sourcedir/kabitool -b . -d %{_tmppath}/kernel-$KernelVer-kabideps -k $KernelVer -w $RPM_BUILD_ROOT/kabi_whitelist
%if %{with_kabichk}
echo "**** kABI checking is enabled in kernel SPEC file. ****"
chmod 0755 $RPM_SOURCE_DIR/check-kabi
if [ -e $RPM_SOURCE_DIR/Module.kabi_%{_target_cpu}$Flavour ]; then
cp $RPM_SOURCE_DIR/Module.kabi_%{_target_cpu}$Flavour $RPM_BUILD_ROOT/Module.kabi
$RPM_SOURCE_DIR/check-kabi -k $RPM_BUILD_ROOT/Module.kabi -s Module.symvers || exit 1
else
echo "**** NOTE: Cannot find reference Module.kabi file. ****"
fi
%endif
Edit it so that the original 23 lines are changed to become the following 24 lines:
# Create the kABI metadata for use in packaging
echo "**** GENERATING kernel ABI metadata ****"
gzip -c9 < Module.symvers > $RPM_BUILD_ROOT/boot/symvers-$KernelVer.gz
%if %{with_kabichk}
chmod 0755 %_sourcedir/kabitool
if [ ! -e $RPM_SOURCE_DIR/kabi_whitelist_%{_target_cpu}$Flavour ]; then
echo "**** No KABI whitelist was available during build ****"
%_sourcedir/kabitool -b $RPM_BUILD_ROOT/$DevelDir -k $KernelVer -l $RPM_BUILD_ROOT/kabi_whitelist
else
cp $RPM_SOURCE_DIR/kabi_whitelist_%{_target_cpu}$Flavour $RPM_BUILD_ROOT/kabi_whitelist
fi
rm -f %{_tmppath}/kernel-$KernelVer-kabideps
%_sourcedir/kabitool -b . -d %{_tmppath}/kernel-$KernelVer-kabideps -k $KernelVer -w $RPM_BUILD_ROOT/kabi_whitelist
echo "**** kABI checking is enabled in kernel SPEC file. ****"
chmod 0755 $RPM_SOURCE_DIR/check-kabi
if [ -e $RPM_SOURCE_DIR/Module.kabi_%{_target_cpu}$Flavour ]; then
cp $RPM_SOURCE_DIR/Module.kabi_%{_target_cpu}$Flavour $RPM_BUILD_ROOT/Module.kabi
$RPM_SOURCE_DIR/check-kabi -k $RPM_BUILD_ROOT/Module.kabi -s Module.symvers || exit 1
else
echo "**** NOTE: Cannot find reference Module.kabi file. ****"
fi
%endif
touch %{_tmppath}/kernel-$KernelVer-kabideps
Go to line 8980 where you will see a block of code that begins with the statement # first copy everything:
# first copy everything
cp --parents `find -type f -name "Makefile*" -o -name "Kconfig*"` $RPM_BUILD_ROOT/lib/modules/$KernelVer/build
cp Module.symvers $RPM_BUILD_ROOT/lib/modules/$KernelVer/build
cp Module.markers $RPM_BUILD_ROOT/lib/modules/$KernelVer/build
mv $RPM_BUILD_ROOT/kabi_whitelist $RPM_BUILD_ROOT/lib/modules/$KernelVer/build
if [ -e $RPM_BUILD_ROOT/Module.kabi ]; then
mv $RPM_BUILD_ROOT/Module.kabi $RPM_BUILD_ROOT/lib/modules/$KernelVer/build
fi
cp symsets-$KernelVer.tar.gz $RPM_BUILD_ROOT/lib/modules/$KernelVer/build
# then drop all but the needed Makefiles/Kconfig files
Edit it so that the original 10 lines are changed to become the following 12 lines:
# first copy everything
cp --parents `find -type f -name "Makefile*" -o -name "Kconfig*"` $RPM_BUILD_ROOT/lib/modules/$KernelVer/build
cp Module.symvers $RPM_BUILD_ROOT/lib/modules/$KernelVer/build
cp Module.markers $RPM_BUILD_ROOT/lib/modules/$KernelVer/build
%if %{with_kabichk}
mv $RPM_BUILD_ROOT/kabi_whitelist $RPM_BUILD_ROOT/lib/modules/$KernelVer/build
if [ -e $RPM_BUILD_ROOT/Module.kabi ]; then
mv $RPM_BUILD_ROOT/Module.kabi $RPM_BUILD_ROOT/lib/modules/$KernelVer/build
fi
cp symsets-$KernelVer.tar.gz $RPM_BUILD_ROOT/lib/modules/$KernelVer/build
%endif
# then drop all but the needed Makefiles/Kconfig files
Finally, if you have any patches to apply, you need to make reference to them by adding two lines for each patch. After line 4354, which should be near the end of the patch declarations, 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
After line 8547 add the line to apply your patch. All you need to do is add is the patch number you declared earlier and rpmbuild will automagically apply it for you. For example:
%patch40000 -p1
5. Building the new kernel
Start the build:
[user@host SPECS]$ rpmbuild -bb --target=`uname -m` kernel-2.6.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 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
To build just the xen kernel packages use:
--with xenonly --without debug --without debuginfo
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 a 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 a 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.
