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进程。
- 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;
- }
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;}
- 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.”);
- }
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()函数会去初始化设备驱动,完成其他驱动程序(直接编译进内核的模块)的初始化。内核中大部分的启动数据输出(都是各设备的驱动模块输出)都是这里产生的。是我们驱动工程师需要重点关注的函数。
阅读全文
0 0
- linux 3.6 启动源码分析(五) kernel_init进程
- linux 3.6 启动源码分析(五) kernel_init进程
- 内核启动kernel_init(init)进程分析
- 内核启动阶段kernel_init(init)进程分析
- linux kernel_init
- linux kernel_init
- 进程启动源码分析
- ServiceManager 进程启动源码分析
- elasticsearch源码分析--启动进程
- ServiceManager 进程启动源码分析
- linux 3.6 启动源码分析(一)
- linux 3.6 启动源码分析(二) start_kernel
- linux 3.6 启动源码分析(三) setup_arch
- linux 3.6 启动源码分析(四) rest_init
- linux 3.6 启动源码分析(六) do_basic_setup
- linux 3.6 启动源码分析(七) do_initcalls
- linux 3.6 启动源码分析(一)
- linux 3.6 启动源码分析(二) start_kernel
- 伪人工智能即将步入爆发临界点,智慧家庭能让它落地吗?
- javascrip 计算器的简单实现
- Python自然语言处理小问题之from __future__ import division
- Scala函数式程序设计原理 week1 Getting Started + Functions & Evaluation
- Codeforces858A k-rouding
- linux 3.6 启动源码分析(五) kernel_init进程
- nodejs -- 链接mongodb
- 前端常用JS库
- ASIC/SoC设计
- 北大 AI 公开课第10讲 胡郁:人工智能+,共创新时代
- leetcode 149. Max Points on a Line 计算斜率的问题
- 【剑指offer】面试题25:从上往下打印二叉树
- Log4j的使用
- http协议详解