Root File System: Design and Building

9.5. Root File System: Design and Building

http://www.denx.de/wiki/DULG/RootFileSystemDesignAndBuilding

It is not an easy task to design the root file systemfor an embedded system.There are three major problems to be solved:

  1. what to put in it
  2. which file system type to use
  3. where to store and how to boot it

For now we will assume that the contents of the root file systemis aready known;for example, it is given to us as a directory treeor a tarball which contains all the required files.

We will also assume that our system is a typical resource-limitedembedded system so we will especially look for solutions where theroot file system can be stored on on-board flash memory or otherflash memory based devices like CompactFlash or SD cards, MMC orUSB memory sticks.

A widespread approach to build a root file system is to use someLinux distribution (like the ELDK) and to remove things not needed.This approach may be pretty common, but it is almost always terriblywrong. You also don't build a family home by taking a skyscraper andremoving parts.Like a house, a root file system should be built bottom up, startingfrom scratch and adding things you know you need. Never add anythingwhere you don't exactly know what it's needed for.

But our focus here is on the second item:the options we have forchosing a file system type and the consequences this has.

In all cases we will base our experiments on the same content of theroot filesystem; we use the images of the SELF (Simple Embedded Linux Framework) that come with the ELDK. In a first step we will transform theSELF images into a tarball to meet the requirements mentioned above:

In a ELDK installation, the SELF images can be found in the/opt/eldk/<architecture>/images/ directory.There is already a compressed ramdisk image in this directory,which we will use (ramdisk_image.gz):

  1. Uncompress ramdisk image:
    bash$ gzip -d -c -v /opt/eldk/ppc_8xx/images/ramdisk_image.gz >/tmp/ramdisk_image
    /opt/eldk/ppc_8xx/images/ramdisk_image.gz:       61.4%
    

    ALERT! Note: The following steps require root permissions!
  2. Mount ramdisk image:
    bash# mount -o loop /tmp/ramdisk_image /mnt/tmp
    
  3. Create tarball; to avoid the need for root permissions in the following steps we don't include the device files in our tarball:
    bash# cd /mnt/tmp
    bash# tar -zc --exclude='dev/*' -f /tmp/rootfs.tar.gz *
    
  4. Instead, we create a separate tarball which contains only the device entries so we can use them when necessary (with cramfs):
    bash# tar -zcf /tmp/devices.tar.gz dev/
    bash# cd /tmp
    
  5. Unmount ramdisk image:
    bash# umount /mnt/tmp
    

We will use the /tmp/rootfs.tar.gz tarball as master file in all following experiments.


9.5.1. Root File System on a Ramdisk

Ram disks are used very often to hold the root file system of embedded systems. They have several advantages:

  • well-known
  • well-supported by the Linux kernel
  • simple to build
  • simple to use - you can even combine the ramdisk with the Linux kernel into a single image file
  • RAM based, thus pretty fast
  • writable file system
  • original state of file system after each reboot = easy recovery from accidental or malicious data corruption etc.
On the other hand, there are several disadvantages, too:
  • big memory footprint: you always have to load the complete filesystem into RAM, even if only small parts of are actually used
  • slow boot time: you have to load (and uncompress) the whole image before the first application process can start
  • only the whole image can be replaced (not individual files)
  • additional storage needed for writable persistent data
Actually there are only very few situations where a ramdisk image is theoptimal solution. But because they are so easy to build and use we will discuss them here anyway.

