Building the Linux Kernel

You need a computer to build a kernel

The first requirement to build a Linux kernel is to have a computer. For this class, we do have a lab computer at your disposal. Meaning that you are free to install a new copy of Linux on the machine, it is not being used by other classes. Multiple kernel builds can coexist on a single machine, and be selected at boot. How this works is that the /boot directory has all the bootable images. Carefully give them different names than the ones there. The file /boot/grub/menu.lst has to be edited to point to the kernel, as well as the initrd file. Also, a copy of the config file that built the kernel is placed in /boot, for future reference.

You can also use your own machine for this class. You can dedicate your machine to linux, or you can dual boot your machine. If you run windows, you will have to partition and dual boot. There is a slight problem with multiple kernels on a machine. Sometimes all of the kernel is not in the kernel. Linux lets you have multiple kernels and modules. But sometimes you might have to edit some header file, for a library. And in that case, you will be modifying a file used by all kernels.

A third method have getting a computer is to run a virtual machine on your computer, and install linux inside that virtual machine. You boot that image, and work on that image to build a custom and hacked kernel. This is my favorite way. Two free VM's for you are Virtual Box by Sun and VMWare 2. Begin by installing the VM software, installing a copy of linux, and then follow the build instructions from there.

Preliminaries.

To build the linux kernel, you must,

  1. install additional software,
  2. download kernel sources,
  3. configure the build,
  4. build kernel and modules,
  5. install kernel and modules,
  6. create initrd and modify bootloader options,
  7. and reboot.

Sources, random package installs

The kernel sources are at www.kernel.org. Identify the appropriate release, such as 2.6.17 and use wget to get the compressed tar file.
    ? cd /usr/src
    ? wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.17.tar.gz
    ? tar xzvf linux-2.6.17.tar.gz
After this you should have the sources in the Right Place for a build, which is, /usr/src/<revision>.

As of August 2009, the source was linux-2.6.30.5.tar.bz2. For bz2 compressed tarballs, use the j, rather than that z option, on the tar command.

If you have installed a minimal Linux system on which to do this build, you do not have enough of a system to continue the build. You need gcc, the gnu compiler, and ncurses, a package for menu display on a terminal (this is needed to build the configuration file). Use yum to download and install these packages.

    ? yum install gcc.i386
    ? yum install ncurses.i386
    ? yum install ncurses-devel.i386

On Ubuntu, apt-get install replaces yum. I needed:

    ? apt-get install libncurses5-dev
in order to do menuconfig.

Configure

The build is done from the /usr/src/<revision> directory. First, edit the Makefile to add something like -myname to the end of the line EXTRAVERSION =. This means that the kernel, its configuration, the modules subdirectory, all will be named <revision>-myname.

Note: The command uname is useful to figure out the name of a running kernel. Option uname -a should give the full kernel name, and uname -r gives just the revision number. Use this command to figure you what kernel is running on a system.

After editing the Makefile, you need to create a .config file. This is the hardest part. If you can find a configuration file that works, start with that. For reasons that I don't understand, you can't just copy a configuration to .config in this directory, and there doesn't seem to be an easy tool to do this from the command line.

   ? make menuconfig
But you can use the make target menuconfig to do this, and then going to the bottom of the presented menu, find load configuration file. Choosing this, point to the configuration file that works, enter, and exit, saving. Now .config is a copy of the working configuration, and whatever other magic had to occur has occured.

You can now build.

Build

From the build directory do make.
    ? make 
Now two things will happen. The kernel will be built, and the modules will be built.

As of August 2009, I just took the defaults and the build took 4 hours on a 2.4GHz Intel Core 2 Duo MacBook, 10.5.8, running linux in Virtual Box.

Installation

The kernel and modules must be moved to special locations in order to be used,
    ? make modules_install
    ? make install
The first will create the /lib/modules/<revision> directory and place the modules there. The second make target will,
  1. Move the kernel, bzImage, to /boot and rename it vmlinuz-<revision>,
  2. Move the System.map to /boot,
  3. Create initrd.img-<revision>
  4. Copy .config to /boot, renaming it to config-<revision>
  5. Modifies the boot loader configuration file /boot/grub/menu.lst so that the new kernel is listed on the boot menu.
However, things sometimes work differently. On 2.6.17 the config file isn't copied and renamed. In other cases, the initrd image is not created automatically.

Initrd

Initrd is a temporary filesystem used just in the early stage of the boot. It is immediately swaped out for the real filesystem as soon as the kernel has been sufficiently assembled from modules to support the real filesystem. If it isn't created, well, that's going to cause some suffering. On Debian, try,

    ? mkinitrd -o /boot/initrd.img-<revision> <revision>
On other Linux variants, you don't need the -o option. It seems that you must name the img file absolutely, with the starting slash.

On Ubuntu, Aug 2009, there was no mkinitrd, and make install did not build an initrd nor edit the grub files. Substitute /usr/sbin/mkinitramfs for mkinitrd, using (?) initrd etc as the file name,

    mkinitramfs -o /boot/initrd.img-2.6.30.5 2.6.30.5
