Section 6.4. Initial RAM Disk


6.4. Initial RAM Disk

The Linux kernel contains a mechanism to mount an early root file system to perform certain startup-related system initialization and configuration. This mechanism is known as the initial RAM disk, or simply initrd. Support for this functionality must be compiled into the kernel. This kernel configuration option is found under Block Devices, RAM disk support in the kernel configuration utility. Figure 6-1 shows an example of the configuration for initrd.

Figure 6-1. Linux kernel configuration utility


6.4.1. Initial RAM Disk Purpose

The initial RAM disk is a small self-contained root file system that usually contains directives to load specific device drivers before the completion of the boot cycle. In Linux workstation distributions such as Red Hat and Fedora Core, an initial RAM disk is used to load the device drivers for the EXT3 file system before mounting the real root file system. An initrd is frequently used to load a device driver that is required in order to access the real root file system.

6.4.2. Booting with initrd

To use the initrd functionality, the bootloader gets involved on most architectures to pass the initrd image to the kernel. A common scenario is that the bootloader loads a compressed kernel image into memory and then loads an initrd image into another section of available memory. In doing so, it becomes the bootloader's responsibility to pass the load address of the initrd image to the kernel before passing control to it. The exact mechanism differs depending on the architecture, bootloader, and platform implementation. However, the kernel must know where the initrd image is located so it can load it.

Some architectures and platforms construct a single composite binary image. This scheme is used when the bootloader does not have specific Linux support for loading initrd images. In this case, the kernel and initrd image are simply concatenated together. You will find reference to this type of composite image in the kernel makefiles as bootpImage. Presently, this is used only for arm architecture.

So how does the kernel know where to find the initrd image? Unless there is some special magic in the bootloader, it is usually sufficient simply to pass the initrd image start address and size to the kernel via the kernel command line. Here is an example of a kernel command line for a popular ARM-based reference board containing the TI OMAP 5912 processor.

console=ttyS0,115200 root=/dev/nfs                        \    nfsroot=192.168.1.9:/home/chris/sandbox/omap-target    \    initrd=0x10800000,0x14af47


The previous kernel command line has been separated into several lines to fit in the space provided. In actual practice, it is a single line, with the individual elements separated by spaces. This kernel command line defines the following kernel behavior:

  • Specify a single console on device ttyS0 at 115 kilobaud

  • Mount a root file system via NFS, the network file system

  • Find the NFS root file system on host 192.168.1.9

    (from directory /home/chris/sandbox/omap-target)

  • Load and mount an initial ramdisk from physical memory location

    0x10800000, which has a size of 0x14AF47 (1,355,591 bytes)

One additional note regarding this example: Almost universally, the initrd image is compressed. The size specified on the kernel command line is the size of the compressed image.

6.4.3. Bootloader Support for initrd

Let's look at a simple example based on the popular U-Boot bootloader running on an ARM processor. This bootloader has been designed with Linux kernel support. Using U-Boot, it is easy to include an initrd image with the kernel image. Listing 6-10 examines a typical boot sequence containing an initial ramdisk image.

Listing 6-10. Booting Kernel with Ramdisk Support

# tftpboot 0x10000000 kernel-uImage ... Load address: 0x10000000 Loading: ############################ done Bytes transferred = 1069092 (105024 hex) # tftpboot 0x10800000 initrd-uboot ... Load address: 0x10800000 Loading: ########################################### done Bytes transferred = 282575 (44fcf hex) # bootm 0x10000000 0x10800040 Uncompressing kernel.................done. ... RAMDISK driver initialized: 16 RAM disks of 16384K size 1024 blocksize ... RAMDISK: Compressed image found at block 0 VFS: Mounted root (ext2 filesystem). Greetings: this is linuxrc from Initial RAMDisk Mounting /proc filesystem BusyBox v1.00 (2005.03.14-16:37+0000) Built-in shell (ash) Enter 'help' for a list of built-in commands. # (<<<< Busybox command prompt)

Here in Listing 6-10, we get a glimpse of the U-Boot bootloader, which we examine in more detail in the next chapter. The tftpboot command causes U-Boot to download the kernel image from a tftp server. The kernel image is downloaded and placed into the base of this target system's memory at the 256MB address (0x10000000 hex[7]). Then a second image, the initial ramdisk image, is downloaded from a tftp server into memory at a higher memory address (256MB + 8MB, in this example). Finally, we issue the U-Boot bootm command, which is the "boot from memory" command. The bootm command takes two arguments: the address of the Linux kernel image, optionally followed by an address representing the location of the initial ramdisk image.

[7] It just so happens that on this particular board, our physical SDRAM starts at 256MB.

