Chinaunix首页 | 论坛 | 博客
  • 博客访问: 235963
  • 博文数量: 82
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2013-10-08 10:41
文章分类

全部博文(82)

文章存档

2017年(33)

2015年(13)

2014年(29)

2013年(7)

我的朋友

分类: LINUX

2015-03-06 10:53:35

精通initramfs构建step by step (十二):大结局 - 测试一下

三十五、测试一下
通过前十一节的内容,我们可以说已经完全掌握了initramfs构建的方法,那么现在就测试一下,拿一个实际的initramfs来分析,看我们是否能理解多少。
我们选择Debian 4.0 AMD64 版本的initramfs作为目标进行分析,它的initramfs文件是initrd.img-2.6.18-6-amd64。首先用cpio命令把initramfs文件解开,然后打开其中的init脚本文件具体分析。好了,大家利用前面各节的知识开始吧。

作为提示,在这里转载一篇文章,来自http://blog.chinaunix.net/u/12679/showart_429816.html

initrd执行顺序

这是安装过程中的笔记,放这里希望对大家有用。错误之处请指正。

(系统为debian etch, 以安装后默认的initrd.img-2.6.18-5为例)

解开initrd文件:
例如有initrd文件/boot/initrd.img, 用file命令看到这是个gzip压缩的文件,可以用下面的命令解开查看:


代码:
mkdir /boot/myinit
cd /boot/myinit
zcat ../initrd.img | cpio -id(注:用mkinitrd命令默认产生的是cramfs格式的。如果文件格式是压缩的ramfs文件系统,可以直接mount之后查看:mount -t cramfs /boot/initrd.img /mnt/)

如果是2.6内核,因为采用的是cpio压缩,方法如下:
cp /boot/initrd-***.img initrd.img.gz
gunzip initrd.img.gz
mkdir initrd
mv initrd.img initrd
cd initrd
cpio -mdiv < initrd.img


在当前目录下就有一些目录和文件init,其中文件init是启动时加载initrd之后执行的脚本。

目录结构:

/bin/: 文件有busybox, mknod, sh, uname, cat, mount, pivot_root等

--------/sbin/: 文件有modprobe, depmod, udevd, udevdtrigger

--------/lib/: 文件有:
----------------(1) 可执行文件需要的动态库
----------------(2) modules/: 内核模块
----------------(3) udev/: udev需要的可执行文件

--------/lib64/: 文件有:x86_64程序装载器

--------/etc/: 与modprobe, udev相关的配置文件

--------/conf/: 有如下的文件
----------------(1) modules: 列出了需要加载的模块
----------------(2) arch.conf: 设置变量DPKG_ARCH=amd64
----------------(3) initramfs.conf: 定义了一些变量

--------/scripts/:
----------------有如下的文件:
----------------functions: 定义了一些方便使用的函数
----------------local和nfs: mount根目录时执行的脚本,一般mount本地系统,执行local
----------------
----------------有如下的目录,其中放置各阶段执行的脚本:
----------------init_top/
----------------init_premount/
----------------init_bottom/
----------------local_top/
----------------local_premount/
----------------local_bottom/

--------/init: 启动时加载initrd之后执行的脚本


生成initrd文件:

find . |cpio -o --dereference -H newc | gzip -9 > ../initrd.img


init文件执行流程:

--------1) 创建目录/dev, /root, /sys, /proc, /tmp, /var/lock,其中/root是下面根文件系统要mount的位置

--------2) mount系统proc和sys

--------3) 执行脚本/etc/udev/udev.conf,仅定义变量

--------4) mount udev设备:mount -t tmpfs -o size= udev /dev

--------5) 创建/dev/console, /dev/null, /dev/.initramfs

--------6) 导入/conf目录下的initramfs.conf, /conf/conf.d/目录以及/scripts/functions定义的变量和函数, 并且根据传递的内核参数设置相应的变量,其中比较重要的变量有:
----------------a) rootdelay=<时间>, 加载根文件系统前等待的时间。如果根文件系统在U盘上,一定要在这里或在grub的kernel后加上这个参数,等待发现U盘后再mount根文件系统,否则会出现找不到根文件系统的错误.
----------------b) panic=<时间> 系统panic后,隔多长时间再reboot。当你试验新内核或新initrd,经常panic而不想按开机按钮时可以加上这个参数

--------7) depmod -a 在/lib/modules/<内核版本号>/目录下产生modules.dep文件

