Build a simple Linux kernel

I will build a basic bare Linux for x86 and execute a simple statically linked program as init0 process. I will use the qemu emulator for executing the kernel. My development system is Ubuntu 12.10 and I have installed qemu directly from Ubuntu repository using apt-get package manager.

Compiling Linux:
I will be working in my home directory

$ mkdir ~/compile_linux 
$ cd compile_linux 

Download any Linux source code. I have linux-3.9.2 source so will be reusing the same. Extract the code in the same directory. So I have Linux code in compile_linux/linux-3.9.2 directory

$ cd linux-3.9.2 

Configuring the kernel. I will restrict the kernel configuration to default configuration.

$ make clean 
$ make i386_defconfig 

Building the kernel

$ make 

Building the root filesystem:
I will create a ramfs file system and the filesystem info will be passed as an argument to the kernel using the kernel parameter initrd. I will not be building an elaborate filesystem rather, as mentioned before, I will execute a statically build program.

$ cd ~/compile_linux 
$ mkdir fs 
$ cd fs 
$ gedit init.c 

And type the following code

#include <stdio.h>
void main() {
  printf("Just a static Hello World\n");

Now save the file and build the code statically using the command

$ gcc -static init.c -o init 

The executable has to be packaged into a ramfs filesystem. The kernel is configured to extract cpio archives of the format newc. I create the cpio archive using the cpio utility as shown below

$ echo init | cpio -o -H newc > testfs 

Emulating the system:
Now I am ready to run the emulator. Type in the following command

$ cd .. 
$ qemu-system-x86_64 -kernel linux-3.9.2/arch/x86/boot/bzImage -initrd fs/testfs -serial stdio -append "root=/dev/ram0 raid=noautodetect console=tty0" 

So you can see a black qemu console come up and at the end you can see your printf message Just a static Hello World. Here Linux was loaded into the emulator and Linux executed /init program as the init0 process. The kernel parameter initrd notifies kernel of the initramfs file system, it can be mounted on /dev/ram0 as per the root=/dev/ram0 argument and used as the rootfs.
I can claim Linux needs no filesystem but this method is highly not recommended for even if you spawn multiple processes if the application crashes then the system is rendered useless.

An interesting accident happened when I was writing this blog. I was building the filesystem. I had earlier build an init program in the fs folder and wanted to save it for some future work. So I used the command

$ mv init init_ 

to save the old init and accidently typed echo init_ instead of init this gave me a crash.This gave me a food for thought How does Linux knows /init? Which will be my next blog


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s