在init/intramfs.c中
static int __init populate_rootfs(void)
{
unpack_to_rootfs(__initramfs_start, __initramfs_size); //1. initramfs的解压
if (initrd_start) {
unpack_to_rootfs((char *)initrd_start, initrd_end - initrd_start); //2.initrd的解压
free_initrd();
}
}
rootfs_initcall(populate_rootfs); //这个相当于module_init在系统初始化时会调用
1. initramfs的解压
unpack_to_rootfs(__initramfs_start, __initramfs_size);
rootfs_initcall(populate_rootfs);
–> populate_rootfs
–> unpack_to_rootfs
在init/initramfs.c中
static char * __init unpack_to_rootfs(char *buf, unsigned len)
{
int i;
int written, res;
decompress_fn decompress;
const char *compress_name;
static __initdata char msg_buf[64];
header_buf = kmalloc(110, GFP_KERNEL);
symlink_buf = kmalloc(PATH_MAX + N_ALIGN(PATH_MAX) + 1, GFP_KERNEL);
name_buf = kmalloc(N_ALIGN(PATH_MAX), GFP_KERNEL);
state = Start;
this_header = 0;
message = NULL;
while (!message && len) {
loff_t saved_offset = this_header;
//如果开头以字符’0’开始,说明这是cpio格式的ram disk,不用解压直接用复制
if (*buf == ‘0’ && !(this_header & 3)) {
state = Start;
written = write_buffer(buf, len);
buf += written;
len -= written;
continue;
}
}
dir_utime();
kfree(name_buf);
kfree(symlink_buf);
kfree(header_buf);
return message;
}
在initramfs.cpio中打包了3个文件(2个目录 1个字符设备文件):
/dev 目录
/dev/console 文件
/root 目录
dir /dev 0755 0 0
nod /dev/console 0600 0 0 c 5 1
dir /root 0700 0 0
下面来看一下它们是如何依次解出来的:
buf=__initramfs_start, len=__initramfs_size
static int __init write_buffer(char *buf, unsigned len)
{
count = len;
victim = buf;

while (!actions[state]());
return len - count;

}
1.1 do_start
因为在initramfs.cpio的文件长度都为0,所以没有do_copy的过程
write_buffer
–> do_start
在init/initramfs.c中
static int __init do_start(void)
{
//实际作用是将collect指针移动到打包的cpio每一个文件头处
read_into(header_buf, 110, GotHeader);
return 0;
}
注意:这个名虽然叫read_into而且第一个参数又是buf,但实际上这个buf没有起到任何作用
static void __init read_into(char *buf, unsigned size, enum state next)
{
if (count >= size) {
collected = victim;
eat(size);
state = next; //下一步要执行do_header
}
}
1.2 do_header解析110字节的头
write_buffer
–> do_start
–> do_header
static int __init do_header(void)
{
if (memcmp(collected, “070707”, 6)==0) {
error(“incorrect cpio method used: use -H newc option”);
return 1;
}
if (memcmp(collected, “070701”, 6)) {
error(“no cpio magic”);
return 1;
}
parse_header(collected); //从101个字节的头中解析出inod mode uid gid等
next_header = this_header + N_ALIGN(name_len) + body_len; //移到下一个文件的头处
next_header = (next_header + 3) & ~3; //cpio的头部都是4字节对齐的
state = SkipIt;
if (name_len <= 0 || name_len > PATH_MAX)
return 0;
if (S_ISLNK(mode)) {
if (body_len > PATH_MAX)
return 0;
collect = collected = symlink_buf;
remains = N_ALIGN(name_len) + body_len;
next_state = GotSymlink;
state = Collect;
return 0;
}
//注意下面这个 !body_len,目录的body_len为0设备文件的body_len也为0
//所以这儿代表的是,所有非链接文件
if (S_ISREG(mode) || !body_len)
read_into(name_buf, N_ALIGN(name_len), GotName); //这个实际的作用是,将指针移动到下一个文件的头处
return 0; //并将状态改为GotName,即要调用do_name
}

