linux内核启动流程略解

        说明:本文档基于linux内核3.4.43版本。本文档只是对内核启动流程做很粗略的讲解,没有具体讲解某个模块,这也没办法,内核太庞大了。

        大体上如下图所示,将内核启动分为三个阶段:

                         linux内核启动流程略解

一、引导阶段

        内核入口可根据链接脚本确定,这里不讨论。我这边的入口是arch/arm/kernel/head.S的ENTRY(stext)。汇编阶段做了很多东西比如,关中断,获取处理器ID等,这里不理会,只管几个关键的:

                      linux内核启动流程略解

        1、__lookup_processor_type:这个主要是检查一下,处理器的类型,看看是否支持linux启动,

        2、__create_page_tables:创建一级页表,也叫创建粗页表,这个比较重要,但是我看不懂,对我工作一点影响都没有,所以懒得深究。主要作用是便于访问内存。

        3、__mmap_switched:这是在使能MMU后跳转的函数,是个关键的跳转函数,细节没看,直接看b   start_kernel这行,start_hernel就是进入了C语言阶段。我这边对应文件是init/main.c

二、初始化阶段

        初始化阶段做了很多初始化,每个初始化都可以独立一个模块讲解,这里暂时不分析那么多,只管两个简单的printk、还有console_init。

                         linux内核启动流程略解

        1、printk,这个其实没什么。你就当文件系统层的printf使用就行,只是多了打印级别这一项,这主要是内核打印太多,做了一个调试处理。打印级别宏定义在include/linux/printk.h中,源码如下图:

linux内核启动流程略解

        一共8个级别,使用时设计的级别,会打印出比级别高的,比如设置级别6时,0到6都会打印。各个级别的意思,都有英文注释,这里就不讲解了。

        2、console_init:控制台初始化,将控制台初始化成uboot环境变量传过来的console,之后用户打印的信息才能被显示出来,也就是内核打印中,时间全为0的地方,都在这个地方,瞬间将之前缓存的,全部打印出去。

        跳入rest_init函数继续初始化

        rest_init非常关键,这里现象了三大内核进程(内核中,线程进程可混为一谈)。如下图

linux内核启动流程略解

        三大内核进程简介:

        1、idle进程,这是唯一一个不是kernel_thread创建的,这个idle进程最终的归属是“睡觉”,也就是机器运行内核没事做的时候就执行idle进程“睡觉”,有事做的时候才起来。

        2、kthreadd进程,这是个守护进程,这个进程天生就是“老板”,用于管理内核空间,复制所有线程调度和管理。

        3、kernel_init进程,这是所有用户空间进程的“老爸”进程,当然要成为“老爸”进程之前是要经过一定的折腾的,也就是接下来的busybox阶段。

三、busyBox阶段

        busybox在这里大概的意思是linux内核提供给用户使用的工具箱。大致流程如下:

                   linux内核启动流程略解

        kernel_init函数做了很多准备工作,其实当然有重要的驱动初始化,驱动初始化在do_basic_setup中,这里暂时不分析,这里只简练的分析一下:控制台设备、文件系统挂载、init进程交接:

        1、控制台设备:由sys_open打开 "/dev/console",其实就是串口设备,然后sys_dup复制两份,获得三个文件描述符,分别是0、1、2,如下图

linux内核启动流程略解

即实现串口调试的超级终端。

        2、根文件系统挂载:prepare_namespace,这个函数大致是根据uboot环境变量提供的文件系统类型,然后进行挂载,详细分析我还没具体看,只是浏览一下。

        3、init进程的交接:init_post,这个函数是大致流程如下:

linux内核启动流程略解

        即挂载根文件系统后试图去运行用户态的init进程。查找路径由uboot环境变量提供,如果没有提供或者提供一个假的,那那内核会去选择备胎,备胎路径有四个,如下图:

              linux内核启动流程略解

        如果四个“备胎”都没有init进程,那内核就要发飙了直接报个panic,说:我找不到init,我要死了。当然找到的话,内核就正式启动了。