Linux内核基础——Linux内核启动初始化流程
一、前言
二、Linux内核启动初始化关键函数流
1、start_kernel()
start_kernel()做了什么?
总体来说start_kernel()做了这些事情
2、rest_init()
总体来说rest_init()做了这些事情
1)调用kernel_thread函数启动了2个内核线程,分别是:kernel_init和kthreadd。
2)调用schedule函数开启内核调度系统;
3)调用cpu_idle函数,将当前进程转变成idle进程(空闲进程)
3、kernel_init()
kernel_init()主要做了什么?
4、init_post()
init_post()主要做了什么呢?
总结
一、前言
本篇博客源码学习为linux2.16-25内核版本,此篇博客简单的讲解了linux内核初始化启动到最后成功创建第一个用户空间init进程的过程。我将此过程称为linux内核启动初始化的关键流程。
本篇博客不对源码进行具体分析注解,仅仅对大的方向进行阐述。(原因在于作者暂无深入浅出分析源码的能力)如读者对源码阅读非常感兴趣可以根据以下即将介绍的四个函数中任一进行搜索,查看源码注解相关文章。
二、Linux内核启动初始化关键函数流
1、start_kernel()
start_kernel()做了什么?
start_kernel做了非常多的事情,代码行数很长,截图截不下来,这里分享一个百度文库链接,里面记载了很多函数的解释。
Start_kernel函数分析 Cr.百度文库
总体来说start_kernel()做了这些事情
(1)内核架构 、通用配置相关初始化
(2)中断向量表相关初始化
(3)内存管理相关初始化
(4)进程管理相关初始化
(5)进程调度相关初始化
(6)网络子系统管理初始化
(7)虚拟文件系统初始化
(8)文件系统初始化 等等
最后调用rest_init()
2、rest_init()
总体来说rest_init()做了这些事情
1)调用kernel_thread函数启动了2个内核线程,分别是:kernel_init和kthreadd。
kernel_init内核线程主要负责开启1号进程init,众所周知,init进程是linux系统下的1号进程,它是linux系统用户空间中所有进程的祖先进程,当用户空间的某一进程丢失了它的父进程时,1号进程init就会接纳它,成为它新的爸爸。
kthreadd内核线程同样也在用户空间开启了2号进程kthreadd,用于管理和调度其他内核线程。
2)调用schedule函数开启内核调度系统;
3)调用cpu_idle函数,将当前进程转变成idle进程(空闲进程)
在前言我称linux内核启动初始化的关键流程就是linux内核初始化启动到最后成功创建第一个用户空间init进程的过程。因此,我们下一步要将焦点放在kernel_init这个内核线程中去。
3、kernel_init()
kernel_init()主要做了什么?
do_basic_setup()函数:主要通过核心函数do_initcalls()调用所有编译内核的驱动模块中的初始化函数。完成外设及其驱动程序的加载和初始化 ;
挂载根文件系统[perpare_namespace函数]
最后调用init_post()函数启动用户空间的init进程。
最后调用的init_post()成功将我们第一个用户空间的init进程开启起来,那接下来我们康康init_post()在干嘛。
4、init_post()
就是它真正启动了用户空间进程init
init_post()主要做了什么呢?
释放__init_begin段到__init_end段中的内存,供其它程序使用。[free_initmem()函数]
打开dev/console控制台设备(串口0),创建init进程的标准输入(文件描述符0)[sys_open()函数]并调用dup打开/dev/console两次,创建init进程的另外2个文件描述符(1和2):标准输出和标准错误。[sys_dup()函数]
通过[run_init_process()函数]运行第一个用户进程init,execute_command变量中存放init程序的执行路径。若execute_command的路径错误,则会执行四个备用方案。第一备用:/sbin/init,第二备用:/etc/init,第三备用:/bin/init,第四备用:/bin/sh。
总结
直至init_post()正确运行,linux内核启动初始化的关键流程执行完毕!第一个用户空间的进程init成功诞生!