In almost all cases you will use an ext2 file system in your ramdiskimage. The following steps are needed to create it:

  1. Create a directory tree with the content of the target root filesystem. We do this by unpacking our master tarball:
    $ mkdir rootfs
    $ cd rootfs
    $ tar zxf /tmp/rootfs.tar.gz
    
  2. We use the genext2fs tool to create the ramdisk image as this allows to use a simple text file to describe which devices shall be created in the generated file system image. That means that no root permissions are required at all. We use the following device table rootfs_devices.tab:
    #<name>    <type> <mode> <uid> <gid> <major> <minor> <start>  <inc>  <count>
    /dev            d  755  0       0        -      -       -       -       -
    /dev/console    c  640  0       0        5      1       -       -       -
    /dev/fb0        c  640  0       0       29      0       -       -       -
    /dev/full       c  640  0       0        1      7       -       -       -
    /dev/hda        b  640  0       0        3      0       -       -       -
    /dev/hda        b  640  0       0        3      1       1       1       16
    /dev/kmem       c  640  0       0        1      2       -       -       -
    /dev/mem        c  640  0       0        1      1       -       -       -
    /dev/mtd        c  640  0       0       90      0       0       2       16
    /dev/mtdblock   b  640  0       0       31      0       0       1       16
    /dev/mtdr       c  640  0       0       90      1       0       2       16
    /dev/nftla      b  640  0       0       93      0       -       -       -
    /dev/nftla      b  640  0       0       93      1       1       1       8
    /dev/nftlb      b  640  0       0       93      16      -       -       -
    /dev/nftlb      b  640  0       0       93      17      1       1       8
    /dev/null       c  640  0       0        1      3       -       -       -
    /dev/ptyp       c  640  0       0        2      0       0       1       10
    /dev/ptypa      c  640  0       0        2      10      -       -       -
    /dev/ptypb      c  640  0       0        2      11      -       -       -
    /dev/ptypc      c  640  0       0        2      12      -       -       -
    /dev/ptypd      c  640  0       0        2      13      -       -       -
    /dev/ptype      c  640  0       0        2      14      -       -       -
    /dev/ptypf      c  640  0       0        2      15      -       -       -
    /dev/ram        b  640  0       0        1      0       0       1       2
    /dev/ram        b  640  0       0        1      1       -       -       -
    /dev/rtc        c  640  0       0       10      135     -       -       -
    /dev/tty        c  640  0       0        4      0       0       1       4
    /dev/tty        c  640  0       0        5      0       -       -       -
    /dev/ttyS       c  640  0       0        4      64      0       1       8
    /dev/ttyp       c  640  0       0        3      0       0       1       10
    /dev/ttypa      c  640  0       0        3      10      -       -       -
    /dev/ttypb      c  640  0       0        3      11      -       -       -
    /dev/ttypc      c  640  0       0        3      12      -       -       -
    /dev/ttypd      c  640  0       0        3      13      -       -       -
    /dev/ttype      c  640  0       0        3      14      -       -       -
    /dev/ttypf      c  640  0       0        3      15      -       -       -
    /dev/zero       c  640  0       0        1      5       -       -       -
    
    A description of the format of this table is part of the manual page for the genext2fs tool, genext2fs(8).
  3. We can now create an ext2 file system image using the genext2fs tool:
    $ ROOTFS_DIR=rootfs                 # directory with root file system content
    $ ROOTFS_SIZE=3700                  # size of file system image
    $ ROOTFS_FREE=100                   # free space wanted
    $ ROOTFS_INODES=380                 # number of inodes
    $ ROOTFS_DEVICES=rootfs_devices.tab # device description file
    $ ROOTFS_IMAGE=ramdisk.img          # generated file system image
    
    $ genext2fs -U \
            -d ${ROOTFS_DIR} \
            -D ${ROOTFS_DEVICES} \
            -b ${ROOTFS_SIZE} \
            -r ${ROOTFS_FREE} \
            -i ${ROOTFS_INODES} \
            ${ROOTFS_IMAGE}
    
  4. Compress the file system image:
    $ gzip -v9 ramdisk.img
    rootfs.img:      55.6% -- replaced with ramdisk.img.gz
    
  5. Create an U-Boot image file from it:
    $ mkimage -T ramdisk -C gzip -n 'Test Ramdisk Image' \
    > -d ramdisk.img.gz uRamdisk
    Image Name:   Test Ramdisk Image
    Created:      Sun Jun 12 16:58:06 2005
    Image Type:   PowerPC Linux RAMDisk Image (gzip compressed)
    Data Size:    1618547 Bytes = 1580.61 kB = 1.54 MB
    Load Address: 0x00000000
    Entry Point:  0x00000000
    

We now have a root file system image uRamdisk that can beused with U-Boot.


9.5.2. Root File System on a JFFS2 File System

JFFS2 (Journalling Flash File System version 2)was specifically designed for use on flash memory devicesin embedded systems.It is a log-structured file system which means that it is robustagainst loss of power, crashes or other unorderly shutdowns of the system("robust" means that data that is just being written when thesystem goes down may be lost,but the file system itself does not get corruptedand the system can be rebootet without need for any kindof file system check).

Some of the advantages of using JFFS2 as root file system in embedded systemsare:

  • file system uses compression, thus making efficient use of flash memory
  • log-structured file system, thus robust against unorderly shutdown
  • flash sector wear-leveling
  • writable flash file system

Disadvantages are:

  • long mount times (especially older versions)
  • slow when reading: files to be read get uncompressed on the fly which eats CPU cycles and takes time
  • slow when writing: files to be written get compressed, which eats CPU cycles and takes time, but it may even take much longer until data gets actually stored in flash if the file system becomes full and blocks must be erased first or - even worse - if garbage collection becomes necessary
  • The garbage collector thread may run at any time, consuming CPU cycles and blocking accesses to the file system.

Despite the aforementioned disadvantages,systems using a JFFS2 based root file system are easy to build,make efficient use of the available resourcesand can run pretty reliably.

To create a JFFS2 based root file system please proceed as follows:

  1. Create a directory tree with the content of the target root filesystem. We do this by unpacking our master tarball:
    $ mkdir rootfs
    $ cd rootfs
    $ tar zxf /tmp/rootfs.tar.gz
    
  2. We can now create a JFFS2 file system image using the mkfs.jffs2 tool:
    $ ROOTFS_DIR=rootfs                 # directory with root file system content
    $ ROOTFS_EBSIZE=0x20000             # erase block size of flash memory
    $ ROOTFS_ENDIAN=b                   # target system is big endian
    $ ROOTFS_DEVICES=rootfs_devices.tab # device description file
    $ ROOTFS_IMAGE=jffs2.img            # generated file system image
    
    $ mkfs.jffs2 -U \
            -d ${ROOTFS_DIR} \
            -D ${ROOTFS_DEVICES} \
            -${ROOTFS_ENDIAN} \
            -e ${ROOTFS_EBSIZE} \
            -o ${ROOTFS_IMAGE}
    mkfs.jffs2: skipping device_table entry '/dev': no parent directory!
    
ALERT! Note: When you intend to write the JFFS2 file system image to a NAND flashdevice, you should also add the "-n" (or "--no-cleanmarkers") option,as cleanmarkers are not needed then.

When booting the Linux kernel prints the followingmessages showing the default partition mapwhich is used for the flash memoryon the TQM8xxL boards:

 TQM flash bank 0: Using static image partition definition
