The Embedded New Testament

The "Holy Bible" for embedded engineers


Project maintained by theEmbeddedGeorge Hosted on GitHub Pages — Theme by mattgraham

Embedded Linux

Customized Linux for Embedded Systems
Understanding Buildroot, Yocto, and custom distributions for resource-constrained devices


📋 Table of Contents


🏗️ Embedded Linux Fundamentals

What is Embedded Linux?

Embedded Linux refers to Linux distributions specifically designed for embedded systems—devices with limited resources, specific hardware requirements, and specialized functionality. Unlike desktop Linux, embedded Linux focuses on efficiency, customization, and reliability.

Embedded Linux Characteristics:

Embedded vs. Desktop Linux

Desktop Linux:

Embedded Linux:

┌─────────────────────────────────────┐
│         Embedded Linux Stack        │
├─────────────────────────────────────┤
│         Application Layer           │
│      (Custom applications)          │
├─────────────────────────────────────┤
│         System Services             │
│      (Init system, networking)      │
├─────────────────────────────────────┤
│         Linux Kernel                │
│      (Optimized for target)        │
├─────────────────────────────────────┤
│         Bootloader                  │
│      (U-Boot, GRUB, etc.)          │
├─────────────────────────────────────┤
│         Hardware Layer              │
│      (Target-specific)             │
└─────────────────────────────────────┘

Embedded Linux Philosophy

Embedded Linux follows the purpose-built principle—create Linux distributions that are specifically designed for the target application, hardware, and operational requirements.

Embedded Linux Design Goals:


🔧 Build System Philosophy

Understanding Build Systems

Build systems for embedded Linux automate the process of creating custom distributions. They handle dependency resolution, cross-compilation, and system integration to produce bootable images.

Build System Philosophy

Build systems follow the automation and reproducibility principle—automate the complex process of building embedded Linux systems while ensuring reproducible results across different environments.

Build System Goals:

Build System Components

Core Components:

Build Process Flow:

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   Source Code   │───▶│  Build System   │───▶│  System Image   │
│   & Patches     │    │   Processing     │    │   Generation    │
└─────────────────┘    └─────────────────┘    └─────────────────┘
         │                       │                       │
         ▼                       ▼                       ▼
┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│  Dependencies   │    │ Cross-compile   │    │  Bootable       │
│   Resolution    │    │   Toolchain     │    │   Image         │
└─────────────────┘    └─────────────────┘    └─────────────────┘

🚀 Buildroot Framework

Simple and Efficient Build System

Buildroot is a lightweight build system that creates embedded Linux systems from source code. It’s designed for simplicity and efficiency, making it ideal for smaller projects and rapid prototyping.

Buildroot Philosophy

Buildroot follows the simplicity and efficiency principle—provide a straightforward build system that produces minimal, efficient embedded Linux systems with minimal overhead.

Buildroot Design Goals:

Buildroot Architecture

Core Components:

┌─────────────────────────────────────┐
│         Buildroot Structure         │
├─────────────────────────────────────┤
│         Config.in                   │
│      (Package selection)            │
├─────────────────────────────────────┤
│         Rules.mak                   │
│      (Build rules)                  │
├─────────────────────────────────────┤
│         Package/                    │
│      (Package definitions)          │
├─────────────────────────────────────┤
│         Board/                      │
│      (Board configurations)         │
├─────────────────────────────────────┤
│         Configs/                    │
│      (Default configurations)       │
└─────────────────────────────────────┘

Buildroot Configuration:

# Basic Buildroot setup
git clone https://github.com/buildroot/buildroot.git
cd buildroot

# Configure for target
make defconfig
make menuconfig

# Build system
make

# Clean build
make clean
make distclean

Buildroot Package Management

Package Definition Example:

# Package definition for custom application
################################################################################
#
# myapp
#
################################################################################

MYAPP_VERSION = 1.0.0
MYAPP_SITE = $(TOPDIR)/package/myapp/src
MYAPP_SITE_METHOD = local
MYAPP_LICENSE = GPL-2.0
MYAPP_LICENSE_FILES = LICENSE

# Build dependencies
MYAPP_DEPENDENCIES = host-pkgconf

# Build commands
define MYAPP_BUILD_CMDS
    $(MAKE) CC=$(TARGET_CC) LD=$(TARGET_LD) -C $(@D)
endef

# Install commands
define MYAPP_INSTALL_TARGET_CMDS
    $(INSTALL) -D -m 0755 $(@D)/myapp $(TARGET_DIR)/usr/bin/myapp
    $(INSTALL) -D -m 0644 $(@D)/myapp.conf $(TARGET_DIR)/etc/myapp.conf
endef

$(eval $(generic-package))

Custom Package Integration:

# Create package directory
mkdir -p package/myapp
cp myapp.mk package/myapp/

# Add to package selection
echo "source package/myapp/Config.in" >> package/Config.in

# Create Config.in
cat > package/myapp/Config.in << EOF
config BR2_PACKAGE_MYAPP
    bool "myapp"
    help
      Custom application for embedded system.
      
      http://example.com/myapp
EOF

🏭 Yocto Project

