linux 3.6 启动源码分析(五) kernel_init进程

来源:互联网 发布:单片机的蓝牙模块 编辑:程序博客网 时间:2024/06/11 02:27
转载地址:http://blog.csdn.net/qing_ping/article/details/17352603

在start_kernel最后的rest_init函数中内核创建了两个内核线程,一个是内核线程的管理者,另一个是内核初始化线程kernel_init.

kernel_init它将完成设备驱动程序的初始化,并调用init_post函数启动用户空间的init进程。

[cpp] view plain copy
print?
  1. static int __init kernel_init(void * unused)  
  2. {  
  3.     /*Wait until kthreadd is all set-up.*/  
  4.     wait_for_completion(&kthreadd_done);  
  5.     /* Now the scheduler is fully set up and can do blocking allocations */  
  6.     gfp_allowed_mask = __GFP_BITS_MASK;  
  7.   
  8.     /* init can allocate pages on any node */  
  9.     set_mems_allowed(node_states[N_HIGH_MEMORY]);  
  10.     /* init can run on any cpu. */  
  11.     set_cpus_allowed_ptr(current, cpu_all_mask);  
  12.     cad_pid = task_pid(current);  
  13.     smp_prepare_cpus(setup_max_cpus);  
  14.     do_pre_smp_initcalls();  
  15.     lockup_detector_init();  
  16.     smp_init();  
  17.     sched_init_smp();  
  18.     //以上代码是在SMP系统做准备,激活所有CPU,并开始SMP系统的调度  
  19.   
  20.     /*do_basic_setup函数主要是初始化设备驱动,完成其他驱动程序(直接编译进内核的模块)的初始化。内核中大部分的启动数据输出(都是各设备的驱动模块输出)都是这里产生的*/  
  21.     do_basic_setup();  
  22.     /* Open the /dev/console on the rootfs, this should never fail */  
  23.     if (sys_open((const char __user *) “/dev/console”, O_RDWR, 0) < 0)  
  24.         printk(KERN_WARNING ”Warning: unable to open an initial console.\n”);  
  25.     (void) sys_dup(0);  
  26.     (void) sys_dup(0);  
  27.     /*   
  28.      复制两次标准输入(0)的文件描述符(它是上面打开的/dev/console,也就是系统控制台): 
  29.      一个作为标准输出(1) 
  30.      一个作为标准出错(2) 
  31.      * check if there is an early userspace init.  If yes, let it do all 
  32.      * the work 
  33.      */  
  34.       
  35.      /*检查是否有早期用户空间的init程序。如果有,让其执行*/  
  36.     if (!ramdisk_execute_command)  
  37.         ramdisk_execute_command = ”/init”;  
  38.   
  39.     if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {  
  40.         ramdisk_execute_command = NULL;  
  41.         prepare_namespace();  
  42.     }  
  43.   
  44.     /* 
  45.      * Ok, we have completed the initial bootup, and 
  46.      * we’re essentially up and running. Get rid of the 
  47.      * initmem segments and start the user-mode stuff.. 
  48.      */  
  49.         printk(KERN_NOTICE ”47—”);  
  50.   
  51.     init_post();//在内核init线程的最后执行了init_post函数,在这个函数中真正启动了用户空间进程init  
  52.     return 0;  
  53. }  