Creating 7 MTD partitions on "TQM8xxL0":
0x00000000-0x00040000 : "u-boot"
0x00040000-0x00100000 : "kernel"
0x00100000-0x00200000 : "user"
0x00200000-0x00400000 : "initrd"
0x00400000-0x00600000 : "cramfs"
0x00600000-0x00800000 : "jffs"
0x00400000-0x00800000 : "big_fs"
We use U-Boot to load and store the JFFS2 image into the lastpartition and set up the Linux boot arguments to use this asroot device:
  1. Erase flash:
    => era 40400000 407FFFFF
    
    ................. done
    Erased 35 sectors
    
  2. Download JFFS2 image:
    => tftp 100000 /tftpboot/TQM860L/jffs2.img
    Using FEC ETHERNET device
    TFTP from server 192.168.3.1; our IP address is 192.168.3.80
    Filename '/tftpboot/TQM860L/jffs2.img'.
    Load address: 0x100000
    Loading: #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             ########
    done
    Bytes transferred = 2033888 (1f08e0 hex)
    
  3. Copy image to flash:
    => cp.b 100000 40400000 ${filesize}
    Copy to Flash... done
    
  4. set up boot arguments to use flash partition 6 as root device:
    => setenv mtd_args setenv bootargs root=/dev/mtdblock6 rw rootfstype=jffs2
    => printenv addip
    addip=setenv bootargs ${bootargs} ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}:${netdev}:off panic=1
    => setenv flash_mtd 'run mtd_args addip;bootm ${kernel_addr}'
    => run flash_mtd
    Using FEC ETHERNET device
    TFTP from server 192.168.3.1; our IP address is 192.168.3.80
    Filename '/tftpboot/TQM860L/uImage'.
    Load address: 0x200000
    Loading: #################################################################
             #################################################################
             ###########
    done
    Bytes transferred = 719233 (af981 hex)
    ## Booting image at 40040000 ...
       Image Name:   Linux-2.4.25
       Created:      2005-06-12  16:32:24 UTC
       Image Type:   PowerPC Linux Kernel Image (gzip compressed)
       Data Size:    782219 Bytes = 763.9 kB
       Load Address: 00000000
       Entry Point:  00000000
       Verifying Checksum ... OK
       Uncompressing Kernel Image ... OK
    Linux version 2.4.25 (wd@xpert) (gcc version 3.3.3 (DENX ELDK 3.1.1 3.3.3-9)) #1 Sun Jun 12 18:32:18 MEST 2005
    On node 0 totalpages: 4096
    zone(0): 4096 pages.
    zone(1): 0 pages.
    zone(2): 0 pages.
    Kernel command line: root=/dev/mtdblock6 rw rootfstype=jffs2 ip=192.168.3.80:192.168.3.1::255.255.255.0:tqm860l:eth1:off panic=1
    Decrementer Frequency = 187500000/60
    Calibrating delay loop... 49.86 BogoMIPS
    ...
    NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
    VFS: Mounted root (jffs2 filesystem).
    Freeing unused kernel memory: 56k init
    
    
    BusyBox v0.60.5 (2005.03.07-06:54+0000) Built-in shell (msh)
    Enter 'help' for a list of built-in commands.
    
    # ### Application running ...
    # mount
    rootfs on / type rootfs (rw)
    /dev/mtdblock6 on / type jffs2 (rw)
    /proc on /proc type proc (rw)
    # df /
    Filesystem           1k-blocks      Used Available Use% Mounted on
    rootfs                    4096      2372      1724  58% /
    


cramfs is a compressed, read-only file system.

Advantages are:

  • file system uses compression, thus making efficient use of flash memory
  • Allows for quick boot times as only used files get loaded and uncompressed

Disadvantages are:

  • only the whole image can be replaced (not individual files)
  • additional storage needed for writable persistent data
  • mkcramfs tool does not support device table, so we need root permissions to create the required device files

