嵌入式Linux根文件系统制作与移植

嵌入式 Linux 根文件系统制作与移植


1. 前言

1.1 为什么需要根文件系统?

在嵌入式Linux系统中,内核(Kernel)负责硬件驱动和资源调度,而根文件系统(Root Filesystem, RootFS)则是用户空间的"地基"。它包含系统启动必需的 init 进程、Shell 命令、动态链接库、配置文件和应用程序。没有根文件系统,内核即使启动成功也会在最后一步因为 "No init found" 而崩溃。

工业级开发常见两类需求:

  1. 极致轻量(BusyBox):用于 Flash 空间极小(<64MB)设备,或 Recovery/维护系统。
  2. 全功能集成(Buildroot/Yocto):用于智能网关/HMI 等,需要 Qt、Python、OpenCV 等复杂库。

本文以 迅为电子 RK3568(ARMv8,Cortex-A55)为例,讲解 BusyBox 与 Buildroot 两种方案 。


1.2 核心工具对比

工具 核心定位 优势 劣势 适用场景
BusyBox 极简工具集 体积极小、启动快、完全可控 依赖库/配置需手动处理 极简系统、维护系统、教学
Buildroot 自动化构建系统 一键生成(工具链+RootFS+可选内核)、易管理第三方库 编译时间长、初次配置复杂 产品级开发、快速原型验证

2. 基础准备

2.1 硬件与环境

  • 开发板:迅为 RK3568(eMMC/SD 卡启动,2GB RAM)

  • 主机环境:Ubuntu 20.04/22.04 LTS(64位)

  • 交叉编译工具链aarch64-linux-gnu-gcc(ARMv8 64位)

    • 注意:尽量确保工具链版本与内核/BSP 配套,否则可能出现 ABI 或库不匹配问题
  • 调试工具:USB 转串口模块

  • 提示 :RK3568 常见默认串口波特率 1,500,000 (1.5M)。请确认 CH340/CP2102 等芯片与驱动支持该波特率,否则会乱码。


2.2 RK3568 启动流程简述

U-Boot 通过 bootargs 告诉内核 rootfs 在哪(如 root=/dev/mmcblk0p2root=/dev/nfs)。


3. 方案一:BusyBox 制作极简根文件系统


3.1 获取并配置 BusyBox

(1)下载源码
bash 复制代码
wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2
tar -jxvf busybox-1.36.1.tar.bz2
cd busybox-1.36.1
(2)配置(menuconfig)
bash 复制代码
make defconfig
make menuconfig

关键配置(针对 RK3568):

  • SettingsBuild static binary (no shared libs)不勾选(动态库利于扩展;极致极简可选静态减少库管理)
  • SettingsCross compiler prefixaarch64-linux-gnu-
  • SettingsDestination path for 'make install'./_install
  • Settingsvi-style line editing commands:建议勾选(历史、编辑更方便)
  • Linux System Utilities → 勾选 mdev(配合热插拔;基础节点由 devtmpfs 提供)

3.2 编译与安装

bash 复制代码
make -j$(nproc)
make install

3.3 构建 RootFS 骨架(关键步骤)

(1)创建目录结构
bash 复制代码
cd _install
mkdir -p dev etc/init.d lib lib64 home mnt proc root sys tmp var usr/lib usr/bin

AArch64 经常出现 /lib + /lib64 并存的情况,建议两者都准备。

(2)最小设备节点

在 devtmpfs 之前,这两个节点能避免很多早期启动问题:

bash 复制代码
sudo mknod -m 600 dev/console c 5 1
sudo mknod -m 666 dev/null c 1 3

3.4 完善配置文件

A. etc/inittab
text 复制代码
::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r

respawn 适合调试:shell 退出会自动重启。产品化可改为 askfirst 或启动你的主程序。

B. etc/init.d/rcS(启动脚本:现代化 devtmpfs + mdev 热插拔)
sh 复制代码
#!/bin/sh

# 挂载虚拟文件系统
mount -t proc  proc  /proc
mount -t sysfs sysfs /sys

# /tmp:很多程序依赖可写临时目录
mount -t tmpfs tmpfs /tmp
chmod 1777 /tmp

#  关键:devtmpfs(内核自动填充 /dev 设备节点)
# 注意:需要内核启用 CONFIG_DEVTMPFS / CONFIG_DEVTMPFS_MOUNT
mount -t devtmpfs none /dev

