You are here

How to create your own initial ram disk (initrd)

Uditha Atukorala's picture
AttachmentSize
Create your own initrd (revision 1.1)111.37 KB

Contents

1. What is initrd?
2. Why create an initrd?
3. Modifying the Debian initrd
3.1 What you need
3.2 Extract the initrd
3.3 Do the changes
3.4 Make the custom initrd image
3.5 Test the new initrd
3.6 Troubleshooting
4. Create a new initrd from scratch
5. The Book


1. What is initrd?

Initial Ram Disk or initrd is a compressed file system which is uncompressed and loaded to the memory by the boot loader. When the kernel is booting it treats this initial file system as the root file system and executes the first program /linuxrc. (Note: for Debian kernels the default is /init) This program then mounts the actual file system and passes the control to it and ideally un-mounting the initrd and freeing memory.

Initial ram disk is a way of resolving the chicken and egg dilemma for the kernel. Imagine you have the actual root file system in a device which requires the kernel to use additional modules, but in order to load these modules the kernel has to access the file system. Thus the initrd could contain all the required modules and mount the actual file system and then pass over the control.

2. Why create an initrd?
At a glance all the distributions come with an initrd (if they need one) and most of the time provides tools to upgrade it. So why go through all the trouble of making a custom initrd? Well, the answer is simple. You can't get the stock initrd to do what you want in the way you want, especially if you are building a system of your own. And that’s when you want to tweak the stock initrd or create your own.

3. Modifying the Debian initrd
As a start, we’ll try modifying a stock initrd. I chose Debian since I’m familiar with it but you could use your own. Obviously the steps won’t be the same, but once you get the basics you’ll be able to continue on your own. Try looking into the troubleshooting section if you face any difficulties.

3.1 What you need
All you need is a Linux System to do your work and a stock initrd.
I chose the initrd from the Debian Etch business-card installation disk since it is simple and small (not the smallest) in size. You can always use your system initrd but remember not to modify the original and always keep a copy of the original.

3.2 Extracting the initrd
Download the business card iso image from Debian and mount it.

# Create the folder to mount
mkdir –p /mnt/isoimage/

# Mount the iso image
mount -o loop -t iso9660 debian-40r2-i386-businesscard.iso /mnt/isoimage/

It is a good idea to have a clean working directory so you know what you are doing at the moment and it is easier to manage. I setup my working directory as $HOME/WorkBench

Now let’s copy the initrd from Debian iso image. But first we need to find where the initrd image is. You could find the initrd image in /boot in a Linux System so hoping that the iso image has the same structure we’ll look in the mounted image structure.

$ ls –l /mnt/isoimage/

Unfortunately the boot folder is not there, but we could find a folder named ‘isolinux’. Since we find this folder we could conclude the iso image uses the ISOLINUX boot system.

So we look inside isolinux folder,

$ ls –l /mnt/isoimage/isolinux

Now we have the isolinux.cfg file which is used to store ISOLINUX configuration.

$ less /mnt/isoimage/isolinux/isolinux.cfg

Try to find something like,

LABEL install
kernel /install.386/vmlinuz
append vga=normal initrd=/install.386/initrd.gz –

There we are, the initrd image is in install.386 folder. Copy it to your work bench.

$ cp /mnt/isoimage/isolinux/install.386/initrd.gz $HOME/WorkBench
$ cd $HOME/WorkBench

Extract the initrd image,
$ zcat initrd.gz | cpio –i

Now you should have a directory structure which is very similar to a root file system extracted to your working directory. Browse through it and try to find something interesting.


3.3 Do the changes

What we should start editing is the initial script or the program executed by the kernel, which is linuxrc or init in the case of Debian.

Just have a glance at the existing init script.

$ less init

