linux子系统的初始化_subsys_initcall():那些入口函数

《5.linux驱动开发-第4部分-5.4.驱动框架入门之LED》真正的驱动开发 从 今天的 课程开始!!!5.4.1.何谓驱动框架 subsys_initcall led_class_attrs 真正的驱动开发 从 今天的 课程开始!!!(1)驱动开发工程师内核开发者 预留一些 驱动开发的接口,让我们来使用合作(2)内核维护者5.4.1.2、驱动编程协作要求(1)接口标准化(2)尽量降低驱动开发者难度5.4.1.3、到底什么是驱动框架驱动框架:部分厂家相同的一部分内核维护者已经写好了,再把不同的部分预留好接口,让驱动开发工程师来写。 阅读详情

内核选项解析完成之后,各个子系统的初始化即进入第二部分—-入口函数的调用。通常USB、PCI这样的子系统都会有一个名为subsys_initcall的入口,如果你选择它们作为研究内核的切入点,那么就请首先找到它。

以下代码来自 linux内核源码中 include/linux/init.h 文件:

  1. 117 #define pure_initcall(fn) __define_initcall("0",fn,1)
  2. 118 
  3. 119 #define core_initcall(fn) __define_initcall("1",fn,1)
  4. 120 #define core_initcall_sync(fn) __define_initcall("1s",fn,1s)
  5. 121 #define postcore_initcall(fn) __define_initcall("2",fn,2)
  6. 122 #define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)
  7. 123 #define arch_initcall(fn) __define_initcall("3",fn,3)
  8. 124 #define arch_initcall_sync(fn) __define_initcall("3s",fn,3s)
  9. 125 #define subsys_initcall(fn) __define_initcall("4",fn,4)
  10. 126 #define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s)
  11. 127 #define fs_initcall(fn) __define_initcall("5",fn,5)
  12. 128 #define fs_initcall_sync(fn) __define_initcall("5s",fn,5s)
  13. 129 #define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)
  14. 130 #define device_initcall(fn) __define_initcall("6",fn,6)
  15. 131 #define device_initcall_sync(fn) __define_initcall("6s",fn,6s)
  16. 132 #define late_initcall(fn) __define_initcall("7",fn,7)
  17. 133 #define late_initcall_sync(fn) __define_initcall("7s",fn,7s)
  18. 134 
  19. 135 #define __initcall(fn) device_initcall(fn)

这些入口有个共同的特征,它们都是使用__define_initcall宏定义的。它们的调用也不是随便的,而是按照一定顺序的,这个顺序就取决于__define_initcall宏。__define_initcall宏用来将指定的函数指针放到.initcall.init节里。

.initcall.init节

内核可执行文件由许多链接在一起的对象文件组成。对象文件有许多节,如文本、数据、init数据、bass等等。这些对象文件都是由一个称为链接器脚本的文件链接并装入的。这个链接器脚本的功能是将输入对象文件的各节映射到输出文件中;换句话说,它将所有输入对象文件都链接到单一的可执行文件中,将该可执行文件的各节装入到指定地址处。 vmlinux.lds是存在于arch/<target>/目录中的内核链接器脚本,它负责链接内核的各个节并将它们装入内存中特定偏移量处。在vmlinux.lds文件里查找initcall.init就可以看到下面的内容:

 

  1. __inicall_start = .;
  2. .initcall.init : AT(ADDR(.initcall.init) – 0xC0000000) {
  3. *(.initcall1.init)
  4. *(.initcall2.init)
  5. *(.initcall3.init)
  6. *(.initcall4.init)
  7. *(.initcall5.init)
  8. *(.initcall6.init)
  9. *(.initcall7.init)
  10. }
  11. __initcall_end = .;

这就告诉我们.initcall.init节又分成了7个子节,而xxx_initcall入口函数指针具体放在哪一个子节里边儿是由xxx_initcall的定义中,__define_initcall宏的参数决定的,比如core_initcall将函数指针放在.initcall1.init子节,device_initcall将函数指针放在了.initcall6.init子节等等。各个子节的顺序是确定的,即先调用.initcall1.init中的函数指针再调用.initcall2.init中的函数指针,等等。不同的入口函数被放在不同的子节中,因此也就决定了它们的调用顺序。

注意:设备驱动程序中常见的module_init(x)函数,查看init.h文件发现:

#define module_init(x)__initcall(x);

#define __initcall(fn) device_initcall(fn)

#define device_initcall(fn) __define_initcall("6",fn,6)

这样推断 module_init 调用优先级为6低于subsys_initcall调用优先级4.


