关闭

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

716人阅读 评论(0) 收藏 举报

自己做一个根文件系统(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工具构建根文件系统

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:417180次
    • 积分:5551
    • 等级:
    • 排名:第5110名
    • 原创:38篇
    • 转载:318篇
    • 译文:0篇
    • 评论:11条
    最新评论