A Linux kernel is not very useful without a root file system containing applications and settings. Root file systems can be created in several formats: mountable over a network (NFS), a RAMDISK, or stored in flash (flash file system). Instructions on building and using these file systems is scattered over the Internet and/or in the Documentation directory in a Linux distribution. This note will describe building a simple root file system in the following formats: mountable over NFS, RAMDISK, Journaling Flash File System 2 (JFFS2), and a read-only flash file system known as CRAMFS.
Introduction
The root file system built in this note is based on BusyBox, also known as “The Swiss Army Knife of Embedded Linux”. BusyBox contains reduced size versions of the most commonly used Unix utilities, all in a single executable. It is customizable so that only the utilities that are needed are built. This note guides the reader through the following:
Downloading and building BusyBox
Mounting the root file system over NFS
Building and testing a RAMDISK from the BusyBox target
Building and testing a JFFS2 file system from the BusyBox target
Building and testing a CRAMFS file system from the BusyBox target
This note assumes that the reader has root privileges on a PC running Linux. The busybox executable and all symbolic links to it must have user and group ownership set to “root”. This is required because the kernel boots as root. If the generated root file system does not have user/group set to root, the kernel will not boot. There are utility programs on the Internet that can change this, but these are out of the scope of this document.
Nomenclature
For this note, all source and target files are assumed to be in the user’s home directory. For simplicity, this note will assume the user’s directory is “user”. The home directory is then
/home/user
All source code will be in the “src” directory, or
/home/user/src
Code will be built in the “build” directory, or
/home/user/build
The target root file system will be built in the “target” directory, or
/home/user/target
To create these directories, go to /home/user and enter
Configure the Linux Kernel to Support File Systems
The Linux kernel must be configured to support the file systems described in this note. To configure the kernel enter “make menuconfig” on the command line. The sub-menus and options to select follow. The Linux kernel source used in this note is from the Texas Instruments V2.6.22.18-OMAP3 release. The sub-menus may be different for other Linux sources and versions.
Device Node Creation
In Linux root file systems the /dev directory contains device nodes – special files that give application access to devices on the system. One example is a serial port. The device node for the first serial port on the system could be /dev/ttyS0. An application could open/read/write/close the serial port. The problem when creating a root file system is which device nodes are needed and which are not?
Early on in Linux root file systems, the creator would statically build the nodes with the “mknod” command (e.g. mknod target/dev/ttyS0 c 4 64). This led to missing nodes, unnecessary nodes, or nodes with the wrong name. During the 2.4.x kernels, the devfs file system was introduced. When device drivers loaded they would register with the devfs file system and the device node would be created. There were problems with this so that starting at 2.6.11 kernels, devfs was removed and replaced.
The current method for dynamic device node creation is to use kernel hotplug with the sysfs and tmpfs file systems. During initialization, when file systems are getting mounted, the tmpfs file system is mounted on /dev. That way all device nodes are in virtual memory and are not saved between reboots of the board.
A driver registers with sysfs and gets added to the system. The kernel then runs the application pointed to by /proc/sys/kernel/hotplug to create the device node and to run any additional scripts (e.g. mounting a device). The application used by the Texas Instruments v2.6.22.x releases is built into busybox and is called “mdev.” This will be described later.
The v2.6.22.x releases default to enabling hotplug, sysfs, and tmpfs. To make sure hotplug is set, type in “make menuconfig” and from the “Main menu” use the down arrow key to scroll down to the “General setup” entry and press the Enter key to select it. Scroll down to “Configure standard kernel features (for small systems)” and press the Enter key. Scroll down to “Support for hot-pluggable devices” and make sure it is set. The Space Bar selects and de-selects options. A sample sub-menu is shown below:
┌──────── Configure standard kernel features (for small systems) ─────────┐
│ Arrow keys navigate the menu. selects submenus --->. │
│ Highlighted letters are hotkeys. Pressing includes, excludes, │
│ modularizes features. Press to exit, > for Help, > │
│ for Search. Legend: [*] built-in [ ] excluded module < > │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ --- Configure standard kernel features (for small systems) │ │
│ │ [*] Enable 16-bit UID system calls │ │
│ │ [ ] Sysctl syscall support │ │
│ │ [*] Load all symbols for debugging/ksymoops │ │
│ │ [ ] Include all symbols in kallsyms │ │
│ │ [*] Do an extra kallsyms pass │ │
│ │ [*] Support for hot-pluggable devices │ │
│ │ [*] Enable support for printk │ │
│ │ [*] BUG() support │ │
│ │ [*] Enable ELF core dumps │ │
│ └────v(+)─────────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────────────────┤
│
To ensure sysfs and tmpfs are selected, start back at the “Main menu” and scroll down to the “File systems” option. Press Enter to select it and then scroll down to the “Pseudo filesystems” option and press Enter to select it. The file systems selected here should be: /proc, /proc/sys, sysfs, and “Virtual memory file system support.” That last one is also referred to as /tmpfs. A sample sub-menu is shown below.
Configure the Linux Kernel for Root File System over NFS
In this configuration the root file system resides on a PC running a NFS server. From the “Main Menu” use the down arrow to scroll down to “File systems” and select it by pressing the Enter key. Under “File Systems” scroll down to “Network file systems” and select it. On this page make sure that “NFS file system support”, “Provide NFSv3 client support”, “Provide NFSv4 client support,” and “Root file system on NFS” are selected. A sample sub-menu is shown below.
┌───────────────────────── Network File Systems ──────────────────────────┐
│ Arrow keys navigate the menu. selects submenus --->. │
│ Highlighted letters are hotkeys. Pressing includes, excludes, │
│ modularizes features. Press to exit, > for Help, > │
│ for Search. Legend: [*] built-in [ ] excluded module < > │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ <*> NFS file system support │ │
│ │ [*] Provide NFSv3 client support │ │
│ │ [ ] Provide client support for the NFSv3 ACL protocol extensi│ │
│ │ [*] Provide NFSv4 client support (EXPERIMENTAL) │ │
│ │ [ ] Allow direct I/O on NFS files │ │
│ │ < > NFS server support │ │
│ │ [*] Root file system on NFS │ │
│ │ [ ] Support for rpcbind versions 3 & 4 (EXPERIMENTAL) │ │
│ │ --- Secure RPC: Kerberos V mechanism (EXPERIMENTAL) │ │
│ │ < > Secure RPC: SPKM3 mechanism (EXPERIMENTAL) │ │
│ └────v(+)─────────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────────────────┤
│
Configure the Linux Kernel for RAMDISK support
In this configuration the u-boot boot loader is used to download a binary image to RAM and pass parameters to the kernel telling it the root file system is on a ramdisk, where it is located, and its size. From the “Main menu” scroll down to “Device Drivers” and select it. Then scroll down to “Block devices” and select it. On this sub-menu make sure “RAM disk support” is selected. For the “Default RAM disk size” enter 16384. The RAM disk built in this note is 16M.
┌───────────────────────────── Block devices ─────────────────────────────┐
│ Arrow keys navigate the menu. selects submenus --->. │
│ Highlighted letters are hotkeys. Pressing includes, excludes, │
│ modularizes features. Press to exit, > for Help, > │
│ for Search. Legend: [*] built-in [ ] excluded module < > │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ <*> Loopback device support │ │
│ │ < > Cryptoloop Support │ │
│ │ < > Network block device support │ │
│ │ < > Low Performance USB Block driver │ │
│ │ <*> RAM disk support │ │
│ │ (16) Default number of RAM disks │ │
│ │ (16384) Default RAM disk size (kbytes) │ │
│ │ (1024) Default RAM disk block size (bytes) │ │
│ │ < > Packet writing on CD/DVD media │ │
│ │ < > ATA over Ethernet support │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────────────────┤
│
The step above configures the kernel for build in a ramdisk. Now go back to the “Main menu” and again select “General setup.” Scroll down and make sure “Initial RAM filesystem and RAM disk (initramfs/initrd) support” is selected. By default in the T.I. kernel it is.
┌───────────────────────────── General setup ─────────────────────────────┐
│ Arrow keys navigate the menu. selects submenus --->. │
│ Highlighted letters are hotkeys. Pressing includes, excludes, │
│ modularizes features. Press to exit, > for Help, > │
│ for Search. Legend: [*] built-in [ ] excluded module < > │
│ ┌────^(-)─────────────────────────────────────────────────────────────┐ │
│ │ [ ] Auditing support │ │
│ │ <*> Kernel .config support │ │
│ │ [*] Enable access to .config through /proc/config.gz │ │
│ │ (14) Kernel log buffer size (16 => 64KB, 17 => 128KB) │ │
│ │ [*] Create deprecated sysfs files │ │
│ │ [ ] Kernel->user space relay support (formerly relayfs) │ │
│ │ [*] Initial RAM filesystem and RAM disk (initramfs/initrd) suppor│ │
│ │ () Initramfs source file(s) │ │
│ │ [*] Optimize for size (Look out for broken compilers!) │ │
│ │ [*] Configure standard kernel features (for small systems) ---> │ │
│ │ Choose SLAB allocator (SLAB) ---> │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────────────────┤
│
Configure the Linux Kernel for Memory Technology Devices (MTD)
To use any of the flash file systems, such as JFFS2 or CRAMFS, the MTD layer must be configured. MTD are typically flash devices used for storage. Configuring the individual drivers can be tricky. If a device is CFI compliant then all that is needed is to select the CFI options. In this example, CFI is selected, as is Intel/Sharp just in case the part it not CFI compliant. Starting at the “Main menu” scroll down to “Device Drivers” and select it. Scroll down to “Memory Technology Devices (MTD) support” and select it. There are numerous options that can/should be selected. The screen captures below are lengthy.
┌──────────────── Memory Technology Device (MTD) support ─────────────────┐
│ Arrow keys navigate the menu. selects submenus --->. │
│ Highlighted letters are hotkeys. Pressing includes, excludes, │
│ modularizes features. Press to exit, > for Help, > │
│ for Search. Legend: [*] built-in [ ] excluded module < > │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ --- Memory Technology Device (MTD) support │ │
│ │ [ ] Debugging │ │
│ │ <*> MTD concatenating support │ │
│ │ [*] MTD partitioning support │ │
│ │ < > RedBoot partition table parsing │ │
│ │ [*] Command line partition table parsing │ │
│ │ < > ARM Firmware Suite partition parsing │ │
│ │ --- User Modules And Translation Layers │ │
│ │ <*> Direct char device access to MTD devices │ │
│ │ --- Common interface to block layer for MTD 'translation layers│ │
│ │ <*> Caching block device access to MTD devices │ │
│ │ < > FTL (Flash Translation Layer) support │ │
│ │ < > NFTL (NAND Flash Translation Layer) support │ │
│ │ < > INFTL (Inverse NAND Flash Translation Layer) support │ │
│ │ < > Resident Flash Disk (Flash Translation Layer) support │ │
│ │ < > NAND SSFDC (SmartMedia) read only translation layer │ │
│ │ RAM/ROM/Flash chip drivers ---> │ │
│ │ Mapping drivers for chip access ---> │ │
│ │ Self-contained MTD device drivers ---> │ │
│ │ <*> NAND Device Support ---> │ │
│ │ <*> OneNAND Device Support ---> │ │
│ │ UBI - Unsorted block images ---> │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────────────────┤
│
Select the “RAM/ROM/Flash chip drivers” and ensure CFI and Intel/Sharp are selected.
┌────────────────────── RAM/ROM/Flash chip drivers ───────────────────────┐
│ Arrow keys navigate the menu. selects submenus --->. │
│ Highlighted letters are hotkeys. Pressing includes, excludes, │
│ modularizes features. Press to exit, > for Help, > │
│ for Search. Legend: [*] built-in [ ] excluded module < > │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ <*> Detect flash chips by Common Flash Interface (CFI) probe │ │
│ │ < > Detect non-CFI AMD/JEDEC-compatible flash chips │ │
│ │ [ ] Flash chip driver advanced configuration options │ │
│ │ <*> Support for Intel/Sharp flash chips │ │
│ │ < > Support for AMD/Fujitsu flash chips │ │
│ │ < > Support for ST (Advanced Architecture) flash chips │ │
│ │ < > Support for RAM chips in bus mapping │ │
│ │ < > Support for ROM chips in bus mapping │ │
│ │ < > Support for absent chips in bus mapping │ │
│ │ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────────────────┤
│
Finally, go back to the MTD menu and select the “Mapping drivers for chip access” option. This option enables the partitioning of the MTD into four partitions: u-boot, u-boot environment, kernel, and file system.
┌──────────────────── Mapping drivers for chip access ────────────────────┐
│ Arrow keys navigate the menu. selects submenus --->. │
│ Highlighted letters are hotkeys. Pressing includes, excludes, │
│ modularizes features. Press to exit, > for Help, > │
│ for Search. Legend: [*] built-in [ ] excluded module < > │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ [ ] Support non-linear mappings of flash chips │ │
│ │ < > CFI Flash device in physical memory map │ │
│ │ < > CFI Flash device mapped on ARM Integrator/P720T │ │
│ │ <*> TI OMAP board mappings │ │
│ │ < > Map driver for platform device RAM (mtd-ram) │ │
│ │ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────────────────┤
│
Configure the Linux Kernel for Flash File Systems (JFFS2 and CRAMFS)
JFFS2 is a second generation journaling flash file system with improved wear leveling and compression. CRAMFS is a compressed ROM file system that is read-only, therefore any writes will generate error messages on the console. If any of the logging utilities are started, they should re-direct their output to a file on a file system capable of read-write. Otherwise, do not start any of the logging utilities at boot. To configure the kernel, start at the “Main menu”, scroll down to the “File systems” entry, and select it. Scroll down to “Miscellaneous filesystems” and select it. Scroll down to “Journalling Flash File System v2 (JFFS2) support” and select it. There are other JFFS2 options to select – see the sub-menu below. Continue scrolling down and select “Compressed ROM file system support (cramfs)”.
┌─────────────────────── Miscellaneous filesystems ───────────────────────┐
│ Arrow keys navigate the menu. selects submenus --->. │
│ Highlighted letters are hotkeys. Pressing includes, excludes, │
│ modularizes features. Press to exit, > for Help, > │
│ for Search. Legend: [*] built-in [ ] excluded module < > │
│ ┌────^(-)─────────────────────────────────────────────────────────────┐ │
│ │ <*> Journalling Flash File System v2 (JFFS2) support │ │
│ │ (0) JFFS2 debugging verbosity (0 = quiet, 2 = noisy) │ │
│ │ [*] JFFS2 write-buffering support │ │
│ │ [ ] JFFS2 summary support (EXPERIMENTAL) │ │
│ │ [ ] JFFS2 XATTR support (EXPERIMENTAL) │ │
│ │ [*] Advanced compression options for JFFS2 │ │
│ │ [*] JFFS2 ZLIB compression support │ │
│ │ [*] JFFS2 RTIME compression support │ │
│ │ [ ] JFFS2 RUBIN compression support │ │
│ │ JFFS2 default compression mode (priority) ---> │ │
│ │ <*> Compressed ROM file system support (cramfs) │ │
│ │ < > FreeVxFS file system support (VERITAS VxFS(TM) compatible) │ │
│ └────v(+)─────────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────────────────┤
│
Download and Build BusyBox
The source to BusyBox can be downloaded fromhttp://www.busybox.net/downloads. One of the smallest and most stable version at the time of this writing is busybox-1.11.1.tar.bz2. Download it to the /home/user/src directory. Change directory to the build directory and extract the source code with the tar utility. The command line options to tar are: x extract the files j the is a file zipped with bzip2 so use bunzip2 to uncompress v display the files as they are extracted f the following file contains the source
[root@localhost src]# cd ../build
[root@localhost build]# tar -xjvf ../src/busybox-1.2.2.1.tar.bz2
As the files are extracted, their names are displayed.
Under the /home/user/build directory there should now be a busybox-1.2.2.1 directory. Change directory to it to start selecting build options. To configure build options, type in make menuconfig.
[root@localhost build]# cd busybox-1.2.2.1
[root@localhost busybox-1.2.2.1]# make menuconfig
To save on space, a hierarchical listing of options that must be selected is shown below.
Busybox Settings
General Configuration
Show terse applet usage messages
Store applet usage messages in compressed form
Use the devpts filesystem for Unix98 PTYs
(/proc/self/exe) Path to BusyBox executable
Build Options
Build BusyBox as a static binary (no shared libs)
Build with Large File Support
Do you want to build BusyBox with a Cross Compiler
(/opt/arm-2007q3/bin/arm-none-linux-gnueabi-) Cross Compiler prefix
Coreutils
basename
cat
chmod
cp
cut
echo
false
head
hostid
ln
ls
mkdir
mkfifo
mknod
mv
pwd
rm
sync
tail
touch
true
uname
yes
Console Utilities
clear
reset
Editors
awk
sed
vi
Finding Utilities
find
grep
Init Utilities
init (keep the defaults that come with this selection)
Support running commands with a controlling-tty
poweroff, halt, and reboot
mesg
Login/Password Management Utilities
Use internal password and group functuions
getty
login
(de-select Support for /etc/securetty)
Linux Module Utilities
insmod
rmmod
lsmod
modprobe
Support version 2.6.x Linux kernels
Linux System Utilities
dmesg
mdev
Support /etc/mdev.conf
Support command execution at device addition/removal
mkswap
more
mount
swaponoff
umount
umount –a option
Networking Utilities
hostname
ifconfig
ping
telnet
telnetd
Process Utilities
kill
killall
pidof
ps
Shells
ash (keep all the defaults)
Expand prompt string
---Bourne Shell Options
Command line editing
History saving
Tab completion
Fancy shell prompts
System Logging Utilities
syslogd
klogd
To build BusyBox, simply type inmakeat the command line. After a few minutes the compile should be complete. When compilation is complete install BusyBox to the target directory. The make and install commands are show below:
[root@localhost busybox-1.2.2.1]# make
[root@localhost busybox-1.2.2.1]# make CONFIG_PREFIX=/home/user/target install
Configure the New Target Root File System
Looking at the newly built root file system, there are only three subdirectories of binaries and a symbolic link of bin/busybox to linuxrc. More directories must be created before the file system can be used. Some device nodes should be created, too.
[root@localhost bin]# cd /home/user/target/
[root@localhost target]# dir
total 28
drwxr-xr-x 2 root root 4096 Nov 21 10:20 bin
lrwxrwxrwx 1 root root 11 Nov 21 10:20 linuxrc -> bin/busybox
drwxr-xr-x 2 root root 4096 Nov 21 10:20 sbin
drwxr-xr-x 4 root root 4096 Nov 21 10:20 usr
[root@localhost target]#
Create the dev, dev/pts, etc, etc/init.d, lib, mnt, opt, proc, root, sys, tmp, var, and var/log directories. Also create the device node for the initial console.
Since 2.6.11 the debugfs has been introduced and so you may optionally create a directory called debug for mounting the debugfs.
[root@localhost target]# mkdir debug
To have the /proc and /dev/pts file systems mounted at boot time, the file etc/fstab must be created in the etc directory. Use an editor to create the file. The example below uses vi to create the file. The two lines to enter into fstab are shown below the vi fstab line.
[root@localhost target]# cd etc
[root@localhost etc]# vi fstab
proc /proc proc defaults 0 0
none /dev/pts devpts mode=0622 0 0
The login utilities use the files group, hosts, and passwd in the etc directory for logging in. For now, only root needs to be defined in group and passwd while hosts just needs to have localhost defined. The contents of the three files are show below:
[root@localhost etc]# vi group
root:x:0:root
[root@localhost etc]# vi passwd
root::0:0:root:/root:/bin/ash
[root@localhost etc]# vi hosts
127.0.0.1 localhost
The kernel starts “/sbin/init” after it boots (actually the kernel attempts to execute several known programs until one succeeds). Init reads the etc/inittab file to determine what to do at start up, shutdown, or when a user logs in. These inittab files can get quite complicated. A simple one is shown below:
[root@localhost etc]# vi inittab
::sysinit:/etc/init.d/rcS
# /bin/ash
#
# Start an "askfirst" shell on the serial port
console::askfirst:-/bin/ash
# Stuff to do when restarting the init process
::restart:/sbin/init
# Stuff to do before rebooting
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::shutdown:/sbin/swapoff -a
The “sysinit” line tells init to run the /etc/init.d/rcS script to set up the system. The rest are self explanatory.
A simple etc/init.d/rcS file could assume file systems existed in the kernel and would simply mount the mount points as needed. A more complicated one would test for the existence of file systems and if found, mount them; if not found, find ways to still get the system booted.
The author has taken the etc/init.d/rcS and mdev.conf files from the V2.6.22.18-OMAP3 release for a simple example. The rcS script will test for the existence of file systems and mount them accordingly. The 1.11.1 version of BusyBox does not create a link for /bin/sh so change any /bin/sh to /bin/ash. The contents are shown below:
[root@localhost etc]# vi init.d/rcS
#!/bin/sh
# ---------------------------------------------
# Common settings
# ---------------------------------------------
HOSTNAME=OMAP3EVM
VERSION=1.0.0
hostname $HOSTNAME
# ---------------------------------------------
# Prints exec