Buildroot Execution Manual
A comprehensive academic and professional guide for configuring, building, deploying, and validating a Buildroot-based embedded Linux system on the Bootlin QEMU ARM environment.
What this presentation covers
Correct Buildroot configuration
Target architecture, external toolchain, kernel, packages, filesystem images, and root password.
Complete command sequence
Commands are provided step by step from cloning Buildroot to booting from SD.
Debugging and validation
Includes verification commands, login recovery, shadow-file issues, and runtime checks.
Buildroot is a system generator
.config
Kernel
Packages
Images
System
Manual rootfs
Useful for learning and experimentation. You manually copy files, libraries, scripts, and web pages.
Buildroot rootfs
Reproducible and automated. The system is generated from configuration and package selections.
Working paths used in this lab
PROJECT=~/Desktop/embedded-linux-qemu-labs BOOT=$PROJECT/bootloader BUILDROOT=$PROJECT/buildroot/buildroot ROOTFS=$PROJECT/buildroot-rootfs TINY=$PROJECT/tinysystem/nfsroot SD=$BOOT/sd.img
cd command first. Do not run deployment commands from an unknown directory.The deployment layout
Partition 1
FAT
Stores zImage, vexpress-v2p-ca9.dtb, and U-Boot environment.
Partition 2
SquashFS
Read-only root filesystem. Stable, compressed, and appropriate for embedded systems.
Partition 3
ext4
Writable data partition for persistent files if needed.
U-Boot → FAT p1 → zImage + DTB Kernel → SquashFS p2 → root filesystem Runtime data → ext4 p3 when needed
Know the toolchain before configuring Buildroot
arm-linux-gcc --version /home/ahmed/x-tools/arm-training-linux-musleabihf/bin/arm-linux-gcc \ --version
Example result
If the version is 14.3.0, choose External toolchain gcc version = 14.x.
Why this matters
Buildroot validates the external toolchain. A wrong GCC version selection stops the build early.
Verify sysroot, C library, and kernel headers
arm-linux-gcc -print-sysroot ls $(arm-linux-gcc -print-sysroot)/lib find $(arm-linux-gcc -print-sysroot)/usr/include \ -name version.h | grep linux
musl, and the kernel headers series used by the external toolchain is 6.1.x.Create the Buildroot workspace
cd ~/Desktop/embedded-linux-qemu-labs mkdir -p buildroot cd buildroot
Clone Buildroot
git clone https://gitlab.com/buildroot.org/buildroot.git cd buildroot
git status.Select the tested Buildroot release
git checkout 2026.02.1
Why not random master?
A release tag is stable and easier to reproduce during labs and grading.
Kernel note
With this release, the generated Linux kernel in your successful build was 6.19.12.
Open Buildroot configuration
make menuconfig
Configure the ARM Cortex-A9 target
| Menu item | Value |
|---|---|
| Target Architecture | ARM (little endian) |
| Target Architecture Variant | cortex-A9 |
| Enable NEON SIMD extension | enabled |
| Enable VFP extension | enabled |
| Target ABI | EABIhf |
| Floating point strategy | VFPv3-D16 |
Use the external crosstool-NG toolchain
| Menu item | Value |
|---|---|
| Toolchain type | External toolchain |
| Toolchain | Custom toolchain |
| Toolchain path | /home/ahmed/x-tools/arm-training-linux-musleabihf |
| External toolchain gcc version | 14.x |
| Kernel headers series | 6.1.x |
| C library | musl |
| SSP support | enabled |
| C++ support | enabled |
Enable Linux kernel build
| Menu item | Value |
|---|---|
| Linux Kernel | enabled |
| Kernel version | latest / 6.19 with 2026.02.1 |
| Kernel configuration | Using in-tree defconfig |
| Defconfig name | vexpress |
| Build a Device Tree Blob | enabled |
| In-tree DTS file names | arm/vexpress-v2p-ca9 |
arm/vexpress-v2p-ca9 is required with newer kernel trees because the DTS file is under arch/arm/boot/dts/arm/.Select required target packages
Target packages --->
BusyBox
System tools --->
[*] htop
Audio and video applications --->
alsa-utils
[*] alsamixer
[*] speaker-test
mpd
[*] alsa
[*] vorbis
[*] tcp sockets
mpd-mpc
htop is useful for comparison and system inspection. For the assignment, students should still implement their own Mini-HTOP logic from /proc.Enable BusyBox httpd
make busybox-menuconfig
Networking Utilities ---> [*] httpd
httpd applet enabled.Set a root password cleanly
make menuconfig
System configuration ---> [*] Enable root login with password Root password
root.Enable tar root filesystem image
Filesystem images ---> [*] tar the root filesystem
The generated rootfs.tar will later be extracted, customized, converted to SquashFS, and written to SD partition 2.
Build the complete system
make -j$(nproc)
Meaning
-j$(nproc) uses all available CPU cores to speed up compilation.
Your working variant
make ARCH=arm CROSS_COMPILE=arm-linux- -j$(nproc)
make -j$(nproc) is normally enough because target architecture and toolchain are stored in .config.Inspect generated Buildroot directories
cd ~/Desktop/embedded-linux-qemu-labs/buildroot/buildroot/output ls
build host images staging target
images
Final artifacts: kernel, DTB, and root filesystem images.
target
Runtime root filesystem tree before image generation.
host / staging
Build tools and development sysroot used during compilation.
Check kernel, DTB, and rootfs
ls -lh images file images/zImage
rootfs.tar zImage vexpress-v2p-ca9.dtb images/zImage: Linux kernel ARM boot executable zImage (little-endian)
Confirm httpd and htop were built
cd ~/Desktop/embedded-linux-qemu-labs/buildroot/buildroot find output/target -name "htop" find output/target -name "httpd" grep -n "CONFIG_HTTPD=y" output/build/busybox-*/.config
output/target/usr/bin/htop output/target/usr/sbin/httpd 890:CONFIG_HTTPD=y
Extract rootfs.tar safely
cd ~/Desktop/embedded-linux-qemu-labs sudo rm -rf buildroot-rootfs rootfs.sqsh mkdir buildroot-rootfs sudo tar xvf buildroot/buildroot/output/images/rootfs.tar \ -C buildroot-rootfs sudo chown -R $USER:$USER buildroot-rootfs chown -R $USER:$USER buildroot-rootfs
mksquashfs may fail to read files such as /etc/shadow.Verify /etc/shadow before SquashFS
cat buildroot-rootfs/etc/shadow
Good sign
The root line contains a password hash such as root:$5$....
Bad sign
If /etc/shadow is empty or unreadable, login will fail even if menuconfig had a password.
Fix shadow only if required
cd ~/Desktop/embedded-linux-qemu-labs/buildroot-rootfs mkpasswd -m sha-256 root nano etc/shadow
Example root line format: root:$5$xxxxxxxxxxxxxxxxxxxxxxxxxxxx:0:0:99999:7:::
Add lab-specific web and assignment files
cd ~/Desktop/embedded-linux-qemu-labs sudo cp -r tinysystem/nfsroot/www buildroot-rootfs/ sudo cp -r tinysystem/nfsroot/deadlock buildroot-rootfs/ sudo cp tinysystem/nfsroot/usr/bin/mini_htop_v2 \ buildroot-rootfs/usr/bin/
Create a minimal index.html if needed
cd ~/Desktop/embedded-linux-qemu-labs mkdir -p buildroot-rootfs/www/cgi-bin tee buildroot-rootfs/www/index.html > /dev/null <<'EOF' <!doctype html> <html> <head> <title>Buildroot Web Test</title> </head> <body> <h1>Buildroot httpd is working</h1> </body> </html> EOF
Add S99custom to mount filesystems and run httpd
nano buildroot-rootfs/etc/init.d/S99custom
#!/bin/sh mount -t proc none /proc 2>/dev/null mount -t sysfs none /sys 2>/dev/null mount -t devtmpfs devtmpfs /dev 2>/dev/null ifconfig eth0 192.168.0.100 up mkdir -p /www /usr/sbin/httpd -h /www exit 0
chmod +x buildroot-rootfs/etc/init.d/S99custom
Create the final root filesystem image
cd ~/Desktop/embedded-linux-qemu-labs rm -f rootfs.sqsh mksquashfs buildroot-rootfs rootfs.sqsh -noappend
Failed to read file buildroot-rootfs/etc/shadow. If it appears, fix ownership and regenerate SquashFS.Attach the SD image safely
cd ~/Desktop/embedded-linux-qemu-labs/bootloader LOOP=$(sudo losetup -fP --show sd.img) echo $LOOP
/dev/loop6. The loop number changes from machine to machine and from run to run.Write SquashFS to partition 2
sudo dd if=~/Desktop/embedded-linux-qemu-labs/rootfs.sqsh \
of=${LOOP}p2 bs=1M status=progress
sync
${LOOP}p2 exists. If not, detach the loop device and attach again with -fP.Copy kernel and DTB to FAT partition 1
sudo mkdir -p /mnt/boot
sudo mount ${LOOP}p1 /mnt/boot
sudo cp ~/Desktop/embedded-linux-qemu-labs/buildroot/buildroot/output/images/zImage \
/mnt/boot/
sudo cp ~/Desktop/embedded-linux-qemu-labs/buildroot/buildroot/output/images/vexpress-v2p-ca9.dtb \
/mnt/boot/
sync
sudo umount /mnt/boot
sudo losetup -d $LOOP
Run QEMU with audio disabled
cd ~/Desktop/embedded-linux-qemu-labs/bootloader ./run6-qemu.sh
sudo qemu-system-arm \ -M vexpress-a9 \ -m 128M \ -nographic \ -kernel u-boot/u-boot \ -sd sd.img \ -net tap,script=./qemu-myifup \ -net nic \ -audio none
-audio none option removes repeated ALSA host audio warnings and makes the console cleaner.Set the normal SD boot command
setenv bootcmd 'fatload mmc 0:1 0x61000000 zImage; fatload mmc 0:1 0x62000000 vexpress-v2p-ca9.dtb; bootz 0x61000000 - 0x62000000' setenv bootargs 'console=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=squashfs rootwait rw' saveenv reset
init=/bin/sh unless you intentionally want debug mode.Temporary login bypass
setenv bootargs 'console=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=squashfs rootwait rw init=/bin/sh' boot
mount -t proc none /proc mount -t sysfs none /sys mount -t devtmpfs devtmpfs /dev ifconfig eth0 192.168.0.100 up
Test the generated system inside QEMU
login: root password: root which htop which httpd htop ps | grep httpd /usr/sbin/httpd -h /www
htop opens and httpd is running, the selected Buildroot packages are present and executable.Verify the web server from Ubuntu
curl http://192.168.0.100/index.html
You may also open the same address in the host browser:
http://192.168.0.100/index.html
eth0 is up inside the target.Login still fails after setting password
/etc/shadow was not copied correctly into SquashFS because of file ownership or permissions.cat buildroot-rootfs/etc/shadow mksquashfs buildroot-rootfs rootfs.sqsh -noappend
| Symptom | Fix |
|---|---|
Failed to read file .../etc/shadow | Run sudo chown -R $USER:$USER buildroot-rootfs then rebuild SquashFS. |
| root/root fails | Verify root hash exists in buildroot-rootfs/etc/shadow. |
Kernel panic: cannot mount root filesystem
VFS: Cannot open root device Please append a correct root= boot option
Cause
Missing or wrong root= in U-Boot bootargs.
Fix
setenv bootargs 'console=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=squashfs rootwait rw' saveenv reset
DTB build error in newer kernels
No rule to make target 'arch/arm/boot/dts/vexpress-v2p-ca9.dtb'
arm/vexpress-v2p-ca9
The older lab name was vexpress-v2p-ca9, but newer kernel trees store the file under the arm/ subdirectory.
External toolchain mismatch
| Error | Meaning | Action |
|---|---|---|
| Expected GCC 12.x, got 14.3.0 | Wrong GCC version selected. | Choose 14.x. |
| Expected headers 6.12.x, got 6.1.x | Wrong kernel headers series. | Choose 6.1.x. |
| C library mismatch | Wrong libc selected. | Select musl. |
arm-linux-gcc --version arm-linux-gcc -print-sysroot
Loop device mistakes
/dev/loop6p2 unless echo $LOOP actually printed /dev/loop6.losetup -a | grep sd.img sudo losetup -d /dev/loopX
LOOP=$(sudo losetup -fP --show sd.img) echo $LOOP
init=/bin/sh and missing /proc
fopen /proc/stat: No such file or directory fopen /proc/meminfo: No such file or directory
init=/bin/sh bypasses normal init scripts.mount -t proc none /proc mount -t sysfs none /sys mount -t devtmpfs devtmpfs /dev
The cleaner long-term method
Manual copying into buildroot-rootfs works for labs. For a reproducible engineering workflow, use a Buildroot root filesystem overlay.
System configuration ---> Root filesystem overlay directories
~/Desktop/embedded-linux-qemu-labs/my-overlay
Full successful command sequence
cd ~/Desktop/embedded-linux-qemu-labs/buildroot/buildroot make busybox-menuconfig make menuconfig make -j$(nproc) cd ~/Desktop/embedded-linux-qemu-labs sudo rm -rf buildroot-rootfs rootfs.sqsh mkdir buildroot-rootfs sudo tar xvf buildroot/buildroot/output/images/rootfs.tar \ -C buildroot-rootfs sudo chown -R $USER:$USER buildroot-rootfs cat buildroot-rootfs/etc/shadow sudo cp -r tinysystem/nfsroot/www buildroot-rootfs/ sudo cp -r tinysystem/nfsroot/deadlock buildroot-rootfs/ sudo cp tinysystem/nfsroot/usr/bin/mini_htop_v2 \ buildroot-rootfs/usr/bin/ mksquashfs buildroot-rootfs rootfs.sqsh -noappend
Deploy to SD and boot
cd ~/Desktop/embedded-linux-qemu-labs/bootloader
LOOP=$(sudo losetup -fP --show sd.img)
echo $LOOP
sudo dd if=~/Desktop/embedded-linux-qemu-labs/rootfs.sqsh \
of=${LOOP}p2 bs=1M status=progress
sync
sudo mkdir -p /mnt/boot
sudo mount ${LOOP}p1 /mnt/boot
sudo cp ~/Desktop/embedded-linux-qemu-labs/buildroot/buildroot/output/images/zImage \
/mnt/boot/
sudo cp ~/Desktop/embedded-linux-qemu-labs/buildroot/buildroot/output/images/vexpress-v2p-ca9.dtb \
/mnt/boot/
sync
sudo umount /mnt/boot
sudo losetup -d $LOOP
./run6-qemu.sh
What success looks like
Boot
The kernel mounts /dev/mmcblk0p2 as SquashFS and reaches login.
Login
root/root works, unless debug mode init=/bin/sh is used.
Applications
htop runs, httpd serves /www, and the browser opens the target web page.
which htop which httpd curl http://192.168.0.100/index.html
Key engineering lessons
Buildroot gives reproducibility
Configuration drives the system. Avoid random manual changes when a reproducible overlay can be used.
Deployment requires discipline
Always verify paths, loop devices, /etc/shadow, kernel image, DTB, and U-Boot bootargs.