现在的位置: 首页 > 综合 > 正文

开发板实务(5)——构建根文件系统

2018年01月23日 ⁄ 综合 ⁄ 共 2337字 ⁄ 字号 评论关闭

自己做一个根文件系统(initrd). 先下载到ram中看运行是否正确, 再烧到板子的flash中去. 简单起见,
使用BusyBox和Scratchbox来进行.

BusyBox : 用来提供/bin, /sbin, /usr/bin,
/usr/sbin目录中的命令以及系统的初始化init.

Scratchbox: 用来提供编译BusyBox的交叉编译工具, 以及glibc,
uClibc库.

根文件系统的内容


一般来说, 根文件系统的结构, 目录安排应该遵循FHS的规定. 但板子的根文件系统里也有些许例外,
比如/module, jffs2, cramfs都是位于根目录中. 为了简便, 我不从头建立目录, 拷贝文件...
而是直接在板子既有的根文件系统上进行更改.

准备工作


把手头原先的根文件系统镜像文件备份, 解压缩, 挂载, 将其中所有的内容拷贝到一个工作目录中. 完成对它们的修改后, 新建一个initrd,
将文件系统放到该initrd中. ramdisk, initrd的介绍及如何制作可参考Embedded
Linux常见文件系统介绍
.

可执行文件: bin, sbin


用户命令, 系统管理员命令都位于这些目录中. 这三个目录完全不需要自己建立, 用BusyBox来. 配置, 编译BusyBox参考本blog中的BusyBox——嵌入式Linux中的瑞士军刀

编译, 安装好BusyBox之后,
在_install目录中会出现bin, sbin, usr三个目录和linuxrc文件. 现在把bin,
sbin目录的内容拷贝到ramdisk文件系统中去:

$ cd
bin

$ sudo rm -r *
$ sudo cp -aR ~<busybox>/bin/* .

将bin, sbin中原先的文件全部删除,
替换成busybox相应目录中的文件.

系统初始化: /linuxrc,
/etc/init.d/rcS


这个文件很重要, 是成功制作能够启动的initrd之关键. /linuxrc在ramdisk被挂在为rootfs后执行. /linuxrc本身可以是可执行文件,
shell脚本, 也可以是指向可执行文件的符号链接. (在内核文档Documentation/initrd.txt中,
介绍了initrd的启动).

Linux使用initrd作为rootfs时, 启动顺序是这样的:

1,
bootloader加载内核, 内核将initrd解压到ram中成为ramdisk.
2, ramdisk被挂在为rootfs,
并执行/linuxrc.

实际上, 在内核挂载ramdisk之后, 它会查找init文件来执行.如果没有找到init文件,
内核就会调用linuxrc文件作为自己的启动脚本.

如果是一般的桌面或服务器Linux系统,
往往还要挂载"真正的"rootfs, 然后执行/sbin/init程序, 卸载initrd. 但在嵌入式系统中,
initrd是作为贯穿始终的rootfs来用的, 并不需要挂载其他的根文件系统.

传统的桌面, 服务器Linux往往使用System V
init来完成系统的初始化. 在嵌入式Linux系统中, 可以使用BusyBox init.

BusyBox
init的init进程将进行下列工作:
1, 为init设置信号处理进程.
2, 初始化控制台.
3, 读取/etc/inittab.
执行系统初始化命令.
4, 若/etc/inittab不存在, 则执行/etc/init.d/rcS中的命令.

BusyBox
init不支持System V init中的runlevel(嵌入式Linux系统一般都是单用户). 所以一般不使用/etc/inittab,
而是将初始化时想要执行的命令放到/etc/init.d/rcS脚本中.

关于BusyBox的init命令,
可参考http://www.busybox.net/downloads/BusyBox.html

这样就清楚该如何组织启动脚本了:
使用BusyBox提供的init.
1, 将/linuxrc作为一个指向busybox程序的符号链接.(BusyBox安装后就是这样)
2,
将启动脚本放到/etc/init.d/rcS中.

其实完全可以不需要/linuxrc, 因为/sbin/init所在的文件系统已经被挂载上了, 内核先执行init, 如果找不到init,
才执行/linuxrc!

测试
完成了上面2步之后, 已经可以测试修改后的根文件系统是否可用了.
因为担心共享库版本问题, 我这里先将BusyBox编译成与uClibc的静态链接. 做成ramdisk.image.gz下载到ram中, 运行成功.

随后,
我将busybox替换成和glibc动态链接的, 然后下载到ram中, 运行, 结果出现这样的错误:  Kernel panic: Attempted to kill
init!

我将板子/lib目录中的所有文件删除,
将scratchbox中/compilers/arm-linux-gcc3.4.cs-glibc2.3/lib中的库文件拷贝到原先的/lib目录中.
然后就可以了.

这难道是因为glibc版本的问题么?

看看与glibc动态链接的busybox需要哪些库:
$ arm-linux-readelf -a busybox | grep "Shared
library"

 0x00000001
(NEEDED)                     Shared library:
[libc.so.6]

而libc.so.6实际上是指向主修订版的符号链接: libc.so.6 ->
libc-2.3.2.so.
到这里, 我只能理解成libc的版本不同导致init程序无法运行了: 板子上原先的libc库是2.2.2版的,
而我用来替换的busybox却是与2.3.2版动态链接的.

to do:

使用Buildroot工具构建根文件系统

抱歉!评论已关闭.