How to Build a Custom Root Filesystem for Embedded Linux with BusyBox
This guide explains the concepts of Linux file systems, compares root and regular file systems, lists common embedded flash file systems, outlines required root‑FS directories, and provides a step‑by‑step procedure—including cross‑compilation, BusyBox configuration, mounting, and ramdisk creation—to build and test a minimal root filesystem for an embedded device.
Analysis
In embedded Linux a root filesystem is required at boot to provide the directory hierarchy, essential binaries, configuration files, and device nodes. Linux supports many file system types (ext2/3, vfat, ntfs, iso9660, jffs, yaffs, romfs, nfs, etc.) and abstracts them through the Virtual File System (VFS). For embedded devices the typical storage media are RAM and flash, so flash‑oriented file systems such as cramfs, jffs2, yaffs, and romfs are commonly used.
Flash‑based file systems
Cramfs : read‑only, fast, reliable, but cannot be expanded.
Jffs2 : journalling flash FS, supports read/write, compression, wear‑leveling; performance degrades when the FS is near full.
Yaffs/Yaffs2 : designed for NAND flash, lightweight, fast mounting, supports small‑page (yaffs) and large‑page (yaffs2) NAND.
NFS : network file system useful for mounting a host‑side rootfs during development.
Tools for creating these images include mkfs.cramfs, mkfs.jffs2, and mkfs.yaffs (source links omitted for brevity).
Root Filesystem Composition
Top‑level directories
bin – basic executables
opt – optional packages
boot – bootloader files
proc – virtual process info
dev – device nodes
root – root user home
etc – configuration files
sbin – system administration binaries
home – regular user homes
tmp – temporary files
lib – shared libraries
usr – user applications
mnt – mount points
var – variable data such as logs
Directories needed for an embedded rootfs
/bin /sbin /etc /proc /tmp /var /dev /mntThe minimal rootfs must contain:
Essential directory hierarchy and kernel‑required mount points.
Required libraries (e.g., glibc).
System scripts such as rcS, inittab, and fstab.
Device node files (e.g., /dev/hd*, /dev/tty*).
Basic utilities (sh, ls, cp, mv, etc.).
Default Preconditions
Cross‑compilation toolchain
Install an ARM cross‑compiler, e.g., arm-none-linux-gnueabi-gcc, typically under /home/peng/toolchain/gcc-4.6.4/.
TFTP server
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/tftpboot"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="--secure"NFS server
/source/rootfs *(rw,sync,no_subtree_check)Filesystem Creation Steps
1. Download source
http://busybox.net/downloads/busybox-1.22.1.tar.bz22. Extract source
tar xvf busybox-1.22.1.tar.bz23. Enter directory
cd busybox-1.22.14. Configure
make menuconfig
# Enable static build, set cross‑compiler prefix to arm-none-linux-gnueabi-
# (other options left as default)5. Build
make6. Install
make install # installs into _install directory7. Create required directories
mkdir dev etc mnt proc var tmp sys root8. Copy libraries from the toolchain
cp -a /home/linux/toolchain/gcc-4.6.4/arm-arm1176jzfssf-linux-gnueabi/lib/ .
chmod +w lib
arm-none-linux-gnueabi-strip lib/*
# Ensure total lib size < 8 MiB9. Add init scripts
Create /etc/inittab:
#this is run first except when booting in single‑user mode.
::sysinit:/etc/init.d/rcS
::askfirst:-/bin/sh
::restart:/sbin/init
::ctrlaltdel:/sbin/rebootCreate /etc/fstab:
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0Ensure the kernel is configured for proc, sysfs, and tmpfs support via make menuconfig.
10. Create rcS script
#!/bin/sh
/bin/mount -a
echo /sbin/mdev > /proc/sys/kernel/hotplug
/sbin/mdev -sMake it executable: chmod +x init.d/rcS.
11. Add profile and device nodes
#!/bin/sh
export HOSTNAME=farsight
export USER=root
export HOME=root
export PS1="[$USER@$HOSTNAME \W]\# "
PATH=/bin:/sbin:/usr/bin:/usr/sbin
LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH
export PATH LD_LIBRARY_PATH
mknod dev/console c 5 1Keep the total rootfs size under 8 MiB; remove unnecessary libraries (e.g., C++ runtime).
Testing
After building the rootfs, copy it to the NFS export directory ( /source/rootfs) and set appropriate U‑Boot environment variables to boot the board via NFS.
Ramdisk Creation
1. Create an 8 MiB image
dd if=/dev/zero of=ramdisk bs=1k count=81922. Format as ext2
mkfs.ext2 -F ramdisk3. Mount and copy files
mkdir -p /mnt/initrd
mount -t ext2 ramdisk /mnt/initrd
cp -a /source/rootfs/* /mnt/initrd
umount /mnt/initrd4. Compress and package for U‑Boot
gzip --best -c ramdisk > ramdisk.gz
mkimage -n "ramdisk" -A arm -O linux -T ramdisk -C gzip -d ramdisk.gz ramdisk.img
cp ramdisk.img /tftpboot5. Enable RAMDISK support in the kernel
make menuconfig
# Enable "Initial RAM filesystem and RAM disk (initramfs/initrd) support"
# Enable RAM block device support and set size to 8 MiBRecompile the kernel, copy the new image to /tftpboot, and adjust U‑Boot boot arguments to load ramdisk.img together with the kernel and device tree.
Note: U‑Boot commands vary by board; refer to the vendor manual for exact syntax.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