To create a cramfs based root file system please proceed as follows:

  1. Create a directory tree with the content of the target root filesystem. We do this by unpacking our master tarball:
    $ mkdir rootfs
    $ cd rootfs
    $ tar -zxf /tmp/rootfs.tar.gz
    
  2. Create the required device files. We do this here by unpacking a special tarball which holds only the device file entries. ALERT! Note: this requires root permissions!
    # cd rootfs
    # tar -zxf /tmp/devices.tar.gz
    
  3. Many tools require some storage place in a filesystem, so we must provide at least one (small) writable filesystem. For all data which may be lost when the system goes down, a "tmpfs" filesystem is the optimal choice. To create such a writable tmpfs filesystem we add the following lines to the /etc/rc.sh script:
    # mount TMPFS because root-fs is readonly
    /bin/mount -t tmpfs -o size=2M tmpfs /tmpfs
    
    Some tools require write permissions on some device nodes (for example, to change ownership and permissions), or dynamically (re-) create such files (for example, /dev/log which is usually a Unix Domain socket). The files are placed in a writable filesystem; in the root filesystem symbolic links are used to point to their new locations:
    dev/ptyp0/tmpfs/dev/ptyp0 dev/ttyp0/tmpfs/dev/ttyp0
    dev/ptyp1/tmpfs/dev/ptyp1 dev/ttyp1/tmpfs/dev/ttyp1
    dev/ptyp2/tmpfs/dev/ptyp2 dev/ttyp2/tmpfs/dev/ttyp2
    dev/ptyp3/tmpfs/dev/ptyp3 dev/ttyp3/tmpfs/dev/ttyp3
    dev/ptyp4/tmpfs/dev/ptyp4 dev/ttyp4/tmpfs/dev/ttyp4
    dev/ptyp5/tmpfs/dev/ptyp5 dev/ttyp5/tmpfs/dev/ttyp5
    dev/ptyp6/tmpfs/dev/ptyp6 dev/ttyp6/tmpfs/dev/ttyp6
    dev/ptyp7/tmpfs/dev/ptyp7 dev/ttyp7/tmpfs/dev/ttyp7
    dev/ptyp8/tmpfs/dev/ptyp8 dev/ttyp8/tmpfs/dev/ttyp8
    dev/ptyp9/tmpfs/dev/ptyp9 dev/ttyp9/tmpfs/dev/ttyp9
    dev/ptypa/tmpfs/dev/ptypa dev/ttypa/tmpfs/dev/ttypa
    dev/ptypb/tmpfs/dev/ptypb dev/ttypb/tmpfs/dev/ttypb
    dev/ptypc/tmpfs/dev/ptypc dev/ttypc/tmpfs/dev/ttypc
    dev/ptypd/tmpfs/dev/ptypd dev/ttypd/tmpfs/dev/ttypd
    dev/ptype/tmpfs/dev/ptype dev/ttype/tmpfs/dev/ttype
    dev/ptypf/tmpfs/dev/ptypf dev/ttypf/tmpfs/dev/ttypf
    tmp/tmpfs/tmp var/tmpfs/var
    dev/log/var/log/log    
    In case you use dhclient also:
    etc/dhclient.conf/tmpfs/var/lib/dhclient.conf etc/resolv.conf/tmpfs/var/lib/resolv.conf

    To place the corresponding directories and device files in the tmpfs file system, the following code is added to the /etc/rc.sh script:
    mkdir -p /tmpfs/tmp /tmpfs/dev \
             /tmpfs/var/lib/dhcp /tmpfs/var/lock /tmpfs/var/run
    
    while read name minor
    do      
            mknod /tmpfs/dev/ptyp$name c 2 $minor
            mknod /tmpfs/dev/ttyp$name c 3 $minor
    done <<__EOD__
    0  0    
    1  1    
    2  2    
    3  3    
    4  4    
    5  5    
    6  6    
    7  7    
    8  8    
    9  9    
    a 10    
    b 11    
    c 12    
    d 13    
    e 14    
    f 15    
    __EOD__ 
    chmod 0666 /tmpfs/dev/*
    
  4. We can now create a cramfs file system image using the mkcramfs tool:
    $ ROOTFS_DIR=rootfs                 # directory with root file system content
    $ ROOTFS_ENDIAN="-r"                # target system has reversed (big) endianess
    $ ROOTFS_IMAGE=cramfs.img           # generated file system image
    
    PATH=/opt/eldk/usr/bin:$PATH
    mkcramfs ${ROOTFS_ENDIAN} ${DEVICES} ${ROOTFS_DIR} ${ROOTFS_IMAGE}
    Swapping filesystem endian-ness
      bin
      dev
      etc
    ...
    -48.78% (-86348 bytes)  in.ftpd
    -46.02% (-16280 bytes)  in.telnetd
    -45.31% (-74444 bytes)  xinetd
    Everything: 1864 kilobytes
    Super block: 76 bytes
    CRC: c166be6d
    warning: gids truncated to 8 bits.  (This may be a security concern.)
    
  5. We can use the same setup as before for the JFFS2 filesystem, just changing the bootargument to "rootfstype=cramfs"


9.5.4. Root File System on a Read-Only ext2 File System

When storing the root file system in on-board flash memoryit seems only natural to look for special flash filesystemslike JFFS2, or for other file system types that are designedfor such environments like cramfs.It seems to be a bad idea to use a standard ext2 file systembecause it contains neither any type of wear leveling whichis needed for writable file systems in flash memory,nor is it robust against unorderly shutdowns.

The situation changes if we use an ext2 file system which we mountread-only. Such a configuration can be very useful in some situations.

Advantages:

  • very fast
  • low RAM memory footprint

Disadvantages:

  • high flash memory footprint because no compression

To create an ext2 imagethat can be used as a read-only root file systemthe following steps are necessary:

  1. Create a directory tree with the content of the target root filesystem. We do this by unpacking our master tarball:
    $ mkdir rootfs
    $ cd rootfs
    $ tar -zxf /tmp/rootfs.tar.gz
    
  2. Like with the cramfs root file system, we use "tmpfs" for cases where a writable file system is needed and add the following lines to the /etc/rc.sh script:
    # mount TMPFS because root-fs is readonly
    /bin/mount -t tmpfs -o size=2M tmpfs /tmpfs
    
    We also create the same symbolic links for device files that must be placed in a writable filesystem:
    dev/ptyp0/tmpfs/dev/ptyp0 dev/ttyp0/tmpfs/dev/ttyp0
    dev/ptyp1/tmpfs/dev/ptyp1 dev/ttyp1/tmpfs/dev/ttyp1
    dev/ptyp2/tmpfs/dev/ptyp2 dev/ttyp2/tmpfs/dev/ttyp2
    dev/ptyp3/tmpfs/dev/ptyp3 dev/ttyp3/tmpfs/dev/ttyp3
    dev/ptyp4/tmpfs/dev/ptyp4 dev/ttyp4/tmpfs/dev/ttyp4
    dev/ptyp5/tmpfs/dev/ptyp5 dev/ttyp5/tmpfs/dev/ttyp5
    dev/ptyp6/tmpfs/dev/ptyp6 dev/ttyp6/tmpfs/dev/ttyp6
    dev/ptyp7/tmpfs/dev/ptyp7 dev/ttyp7/tmpfs/dev/ttyp7
    dev/ptyp8/tmpfs/dev/ptyp8 dev/ttyp8/tmpfs/dev/ttyp8
    dev/ptyp9/tmpfs/dev/ptyp9 dev/ttyp9/tmpfs/dev/ttyp9
    dev/ptypa/tmpfs/dev/ptypa dev/ttypa/tmpfs/dev/ttypa
    dev/ptypb/tmpfs/dev/ptypb dev/ttypb/tmpfs/dev/ttypb
    dev/ptypc/tmpfs/dev/ptypc dev/ttypc/tmpfs/dev/ttypc
    dev/ptypd/tmpfs/dev/ptypd dev/ttypd/tmpfs/dev/ttypd
    dev/ptype/tmpfs/dev/ptype dev/ttype/tmpfs/dev/ttype
    dev/ptypf/tmpfs/dev/ptypf dev/ttypf/tmpfs/dev/ttypf
    tmp/tmpfs/tmp var/tmpfs/var
    dev/log/var/log/log    
    In case you use dhclient also:
    etc/dhclient.conf/tmpfs/var/lib/dhclient.conf etc/resolv.conf/tmpfs/var/lib/resolv.conf

    To place the corresponding directories and device files in the tmpfs file system, the following code is added to the /etc/rc.sh script:
    mkdir -p /tmpfs/tmp /tmpfs/dev \
             /tmpfs/var/lib/dhcp /tmpfs/var/lock /tmpfs/var/run
    
    while read name minor
    do      
            mknod /tmpfs/dev/ptyp$name c 2 $minor
            mknod /tmpfs/dev/ttyp$name c 3 $minor
    done <<__EOD__
    0  0    
    1  1    
    2  2    
    3  3    
    4  4    
    5  5    
    6  6    
    7  7    
    8  8    
    9  9    
    a 10    
    b 11    
    c 12    
    d 13    
    e 14    
    f 15    
    __EOD__ 
    chmod 0666 /tmpfs/dev/*
    
  3. Like we did for the ramdisk, we now create an ext2 file system image using the genext2fs tool:
    $ ROOTFS_DIR=rootfs                 # directory with root file system content
    $ ROOTFS_SIZE=3700                  # size of file system image
    $ ROOTFS_FREE=100                   # free space wanted
    $ ROOTFS_INODES=380                 # number of inodes
    $ ROOTFS_DEVICES=rootfs_devices.tab # device description file
    $ ROOTFS_IMAGE=ext2.img             # generated file system image
    
    $ genext2fs -U \
            -d ${ROOTFS_DIR} \
            -D ${ROOTFS_DEVICES} \
            -b ${ROOTFS_SIZE} \
            -r ${ROOTFS_FREE} \
            -i ${ROOTFS_INODES} \
            ${ROOTFS_IMAGE}
    
  4. We can again use the same setup as before for the JFFS2 filesystem, just changing the boot argument to "rootfstype=ext2" (or simply omit it completely as this is the default anyway), and we must change the "rw" argument into "ro" to mount our root file system really read-only:
    ...
    Linux version 2.4.25 (wd@xpert) (gcc version 3.3.3 (DENX ELDK 3.1.1 3.3.3-9)) #1 Sun Jun 12 18:32:18 MEST 2005
    On node 0 totalpages: 4096
    zone(0): 4096 pages.
    zone(1): 0 pages.
    zone(2): 0 pages.
    Kernel command line: root=/dev/mtdblock6 ro rootfstype=ext2 ip=192.168.3.80:192.168.3.1::255.255.255.0:tqm860l:eth1:off panic=1
    Decrementer Frequency = 187500000/60
    Calibrating delay loop... 49.86 BogoMIPS
    ...
    


9.5.5. Root File System on a Flash Card

Using an ext2 file system on a flash memory card(like CompactFlash, SD, MMC or a USB memory stick)is standard technology.To avoid unnecessary flash wear it is a good idea to mountthe root file system read-only,or at least using the "noatime" mount option.

For our test we can use the "ext2.img" file from the previous step without changes:

  1. In this test we use a standard CompactFlash card which comes with a single partition on it. We use U-Boot to copy the ext2 file system image into this partition:
    => tftp 100000 /tftpboot/TQM860L/ext2.img
    Using FEC ETHERNET device
    TFTP from server 192.168.3.1; our IP address is 192.168.3.80
    Filename '/tftpboot/TQM860L/ext2.img'.
    Load address: 0x100000
    Loading: #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             ##########################
    done
    Bytes transferred = 3788800 (39d000 hex)
    => ide part
    
    Partition Map for IDE device 0  --   Partition Type: DOS
    
    Partition     Start Sector     Num Sectors     Type
        1                   32          500704       6
    => ide write 100000 20 1ce8
    
    IDE write: device 0 block # 32, count 7400 ... 7400 blocks written: OK
    
    Note that the "ide write" command takes parameters as hex numbers, and the write count is in terms of disk blocks of 512 bytes each. So we have to use 0x20 for the starts sector of the first partition, and 3788800 / 512 = 7400 = 0x1CE8 for the block count.
  2. We now prepare the Linux boot arguments to take this partition as read-only root device:
    => setenv cf_args setenv bootargs root=/dev/hda1 ro
    => setenv flash_cf 'run cf_args addip;bootm ${kernel_addr} - ${fdt_addr}'
    => setenv bootcmd run flash_cf
    
  3. ...and boot the system:
    ...
    Linux version 2.4.25 (wd@xpert) (gcc version 3.3.3 (DENX ELDK 3.1.1 3.3.3-9)) #1 Sun Jun 12 18:32:18 MEST 2005
    On node 0 totalpages: 4096
    zone(0): 4096 pages.
    zone(1): 0 pages.
    zone(2): 0 pages.
    Kernel command line: root=/dev/hda1 ro ip=192.168.3.80:192.168.3.1::255.255.255.0:tqm860l:eth1:off panic=1
    Decrementer Frequency = 187500000/60
    Calibrating delay loop... 49.86 BogoMIPS
    ...
    


9.5.6. Root File System in a Read-Only File in a FAT File System

This is a more complicated example that shows that - dependingon project requirements - many other alternatives for chosing a rootfile system for your embedded system exist.

The scenario is as follows: on your embedded device you use acheap and popular storage medium like CompactFlash, MMC or SD cardsor USB memory sticksto store both the Linux kernel and your root file system.You want to distribute software updates over the internet:your customers can download the file from your web site,or you sent the images by email.Your customers may use any flash card or memory stick they happen to find,so you have no information about brand or size of the storage device.

Unfortunately most of your customers use Windows systems.And they don't want to be bothered with long instructionshow to create special partitions on the storage deviceor how to write binary images or things like that.A simple "copy file" operation is nearly exhausting their capabilities.

What to do?Well, if copying a file is all your customers can do we shouldnot ask for more. Storage devices like CompactFlash cards etc.typically come with a single partition on it, which holds a FAT orVFAT file system. This cannot be used as a Linux root file system directly,so we have to use some trickery.

Here is one possible solution:Your software distribution consistes of two files:The first file is the Linux kernel with a minimal ramdisk image attached(using the multi-file image format for U-Boot); U-Boot can load and boot such files from a FAT or VFAT file system.The second file is your root file system.For convenience and speed we use again an image of an ext2file system.When Linux boots, it will initially use the attached ramdiskas root file system.The programs in this ramdisk will mount the FAT or VFAT file system -read-only.Then we can use a loop device (see losetup(8))to associate the root file system image with a block devicewhich can be used as a mount point.And finally we use pivot_root(8) to change the root file systemto our image on the CF card.

This sounds not so complicated,and actually it is quite simple onceyou understand what needs to be done.Here is a more detailed description:

  1. The root file system image is easy: as mantioned before, we will use an ext2 file system image, and to avoid wearing the flash storage device we will use it in read-only mode - we did a read-only ext2 root file system image before, and here we can just re-use the existing image file.
  2. The initial ramdisk image that performs the pivot_root step must be created from scratch, but we already know how to create ramdisk images, so we just have to figure out what to put in it.

    The most important tool here is nash, a script interpreter that was specifically designed for such purposes (see nash(8)). We don't need any additional tools, and if we use static linking, then the nash binary plus a small script to control it is all we need for our initial ramdisk.

    To be precise, we need a couple of (empty) directories (bin, dev, etc, lib, loopfs, mnt, proc, and sysroot), the bin/nash binary, the linuxrc script and a symbolic link sbin pointing to bin:
    drwxr-xr-x    2 wd       users        4096 Apr 13 01:11 bin
    -rwxr-xr-x    1 wd       users      469512 Apr 11 22:47 bin/nash
    drwxr-xr-x    2 wd       users        4096 Apr 12 00:04 dev
    drwxr-xr-x    2 wd       users        4096 Apr 12 00:04 etc
    drwxr-xr-x    2 wd       users        4096 Apr 12 00:04 lib
    -rwxr-xr-x    1 wd       users         511 Apr 13 01:28 linuxrc
    drwxr-xr-x    2 wd       users        4096 Apr 12 00:04 loopfs
    drwxr-xr-x    2 wd       users        4096 Apr 12 00:09 mnt
    drwxr-xr-x    2 wd       users        4096 Apr 12 00:04 proc
    lrwxrwxrwx    1 wd       users           3 Jun 12 18:54 sbin -> bin
    drwxr-xr-x    2 wd       users        4096 Apr 12 00:04 sysroot
    
  3. We also need only a minimal device table for creating the initial ramdisk:
    #<name>    <type> <mode> <uid> <gid> <major> <minor> <start>  <inc>  <count>
    /dev            d  755  0       0       -       -       -       -       -
    /dev/console    c  640  0       0        5      1       -       -       -
    /dev/hda        b  640  0       0        3      0       -       -       -
    /dev/hda        b  640  0       0        3      1       1       1       8
    /dev/loop       b  640  0       0        7      0       0       1       4
    /dev/null       c  640  0       0        1      3       -       -       -
    /dev/ram        b  640  0       0        1      0       0       1       2
    /dev/ram        b  640  0       0        1      1       -       -       -
    /dev/tty        c  640  0       0        4      0       0       1       4
    /dev/tty        c  640  0       0        5      0       -       -       -
    /dev/ttyS       c  640  0       0        4      64      0       1       4
    /dev/zero       c  640  0       0        1      5       -       -       -
    
  4. To create the initial ramdisk we perform the usual steps:
    $ INITRD_DIR=initrd
    $ INITRD_SIZE=490
    $ INITRD_FREE=0
    $ INITRD_INODES=54
    $ INITRD_DEVICES=initrd_devices.tab
    $ INITRD_IMAGE=initrd.img
    
    $ genext2fs -U \
            -d ${INITRD_DIR} \
            -D ${INITRD_DEVICES} \
            -b ${INITRD_SIZE} \
            -r ${INITRD_FREE} \
            -i ${INITRD_INODES} \
            ${INITRD_IMAGE}
    
    $ gzip -v9 ${INITRD_IMAGE}
    
    The result is a really small (233 kB) compressed ramdisk image.
  5. Assuming you already have your Linux kernel image, you can now use mkimage to build an U-Boot multi-file image that combines the Linux kernel and the initial ramdisk:
    $ LINUX_KERNEL=linuxppc_2_4_devel/arch/ppc/boot/images/vmlinux.gz
    $ mkimage -A ppc -O Linux -T multi -C gzip \
    > -n 'Linux with Pivot Root Helper' \
    > -d ${LINUX_KERNEL}:${INITRD_IMAGE}.gz linux.img
    Image Name:   Linux with Pivot Root Helper
    Created:      Mon Jun 13 01:48:11 2005
    Image Type:   PowerPC Linux Multi-File Image (gzip compressed)
    Data Size:    1020665 Bytes = 996.74 kB = 0.97 MB
    Load Address: 0x00000000
    Entry Point:  0x00000000
    Contents:
       Image 0:   782219 Bytes =  763 kB = 0 MB
       Image 1:   238433 Bytes =  232 kB = 0 MB
    
    The newly created file linux.img is the second image we have to copy to the CF card.

    We are done.

But wait - one essential part was not mentioned yet:the linuxrc script in our initial ramdisk imagewhich contains all the magic.This script is quite simple:

#!/bin/nash

echo Mounting /proc filesystem
mount -t proc /proc /proc

echo Creating block devices
mkdevices /dev

echo Creating root device
mkrootdev /dev/root
echo 0x0100 > /proc/sys/kernel/real-root-dev

echo Mounting flash card
mount -o noatime -t vfat /dev/hda1 /mnt

echo losetup for filesystem image
losetup /dev/loop0 /mnt/rootfs.img

echo Mounting root filesystem image
mount -o defaults --ro -t ext2 /dev/loop0 /sysroot

echo Running pivot_root
pivot_root /sysroot /sysroot/initrd
umount /initrd/proc
Let's go though it step by step:
  • The first line says that it's a script file for the /bin/nash interpreter.
    ALERT! Note: even if this file looks like a shell script it is NOT interpreted by a shell, but by the nash interpreter. For a complete list of available nash commands and their syntax please refer to the manual page, nash(8).
  • The first action is to mount the /proc pseudo file system which is needed to find out some required information.
  • Then we create block device entries for all partitions listed in /proc/partitions (mkdevices command).
  • In the next step a block device for our new root file system is created (mkrootdev command).
  • Then we mount the CF card. We assume that there is only a single partition on it (/dev/hda1) which is of type VFAT (which also will work with FAT file systems). These assumptions work fine with basicly all memory devices used under Windows.
  • We further assume that the file name of the root file system image on the CF card is "rootfs.img" - this file now gets mounted using a loop device (losetup and mount commands).
  • Our file system image, is now mounted on the /sysroot directory. In the last step we use pivot_root to make this the new root file system.
  • As a final cleanup we unmount the /proc file system which is not needed any more.
There is one tiny flaw in this method:since we mount the CF card on a directory in the ramdiskto be able to access to root file system image.This means that we cannot unmount the CF card,which in turn prevents us from freeing the space for theinital ramdisk.The consequence is that you permanently loseapprox. 450 kB of RAM for the ramdisk.[We could of course re-use this ramdisk space for temporary data,but such optimization is beyond the scope of this document.]

And how does this work on our target?

  1. First we copy the two images to the CF card; we do this on the target under Linux:
    bash-2.05b# fdisk -l /dev/hda
    
    Disk /dev/hda: 256 MB, 256376832 bytes
    16 heads, 32 sectors/track, 978 cylinders
    Units = cylinders of 512 * 512 = 262144 bytes
    
       Device Boot    Start       End    Blocks   Id  System
    /dev/hda1   *         1       978    250352    6  FAT16
    bash-2.05b# mkfs.vfat /dev/hda1
    mkfs.vfat 2.8 (28 Feb 2001)
    bash-2.05b# mount -t vfat /dev/hda1 /mnt
    bash-2.05b# cp -v linux.img rootfs.img /mnt/
    `linux.img' -> `/mnt/linux.img'
    `rootfs.img' -> `/mnt/rootfs.img'
    bash-2.05b# ls -l /mnt
    total 4700
    -rwxr--r--    1 root     root      1020729 Jun 14 05:36 linux.img
    -rwxr--r--    1 root     root      3788800 Jun 14 05:36 rootfs.img
    bash-2.05b# umount /mnt
    
  2. We now prepare U-Boot to load the "uMulti" file (combined Linux kernel and initial ramdisk) from the CF card and boot it:
    => setenv fat_args setenv bootargs rw
    => setenv fat_boot 'run fat_args addip;fatload ide 0:1 200000 linux.img;bootm'
    => setenv bootcmd run fat_boot
    
  3. And finally we try it out:
    U-Boot 1.1.3 (Jun 13 2005 - 02:24:00)
    
    CPU:   XPC86xxxZPnnD4 at 50 MHz: 4 kB I-Cache 4 kB D-Cache FEC present
    Board: TQM860LDB0A3-T50.202
    DRAM:  16 MB
    FLASH:  8 MB
    In:    serial
    Out:   serial
    Err:   serial
    Net:   SCC ETHERNET, FEC ETHERNET [PRIME]
    PCMCIA: 3.3V card found: Transcend    256M
                Fixed Disk Card
                IDE interface 
                [silicon] [unique] [single] [sleep] [standby] [idle] [low power]
    Bus 0: OK 
      Device 0: Model: Transcend    256M Firm: 1.1 Ser#: SSSC256M04Z27A25906T
                Type: Removable Hard Disk
                Capacity: 244.5 MB = 0.2 GB (500736 x 512)
    
    Type "run flash_nfs" to mount root filesystem over NFS
    
    Hit any key to stop autoboot:  0 
    reading linux.img
    
    1025657 bytes read
    ## Booting image at 00200000 ...
       Image Name:   Linux with Pivot Root Helper
       Created:      2005-06-13   0:32:41 UTC
       Image Type:   PowerPC Linux Multi-File Image (gzip compressed)
       Data Size:    1025593 Bytes = 1001.6 kB
       Load Address: 00000000
       Entry Point:  00000000
       Contents:
       Image 0:   787146 Bytes = 768.7 kB
       Image 1:   238433 Bytes = 232.8 kB
       Verifying Checksum ... OK
       Uncompressing Multi-File Image ... OK
       Loading Ramdisk to 00f3d000, end 00f77361 ... OK
    Linux version 2.4.25 (wd@xpert) (gcc version 3.3.3 (DENX ELDK 3.1.1 3.3.3-9)) #1 Mon Jun 13 02:32:10 MEST 2005
    On node 0 totalpages: 4096
    zone(0): 4096 pages.
    zone(1): 0 pages.
    zone(2): 0 pages.
    Kernel command line: rw ip=192.168.3.80:192.168.3.1::255.255.255.0:tqm860l:eth1:off panic=1
    Decrementer Frequency = 187500000/60
    Calibrating delay loop... 49.86 BogoMIPS
    ...
    NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
    RAMDISK: Compressed image found at block 0
    Freeing initrd memory: 232k freed
    VFS: Mounted root (ext2 filesystem).
    Red Hat nash version 4.1.18 starting
    Mounting /proc filesystem
    Creating block devices
    Creating root device
    Mounting flash card
     hda: hda1
     hda: hda1
    losetup for filesystem image
    Mounting root filesystem image
    Running pivot_root
    Freeing unused kernel memory: 60k init
    
    
    BusyBox v0.60.5 (2005.03.07-06:54+0000) Built-in shell (msh)
    Enter 'help' for a list of built-in commands.
    
    # ### Application running ...
    

Kernel with a Flattened Device Tree Blob

When booting an arch/powerpc kernel that requires a flattened device tree blob, the above procedure must be slightly modified. Namely, the multi-image file has to include the blob as the thrid image. Here's an example of the mkimage command to create it:
mkimage -A ppc -O Linux -T multi -C gzip -n 'Kernel + Pivot Root Helper initrd + FDT blob' -d vmlinux.bin.gz:ramdisk_image.gz:canyonlands.dtb kernel+initrd+blob.img
Image Name:   Kernel + Pivot Root Helper initrd + FDT blob
Created:      Fri Sep 14 18:24:29 2007
Image Type:   PowerPC Linux Multi-File Image (gzip compressed)
Data Size:    2894576 Bytes = 2826.73 kB = 2.76 MB
Load Address: 0x00000000
Entry Point:  0x00000000
Contents:
   Image 0:  1351205 Bytes = 1319 kB = 1 MB
   Image 1:  1531063 Bytes = 1495 kB = 1 MB
   Image 2:    12288 Bytes =   12 kB = 0 MB

The newly created file kernel+initrd+blob.img needs to be copied to the CF card.


9.6. Root File System Selection

Now we know several options for file systems we can use,and know how to create the corresponding images.But how can we decide which one to chose?

For practical purposes in embedded systemsthe following criteria are often essential:

  • boot time (i. e. time needed from power on until application code is running)
  • flash memory footprint
  • RAM memory footprint
  • effects on software updates

The following data was measured for the different configurations.All measurements were performed on the same TQM860L board (MPC860 CPU at 50 MHz, 16 MB RAM, 8 MB flash, 256 MB CompactFlash card):

File System TypeBoot TimeFree MemUpdateswhile running
ramdisk16.3 sec6.58 MBwhole imageyes
JFFS221.4 sec10.3 MBper fileonly non-active files
cramfs10.8 sec10.3 MBwhole imageno
ext2 (ro)9.1 sec10.8 MBwhole imageno
ext2 on CF (ro)9.3 sec10.9 MBwhole imageno
File on FAT fs11.4 sec7.8 MBwhole imageyes

As you can see, the ramdisk solution is the worst of allin terms of RAM memory footprint;also it takes a pretty long time to boot.However, it is one of the few solutions that allow an in-situupdate while the system is running.

JFFS2 is easy to use as it's a writable file systembut it takes a long time to boot.

A read-only ext2 file system shines when boot time and RAM memoryfootprint are important; you pay for this with an increased flash memoryfootprint.

External flash memory devices like CompactFlash cards or USB memorysticks can be cheap and efficient solutions especially whenlots of data need to be stored or when easy update procedures are required.



Other resources http://man.chinaunix.net/linux/how/Bootdisk-HOWTO-4.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值