RK3568最小根文件系统构建—静态库
1. BusyBox源码及工具链获取
1.1 BusyBox源码获取
BusyBox 是一个集成了三百多个最常用Linux命令和工具的软件。BusyBox 包含了一些简单的工具,例如ls、cat和echo等等,还包含了一些更大、更复杂的工具,例grep、find、mount以及telnet。
官方网站:https://busybox.net/
目前最新版本为:BusyBox 1.36.1
为了获取到最新功能及各种工具的稳定版本,所以采用最新版构建本次使用的根文件系统,Git获取到的压缩包名称为busybox-1.36.1.tar.bz2
1.2 编译工具链获取
本次使用的工具链采用由ARM官方提供的预编译过的GNU编译器:
官方网站:https://developer.arm.com/downloads/-/gnu-a
选用10.2版本编译器,名称:
gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu.tar.xz
2. BusyBox编译及构建
2.1 编译环境搭建
编译环境选择Linux-Ubuntu-22.04.2-LTS版本
完成系统安装之后,首先进行基础编译环境的搭建,编译BusyBox除了需要交叉编译工具链之外,还需要一些基础的编译工具,包括了GCC以及build-essential工具箱。
build-essential工具箱主要包含了以下工具:
binutils binutils-common binutils-x86-64-linux-gnu build-essential dpkg-dev
fakeroot g++ g++-11 gcc gcc-11 libalgorithm-diff-perl libalgorithm-diff-xs-perl
libalgorithm-merge-perl libasan6 libbinutils libc-dev-bin libc-devtools
libc6-dev libcc1-0 libcrypt-dev libctf-nobfd0 libctf0 libdpkg-perl libfakeroot
libfile-fcntllock-perl libgcc-11-dev libitm1 liblsan0 libnsl-dev libquadmath0
libstdc++-11-dev libtirpc-dev libtsan0 libubsan1 linux-libc-dev lto-disabled-list
manpages-dev rpcsvc-proto
为了使用menuconfig功能,需要安装libncurses5-dev工具箱。
zl@zl-virtual-machine:~/busybox/target/busybox-1.36.1$ sudo apt-get install libncurses5-dev
2.2 编译
2.2.1 编译选项控制
首先使用make defconfig产生Busybox的默认配置。
zl@zl-virtual-machine:~/busybox/target/busybox-1.36.1$ make defconfig
scripts/kconfig/conf -d Config.in
* Busybox Configuration
*
*
* Settings
*
*
* Done!
使用该功能之后,BusyBox会依据默认配置对自身进行一个初始化配置,而后使用make menuconfig图形化编译工具对所需选项进行逐项修改。
zl@zl-virtual-machine:~/busybox/target/busybox-1.36.1$ make menuconfig
图形化控制界面:
在Setting当中选中[*] Build static binary (no shared libs)选项,将动态库编译更改为静态库编译,使用该方式编译完成后的工具将不再需要工具链当中的动态库即可独立运行。此外,为了便于测试,勾选lspci工具箱以及mke2fs、mkfs.ext2、mount、fsck等磁盘工具。
双击Esc,在退出菜单中选择保存文件,该功能会自动替换根目录下的.config文件。
scripts/kconfig/mconf Config.in
#
# using defaults found in .config
#
*** End of configuration.
2.2.2 顶层MakeFile修改
修改顶层MakeFile文件,完成ARCH、CROSS_COMPILE参数配置。
ARCH ?= aarch64
CROSS_COMPILE ?= /home/zlt/busybox/toolchain/gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-
环境变量配置。
指定动态链接lib库的相对路径,编译时会使用到该环境变量。
export LD_LIBRARY_PATH=/home/zl/busybox/toolchain/gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu/lib/
2.2.3 可执行文件编译
使用make完成busybox编译及可执行文件生成。
zl@zl-virtual-machine:~/busybox/target/busybox-1.36.1$ make
编译完成之后使用make install完成基础文件系统构建
zl@zl-virtual-machine:~/busybox/target/busybox-1.36.1$ make install
生成的文件默认在同级目录下的_install文件夹当中目前,该文件夹中仅有 bin、sbin、usr这 3个目录和软链接linuxrc,目录里都是二进制命令工具,这还不足以构成一个可用的根文件系统,必须进行其它完善工作,才能构建一个可用的根文件系统。
依照嵌入式Linux根文件系统结构,在rootfs目录中创建其他目录
zl@zl-virtual-machine:~/busybox/target/busybox-1.36.1/_install$ mkdir dev etc lib proc sys tmp var
添加初始化配置脚本,该脚本是Linux运行时所需的基础配置,在BusyBox当中的examples文件夹中有相对应的提供,使用命令将配置放置于构建的文件系统当中。
zl@zl-virtual-machine:~/busybox/target/busybox-1.36.1$ cp -a ../busybox/busybox-1.36.1/examples/bootfloppy/etc/* etc/
2.3 完善根文件系统
2.3.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
2.3.2 修改/etc/init.d/rcS文件
在etc/inittab文件的第一行配置项是”::sysinit:/etc/init.d/rcS”,表明系统初始化阶段(进入命令行前),会调用/etc/init.d/rcS文件。该文件是linux运行时最重要的配置文件,其余配置均由该文件引出。
#! /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
2.3.3 修改/etc/fstab文件
目录etc下的fstab文件用来存放文件系统信息。系统过程中执行/etc/init.d/rcS文件当中的/bin/mount -a命令时,将会自动挂载fstab当中的文件系统。修改如下:
# 主机名
export HOSTNAME=zl
# 用户名
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
最后,创建该用户所对应的家目录
zl@zl-virtual-machine:~/busybox/target/busybox-1.36.1/_install$ mkdir root
至此,基础文件系统构建完成
3. 内存文件系统制作
3.1 内存根文件系统
在Linux的启动阶段,内核和ramdisk都是由 bootloader在启动时加载至内存的指定位置,而initrd提供了一套机制,可以将内核映像和根文件系统一起载入内存。initrd 是boot loader initialized RAM disk,顾名思义是在系统初始化引导时候用的ramdisk,它的作用是完善内核的模块机制,让内核的初始化流程更具弹性。
基于RAM的文件系统有initramfs、ramdisk、ramfs、tmpfs以及nfs等,其中initramfs系统使用cpio格式进行构建,这种构建方式也可以将其编译到系统当中直接使用,无需再另外挂载文件系统;ramdisk则是一种基于内存的虚拟文件系统,其主要使用内存当中的一部分固定位置来实现虚拟的磁盘功能。
本次试验采用ext4格式的ramdisk来进行根文件系统制作。
3.2 ramdisk构建
3.2.1 镜像生成及挂载
利用Ubuntu运行时dev下的zero节点进行文件镜像制作,其中bs块大小为1024,count为128000
zl@zl-virtual-machine:~/busybox/target/busybox-1.36.1$ dd if=/dev/zero of=ramdisk.img bs=1024 count=128000
128000+0 records in
128000+0 records out
131072000 bytes (131 MB, 125 MiB) copied, 8.74144 s, 15.0 MB/s
接下来对生成的新文件系统进行相对应的格式化,该步骤使用mkfs.ext4工具进行。
zl@zl-virtual-machine:~/busybox/target/busybox-1.36.1$ mkfs.ext4 -F ramdisk.img
mke2fs 1.46.5 (30-Dec-2021)
Discarding device blocks: done
Creating filesystem with 32000 4k blocks and 32000 inodes
Allocating group tables: done
Writing inode tables: done
Creating journal (1024 blocks): done
Writing superblocks and filesystem accounting information: done
创建临时目录tmp,用于挂载ramdisk.img文件镜像,并将空的ramdisk.img虚拟磁盘挂载在tmp文件目录,命令和流程如下。
zl@zl-virtual-machine:~/busybox/target/busybox-1.36.1$ mkdir tmp
zl@zl-virtual-machine:~/busybox/target/busybox-1.36.1$ sudo mount -t ext4 -o loop ramdisk.img tmp/
3.2.2 添加BusyBox到镜像
将根文件系统rootfs目录下的所有内容拷贝到tmp目录,命令和流程如下所示:
zl@zl-virtual-machine:~/busybox/target/busybox-1.36.1$ sudo cp -r _install/* tmp/ -d
挂载完成及拷贝过后的文件系统内容如下:
zl@zl-virtual-machine:~/busybox/target/busybox-1.36.1$ ls tmp/
bin dev etc lib linuxrc lost+found proc root sbin sys tmp usr var
确认文件拷贝完成之后即可进行tmp文件系统的卸载
zl@zl-virtual-machine:~/busybox/target/busybox-1.36.1$ sudo umount tmp
3.2.3 制作uboot引导
首先安装uboot工具箱,该工具箱当中的工具可以帮助完成根文件系统的加头操作,命令如下:
zl@zl-virtual-machine:~/busybox/target/busybox-1.36.1$ sudo apt-get install u-boot-tools
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
device-tree-compiler libfdt1 libubootenv-tool libubootenv0.1
The following NEW packages will be installed:
device-tree-compiler libfdt1 libubootenv-tool libubootenv0.1 u-boot-tools
0 upgraded, 5 newly installed, 0 to remove and 16 not upgraded.
Need to get 463 kB of archives.
After this operation, 1,349 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
Get:1 http://mirrors.aliyun.com/ubuntu jammy/main amd64 libubootenv0.1 amd64 0.3.2-1build1 [12.0 kB]
Get:2 http://mirrors.aliyun.com/ubuntu jammy/main amd64 libubootenv-tool amd64 0.3.2-1build1 [7,304 B]
Get:3 http://mirrors.aliyun.com/ubuntu jammy-updates/main amd64 u-boot-tools amd64 2022.01+dfsg-2ubuntu2.3 [196 kB]
Get:4 http://mirrors.aliyun.com/ubuntu jammy/main amd64 libfdt1 amd64 1.6.1-1 [20.0 kB]
Get:5 http://mirrors.aliyun.com/ubuntu jammy/main amd64 device-tree-compiler amd64 1.6.1-1 [228 kB]
Fetched 463 kB in 1s (441 kB/s)
Selecting previously unselected package libubootenv0.1:amd64.
(Reading database ... 210461 files and directories currently installed.)
Preparing to unpack .../libubootenv0.1_0.3.2-1build1_amd64.deb ...
Unpacking libubootenv0.1:amd64 (0.3.2-1build1) ...
Selecting previously unselected package libubootenv-tool.
Preparing to unpack .../libubootenv-tool_0.3.2-1build1_amd64.deb ...
Unpacking libubootenv-tool (0.3.2-1build1) ...
Selecting previously unselected package u-boot-tools.
Preparing to unpack .../u-boot-tools_2022.01+dfsg-2ubuntu2.3_amd64.deb ...
Unpacking u-boot-tools (2022.01+dfsg-2ubuntu2.3) ...
Selecting previously unselected package libfdt1:amd64.
Preparing to unpack .../libfdt1_1.6.1-1_amd64.deb ...
Unpacking libfdt1:amd64 (1.6.1-1) ...
Selecting previously unselected package device-tree-compiler.
Preparing to unpack .../device-tree-compiler_1.6.1-1_amd64.deb ...
Unpacking device-tree-compiler (1.6.1-1) ...
Setting up libfdt1:amd64 (1.6.1-1) ...
Setting up libubootenv0.1:amd64 (0.3.2-1build1) ...
Setting up device-tree-compiler (1.6.1-1) ...
Setting up u-boot-tools (2022.01+dfsg-2ubuntu2.3) ...
Setting up libubootenv-tool (0.3.2-1build1) ...
Processing triggers for man-db (2.10.2-1) ...
Processing triggers for libc-bin (2.35-0ubuntu3.1) ...
接下来,压缩ramdisk.img虚拟磁盘为ramdisk.img.gz文件,作为uboot引导使用。
zl@zl-virtual-machine:~/busybox/target/busybox-1.36.1$ gzip --best -c ramdisk.img > ramdisk.img.gz
使用mkimage命令对ramdisk.img.gz文件增加uboot头部,命令如下:
zl@zl-virtual-machine:~/busybox/target/busybox-1.36.1$ sudo mkimage -n 'uboot ext4 ramdisk rootfs' -A arm -O linux -T ramdisk -C gzip -d ramdisk.img.gz ramdisk.img.gz.uboot
Image Name: uboot ext4 ramdisk rootfs
Created: Sun Jul 30 21:36:36 2023
Image Type: ARM Linux RAMDisk Image (gzip compressed)
Data Size: 1261173 Bytes = 1231.61 KiB = 1.20 MiB
Load Address: 00000000
Entry Point: 00000000
使用mkimage进行加头操作的ramdisk.img.gz.uboot文件即为最终的uboot可以识别的内存根文件系统。
4. 文件系统测试
4.1 试验平台
本次试验平台采用ARM+FPGA方式,链接通路选择PCIE通道,其中ARM平台采用RK3568,FPGA平台采用Xilinx的K7-325T系列,平台如下:
4.2 根文件系统挂载
文件系统、内核以及设备树在uboot当中采用TFTP方式下载至RK3568的内存中,命令如下:
服务器及本地信息设置
Net: eth0: ethernet@fe2a0000, eth1: ethernet@fe010000
Hit key to stop autoboot('CTRL+C'): 0
=> setenv ipaddr 192.168.0.90
=> setenv gatewayip 192.168.0.1
=> setenv serverip 192.168.0.100
=> saveenv
Image镜像下载
=> tftp 0x10000000 Image
ethernet@fe2a0000 Waiting for PHY auto negotiation to complete. done
Using ethernet@fe2a0000 device
TFTP from server 192.168.0.100; our IP address is 192.168.0.90
Filename 'Image'.
Load address: 0x10000000
设备树下载
=> tftp 0x12000000 RK3568-zhuliang-linux.dtb
Using ethernet@fe2a0000 device
TFTP from server 192.168.0.100; our IP address is 192.168.0.90
Filename ' RK3568-zhuliang -linux.dtb'.
Load address: 0x12000000
ramdisk镜像下载
=> tftp 0x13000000 ramdisk.img.gz.uboot
Using ethernet@fe2a0000 device
TFTP from server 192.168.0.100; our IP address is 192.168.0.90
Filename 'ramdisk.img.gz.uboot'.
Load address: 0x13000000
内核跳转
=> booti 0x10000000 0x13000000 0x12000000
Fdt Ramdisk skip relocation
## Loading init Ramdisk from Legacy Image at 13000000 ...
Image Name: uboot ext4 ramdisk rootfs
Image Type: ARM Linux RAMDisk Image (gzip compressed)
Data Size: 15092558 Bytes = 14.4 MiB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
## Flattened Device Tree blob at 0x12000000
Booting using the fdt blob at 0x12000000
'reserved-memory' ramoops@110000: addr=110000 size=f0000
Using Device Tree in place at 0000000012000000, end 0000000012023b80
Adding bank: 0x00200000 - 0x08400000 (size: 0x08200000)
Adding bank: 0x09400000 - 0x80000000 (size: 0x76c00000)
== DO RELOCATE == Kernel from 0x00280000 to 0x10080000
Total: 226540.184 ms
Starting kernel ...
I/TC: Secondary CPU 1 initializing
I/TC: Secondary CPU 1 switching to normal world boot
I/TC: Secondary CPU 2 initializing
I/TC: Secondary CPU 2 switching to normal world boot
I/TC: Secondary CPU 3 initializing
I/TC: Secondary CPU 3 switching to normal world boot
[ 0.000000] Booting Linux on physical CPU 0x0000000000 [0x412fd050]
使用ls命令可以看到根文件系统挂载是否成功
[root@zl:/]# ls
bin lib proc sys var
dev linuxrc root tmp
etc lost+found sbin usr
4.3 FPGA信息读取
该试验主要是验证使用BusyBox进行构建的二进制文件能否正常使用,首先使用busybox命令对编译出的二进制信息进行验证:
[root@zl:/]# busybox
而后利用lspci工具验证FPGA能否正常挂载,FPGA内部已经使用Xilinx所提供的XDMA-IP核构建基础环境,并将其固化于外部SPI-NOR当中,无需再次进行程序下载,使用工具对PCIE设备进行扫描:
[root@zl:/]# ./lspci -v
可以看到1d87节点为瑞芯微的厂商ID,在该系统当中为PCIE根节点,而10ee节点则是赛灵思的厂商ID,该信息通过配置的FPGA-BAR空间获取,FPGA相关配置如下:
5. 项目开源
BusyBox工程开源://todo
FPGA工程开源://todo