Linux引导启动顺序

1.所有的__init函数在区段.initcall.init中还保存了一份函数指针,在初始化时内核会通过这些函数指针调用这些__init函数,并在整个初始化完成后,释放整个init区段(包括.init.text,.initcall.init等)。注意,这些函数在内核初始化过程中的调用顺序只和这里的函数指针的顺序有关,和这些函数本身在.init.text区段中的顺序无关。在2.4内核中,这些函数指针的顺序也是和链接的顺序有关的,是不确定的。在2.6内核中,initcall.init区段又分成7个子区段,如下:,数字越小越先调用,数字越大越后调用

.initcall1.init 
.initcall2.init 
.initcall3.init 
.initcall4.init 
.initcall5.init 
.initcall6.init 
.initcall7.init

数字越小越先被调用,include/linux/init.h文件中,包括各种常见的包装:

#define pure_initcall(fn)          __define_initcall(fn, 0)

#define core_initcall(fn)          __define_initcall(fn, 1)
#define core_initcall_sync(fn)     __define_initcall(fn, 1s)
#define postcore_initcall(fn)      __define_initcall(fn, 2)
#define postcore_initcall_sync(fn) __define_initcall(fn, 2s)
#define arch_initcall(fn)          __define_initcall(fn, 3)
#define arch_initcall_sync(fn)     __define_initcall(fn, 3s)
#define subsys_initcall(fn)        __define_initcall(fn, 4)
#define subsys_initcall_sync(fn)   __define_initcall(fn, 4s)
#define fs_initcall(fn)            __define_initcall(fn, 5)
#define fs_initcall_sync(fn)       __define_initcall(fn, 5s)
#define rootfs_initcall(fn)        __define_initcall(fn, rootfs)
#define device_initcall(fn)        __define_initcall(fn, 6)
#define device_initcall_sync(fn)   __define_initcall(fn, 6s)
#define late_initcall(fn)          __define_initcall(fn, 7)
#define late_initcall_sync(fn)     __define_initcall(fn, 7s)

 

 

2. Linux内核启动流程

//init/main.c kernel4.19
start_kernel()
    rest_init
        kernel_init //内核线程执行,kernel_thread(kernel_init, NULL, CLONE_FS);
            kernel_init_freeable 
                do_basic_setup
                    do_initcalls
                        do_initcall_level //在内核线程的执行路径中调用各个initcall.

进入子系统初始化时,在内核init进程中进行设备初始化,最为复杂、诡异的机制莫过于do_initcalls()函数调用,该函数完成了所有需要静态加载模块的初始化,需要进行静态加载的内核模块,需要使用一些特定的宏进行处理,

kernel_init 这个内核线程最终会执行"/bin/init",变成首个init进程。

原来 start_kernel 执行的进程最终会while (1) do_idle() 变成 idle 进程。

 

3.1.linux内核中initcalls机制

  先来看看do_initcalls()函数原型:该部分是一个函数指针调用,遍历_initcall_start~_initcall_end范围,逐个调用这里面的函数指针指向的函数。

 

 

// kernel_init 这个内核线程最终会执行"/bin/init",变成首个init进程。// 原来 start_kernel 执行的进程最终会while (1) do_idle() 变成 idle 进程。

 

补充:

1. 各类init call 调用的先后次序在数组中也有描述

/* Keep these in sync with initcalls in include/linux/init.h */
static const char *initcall_level_names[] __initdata = {
    "pure",
    "core",
    "postcore",
    "arch",
    "subsys",
    "fs",
    "device",
    "late",
};

 

posted on 2017-09-23 16:09  Hello-World3  阅读(741)  评论(0编辑  收藏  举报

导航