Be patient, it takes a few minutes.

Grub and menu.lst

The Grand Unifid Bootload ... sigh ... Before this it was a faceoff between Lilo and Grub. Grub has won.

Boot is short for bootstrap, AFAIK, as in to pull one's self up by one's own bootstraps. After power on, the firmware aka BIOS (software written into memory chips on the motherboard) does the Power On Self Test, aka POST, and then pulls one block of data from the zero-th loaction of the zero-th (more or less) disk. You can interrupt and talk to the BIOS to select another disk.

That block is called the MBR, the master boot record. In there is is a tiny program which is just smart enough to reach into the Linux file system and start to read the rest of the bootloader into memory. If you look for /boot/grub/stage1, it is exactly 512 bytes long. This is a copy of the MBR, and is a part of grub. This is copied into block zero and is stage one of the boot. They actualy aren't exactly similar. See for yourself:

root@davis grub]# dd if=/dev/sda bs=512 count=1 > mbr
1+0 records in
1+0 records out
512 bytes (512 B) copied, 0.000376454 seconds, 1.4 MB/s
[root@davis grub]# hexdump mbr
0000000 48eb 8e90 8ec0 8ed8 bcd0 7c00 e689 00bf
0000010 b906 0100 a5f3 fd89 08b1 abf3 45fe e9f2
0000020 8a00 46f6 20bb 0875 d284 0778 4e80 40bb
0000030 568a 88ba 0056 fae8 5200 c2bb 3107 0203
0000040 0080 8000 ac41 0002 0800 90fa f690 80c2
0000050 0275 80b2 59ea 007c 3100 8ec0 8ed8 bcd0
0000060 2000 a0fb 7c40 ff3c 0274 c288 be52 7d7f
0000070 34e8 f601 80c2 5474 41b4 aabb cd55 5a13
0000080 7252 8149 55fb 75aa a043 7c41 c084 0575
0000090 e183 7401 6637 4c8b be10 7c05 44c6 01ff
00000a0 8b66 441e c77c 1004 c700 0244 0001 8966
00000b0 085c 44c7 0006 6670 c031 4489 6604 4489
00000c0 b40c cd42 7213 bb05 7000 7deb 08b4 13cd
00000d0 0a73 c2f6 0f80 ea84 e900 008d 05be c67c
00000e0 ff44 6600 c031 f088 6640 4489 3104 88d2
00000f0 c1ca 02e2 e888 f488 8940 0844 c031 d088
0000100 e8c0 6602 0489 a166 7c44 3166 66d2 34f7
0000110 5488 660a d231 f766 0474 5488 890b 0c44
0000120 443b 7d08 8a3c 0d54 e2c0 8a06 0a4c c1fe
0000130 d108 6c8a 5a0c 748a bb0b 7000 c38e db31
0000140 01b8 cd02 7213 8c2a 8ec3 4806 607c b91e
0000150 0100 db8e f631 ff31 f3fc 1fa5 ff61 4226
0000160 be7c 7d85 40e8 eb00 be0e 7d8a 38e8 eb00
0000170 be06 7d94 30e8 be00 7d99 2ae8 eb00 47fe
0000180 5552 2042 4700 6f65 006d 6148 6472 4420
0000190 7369 006b 6552 6461 2000 7245 6f72 0072
00001a0 01bb b400 cd0e ac10 003c f475 00c3 0000
00001b0 0000 0000 0000 0000 00b1 0f80 00b6 0180
00001c0 0001 fe83 0c3f 003f 0000 2f8e 0003 0000
00001d0 0d01 fe83 ffff 2fcd 0003 14d4 1700 fe00
00001e0 ffff fe82 ffff 44a1 1703 823f 003e 0000
00001f0 0000 0000 0000 0000 0000 0000 0000 aa55
0000200
[root@davis grub]# hexdump stage1
0000000 48eb 0090 0000 0000 0000 0000 0000 0000
0000010 0000 0000 0000 0000 0000 0000 0000 0000
*
0000030 0000 0000 0000 0000 0000 0000 0000 0203
0000040 00ff 8000 0001 0000 0800 ebfa f607 80c2
0000050 0275 80b2 59ea 007c 3100 8ec0 8ed8 bcd0
0000060 2000 a0fb 7c40 ff3c 0274 c288 be52 7d7f
0000070 34e8 f601 80c2 5474 41b4 aabb cd55 5a13
0000080 7252 8149 55fb 75aa a043 7c41 c084 0575
0000090 e183 7401 6637 4c8b be10 7c05 44c6 01ff
00000a0 8b66 441e c77c 1004 c700 0244 0001 8966
00000b0 085c 44c7 0006 6670 c031 4489 6604 4489
00000c0 b40c cd42 7213 bb05 7000 7deb 08b4 13cd
00000d0 0a73 c2f6 0f80 ea84 e900 008d 05be c67c
00000e0 ff44 6600 c031 f088 6640 4489 3104 88d2
00000f0 c1ca 02e2 e888 f488 8940 0844 c031 d088
0000100 e8c0 6602 0489 a166 7c44 3166 66d2 34f7
0000110 5488 660a d231 f766 0474 5488 890b 0c44
0000120 443b 7d08 8a3c 0d54 e2c0 8a06 0a4c c1fe
0000130 d108 6c8a 5a0c 748a bb0b 7000 c38e db31
0000140 01b8 cd02 7213 8c2a 8ec3 4806 607c b91e
0000150 0100 db8e f631 ff31 f3fc 1fa5 ff61 4226
0000160 be7c 7d85 40e8 eb00 be0e 7d8a 38e8 eb00
0000170 be06 7d94 30e8 be00 7d99 2ae8 eb00 47fe
0000180 5552 2042 4700 6f65 006d 6148 6472 4420
0000190 7369 006b 6552 6461 2000 7245 6f72 0072
00001a0 01bb b400 cd0e ac10 003c f475 00c3 0000
00001b0 0000 0000 0000 0000 0000 0000 0000 1224
00001c0 090f be00 7dbd c031 13cd 8a46 800c 00f9
00001d0 0f75 dabe e87d ffcf 9deb 6c46 706f 7970
00001e0 bb00 7000 01b8 b502 b600 cd00 7213 b6d7
00001f0 b501 e94f fee6 0000 0000 0000 0000 aa55
0000200
[root@davis grub]# 