static int __init kernel_init(void * unused){    /*Wait until kthreadd is all set-up.*/    wait_for_completion(&kthreadd_done);    /* Now the scheduler is fully set up and can do blocking allocations */    gfp_allowed_mask = __GFP_BITS_MASK;    /* init can allocate pages on any node */    set_mems_allowed(node_states[N_HIGH_MEMORY]);    /* init can run on any cpu. */    set_cpus_allowed_ptr(current, cpu_all_mask);    cad_pid = task_pid(current);    smp_prepare_cpus(setup_max_cpus);    do_pre_smp_initcalls();    lockup_detector_init();    smp_init();    sched_init_smp();    //以上代码是在SMP系统做准备,激活所有CPU,并开始SMP系统的调度    /*do_basic_setup函数主要是初始化设备驱动,完成其他驱动程序(直接编译进内核的模块)的初始化。内核中大部分的启动数据输出(都是各设备的驱动模块输出)都是这里产生的*/    do_basic_setup();    /* Open the /dev/console on the rootfs, this should never fail */    if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)        printk(KERN_WARNING "Warning: unable to open an initial console.\n");    (void) sys_dup(0);    (void) sys_dup(0);    /*       复制两次标准输入(0)的文件描述符(它是上面打开的/dev/console,也就是系统控制台):     一个作为标准输出(1)     一个作为标准出错(2)     * check if there is an early userspace init.  If yes, let it do all     * the work     */     /*检查是否有早期用户空间的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();    }    /*     * Ok, we have completed the initial bootup, and     * we're essentially up and running. Get rid of the     * initmem segments and start the user-mode stuff..     */        printk(KERN_NOTICE "47---");    init_post();//在内核init线程的最后执行了init_post函数,在这个函数中真正启动了用户空间进程init    return 0;}
[cpp] view plain copy
print?
  1. static noinline int init_post(void)  
  2. {  
  3.     /* need to finish all async __init code before freeing the memory */      
  4.     /* 在释放内存前,必须完成所有的异步 __init 代码 */  
  5.     async_synchronize_full();  
  6.     free_initmem();//释放所有init.* 段中的内存。  
  7.       
  8.     mark_rodata_ro();//通过修改页表,保证只读数据段为只读属性。大部分构架为空函数  
  9.     system_state = SYSTEM_RUNNING;//设置系统状态为运行状态  
  10.       
  11.     numa_default_policy();//设定NUMA系统的内存访问策略为默认  
  12.   
  13.     current->signal->flags |= SIGNAL_UNKILLABLE;//设置当前进程(init)为不可以杀进程(忽略致命的信号)  
  14.     flush_delayed_fput();  
  15.   
  16.     if (ramdisk_execute_command) {//如果ramdisk_execute_command有指定的init程序,就执行它  
  17.         run_init_process(ramdisk_execute_command);  
  18.         printk(KERN_WARNING ”Failed to execute %s\n”,  
  19.                 ramdisk_execute_command);  
  20.     }  
  21.   
  22.     /* 
  23.      * We try each of these until one succeeds. 
  24.      * The Bourne shell can be used instead of init if we are 
  25.      * trying to recover a really broken machine. 
  26.      我们尝试以下的每个函数,直到函数成功执行. 
  27.     如果我们试图修复一个真正有问题的设备, 
  28.     Bourne shell 可以替代init进程。 
  29.     */  
  30.       
  31.     if (execute_command) {  
  32.         run_init_process(execute_command);  
  33.         printk(KERN_WARNING ”Failed to execute %s.  Attempting ”  
  34.                     ”defaults…\n”, execute_command);  
  35.     }  
  36.     run_init_process(”/sbin/init”);  
  37.     run_init_process(”/etc/init”);  
  38.     run_init_process(”/bin/init”);  
  39.     run_init_process(”/bin/sh”);  
  40.   
  41.     panic(”No init found.  Try passing init= option to kernel. ”  
  42.           ”See Linux Documentation/init.txt for guidance.”);  
  43. }  
static noinline int init_post(void){    /* need to finish all async __init code before freeing the memory */        /* 在释放内存前,必须完成所有的异步 __init 代码 */    async_synchronize_full();    free_initmem();//释放所有init.* 段中的内存。    mark_rodata_ro();//通过修改页表,保证只读数据段为只读属性。大部分构架为空函数    system_state = SYSTEM_RUNNING;//设置系统状态为运行状态    numa_default_policy();//设定NUMA系统的内存访问策略为默认    current->signal->flags |= SIGNAL_UNKILLABLE;//设置当前进程(init)为不可以杀进程(忽略致命的信号)    flush_delayed_fput();    if (ramdisk_execute_command) {//如果ramdisk_execute_command有指定的init程序,就执行它        run_init_process(ramdisk_execute_command);        printk(KERN_WARNING "Failed to execute %s\n",                ramdisk_execute_command);    }    /*     * We try each of these until one succeeds.     * The Bourne shell can be used instead of init if we are     * trying to recover a really broken machine.     我们尝试以下的每个函数,直到函数成功执行.    如果我们试图修复一个真正有问题的设备,    Bourne shell 可以替代init进程。    */    if (execute_command) {        run_init_process(execute_command);        printk(KERN_WARNING "Failed to execute %s.  Attempting "                    "defaults...\n", execute_command);    }    run_init_process("/sbin/init");    run_init_process("/etc/init");    run_init_process("/bin/init");    run_init_process("/bin/sh");    panic("No init found.  Try passing init= option to kernel. "          "See Linux Documentation/init.txt for guidance.");}


至此,内核的初始化结束,正式进入了用户空间的初始化过程至此,内核的初始化结束,正式进入了用户空间的初始化过程至此,内核的初始化结束,正式进入了用户空间的初始化过程,在kernel_init线程中调用的do_basic_setup()函数会去初始化设备驱动,完成其他驱动程序(直接编译进内核的模块)的初始化。内核中大部分的启动数据输出(都是各设备的驱动模块输出)都是这里产生的。是我们驱动工程师需要重点关注的函数。

 

 

 

 

原创粉丝点击