Linux内核启动过程的分析
2015-03-22 20:11
417 查看
Linux内核启动过程分析
Linux内核的启动从src/init/main.c的start_kernel函数开始,因此使用gdb在start_kernel函数下断点并进行跟踪
start_kernel的代码比较多,近200行,大多数是各个系统模块的初始化,本文不叙述这部分内容,本文需要注意的代码位于start_kernel函数的开头部分和结尾部分,粘贴如下
这句是内核启动的第一步,init_task是一个声明在init_task.c中的全局变量,具体定义位于init_task.h,其内容就是一个完整的进程控制块,这句中的函数名可以推测出其作用,即标记处进程栈的底部,其具体实现位于fork.c和sched.c中,sched.c中实现的是设置进程栈底的功能
到这儿就不难理解了。init_task这个手动设置出来的进程控制块实际上就是0号进程,也就是Linux后续系统进程和用户进程的起点
设置完0号进程以后,start_kernel执行了大量运行环境的初始化,包括中断门初始化,SMP结构初始化,内存分页初始化,终端初始化等等,到最后一行的rest_init,在rest_init中,Linux内核将启动第一个用户态进程,即init进程
rest_init首先初始化了调度器,随后以kernel_init作为处理函数构造出了一个内核线程,接着在启动调度器进行一次调度,在代码注释里面说的很清楚
而cpu_startup_entry这个函数最终会进入cpu_idle_loop();这样一个死循环,
kernel_init也就是1号init进程,即一切用户态进程的祖先
可以看出kernel_init和linux的initrd机制有关联,最后按照/sbin/init/;/etc/init/;/bin/init/;/bin/sh;的顺序寻找init执行,我们之前的menuOS就是通过initrd来执行的,可以将menuos换成其他C代码作为init执行
吴韬 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
Linux内核启动过程分析
这次我们使用gdb跟踪Linux内核的启动来分析其启动过程,内核版本3.18.6Linux内核的启动从src/init/main.c的start_kernel函数开始,因此使用gdb在start_kernel函数下断点并进行跟踪
start_kernel的代码比较多,近200行,大多数是各个系统模块的初始化,本文不叙述这部分内容,本文需要注意的代码位于start_kernel函数的开头部分和结尾部分,粘贴如下
asmlinkage __visible void __init start_kernel(void) { char *command_line; char *after_dashes; /* * Need to run as early as possible, to initialize the * lockdep hash: */ lockdep_init(); set_task_stack_end_magic(&init_task); ........ /* Do the rest non-__init'ed, we're now alive */ rest_init(); }
set_task_stack_end_magic(&init_task);
这句是内核启动的第一步,init_task是一个声明在init_task.c中的全局变量,具体定义位于init_task.h,其内容就是一个完整的进程控制块,这句中的函数名可以推测出其作用,即标记处进程栈的底部,其具体实现位于fork.c和sched.c中,sched.c中实现的是设置进程栈底的功能
static inline unsigned long *end_of_stack(struct task_struct *p) { #ifdef CONFIG_STACK_GROWSUP return (unsigned long *)((unsigned long)task_thread_info(p) + THREAD_SIZE) - 1; #else return (unsigned long *)(task_thread_info(p) + 1); #endif }
到这儿就不难理解了。init_task这个手动设置出来的进程控制块实际上就是0号进程,也就是Linux后续系统进程和用户进程的起点
设置完0号进程以后,start_kernel执行了大量运行环境的初始化,包括中断门初始化,SMP结构初始化,内存分页初始化,终端初始化等等,到最后一行的rest_init,在rest_init中,Linux内核将启动第一个用户态进程,即init进程
static noinline void __init_refok rest_init(void) { int pid; rcu_scheduler_starting(); kernel_thread(kernel_init, NULL, CLONE_FS); numa_default_policy(); pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES); rcu_read_lock(); kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns); rcu_read_unlock(); complete(&kthreadd_done); init_idle_bootup_task(current); schedule_preempt_disabled(); /* Call into cpu_idle with preempt disabled */ cpu_startup_entry(CPUHP_ONLINE); }
rest_init首先初始化了调度器,随后以kernel_init作为处理函数构造出了一个内核线程,接着在启动调度器进行一次调度,在代码注释里面说的很清楚
/* * We need to spawn init first so that it obtains pid 1, however * the init task will end up wanting to create kthreads, which, if * we schedule it before we create kthreadd, will OOPS. */
而cpu_startup_entry这个函数最终会进入cpu_idle_loop();这样一个死循环,
kernel_init也就是1号init进程,即一切用户态进程的祖先
static int __ref kernel_init(void *unused) { ...... if (ramdisk_execute_command) { ret = run_init_process(ramdisk_execute_command); if (!ret) return 0; pr_err("Failed to execute %s (error %d)\n", ramdisk_execute_command, ret); } if (execute_command) { ret = run_init_process(execute_command); if (!ret) return 0; pr_err("Failed to execute %s (error %d). Attempting defaults...\n", execute_command, ret); } if (!try_to_run_init_process("/sbin/init") || !try_to_run_init_process("/etc/init") || !try_to_run_init_process("/bin/init") || !try_to_run_init_process("/bin/sh")) return 0; panic("No working init found. Try passing init= option to kernel. " "See Linux Documentation/init.txt for guidance."); }
可以看出kernel_init和linux的initrd机制有关联,最后按照/sbin/init/;/etc/init/;/bin/init/;/bin/sh;的顺序寻找init执行,我们之前的menuOS就是通过initrd来执行的,可以将menuos换成其他C代码作为init执行
吴韬 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
相关文章推荐
- Linux内核源码分析--内核启动命令行的传递过程(Linux-3.0 ARMv7)
- 基于I386的Linux2.4.18内核启动过程分析
- Linux内核启动过程分析 ___x86
- Linux内核启动过程分析
- [转载] linux启动流程分析(3)---内核解压缩过程
- linux内核启动过程分析
- Linux内核源码分析--内核启动命令行的传递过程(Linux-3.0 ARMv7)
- Linux内核源码分析--内核启动命令行的传递过程(Linux-3.0 ARMv7)
- Linux内核源码分析--内核启动命令行的传递过程(Linux-3.0 ARMv7)
- linux 内核启动过程分析
- Linux内核源码分析--内核启动命令行的传递过程(Linux-3.0 ARMv7)
- linux2.4启动分析(2)---内核解压缩过程 compress booting kernel
- linux启动流程分析-内核解压缩过程
- Linux启动过程的内核代码分析
- Linux内核源码分析--内核启动之(1)zImage自解压过程(Linux-3.0 ARMv7)
- linux内核启动过程分析(二)
- Linux内核启动过程分析
- linux内核启动过程分析(一) arm
- Linux内核源码分析--内核启动命令行的传递过程(Linux-3.0 ARMv7)
- [转载] linux启动流程分析(1)---bootloader启动内核过程