# mdev:用于处理热插拔(U盘/网卡热插拔等)
# 说明:hotplug 的行为与内核配置有关(部分内核可能禁用 uevent helper)
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s

# 网络配置(示例:eth0)
ifconfig lo 127.0.0.1 up

# 方案1:固定 IP(工业现场常用)
ifconfig eth0 192.168.1.101 netmask 255.255.255.0 up
route add default gw 192.168.1.1 2>/dev/null

# 方案2:DHCP(调试更方便,需 BusyBox 启用 udhcpc)
# udhcpc -i eth0 &

echo "System initialized using BusyBox..."

赋予执行权限:

bash 复制代码
chmod +x etc/init.d/rcS
C. etc/fstab
text 复制代码
proc    /proc    proc    defaults    0 0
sysfs   /sys     sysfs   defaults    0 0
tmpfs   /tmp     tmpfs   defaults    0 0
D. 用户与组配置(避免 I have no name!

etc/passwd

text 复制代码
root:x:0:0:root:/root:/bin/sh

etc/group

text 复制代码
root:x:0:

(可选)etc/profile

sh 复制代码
export PATH=/sbin:/bin:/usr/sbin:/usr/bin

3.5 移植动态链接库

很多人遇到过这种现象:

  • 文件明明存在,但运行报:No such file or directory

这通常不是文件缺失,而是动态链接器(loader)缺失或路径不对

(1)确认 BusyBox 需要的解释器路径

在宿主机执行:

bash 复制代码
aarch64-linux-gnu-readelf -l _install/bin/busybox | grep "interpreter"

常见输出之一:

  • /lib/ld-linux-aarch64.so.1
  • /lib64/ld-linux-aarch64.so.1

记住它在哪个目录(lib / lib64),后面要对齐拷贝。

(2)从 sysroot 拷贝库(按目录对齐)
bash 复制代码
SYSROOT=$(aarch64-linux-gnu-gcc -print-sysroot)
echo "$SYSROOT"

推荐做法:同时准备 lib 与 lib64

bash 复制代码
# 关键:把 loader 拷对目录(lib 或 lib64)
cp -av "$SYSROOT/lib/ld-linux-aarch64.so.1"   lib/   2>/dev/null || true
cp -av "$SYSROOT/lib64/ld-linux-aarch64.so.1" lib64/ 2>/dev/null || true

# 拷贝常用运行库(根据 sysroot 实际情况,lib/lib64/usr/lib 可能存在其一或多个)
cp -av "$SYSROOT/lib/"*.so*   lib/   2>/dev/null || true
cp -av "$SYSROOT/lib64/"*.so* lib64/ 2>/dev/null || true
cp -av "$SYSROOT/usr/lib/"*.so* usr/lib/ 2>/dev/null || true
(3)剥离符号(可选,大幅减体积)
bash 复制代码
aarch64-linux-gnu-strip lib/*.so*    2>/dev/null || true
aarch64-linux-gnu-strip lib64/*.so*  2>/dev/null || true
aarch64-linux-gnu-strip usr/lib/*.so* 2>/dev/null || true
(4)检查点
bash 复制代码
ls -l lib/ld-linux-aarch64.so.1 2>/dev/null || true
ls -l lib64/ld-linux-aarch64.so.1 2>/dev/null || true

只要解释器与库齐了,BusyBox 基本就能跑。


3.6 制作 ext4 镜像与打包(确保属主为 root)

⚠️ 为保证文件属主/权限正确,打包时务必使用 sudo

bash 复制代码
# 1) 制作空镜像(示例 128MB,按 du -sh 估算后留余量)
dd if=/dev/zero of=rootfs.ext4 bs=1M count=128
mkfs.ext4 -F rootfs.ext4

# 2) 挂载(关键:用 loop)
mkdir -p /mnt/tmp_rootfs
sudo mount -o loop rootfs.ext4 /mnt/tmp_rootfs

# 3) 拷贝(保留属性)
sudo cp -a _install/* /mnt/tmp_rootfs/
sync

# 4) 卸载
sudo umount /mnt/tmp_rootfs

4. 方案二:Buildroot 自动化构建(推荐)

Buildroot 适合需要集成 SSH、Python、Qt 等复杂功能场景。

4.1 快速配置

注意:Buildroot 不同版本 defconfig 名称可能不同。若找不到 RK3568 专用配置,优先使用 rockchip64_defconfig

bash 复制代码
make rockchip64_defconfig
make menuconfig

必选建议:

  1. System configurationRoot password:设置 root 密码(否则 SSH 登录不方便)
  2. Target packagesNetworking applications:勾选 dropbear(轻量)或 openssh
  3. Target packagesEditors:勾选 vim/nano
  4. Filesystem images:确保勾选 ext2/3/4 root filesystem 并选择 ext4

4.2 国内下载慢的解决办法

  • Build optionsMirrors and Download locations:配置镜像源
  • 或提前把源码包放入 dl/ 目录

4.3 编译

bash 复制代码
make -j$(nproc)
# 输出通常在 output/images/rootfs.ext4

5. 开发调试技巧

5.1 NFS 网络根文件系统(开发效率加速器)

主机端(Ubuntu)

bash 复制代码
sudo apt-get install -y nfs-kernel-server
sudo mkdir -p /home/nvdia/rootfs_nfs

编辑 /etc/exports

text 复制代码
/home/nvdia/rootfs_nfs *(rw,sync,no_root_squash,no_subtree_check)

重启服务:

bash 复制代码
sudo service nfs-kernel-server restart

开发板端(U-Boot)设置 bootargs

bash 复制代码
setenv bootargs "console=ttyS2,1500000 root=/dev/nfs nfsroot=192.168.1.100:/home/nvdia/rootfs_nfs,v3,tcp rw ip=192.168.1.101:192.168.1.100:192.168.1.1:255.255.255.0::eth0:off init=/linuxrc"
saveenv
boot

优势:在 Ubuntu 上编译完程序直接复制到 NFS 目录,板端立即运行,不用频繁烧录。


5.2 开启 SSH

简要流程:

  1. 交叉编译 dropbear 并放入 rootfs
  2. 板端生成 key:
bash 复制代码
mkdir -p /etc/dropbear
dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key
  1. 启动:
bash 复制代码
dropbear

6. 常见故障排查

  1. Kernel panic - not syncing: No init found
  • 检查 bootargsinit= 是否正确(/linuxrc vs /sbin/init
  • 检查 linuxrc/busybox 是否可执行
  • 最常见原因 :动态库不全或 loader 缺失(ld-linux-aarch64.so.1
  1. I have no name!@rk3568:/#
  • 缺少 /etc/passwd/etc/group
  1. 服务提示 Permission denied
  • 打包没用 sudo,属主不对
  • 修复:sudo chown -R root:root _install 后重新打包
  1. 串口乱码
  • 再次确认波特率是否为 1500000,以及 USB 转串口芯片/驱动是否支持

7. 总结

  1. 方案选择
  • 极致轻量、深度定制:BusyBox
  • 快速集成、标准化构建:Buildroot
  1. RK3568 移植核心要点
  • bootargs 必须正确:console=root=rootfstype=、(建议)rootwait
  • /proc /sys /tmp 挂载正确
  • 动态库必须匹配工具链,并确保动态链接器存在(AArch64 常见 ld-linux-aarch64.so.1
  • 建议准备 /dev/console /dev/null "保命节点"

核心宗旨:根据硬件资源、项目需求、开发周期,在"体积 / 功能 / 开发效率"间找到平衡。


参考资料

相关推荐
开开心心_Every2 小时前
局域网大文件传输,设密码双向共享易用工具
运维·服务器·网络·游戏·pdf·电脑·excel
阿猿收手吧!2 小时前
【Linux/C++】线程切换与协程切换,协程池
linux·c++
qq_24218863322 小时前
分享Xshell在服务器管理中的高级技巧与自动化脚本案例
运维·服务器·自动化
知识分享小能手2 小时前
SQL Server 2019入门学习教程,从入门到精通,SQL Server 2019 存储过程与自定义函数 — 语法知识点及使用方法详解(15)
数据库·学习·sqlserver
强子感冒了2 小时前
Javascript学习笔记:BOM和DOM
javascript·笔记·学习
袁袁袁袁满2 小时前
Linux网络连接之ss命令详细使用指南(从入门到运维实战)
linux·运维·服务器·网络·ssh·网络连接·ss命令
2501_901147833 小时前
学习笔记|LeetCode 739 每日温度:从暴力枚举到单调栈线性最优解
笔记·学习·leetcode
爱编程的Zion3 小时前
小白AI学习笔记---第一章,如何正确使用
人工智能·笔记·学习
Gary Studio3 小时前
rtos入门问题
学习