Chapter 28. the Linux kernel

Table of Contents

about the Linux kernel
kernel versions
uname -r
/proc/cmdline
single user mode
init=/bin/bash
/var/log/messages
dmesg
Linux kernel source
ftp.kernel.org
/usr/src
downloading the kernel source
kernel boot files
vmlinuz
initrd
System.map
.config
Linux kernel modules
about kernel modules
/lib/modules
<module>.ko
lsmod
/proc/modules
module dependencies
insmod
modinfo
modprobe
/lib/modules/<kernel>/modules.dep
depmod
rmmod
modprobe -r
/etc/modprobe.conf
compiling a kernel
extraversion
make mrproper
.config
make menuconfig
make clean
make bzImage
make modules
make modules_install
/boot
mkinitrd
bootloader
compiling one module
hello.c
Makefile
make
hello.ko

about the Linux kernel

kernel versions

In 1991 Linux Torvalds wrote (the first version of) the Linux kernel. He put it online, and other people started contributing code. Over 4000 individuals contributed source code to the latest kernel release (version 2.6.27 in November 2008).

Major Linux kernel versions used to come in even and odd numbers. Versions 2.0, 2.2, 2.4 and 2.6 are considered stable kernel versions. Whereas 2.1, 2.3 and 2.5 were unstable (read development) versions. Since the release of 2.6.0 in January 2004, all development has been done in the 2.6 tree. There is currently no v2.7.x and according to Linus the even/stable vs odd/development scheme is abandoned forever.

uname -r

To see your current Linux kernel version, issue the uname -r command as shown below.

This first example shows Linux major version 2.6 and minor version 24. The rest -22-generic is specific to the distribution (Ubuntu in this case).

paul@laika:~$ uname -r
2.6.24-22-generic

The same command on Red Hat Enterprise Linux shows an older kernel (2.6.18) with -92.1.17.el5 being specific to the distribution.

[paul@RHEL52 ~]$ uname -r
2.6.18-92.1.17.el5

/proc/cmdline

The parameters that were passed to the kernel at boot time are in /proc/cmdline.

paul@RHELv4u4:~$ cat /proc/cmdline 
ro root=/dev/VolGroup00/LogVol00 rhgb quiet

single user mode

When booting the kernel with the single parameter, it starts in single user mode. Linux can start in a bash shell with the root user logged on (without password).

Some distributions prevent the use of this feature (at kernel compile time).

init=/bin/bash

Normally the kernel invokes init as the first daemon process. Adding init=/bin/bash to the kernel parameters will instead invoke bash (again with root logged on without providing a password).

/var/log/messages

The kernel reports during boot to syslog which writes a lot of kernel actions in /var/log/messages. Looking at this file reveals when the kernel was started, including all the devices that were detected at boot time.