Industrial-Grade Build System

The Yocto Project is a comprehensive build system designed for industrial embedded Linux development. It provides advanced features, extensive package support, and enterprise-grade reliability.

Yocto Project Philosophy

Yocto follows the industrial strength principle—provide a robust, scalable build system that meets the requirements of enterprise embedded Linux development with comprehensive tooling and support.

Yocto Design Goals:

Yocto Architecture

Core Components:

┌─────────────────────────────────────┐
│         Yocto Architecture          │
├─────────────────────────────────────┤
│         BitBake                     │
│      (Build engine)                 │
├─────────────────────────────────────┤
│         OpenEmbedded Core           │
│      (Build system)                 │
├─────────────────────────────────────┤
│         Meta Layers                 │
│      (Configuration & packages)     │
├─────────────────────────────────────┤
│         Build Output                │
│      (Images, packages, SDK)        │
└─────────────────────────────────────┘

Yocto Setup:

# Clone Yocto Project
git clone -b kirkstone git://git.yoctoproject.org/poky.git
cd poky

# Source environment
source oe-init-build-env

# Configure for target
bitbake-layers add-layer meta-raspberrypi
bitbake-layers add-layer meta-openembedded/meta-oe

# Build core image
bitbake core-image-minimal

# Build custom image
bitbake my-custom-image

Yocto Recipe Development

Basic Recipe Example:

# Recipe for custom application
DESCRIPTION = "Custom embedded application"
HOMEPAGE = "http://example.com"
LICENSE = "GPL-2.0-only"
LIC_FILES_CHKSUM = "file://LICENSE;md5=1234567890abcdef"

SRC_URI = "file://myapp-${PV}.tar.gz"
SRC_URI[sha256sum] = "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"

S = "${WORKDIR}/myapp-${PV}"

inherit autotools pkgconfig

# Build dependencies
DEPENDS += "pkgconfig-native"

# Runtime dependencies
RDEPENDS:${PN} += "libc"

# Install additional files
do_install:append() {
    install -d ${D}${sysconfdir}/myapp
    install -m 0644 ${S}/config/myapp.conf ${D}${sysconfdir}/myapp/
    
    install -d ${D}${systemd_system_unitdir}
    install -m 0644 ${S}/systemd/myapp.service ${D}${systemd_system_unitdir}/
}

# Enable systemd integration
inherit systemd
SYSTEMD_AUTO_ENABLE = "enable"
SYSTEMD_SERVICE:${PN} = "myapp.service"

Custom Image Recipe:

# Custom image recipe
DESCRIPTION = "Custom embedded Linux image"
LICENSE = "MIT"

inherit core-image

# Include additional packages
IMAGE_INSTALL += " \
    myapp \
    openssh \
    iperf3 \
    htop \
"

# Include development tools (debug builds)
IMAGE_INSTALL:append = " \
    packagegroup-core-buildessential \
    gdb \
    strace \
"

# Configure image features
IMAGE_FEATURES += " \
    ssh-server-openssh \
    tools-debug \
    tools-profile \
"

# Set root password
ROOTFS_POSTPROCESS_COMMAND += "set_root_passwd;"
set_root_passwd() {
    sed -i 's/^root:[^:]*:/root:\$6\$rounds=5000\$salt\$hash:/' ${IMAGE_ROOTFS}/etc/shadow
}

🛠️ Custom Distribution Development

Building Tailored Linux Systems

Custom distribution development involves creating Linux systems specifically designed for target applications. This requires understanding system requirements, component selection, and integration.

Custom Distribution Philosophy

Custom distributions follow the application-specific principle—design Linux systems that perfectly match the target application’s requirements, constraints, and operational environment.

Custom Distribution Goals:

System Component Selection

Essential Components:

# Minimal system components
- Linux kernel (optimized for target)
- Init system (systemd, busybox, or custom)
- Core libraries (glibc, uclibc, or musl)
- Basic utilities (coreutils, busybox)
- Device management (udev, mdev)
- Network stack (if required)
- Application-specific packages

Component Selection Criteria:

# Size considerations
- Memory footprint
- Storage requirements
- Boot time impact

# Functionality requirements
- Application dependencies
- Hardware support needs
- Network requirements

# Maintenance considerations
- Update mechanisms
- Security updates
- Long-term support

Custom Init System

Systemd Configuration:

# /etc/systemd/system/myapp.service
[Unit]
Description=Custom Application
After=network.target
Wants=network.target

