简单分析Linux内核基础篇——initcall

写过Linux驱动的人都知道module_init宏,因为它声明了一个驱动的入口函数。

除了module_init宏,你会发现在Linux内核中有许多的驱动并没有使用module_init宏来声明入口函数,而是看到了许多诸如以下的声明:

static int __init qcom_iommu_init(void)
{
 int ret;

 ret = platform_driver_register(&qcom_iommu_ctx_driver);
 if (ret)
  return ret;

 ret = platform_driver_register(&qcom_iommu_driver);
 if (ret)
  platform_driver_unregister(&qcom_iommu_ctx_driver);

 return ret;
}
device_initcall(qcom_iommu_init);
static int __init ebsa110_init(void)
{
 arm_pm_idle = ebsa110_idle;
 return platform_add_devices(ebsa110_devices, ARRAY_SIZE(ebsa110_devices));
}

arch_initcall(ebsa110_init);

上述举例的两个驱动入口分别使用了device_initcall()和arch_initcall()来声明驱动入口,这些本质上都是对initcall的调用,module_init也如此。

initcall等级

Linux内核对initcall进行了等级划分,每一种类型的initcall都有对应等级,等级0-7。

路径:include/init/init.h

/* initcalls are now grouped by functionality into separate 
 * subsections. Ordering inside the subsections is determined
 * by link order. 
 * For backwards compatibility, initcall() puts the call in 
 * the device init subsection.
 *
 * The `id' arg to __define_initcall() is needed so that multiple initcalls
 * can point at the same handler without causing duplicate-symbol build errors.
 */

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

id越小等级越高,Linux会按照等级由高到低顺序执行:

/*
 * Early initcalls run before initializing SMP.
 *
 * Only for built-in code, not modules.
 */
#define early_initcall(fn)  __define_initcall(fn, early)

/*
 * A "pure" initcall has no dependencies on anything else, and purely
 * initializes variables that couldn't be statically initialized.
 *
 * This only exists for built-in code, not for modules.
 * Keep main.c:initcall_level_names[] in sync.
 */
#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)

这么做的目的主要是根据优先级依次对设备进行初始化,例如会先初始化与架构相关的,然后再初始化内核子系统。

资料直通车:Linux内核源码技术学习路线+视频教程内核源码

学习直通车:Linux内核源码内存调优文件系统进程管理设备驱动/网络协议栈

Linux对initcall的调用

在Linux启动时,会依次遍历所有等级的initcall,以完成一系列的初始化。

initcall的调用流程:

start_kernel->
   kernel_init->
      kernel_init_freeable->
         do_basic_setup->
            do_initcalls->
               do_initcall_level()

在do_initcalls()函数中,会遍历所有等级的initcall,完成初始化。

static void __init do_initcalls(void)
{
 int level;
 size_t len = strlen(saved_command_line) + 1;
 char *command_line;

 command_line = kzalloc(len, GFP_KERNEL);
 if (!command_line)
  panic("%s: Failed to allocate %zu bytes\n", __func__, len);

    //遍历所有等级的initcall,level变量对应等级
 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);
}

do_initcall_level()会执行对应等级下的所有函数:

static void __init do_initcall_level(int level, char *command_line)
{
 initcall_entry_t *fn;

 parse_args(initcall_level_names[level],
     command_line, __start___param,
     __stop___param - __start___param,
     level, level,
     NULL, ignore_unknown_bootoption);

 trace_initcall_level(initcall_level_names[level]);
 for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
  do_one_initcall(initcall_from_entry(fn));
}

module_init等级

module_init宏使用的是device_initcall,等级为6:

#define device_initcall(fn)  __define_initcall(fn, 6)
......
#define __initcall(fn) device_initcall(fn)
......
#define module_init(x) __initcall(x);

在一些内核驱动中,直接使用了device_initcall()来声明驱动入口,其效果与使用module_init是一样的。

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/2090.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java之类与对象(图文结合)