--------8) 执行init_top目录下的脚本文件。这里只有一个framebuffer,它处理内核参数video=,vga=,splash等参数, 另外创建节点/dev/tty[0-8]

--------9) 用modprobe按顺序加载/conf/modules列出的模块。注意,udev需要unix模块,否则会出现错误: udevd[606]: error initializing udev socket

--------10) 执行/scripts/init-premount/下的脚本文件。
-------------10.1) 文件thermal: 它根据DPKG_ARCH的不同值加载相应需要的模块,并且加载fan和thermal模块。
-------------10.2) 文件udev: 执行如下过程:
------------------------a) mkdir -p /dev/.udev/db
------------------------b) udevd --daemon 以daemon形式启动udevd,大概用于监视hotplug设备的插拔
------------------------c) mkdir -p /dev/.udev/queue/ (不知道这两个mkdir的用途)
------------------------d) udevtrigger 对于coldplug的设备,(也就是开机前插入的设备),触发设备的uevents,以便内核处理
------------------------e) udevsettle 等待,直到内核uevents事件处理完

--------11) 执行/scripts/local, 它完成mount根文件系统的过程:
----------------11.1) 首先执行local-top/目录下的脚本
------------------------11.1.1) 文件udev_helper:
----------------------------------a) 针对根文件系统设备(如通常的/dev/sda1, /dev/sda2等)不存在的情况,加载了模块ide_generic。我可以针对找不到硬盘的情况,加载模块aic94xx, sd_mod.
----------------11.2) 如果根文件系统设备还不存在,则年等待一段时间(默认180s),过了这段时间还找不到根文件系统设备就panic.
----------------11.3) 取得根文件系统的类型:先看有没有传递参数rootfstype=,如果没有就执行/bin/fstype,如果还不知道文件系统类型就执行/lib/udev/vol_id来取得文件系统类型。
----------------11.4) 执行local-premount/ 下的脚本:
-------------------------11.4.1) 文件resume: (没看太懂)
------------------------------a) 处理传递的resume参数,它指定的是一个分区,格式为resume=LABEL=/dev/sda1或resume=UUID=xxx, 用于suspend to disk
----------------11.5) 根据文件系统类型加载相应的模块,例如如果根文件系统是ext2类型的,就加载ext2(如果没编译进内核)。
----------------11.6)mount根文件系统到/root上
----------------11.7) 执行local-bottom/下的脚本(这里没有脚本)。

--------12) 执行init-bottom/下的脚本:
---------------12.1) 文件udev:
------------------------a) kill掉udevd
------------------------b) nuke /dev/.udev/queue/ (不知啥意思)
------------------------c) 执行/etc/udev/udev.conf 设置变量tmpfs_size=10M
------------------------d) mkdir /dev/.static/dev (注意,这个目录不是在硬盘上创建的)
------------------------e) mount -n -o bind /root/dev /dev/.static/dev 把真实文件系统的/dev目录下的node(在硬盘上) bind到/dev/.static/dev/下
------------------------f) mount -n -o move /dev /root/dev 把tmpfs类型的udev移到真实的文件系统的/dev下,(注意前面一开始就在/dev上mount了udev), 这时真实文件系统的/dev上mount了udev,而原来在硬盘的/dev目录下的node到了/dev/.static/dev下,实际上在硬盘上没有/dev/.static这个目录. (这个不太好理解)
------------------------g) nuke /dev (不知啥意思)
------------------------h) ln -s /root/dev /dev 前面mount -o move之后,目录/dev下什么也没了,这时/root还没真正成为根。这一步使得,如果其它脚本要使用/dev/下的设备文件时不至于找不到。

--------13) mount -n -o move /sys /root/sys

--------14) mount -n -o move /proc /root/proc

--------15) exec run-init /root /sbin/init "$@" /root/dev/console 这一步应该是使真实文件系统成为根,并执行它的/sbin/init(没看懂)

注:加载aic94xx时,需要从目录/usr/lib/hotplug/firmware或者/lib/udev/firmware下读入firmware数据,所以还要建立目录usr/lib/hotplug/firmware或者lib/udev/firmware (在initrd的根目录下,即/boot/myinit) ,然后,把aic94xx-seq.fw拷到任何一个目录中。 可以看出,如果把aic94xx编译进内核,就应把firmware数据也放进内核,但这个功能还没实现。参见内核文档Documentation/firmware_class/README的末尾。

阅读(1815) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~