程序项目代做,有需求私信(vue、React、Java、爬虫、电路板设计、嵌入式linux等)

Rockchip RK3399 - busybox 1.36.0制作根文件系统

在《Mini2440linux根文件系统yaffs2移植》文章中我们已经介绍了根文件系统的概念以及制作过程,不过当时是制作的是yaffs2类型的根文件系统,适用于外部设备Nand Flash,这一节我们将尝试制作ramdiskext4类型的根文件系统。

一、 编译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个文件:binsbinusr这三个目录里都是二进制命令工具,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

这里我们挂载的文件系统有三个procsysfstmpfs,在内核中procsysfs默认都支持,而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.scriptRESOLV_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.scriptDNS配置文件/tmp/resolv.conf。在rcS中启动udhcpc,默认使用default.script脚本已达到自动配置iproute等。

修改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.gz64字节数据头。所以用这种方法向内核传递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

参考文章

[1] 嵌入式ARM64 Linux内核编译及根文件系统构建

[2] Mini2440linux根文件系统yaffs2移植

posted @ 2023-05-29 00:05  大奥特曼打小怪兽  阅读(1051)  评论(0编辑  收藏  举报
如果有任何技术小问题,欢迎大家交流沟通,共同进步