目录 一、面向对象的初步认知 1、什么是面向对象 2、面向对象与面向过程 二、类定义和使用 1、简单认识类 2、类的定义格式 3、练习 &#xff08;1&#xff09;定义一个狗类 &#xff08;2&#xff09;定义一个学生类 三、类的实例化 1、什么是实例化 2、类和对象的…

CSDN 周赛38期题解

CSDN 周赛38期题解1、题目名称&#xff1a;代写匿名信2、题目名称&#xff1a;寻因找祖3、题目名称&#xff1a;小Q新式棋盘4、题目名称&#xff1a;拯救公主结束语1、题目名称&#xff1a;代写匿名信 小Q想要匿名举报XX领导不务正业&#xff01; 小Q害怕别人认出他的字迹。 他…

【数据结构】Java实现双向链表

目录 1. 接口的实现 2. 动手实现双链表 2.1 重写SeqList接口方法 2.2 在当前链表尾部添加节点&#xff08;尾插&#xff09; 2.3 在当前链表头部添加节点&#xff08;头插&#xff09; 2.4 检验index是否合法 2.5 在 第index位置添加节点&#xff08;任意位置&#xff09; 2.6 …

【精品】华为认证数通HCIA+HCIP题库分享(含答案解析)

嗨~大家好久不见&#xff0c;我是薄荷学姐&#xff0c;随着华为业务也全球领域的迅猛发展&#xff0c;越来越多人开始重视华为认证的重要性。今天给大家分享一下去年8月份的题库&#xff0c;基本都是一样&#xff0c;希望可以帮助到大家哈想要通过华为认证&#xff0c;除了进行…

gdb调试工具和makemakefile工具

gdb调试工具和make/makefile工具 文章目录gdb调试工具和make/makefile工具一、gdb调试工具1.debug/release2.使用二、make/makefile1.什么是make/makefile2.编写一、gdb调试工具 1.debug/release 程序有两种默认的发布方式debug和release。release是无法进行调试的。Linux中g…

Bing+ChatGPT 对传统搜索引擎的降维打击

早些时候申请了新版 Bing 的内测资格&#xff0c;终于收到了通过的邮件。 一天的体验之后&#xff0c;我的感受是&#xff1a;当新版 Bing 具备了 ChatGPT 的聊天能力之后&#xff0c;它的能力不论是对传统搜索引擎&#xff0c;还是 ChatGPT 自身&#xff0c;都将是降维打击。 …

菜鸟刷题Day3

⭐作者&#xff1a;别动我的饭 ⭐专栏&#xff1a;菜鸟刷题 ⭐标语&#xff1a;悟已往之不谏&#xff0c;知来者之可追 一.字符串压缩&#xff1a;面试题 01.06. 字符串压缩 - 力扣&#xff08;LeetCode&#xff09; 描述 字符串压缩。利用字符重复出现的次数&#xff0c;编…

Python程序员看见一个好看的手机壁纸网站,开撸!

人生苦短&#xff0c;我用python 最近好像没什么大事&#xff0c; .那就采集一下小——姐——姐————看下吧~ python 安装包资料:点击此处跳转文末名片获取 最近有同学的爬虫代码出了bug&#xff0c;给问我怎么改 于是就发现了这个好看的手机壁纸网站。 这个图片应该是违规…

【Unity工具,简单学习】PUN 2,多人在线游戏开发,初步使用

【Unity工具&#xff0c;简单学习】PUN 2&#xff0c;多人在线网络工具前言简单介绍安装简单使用一些 nomenclature 部分连接到 Server设置简单的大厅UI游戏场景搭建关卡加载事后前言 链接 简单介绍 PUN 可以让你简单地开发多人游戏&#xff0c;在全球范围推出 让开发者不用…

【Java学习笔记】38.Java 发送邮件

Java 发送邮件 使用Java应用程序发送 E-mail 十分简单&#xff0c;但是首先你应该在你的机器上安装 JavaMail API 和Java Activation Framework (JAF) 。 您可以从 Java 网站下载最新版本的 JavaMail&#xff0c;打开网页右侧有个 Downloads 链接&#xff0c;点击它下载。 您…

MySQL注入秘籍【上篇】

