initcall机制

"node" {
    "label": "initcall",
    "categories": ["init"],
    "info": "kernel initcall",
    "depends": [ 
        "kernel start"
    ]
}

代码段

内核在生成链接脚本时,会包含下列段

__initcall_start = .;

KEEP(*(.initcallearly.init)) 
__initcall0_start = .; 
KEEP(*(.initcall0.init)) 
KEEP(*(.initcall0s.init)) 

__initcall1_start = .; 
KEEP(*(.initcall1.init)) 
KEEP(*(.initcall1s.init)) 

__initcall2_start = .;
KEEP(*(.initcall2.init)) 
KEEP(*(.initcall2s.init)) 

__initcall3_start = .; 
KEEP(*(.initcall3.init)) 
KEEP(*(.initcall3s.init)) 
__initcall4_start = .; 
KEEP(*(.initcall4.init)) 
KEEP(*(.initcall4s.init)) 

__initcall5_start = .; 
KEEP(*(.initcall5.init)) 
KEEP(*(.initcall5s.init))

__initcallrootfs_start = .; 
KEEP(*(.initcallrootfs.init))
KEEP(*(.initcallrootfss.init))

__initcall6_start = .; 
KEEP(*(.initcall6.init)) 
KEEP(*(.initcall6s.init)) 

__initcall7_start = .; 
KEEP(*(.initcall7.init)) 
KEEP(*(.initcall7s.init)) 
__initcall_end = .;

函数如何声明为属于某个初始化段

  #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)

  #define __initcall(fn) device_initcall(fn)

可以通过上述宏声明具体的函数链接地址,则对应的函数指针在链接阶段会放在对应的段内存

array initcall_levels

系统初始化,对每个段分为如下几个等级

  static const char *initcall_level_names[] __initdata = {
          "pure",
          "core",
          "postcore",
          "arch",
          "subsys",
          "fs",
          "device",
          "late",
  };

 static initcall_entry_t *initcall_levels[] __initdata = {
          __initcall0_start,
          __initcall1_start,     
          __initcall2_start,
          __initcall3_start,
          __initcall4_start,
          __initcall5_start,
          __initcall6_start,
          __initcall7_start,
          __initcall_end,
  };

初始化: do_initcalls

do_initcalls 属于比较靠后的初始化,此时系统有依赖的核心功能已经初始化完成,开始子系统初始化 ,初始化调用的时机

user thread: 
  kernel_init()
     -> kernel_init_freeable()
       -> do_basic_setup()
         -> do_initcalls()
  static void __init do_initcalls(void)
  {       
          int level;
          size_t len = saved_command_line_len + 1;
          char *command_line;
          command_line = kzalloc(len, GFP_KERNEL);
          for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++) {
                  /* Parser modifies command_line, restore it each time */
                  strcpy(command_line, saved_command_line);
                  do_initcall_level(level, command_line);
          }
          kfree(command_line);
  }

就是按照level遍历调用各个初始化段的 初始化回调函数