Next Grub might use a stage 1.5 which is located in a fixed place for the simplicity of stage 1. Stage 1.5 will understand the filesystem and therefore be able to load Stage 2 using the boot filesystem. Installation of Grub selects from several stage 1.5's, depending on the filesystem to use in stage 2. These binaries are found in /boot/grub/filesystem_stage1_5. If the hard disk partition table shows space before the start of the first partition, using dd you might discover a copy of the appropriate stage 1.5 code is located in this space.

Once 1.5 loads stage 2, /boot/grub/menu.lst is consulted for the kernel, modules, and initrd to load. One reason for initrd is to contain the module that allows the operating system to understand the file system on which the rest of the modules are located. I think the name stands for initial root directory. Once the kernel is loaded, with the initrd as it's initial root directory, the rest of the story no longer belongs to Grup. From here on in, the computer is still booting, but it's a topic of "how linux boots" rather than "how grub works".

If you don't believe be about grub, and maybe you shouldn't, try Joydeep Bakshi, he seems knowledgable and friendly. Also, Details of Grub and my own notes on Dos Partitions.

Menu.lst

# grub.conf generated by anaconda
#
# Note that you do not have to rerun grub after making changes to this file
# NOTICE:  You have a /boot partition.  This means that
#          all kernel and initrd paths are relative to /boot/, eg.
#          root (hd0,0)
#          kernel /vmlinuz-version ro root=/dev/VolGroup00/LogVol00
#          initrd /initrd-version.img
#boot=/dev/hda
default=1
timeout=5
splashimage=(hd0,0)/grub/splash.xpm.gz
hiddenmenu
title Fedora Core (2.6.22)
       root (hd0,0)
       kernel /vmlinuz-2.6.22 ro root=/dev/VolGroup00/LogVol00 rhgb quiet enforcing=0
       initrd /initrd-2.6.22.img
title Fedora Core (2.6.11-1.1369_FC4)
       root (hd0,0)
       kernel /vmlinuz-2.6.11-1.1369_FC4 ro root=/dev/VolGroup00/LogVol00 rhgb quiet
       initrd /initrd-2.6.11-1.1369_FC4.img

On Ubuntu, the menu was more elaborate, because it was using labeled volumes, with GUID's. Oh joy! I copied the lines for existing boots, since the GUID's refer to the root volume, and that's the same for all boots. It looked like this:


title	Ubuntu 9.04 hacked kernel 2.6.30.5
uuid	82cf7738-31b9-4666-bbba-c3eec6e09c6b
kernel	/boot/vmlinux-2.6.30.5 root=UUID=82cf7738-31b9-4666-bbba-c3eec6e09c6b ro
initrd	/boot/initrd.img-2.6.30.5

Saminda's blog recommends a tool called update-grub, which appears to look around at the stuff you have and edit menu.lst automagically.

N.B.: On 5 Sep 2007, booting to 2.6.22, got error message Enforcing mode requested but no policy loaded. Halting now. The answer was to turn off enforcing mode. Either use "e" during boot to edit the kernel line, or make the change permanent by editing /boot/grub/menu.lst. Google enforcing mode requested.

Reboot

Assuming that /boot/grub/menu.lst is properly modified, you will be offered to boot to the new kernel. When the grub menu appears, hit the space bar to halt the progress of the automatic reboot. Select the kernel you wish to boot and hit enter.

You can also type e to edit the instructions for the selected boot. The several lines will appear, and they can be individually selected and edited, using the arrows and typing e. For instance, you can add the word single to the end of the line beginning with the word kernel. This will halt the boot process in linux single user mode. This is a useful mode when the kernel is working, but some other part of the system is broken. You can boot to single user, get a shell, and start trying to figure out what is going wrong.