Rockchip RK3399 - busybox 1.36.0制作根文件系统
在Mini2440之linux根文件系统yaffs2移植文章中我们已经介绍了根文件系统的概念以及制作过程,不过当时是制作的是yaffs2类型的根文件系统,适用于外部设备Nand Flash,这一节我们将制作ramdisk、ext4类型的根文件系统。制作流程基本是一致的。
一、 编译、安装、配置 busybox
1.1 下载源码
根文件系统是根据busybox来制作的。下载地址:https://busybox.net/downloads/。
这里我们就以1.36.0版本为例进行编译安装介绍:
注意:一般你使用什么版本的交叉编译器来编译linux内核时,文件系统中的所有程序也要使用同样的交叉编译器来编译。
下载完成后解压:
root@zhengyang:/work/sambashare/rk3399# mkdir rootfs root@zhengyang:/work/sambashare/rk3399# cd rootfs root@zhengyang:/work/sambashare/rk3399/rootfs# wget https://busybox.net/downloads/busybox-1.36.0.tar.bz2 tar root@zhengyang:/work/sambashare/rk3399/rootfs# tar -jxf busybox-1.36.0.tar.bz2
1.2 配置busybox
在路径busybox-1.36.0下运行如下命令,使用默认配置:
root@zhengyang:/work/sambashare/rk3399/rootfs# cd busybox-1.36.0/ root@zhengyang:/work/sambashare/rk3399/rootfs/busybox-1.36.0# make defconfig
然后进入图像化配置页面,修改配置 :
root@zhengyang:/work/sambashare/rk3399/rootfs/busybox-1.36.0# make menuconfig
进入Busybox Settings,配置如下参数:
Settings ---> (/usr/local/arm/12.2.1/bin/arm-linux-) Cross compile prefix ( -march=armv8-a) additional CFLAGS [ ] Build static binary (no shared libs) [*] Build Shared libbusybox
编译方式有两种:
- 第一种是以静态方式编译,即生成的busybox不需要动态库的支持就能运行。这样做我们就不需要部署动态库了,缺点就是自己写的程序在这个根文件系统中是不能运行的,因为缺少动态库库的支持。
- 第二种方式使用动态编译,这样的话我们就需要部署动态库了,在linux动态库文件是以so为后缀,而windows下文件是以dll为后缀。
这里我们指定了arm-linux-gcc 12.2.1编译器的路径,这里就不具体介绍编译器如何安装了。
继续配置:
Linux System Utilities ---> [] nsenter Coreutils ---> [] sync Miscellaneous Utilities ---> 自己选择 Networking Utilities ---> 自己选择 Linux System Utilities ---> [*] hexdump
1.3 编译安装
运行命令:
root@zhengyang:/work/sambashare/rk3399/rootfs/busybox-1.36.0# make
然后查看当前路径下是否存在busybox:
root@zhengyang:/work/sambashare/rk3399/rootfs/busybox-1.36.0# ll busybox -rwxr-xr-x 1 root root 1119768 May 19 19:28 busybox*
执行make install:
root@zhengyang:/work/sambashare/rk3399/rootfs/busybox-1.36.0# make install
make install的目的就是将编译生成的可执行程序及其依赖的库文件、配置文件、头文件安装到当前系统中指定(一般都可以自己指定安装到哪个目录下,如果不指定一般都有个默认目录)的目录下,默认被安装到_install 目录下:
root@zhengyang:/work/sambashare/rk3399/rootfs/busybox-1.36.0# ll _install/ 总用量 92 drwxr-xr-x 6 root root 4096 May 19 19:29 ./ drwxr-xr-x 38 root root 4096 May 19 19:29 ../ drwxr-xr-x 2 root root 4096 May 19 19:29 bin/ drwxr-xr-x 2 root root 4096 May 19 19:29 lib64/ -rwxr-xr-x 1 root root 67392 May 19 19:28 linuxrc* drwxr-xr-x 2 root root 4096 May 19 19:29 sbin/ drwxr-xr-x 4 root root 4096 May 19 19:29 usr/
里面有5个文件:bin、sbin、usr这三个目录里都是二进制命令工具,lib64里面是库文件,这还不足以构成 一个可用的根文件系统,必须进行其它完善工作,才能构建一个可用的根文件系统。
二、 构建根文件系统
新建一个目录用来存放制作的根文件系统,可以命名为busybox_install。将利用BusyBox生成的二进制文件及目录,即_install目录下的所有文件及目录复制到busybox_install目录下。
root@zhengyang:/work/sambashare/rk3399/rootfs/busybox-1.36.0# mkdir ../busybox_install root@zhengyang:/work/sambashare/rk3399/rootfs/busybox-1.36.0# cp -a _install/* ../busybox_install/
2.1 添加库文件
切换到busybox_install路径下:
root@zhengyang:/work/sambashare/rk3399/rootfs/busybox-1.36.0# cd ../busybox_install
找到交叉编译工具里的动态库复制到lib目录下:
root@zhengyang:/work/sambashare/rk3399/rootfs/busybox_install# mkdir lib root@zhengyang:/work/sambashare/rk3399/rootfs/busybox_install# cp -a /usr/local/arm/12.2.1/aarch64-none-linux-gnu/libc/lib/*so* ./lib/ root@zhengyang:/work/sambashare/rk3399/rootfs/busybox_install# cp -a /usr/local/arm/12.2.1/aarch64-none-linux-gnu/libc/lib64/*so* ./lib64/ root@zhengyang:/work/sambashare/rk3399/rootfs/busybox_install# cp -a /usr/local/arm/12.2.1/aarch64-none-linux-gnu/libc/usr/lib/*so* ./lib/ root@zhengyang:/work/sambashare/rk3399/rootfs/busybox_install# cp -a /usr/local/arm/12.2.1/aarch64-none-linux-gnu/libc/usr/lib64/*so* ./lib64/
-a保留权限,复制软链接本身,递归复制。
查看库文件:
root@zhengyang:/work/sambashare/rk3399/rootfs/busybox_install# ls ./lib ld-linux-aarch64.so.1 libinproctrace.so root@zhengyang:/work/sambashare/rk3399/rootfs/busybox_install# ls ./lib64/ libanl.so libcrypt.so.1 libhwasan.so.0.0.0 libnss_db.so.2 libstdc++.so.6.0.30-gdb.py libanl.so.1 libc.so libitm.so libnss_dns.so.2 libthread_db.so libasan.so libc.so.6 libitm.so.1 libnss_files.so.2 libthread_db.so.1 libasan.so.8 libdl.so.2 libitm.so.1.0.0 libnss_hesiod.so libtsan.so libasan.so.8.0.0 libgcc_s.so liblsan.so libnss_hesiod.so.2 libtsan.so.2 libatomic.so libgcc_s.so.1 liblsan.so.0 libpcprofile.so libtsan.so.2.0.0 libatomic.so.1 libgfortran.so liblsan.so.0.0.0 libpthread.so.0 libubsan.so libatomic.so.1.2.0 libgfortran.so.5 libmemusage.so libresolv.a libubsan.so.1 libBrokenLocale.so libgfortran.so.5.0.0 libm.so libresolv.so libubsan.so.1.0.0 libBrokenLocale.so.1 libgomp.so libm.so.6 libresolv.so.2 libutil.so.1 libbusybox.so.1.36.0 libgomp.so.1 libnsl.so.1 librt.so.1 libc_malloc_debug.so libgomp.so.1.0.0 libnss_compat.so libstdc++.so libc_malloc_debug.so.0 libhwasan.so libnss_compat.so.2 libstdc++.so.6 libcrypt.so libhwasan.so.0 libnss_db.so libstdc++.so.6.0.30
这里只是拷贝动态链接库。一般开发程序使用动态编译需要板子上动态库的支持才能运行,所以拷贝动态库。
2.2 构建etc目录
初始化配置脚本放在在/etc目录下,用于系统启动所需的初始化配置脚本。BusyBox提供了一些初始化范例脚本,在examples/bootfloppy/etc/目录下:
root@zhengyang:/work/sambashare/rk3399/rootfs# cd busybox-1.36.0/ root@zhengyang:/work/sambashare/rk3399/rootfs/busybox-1.36.0# ll examples/bootfloppy/etc/ 总用量 24 drwxr-xr-x 3 root root 4096 Jan 3 22:17 ./ drwxr-xr-x 3 root root 4096 Jan 3 22:17 ../ -rw-r--r-- 1 root root 33 Jan 3 22:17 fstab drwxr-xr-x 2 root root 4096 Jan 3 22:17 init.d/ -rw-r--r-- 1 root root 100 Jan 3 22:17 inittab -rw-r--r-- 1 root root 133 Jan 3 22:17 profile
在rootfs目录,创建etc文件夹:
root@zhengyang:/work/sambashare/rk3399/rootfs/busybox_install# mkdir etc
将这些配置文件复制到新制作的根文件系统etc目录下。
root@zhengyang:/work/sambashare/rk3399/rootfs/busybox_install# cp -a ../busybox-1.36.0/examples/bootfloppy/etc/* ./etc root@zhengyang:/work/sambashare/rk3399/rootfs# ll etc 总用量 24 drwxr-xr-x 3 root root 4096 May 19 20:24 ./ drwxr-xr-x 8 root root 4096 May 19 20:23 ../ -rw-r--r-- 1 root root 33 Jan 3 22:17 fstab drwxr-xr-x 2 root root 4096 Jan 3 22:17 init.d/ -rw-r--r-- 1 root root 100 Jan 3 22:17 inittab -rw-r--r-- 1 root root 133 Jan 3 22:17 profile
2.2.1 修改/etc/inittab文件
/etc/inittab文件是init进程解析的配置文件,通过这个配置文件决定执行哪个进程,何时执行。将文件修改为:
# 系统启动时 ::sysinit:/etc/init.d/rcS # 系统启动按下Enter键时 ::askfirst:-/bin/sh # 按下Ctrl+Alt+Del键时 ::ctrlaltdel:/sbin/reboot # 系统关机时 ::shutdown:/sbin/swapoff -a ::shutdown:/bin/umount -a -r # 系统重启时 ::restart:/sbin/init
以上内容定义了系统启动时,关机时,重启时,按下Ctrl+Alt+Del键时执行的进程。
2.2.2 修改/etc/init.d/rcS文件
#!/bin/sh # 挂载 /etc/fstab 中定义的所有文件系统 /bin/mount -a # 挂载虚拟的devpts文件系统用于用于伪终端设备 /bin/mkdir -p /dev/pts /bin/mount -t devpts devpts /dev/pts # 使用mdev动态管理u盘和鼠标等热插拔设备 /bin/echo /sbin/mdev > /proc/sys/kernel/hotplug # 扫描并创建节点 /sbin/mdev -s
修改init.d文件权限:
root@zhengyang:/work/sambashare/rk3399/rootfs/busybox_install# chmod -R 777 etc/init.d/*
2.2.3 修改/etc/fstab
/etc/fstab文件存放的是文件系统信息。在系统启动后执行/etc/init.d/rcS文件里/bin/mount -a命令时,自动挂载这些文件系统。
# <file system> <mount point> <type> <options> <dump> <pass> proc /proc proc defaults 0 0 sysfs /sys sysfs defaults 0 0 tmpfs /tmp tmpfs defaults 0 0 tmpfs /dev tmpfs defaults 0 0
这里我们挂载的文件系统有三个proc、sysfs和tmpfs,在内核中proc和sysfs默认都支持,而tmpfs是没有支持的,我们需要添加tmpfs的支持。
2.2.4 修改/etc/profile文件
/etc/profile文件作用是设置环境变量,每个用户登录时都会运行它,将文件内容修改为:
# 主机名 export HOSTNAME=zy # 用户名 export USER=root # 用户目录 export HOME=/root # 终端默认提示符 export PS1="[$USER@$HOSTNAME:\$PWD]\# " # 环境变量 export PATH=/bin:/sbin:/usr/bin:/usr/sbin # 动态库路径 export LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH
2.3 构建dev目录
在rootfs目录,创建dev文件夹:
root@zhengyang:/work/sambashare/rk3399/rootfs/busybox_install# mkdir dev
创建终端文件:
root@zhengyang:/work/sambashare/rk3399/rootfs/busybox_install# sudo mknod dev/console c 5 1 root@zhengyang:/work/sambashare/rk3399/rootfs/busybox_install# sudo mknod dev/null c 1 3
2.4 构建其他文件
root@zhengyang:/work/sambashare/rk3399/rootfs/busybox_install# mkdir mnt proc tmp sys root root@zhengyang:/work/sambashare/rk3399/rootfs/busybox_install# ll 总用量 124 drwxr-xr-x 14 root root 4096 May 19 20:33 ./ drwxr-xr-x 12 root root 4096 May 19 20:15 ../ drwxr-xr-x 2 root root 4096 May 19 19:29 bin/ drwxr-xr-x 2 root root 4096 May 19 20:33 dev/ drwxr-xr-x 3 root root 4096 May 19 20:32 etc/ drwxr-xr-x 2 root root 4096 May 19 20:20 lib/ drwxr-xr-x 2 root root 4096 May 19 20:21 lib64/ -rwxr-xr-x 1 root root 67392 May 19 19:28 linuxrc* drwxr-xr-x 2 root root 4096 May 19 20:33 mnt/ drwxr-xr-x 2 root root 4096 May 19 20:33 proc/ drwxr-xr-x 2 root root 4096 May 19 20:33 root/ drwxr-xr-x 2 root root 4096 May 19 19:29 sbin/ drwxr-xr-x 2 root root 4096 May 19 20:33 sys/ drwxr-xr-x 2 root root 4096 May 19 20:33 tmp/ drwxr-xr-x 4 root root 4096 May 19 19:29 usr/
三、制作ext4根文件系统镜像
建立根文件系统挂载点busybox_rootfs:
root@zhengyang:/work/sambashare/rk3399/rootfs# mkdir busybox_rootfs
创建空镜像文件busybox_ext4_rootfs.img,大小300m,具体需要的大小可以通过du build -h查看我们根文件系统大小调整;
root@zhengyang:/work/sambashare/rk3399/rootfs# dd if=/dev/zero of=busybox_ext4_rootfs.img bs=1M count=300 记录了300+0 的读入 记录了300+0 的写出 314572800字节(315 MB,300 MiB)已复制,0.166846 s,1.9 GB/s root@zhengyang:/work/sambashare/rk3399/rootfs# ll busybox_ext4_rootfs.img -rw-r--r-- 1 root root 314572800 May 25 21:39 busybox_ext4_rootfs.img root@zhengyang:/work/sambashare/rk3399/rootfs# mkfs.ext4 busybox_ext4_rootfs.img
将该镜像文件挂载到busybox_rootfs:
root@zhengyang:/work/sambashare/rk3399/rootfs# mount busybox_ext4_rootfs.img busybox_rootfs
然后将busybox_install的文件复制到该空文件夹中:
root@zhengyang:/work/sambashare/rk3399/rootfs# cp ./busybox_install/* ./busybox_rootfs/ -af
使用df命令可以查看是否已经挂载:
root@zhengyang:/work/sambashare/rk3399# df busybox_rootfs/ 文件系统 1K-块 已用 可用 已用% 挂载点 /dev/loop12 280880 99872 159504 39% /work/sambashare/rk3399/rootfs/busybox_rootfs
将之前挂载的卸载掉:
root@zhengyang:/work/sambashare/rk3399/rootfs# umount busybox_rootfs root@zhengyang:/work/sambashare/rk3399/rootfs# ll busybox_rootfs/ 总用量 8 drwxr-xr-x 2 root root 4096 May 25 21:47 ./ drwxr-xr-x 14 root root 4096 May 25 21:47 ../
此时我们已经得到了ext4根文件系统镜像busybox_ext4_rootfs.img:
root@zhengyang:/work/sambashare/rk3399/rootfs# ll busybox_ext4_rootfs.img -rw-r--r-- 1 root root 314572800 May 25 21:54 busybox_ext4_rootfs.img
删除文件夹busybox_rootfs:
root@zhengyang:/work/sambashare/rk3399/rootfs# rm -rf busybox_rootfs
用e2fsck修复及检测镜像文件系统,resize2fs减小镜像文件的大小;
root@zhengyang:/work/sambashare/rk3399/rootfs# e2fsck -p -f busybox_ext4_rootfs.img busybox_ext4_rootfs.img:503/76800 文件(0.4% 为非连续的),31515/76800 块 root@zhengyang:/work/sambashare/rk3399/rootfs# resize2fs -M busybox_ext4_rootfs.img resize2fs 1.45.5 (07-Jan-2020) 将 busybox_ext4_rootfs.img 上的文件系统调整为 31605 个块(每块 4k)。 busybox_ext4_rootfs.img 上的文件系统大小已经调整为 31605 个块(每块 4k)。 root@zhengyang:/work/sambashare/rk3399/rootfs# ll busybox_ext4_rootfs.img -rw-r--r-- 1 root root 129454080 May 30 22:33 busybox_ext4_rootfs.img root@zhengyang:/work/sambashare/rk3399/rootfs# du -sh busybox_ext4_rootfs.img 114M busybox_ext4_rootfs.img root@zhengyang:/work/sambashare/r
最终得到的ext4根文件系统镜像busybox_ext4_rootfs.img大小为114MB。
四、制作ramdist根文件系统镜像
前面我们已经制作了ext4文件文件系统,至于ramdisk,就是用内存模拟了一个块设备(比如内核设备节点/dev/ram0),这个模拟的“块设备”是需要一个文件系统(比如ext4或者其它文件系统)来组织数据的。
这里为了减少文件系统的大小,我们对busybox_ext4_rootfs.img文件系统进行镜像压缩,压缩后为 ramdisk.gz。
root@zhengyang:/work/sambashare/rk3399/rootfs# gzip -v9 busybox_ext4_rootfs.img busybox_ext4_rootfs.img: 91.2% -- replaced with busybox_ext4_rootfs.img.gz root@zhengyang:/work/sambashare/rk3399/rootfs# mv busybox_ext4_rootfs.img.gz ramdisk.gz
如果要使用ramdisk根文件系统,除了在make menuconfig阶段配置的RAM块设备驱动的支持,还需要:
- 在uboot启动阶段将ramdisk.gz加载到内存某个位置;这个比较简单,无论是通过tftp下载,还是从eMMC等外部存储设备加载到内存都可以;
- 在uboot启动命令行中指定根文件系统的位置;修改uboot启动参数bootargs中的root属性为root=/dev/ram0,表示根目录挂载点为/dev/ram0块设备;
- 告诉内核ramdisk.gz在内存的位置;这个有两种方式,下面具体介绍;
4.1 配置内核启动参数bootargs
假设ramdisk.gz文件被加载到内存指定位置0x42000000。修改bootargs加入如下配置:
initrd=0x42000000,0x14000000
initrd参数格式为:地址,长度,这里设备ram地址为0x42000000起始,只要是在内核DDR物理地址空间内。长度这里只要比ramdisk.gz压缩包大小大就可以了;
4.2 bootm指定ramdisk加载地址
bootm命令支持多个参数:
bootm <Legacy uImage addr> <ramdisk addr> <dtb addr>
其中第二个参数就是ramdisk.gz文件加载到内存中的地址,和加载uIamge时一样,bootm加载ramdisk时,也需要判断ramdisk.gz的64字节数据头。所以用这种方法向内核传递ramdisk时,ramdisk.gz需要通过mkimage命令给ramdisk.gz加上64字节头。
在命令行使用uboot根目录tools/mkimage工具编译即可:
mkimage -A arm -O linux -C gzip -T ramdisk -d ramdisk.gz ramdisk_1.gz
执行完成后生成ramdisk_1.gz压缩包,将其加载到内存地址0x42000000,使用bootm命令启动。
参考文章