当前位置: 首页 > news >正文

[IMX][UBoot] 17.Linux 根文件系统

目录

1.BusyBox 简介

2.修改 Makefile

3.添加中文支持

4.配置 BusyBox

5.编译 BusyBox

6.添加库文件

6.1.向 /lib 目录添加库文件

6.2.向 /usr/lib 目录添加库文件

7.创建其他目录

8.根文件系统测试

9.添加启动脚本

10.添加文件系统脚本

11.添加配置脚本

12.库文件测试

13.开机自启动测试

14.添加域名解析配置


Linux 中所有目录、文件、驱动等均被组织成一个树状结构,根文件系统 rootfs 就是该文件树的根节点

根文件系统包含了操作系统运行所需的基本组件和数据 (包含驱动、库文件等),位于 Linux 的根目录 / 下

根文件系统是内核启动时挂载的第一个文件系统,系统引导程序会在根文件系统挂载后,将其中的基础服务、脚本等加载至内存中运行,根文件系统一般包含以下部分:

  • 核心组件:构建根文件系统所需的软件包、系统库、编译器、Shell 等,提供基本的系统功能,如文件管理、网络访问、进程管理、设备管理等;

  • 标准目录结构:符合 Linux 标准文件系统层次结构规范的目录结构,包括 /bin、/sbin、/usr、/etc、/proc 等目录,用于存放系统关键部件的信息、配置、库和命令;

  • 设备驱动:各种硬件的驱动程序和内核模块,如串口驱动、网卡驱动等,使 Linux 能够正确地访问硬件设备;

  • 网络工具和协议:如 SSH、FTP、HTTP、DHCP 等,提供连接其他网络设备、数据交换和网络管理的能力;

  • 调试工具:如 gdb、strace、top 等,帮助定位和解决系统中的各种问题和异常;

根目录 / 中包含以下子目录:

其中常用目录的含义如下:

  • /bin:可执行文件,如 ls 、cd 等命令,所有用户均可使用;

  • /dev:设备文件,如 /dev/ttymxc0 表示串口 0,通过串口 0 收发数据就是读写文件 /dev/ttymxc0;

  • /etc:配置文件,如 SSH 的配置文件 init.d、MySQL 的配置文件 my.cnf 等;

  • /lib:共享库文件,一些命令和用户编写的程序会使用这些库;

  • /mnt:临时挂载目录,可创建空的子目录,如 /mnt/sd、/mnt/usb 等,用于管理挂载的 SD卡、U 盘等设备;

  • /proc:系统启动后将该目录作为 proc 文件系统 (虚拟文件系统) 的挂载点,无实际存储,一般保存系统运行信息相关的临时文件;

  • /usr:软件资源,存放软件;

  • /var:存放一些可改变的数据;

  • /sbin:可执行文件,该目录下的文件或命令只有管理员能使用,主要用于系统管理;

  • /sys:系统启动后作为 sysfs 文件系统的挂载点,sysfs 是一个类似 proc 文件系统的特殊文件系统,sysfs 是基于 ram 的文件系统,没有实际的存储设备,该目录是系统设备管理的重要目录,其通过一定的组织结构向用户提供详细的内核数据结构信息;

  • /opt:可选的文件、软件存放区,由用户选择将哪些文件或软件放到该目录中;

1.BusyBox 简介

BusyBox 是一个集成了大量 Linux 命令和工具的软件,使用该软件可以制作基础的根文件系统

BusyBox 的官网为:BusyBox

点击 Download Source 进入下载页面,在该页面中点击所需的版本开始下载:

Linux 驱动开发一般通过 NFS 挂载文件系统,在虚拟机的 NFS 服务器目录中新建 /rootfs 目录:

2.修改 Makefile

修改 BusyBox 的 Makefile,设置目标架构 ARCH 和交叉编译器 CROSS_COMPILE:

// busybox-1.29.0/Makefile
CROSS_COMPILE ?= arm-linux-gnueabihf-
ARCH ?= arm

3.添加中文支持

