A practical tour to the Linux Kernel

Day 1: Read the original in 1991

Start with the 79K tarball of Linux Kernel 0.11 written by Linus Torvalds for i386. This may just be a short-cut (my story), but it may be a helpful start. If you have forgotten i386 — it can be easily picked up by re-reading the i386 protected mode, hardware MMU paging support, and a bit of the assembly language. After somehow understanding Kernel 0.11, you will find that most internals are still kept in today's kernel, which is much more mature and complicated, supporting Virtual Memory, SMP, new scheduling algorithms, a dazzling collection of file systems, architectures, and devices.

Resources
Linux 0.11 source: http://www.kernel.org/pub/linux/kernel/Historic/old-versions/
i386 IDT: http://www.acm.uiuc.edu/sigops/roll_your_own/i386/idt.html
Protected mode and paging: http://en.wikipedia.org/wiki/Protected_mode
How to write an OS: http://www.acm.uiuc.edu/sigops/roll_your_own/
An interesting experiment of using int 0x81 instead of 0x80 for syscall: http://weichong78.blogspot.com/2008/03/trap-gate-and-system-call.html

Day 2: Back to the future, compile Kernel 2.6

Compiling a current kernel may be the most headache-free thing in this tour. One can just follow the steps in the one of the references below, to download a kernel tarball, configure, compile and install it. Here, I also recap the basic steps.

1. Select a kernel
Latest releases can be found on http://www.kernel.org. One can select the latest stable kernel. Recent versions contain four numbers, A.B.C.D. For example, 2.6.33.4. The number A is the kernel version, B is the major number, C is the minor number, and D accounts for security patches, bug fixes and new features or device drivers. [However, the terminology is a big inconsistent. Sometimes, A is referred to as the major, B minor, C patch level, etc.] Here, we just use the above system. The most important is to differentiate between stable revision major numbers and development revision major numbers. Even B numbers such as 2.4 and 2.6 are stable majors, where odd numbers 2.3 and 2.5 are development majors, in which many new features and experimental updates are added. Using these rules, the announced stable version 2.6.33.4 on kernel.org around this time would be a good choice.

If one wants to cross-compile an ARM kernel for an embedded system, a good place to start might be the ARM Linux Project http://www.arm.linux.org.uk. It maintains ARM patches for different Linux kernel mainlines. One would probably need to select an ARM release (a patch), get its corresponding mainline from http://www.kernel.org, and apply the patch over it. The ARM Linux Project provides new patches that haven't been mainlined, and there are useful documents about booting on the ARM architecture.

2. Getting the source and generate the configuration file .config
The source code archive (e.g., linux-a.b.c.d.tar.bz2) can be downloaded. For a desktop or laptop, one may download it into /usr/src, but for cross-compiling, it is recommended to avoid /usr/src/linux, but use something like the user's $HOME directory to avoid confusion.

Unpack the archive using:

$ tar jxvf linux-a.b.c.d.tar.bz2
or
$ tar zxvf linux-a.b.c.d.tar.gz

Start the configuration

$ cd linux-a.b.c.d
$ make menuconfig

In the menu, one can select the kernel features and device driver modules to be compiled. If compiling for a PC, one may want to specify a suffix for the kernel image so that it can be distinguished from the current kernel used in the system. The suffix is set under the menu "General Setup —> Local version". It may be a time-consuming process to go over the Kernel configuration. Each configuration option has HELP button associated with it so one can select help button to get help. Usually, the default configuration can guarantee boot up into the console, but to start X-windows, one may need to make sure the corresponding video driver is selected.

After exiting the "menuconfig" application, the configuration file .config is generated under the linux-a.b.c.d directory. If one is using a Linux desktop configured by a system admin, one may want to use the original .config file. It might be copied from the existing kernel (e.g., under /usr/src/linux*). If the file cannot be found there, it might be available from the /proc directory of a running kenrel, try

# zcat /proc/config.gz > .config

After the .config file has been updated, "make menuconfig" may first ask about the new options added in the new file. One will first answer these questions before entering the menu. This confirmation step can also be explicitly started with "make oldconfig".

The procedures for configuring the kernel for cross-compilation (e.g., Android) can be somehow different, because the build system may include makefiles to generate the kernel based on the selected platform. The configuration may be read from a platform-specific default file, and the user might not need to directly run "make menuconfig". Nonetheless, the file .config will be the file to control the compilation of the kernel.

3. Compile the kernel
Use the following commands:

$ make 
$ make modules

4. Install the kernel into /boot
Use the following commands:

$ su -   (become root. use "sudo bash" if su is not allowed)
$ make modules_install
$ make install

These commands will copy the following files to /boot
  • System.map-a.b.c.d
  • config-a.b.c.d
  • vmlinuz-a.b.c.d

5. Create an initrd image for device drivers
Type the following command at a shell prompt (replace the a.b.c.d by the actual kernel version being used):

  1. cd /boot
  2. mkinitrd -o initrd.img-a.b.c.d a.b.c.d

These commands will make the ramdisk for booting. The initrd.img-a.b.c.d image contains device drivers which are needed to load rest of the operating system. Not all systems require initrd, but it is safe to create one.

6. Configure grub to load the new image
Suppose grub has already been installed on the system, one can just add one entry to its menu file /boot/grub/menu.lst. An example is

title           GNU/Linux, kernel 2.6.33.4 Default
root            (hd0,0)
kernel          /boot/vmlinuz-2.6.33.4 root=/dev/sda1 ro
initrd          /boot/initrd.img-2.6.33.4
savedefault
boot

The kernel and initrd need to match the generated files under /boot. "root=/dev/sdxx" will need to match the device on which the linux system is installed. After adding the new image to grub, one can run the following commands to try it out.

update-grub
reboot

In any case, one wants to install the new kernel on a new hard drive or other boot media, one would need to install grub onto the system first. I will discuss this in the "USB Linux boot-up" in the next section.

Resources
The Linux Kernel HOWTO: http://www.faqs.org/docs/Linux-HOWTO/Kernel-HOWTO.html
How to: Compile Linux kernel 2.6: http://www.cyberciti.biz/tips/compiling-linux-kernel-26.html
ARM Linux kernel configuration: http://linuxreviews.org/sysadmin/kernel-configuration/

Day 3: Boot up Linux from a USB drive

To test the boot-up skills, it would be a good exercise to try to boot the Kernel from a USB flash disk. Then, how about an embedded system?

These topics are discussed here Linux Boot.

Resources
Linux recovery and boot disk creation: http://www.yolinux.com/TUTORIALS/LinuxTutorialRecoveryAndBootDisk.html#GRUB
ARM bootloader requirements: http://www.arm.linux.org.uk/developer/booting.php
ARM Linux Boot: http://www.arm.linux.org.uk/developer/booting.php

Day 4-5: Kernel modules

Kernel modules are kernel object files (.o or .ko, depending on the Kernel version) which can be loaded into and removed from the Kernel memory space. They can be used to extend kernel functionalities, including adding new character devices or block (aka. mass storage) devices, hooking up syscalls, and handling interrupts. I found it quite useful to read through some tutorials, compile the examples, and plug them into the system to play. It is also a way to appreciate the version differences in the Kernel code, since many old examples probably need some modification to compile on the latest kernels, which should be an interesting and manageable practice.

Resources
The Linux Kernel Module Programming Guide: http://tldp.org/LDP/lkmpg/2.6/html/lkmpg.html
Linux Device Drivers (2nd edition): http://www.xml.com/ldd/chapter/book/ (example code)
Linux Device Drivers (3rd edition): http://lwn.net/Kernel/LDD3/

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License