子系统的初始化

6.2 子系统的初始化

所以接下来说do_basic_setup函数,任然是来自init/main.c

 

778/*

 779 * Ok, the machine is now initialized. None of the devices

 780 * have been touched yet, but the CPU subsystem is up and

 781 * running, and memory and process management works.

 782 *

 783 * Now we can finally start doing some real work..

 784 */

 785static void __init do_basic_setup(void)

 786{

 787        init_workqueues();

 788        cpuset_init_smp();

 789        usermodehelper_init();

 790        init_tmpfs();

 791        driver_init();

 792        init_irq_proc();

 793        do_ctors();

 794        do_initcalls();

 795}

 

第一个函数init_workqueues初始化工作队列events每个CPU一个对工作队列机制感兴趣的同学请访问博客下半部分

http://blog.csdn.net/yunsongice/archive/2010/03/07/5354011.aspx

 

第二个函数cpuset_init_smp是个空函数因为没有配置CONFIG_CPUSETS

 

第三个函数usermodehelper_init初始化工作队列khelper每个CPU一个。

 

第四个函数init_tmpfs注册并安装tmpfs文件系统它的file_system_type结构如下:

static struct file_system_type tmpfs_fs_type = {

       .owner           = THIS_MODULE,

       .name             = "tmpfs",

       .get_sb           = shmem_get_sb,

       .kill_sb    = kill_litter_super,

};

 

第五个函数driver_init建立设备驱动模型sysfsksetkobjectsubsystem结构并向其中注册cpu、内存和总线的驱动。

 

第六个函数init_irq_proc/proc文件系统中增加子目录irq来显示中断描述符表中的所有元素。

 

第七个函数do_ctors,不是太明白,忽略它。

 

最后来说说第八个函数do_initcalls();

 

首先说一下,内核中有一个专门的节,用来存放初始化末尾要被调用的函数。举个例子init/initramfs.c中的最后一句是:

rootfs_initcall(populate_rootfs);

而:

#define rootfs_initcall(fn)             __define_initcall("rootfs",fn,rootfs)

#define __define_initcall(level,fn,id) /

        static initcall_t __initcall_##fn##id __attribute_used__ /

        __attribute__((__section__(".initcall" level ".init"))) = fn

 

可以看出来这个populate_rootfs被放在.initcallrootfs.init节中了。然后呢,这个节在链接的时候会被output.initcall.init节中 (为了避免交叉过多)。

 

好了,在明白了initcall相关信息后,继续看看do_initcalls()

它的本质就是

        for (call = __initcall_start; call < __initcall_end; call++)

                result = (*call)();

 

这样所有的initcall就会被调用了,这是为了避免把所有代码集合到一块的一个方法,虽然这带来了一个问题,谁在前谁在后?内核专门为这个大节分了一些类,哪些在前哪些在后连接的时候会安排的。

 

正好,现在知道 populate_rootfs会被执行,它处理initfamfsinitrd,首先是执行unpack_to_rootfs,然后检查是否有initrd。代码就不列出来了。

 

再回到调用do_basic_setup()kernel_init中:接下来

    if (!ramdisk_execute_command)

         ramdisk_execute_command = "/init";

   if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {

         ramdisk_execute_command = NULL;

         prepare_namespace();

    }

 

这段代码检查是否有必要mount根文件系统,如果vmlinuz中带有initfamfs,而且其中已经有init,那么就不这么做了(我现在工作用的目标系统就是这样的,里面有个init),否则的话内核还要mount init所在的(也是所有用户态进程的最除根文件系统)根文件系统,挂在根文件系统和执行initlinux启动过程最后要做的事情。

 

好了,就不说mount_root的细节了,prepare_namespace还是很值得一看的,可以去翻源代码。如果它失败了,就是panic VFS no root found 这样的错误了。现在假设已经有了根文件系统了,这样就到了kernel_init中的最后一条函数调用了——init_post

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值