嵌入式 linux 根文件系统原理和制作方法
扫描二维码
随时随地手机看文章
关注、星标嵌入式云IOT技术圈,精彩及时送达
来源 | Github-EmbeddedSystem
1. 根文件系统原理
1.1 为什么需要根文件系统
- init进程的应用程序在根文件系统上
- 根文件系统提供了根目录 /
- 内核启动后的应用层配置( etc 目录)在根文件系统上。几乎可以认为:发行版=内核 rootfs
- shell命令程序在根文件系统上,比如 ls、cd 等命令
1.2 根文件系统的实质
- 根文件系统是特殊用途的文件系统。
- 根文件系统也必须属于某种文件系统格式。rootfstype=
1.3 根文件系统的形式
- 使用专用工具软件制作的可供烧录的镜像文件
- 镜像中包含了根文件系统中的所有文件
- 烧录此镜像类似于对相应分区格式化。
- 镜像文件系统具有一定的格式,格式是内化的,跟文件名后缀是无关的。
- 根文件系统其实就是一个包含特定内容的文件夹
- 根文件系统可由任何一个空文件夹添加必要文件构成而成
- 根文件系统的雏形就是在开发主机中构造的文件夹形式的
1.4 自己制作简单的根文件系统
1.4.1 动手制作ext3格式的根文件系统
- mke2fs介绍
- 创建rootfs.ext2文件并且将之挂载到一个目录下方便访问它 《参考资料:http://blog.csdn.net/zhengmeifu/article/details/24174513》
dd if=/dev/zero of=rootfs.ext2 bs=1024 count=2048
losetup /dev/loop1 rootfs.ext2
mke2fs -m 0 /dev/loop1 2048
mount -t ext2 /dev/loop1 ./rootfs/
- 我们向镜像中写入一个普通文件linuxrc。这个文件就会成为我们制作的镜像中的/linuxrc。内核挂载了这个镜像后就会尝试去执行/linuxrc。然后执行时必然会失败。我们将来实验看到的现象就应该是:挂载成功,执行/linuxrc失败。
- 将来真正去做有用的rootfs时,就要在这一步添加真正可以执行的 linuxrc 程序,然后还要添加别的 /lib 目录下的库文件,/etc目录下的配置文件等。
- 卸载掉,然后镜像就做好了。
umount /dev/loop1
losetup -d /dev/loop1
1.4.2 nfs 方式启动 rootfs
- 什么是 nfs?
- 搭建nfs服务器
- 总结
- uboot 中的启动参数设置
setenv bootargs root=/dev/nfs nfsroot=192.168.1.104:/home/SummerGift/work/samsung_kernel/rootfs/rootfs ip=192.168.1.88:192.168.1.104:192.168.1.1:255.255.255.0::eth0:off init=/linuxrc console=ttySAC2,115200
- 测试 nfs 挂载
mount -t nfs -o nolock 192.168.1.104:/home/SummerGift/work/samsung_kernel/rootfs/rootfs /opt
1.4.3 关于 linuxrc
- /linuxrc 是一个可执行的应用程序 /linuxrc 是应用层的,和内核源码一点关系都没有,/linuxrc 在开发板当前内核系统下是可执行的。因此在 ARM SoC 的 linux 系统下,这个应用程序就是用 arm-linux-gcc 编译链接的;如果是在 PC 机 linux 系统下,那么这个程序就是用 gcc 编译连接的。
- /linuxrc执行时引出用户界面 操作系统启动后在一系列的自己运行配置之后,最终会给用户一个操作界面(也许是 cmdline,也许是 GUI),这个用户操作界面就是由 /linuxrc 带出来的。
- /linuxrc 负责系统启动后的配置 就好像一个房子建好之后不能直接住,还要装修一样;操作系统启动起来后也不能直接用,要配置下。操作系统启动后的应用层的配置(一般叫运行时配置,英文简写 etc)是为了让我们的操作系统用起来更方便,更适合我个人的爱好或者实用性。
- /linuxrc在嵌入式linux中一般就是busybox busybox 是一个 C 语言写出来的项目,里面包含了很多 .c 文件和 .h 文件。这个项目可以被配置编译成各个平台下面可以运行的应用程序。我们如果用 arm-linux-gcc 来编译busybox就会得到一个可以在我们开发板 linux 内核上运行的应用程序。
1.4.4 rootfs 中的其他目录
- /linuxrc
- dev目录下的设备文件
- sys和proc目录
- usr是系统的用户所有的一些文件的存放地,这个东西将来 busybox 安装时会自动生成。
- etc 目录中的所有文件全部都是运行时配置文件。/etc 目录下的所有配置文件会直接或者间接的被 /linuxrc 所调用执行,完成操作系统的运行时配置。etc 目录是制作 rootfs 的关键,所以后面下一个课程专门讲这个 etc 目录。
- lib 目录也是 rootfs 中很关键的一个,不能省略的一个。lib目录下放的是当前操作系统中的动态和静态链接库文件。我们主要是为了其中的动态链接库。
2. 用 busybox 制作一个简单的 rootfs
2.1 移植 busybox 到开发板
- busybox源码下载
- 修改Makefile
ARCH = arm
CROSS_COMPILE = /usr/local/arm/arm-2009q3/bin//arm-none-linux-gnueabi-
- make menuconfig 进行配置
Busybox Settings--->
Build Options--->
[*]Build BusyBox as a static binary(no shared libs)
Busybox Library Tuning--->
[*]vi-style line editing commands
[*]Fancy shell prompts
Linux Module Utilities--->
[ ]Simplified modutils
[*]insmod
[*]rmmod
[*]lsmod
[*]modprobe
[*]depmod
Linux System Utilities--->[*]mdev
[*]Support /etc/mdev.conf
[*]Support subdirs/symlinks
[*]Support regular expressions substitutions when renaming dev
[*]Support command execution at device addition/removal
[*]Support loading of firmwares
- make 然后 make install
- 设置 bootargs 挂载添加了busybox移植的rootfs
setenv bootargs root=/dev/nfs nfsroot=192.168.1.141:/root/porting_x210/rootfs ip=192.168.1.10:192.168.1.141:192.168.1.1:255.255.255.0::eth0:off init=/linuxrc console=ttySAC2,115200
挂载成功,执行 /linuxrc(也就是busybox)成功,但是因为找不到 /etc/init.d/rcS 和 /dev/tty2 等文件所以一直在打印错误提示信息,但是其实有进入命令行。2.2 inittab 详解
- 添加一个典型的inittab
- inittab格式解析
- 常见的配置项
3. busybox 源码分析
3.1 分析 busybox 启动状况
分析一个程序,不管多庞大还是小,最好的路线都是按照程序运行时的逻辑顺序来。所以找到一个程序的入口至关重要。主函数main函数就是整个程序的入口,这种情况适应于操作系统下工作的应用程序的情况。在 uboot 和 linux kernel 这两个大的 C 语言的项目中,main函数都没有,都不是入口。在我们这种裸机程序中入口不是 main 函数,而是由连接脚本来指定的。busybox 是 linux 启动起来后工作的一个应用程序,因此其中必然有 main 函数,而且 main 就是入口。3.2 busybox 中 main 函数全解析
busybox 入口就是 main 函数,其中有很多个 main 但是只有一个起作用了,其他的是没起作用的。真正的busybox工作时的入口是 libbb/appletlib.c 中的 main 函数。busybox中有很多 xxx_main 函数,这些 main 函数每一个都是 busybox 支持的一个命令的真正入口。例如 ls_main 函数就是 busybox 当作 ls 函数使用时的入口程序。ls 或者 cd 等命令其实都是 busybox 一个程序,但是实际执行时的效果却是各自的效果。busybox 每次执行时都是先执行其 main,在 main 函数中识别(靠 main 函数的传参 argv[0] 来识别)我们真正要执行的函数(譬如ls)然后去调用相应的xxx_main(譬如ls_main)来具体实现这个命令。3.3 inittab 解析与执行
inittab 的解析是在 busybox/init/init.c/init_main 函数中。执行逻辑是:先通过 parse_inittab 函数解析 /etc/inittab(解析的重点是将 inittab 中的各个 action 和 process 解析出来),然后后面先直接执行 sysinit 和 wait 和 once(注意这里只执行一遍),然后在 while(1) 死循环中去执行 respwan 和 askfirst。3.4 busybox 的体积优势原理
busybox 实际上就是把 ls、cd、mkdir 等很多个 linux 中常用的 shell 命令集成在一起了。集成在一起后有一个体积优势:就是 busybox 程序的大小比 busybox 中实现的那些命令的大小加起来要小很多。busybox 体积变小的原因主要有2个:- 第一个是 busybox 本身提供的 shell 命令是阉割版的(busybox 中的命令支持的参数选项比发行版中要少,譬如ls在发行版中可以有几十个 -x,但是在 busybox 中只保留了几个常用的选项,不常用的都删除掉了)
- 第二个是 busybox 中因为所有的命令的实现代码都在一个程序中实现,而各个命令中有很多代码函数都是通用的(譬如 ls 和 cd、mkdir 等命令都会需要去操作目录,因此在 busybox 中实现目录操作的函数就可以被这些命令共用),共用会降低重复代码出现的次数,从而减少总的代码量和体积。
4. rcS 文件分析与实战
4.1 rcS 文件介绍
/etc/init.d/rcS 文件是linux的运行时配置文件中最重要的一个,其他的一些配置都是由这个文件引出来的。这个文件可以很复杂也可以很简单,里面可以有很多的配置项。- PATH=xxx
- rcS 中为什么要先导出 PATH?
- runlevel=
- umask=
- mount -a
- mdev
- hostname
- ifconfig
4.2 rcS 文件测试问题记录
- PATH