do_initcalls()函数

那些入口函数的调用由do_initcalls函数来完成。do_initcall函数通过for循环,由__initcall_start开始,直到__initcall_end结束,依次调用识别到的初始化函数。而位于__initcall_start和__initcall_end之间的区域组成了.initcall.init节,其中保存了由xxx_initcall形式的宏标记的函数地址,do_initcall函数可以很轻松的取得函数地址并执行其指向的函数。.initcall.init节所保存的函数地址有一定的优先级,越前面的函数优先级越高,也会比位于后面的函数先被调用。由do_initcalls函数调用的函数不应该改变其优先级状态和禁止中断。因此,每个函数执行后,do_initcalls会检查该函数是否做了任何变化,如果有必要,它会校正优先级和中断状态。另外,这些被执行的函数有可以完成一些需要异步执行的任务,

flush_scheduled_work函数则用于确保do_initcalls函数在返回前等待这些异步任务结束。

    666 static void __init do_initcalls(void)
    667 {
    668 initcall_t *call;
    669 int count = preempt_count();
    670 
    671 for (call = __initcall_start; call < __initcall_end; call++) {
    672 ktime_t t0, t1, delta;
    673 char *msg = NULL;
    674 char msgbuf[40];
    675 int result;
    676 
    677 if (initcall_debug) {
    678 printk("Calling initcall 0x%p", *call);
    679 print_fn_descriptor_symbol(": %s()",
    680 (unsigned long) *call);
    681 printk("/n");
    682 t0 = ktime_get();
    683 }
    684 
    685 result = (*call)();
    686 
    687 if (initcall_debug) {
    688 t1 = ktime_get();
    689 delta = ktime_sub(t1, t0);
    690 
    691 printk("initcall 0x%p", *call);
    692 print_fn_descriptor_symbol(": %s()",
    693 (unsigned long) *call);
    694 printk(" returned %d./n", result);
    695 
    696 printk("initcall 0x%p ran for %Ld msecs: ",
    697 *call, (unsigned long long)delta.tv64 >> 20);
    698 print_fn_descriptor_symbol("%s()/n",
    699 (unsigned long) *call);
    700 }
    701 
    702 if (result && result != -ENODEV && initcall_debug) {
    703 sprintf(msgbuf, "error code %d", result);
    704 msg = msgbuf;
    705 }
    706 if (preempt_count() != count) {
    707 msg = "preemption imbalance";
    708 preempt_count() = count;
    709 }
    710 if (irqs_disabled()) {
    711 msg = "disabled interrupts";
    712 local_irq_enable();
    713 }
    714 if (msg) {
    715 printk(KERN_WARNING "initcall at 0x%p", *call);
    716 print_fn_descriptor_symbol(": %s()",
    717 (unsigned long) *call);
    718 printk(": returned with %s/n", msg);
    719 }
    720 }
    721 
    722 /* Make sure there is no pending stuff from the initcall sequence */
    723 flush_scheduled_work();
    724 }


目前研究Linux驱动程序的启动流程,这篇文章对Linux子系统调用顺序进行了详细的讲解,同时也说明了设备驱动程序的调用顺序,很值得收藏。

linux驱动开发扩展--module_init与subsys_initcall详解 __init include/linux/init.h #define __init __section(.init.text) __cold notrace 将用__init修饰的函数放到.init.text段(通过后面的分析可以知道这个段里的东西在被初始化时调用一次之后为了节省内存就被释放掉了) #define __cold __attribute__((__cold__))。函数前面使用这个扩展,表示该函数比较冷门,这样在分支预测机制里就不会对该函数进行预取,或说是... 阅读详情

相关推荐

Linux内核中的初始化initcall

由于在下水平相当有限,不当之处,还望大家批评指正^_^ 基于Linux 2.6.32 include\asm-generic\Vmlinux.lds.h中有如下定义: 这等于是安排了名称如.initcall[s].init的一系列section的顺序,level越小,越靠前。 符号__initcall_start记录了这片区域的开始,__initcall_end符号记录了这

无忧老猪 3876

subsys_initcall

subsys_initcall linux子系统的初始化_subsys_initcall():那些入口函数【转】 https://blog.youkuaiyun.com/u010388659/article/details/81265010 内核选项的解析完成之后,各个子系统的初始化即进入第二部分—入口函数的调用。通常USB、PCI这样的子系统都会有一个名为subsys_initcall的...

weixin_42082222的博客 2761

Linux内核initcall机制详解与驱动初始化实践

