15AH, San Francisco

California, United States.

Send Your Mail At:

tianyingkejishe@sina.cn

Working Hours

Mon-Sat: 9.30am To 7.00pm

归档标题

Autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et dolore feugait.

月度归档 6月 16, 2026

【Linux】构建基于Busybox的Initramfs

一、BusyBox

1、下载BusyBox

$ wget http://busybox.net/downloads/busybox-1.22.1.tar.bz2

2、配置

$ tar xf busybox-1.22.1.tar.bz2
$ cd busybox-1.22.1
$ make defconfig
$ make menuconfig

执行 make menuconfig 之后,把下面几个选项选上:

Busybox Settings:
- General Configuration -> Don't use /usr
- General Configuration -> Show verbose applet usage messages
- General Configuration -> Runtime SUID/SGID configuration via /etc/busybox.conf
- Build Options -> Build BusyBox as a static binary (no shared libs)
- Cross compi—>指定编译工具链路径,这个可选项

注解:

defconfig – set .config to largest generic configuration就是最大化选用通用的功能

3、编译及安装

$ make
$ make install

执行 make install 之后,会生成一个 _install 目录,里面就是 编译后Busybox,包含 bin 、 sbin 、 及 linuxrc 软链接。这个目 录的内容可以直接复制到下面制作initramfs的目录。

警告:

这里假设initramfs的根目录是 /tmp/initramfs/ 。