[root@RHEL53 ~]# grep -A16 "syslogd 1.4.1:" /var/log/messages|cut -b24-
syslogd 1.4.1: restart.
kernel: klogd 1.4.1, log source = /proc/kmsg started.
kernel: Linux version 2.6.18-128.el5 (mockbuild@hs20-bc1-5.build.red...
kernel: BIOS-provided physical RAM map:
kernel:  BIOS-e820: 0000000000000000 - 000000000009f800 (usable)
kernel:  BIOS-e820: 000000000009f800 - 00000000000a0000 (reserved)
kernel:  BIOS-e820: 00000000000ca000 - 00000000000cc000 (reserved)
kernel:  BIOS-e820: 00000000000dc000 - 0000000000100000 (reserved)
kernel:  BIOS-e820: 0000000000100000 - 000000001fef0000 (usable)
kernel:  BIOS-e820: 000000001fef0000 - 000000001feff000 (ACPI data)
kernel:  BIOS-e820: 000000001feff000 - 000000001ff00000 (ACPI NVS)
kernel:  BIOS-e820: 000000001ff00000 - 0000000020000000 (usable)
kernel:  BIOS-e820: 00000000fec00000 - 00000000fec10000 (reserved)
kernel:  BIOS-e820: 00000000fee00000 - 00000000fee01000 (reserved)
kernel:  BIOS-e820: 00000000fffe0000 - 0000000100000000 (reserved)
kernel: 0MB HIGHMEM available.
kernel: 512MB LOWMEM available.

This example shows how to use /var/log/messages to see kernel information about /dev/sda.

[root@RHEL53 ~]# grep sda /var/log/messages | cut -b24-
kernel: SCSI device sda: 41943040 512-byte hdwr sectors (21475 MB)
kernel: sda: Write Protect is off
kernel: sda: cache data unavailable
kernel: sda: assuming drive cache: write through
kernel: SCSI device sda: 41943040 512-byte hdwr sectors (21475 MB)
kernel: sda: Write Protect is off
kernel: sda: cache data unavailable
kernel: sda: assuming drive cache: write through
kernel:  sda: sda1 sda2
kernel: sd 0:0:0:0: Attached scsi disk sda
kernel: EXT3 FS on sda1, internal journal

dmesg

The dmesg command prints out all the kernel bootup messages (from the last boot).

[root@RHEL53 ~]# dmesg | head
Linux version 2.6.18-128.el5 (mockbuild@hs20-bc1-5.build.redhat.com)
BIOS-provided physical RAM map:
 BIOS-e820: 0000000000000000 - 000000000009f800 (usable)
 BIOS-e820: 000000000009f800 - 00000000000a0000 (reserved)
 BIOS-e820: 00000000000ca000 - 00000000000cc000 (reserved)
 BIOS-e820: 00000000000dc000 - 0000000000100000 (reserved)
 BIOS-e820: 0000000000100000 - 000000001fef0000 (usable)
 BIOS-e820: 000000001fef0000 - 000000001feff000 (ACPI data)
 BIOS-e820: 000000001feff000 - 000000001ff00000 (ACPI NVS)
 BIOS-e820: 000000001ff00000 - 0000000020000000 (usable)

Thus to find information about /dev/sda, using dmesg will yield only kernel messages from the last boot.

[root@RHEL53 ~]# dmesg | grep sda
SCSI device sda: 41943040 512-byte hdwr sectors (21475 MB)
sda: Write Protect is off
sda: Mode Sense: 5d 00 00 00
sda: cache data unavailable
sda: assuming drive cache: write through
SCSI device sda: 41943040 512-byte hdwr sectors (21475 MB)
sda: Write Protect is off
sda: Mode Sense: 5d 00 00 00
sda: cache data unavailable
sda: assuming drive cache: write through
 sda: sda1 sda2
sd 0:0:0:0: Attached scsi disk sda
EXT3 FS on sda1, internal journal

Linux kernel source

ftp.kernel.org

The home of the Linux kernel source is ftp.kernel.org. It contains all official releases of the Linux kernel source code from 1991. It provides free downloads over http, ftp and rsync of all these releases, as well as changelogs and patches. More information can be otained on the website www.kernel.org.

Anyone can anonymously use an ftp client to access ftp.kernel.org

paul@laika:~$ ftp ftp.kernel.org
Connected to pub3.kernel.org.
220 Welcome to ftp.kernel.org.
Name (ftp.kernel.org:paul): anonymous
331 Please specify the password.
Password:
230-			    Welcome to the
230-
230-			LINUX KERNEL ARCHIVES
230-			    ftp.kernel.org

All the Linux kernel versions are located in the pub/linux/kernel/ directory.

ftp> ls pub/linux/kernel/v*
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxrwsr-x    2 536      536          4096 Mar 20  2003 v1.0
drwxrwsr-x    2 536      536         20480 Mar 20  2003 v1.1
drwxrwsr-x    2 536      536          8192 Mar 20  2003 v1.2
drwxrwsr-x    2 536      536         40960 Mar 20  2003 v1.3
drwxrwsr-x    3 536      536         16384 Feb 08  2004 v2.0
drwxrwsr-x    2 536      536         53248 Mar 20  2003 v2.1
drwxrwsr-x    3 536      536         12288 Mar 24  2004 v2.2
drwxrwsr-x    2 536      536         24576 Mar 20  2003 v2.3
drwxrwsr-x    5 536      536         28672 Dec 02 08:14 v2.4
drwxrwsr-x    4 536      536         32768 Jul 14  2003 v2.5
drwxrwsr-x    7 536      536        110592 Dec 05 22:36 v2.6
226 Directory send OK.
ftp>

/usr/src

On your local computer, the kernel source is located in /usr/src. Note though that the structure inside /usr/src might be different depending on the distribution that you are using.

First let's take a look at /usr/src on Debian. There appear to be two versions of the complete Linux source code there. Looking for a specific file (e1000_main.c) with find reveals it's exact location.

paul@barry:~$ ls -l /usr/src/
drwxr-xr-x 20 root root     4096 2006-04-04 22:12 linux-source-2.6.15
drwxr-xr-x 19 root root     4096 2006-07-15 17:32 linux-source-2.6.16
paul@barry:~$ find /usr/src -name e1000_main.c
/usr/src/linux-source-2.6.15/drivers/net/e1000/e1000_main.c
/usr/src/linux-source-2.6.16/drivers/net/e1000/e1000_main.c

This is very similar to /usr/src on Ubuntu, except there is only one kernel here (and it is newer).

paul@laika:~$ ls -l /usr/src/
drwxr-xr-x 23 root root     4096 2008-11-24 23:28 linux-source-2.6.24
paul@laika:~$ find /usr/src -name "e1000_main.c"
/usr/src/linux-source-2.6.24/drivers/net/e1000/e1000_main.c

Now take a look at /usr/src on Red Hat Enterprise Linux.

[paul@RHEL52 ~]$ ls -l /usr/src/
drwxr-xr-x 5 root root 4096 Dec  5 19:23 kernels
drwxr-xr-x 7 root root 4096 Oct 11 13:22 redhat

We will have to dig a little deeper to find the kernel source on Red Hat!

[paul@RHEL52 ~]$ cd /usr/src/redhat/BUILD/
[paul@RHEL52 BUILD]$ find . -name "e1000_main.c"
./kernel-2.6.18/linux-2.6.18.i686/drivers/net/e1000/e1000_main.c

downloading the kernel source

Debian

Installing the kernel source on Debian is really simple with aptitude install linux-source. You can do a search for all linux-source packeges first, like in this screenshot.

root@barry:~# aptitude search linux-source
v   linux-source           -
v   linux-source-2.6       -
id  linux-source-2.6.15    - Linux kernel source for version 2.6.15
i   linux-source-2.6.16    - Linux kernel source for version 2.6.16
p   linux-source-2.6.18    - Linux kernel source for version 2.6.18
p   linux-source-2.6.24    - Linux kernel source for version 2.6.24

And then use aptitude install to download and install the Debian Linux kernel source code.

root@barry:~# aptitude install linux-source-2.6.24

When the aptitude is finished, you will see a new file named /usr/src/linux-source-<version>.tar.bz2

root@barry:/usr/src# ls -lh
drwxr-xr-x 20 root root 4.0K 2006-04-04 22:12 linux-source-2.6.15
drwxr-xr-x 19 root root 4.0K 2006-07-15 17:32 linux-source-2.6.16
-rw-r--r--  1 root root  45M 2008-12-02 10:56 linux-source-2.6.24.tar.bz2

Ubuntu

Ubuntu is based on Debian and also uses aptitude, so the task is very similar.

root@laika:~# aptitude search linux-source
i   linux-source           - Linux kernel source with Ubuntu patches
v   linux-source-2.6       -
i A linux-source-2.6.24    - Linux kernel source for version 2.6.24
root@laika:~# aptitude install linux-source

And when aptitude finishes, we end up with a /usr/src/linux-source-<version>.tar.bz file.

oot@laika:~# ll /usr/src
total 45M
-rw-r--r--  1 root root  45M 2008-11-24 23:30 linux-source-2.6.24.tar.bz2

Red Hat Enterprise Linux

The Red Hat kernel source is located on the fourth source cdrom. The file is called kernel-2.6.9-42.EL.src.rpm (example for RHELv4u4). It is also available online at ftp://ftp.redhat.com/pub/redhat/linux/enterprise/5Server/en/os/SRPMS/ (example for RHEL5).

To download the kernel source on RHEL, use this long wget command (on one line, without the trailing \).

wget ftp://ftp.redhat.com/pub/redhat/linux/enterprise/5Server/en/os/\
SRPMS/kernel-`uname -r`.src.rpm

When the wget download is finished, you end up with a 60M .rpm file.

[root@RHEL52 src]# ll
total 60M
-rw-r--r-- 1 root root  60M Dec  5 20:54 kernel-2.6.18-92.1.17.el5.src.rpm
drwxr-xr-x 5 root root 4.0K Dec  5 19:23 kernels
drwxr-xr-x 7 root root 4.0K Oct 11 13:22 redhat

We will need to perform some more steps before this can be used as kernel source code.

First, we issue the rpm -i kernel-2.6.9-42.EL.src.rpm command to install this Red Hat package.

[root@RHEL52 src]# ll
total 60M
-rw-r--r-- 1 root root  60M Dec  5 20:54 kernel-2.6.18-92.1.17.el5.src.rpm
drwxr-xr-x 5 root root 4.0K Dec  5 19:23 kernels
drwxr-xr-x 7 root root 4.0K Oct 11 13:22 redhat
[root@RHEL52 src]# rpm -i kernel-2.6.18-92.1.17.el5.src.rpm

Then we move to the SPECS directory and perform an rpmbuild.

[root@RHEL52 ~]# cd /usr/src/redhat/SPECS
[root@RHEL52 SPECS]# rpmbuild -bp -vv --target=i686 kernel-2.6.spec

The rpmbuild command put the RHEL Linux kernel source code in /usr/src/redhat/BUILD/kernel-<version>/.

[root@RHEL52 kernel-2.6.18]# pwd
/usr/src/redhat/BUILD/kernel-2.6.18
[root@RHEL52 kernel-2.6.18]# ll
total 20K
drwxr-xr-x  2 root root 4.0K Dec  6  2007 config
-rw-r--r--  1 root root 3.1K Dec  5 20:58 Config.mk
drwxr-xr-x 20 root root 4.0K Dec  5 20:58 linux-2.6.18.i686
drwxr-xr-x 19 root root 4.0K Sep 20  2006 vanilla
drwxr-xr-x  8 root root 4.0K Dec  6  2007 xen

kernel boot files

vmlinuz

The vmlinuz file in /boot is the compressed kernel.

paul@barry:~$ ls -lh /boot | grep vmlinuz
-rw-r--r-- 1 root root 1.2M 2006-03-06 16:22 vmlinuz-2.6.15-1-486
-rw-r--r-- 1 root root 1.1M 2006-03-06 16:30 vmlinuz-2.6.15-1-686
-rw-r--r-- 1 root root 1.3M 2008-02-11 00:00 vmlinuz-2.6.18-6-686
paul@barry:~$

initrd

The kernel uses initrd (an initial RAM disk) at boot time. The initrd is mounted before the kernel loads, and can contain additional drivers and modules. It is a compressed cpio archive, so you can look at the contents in this way.

root@RHELv4u4:/boot# mkdir /mnt/initrd
root@RHELv4u4:/boot# cp initrd-2.6.9-42.0.3.EL.img TMPinitrd.gz
root@RHELv4u4:/boot# gunzip TMPinitrd.gz 
root@RHELv4u4:/boot# file TMPinitrd 
TMPinitrd: ASCII cpio archive (SVR4 with no CRC)
root@RHELv4u4:/boot# cd /mnt/initrd/
root@RHELv4u4:/mnt/initrd# cpio -i | /boot/TMPinitrd 
4985 blocks
root@RHELv4u4:/mnt/initrd# ls -l
total 76
drwxr-xr-x  2 root root 4096 Feb  5 08:36 bin
drwxr-xr-x  2 root root 4096 Feb  5 08:36 dev
drwxr-xr-x  4 root root 4096 Feb  5 08:36 etc
-rwxr-xr-x  1 root root 1607 Feb  5 08:36 init
drwxr-xr-x  2 root root 4096 Feb  5 08:36 lib
drwxr-xr-x  2 root root 4096 Feb  5 08:36 loopfs
drwxr-xr-x  2 root root 4096 Feb  5 08:36 proc
lrwxrwxrwx  1 root root    3 Feb  5 08:36 sbin -> bin
drwxr-xr-x  2 root root 4096 Feb  5 08:36 sys
drwxr-xr-x  2 root root 4096 Feb  5 08:36 sysroot
root@RHELv4u4:/mnt/initrd#

System.map

The System.map contains the symbol table and changes with every kernel compile. The symbol table is also present in /proc/kallsyms (pre 2.6 kernels name this file /proc/ksyms).

root@RHELv4u4:/boot# head System.map-`uname -r`
00000400 A __kernel_vsyscall
0000041a A SYSENTER_RETURN_OFFSET
00000420 A __kernel_sigreturn
00000440 A __kernel_rt_sigreturn
c0100000 A _text
c0100000 T startup_32
c01000c6 t checkCPUtype
c0100147 t is486
c010014e t is386
c010019f t L6
root@RHELv4u4:/boot# head /proc/kallsyms 
c0100228 t _stext
c0100228 t calibrate_delay_direct
c0100228 t stext
c0100337 t calibrate_delay
c01004db t rest_init
c0100580 t do_pre_smp_initcalls
c0100585 t run_init_process
c01005ac t init
c0100789 t early_param_test
c01007ad t early_setup_test
root@RHELv4u4:/boot#

.config

The last file copied to the /boot directory is the kernel configuration used for compilation. This file is not necessary in the /boot directory, but it is common practice to put a copy there. It allows you to recompile a kernel, starting from the same configuration as an existing working one.

Linux kernel modules

about kernel modules

The Linux kernel is a monolithic kernel with loadable modules. These modules contain parts of the kernel used typically for device drivers, file systems and network protocols. Most of the time the necessary kernel modules are loaded automatically and dynamically without administrator interaction.

/lib/modules

The modules are stored in the /lib/modules/<kernel-version> directory. There is a separate directory for each kernel that was compiled for your system.

paul@laika:~$ ll /lib/modules/
total 12K
drwxr-xr-x 7 root root 4.0K 2008-11-10 14:32 2.6.24-16-generic
drwxr-xr-x 8 root root 4.0K 2008-12-06 15:39 2.6.24-21-generic
drwxr-xr-x 8 root root 4.0K 2008-12-05 12:58 2.6.24-22-generic

<module>.ko

The file containing the modules usually ends in .ko. This screenshot shows the location of the isdn module files.

paul@laika:~$ find /lib/modules -name isdn.ko
/lib/modules/2.6.24-21-generic/kernel/drivers/isdn/i4l/isdn.ko
/lib/modules/2.6.24-22-generic/kernel/drivers/isdn/i4l/isdn.ko
/lib/modules/2.6.24-16-generic/kernel/drivers/isdn/i4l/isdn.ko

lsmod

To see a list of currently loaded modules, use lsmod. You see the name of each loaded module, the size, the use count, and the names of other modules using this one.

[root@RHEL52 ~]# lsmod | head -5
Module                  Size  Used by
autofs4                24517  2 
hidp                   23105  2 
rfcomm                 42457  0 
l2cap                  29505  10 hidp,rfcomm

/proc/modules

/proc/modules lists all modules loaded by the kernel. The output would be too long to display here, so lets grep for the vm module.

We see that vmmon and vmnet are both loaded. You can display the same information with lsmod. Actually lsmod only reads and reformats the output of /proc/modules.

paul@laika:~$ cat /proc/modules | grep vm
vmnet 36896 13 - Live 0xffffffff88b21000 (P)
vmmon 194540 0 - Live 0xffffffff88af0000 (P)
paul@laika:~$ lsmod | grep vm
vmnet                  36896  13 
vmmon                 194540  0 
paul@laika:~$

module dependencies

Some modules depend on others. In the following example, you can see that the nfsd module is used by exportfs, lockd and sunrpc.

paul@laika:~$ cat /proc/modules | grep nfsd
nfsd 267432 17 - Live 0xffffffff88a40000
exportfs 7808 1 nfsd, Live 0xffffffff88a3d000
lockd 73520 3 nfs,nfsd, Live 0xffffffff88a2a000
sunrpc 185032 12 nfs,nfsd,lockd, Live 0xffffffff889fb000
paul@laika:~$ lsmod | grep nfsd
nfsd                  267432  17 
exportfs                7808  1 nfsd
lockd                  73520  3 nfs,nfsd
sunrpc                185032  12 nfs,nfsd,lockd
paul@laika:~$

insmod

Kernel modules can be manually loaded with the insmod command. This is a very simple (and obsolete) way of loading modules. The screenshot shows insmod loading the fat module (for fat file system support).

root@barry:/lib/modules/2.6.17-2-686# lsmod | grep fat
root@barry:/lib/modules/2.6.17-2-686# insmod kernel/fs/fat/fat.ko 
root@barry:/lib/modules/2.6.17-2-686# lsmod | grep fat
fat                    46588  0

insmod is not detecting dependencies, so it fails to load the isdn module (because the isdn module depends on the slhc module).

[root@RHEL52 drivers]# pwd
/lib/modules/2.6.18-92.1.18.el5/kernel/drivers
[root@RHEL52 kernel]# insmod isdn/i4l/isdn.ko 
insmod: error inserting 'isdn/i4l/isdn.ko': -1 Unknown symbol in module

modinfo

As you can see in the screenshot of modinfo below, the isdn module depends in the slhc module.

[root@RHEL52 drivers]# modinfo isdn/i4l/isdn.ko | head -6
filename:       isdn/i4l/isdn.ko
license:        GPL
author:         Fritz Elfert
description:    ISDN4Linux: link layer
srcversion:     99650346E708173496F6739
depends:        slhc

modprobe

The big advantage of modprobe over insmod is that modprobe will load all necessary modules, whereas insmod requires manual loading of dependencies. Another advantage is that you don't need to point to the filename with full path.

This screenshot shows how modprobe loads the isdn module, automatically loading slhc in background.

[root@RHEL52 kernel]# lsmod | grep isdn
[root@RHEL52 kernel]# modprobe isdn
[root@RHEL52 kernel]# lsmod | grep isdn
isdn                  122433  0 
slhc                   10561  1 isdn
[root@RHEL52 kernel]#

/lib/modules/<kernel>/modules.dep

Module dependencies are stored in modules.dep.

[root@RHEL52 2.6.18-92.1.18.el5]# pwd
/lib/modules/2.6.18-92.1.18.el5
[root@RHEL52 2.6.18-92.1.18.el5]# head -3 modules.dep 
/lib/modules/2.6.18-92.1.18.el5/kernel/drivers/net/tokenring/3c359.ko:
/lib/modules/2.6.18-92.1.18.el5/kernel/drivers/net/pcmcia/3c574_cs.ko:
/lib/modules/2.6.18-92.1.18.el5/kernel/drivers/net/pcmcia/3c589_cs.ko:

depmod

The modules.dep file can be updated (recreated) with the depmod command. In this screenshot no modules were added, so depmod generates the same file.

root@barry:/lib/modules/2.6.17-2-686# ls -l modules.dep 
-rw-r--r-- 1 root root 310676 2008-03-01 16:32 modules.dep
root@barry:/lib/modules/2.6.17-2-686# depmod
root@barry:/lib/modules/2.6.17-2-686# ls -l modules.dep 
-rw-r--r-- 1 root root 310676 2008-12-07 13:54 modules.dep

rmmod

Similar to insmod, the rmmod command is rarely used anymore.

[root@RHELv4u3 ~]# modprobe isdn
[root@RHELv4u3 ~]# rmmod slhc
ERROR: Module slhc is in use by isdn
[root@RHELv4u3 ~]# rmmod isdn
[root@RHELv4u3 ~]# rmmod slhc
[root@RHELv4u3 ~]# lsmod | grep isdn
[root@RHELv4u3 ~]#

modprobe -r

Contrary to rmmod, modprobe will automatically remove unneeded modules.

[root@RHELv4u3 ~]# modprobe isdn
[root@RHELv4u3 ~]# lsmod | grep isdn
isdn                  133537  0 
slhc                    7233  1 isdn
[root@RHELv4u3 ~]# modprobe -r isdn
[root@RHELv4u3 ~]# lsmod | grep isdn
[root@RHELv4u3 ~]# lsmod | grep slhc
[root@RHELv4u3 ~]#

/etc/modprobe.conf

The /etc/modprobe.conf file and the /etc/modprobe.d directory can contain aliases (used by humans) and options (for dependent modules) for modprobe.

[root@RHEL52 ~]# cat /etc/modprobe.conf
alias scsi_hostadapter mptbase
alias scsi_hostadapter1 mptspi
alias scsi_hostadapter2 ata_piix
alias eth0 pcnet32
alias eth2 pcnet32
alias eth1 pcnet32

compiling a kernel

extraversion

Enter into /usr/src/redhat/BUILD/kernel-2.6.9/linux-2.6.9/ and change the extraversion in the Makefile.

[root@RHEL52 linux-2.6.18.i686]# pwd
/usr/src/redhat/BUILD/kernel-2.6.18/linux-2.6.18.i686
[root@RHEL52 linux-2.6.18.i686]# vi Makefile 
[root@RHEL52 linux-2.6.18.i686]# head -4 Makefile 
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 18
EXTRAVERSION = -paul2008

make mrproper

Now clean up the source from any previous installs with make mrproper. If this is your first after downloading the source code, then this is not needed.

[root@RHEL52 linux-2.6.18.i686]# make mrproper
  CLEAN   scripts/basic
  CLEAN   scripts/kconfig
  CLEAN   include/config
  CLEAN   .config .config.old

.config

Now copy a working .config from /boot to our kernel directory. This file contains the configuration that was used for your current working kernel. It determines whether modules are included in compilation or not.

[root@RHEL52 linux-2.6.18.i686]# cp /boot/config-2.6.18-92.1.18.el5 .config

make menuconfig

Now run make menuconfig (or the graphical make xconfig). This tool allows you to select whether to compile stuff as a module (m), as part of the kernel (*), or not at all (smaller kernel size). If you remove too much, your kernel will not work. The configuration will be stored in the hidden .config file.

[root@RHEL52 linux-2.6.18.i686]# make menuconfig

make clean

Issue a make clean to prepare the kernel for compile. make clean will remove most generated files, but keeps your kernel configuration. Running a make mrproper at this point would destroy the .config file that you built with make menuconfig.

[root@RHEL52 linux-2.6.18.i686]# make clean

make bzImage

And then run make bzImage, sit back and relax while the kernel compiles. You can use time make bzImage to know how long it takes to compile, so next time you can go for a short walk.

[root@RHEL52 linux-2.6.18.i686]# time make bzImage
  HOSTCC  scripts/basic/fixdep
  HOSTCC  scripts/basic/docproc
  HOSTCC  scripts/kconfig/conf.o
  HOSTCC  scripts/kconfig/kxgettext.o
... 

This command will end with telling you the location of the bzImage file (and with time info if you also specified the time command.

Kernel: arch/i386/boot/bzImage is ready  (#1)

real	13m59.573s
user	1m22.631s
sys	11m51.034s
[root@RHEL52 linux-2.6.18.i686]#

You can already copy this image to /boot with cp arch/i386/boot/bzImage /boot/vmlinuz-<kernel-version>.

make modules

Now run make modules. It can take 20 to 50 minutes to compile all the modules.

[root@RHEL52 linux-2.6.18.i686]# time make modules
  CHK     include/linux/version.h
  CHK     include/linux/utsrelease.h
  CC [M]  arch/i386/kernel/msr.o
  CC [M]  arch/i386/kernel/cpuid.o
  CC [M]  arch/i386/kernel/microcode.o

make modules_install

To copy all the compiled modules to /lib/modules just run make modules_install (takes about 20 seconds). Here's a screenshot from before the command.

[root@RHEL52 linux-2.6.18.i686]# ls -l /lib/modules/
total 20
drwxr-xr-x 6 root root 4096 Oct 15 13:09 2.6.18-92.1.13.el5
drwxr-xr-x 6 root root 4096 Nov 11 08:51 2.6.18-92.1.17.el5
drwxr-xr-x 6 root root 4096 Dec  6 07:11 2.6.18-92.1.18.el5
[root@RHEL52 linux-2.6.18.i686]# make modules_install

And here is the same directory after. Notice that make modules_install created a new directory for the new kernel.

[root@RHEL52 linux-2.6.18.i686]# ls -l /lib/modules/
total 24
drwxr-xr-x 6 root root 4096 Oct 15 13:09 2.6.18-92.1.13.el5
drwxr-xr-x 6 root root 4096 Nov 11 08:51 2.6.18-92.1.17.el5
drwxr-xr-x 6 root root 4096 Dec  6 07:11 2.6.18-92.1.18.el5
drwxr-xr-x 3 root root 4096 Dec  6 08:50 2.6.18-paul2008

/boot

We still need to copy the kernel, the System.map and our configuration file to /boot. Strictly speaking the .config file is not obligatory, but it might help you in future compilations of the kernel.

[root@RHEL52 ]# pwd
/usr/src/redhat/BUILD/kernel-2.6.18/linux-2.6.18.i686
[root@RHEL52 ]# cp System.map /boot/System.map-2.6.18-paul2008
[root@RHEL52 ]# cp .config /boot/config-2.6.18-paul2008
[root@RHEL52 ]# cp arch/i386/boot/bzImage /boot/vmlinuz-2.6.18-paul2008

mkinitrd

The kernel often uses an initrd file at bootup. We can use mkinitrd to generate this file. Make sure you use the correct kernel name!

[root@RHEL52 ]# pwd
/usr/src/redhat/BUILD/kernel-2.6.18/linux-2.6.18.i686
[root@RHEL52 ]# mkinitrd /boot/initrd-2.6.18-paul2008 2.6.18-paul2008

bootloader

Compilation is now finished, don't forget to create an additional stanza in grub or lilo.

compiling one module

hello.c

A little C program that will be our module.

[root@rhel4a kernel_module]# cat hello.c 
#include <linux/module.h>
#include <section>
			
int init_module(void)
{
	printk(KERN_INFO "Start Hello World...\n");
	return 0;
}
			
void cleanup_module(void)
{
	printk(KERN_INFO "End Hello World... \n");
}

Makefile

The make file for this module.

[root@rhel4a kernel_module]# cat Makefile 
obj-m += hello.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

These are the only two files needed.

[root@rhel4a kernel_module]# ll
total 16
-rw-rw-r--  1 paul paul 250 Feb 15 19:14 hello.c
-rw-rw-r--  1 paul paul 153 Feb 15 19:15 Makefile

make

The running of the make command.

[root@rhel4a kernel_module]# make
make -C /lib/modules/2.6.9-paul-2/build M=~/kernel_module modules
make[1]: Entering dir... `/usr/src/redhat/BUILD/kernel-2.6.9/linux-2.6.9'
CC [M]  /data/sites/web/cobbautbe/subsites/kernel_module/hello.o
Building modules, stage 2.
MODPOST
CC      /data/sites/web/cobbautbe/subsites/kernel_module/hello.mod.o
LD [M]  /data/sites/web/cobbautbe/subsites/kernel_module/hello.ko
make[1]: Leaving dir... `/usr/src/redhat/BUILD/kernel-2.6.9/linux-2.6.9'
[root@rhel4a kernel_module]#

Now we have more files.

[root@rhel4a kernel_module]# ll
total 172
-rw-rw-r--  1 paul paul   250 Feb 15 19:14 hello.c
-rw-r--r--  1 root root 64475 Feb 15 19:15 hello.ko
-rw-r--r--  1 root root   632 Feb 15 19:15 hello.mod.c
-rw-r--r--  1 root root 37036 Feb 15 19:15 hello.mod.o
-rw-r--r--  1 root root 28396 Feb 15 19:15 hello.o
-rw-rw-r--  1 paul paul   153 Feb 15 19:15 Makefile
[root@rhel4a kernel_module]#

hello.ko

Use modinfo to verify that it is really a module.

[root@rhel4a kernel_module]# modinfo hello.ko 
filename:       hello.ko
vermagic:       2.6.9-paul-2 SMP 686 REGPARM 4KSTACKS gcc-3.4
depends:        
[root@rhel4a kernel_module]#

Good, so now we can load our hello module.

[root@rhel4a kernel_module]# lsmod | grep hello
[root@rhel4a kernel_module]# insmod ./hello.ko
[root@rhel4a kernel_module]# lsmod | grep hello
hello                   5504  0 
[root@rhel4a kernel_module]# tail -1 /var/log/messages 
Feb 15 19:16:07 rhel4a kernel: Start Hello World...
[root@rhel4a kernel_module]# rmmod hello
[root@rhel4a kernel_module]#

Finally /var/log/messages has a little surprise.

[root@rhel4a kernel_module]# tail -2 /var/log/messages 
Feb 15 19:16:07 rhel4a kernel: Start Hello World...
Feb 15 19:16:35 rhel4a kernel: End Hello World... 
[root@rhel4a kernel_module]#