Linux内核的初始化机制是操作系统启动过程中的关键技术,其中initcall作为核心架构,通过分级管理确保各子系统按正确顺序初始化。该机制利用GCC的section属性和链接器脚本,将初始化函数按优先级分类存放,从pure_initcall(0)到late_initcall(7)共8个等级。在驱动开发中,module_init宏实质是device_initcall(6)的别名,而直接使用特定等级的initcall可以精确控制初始化时序。理解initcall的分级原理和执行流程,对于解决驱动依赖关系、优化启

weixin_35370061的博客 607

系统初始化函数集(subsys_initcall)和初始化段应用

参考博文: https://blog.youkuaiyun.com/jackaly/article/details/7426353 https://blog.youkuaiyun.com/qlexcel/article/details/92656797 1.函数定义(subsys_initcall/late_initcall是什么) 内核代码4.14.99/include/linux/init.h,需要注意的是这里只针对build-in code,所以代码加上了#ifndef MODULE的限制 我们用C代码

liaojunwu的博客 1373

linux模块(module_init)、子系统(subsys_initcall)入口函数详解

linux内核代码是以模块(module)和子系统(subsys)为单元的层次结构。在写模块代码时我们知道入口函数是module_init()或subsys_initcall(),在linux启动时会被调用,这其中更为详细的前因后果是什么呢,一起来了解一下。 一,linux模块程序示例 下面是一个linux模块的示例程序: #include #include MODUL

Radia的专栏 3165

2.13寸电子墨水屏HINK-E0213+esp8266

很久以前买的一块电子墨水屏,运气很好,这个型号HINK-E0213资料很全,而且微雪官网也有相关电路资料等。

梦境虽美,却不长. 3002

linux子系统的初始化_subsys_initcall()

这就告诉我们.initcall.init节又分成了7个子节,而xxx_initcall入口函数指针具体放在哪一个子节里边儿是由xxx_initcall的定义中,__define_initcall宏的参数决定的,比如core_initcall将函数指针放在.initcall1.init子节,device_initcall将函数指针放在了.initcall6.init子节等等。各个子节的顺序是确定的,即先调用.initcall1.init中的函数指针再调用.initcall2.init中的函数指针,等等。

uunubt的专栏 446

微生物组β-多样性——PCoA分析及可视化

让你的数据映入眼帘

qq_47369980的博客 1万+

对于内核中各种xxx_initcall调用的分析———linux子系统初始化

对应内核版本  linux-2.6.32.63, 架构arm(版本较老,但已经属于2.6以后的版本了)。 一、 xxx_initcall是一系列子系统的初始化入口函数 对应文件include/linux/init.h #define early_initcall(fn)           __define_initcall("early",fn,early) #de

fridayLL的专栏 2303

JLink 添加国产芯片手把手教程(雅特力 + 华大)

拷贝厂商算法文件夹 + 配置 JLinkDevices.xml。雅特力直接复制官方配置,华大按需添加芯片节点,操作一次,永久生效,以后调试 AT32、HC32 再也不用愁找不到型号。这套方法适配全版本 JLink,也是国产 MCU 替代项目的必备技能,看完照着做,新手也能轻松搞定。百度网盘资料分享:通过网盘分享的文件:jink驱动(包括新增芯片型号)链接: https://pan.baidu.com/s/14SLgrPfyof1lglD6VQguAw?pwd=cfuq 提取码: cfuq。

weixin_48867130的博客 709

linux子系统的初始化,linux子系统的初始化_subsys_initcall()

概述内核选项的解析完成之后,各个子系统的初始化即进入第二部分—入口函数的调用。通常USB、PCI这样的子系统都会有一个名为subsys_initcall的入口,如果你选择它们作为研究内核的切入点,那么就请首先找到它。section的声明C 语言中attribute属性的section是在目标文件链接时可以用于主动定制代码的位置,具体可以WIKI,下面看linux kernel中是如何定义的。以下代...

weixin_39640767的博客 272

抖音直播参数逆向实战:手把手教你用Python获取ttwid和x-bogus(附完整代码)

本文深入解析抖音直播接口的反爬机制,重点剖析核心防护参数ttwid和x-bogus的生成原理与作用。通过Python实战,手把手教你逆向获取ttwid、webid等关键参数,并构建稳定的数据采集方案,为开发者提供企业级数据获取能力。

weixin_29196891的博客 1043

【Linux】内核宏定义解释postcore_initcall,arch_initcall,subsys_initcall

