达永编程网

程序员技术分享与交流平台

initramfs编译到内核似乎没运行,都怪自己没看官方教程

现象

Kernel挂载自定义的文件系统后似乎没有任何提示,不知文件系统制作是否成功。

背景

Linux的根文件系统调试方式有很多种,uboot传递相应参数告知从Kernel从哪里挂载根文件系统: MTD、硬盘、NFS、SD卡、initramfs。这里我选择的是initramfs的方式挂载,目的是尽可能 排除其他环境因素影响文件系统测试,包括:NFS root没有执行权限;uboot的NAND纠错算法(ECC)和 Kernel的不一致导致MTD数据载入错误。

initramfs是直接和Kernel绑定在一起,同时解压到内存,踩坑的概率要小很多,保证文件系统 足够小、内存足够大,基本不会遇到问题。

之所以写这篇文章是没仔细读取Kernel官方文档:
Documentation/filesystems/ramfs-rootfs-initramfs.rst。

1. 制作方式

上文说了initramfs要保证文件系统足够小、内存足够大。没有什么比一句话代码的容量更小。 万能的儿童版Hello world教程,这个例位于linux源码 Documentation 目录下,注意后面的休眠2秒,

为什么休眠2秒,这里先埋个包袱

源码最好静态编译,避免遗漏拷贝 .so 影响测试。

配置内核填入initramfs的根目录

uboot传递启动参数:setenv bootargs ‘console=ttyAM0,115200n8 rdinit=/sbin/init’

Kernel的ramdisk_execute_command字符串接受这个参数,rdinit是initramfs执行的第一个程序位置, 进程的PID是1。

console这么传递请参考上一篇文章《uboot传递console究竟怎么填?ttyX傻傻分不清》。

Kernel最后加载文件系统阶段首先检查是否存在rdinit所指的文件,不存在则从其他媒介设备 挂载文件系统。从Kernel角度来说,无论是rdinit和其他媒介设备的文件系统内核都同等对待, 只是找到谁就执行谁而已。

相关源码位于init/main.c

走你,咦!内核启动结束后没看到期待的 “Hello world”

2. 提出排查方向

起初怀疑3个方向:

  • 文件没有找到
  • 文件找到了,却没执行权限
  • 文件找到了,也执行了,但没找到stdout

3. 排除设想1、2

从输出结果怀疑方向,首先最先排除的是“设想1”,肯定是找到/sbin/init,否则不会出现倒数第二行 “CPU 0执行的init进程PID 1 退出”,没执行哪来的退出,于是排除“设想2”。

验证方案也很简单,删除/work/ramfs/sbin/init再测试一次。

输出内容有明显差异,输出意思:rdinit所指文件不存在,尝试从其他媒体设备挂载文件系统,而其他媒体 设备位置却没有传递,请纠正 “root=” 参数。

5. 确认设想3

回头看 Warning: unable to open an initial console。某个console没有打开?会不会是 “设想3”的stdout呢?

该字符串出现在源码 init/main.c。尝试打开/dev/console作为标准输入/输出/错误,节点的信息照抄 本地PC的 “ls -l /dev/console”。照葫芦画瓢创建节点。

sudo mknod -m 622 console c 5 1

再次上电测试成功看到 “Hello world”

为什么延时2秒

延时2秒是为了看效果,系统正常运行时是不允许PID 1退出,它很特殊起到脱孤进程的作用,一旦退出系统认为出大事咯,立即打印出堆栈信息,并停止运行。

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言