$ cp -r _install/* /tmp/initramfs/

到这里,编译Busybox的工作就算是完成了。

二、InitramFs

1、文件结构

经过上面的步骤之后,现在来看看initramfs根目录( /tmp/initramfs/ )的结 构,应该是这样子的:

├── bin
├── linuxrc -> bin/busybox
└── sbin

下面我们需要创建一个可执行文件 init ,这是一个Shell脚本。

2、init文件

init 起到承上启下的作用。内核加载完成之后,就会执行这个文件,在这个 文件,可以执行相关命令,最后挂载要启动的文件系统,并切换执行目标系统的 /sbin/init 文件,开始引导真实的Linux系统。

为了简单,这里直接贴出源代码,流程也相对比较简单。

#!/bin/sh

echo "Loading, please wait..."

export PATH="/bin:/sbin"

[ -d /dev ] || mkdir -m 0755 /dev
[ -d /root ] || mkdir --mode=0700 /root
[ -d /sys ] || mkdir /sys
[ -d /proc ] || mkdir /proc
[ -d /tmp ] || mkdir /tmp
[ -d /mnt ] || mkdir /mnt

# Mount /proc and /sys:
mount -n proc /proc -t proc
mount -n sysfs /sys -t sysfs

# Note that this only becomes /dev on the real filesystem if udev's scripts
# are used; which they will be, but it's worth pointing out
#mount -t tmpfs -o mode=0755 udev /dev
[ -e /dev/console ] || mknod /dev/console c 5 1
[ -e /dev/null ] || mknod /dev/null c 1 3

echo /sbin/mdev >/proc/sys/kernel/hotplug
mdev -s

# Get real root device by LABEL or UUID
get_root() {
    if [ ! -z "$LABEL" ]; then
        ROOT=`blkid | sed -n "/$LABEL/p" | cut -d: -f 1`
    fi
    if [ ! -z "$UUID" ]; then
        ROOT=`blkid | sed -n "/$UUID/p" | cut -d: -f 1`
    fi
}

for x in $(cat /proc/cmdline); do
    case $x in
    init=*)
        init=${x#init=}
        ;;
    root=*)
        ROOT=${x#root=}
        case $ROOT in
            LABEL=*)
                LABEL=${ROOT#LABEL=}
                ;;
            UUID=*)
                UUID=${ROOT#UUID=}
                ;;
            /dev/nfs)
                [ -z "${BOOT}" ] && BOOT=nfs
                ;;
        esac
        ;;
    rootflags=*)
        ROOTFLAGS="-o ${x#rootflags=}"
        ;;
    rootfstype=*)
        ROOTFSTYPE="${x#rootfstype=}"
        ;;
    rootdelay=*)
        ROOTDELAY="${x#rootdelay=}"
        ;;
    resumedelay=*)
        RESUMEDELAY="${x#resumedelay=}"
        ;;
    loop=*)
        LOOP="${x#loop=}"
        ;;
    loopflags=*)
        LOOPFLAGS="-o ${x#loopflags=}"
        ;;
    loopfstype=*)
        LOOPFSTYPE="${x#loopfstype=}"
        ;;
    cryptopts=*)
        cryptopts="${x#cryptopts=}"
        ;;
    nfsroot=*)
        NFSROOT="${x#nfsroot=}"
        ;;
    netboot=*)
        NETBOOT="${x#netboot=}"
        ;;
    ip=*)
        IPOPTS="${x#ip=}"
        ;;
    boot=*)
        BOOT=${x#boot=}
        ;;
    resume=*)
        RESUME="${x#resume=}"
        ;;
    noresume)
        NORESUME=y
        ;;
    panic=*)
        panic="${x#panic=}"
        ;;
    quiet)
        quiet=y
        ;;
    ro)
        readonly=y
        ;;
    rw)
        readonly=n
        ;;
    debug)
        debug=y
        exec >/tmp/initramfs.debug 2>&1
        set -x
        ;;
    debug=*)
        debug=y
        set -x
        ;;
    break=*)
        break=${x#break=}
        ;;
    break)
        break=premount
        ;;
    0|1|2|3|4|5|6)
        RUNLEVEL=$x
        ;;
    esac
done

for t in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16;
do
    echo "Mounting the ROOT DEVICE (Time $t) ..."
    get_root $ROOT
    mount -o ro $ROOT /mnt
    mountpoint -q /mnt && break
    echo "Sleep 4s ..."
    sleep 4
done

if [ -e /mnt/sbin/init ] ;
then
    umount /proc
    umount /sys
    exec switch_root /mnt /sbin/init $RUNLEVEL
fi

/bin/sh -i

别忘记给 init 加上执行权限:

$ chmod +x init

现在文件结构应该是这样的:

├── bin
├── init
├── linuxrc -> bin/busybox
└── sbin

到这里,initramfs已经构建好了,下面进行打包及压缩。

注解

关于mdev的几点说明:

  1. mdev不支持LVM卷
  2. mdev支持USB设置热插拨,不过需要把HOTPLUG及USB_STORAGE支持及驱动编 译进内容,而不是编译成模块。Bus options (PCI, PCMCIA, EISA, MCA, ISA) -> PCI Hotplug SupportDevice Drivers -> USB support

3、打包压缩

使用下面这个命令就可以完成打包压缩工作:

cd /tmp/initramfs
find * | cpio -o -H newc | gzip -9 > ../initrd.img

现在, /tmp/initrd.img 就是制作好的initramfs。

三、uboot引导initramfs

  • 内核镜像:Image
  • 设备树:system.dtb
  • initrd 镜像:initrd.img(约 16MB)
# 1. 设置加载地址(按需调整,确保不与内核/DTB 冲突)
setenv loadaddr    0x80080000   # kernel
setenv fdtaddr    0x81000000   # dtb
setenv initrd_addr 0x83000000   # initrd

# 2. 加载内核、DTB、initrd
load mmc 0:1 ${loadaddr}    /boot/Image
load mmc 0:1 ${fdtaddr}     /boot/system.dtb
load mmc 0:1 ${initrd_addr} /boot/initrd.img

# 3. 计算 initrd 大小(U-Boot 自动填充)
setexpr initrd_size ${filesize} - 0

# 4. 构造 bootargs(关键!必须含 initrd 参数)
setenv bootargs \
  "console=ttyS0,115200n8 \
   root=/dev/mmcblk0p2 rw \
   init=/init \
   initrd=${initrd_addr},${initrd_size} \
   ${extra_bootargs}"

# 5. 启动(ARM64 使用 booti)
booti ${loadaddr} ${initrd_addr}:${initrd_size} ${fdtaddr}

【flash】bin制作工具

#!/bin/bash

echo $1
echo $(stat -c%s flash-system.bin)

if [ "$1" = "Image" ];then
        rm flash-system.bin
        cp fip-all.bin flash-system.bin
        echo "Image"
        dd if=$1 of=flash-system.bin bs=1M seek=8 conv=notrunc
elif [ "$1" = "s5000c-64c.dtb" ];then
        echo "s5000c-64c.dtb"
        dd if=$1 of=flash-system.bin bs=1M seek=78 conv=notrunc
else
        echo "Input Error"
        exit 1
fi

【飞腾】实现flash超过16M访问

参考《飞腾编程手册》,0x1a100000为qspi基地址

1、uboot指令操作

mw.l 0x1a100010 0x9f003000 //参考 flash 数据手册,RDID=0x9f
md.l 0x1a10001c 1 (2801401c: 000000c8 )

mw 0x1a100010 0xb7001000 //参考 flash 数据手册,Enable 4-byte Mode cmd=0xb7
mw 0x1a10001c 1

mw 0x1a100010 0x35003000 //参考 flash 数据手册,RDSD=0x35
md.l 0x1a10001c 1 (此处打印 2801401c: 00000008 )

mw 0x1a100000 0x00000005

mw 0x1a100004 0x0308000e

md 0x1000000

2、uboot程序修改

writel(0xb7001000,0x1a100010);
writel(0x1,0x1a10001c);
writel(0x5,0x1a100000);
writel(0x0308000e,0x1a100000);

3、设置启动参数

setenv boot_fdt “booti 0x800000 -:- 0x4e00000”

0x800000为Image起始地址

0x4e00000为dtb起始地址