1.3 do_name建立目录文件
write_buffer
–> do_start
–> do_header
–> do_name
进行到此处,系统中己存在/与/root两个目录(都是虚拟的),此时再把打包在cpio里面的文件解析到系统的相应位置上.
static int __init do_name(void)
{
state = SkipIt;
next_state = Reset;
if (strcmp(collected, “TRAILER!!!”) == 0) { //判断是不是结尾
free_hash();
return 0;
}
clean_path(collected, mode); //把原先有的路径去掉, 相当于rmdir /dev 或 rm /dev/console
if (S_ISREG(mode)) {
int ml = maybe_link();
if (ml >= 0) {
int openflags = O_WRONLY|O_CREAT;
if (ml != 1)
openflags |= O_TRUNC;
wfd = sys_open(collected, openflags, mode); //如果是普通文件打开sys_open

        if (wfd >= 0) {sys_fchown(wfd, uid, gid);                 //设置权限等sys_fchmod(wfd, mode);if (body_len)sys_ftruncate(wfd, body_len);vcollected = kstrdup(collected, GFP_KERNEL);state = CopyFile;                         //最后调用do_copy将文件内容复制过来}}
} else if (S_ISDIR(mode)) {                      // 以/dev为例 sys_mkdir(collected, mode);                  // 创建 /dev目录sys_chown(collected, uid, gid);              // 设置所有者sys_chmod(collected, mode);                  // 设置权限dir_add(collected, mtime);                   // 更改/dev目录的mtime
} else if (S_ISBLK(mode) || S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode)) {if (maybe_link() == 0) {                     // 以/dev/console为例  sys_mknod(collected, mode, rdev);        // 创建 /dev/console结点sys_chown(collected, uid, gid);          // 设置所有者sys_chmod(collected, mode);              // 设置权限do_utime(collected, mtime);              // 更改时间戳}
}
return 0;

}
1.3 do_skip
write_buffer
–> do_start
–> do_header
–> do_name
–> do_skip
static int __init do_skip(void)
{
if (this_header + count < next_header) {
dbmsg();
eat(count);
return 1;
} else {
dbmsg();
eat(next_header - this_header);
state = next_state;
return 0;
}
}
1.5 do_reset
write_buffer
–> do_start
–> do_header
–> do_name
–> do_skip
–> do_reset
static int __init do_reset(void)
{
dbmsg();
while(count && *victim == ‘\0’)
eat(1);
if (count && (this_header & 3))
error(“broken padding”);
return 1;
}
2.initrd的解压
2.1 initrd的起始地址的获取
make menuconfig中
General setup —>
[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support

start_kernel
–>setup_arch
在arch/arm/kernel/setup.c中
void __init setup_arch(char **cmdline_p)
{
struct machine_desc *mdesc;
mdesc = setup_machine_fdt(__atags_pointer);
if (!mdesc)
mdesc = setup_machine_tags(machine_arch_type); //读取内核参数
//uboot的参数: init=/init initrd=0x62000000,0x00130000
//指定了initrd在内存的起始地址0x62000000,长度0x130000
parse_early_param();
arm_memblock_init(&meminfo, mdesc); //将物理地址转为虚地址
}
start_kernel
–>setup_arch
–> arm_memblock_init
在arch/arm/mm/init.c中
void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
{

ifdef CONFIG_BLK_DEV_INITRD

if (phys_initrd_size) {memblock_reserve(phys_initrd_start, phys_initrd_size);initrd_start = __phys_to_virt(phys_initrd_start);     //将物理地址0x62000000转为虚地址initrd_end = initrd_start + phys_initrd_size;         //end地址+size=0x00130000
}

endif

}
unpack_to_rootfs((char *)initrd_start, initrd_end - initrd_start);
其中initrd_start是uboot传入的参数0x62000000的虚地址
里面的内容是烧入板子的boot.img去掉头8字节与尾4个字节,即out/target/product/rk3188/ramdisk.img
注: boot.img的生成
目录out/target/product/rk30sdk/root存在
a.将root下的每个文件加上cpio头+每个文件的内容,打包成cpios格式
b. 将这个cpio文件用gzip压缩后写到文件ramdisk.img中
c. mkkrnlimg会对ramdisk.img加上8个字节的头标志,尾部加上4个字节
2.2 解压并释放initrd中的文件目录
rootfs_initcall(populate_rootfs);
–> populate_rootfs
–> unpack_to_rootfs
在init/initramfs.c中
static char * __init unpack_to_rootfs(char *buf, unsigned len)
{
int i;
int written, res;
decompress_fn decompress;
const char *compress_name;
static __initdata char msg_buf[64];
header_buf = kmalloc(110, GFP_KERNEL);
symlink_buf = kmalloc(PATH_MAX + N_ALIGN(PATH_MAX) + 1, GFP_KERNEL);
name_buf = kmalloc(N_ALIGN(PATH_MAX), GFP_KERNEL);

if (!header_buf || !symlink_buf || !name_buf)panic("can't allocate buffers");state = Start;
this_header = 0;
message = NULL;
while (!message && len) {loff_t saved_offset = this_header;if (*buf == '0' && !(this_header & 3)) {//不是cpio格式,zip压缩过的开头不为字符'0'continue;}this_header = 0;//以开头的0x1f, 0x8b判断是zip压缩的,找到gunzipdecompress = decompress_method(buf, len, &compress_name);//调用压缩函数进行解压缩,解压后调用flush_buffer拷贝到各个目录decompress(buf, len, NULL, flush_buffer, NULL, &my_inptr, error);        this_header = saved_offset + my_inptr;buf += my_inptr;len -= my_inptr;
}
dir_utime();
kfree(name_buf);
kfree(symlink_buf);
kfree(header_buf);
return message;

}
do_start
do_header
do_name
do_copy
do_utime
do_skip
do_reset
这儿的wite_buffer,比initramfs的write_buffer多了一个do_copy的过程
因为initramfs中只有名,没有数据.initrd有数据,所以需要将数据复制过去.
static int __init flush_buffer(void *bufv, unsigned len)
{
char buf = (char ) bufv;
int written;
int origLen = len;
if (message)
return -1;
while ((written = write_buffer(buf, len)) < len && !message) {
char c = buf[written];
if (c == ‘0’) {
buf += written;
len -= written;
state = Start;
} else if (c == 0) {
buf += written;
len -= written;
state = Reset;
} else
error(“junk in compressed archive”);
}
return origLen;
}

rk3188--4.android用initrd文件系统启动流程相关推荐

  1. linux文件系统启动流程,linux 内核启动过程以及挂载android 根文件系统的过程

    转载 作者:汕头大学-黄珠唐 时间:2009 年10 月29 日 主要介绍linux 内核启动过程以及挂载android 根文件系统的过程,以及介绍android 源代码中文件系统部分的浅析. 主要源 ...

  2. linux文件系统启动流程 ---笔记整理

    下面是一张linux启动流程图: 在了解启动流程之前,我们应该先知道系统的几个重要脚本和配置文件,他们对应的路径为: 1. /sbin/init 2. /etc/inittab 3. /etc/rc. ...

  3. Android 打包 aar文件的流程以及aar的引用

    打包aar 分为原项目打包成aar 和新建module 打包成aar 1 原项目打包成aar 文件 需要把项目先变成库 把apply plugin: 'com.android.application' ...

  4. linux 文件系统 启动,linux kernel文件系统启动部分

    现在的kernel里,有个叫做ramfs的文件系统,会把initrd(或者ramdisk,为惯性叫法)里的东西挂载到early-rootfs里(即rootfs,是ramfs的一个特殊实例),执行一些在 ...

  5. Linux 操作系统原理 — 系统启动流程

    目录 文章目录 目录 系统启动流程 编辑 gurb.cfg RHEL7 的启动级别 RHEL7 破密码步骤 grup2 加密,防止破密码 initramfs 文件 系统启动流程 RHEL7 使用了 G ...

  6. Android系统启动流程 -- bootloader

    Android系统启动流程 -- bootloader   BootLoader:在嵌入式操作系统中,BootLoader是在操作系统内核运行之前运行.可以初始化硬件设备.建立内存空间映射图,从而将系 ...

  7. 【Android 系统开发】 Android 系统启动流程简介

    作者 : 万境绝尘 (octopus_truth@163.com) 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/3889548 ...

  8. CentOS系统启动流程及GRUB文件说明

    CentOS系统启动流程及GRUB文件说明 时间:2013-10-24 01:33来源:"过程就是为了实现结果" 博客 作者:本站 举报 点击:1114次 id="ifr ...

  9. Android系统启动流程分析之安装应用

    2016六月 21 原 Android系统启动流程分析之安装应用 分类:Android系统源码研究 (295)  (0)  举报  收藏 跟随上一篇博客Android系统的启动流程简要分析继续分析an ...

最新文章

  1. 使用ATS中的regex_remap插件实现正则匹配的url重定向
  2. 【03-14】日常资源访问备份
  3. java vm 远程监控配置文件_Java VisualVM监控远程JVM(详解)
  4. javaWeb服务详解【客户端调用】(含源代码,测试通过,注释) ——applicationContext.xml
  5. leetcode236 二叉树的最近公共祖先
  6. postgresql定义访问ip与用户_PostgreSQL 设置允许访问IP的操作
  7. 编程语言对比 条件控制语句
  8. 学html和css的感受
  9. 教程分享:mp3语音转文字免费方法有哪些?
  10. 计算机技术和通信技术始于,计算机网络基础试题精选.doc
  11. natapp反向代理
  12. 【视频学习】宋维钢词霸天下38000词汇速记 万法归宗之英语语法速成全集
  13. 陆地生态系统生态学原理
  14. 【贪玩巴斯】无线传感器网络(二)「无线传感器网络中物理层的五点详解」 2021-09-24
  15. [接口测试]POST请求提交数据的三种方式及Postman实现
  16. 微信小程序font-family中提供的十四种字体
  17. Oracle Spatial中上载GIS空间数据方法研究
  18. 解析华为OSPF协议
  19. Android开发中WIFI和GPRS网络的切换
  20. php 每次加密结果都不一样,实用的PHP带公钥加密类分享(每次加密结果都不一样哦)...

热门文章

  1. GIS二次开发实习——鹰眼功能模块的实现(鹰眼锁定不能动,红框与主地图联动)
  2. 量子计算机和肖尔算法,量子计算机、肖尔算法与多重宇宙有关联性,能证明多重宇宙存在...
  3. 整合tomcat和apche服务器
  4. 微软安全软件OneCare Live
  5. 深圳大学计算机考研难吗,深圳大学(专业学位)计算机技术考研难吗
  6. java二维码生成器及下载
  7. SpringCloud Edgware.SR3版本-Ribbon的timeout设置
  8. 乔姆斯基生成语法_乔姆斯基转换生成语法的发展及其影响
  9. 爱丁堡大学—计算机应用数学,爱丁堡大学计算机应用数学理学硕士
  10. 一根均线选股法_建议收藏!一根均线走天下战法详解,(附选股方法)