是一个宏,用于在Linux内核初始化过程中注册一个后期初始化函数。是一个宏定义,用于指定注册的函数在内核初始化的哪个阶段执行。是要注册的函数的名称,它是一个后期初始化函数。后期初始化函数是在内核初始化过程的最后阶段执行的函数。这些函数通常用于执行一些需要在其他子系统初始化之后才能进行的操作。截图汇总,是一个后期初始化函数,可能用于初始化PCI总线的相关内容。通过调用宏将后期初始化函数注册到内核中,可以确保在内核初始化的最后阶段执行该函数,从而完成相应的后期初始化工作。

逆风水手的博客 1969

第一篇:APS智能排产理论核心与求解器选型指南

本文系统解析了APS(高级计划与排程)系统的核心功能与技术实现。APS作为融合生产计划与排程的智能决策系统,通过运筹优化算法实现全局最优,平衡交付与效率。重点探讨了混合整数线性规划(MILP)在APS中的应用,包括设备分配、生产批量和人员班次优化等场景,并分析了其局限性与其他算法(如启发式算法)的互补性。文章还提供了APS实施策略建议和优化建模技巧,强调从简单模型开始迭代验证的重要性。最后介绍了甘特图在APS中的多维可视化作用,包括计划调整和决策支持功能。全文为理解APS系统原理及实践应用提供了全面指导。

算法工程师 544

(十一)随机性与独立性回顾

随机性与独立性回顾

旺旺的碎冰冰~的博客 1017

说说subsys_initcall

 在linux内核代码里, 到处充满了subsys_initcall,这个调用是用来干吗的呢?有人回答是系统启动时候用来初始化某些系统的,具体怎么初始化的呢,说起来还是有点复杂。以2.6.21内核作为例子。在linux/init.h里,有这样一段代码:#define pure_initcall(fn)  __define_initcall("0",fn,1)#define core_i

8909

【WRF安装】WRF编译错误:problems building executables look for error in the build log

WRF编译错误:problems building executables look for error in the build log

WW、forever的博客 752

postcore_initcall(), arch_initcall(), subsys_initcall(), device_initcall() 调用顺序

在内核源代码中,platform 设备的初始化(注册)用arch_initcall()调用,它的initcall 的level为3; 而驱动的注册用module_init()调用,即device_initcall(),它的initcall 的level为6。 #define module_init(x)__initcall(x); #define __initcall(fn) device_initcall(fn) kernel 初始化时(kernel_init@init/main.c),按照内核...

boyemachao的专栏 1605

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

各种initcall的执行先后顺序(module_init、postcore_initcall、arch_initcall、subsys_initcall、 fs_initcall)

现在以module_init为例分析initcall在内核中的调用顺序 在头文件init.h中,有如下定义: #define module_init(x)     __initcall(x); 很明显,module_init()只是一个面具而已,揭开这个面具,下面藏着的是_

fenzhikeji的专栏 3万+

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

module_init subsys_initcall与late_initcall的区别

kernel-4.4\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) #defi...

每一个不曾起舞的日子,都是对生命的辜负 2001

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

linux内核__define_initcall分析

在阅读linux内核代码的过程中经常会看到驱动代码中在最后调用arch_initcall subsys_initcall module_init等函数,虽然知道这些函数是来确定驱动在内核启动过程中的加载顺序的,但是没有仔细看过实现原理,借清明节空闲来看一下具体实现,以mips处理器2.6.21内核为例。   在linux/init.h中可以看到以下代码: /* initcalls ar

做一个有技术追求的人 6468

linux内核中的subsys_initcall是干什么的?

注意:使用的内核源码版本为5.1.3 1. subsys_initcall长什么样子?   它其实是个宏定义,定义如下:     #define subsys_initcall(fn) __define_initcall(fn, 4) (注意,这是使用在内置模块中的)     或     #define subsys_initcall(fn) module_init(f...

weixin_30599769的博客 699

Linux 内核揭秘:initcall 机制,内核初始化函数的调用顺序

你是否曾好奇 Linux 内核启动时,成百上千的初始化函数是如何有条不紊地执行的?为何有些驱动总是在特定服务之前加载?本文将深入解析内核初始化的核心机制——initcall,带你揭开函数调用顺序的神秘面纱。读完本文,你将掌握:initcall 等级划分规则、优先级控制方法、实战调试技巧,以及如何在自己的内核模块中合理使用 initcall 机制。 ## initcall 机制的核心价值 在 L...

gitblog_00981的博客 963
上一篇: android cts 目录
下一篇: 蓝牙物理链路类型:SCO和ACL链路
it_passioner
博客等级 码龄14年 23粉丝 8原创
评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值