#!/bin/sh -e
# used for initramfs
export PATH
. /lib/debian-installer/init-debug
debugshell "just booted"
mount /proc
if [ -x /sbin/udevd ]; then
/lib/debian-installer/init-udev-devices
else
mount /dev
mount /dev/pts
fi
init='busybox init'
for i in $(cat /proc/cmdline); do
case $i in
init=*)
init=${i#init=}
;;
esac
done
debugshell "before init"
exec $init

It isn’t so hard to understand, is it now?
It’ll be a good idea to trace the execution of the stock init script just to have an understanding of how it works. Especially if you trace this init script you’ll get the understanding of how the Debian installer works.

Anyway, back to our work...

Let’s create our own init script, so we’ll be able to execute basic shell commands.

Debian initrd comes with BusyBox packed into it, so let’s use advantage of it and it’s build in ash shell. First we need to mount the /proc and /sys file systems and then give the ash prompt. Edit the init script so that it’ll be similar to the one below and don’t hesitate to add your own code and your own greeting.

init script

#!/bin/ash
mount -t proc /proc /proc
mount -t sysfs none /sys
echo
echo "initrd is running"
echo "Using BusyBox..."
echo
exec /bin/ash --login

Well, that’s all for our simple init script. Now it’s time to make our custom initrd.


3.4 Make the custom initrd image

First move or delete the stock initrd.gz image because we don’t want that in our new initrd image.

$ rm initrd.gz

Now compress and create our initrd image.

$ find . | cpio -o -H newc | gzip > ../initrd.img


3.5 Test the new initrd

Copy our new initrd image to the /boot folder,

# cp $HOME/initrd.img /boot
Note: You might have to be in root mode.

Edit your boot loader to load the new initrd and it’s always a good idea to add a new entry with the new initrd rather than editing the existing entries.

I added the following entry to my GRUB boot loader,

# nano /boot/grub/menu.lst

title Linux [New initrd]
kernel /boot/vmlinuz-2.6.18-6-686
initrd /boot/initrd.img

Do a reboot and select our new entry while booting. After booting you should get the BusyBox ash prompt and should be able to enter simple commands.


3.6 Troubleshooting

If you are not using a Debian system then you might face some problems. In this section I try to highlight some of the things that you might face.

First thing would be having problems with extracting the stock initrd image. The initrd image I used and all the other Debian initrd images (I haven’t tested old Debian initrds so this could not be the case with the old ones) are compressed using cpio archive. But other initrd images could have some other compression such as gzip.

So try uncompressing using gzip and mount in a loop device.

# mkdir -p /mnt/initrd
# gunzip initrd.img.gz
# mount -t ext -o loop initrd.img /mnt/initrd

Note that the initrd image had the extension .img.gz this could give a hint that it’s compressed using gzip.

If you uncompress a gzip image then it’s probably best to compress it back using gzip because you kernel might not recognize cramfs file system (file system used in cpio archives)

# umount /mnt/initrd
# gzip –c initrd.img

For any reason if you need to recreate the stock initrd you could use this command on a Debian system.

# dpkg-reconfigure linux-image-`uname -r`

For mounting a cramfs you could try this method as well,

# mkdir -p /mnt/initrd
# mount -t cramfs initrd.img /mnt/initrd -o loop


Reference:
http://kernel-handbook.alioth.debian.org/ch-initramfs.html


4. Create a new initrd from scratch

Initial Ram Disk is a root file system and it is no different to any other Linux root file system apart from the size. Obviously reduced size means lesser functionality but we can pack all what we need into our initrd if selected carefully. After all, a fully functional Linux system can be packed into a set of two 1.44MB floppy disks.

We’ll start by creating a new folder to contain our initrd file system.

$ mkdir $HOME/WorkBench/initfs
$ cd $HOME/WorkBench/initfs

Now let’s populate the directory structure,

$ mkdir {bin,sys,dev,proc,etc,lib}

We need to have some software to provide the functions we need. I’m using BusyBox since it is small in size and packed with commonly used commands. You can either compile BusyBox from source or get it from your Linux system if it is there or get your own software in your initrd. The choice is up to you.

I’m going to use the BusyBox which shipped with my Debian Linux System. If you are having thoughts of compiling your own selection of programs it would be a good idea to use a static compile so you don’t have to worry about the dynamic libraries. But if you really insist on using dynamic libraries you could try installing them to your initfs directory.

$ make PREFIX=$HOME/WorkBench/initfs install

Anyway as I’ve mentioned earlier the choice is up to you and don’t hesitate to try new things.

As for my method what I should do is to copy BusyBox to my initfs.

# BusyBox
$ cp /bin/busybox $HOME/WorkBench/initfs/bin

# Dynamic Libraries
$ pushd $HOME/WorkBench/initfs/lib
$ cp /lib/libc.so.6 .
$ cp /lib/libdl.so.2 .
$ cp /lib/ld-linux.so.2 .
$ cp /lib/libcrypt.so.1 .
$ cp /lib/libm.so.6 .
$ popd

Note: lib files required by BusyBox may vary depending on your BusyBox compilation. You can use $ ldd /bin/busybox to find out the library dependencies for your BusyBox.

And we need to create some sym-links to get the BusyBox working as we need.

$ pushd $HOME/WorkBench/initfs/bin
$ ln -s busybox ash
$ ln -s busybox mount
$ ln -s busybox echo
$ ln -s busybox ls
$ ln -s busybox cat
$ ln -s busybox ps
$ ln -s busybox dmesg
$ ln -s busybox sysctl
$ ln -s busybox sh
$ popd

I found out that these links are really not necessary when you are using the BusyBox built-in ash shell. You can just enter the commands and they’ll work. But if you are using a different shell like bash, you’ll have to have these links to get things working.

Now we have got all the software for our simple initrd but we need to make some device nodes for the software to work. You can simple copy them from your Linux system or create them.

Method 1: Copy them

# cp -a /dev/console  dev
# cp -a /dev/ram0  dev
# cp -a /dev/null  dev
# cp -a /dev/tty1  dev
# cp -a /dev/tty2  dev


Method 2: Create them
# mknod dev/console c 5 1
# mknod dev/ram0 b 1 1
# mknod dev/null c 1 3
# mknod dev/tty1 c 4 1
# mknod dev/tty2 c 4 2

If you have noticed we didn’t create the sbin directory when we were population the file system earlier. That is simply because we are only going to have root login and everything will be executed as root. And that’s why we didn’t even consider setting the appropriate privileges to the device nodes as well. So it is safe to just link the bin and sbin directories.

$ ln -s bin sbin

We are almost there now. All there is left is to create the init (or linuxrc) script which will be executed by the kernel as the first program. We will use the same init script as before so we could test our initrd against the stock initrd.

init script

#!/bin/ash
mount -t proc /proc /proc
mount -t sysfs none /sys
echo
echo "initrd is running"
echo "Using BusyBox..."
echo
exec /bin/ash –login

Have a look at the contents in our initfs folder now. It should be similar to this.

total 24
drwxr-xr-x 2 root root 4096 2008-03-17 14:44 bin
drwxr-xr-x 2 root root 4096 2008-03-17 14:44 dev
-rwxr-xr-x 1 root root  142 2008-03-17 14:44 init
drwxr-xr-x 2 root root 4096 2008-03-17 14:44 lib
drwxr-xr-x 2 root root 4096 2008-03-17 14:44 proc
lrwxrwxrwx 1 root root    3 2008-03-17 14:44 sbin -> bin
drwxr-xr-x 2 root root 4096 2008-03-17 14:44 sys

Our initfs is now ready. So let’s create the compressed initrd.

$ find . | cpio -o -H newc | gzip > ../initrd-2.img

Follow the same procedure to test our newly created initrd.

# cp $HOME/WorkBench/initrd-2.img /boot
# nano /boot/grub/menu.lst

title Linux [Custom initrd]
kernel /boot/vmlinuz-2.6.18-6-686
initrd /boot/initrd-2.img

Reboot and select the ‘Linux [Custom initrd]’ from the boot menu and you should get to the BusyBox built-in ash shell prompt. Key in some commands like ls, ls –l to make sure our initrd is working properly.

If you didn’t make any sym-links to BusyBox or you only made some of them, you can find out what are the available commands by typing ‘help’ on the ash prompt. Try experimenting with some of them just to make sure that everything is working as planned.


5. The Book

I've already done three (yes, 3) revisions to this and it's a little hard to edit in the web format. So I've put all this together into a little book and I'll continue to update the book simply becase it's easier for me. Please find the attached book in PDF format.