BusyBox 默认不支持中文,因此会导致串口中文字符输出为 ?,修改源码取消中文限制:

// busybox-1.29.0/libbb/printable_string.c
const char* FAST_FUNC printable_string(uni_stat_t *stats, const char *str)
{...while (1) {...// 注释下面两行,避免字符编码大于 0x7F 时跳出// if (c >= 0x7f)//     break;...}...#else{...while (1) {...// 修改判断条件,避免字符编码大于 0x7F 时跳出// if (c < ' ' || c >= 0x7f)if( c < ' ')
----------------------------------------------------------------------------------// /home/alientek/mx/busybox-1.29.0/libbb/unicode.c
static char* FAST_FUNC unicode_conv_to_printable2(uni_stat_t *stats, const char *src, unsigned width, int flags)
{...if (unicode_status != UNICODE_ON) {...if (flags & UNI_FLAG_PAD) {...while ((int)--width >= 0) {...// 修改判断条件,避免字符编码大于 0x7F 时将字符设置为 ?// *d++ = (c >= ' ' && c < 0x7f) ? c : '?';*d++ = (c >= ' ') ? c : '?';...} else {...while (*d) {...// 修改判断条件,避免字符编码大于 0x7F 时将字符设置为 ?// if (c < ' ' || c >= 0x7f)if (c < ' ')

以上修改的主要目的是,防止字符编码大于 0x7F 时将字符设置为 ?

4.配置 BusyBox

BusyBox 可以使用以下三种配置:

  • defconfig:默认配置;

  • allyesconfig:全选配置,编译全部功能;

  • allnoconfig:最小配置,仅编译必备的功能模块;

一般使用默认配置,使用以下命令编译配置文件:

make defconfig

BusyBox 支持图形化配置,使用以下命令打开图形化配置界面:

make menuconfig

通过图形化配置使能动态编译,配置路径如下:

Settings--> Build static binary (no shared libs)

该选项控制静态编译还是动态编译,静态编译不需要库文件,但是生成的文件较大,动态编译需要库文件支持,但是编译出来的文件较小,这里禁用静态编译 (会导致 DNS 出问题):

选择 VI 风格的编辑命令,配置路径如下:

Settings--> vi-style line editing commands

不使用简化的模块,配置路径如下:

Linux Module Utilities--> Simplified modutils

支持模块化编译 (选中所有支持选项),配置路径如下:

Linux System Utilities--> mdev (16 kb)

使能 unicode 编码以支持中文,配置路径如下:

Settings--> Support Unicode--> Check $LC_ALL, $LC_CTYPE and $LANG environment variables

5.编译 BusyBox

配置完成后编译 BusyBox,指定编译结果存放的目录为之前新建的 /rootfs 目录,编译命令如下:

makemake install CONFIG_PREFIX=/home/alientek/linux/nfs/rootfs

编译完成后会在该目录中生成 /bin、/sbin、/usr 三个目录以及 linuxrc 文件:

Linux 的 init 进程会查找用户空间的 init 程序,通过运行该程序切换至用户态,bootargs 可以将 linuxrc 作为用户空间的 init 程序,因此,用户空间的 init 程序实际上由 BusyBox 生成

6.添加库文件

Linux 中的应用程序可以使用静态库或动态库,静态库会直接链接至应用程序中,因此生成的程序体积较大,而依赖动态库的程序占用空间较小,但是无法独立运行,Linux 中的大部分系统程序或工具均依赖于动态库,因此在制作完根文件系统后,需要在指定目录中添加动态库文件

6.1.向 /lib 目录添加库文件

在 /rootfs 中创建 /lib 目录:

mkdir lib

库文件从交叉编译器中获取,进入交叉编译器所在的目录:

cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib

该目录存放动态库文件和静态库文件:

使用以下命令将这些库文件拷贝至 /rootfs 的 /lib 目录中:

cp *so* *.a /home/alientek/linux/nfs/rootfs//lib/ -d

其中 -d 选项表示需要拷贝符号链接,/lib 目录中的 ld-linux-armhf.so.3 为软链接,链接至 ld-2.19-2014.08-1-git.so,因此,ld-linux-armhf.so.3 为符号链接,而非实际的文件

ld-linux-armhf.so.3 不能作为符号链接存在,而是需要实际文件,因此,先删除 /rootfs/lib 中的 ld-linux-armhf.so.3:

rm ld-linux-armhf.so.3

然后进入 /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib 目录中,重新拷贝 ld-linux-armhf.so.3:

cp ld-linux-armhf.so.3 /home/alientek/linux/nfs/rootfs/lib/

可以看到,拷贝完成后的 ld-linux-armhf.so.3 不再是一个软链接,而是一个实际的文件:

进入以下目录:

cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/lib

将该目录中的库文件拷贝至 /rootfs/lib 中:

cp *so* *.a /home/alientek/linux/nfs/rootfs/lib/ -d

6.2.向 /usr/lib 目录添加库文件

在 /rootfs/usr 中新建 /lib 目录,然后进入以下目录:

cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/lib

将该目录中的库文件拷贝至新建的 /rootfs/usr/lib 目录中:

cp *so* *.a /home/alientek/linux/nfs/rootfs/usr/lib/ -d

至此所有的库文件添加完成

7.创建其他目录

在 /rootfs 中创建其他目录,如 /dev、/proc、/mnt、/sys、/tmp、/root 等,创建完成后 /rootfs 包含以下目录:

8.根文件系统测试

通过 NFS 挂载制作好的根文件系统,测试能否正常运行

uboot 中的 bootargs 环境变量会设置参数 root 的值,因此需要将参数 root 的值改为 NFS 挂载,格式如下:

root=/dev/nfs nfsroot=[<server-ip>:]<root-dir>[,<nfs-options>] ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>:<dns0-ip>:<dns1-ip>
  • server-ip:服务器 IP 地址,存放 rootfs 主机的 IP 地址,虚拟机的 IP 地址为 172.17.40.88;

  • root-dir:存放根文件系统的路径,虚拟机中 rootfs 的存放路径为 /home/alientek/linux/nfs/rootfs;

  • nfs-options:其他 NFS 选项,一般不设置;

  • client-ip:客户端的 IP 地址,即开发板的 IP 地址,开发板上的 Linux 系统启动后使用该 IP 地址,需要保证和 PC 位于同一网段内,开发板的 IP 地址设置为 172.17.40.10;

  • gw-ip:客户端的网关地址,开发板的网关地址设置为 172.17.40.1;

  • netmask:客户端的子网掩码,开发板的子网掩码设置为 255.255.255.0;

  • hostname:主机名称,一般不设置;

  • device:网卡名称,一般为 eth0、eth1 等,正点原子的开发板使用 ENET2 网卡,名称为 eth0;

  • autoconf:自动配置,一般不使用 (将值设置为 off);

  • dns0-ip:DNS0 服务器的 IP 地址,不使用;

  • dns1-ip:DNS1 服务器的 IP 地址,不使用;

根据以上配置,将环境变量 bootargs 中参数 root 的值设置为:

root=/dev/nfs nfsroot=172.17.40.88:/home/alientek/linux/nfs/rootfs,proto=tcp rw ip=172.17.40.10:172.17.40.88:172.17.40.1:255.255.255.0::eth0:off
  • proto=tcp 表示使用 TCP 协议;

  • rw 表示 NFS 挂载的根文件系统可读可写;

重启开发板后进入 uboot 命令行模式,设置环境变量 bootargs 的值:

setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=172.17.40.88:/home/alientek/linux/nfs/rootfs,proto=tcp rw ip=172.17.40.10:172.17.40.88:172.17.40.1:255.255.255.0::eth0:off::'saveenv

设置完成后,使用 boot 命令启动 Linux 内核,检查根文件系统是否成功挂载:

从图中可以看出,根文件系统已成功挂载,提示缺少 /etc/init.d/rcS 启动脚本

9.添加启动脚本

rcS 是一个 Bash Shell 脚本,系统启动时调用该脚本设置环境变量、挂载文件系统、启动基本服务等

在 /rootfs 中新建 /etc/init.d/rcS,启动脚本的内容如下:

#!/bin/shPATH=/sbin:/bin:/usr/sbin:/usr/bin:$PATH
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib:/usr/lib
export PATH LD_LIBRARY_PATHmount -a
mkdir /dev/pts
mount -t devpts devpts /dev/ptsecho /sbin/mdev > /proc/sys/kernel/hotplug 
mdev -s
  • 环境变量 PATH 保存可能存在可执行文件的目录;

  • 环境变量 LD_LIBRARY_PATH 保存库文件所在目录;

  • 通过 export 将环境变量 PATHLD_LIBRARY_PATH 导出为全局变量;

  • mount -a 挂载所有的系统文件,这些文件由 /etc/fstab 脚本指定;

  • mkdir /dev/pts 创建 /dev/pts 目录;

  • mount -t devpts devpts /dev/pts 将伪终端设备 devpts 挂载至 /dev/pts 目录;

  • 最后两行命令设置使用 mdev 管理热插拔设备,Linux 会在 /dev 目录中自动创建设备节点;

以上为精简的启动脚本,复杂的启动脚本依靠 BuildRoot 制作

使用以下命令为启动脚本赋予可执行权限:

chmod +x rcS

10.添加文件系统脚本

/etc/fstab 脚本用于存放文件系统的相关信息,Linux 启动时通过该脚本获取需要自动挂载的分区,其格式如下:

<file system> <mount point> <type> <options> <dump> <pass>
  • file system:要挂载的特殊设备,可以是块设备,如 /dev/sda 等;

  • mount point:挂载点;

  • type:文件系统类型,如 ext2、ext3、proc、romfs、tmpfs 等;

  • options:挂载选项,一般使用默认选项 defaults (包含 rw、suid、 dev、 exec、 auto、 nouser、async);

  • dump:是否允许备份,一般设置为 0,表示不允许备份;

  • pass:是否进行磁盘检查,一般不在 fstab 中挂载根目录,因此设置为 0;

按照以上配置,脚本 fstab 中的内容如下:

# <file system> <mount point> <type> <options> <dump> <pass>
proc  /proc proc  defaults 0 0
tmpfs /tmp  tmpfs defaults 0 0
sysfs /sys  sysfs defaults 0 0

11.添加配置脚本

/etc/inittab 脚本用于初始化系统设置,其中定义了系统启动时的运行级别、系统初始化过程、控制台进程及电源故障处理等,系统管理员可以控制系统启动流程、切换运行级别、自定义服务的启动和停止等,init 程序会读取该文件,并设置各个程序的运行级别或执行相应的操作,该文件内容的格式如下:

<id>:<runlevels>:<action>:<process>
  • id:指令标识符,不能重复,BusyBox 根据 ID 指定启动进程的控制台,一般将串口或 LCD 设置为控制台 tty;

  • runlevels:运行等级;

  • action:指定 process 可能执行的操作,BusyBox 支持的操作如下:

  • process:具体的操作,如运行程序、执行脚本等;

参考 BusyBox 的 /examples/inittab 文件,创建 /etc/inittab 脚本,其内容如下:

#etc/inittab
::sysinit:/etc/init.d/rcS
console::askfirst:-/bin/sh
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::shutdown:/sbin/swapoff -a
  • ::sysinit:/etc/init.d/rcS 指定系统启动后运行 rcS 脚本;

  • console::askfirst:-/bin/sh 将 console (ttymxc0) 作为终端控制台;

  • ::restart:/sbin/init 指定重启时运行 /sbin/init;

  • ::ctrlaltdel:/sbin/reboot 指定按下 ctrl+alt+del 组合键时运行 /sbin/reboot 重启系统;

  • ::shutdown:/bin/umount -a -r 指定关机时运行 /bin/umount 卸载各个文件系统;

  • ::shutdown:/sbin/swapoff -a 指定关机时运行 /sbin/swapoff 禁用交换分区 swap;

至此 Linux 系统必备的相关脚本准备完成,重启开发板检查是否可以正常运行

12.库文件测试

程序编译时一般使用动态库,在之前的操作中已经将相关库文件添加至 rootfs 中,使用以下程序测试库文件是否可以正常工作,在 rootfs 中创建 /drivers 目录并在其中新建 hello.c 文件,内容如下:

#include <stdio.h>int main(void)
{while(1) {printf("Hello World!\r\n");sleep(2);}return 0;
}

使用以下命令编译该程序:

arm-linux-gnueabihf-gcc hello.c -o hello

在开发板上执行该程序,输出结果如下图所示:

程序运行正常,表示添加的库文件没有问题,也可以使用以下命令让 hello 程序在后台运行:

./hello &

这样在 hello 程序运行时,终端仍然可以使用,关闭程序时需要使用 ps -a 查询对应的 PID,然后通过 kill -9 PID 终止程序的运行:

13.开机自启动测试

在 /etc/init.d/rcS 脚本的末尾添加命令,实现开机时自动运行 hello 程序:

#!/bin/shPATH=/sbin:/bin:/usr/sbin:/usr/bin:$PATH
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib:/usr/lib
export PATH LD_LIBRARY_PATHmount -a
mkdir /dev/pts
mount -t devpts devpts /dev/ptsecho /sbin/mdev > /proc/sys/kernel/hotplug 
mdev -scd /drivers
./hello &
cd /

14.添加域名解析配置

在 rootfs 中新建文件 /etc/resolv.conf,其中的内容设置为:

nameserver 114.114.114.114 
nameserver 172.17.40.1

nameserver 表示域名服务器,上面的代码设置了两个域名服务器

使用 udhcpc 命令自动获取域名服务器时,会自动修改 nameserver 的值

http://www.lryc.cn/news/597452.html

相关文章:

  • Elasticsearch Circuit Breaker 全面解析与最佳实践
  • MCU驱动AD5231BRUZ_10K
  • 【Elasticsearch】跨集群检索(Cross-Cluster Search)
  • 83、设置有人DTU设备USR-M100采集传感器数据,然后上传阿里云服务
  • now能减少mysql的压力吗
  • 旅游管理虚拟仿真实训室:重构实践教学新生态
  • 【数据库】国产数据库的新机遇:电科金仓以融合技术同步全球竞争
  • 云蝠智能 Voice Agent:重构企业语音交互,引领 AI 服务新范式
  • QGraphicsScene导出为PDF
  • SQL Server 数据类型的含义、特点及常见使用场景的详细说明
  • 【轨物洞见】光伏逆变器数据:分布式电站价值回归的“第一块多米诺骨牌”
  • Pycharm2025 安装教程 免费分享 没任何套路
  • PyCharm高效进阶指南:掌握专业开发技巧与最佳实践
  • Spring DeferredResult 实现长轮询
  • [HarmonyOS] HarmonyOS LiteOS-A 设备开发全流程指南
  • 清华大学层次化空间记忆助力具身导航!Mem4Nav:基于层次化空间认知长短期记忆系统的城市环境视觉语言导航
  • 本地部署 Stable Diffusion:零基础搭建 AI文生图模型
  • 仓颉兴趣组优秀项目-Ginger
  • CPU,减少晶体管翻转次数的编码
  • opencv学习(视频读取)
  • 策略模式(Strategy Pattern)+ 模板方法模式(Template Method Pattern)的组合使用
  • AR维修辅助系统UI设计:虚实融合界面中的故障标注与操作引导
  • 设计模式(单例)
  • ar景区导航导览开发方案:核心技术架构与功能设计
  • HarmonyOS学习记录5
  • 第三章.Redis渐进式遍历
  • 计算机毕设分享-基于SpringBoot的房屋租赁系统(开题报告+源码+Lun文+开发文档+数据库设计文档)
  • 神经架构搜索革命:从动态搜索到高性能LLM的蜕变之路
  • Spark实现WorldCount执行流程图
  • 05-ES6