Linux initcall执行顺序分析

Linux initcall执行顺序分析

1 Linux关于initcall的定义

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

以上定义,数字越小,其优先级越高,高优先级的优先执行,同等优先级的则根据Kernel下的Makefile中.o文件的链接次序决定。

而常用的module_init在启动序号为6,其展开后就是__define_initcall(“6”, fn, 6),具体如下:

/include/linux/module.h:#define module_init(x) __initcall(x)
/include/linux/init.h:#define __initcall(fn) device_initcall(fn)
/include/linux/init.h:#define device_initcall(fn) __define_initcall("6",fn,6)

__define_initcall的原型如下:

#define __define_initcall(fn, id) \
	static initcall_t __initcall_##fn##id __used \
	__attribute__((__section__(".initcall" #id ".init"))) = fn;

该宏将函数重新组装成__initcall为前缀,等级为后缀的函数名,并把此函数的定义到代码段.initcallX.init中。
以module_init为例进行分析:
Module_init的函数名组装为:__initcall_xxx6_used,其代码段为.initcall6.init里面。

而.initcall6.init代码段则将在vmlinux.lds的链接文件中体现,具体如下:
arch/arm/kernel/vmlinux.lds
__initcall_start = .; *(.initcallearly.init) __initcall0_start = .; *(.initcall0.init) *(.initcall0s.init) __initcall1_start = .; *(.initcall1.init) *(.initcall1s.init) __initcall2_start = .; *(.initcall2.init) *(.initcall2s.init) __initcall3_start = .; *(.initcall3.init) *(.initcall3s.init) __initcall4_start = .; *(.initcall4.init) *(.initcall4s.init) __initcall5_start = .; *(.initcall5.init) *(.initcall5s.init) __initcallrootfs_start = .; *(.initcallrootfs.init) *(.initcallrootfss.init) __initcall6_start = .; *(.initcall6.init) *(.initcall6s.init) __initcall7_start = .; *(.initcall7.init) *(.initcall7s.init) __initcall_end = .;

2 initcall函数调用过程

Linux-4.14调用过程:
相关代码在/init/main.c中:

  • start_kenrel->rest_init-> kernel_init -> kernel_init_freeable ->do_basic_setup->do_initcalls

Linux-3.4.19调用过程:

  • start_kenrel->rest_init-> kernel_init ->do_basic_setup->do_initcalls

      /*
       * Ok, the machine is now initialized. None of the devices
       * have been touched yet, but the CPU subsystem is up and
       * running, and memory and process management works.
       *
       * Now we can finally start doing some real work..
       */
      static void __init do_basic_setup(void)
      {
      	cpuset_init_smp();
      	usermodehelper_init();
      	shmem_init();
      	driver_init();
      	init_irq_proc();
      	do_ctors();
      	usermodehelper_enable();
      	do_initcalls();
      }
    

//遍历从低等级到高等级的初始化函数

static void __init do_initcalls(void)
{
	int level;

	for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
		do_initcall_level(level);
}

//遍历同等级的初始化函数

static void __init do_initcall_level(int level)
{
	extern const struct kernel_param __start___param[], __stop___param[];
	initcall_t *fn;

	strcpy(static_command_line, saved_command_line);
	parse_args(initcall_level_names[level],
		   static_command_line, __start___param,
		   __stop___param - __start___param,
		   level, level,
		   repair_env_string);

	for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
		do_one_initcall(*fn);
}

//执行一个初始化函数

int __init_or_module do_one_initcall(initcall_t fn)
{
	int count = preempt_count();
	int ret;

	if (initcall_debug)
		ret = do_one_initcall_debug(fn);
	else
		ret = fn();//执行具体的初始化函数

	msgbuf[0] = 0;

	if (ret && ret != -ENODEV && initcall_debug)
		sprintf(msgbuf, "error code %d ", ret);

	if (preempt_count() != count) {
		strlcat(msgbuf, "preemption imbalance ", sizeof(msgbuf));
		preempt_count() = count;
	}
	if (irqs_disabled()) {
		strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf));
		local_irq_enable();
	}
	if (msgbuf[0]) {
		printk("initcall %pF returned with %s\n", fn, msgbuf);
	}

	return ret;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值