内核版本:linux-4.19

上一篇文章提到了这段代码:

  1. arch_initcall_sync(of_platform_default_populate_init);

它的功能是完成 device_node 到 platform_device 的转换。这篇文章就来大概的分析一下,它是怎样被调用的。

arch_initcall_sync 定义如下:

  1. #define ___define_initcall(fn, id, __sec) \
  2. static initcall_t __initcall_##fn##id __used \
  3. __attribute__((__section__(#__sec ".init"))) = fn;
  4. #define __define_initcall(fn, id) ___define_initcall(fn, id, .initcall##id)
  5. #define arch_initcall_sync(fn) __define_initcall(fn, 3s)

根据 LDS 文件的定义,会将这些 data 存储在指定的位置:

  1. #define INIT_CALLS_LEVEL(level) \
  2. __initcall##level##_start = .; \
  3. KEEP(*(.initcall##level##.init)) \
  4. KEEP(*(.initcall##level##s.init)) \
  5. #define INIT_CALLS \
  6. __initcall_start = .; \
  7. KEEP(*(.initcallearly.init)) \
  8. INIT_CALLS_LEVEL(0) \
  9. INIT_CALLS_LEVEL(1) \
  10. INIT_CALLS_LEVEL(2) \
  11. INIT_CALLS_LEVEL(3) \
  12. INIT_CALLS_LEVEL(4) \
  13. INIT_CALLS_LEVEL(5) \
  14. INIT_CALLS_LEVEL(rootfs) \
  15. INIT_CALLS_LEVEL(6) \
  16. INIT_CALLS_LEVEL(7) \
  17. __initcall_end = .;

在内核中,想要调用到这些数据,就会用到

  1. __initcall##level##_start = .;

这个标识。

数据的位置已经搞定了,那么内核又是怎样调用的呢?接下来找到这些函数调用。

调用流程如下:

  1. start_kernel
  2. -->rest_init
  3. -->kernel_thread(kernel_init, NULL, CLONE_FS);
  4. -->kernel_init
  5. -->kernel_init_freeable
  6. -->do_basic_setup
  7. -->do_initcalls
  8. -->do_initcall_level

do_initcall_level 代码如下:

  1. static void __init do_initcall_level(int level)
  2. {
  3. initcall_entry_t *fn;
  4. strcpy(initcall_command_line, saved_command_line);
  5. parse_args(initcall_level_names[level],
  6. initcall_command_line, __start___param,
  7. __stop___param - __start___param,
  8. level, level,
  9. NULL, &repair_env_string);
  10. trace_initcall_level(initcall_level_names[level]);
  11. for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
  12. do_one_initcall(initcall_from_entry(fn));
  13. }

根据下表,分别调用 do_one_initcall 来执行每一个 initcall。

  1. static initcall_entry_t *initcall_levels[] __initdata = {
  2. __initcall0_start,
  3. __initcall1_start,
  4. __initcall2_start,
  5. __initcall3_start,
  6. __initcall4_start,
  7. __initcall5_start,
  8. __initcall6_start,
  9. __initcall7_start,
  10. __initcall_end,
  11. };

表中的 xxx_start 恰恰就是前面所提到的存储标识,那么这些调用就联系到了一起,实现函数的调用。

分析到这里,相信关于 xxx_initcall 调用的云雾就已经拨开了吧!

内核中 xxx_initcall 的调用过程分析的更多相关文章

  1. 浅析linux内核中timer定时器的生成和sofirq软中断调用流程(转自http://blog.chinaunix.net/uid-20564848-id-73480.html)

    浅析linux内核中timer定时器的生成和sofirq软中断调用流程 mod_timer添加的定时器timer在内核的软中断中发生调用,__run_timers会spin_lock_irq(& ...

  2. 浅析linux内核中timer定时器的生成和sofirq软中断调用流程【转】

    转自:http://blog.chinaunix.net/uid-20564848-id-73480.html 浅析linux内核中timer定时器的生成和sofirq软中断调用流程 mod_time ...

  3. Linux 2.6内核中新的锁机制--RCU

    转自:http://www.ibm.com/developerworks/cn/linux/l-rcu/ 一. 引言 众所周知,为了保护共享数据,需要一些同步机制,如自旋锁(spinlock),读写锁 ...

  4. Linux 内核中的 Device Mapper 机制

    本文结合具体代码对 Linux 内核中的 device mapper 映射机制进行了介绍.Device mapper 是 Linux 2.6 内核中提供的一种从逻辑设备到物理设备的映射框架机制,在该机 ...

  5. 内核中用于数据接收的结构体struct msghdr(转)

    内核中用于数据接收的结构体struct msghdr(转) 我们从一个实际的数据包发送的例子入手,来看看其发送的具体流程,以及过程中涉及到的相关数据结构.在我们的虚拟机上发送icmp回显请求包,pin ...

  6. 向linux内核中添加外部中断驱动模块

    本文主要介绍外部中断驱动模块的编写,包括:1.linux模块的框架及混杂设备的注册.卸载.操作函数集.2.中断的申请及释放.3.等待队列的使用.4.工作队列的使用.5.定时器的使用.6.向linux内 ...

  7. [php-src]窥探Php内核中的变量

    内容均以php-5.6.14为例. 在看各种组合数据类型之前,有必要先熟悉下 Zend/zend_types.h 里面的自定义数据类型. #ifndef ZEND_TYPES_H // 防止多次 in ...

  8. [php-src]理解Php内核中的函数与INI

    内容均以php-5.6.14为例. 一. 函数结构 内核中定义一个php函数使用 PHP_FUNCTION 宏 包装,扩展也不例外,该宏在 ./main/php.h:343 有着一系列类似以 PHP ...

  9. Openvswitch原理与代码分析(5): 内核中的流表flow table操作

      当一个数据包到达网卡的时候,首先要经过内核Openvswitch.ko,流表Flow Table在内核中有一份,通过key查找内核中的flow table,即可以得到action,然后执行acti ...

随机推荐

  1. 调用获取学生信息的接口,保存到excel里面

    # 2.http: // doc.nnzhp.cn / index.php?s = / 6 & page_id = 14# 调用获取学生信息的接口,保存到excel里面 import requ ...

  2. ionic3+angular4开发混合app 之自定义组件

    这里主要是记录ionic3+angular4开发混合app时自定义组件,我想自定义组件的方法和angular4应该类似,具体在纯angular4中自定义组件,暂时没有实践,个人觉得差别不大,之后实践了 ...

  3. 关于height、offsetheight、clientheight、scrollheight、innerheight、outerheight的区别

    二.也是平时经常用到的offsetheight 它返回的高度是内容高+padding+边框,但是注意哦,木有加margin哦,当然一般也木有啥需要把margin加进去的,以上代码为例,结果显示上图h2 ...

  4. 关于实体类getset方法首字母小写问题

    实体类:private Date cDateTime;private String cNickname; public Date getcDateTime() { return cDateTime;} ...

  5. Edge Intelligence: On-Demand Deep Learning Model Co-Inference with Device-Edge Synergy

    边缘智能:按需深度学习模型和设备边缘协同的共同推理 本文为SIGCOMM 2018 Workshop (Mobile Edge Communications, MECOMM)论文. 笔者翻译了该论文. ...

  6. Vs 发布编译问题

    如果勾选了预编译 发布后的目录会有PrecompiledApp.config文件,bin目录中会有App_global.asax.dll和App_global.asax.compiled文件 不勾选预 ...

  7. 又到毕业季,尚学堂喊你免费领取100个Java毕设项目(含源码视频),限时一周哦!

    你还在为毕设发愁?不知道该如何命题?不知道从哪里下手?担心毕设过不了影响毕业? 尚学堂首家隆重推出了刷爆朋友圈的毕设100个项目,别说你还没去下载观看!!最最重要的是:免费!免费!免费!而且限时一周! ...

  8. Android OpenSL ES 开发:Android OpenSL 介绍和开发流程说明

    一.Android OpenSL ES 介绍 OpenSL ES (Open Sound Library for Embedded Systems)是无授权费.跨平台.针对嵌入式系统精心优化的硬件音频 ...

  9. data自定义属性获取方法和设置

    <!--原生获取方法--> <div data-id="id=1"></div> <script> //js原生获取方法 var i ...

  10. [Swift]LeetCode321. 拼接最大数 | Create Maximum Number

    Given two arrays of length m and n with digits 0-9 representing two numbers. Create the maximum numb ...