MySQL注入秘籍【上篇】1.数据库敏感信息常用语句2.联合(UNION)查询注入3.报错注入原理常见报错注入函数1.数据库敏感信息常用语句 获取数据库版本信息 select version(); select innodb_version;获取当前用户 select user();获取当前数据库 select database()&#xff1b;数…

高数重点总结

高数 公式不要去死记 配合训练题在训练中记忆 完成一下这些题目 高中函数图像回忆 与其记忆各种公式不如去思考他们的本质 这和调用c动态库可不一样 考试的时候你相当于在使用汇编答题 1 定义域&#xff08;x&#xff09; 性质 1/x(x!0)√x(x>0 || x0)log a x (x>…

血氧仪是如何得出血氧饱和度值的?

目录 一、血氧饱和度概念 二、血氧饱和度监测意义 三、血氧饱和度的监测方式 四、容积脉搏波计算血氧饱和度原理 五、容积脉搏波波形的测量电路方案 1&#xff09;光源和光电探测器的集成测量模块&#xff1a;SFH7050—反射式 2&#xff09;模拟前端 六、市面上血氧仪类型…

Spring 源码解析 - Bean创建过程 以及 解决循环依赖

一、Spring Bean创建过程以及循环依赖 上篇文章对 Spring Bean资源的加载注册过程进行了源码梳理和解析&#xff0c;我们可以得到结论&#xff0c;资源文件中的 bean 定义信息&#xff0c;被组装成了 BeanDefinition 存放进了 beanDefinitionMap 容器中&#xff0c;那 Bean 是…

图形视图框架QGraphicsScene(场景,概念)

QGraphicsScene 该类充当 QGraphicsItems 的容器。它与 QGraphicsView 一起使用&#xff0c;用于在 2D 表面上可视化图形项目&#xff0c;例如线条、矩形、文本甚至自定义项目。 QGraphicsScene具有的功能&#xff1a; 提供用管理大量数据项的高速接口传播事件到每一个图形项…

艹,终于在8226上把灯点亮了

接上次点文章ESP8266还可以这样玩这次&#xff0c;我终于学会了在ESP8266上面点亮LED灯了现在一个单片机的价格是几块&#xff0c;加上一个晶振&#xff0c;再来一个快递费&#xff0c;十几块钱还是需要的。所以能用这个ESP8266来当单片机玩&#xff0c;还是比较不错的可以在ub…

【设计模式】创建型设计模式

文章目录1. 基础①如何学习设计模式② 类模型③ 类关系2. 设计原则3. 模板方法① 定义②背景③ 要点④ 本质⑤ 结构图⑥ 样例代码4. 观察者模式① 定义②背景③ 要点④ 本质⑤ 结构图⑥ 样例代码5. 策略模式① 定义②背景③ 要点④ 本质⑤ 结构图⑥ 样例代码1. 基础 ①如何学习…

三维电子沙盘数字沙盘开发教程第7课

三维电子沙盘数字沙盘大数据人工智能开发教程第7课设置system.ini 如下内容Server122.112.229.220userGisTestPasswordchinamtouch.com该数据库中只提供 成都市火车南站附近的数据请注意&#xff0c;104.0648,30.61658利用三方工具&#xff0c;如幻影粒子&#xff1a;或者flash…

python例程:《彩图版飞机大战》程序

目录开发环境要求运行方法《彩图版飞机大战》程序使用说明源码示例源码及说明文档下载路径开发环境要求 本系统的软件开发及运行环境具体如下。 操作系统&#xff1a;Windows 7、Windows 10。 Python版本&#xff1a;Python 3.7.1。 开发工具&#xff1a;PyCharm 2018。…

软件测试拿了几个20K offer,分享一波面经

1、你的测试职业发展是什么? 测试经验越多&#xff0c;测试能力越高。所以我的职业发展是需要时间积累的&#xff0c;一步步向着高级测试工程师奔去。而且我也有初步的职业规划&#xff0c;前3年积累测试经验&#xff0c;按如何做好测试工程师的要点去要求自己&#xff0c;不断…