15AH, San Francisco

California, United States.

Send Your Mail At:

tianyingkejishe@sina.cn

Working Hours

Mon-Sat: 9.30am To 7.00pm

【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}

anyShare分享到:
本站的文章和资源来自互联网或者站长的原创,按照 CC BY -NC -SA 3.0 CN协议发布和共享,转载或引用本站文章应遵循相同协议。如果有侵犯版权的资源请尽快联系站长,我们会在24h内删除有争议的资源。欢迎大家多多交流,期待共同学习进步。
stormwind

发表评论