Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3625459
  • 博文数量: 880
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 6155
  • 用 户 组: 普通用户
  • 注册时间: 2016-11-11 09:12
个人简介

To be a better coder

文章分类

全部博文(880)

文章存档

2022年(5)

2021年(60)

2020年(175)

2019年(207)

2018年(210)

2017年(142)

2016年(81)

分类: LINUX

2020-05-09 15:41:39

原文地址:initramfs的运行过程 作者:lifefocus

  首先说明我从事的是嵌入式行业,所以以后的linux文章都是嵌入式相关的,除非有特别说明。

    我用的芯片是欧洲Gaisler Research公司的Leon3(Sparc架构),内核是Snapgear(包含ucLinux2.0Linux2.6),已经做好移植工作。 

    周一的时候,把linux2.6.21下载到leon3的板子上运行,结果莫名退出。

    检查的时候主要从配置出发,结果发现gaisler的默认配置有问题。它配置initial root filesystemromfs,其实从linux2.6内核开始这必须是initramfs。并且我们考虑到sram的大小可能不足以下载运行linux,所以我们使用了sdram

    经过一番更改后,编译下载运行,照样出错。没办法,必须要debug,可是kgdb没有for sparc/leonpatch。所以只能printk了。错误提示如下:

grlib> lo image.dsu

......

IP route cache hash table entries: 1024 (order: 0, 4096 bytes)

TCP established hash table entries: 512 (order: 0, 4096 bytes)

TCP bind hash table entries: 512 (order: -1, 2048 bytes)

TCP: Hash tables configured (established 512 bind 512)

TCP reno registered

initramfs:populate_rootfs:first line:allen


    按照提示发现代码在../linux2.6.21.1/init/initramfs.c

static int __init populate_rootfs(void)

{

    printk("initramfs:populate_rootfs:first line:allen\n");

    (stop in here)--> char *err = unpack_to_rootfs(__initramfs_start,

                __initramfs_end - __initramfs_start, 0);

......

    经过读源代码和看文档,最后终于把这个问题的过程搞清楚。

    首先要清楚initrd 的英文含义是 boot loader initialized RAM disk,就是由 boot loader 初始化的内存盘。在 linu2.6内核启动前, boot loader 会将存储介质中的 initrd 文件加载到内存,内核启动时会在访问真正的根文件系统前先访问该内存中的 initrd 文件系统。在 boot loader 配置了 initrd 的情况下,内核启动被分成了两个阶段,第一阶段先执行 initrd 文件系统中的init,完成加载驱动模块等任务,第二阶段才会执行真正的根文件系统中的 /sbin/init 进程。

    linux2.6 内核使用的 initrd 是 cpio 格式,其核心文件是 /init。下面介绍 linux2.6 内核对initrd 的处理流程:

  1. boot loader 把内核以及 initrd 文件加载到内存的特定位置。

  2. 内核判断initrd的文件格式,如果是cpio格式。

  3. initrd的内容释放到rootfs中。

  4. 执行initrd中的/init文件,执行到这一点,内核的工作全部结束,完全交给/init文件处理。

    这里要清楚另一个概念:

    initramfsinitramfs 是在 kernel 2.5中引入的技术,实际上它的含义就是:在内核镜像中附加一个cpio包,这个cpio包中包含了一个小型的文件系统,当内核启动时,内核将这个 cpio包解开,并且将其中包含的文件系统释放到rootfs中,内核中的一部分初始化代码会放到这个文件系统中,作为用户层进程来执行。这样带来的明显 的好处是精简了内核的初始化代码,而且使得内核的初始化过程更容易定制。

    所以内核首先要生成一个cpio包,这个包中又包含了initramfs的文件系统,这个就是initfamfs.cpio.gz。生成这个包的文件是:usr/gen_init_cpio.c,编译时initramfs_data.cpio.gz被链接进内核中。这个包放在usr/下,我们的内核也已经生成了这个包。 unpack_to_rootfs(__initramfs_start, __initramfs_end - __initramfs_start, 0)这句话的意思就是试图通过gunzip解压initfamfs.cpio.gz,在[__initramfs_start, __initramfs_end]之间找到initramfs。现在我们的gz包有了,还停在这里,所以我有理由怀疑是内核的下载地址和sdram的映射地址不相符合而引发的问题。

    进一步考证,需要下星期有硬件的情况下才能完成。

    还有,这个星期和Gailer ResearchD哥通了一下email,他觉得内核没有问题,主要强调了grmon下运行linux2.6的配置参数,如下:

    1.不要使用-u,使用minicom

    2.要加-nb

    3.要加-nosram,这样才能把sdram的地址映射到0x40000000。不然有可能映射地址0x40000000sram

    4.配置initial root filesysteminitramfs,内核要支持initramfs





后记:

    Ok,为了了解细节,Documentation/early-userspace/buffer-format.txt是必须要看看的。initramfs.cpio.gz是为内核准备一个包(这个包最终是连接在__initramfs_start),其格式大致如下:
initramfs := ("\0" | cpio_archive | cpio_gzip_archive)* 
cpio_gzip_archive := GZIP(cpio_archive) 
cpio_archive := cpio_file* + ( | cpio_trailer) 
cpio_file := ALGN(4) + cpio_header + filename + "\0" + ALGN(4) + data 
cpio_trailer := ALGN(4) + cpio_header + "TRAILER!!!\0" + ALGN(4)

    下面就简单讲一下如何生成:

    usr/gen_init_cpio.c在编译后生成程序gen_init_cpio(这是一个host program),它在主机上被执行,并产生一个cpio_archive(结果输出到stdout, 大家执行一下usr/gen_init_cpio就知道了)2.6.x内核的KBUILD在调用它时用下列命令(make V=1可以看到)将其结果重定向到文件initramfs_data.cpio
./usr/gen_init_cpio > usr/initramfs_data.cpio 
这样就生成一个未压缩的,"newc"格式的CPIO archive。然后,KBUILD再用gzipinitramfs_data.cpio压缩生成initramfs_data.cpio.gz文件。最后,KBUILDinitramfs_data.cpio.gz链接进内核中。

    生成了文件就要使用了,回到../linux2.6.21.1/init/initramfs.c。至于这里为什么要解压两次,我就不太清楚了,感觉一次就能搞完了。

static int __init populate_rootfs(void)

{

    char *err = unpack_to_rootfs(__initramfs_start,

        __initramfs_end - __initramfs_start, 0);

    if (err)

        panic(err);

#ifdef CONFIG_BLK_DEV_INITRD

    if (initrd_start) {

#ifdef CONFIG_BLK_DEV_RAM

        int fd;

        printk(KERN_INFO "checking if image is initramfs...");

        err = unpack_to_rootfs((char *)initrd_start,

        initrd_end - initrd_start, 1);

        if (!err) {

            unpack_to_rootfs((char *)initrd_start,

            initrd_end - initrd_start, 0);

            free_initrd();

            return 0;

        }


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