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@ubuntu:/work/sambashare/rk3399# mkdir rootfs
root@ubuntu:/work/sambashare/rk3399# cd rootfs
root@ubuntu:/work/sambashare/rk3399/rootfs# wget https://busybox.net/downloads/busybox-1.36.0.tar.bz2
tar
root@ubuntu:/work/sambashare/rk3399/rootfs# tar -jxf busybox-1.36.0.tar.bz2
1.2 配置busybox
在路径busybox-1.36.0
下运行如下命令,使用默认配置:
root@ubuntu:/work/sambashare/rk3399/rootfs# cd busybox-1.36.0/
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox-1.36.0# make defconfig
然后进入图像化配置页面,修改配置 :
root@ubuntu:/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
( ) Path to sysroot # 根路径未指定
[ ] Build static binary (no shared libs)
[*] Build Shared libbusybox
(./_install) Destination path for 'make install'
编译方式有两种:
- 第一种是以静态方式编译,即生成的
busybox
不需要动态库的支持就能运行。这样做我们就不需要部署动态库了,缺点就是自己写的程序在这个根文件系统中是不能运行的,因为缺少动态库库的支持。 - 第二种方式使用动态编译,这样的话我们就需要部署动态库了,在
linux
动态库文件是以so
为后缀,而windows
下文件是以dll
为后缀。
这里我们指定了 arm-gnu-toolchain-12.2.rel1-x86_64-aarch64-none-linux-gnu
交叉编译工具链的路径,有关交叉编译工具链的安装可以参考我们这两篇博客;
继续配置:
Linux System Utilities --->
[] nsenter
Coreutils --->
[] sync
Miscellaneous Utilities --->
自己选择
Networking Utilities --->
[*] Support /etc/networks
[*] udhcpc (24 kb)
[*] Verify that the offered address is free, using ARP ping
[*] Do not pass malformed host and domain names
(/usr/share/udhcpc/default.script) Absolute path to config script
(/usr/share/udhcpc/default6.script) Absolute path to config script for IPv6
Linux System Utilities --->
[*] mdev (17 kb)
[*] hexdump
Linux Module Utilities --->
[*] depmod (27 kb)
[*] Support module.aliases file
[*] Support module.symbols file
(/lib/modules) Default directory containing modules
(modules.dep) Default name of modules.dep
1.3 编译安装
运行命令:
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox-1.36.0# make
然后查看当前路径下是否存在busybox
:
root@ubuntu:/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@ubuntu:/work/sambashare/rk3399/rootfs/busybox-1.36.0# make install
make install
的目的就是将编译生成的可执行程序及其依赖的库文件、配置文件、头文件安装到当前系统中指定(一般都可以自己指定安装到哪个目录下,如果不指定一般都有个默认目录)的目录下,默认被安装到_install
目录下:
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox-1.36.0# ll _install/
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@ubuntu:/work/sambashare/rk3399/rootfs/busybox-1.36.0# mkdir ../busybox_install
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox-1.36.0# cp -a _install/* ../busybox_install/
2.1 添加库文件
切换到busybox_install
路径下:
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox-1.36.0# cd ../busybox_install
找到交叉编译工具里的动态库复制到lib
目录下:
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install# mkdir lib
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install# cp -a /usr/local/arm/12.2.1/aarch64-none-linux-gnu/libc/lib/*so* ./lib/
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install# cp -a /usr/local/arm/12.2.1/aarch64-none-linux-gnu/libc/lib64/*so* ./lib64/
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install# cp -a /usr/local/arm/12.2.1/aarch64-none-linux-gnu/libc/usr/lib/*so* ./lib/
root@ubuntu:/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@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install# ls ./lib
ld-linux-aarch64.so.1 libinproctrace.so
root@ubuntu:/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@ubuntu:/work/sambashare/rk3399/rootfs# cd busybox-1.36.0/
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox-1.36.0# ll examples/bootfloppy/etc/
-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
在busybox_install
目录,创建etc
文件夹:
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install# mkdir etc
将这些配置文件复制到新制作的根文件系统etc
目录下。
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install# cp -a ../busybox-1.36.0/examples/bootfloppy/etc/* ./etc
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install# ll etc
-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/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.3 修改/etc/profile
文件
/etc/profile
文件作用是设置环境变量,每个用户登录时都会运行它,将文件内容修改为:
# 主机名
export HOSTNAME=NanoPC-T4 # NanoPC-T6
# 用户名
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.2.4 新建 S40network
需要创建/etc/init.d/S40network
文件:
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install# vim etc/init.d/S40network
内容如下:
#!/bin/sh
#
# Start the network....
#
# Debian ifupdown needs the /run/network lock directory
mkdir -p /run/network
case "$1" in
start)
printf "Starting network: "
/sbin/ifup -a
[ $? = 0 ] && echo "OK" || echo "FAIL"
;;
stop)
printf "Stopping network: "
/sbin/ifdown -a
[ $? = 0 ] && echo "OK" || echo "FAIL"
;;
restart|reload)
"$0" stop
"$0" start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
esac
exit $?
2.2.5 udhcpc
配置
拷贝文件simple.script
到根文件系统的/usr/share/udhcpc/
目录下,更名为default.script
;
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install# mkdir -p ./usr/share/udhcpc
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install# cp ../busybox-1.36.0/examples/udhcp/simple.script ./usr/share/udhcpc
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install# mv ./usr/share/udhcpc/simple.script ./usr/share/udhcpc/default.script
再将default.script
中RESOLV_CONF=”/etc/resolv.conf”
更改为RESOLV_CONF=”/tmp/resolv.conf”
;
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install# vim ./usr/share/udhcpc/default.script
RESOLV_CONF="/tmp/resolv.conf"
......
我们配置一下网络DHCP
,这样系统启动以后就会自动设置好网络;
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install# mkdir -p etc/network/interfaces.d
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install# vim etc/network/interfaces
# interface file auto-generated by buildroot
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install# mkdir etc/network/if-down.d
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install# vim etc/network/if-down.d/dhcp-down.sh
#!/bin/sh
# This file is executed by ifupdown in pre-up, post-up, pre-down and
# post-down phases of network interface configuration.
# run this script only for interfaces which have dhcp-down option
[ -z "$IF_DHCP_DOWN" ] && exit 0
$IF_DHCP_DOWN $IFACE
exit 0
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install# mkdir etc/network/if-up.d
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install# vim etc/network/if-up.d/dhcp-up.sh
#!/bin/sh
# This file is executed by ifupdown in pre-up, post-up, pre-down and
# post-down phases of network interface configuration.
# run this script only for interfaces which have dhcp-up option
[ -z "$IF_DHCP_UP" ] && exit 0
$IF_DHCP_UP $IFACE&
exit 0
2.2.6 修改/etc/init.d/rcS
文件
#!/bin/sh
# 挂载 /etc/fstab 中定义的所有文件系统
/bin/mount -a
# 挂载虚拟的devpts文件系统用于用于伪终端设备
/bin/mkdir -p /dev/pts
/bin/mount -t devpts devpts /dev/pts
# 扫描并创建节点
/sbin/mdev -s
# 加载网卡驱动
/sbin/modprobe r8125
# 配置网络
/sbin/udhcpc
# Start all init scripts in /etc/init.d
# executing them in numerical order.
#
for i in /etc/init.d/S??* ;do
# Ignore dangling symlinks (if any).
[ ! -f "$i" ] && continue
case "$i" in
*.sh)
# Source shell script for speed.
(
trap - INT QUIT TSTP
set start
. $i
)
;;
*)
# No sh extension, so fork subprocess.
$i start
;;
esac
done
整个udhcpc
的框架是可执行文件/sbin/udhcpc
、脚本文件/usr/share/udhcpc/default.script
、DNS
配置文件/tmp/resolv.conf
。在rcS
中启动udhcpc
,默认使用default.script
脚本已达到自动配置ip
、route
等。
修改init.d
文件权限:
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install# chmod -R 777 etc/init.d/*
2.3 安装网卡驱动
从此我们以 NanoPC-T6
开发板为例介绍网卡驱动安装,首先我们需要给开发板烧录官方提供的debian-bullseye-desktop
系统,开发板启动后我们需要拷贝debian-bullseye-desktop
系统重网卡相关驱动和固件到busybox
文件系统;
root@ubuntu:/work/sambashare/rk3588/rootfs$ mkdir lib
在宿主机执行如下命令:
root@ubuntu:/work/sambashare/rk3588/rootfs$ scp -r pi@192.168.0.100:/lib/modules ./lib
root@ubuntu:/work/sambashare/rk3588/rootfs$ scp -r pi@192.168.0.100:/lib/firmware ./lib
查看文件:
root@ubuntu:/work/sambashare/rk3588/rootfs$ ls lib/modules/6.1.25/
cryptodev.ko modules.builtin.bin modules.softdep rtl8821CU.ko rtw_8723du.ko rtw_8822bs.ko rtw_sdio.ko
kernel modules.builtin.modinfo modules.symbols rtl8822bu.ko rtw_8821ce.ko rtw_8822ce.ko rtw_usb.ko
modules.alias modules.dep modules.symbols.bin rtl8822cs.ko rtw_8821c.ko rtw_8822c.ko
modules.alias.bin modules.dep.bin nft_fullcone.ko rtw_8723de.ko rtw_8821cs.ko rtw_8822cs.ko
modules.builtin modules.devname r8125.ko rtw_8723d.ko rtw_8822be.ko rtw_core.ko
modules.builtin.alias.bin modules.order rtl8812au.ko rtw_8723ds.ko rtw_8822b.ko rtw_pci.ko
zhengyang@ubuntu:/work/sambashare/rk3588$ ls lib/firmware/
brcm iwlwifi-cc-a0-59.ucode mediatek mt7662_rom_patch.bin regulatory.db.p7s rtl_bt rtw88
intel mali_csffw.bin mt7662.bin regulatory.db rockchip rtl_nic
由于lib
目录下文件比较多,如果都复制到我们制作的根文件系统中,那我们就得重新调整如下参数;
- 内核配置参数:
RAM disk size
; buildroot配置参数:
exact size
;- 分区表
parameter.txt
;
否则系统启动可能出现如下异常:
[ 6.323929] BUG: Bad page state in process kworker/u16:2 pfn:10400
[ 6.323943] page:(____ptrval____) refcount:0 mapcount:-128 mapping:0000000000000000 index:0x4 pfn:0x10400
[ 6.323953] flags: 0x0(zone=0) CMA
[ 6.323964] raw: 0000000000000000 dead000000000100 dead000000000122 0000000000000000
[ 6.323973] raw: 0000000000000004 000000000000000a 00000000ffffff7f 0000000000000000
[ 6.323978] page dumped because: nonzero mapcount
[ 6.323983] Modules linked in:
[ 6.323992] CPU: 4 PID: 71 Comm: kworker/u16:2 Not tainted 6.1.25 #4
[ 6.324001] Hardware name: FriendlyElec NanoPC-T6 (DT)
[ 6.324007] Workqueue: events_unbound async_run_entry_fn
[ 6.324020] Call trace:
[ 6.324025] dump_backtrace+0xdc/0x130
[ 6.324039] show_stack+0x1c/0x30
[ 6.324050] dump_stack_lvl+0x64/0x7c
[ 6.324061] dump_stack+0x14/0x2c
[ 6.324071] bad_page+0xe8/0x110
[ 6.324080] free_page_is_bad_report+0x84/0x8c
[ 6.324089] free_pcppages_bulk+0x1d0/0x284
[ 6.324098] free_unref_page_commit+0x168/0x1b0
[ 6.324107] free_unref_page+0x128/0x1a0
[ 6.324116] __free_pages+0xf8/0x104
[ 6.324125] free_reserved_area+0x88/0x14c
[ 6.324135] free_initrd_mem+0x48/0x54 # free_initrd_mem
[ 6.324144] do_populate_rootfs+0x12c/0x16c
[ 6.324151] async_run_entry_fn+0x3c/0x170
[ 6.324158] process_one_work+0x1c8/0x3d0
[ 6.324169] worker_thread+0x74/0x414
[ 6.324178] kthread+0xdc/0xe0
[ 6.324187] ret_from_fork+0x10/0x20
[ 6.324196] Disabling lock debugging due to kernel taint
为此,这里我们仅仅复制网卡驱动到/lib/modules
目录下。
接着我们需要将网卡驱动拷贝到/lib/modules
目录下;
root@ubuntu:/work/sambashare/rk3588/rootfs$ cd busybox_install
root@ubuntu:/work/sambashare/rk3588/rootfs/busybox_install$ mkdir -p ./lib/modules/6.1.25
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install$ cp -a ../lib/modules/6.1.25/*.ko ./lib/modules/6.1.25
注意:位于busybox
系统/lib/modules
目录下的驱动模块在内核启动的时候并不会自动加载,因此我们才在/etc/init.d/rcS
中使用modprobe
去加载了r8125.ko
驱动;
root@ubuntu:/work/sambashare/rk3588/rootfs$ ls busybox_install/lib/modules
cryptodev.ko rtl8812au.ko rtl8822cs.ko rtw_8723ds.ko rtw_8821c.ko rtw_8822b.ko rtw_8822c.ko rtw_pci.ko
nft_fullcone.ko rtl8821CU.ko rtw_8723de.ko rtw_8723du.ko rtw_8821cs.ko rtw_8822bs.ko rtw_8822cs.ko rtw_sdio.ko
r8125.ko rtl8822bu.ko rtw_8723d.ko rtw_8821ce.ko rtw_8822be.ko rtw_8822ce.ko rtw_core.ko rtw_usb.ko
root@ubuntu:/work/sambashare/rk3588/rootfs$ vim busybox_install/etc/init.d/rcS
......
# 加载网卡驱动
/sbin/modprobe r8125
......
2.4 构建dev
目录
在rootfs
目录,创建dev
文件夹:
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install# mkdir dev
创建终端文件:
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install# mknod dev/console c 5 1
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install# mknod dev/null c 1 3
2.5 构建其他文件
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install# mkdir mnt proc tmp sys root
root@ubuntu:/work/sambashare/rk3399/rootfs/busybox_install# ll
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/
三、制作根文件系统镜像
3.1 ext4
建立根文件系统挂载点busybox_rootfs
:
root@ubuntu:/work/sambashare/rk3399/rootfs# mkdir busybox_rootfs
创建空镜像文件busybox_ext4_rootfs.img
,大小300m
,具体需要的大小可以通过du build -h
查看我们根文件系统大小调整;
root@ubuntu:/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@ubuntu:/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@ubuntu:/work/sambashare/rk3399/rootfs# mkfs.ext4 busybox_ext4_rootfs.img
将该镜像文件挂载到busybox_rootfs
:
root@ubuntu:/work/sambashare/rk3399/rootfs# mount busybox_ext4_rootfs.img busybox_rootfs
然后将busybox_install
的文件复制到该空文件夹中:
root@ubuntu:/work/sambashare/rk3399/rootfs# cp ./busybox_install/* ./busybox_rootfs/ -af
使用df
命令可以查看是否已经挂载:
root@ubuntu:/work/sambashare/rk3399# df busybox_rootfs/
文件系统 1K-块 已用 可用 已用% 挂载点
/dev/loop12 280880 99872 159504 39% /work/sambashare/rk3399/rootfs/busybox_rootfs
将之前挂载的卸载掉:
root@ubuntu:/work/sambashare/rk3399/rootfs# umount busybox_rootfs
root@ubuntu:/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@ubuntu:/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@ubuntu:/work/sambashare/rk3399/rootfs# rm -rf busybox_rootfs
用e2fsck
修复及检测镜像文件系统,resize2fs
减小镜像文件的大小;
root@ubuntu:/work/sambashare/rk3399/rootfs# e2fsck -p -f busybox_ext4_rootfs.img
busybox_ext4_rootfs.img:503/76800 文件(0.4% 为非连续的),31515/76800 块
root@ubuntu:/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@ubuntu:/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@ubuntu:/work/sambashare/rk3399/rootfs# du -sh busybox_ext4_rootfs.img
114M busybox_ext4_rootfs.img
最终得到的ext4
根文件系统镜像busybox_ext4_rootfs.img
大小为114MB
。
3.2 ramdisk
前面我们已经制作了ext4
文件文件系统,至于ramdisk
,就是用内存模拟了一个块设备(比如内核设备节点/dev/ram0
),这个模拟的块设备是需要一个文件系统(比如ext4
或者其它文件系统)来组织数据的。
这里为了减少文件系统的大小,我们对busybox_ext4_rootfs.img
文件系统进行镜像压缩,压缩后为ramdisk.gz
。
root@ubuntu:/work/sambashare/rk3399/rootfs# gzip -v9 busybox_ext4_rootfs.img
busybox_ext4_rootfs.img: 91.2% -- replaced with busybox_ext4_rootfs.img.gz
root@ubuntu:/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
在内存的位置。
- 修改
内核启动时如何告诉内核ramdisk.gz
在内存的位置有两种方式,具体如下。
3.2.1 配置内核启动参数bootargs
假设ramdisk.gz
文件被加载到内存指定位置0x42000000
。修改bootargs
加入如下配置:
initrd=0x42000000,0x14000000
initrd
参数格式为:地址,长度,这里设备RAM
地址为0x42000000
起始,只要是在内核RAM
物理地址空间内。长度这里只要比ramdisk.gz
压缩包大小大就可以了;
3.2.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
命令启动。
四、mk-ramdisk.sh
我们将构建根文件系统和ramdisk
镜像的过程,整理到mk-ramdisk.sh
脚本中;
点击查看代码
#!/bin/bash
[[ -n DEBUG ]] && set -x
err_handler()
{
# 如果参数1为空,则获取最近一次执行命令的退出状态
ret=${1:-$?}
# 退出状态为0,直接返回
[ "$ret" -eq 0 ] && return
# 入参参数2为空,输出调用栈中的第二个函数名
echo "ERROR: Running $0 - ${2:-${FUNCNAME[1]}} failed!"
# 输出错误状态码,以及发生错误的行号
echo "ERROR: exit code $ret from line ${BASH_LINENO[0]}:"
# 如果参数3为空,输出当前正在执行的命令
echo " ${3:-$BASH_COMMAND}"
echo "ERROR: call stack:"
for i in $(seq 1 $((${#FUNCNAME[@]} - 1))); do
SOURCE="${BASH_SOURCE[$i]}"
LINE=${BASH_LINENO[$(( $i - 1 ))]}
echo " $(basename "$SOURCE"): ${FUNCNAME[$i]}($LINE)"
done
exit $ret
}
trap 'err_handler' ERR
set -eE
# 获取当前工作路径
WORK_DIR=$(dirname "$(realpath "$BASH_SOURCE")")
# busybox编译安装目录
BUSYBOX_SOURCR_DIR="$WORK_DIR/busybox-1.36.0"
# 保存busybox根文件系统目录
BUSYBOX_ROOTFS="$WORK_DIR/busybox_install"
# 判断当前目录下是否存在安装目录_install
if [[ ! -d "$BUSYBOX_SOURCR_DIR/_install" ]];then
echo "请先编译安装Busybox"
exit 1
fi
# 删除目录
rm -rf $BUSYBOX_ROOTFS
# 创建目录
echo "开始创建目录${BUSYBOX_ROOTS}"
mkdir $BUSYBOX_ROOTFS
cd $BUSYBOX_ROOTFS
cp -a $BUSYBOX_SOURCR_DIR/_install/* ./
# 找到交叉编译工具里的动态库复制到lib目录下
echo "开始拷贝lib文件"
cp -a /usr/aarch64-linux-gnu/lib/* ./lib
if [[ -d "${WORD_DIR}/lib" ]];then
mkdir -p ./lib/modules/6.1.25
cp -a $WORK_DIR/lib/modules/6.1.25/*.ko ./lib/modules/6.1.25
fi
# 1. 构建etc目录
echo "开始创建etc目录"
mkdir etc
mkdir -p etc/init.d/
echo "开始创建/etc/inittab文件"
# 1.1 构建/etc/inittab
cat>etc/inittab<<EOF
# 系统启动时
::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
EOF
chmod 755 etc/inittab
echo "开始创建/etc/init.d/rcS文件"
# 1.2 构建/etc/init.d/rcS
cat>etc/init.d/rcS<<EOF
#!/bin/sh
# 挂载 /etc/fstab 中定义的所有文件系统
/bin/mount -a
# 挂载虚拟的devpts文件系统用于用于伪终端设备
/bin/mkdir -p /dev/pts
/bin/mount -t devpts devpts /dev/pts
# 扫描并创建节点
/sbin/mdev -s
# 加载网卡驱动
/sbin/modprobe r8125
# 配置网络
/sbin/udhcpc
# Start all init scripts in /etc/init.d
# executing them in numerical order.
#
for i in /etc/init.d/S??* ;do
# Ignore dangling symlinks (if any).
[ ! -f "\$i" ] && continue
case "\$i" in
*.sh)
# Source shell script for speed.
(
trap - INT QUIT TSTP
set start
. \$i
)
;;
*)
# No sh extension, so fork subprocess.
\$i start
;;
esac
done
EOF
echo "开始创建/etc/fstab文件"
# 1.3 构建/etc/fstab
cat>etc/fstab<<EOF
# <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
EOF
echo "开始创建/etc/profile文件"
# 1.4 构建/etc/profile
cat>etc/profile<<EOF
# 主机名
export HOSTNAME=NanoPC-T6
# 用户名
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
EOF
echo "开始创建dev目录"
#1.5 构建dev目录
mkdir dev
mknod dev/console c 5 1
mknod dev/null c 1 3
mknod dev/tty1 c 4 1
echo "开始创建/etc/init.d/S40network文件"
#1.6 构建/etc/init.d/S40network
cat>etc/init.d/S40network<<EOF
#!/bin/sh
#
# Start the network....
#
# Debian ifupdown needs the /run/network lock directory
mkdir -p /run/network
case "\$1" in
start)
printf "Starting network: "
/sbin/ifup -a
[ \$? = 0 ] && echo "OK" || echo "FAIL"
;;
stop)
printf "Stopping network: "
/sbin/ifdown -a
[ \$? = 0 ] && echo "OK" || echo "FAIL"
;;
restart|reload)
"\$0" stop
"\$0" start
;;
*)
echo "Usage: \$0 {start|stop|restart}"
exit 1
esac
exit $?
EOF
echo "开始创建/usr/share/udhcpc/default.script文件"
# 1.7 构建/usr/share/udhcpc/default.script
mkdir -p ./usr/share/udhcpc
cp $BUSYBOX_SOURCR_DIR/examples/udhcp/simple.script ./usr/share/udhcpc
mv ./usr/share/udhcpc/simple.script ./usr/share/udhcpc/default.script
sed -i 's/\/etc\/resolv\.conf/\/tmp\/resolv\.conf/g' ./usr/share/udhcpc/default.script
mkdir -p etc/network/interfaces.d
cat>etc/network/interfaces<<EOF
# interface file auto-generated by buildroot
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp
EOF
mkdir etc/network/if-down.d
cat>etc/network/if-down.d/dhcp-down.sh<<EOF
#!/bin/sh
# This file is executed by ifupdown in pre-up, post-up, pre-down and
# post-down phases of network interface configuration.
# run this script only for interfaces which have dhcp-down option
[ -z "\$IF_DHCP_DOWN" ] && exit 0
\$IF_DHCP_DOWN \$IFACE
exit 0
EOF
mkdir etc/network/if-up.d
cat>etc/network/if-up.d/dhcp-up.sh<<EOF
#!/bin/sh
# This file is executed by ifupdown in pre-up, post-up, pre-down and
# post-down phases of network interface configuration.
# run this script only for interfaces which have dhcp-up option
[ -z "\$IF_DHCP_UP" ] && exit 0
\$IF_DHCP_UP \$IFACE&
exit 0
EOF
# 修改权限
chmod -R 777 etc/init.d/*
# 构建其他文件
mkdir mnt proc tmp sys root
# 构建ramdisk镜像
echo "开始构建ramdisk镜像文件"
cd ..
mkdir busybox_rootfs
dd if=/dev/zero of=busybox_ext4_rootfs.img bs=1M count=300
mkfs.ext4 busybox_ext4_rootfs.img
mount busybox_ext4_rootfs.img busybox_rootfs
cp ${BUSYBOX_ROOTFS}/* ./busybox_rootfs/ -af
umount busybox_rootfs
rm -rf busybox_rootfs
e2fsck -p -f busybox_ext4_rootfs.img
resize2fs -M busybox_ext4_rootfs.img
gzip -v9 busybox_ext4_rootfs.img
mv busybox_ext4_rootfs.img.gz ramdisk.gz
编译安装busybox
之后,执行如下命令;
root@ubuntu:/work/sambashare/rk3399/rootfs$ ./mk-ramdisk.sh
参考文章