Fundamentals 16 min read

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.

Liangxu Linux
Liangxu Linux
Liangxu Linux
How to Build a Custom Root Filesystem for Embedded Linux with BusyBox

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 /mnt

The 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.bz2

2. Extract source

tar xvf busybox-1.22.1.tar.bz2

3. Enter directory

cd busybox-1.22.1

4. Configure

make menuconfig
# Enable static build, set cross‑compiler prefix to arm-none-linux-gnueabi-
# (other options left as default)

5. Build

make

6. Install

make install   # installs into _install directory

7. Create required directories

mkdir dev etc mnt proc var tmp sys root

8. 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 MiB

9. 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/reboot

Create /etc/fstab:

proc       /proc   proc    defaults 0 0
tmpfs      /tmp    tmpfs   defaults 0 0
sysfs      /sys    sysfs   defaults 0 0

Ensure 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 -s

Make 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 1

Keep 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=8192

2. Format as ext2

mkfs.ext2 -F ramdisk

3. Mount and copy files

mkdir -p /mnt/initrd
mount -t ext2 ramdisk /mnt/initrd
cp -a /source/rootfs/* /mnt/initrd
umount /mnt/initrd

4. 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 /tftpboot

5. 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 MiB

Recompile 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.

LinuxembeddedrootfsbusyboxCrossCompilation
Liangxu Linux
Written by

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.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.