【linux kernel】linux内核重要函数 do_initcalls_linux 内核函数

收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
img
img

如果你需要这些资料,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

	do\_initcall\_level(level);

}


函数中内容比较少,是一个`for`循环结构,循环的对象是`initcall_levels`数组,该数组用于描述初始化调用的级别,定义如下:



extern initcall_t __initcall_start[];
extern initcall_t __initcall0_start[];
extern initcall_t __initcall1_start[];
extern initcall_t __initcall2_start[];
extern initcall_t __initcall3_start[];
extern initcall_t __initcall4_start[];
extern initcall_t __initcall5_start[];
extern initcall_t __initcall6_start[];
extern initcall_t __initcall7_start[];
extern initcall_t __initcall_end[];

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


从上述代码可见,`initcall_levels`数组中的元素为initcall\_t类型的指针,回到`do_initcalls()`函数中,该函数的核心操作是:按顺序从`__initcall0_start`开始,到`__initcall_end`结束的节段中取出存在不同段之间的函数,并执行。存在这几个初始化调用段之间的函数都是各个模块的初始化函数,而这些函数是如何加入到初始化调用段中的呢?又是如何设置调用级别的,会在后文中描述到。


在`do_initcalls()`函数中,会根据`initcall_levels`初始化调用级别的数量调用`do_initcall_level()`,该函数实现如下:



static void __init do_initcall_level(int level)
{
initcall_t *fn;

strcpy(initcall_command_line, saved_command_line);
parse\_args(initcall_level_names[level],
	   initcall_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);

}


从上述代码可见,在函数的最后是一个for循环结构,该循环的操作对象为函数指针,且会将对应的函数指针传递到`do_one_initcall`中,在该函数则会执行函数指针所指向的函数:


![](https://img-blog.csdnimg.cn/img_convert/205335b6bbae048b7bb9e485ef21afae.png)


### 三、构造section并添加函数


#### (3-1)构造初始化调用section


在linux内核中,不同架构(ARCH)下的kernel目录中,都会有一个名为`vmlinux.lds.S`的链接脚本,初始化调用section的构造则在该链接脚本中完成。



> 
> 本文以ARM32架构为例
> 
> 
> 


在/arch/arm/kernel/vmlinux.lds.S中的链接脚本中,在`.init.data`输出节段中则需要`INIT_CALLS`作为输入节段:


![](https://img-blog.csdnimg.cn/img_convert/6ceb1357cf99774278fb3e73c4975217.png)


`INIT_CALLS`定义在/include/asm-generic/vmlinux.lds.h文件中:


![](https://img-blog.csdnimg.cn/img_convert/f36d022322512fd46d35a635d348c7d8.png)


而在内核的makefile中有以下语句:



LDFLAGS_vmlinux += -T arch/$(ARCH)/kernel/vmlinux.lds.s


指定了构建linux内核镜像时所使用的链接脚本,基于此,则会构造好初始化调用section。当初始化调用section构造完成后,是如何向该section中添加函数的呢?继续往下看。


#### (3-2)向section中添加函数


向section中添加函数的本质操作则是`__define_initcall()`,定义如下:


![](https://img-blog.csdnimg.cn/img_convert/a64029dfcc518b672351d94800bb3076.png)


然后linux内核会基于`__define_initcall()`封装出多个宏定义接口,供内核中各个模块使用,接口如下:


![](https://img-blog.csdnimg.cn/img_convert/b051c657d5abc1a0d4ef702cfcd9cd54.png)


`__define_initcall()`宏定义的本质则是定义一个`initcall_t`函数指针类型的变量并命名为`__initcall_##fn##id`,其中fn为赋值给该变量的函数名称,id为初始化调用级别,然后并将fn赋值给该变量。接着就是最为重要的技术点:使用`__attribute__`将该变量加入到命名为"initcall##id.init"的section中,其中id为初始化调用级别,所以将fn添加到初始化调用section中则是通过这一点实现。例如:如果有以下类似的代码:



static void __init show_info(void)
{
printk(“I’m iriczhao \n”)
}

core_initcall(show_info);

收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
img
img

如果你需要这些资料,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

](https://bbs.csdn.net/topics/618679757)**

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 25
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: "do_initcalls" 是 Linux 内核启动过程中的另一个重要函数,它负责执行内核初始化时注册的各种初始化函数。这些函数通常是由内核模块或者其他内核组件注册的,它们会在内核启动过程中被依次调用,以完成特定的初始化任务。这些初始化函数的执行顺序是由它们在注册时指定的优先级决定的,优先级越高的函数会先被执行。这个函数的执行标志着内核启动过程的正式结束,此时内核已经完成了所有的初始化工作,并进入了正常的工作状态。 ### 回答2: do_initcalls是Linux系统中的一个函数,用于初始化系统中的各个子系统和驱动程序。它在内核启动时被调用,并按照特定的顺序执行各个初始化函数。 do_initcalls的作用是按照依赖关系递归地调用所有的初始化函数。这些初始化函数被定义在不同的模块中,它们通常用宏定义(initcall)注册到do_initcalls中。在系统启动过程中,do_initcalls会按照它们的注册顺序调用这些初始化函数。 在调用这些初始化函数之前,do_initcalls会先调用一些内核的核心初始化函数,以确保系统的基本功能正常工作。然后,它按照特定的顺序调用模块初始化函数,这些函数初始化各个子系统和驱动程序。这种依赖关系可以确保在调用某个初始化函数之前,所依赖的其他模块已经完成初始化。这样可以避免因为初始化顺序问题导致的功能异常或系统崩溃。 通过do_initcalls函数的调用,系统可以自动地按照一定的顺序初始化各个子系统和驱动程序,简化了系统的初始化过程。它的作用是确保系统能够按照正确的顺序完成初始化工作,并且各个模块之间的依赖关系得到满足。 总之,do_initcalls是Linux系统中的一个重要函数,它的作用是按照依赖关系调用初始化函数,确保系统能够正常运行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值