Take special note of one feature of the U-Boot bootloader. It fully supports loading kernel and ramdisk images over an Ethernet connection. This is a very useful development configuration. You can get a kernel and ramdisk image onto your board in other ways as well. You can flash them into your Flash memory using a hardware-based flash programming tool, or you can use a serial port and download the kernel and file system images via RS-232. However, because these images are typically large (a kernel can be about a megabyte, and a ramdisk can be tens of megabytes), you will save a significant amount of engineering time if you invest in this Ethernet-based tftp download method. Whatever bootloader you choose, make sure it supports network download of development images.

6.4.4. initrd Magic: linuxrc

When the kernel boots, it detects the presence of the initrd image, and copies the compressed binary file from the specified physical location in RAM into a proper kernel ramdisk and mounts it as the root file system. The magic of the initrd comes from the contents of a special file within the initrd image. When the kernel mounts the initial ramdisk, it looks for a specific file called linuxrc. It treats this file as a script file and proceeds to execute the commands contained therein. This mechanism enables the system designer to specify the behavior of initrd. Listing 6-11 contains a sample linuxrc file.

Listing 6-11. Example linuxrc File

#!/bin/sh echo 'Greetings: this is 'linuxrc' from Initial Ramdisk' echo 'Mounting /proc filesystem' mount -t proc /proc /proc busybox sh

In practice, this file would contain directives required before we mount the real root file system. One example might be to load CompactFlash drivers to obtain a real root file system from a CompactFlash device. For purposes of this example, we simply spawn a busybox shell and halt the boot process for examination. You can see the # command prompt from Listing 6-10 resulting from this busybox shell. If one were to type the exit command here, the kernel would continue its boot process until complete.

After the kernel copies the ramdisk from physical memory into a kernel ramdisk, it returns this physical memory back to the available memory pool. You can think of this as transferring the initrd image from physical memory at the hard-coded address into the kernel's own virtual memory (in the form of a kernel ramdisk device).

One last comment about Listing 6-11: The mount command in which the /proc file system is mounted seems redundant in its use of the word proc. This command would also work:

mount -t proc none /proc


Notice that the device field of the mount command has been changed to none. The mount command ignores the device field because no physical device is associated with the proc file system. The -t proc is enough to instruct mount to mount the /proc file system on the /proc mount point. I use the former invocation as a mental reminder that we are actually mounting the kernel pseudo device (the /proc file system) on /proc. The mount command ignores this argument. Use the method that you prefer.

6.4.5. The initrd Plumbing

As part of the Linux boot process, the kernel must locate and mount a root file system. Late in the boot process, the kernel decides what and where to mount in a function called prepare_namespace(). If initrd support is enabled in the kernel, as illustrated in Figure 6-1, and the kernel command line is so configured, the kernel decompresses the compressed initrd image from physical memory and eventually copies the contents of this file into a ramdisk device (/dev/ram). At this point, we have a proper file system on a kernel ramdisk. After the file system has been read into the ramdisk, the kernel effectively mounts this ramdisk device as its root file system. Finally, the kernel spawns a kernel thread to execute the linuxrc file on the initrd image.[8]

[8] Out of necessity (space), this is a very simplified description of the sequence of events. The actual mechanism is similar in concept, but several significant details are omitted for clarity. You are encouraged to consult the kernel source code for more details. See .../init/main.c and .../init/do_mounts*.c.

When the linuxrc script has completed execution, the kernel unmounts the initrd and proceeds with the final stages of system boot. If the real root device has a directory called /initrd, Linux mounts the initrd file system on this path (in this context, called a mount point). If this directory does not exist in the final root file system, the initrd image is simply discarded.

If the kernel command line contains a root= parameter specifying a ramdisk (root=/dev/ram0, for example), the previously described initrd behavior changes in two important ways. First, the processing of the linuxrc executable is skipped. Second, no attempt is made to mount another file system as root. This means that you can have a Linux system with initrd as the only root file system. This is useful for minimal system configurations in which the only root file system is the ramdisk. Placing /dev/ram0 on the kernel command line allows the full system initialization to complete with the initrd as the final root file system.

6.4.6. Building an initrd Image

Constructing a suitable root file system image is one of the more challenging aspects of embedded systems. Creating a proper initrd image is even more challenging because it needs to be small and specialized. For this section, we examine initrd requirements and file system contents.

Listing 6-12 was produced by running the tree utility on our example initrd image from this chapter.

Listing 6-12. Contents of Example initrd

. |-- bin |   |-- busybox |   |-- echo -> busybox |   |-- mount -> busybox |   '-- sh -> busybox |-- dev |   |-- console |   |-- ram0 |   '-- ttyS0 |-- etc |-- linuxrc '-- proc 4 directories, 8 files

As you can see, it is very small indeed; it takes up a little more than 500KB in uncompressed form. Since it is based on busybox, it has many capabilities. Because busybox is statically linked, it has no dependencies on any system libraries. You will learn more about busybox in Chapter 11.



Embedded Linux Primer(c) A Practical Real-World Approach
Embedded Linux Primer: A Practical Real-World Approach
ISBN: 0131679848
EAN: 2147483647
Year: 2007
Pages: 167

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net