[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/myapp
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

Busybox Init Configuration:

# /etc/inittab
::sysinit:/etc/init.d/rcS
::respawn:/sbin/getty -L ttyS0 115200 vt100
::respawn:/opt/myapp/myapp
::shutdown:/etc/init.d/rcK

System Optimization

Optimizing for Embedded Use

System optimization involves reducing resource usage, improving performance, and ensuring reliable operation within the constraints of embedded hardware.

Optimization Philosophy

System optimization follows the efficiency and reliability principle—maximize system performance and reliability while minimizing resource usage and power consumption.

Optimization Goals:

Kernel Optimization

Kernel Configuration:

# Essential kernel options
CONFIG_EMBEDDED=y
CONFIG_EXPERT=y
CONFIG_SLOB=y                    # Simple memory allocator
CONFIG_BLK_DEV_INITRD=y         # Initial RAM disk
CONFIG_DEVTMPFS=y               # Device filesystem
CONFIG_DEVTMPFS_MOUNT=y         # Auto-mount devtmpfs

# Disable unnecessary features
# CONFIG_DEBUG_FS is not set
# CONFIG_DEBUG_KERNEL is not set
# CONFIG_DEBUG_INFO is not set
# CONFIG_DEBUG_MEMORY_INIT is not set

# Enable only required drivers
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_MMC=y
CONFIG_MMC_BLOCK=y

Kernel Size Reduction:

# Remove unused drivers
# CONFIG_SOUND is not set
# CONFIG_VIDEO_DEV is not set
# CONFIG_INPUT is not set

# Optimize for size
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_KERNEL_GZIP=y
CONFIG_MODULES=n

Root Filesystem Optimization

Filesystem Selection:

# Lightweight filesystems
- squashfs: Read-only, compressed
- ext4: Journaling, good performance
- f2fs: Flash-optimized
- jffs2: Flash filesystem
- ubifs: Advanced flash filesystem

Library Optimization:

# Use lightweight alternatives
- musl libc instead of glibc
- busybox instead of coreutils
- dropbear instead of openssh
- mdev instead of udev

Package Optimization:

# Remove unnecessary packages
- Development tools
- Documentation
- Locale data (keep only required)
- Debug symbols
- Unused libraries

🚀 Deployment and Maintenance

Deploying and Maintaining Embedded Systems

Deployment and maintenance involve creating reliable update mechanisms, monitoring system health, and ensuring long-term operation in the field.

Deployment Philosophy

Deployment follows the reliability and maintainability principle—ensure systems can be deployed reliably and maintained effectively throughout their operational lifetime.

Deployment Goals:

Update Mechanisms

OTA (Over-The-Air) Updates:

# Update script example
#!/bin/sh

# Download update
wget -O /tmp/update.tar.gz http://update.server/update.tar.gz

# Verify checksum
echo "expected_checksum /tmp/update.tar.gz" | sha256sum -c

# Extract update
tar -xzf /tmp/update.tar.gz -C /tmp/update

# Backup current system
cp -r /opt/myapp /opt/myapp.backup

# Install update
cp -r /tmp/update/* /opt/myapp/

# Restart application
systemctl restart myapp

# Cleanup
rm -rf /tmp/update*

Dual Partition Updates:

# Dual partition update script
#!/bin/sh

# Determine current partition
CURRENT_PART=$(cat /proc/cmdline | grep -o "root=/dev/mmcblk0p[12]")

if echo $CURRENT_PART | grep -q "p1"; then
    UPDATE_PART="/dev/mmcblk0p2"
    NEXT_PART="p2"
else
    UPDATE_PART="/dev/mmcblk0p1"
    NEXT_PART="p1"
fi

# Format update partition
mkfs.ext4 $UPDATE_PART

# Mount and copy files
mount $UPDATE_PART /mnt/update
cp -r /opt/myapp/* /mnt/update/

# Update bootloader to boot from new partition
fw_setenv bootpart $NEXT_PART

# Reboot to new partition
reboot

System Monitoring

Health Monitoring:

#!/bin/sh

# System health check script
while true; do
    # Check memory usage
    MEM_USAGE=$(free | grep Mem | awk '{print $3/$2 * 100.0}')
    if [ $(echo "$MEM_USAGE > 90" | bc) -eq 1 ]; then
        logger "WARNING: High memory usage: ${MEM_USAGE}%"
    fi
    
    # Check disk usage
    DISK_USAGE=$(df / | tail -1 | awk '{print $5}' | sed 's/%//')
    if [ $DISK_USAGE -gt 90 ]; then
        logger "WARNING: High disk usage: ${DISK_USAGE}%"
    fi
    
    # Check application status
    if ! pgrep myapp > /dev/null; then
        logger "ERROR: Application not running, restarting"
        systemctl restart myapp
    fi
    
    sleep 60
done

Log Management:

# Log rotation configuration
cat > /etc/logrotate.d/myapp << EOF
/var/log/myapp/*.log {
    daily
    missingok
    rotate 7
    compress
    notifempty
    create 644 myapp myapp
    postrotate
        systemctl reload myapp
    endscript
}
EOF

🎯 Conclusion

Embedded Linux provides powerful capabilities for creating customized, efficient Linux systems for embedded applications. Understanding Buildroot, Yocto, and custom distribution development is essential for building reliable embedded systems.

Key Takeaways:

The Path Forward:

As embedded systems become more complex and connected, the importance of embedded Linux skills will only increase. Modern systems continue to evolve, providing new optimization techniques and deployment strategies.

Remember: Embedded Linux is not just about running Linux on embedded devices—it’s about creating purpose-built systems that perfectly match your application requirements while efficiently using available resources. The skills you develop here will enable you to create robust, efficient, and maintainable embedded Linux systems.