文章目录

  • 1、initcall的分类
  • 2、__initcall的调用
  • 3、module_driver/module_i2c_driver

★★★ 友情链接 : 个人博客导读首页—点击此处 ★★★

1、initcall的分类

在kernel/include/linux/module.h中

#define module_init(x)   __initcall(x);

在kernel/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)#define __initcall(fn) device_initcall(fn)

其实对应的就是就是".initcall0.init ~ .initcall7.init"的__section__段

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

我们再总结下,module_init(xxx_init)其实就是在.initcall6.init的__section__段中分配一个地址,指向xxx_init函数

而__section__段的定义在vmlinux.ld.S的INIT_CALLS中

.init.data : {
INIT_DATA
INIT_SETUP(16)
INIT_CALLS
CON_INITCALL
SECURITY_INITCALL
INIT_RAM_FS
}

INIT_CALLS是定义在vmlinux.ld.h的一个宏

#define INIT_CALLS_LEVEL(level)                      \VMLINUX_SYMBOL(__initcall##level##_start) = .;        \*(.initcall##level##.init)             \*(.initcall##level##s.init)                \

#define INIT_CALLS                          \VMLINUX_SYMBOL(__initcall_start) = .;         \*(.initcallearly.init)                 \INIT_CALLS_LEVEL(0)                    \INIT_CALLS_LEVEL(1)                    \INIT_CALLS_LEVEL(2)                    \INIT_CALLS_LEVEL(3)                    \INIT_CALLS_LEVEL(4)                    \INIT_CALLS_LEVEL(5)                    \INIT_CALLS_LEVEL(rootfs)               \INIT_CALLS_LEVEL(6)                    \INIT_CALLS_LEVEL(7)                    \VMLINUX_SYMBOL(__initcall_end) = .;

这些section段的地址是:

__initcall0_start,
__initcall1_start,
__initcall2_start,
__initcall3_start,
__initcall4_start,
__initcall5_start,
__initcall6_start,
__initcall7_start,

2、__initcall的调用

在kernel/init/main.c中:

依次循环调用了这些section段的函数

static initcall_t *initcall_levels[] __initdata = {__initcall0_start,__initcall1_start,__initcall2_start,__initcall3_start,__initcall4_start,__initcall5_start,__initcall6_start,__initcall7_start,__initcall_end,
};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,NULL, &repair_env_string);for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)do_one_initcall(*fn);
}static void __init do_initcalls(void)
{int level;for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)do_initcall_level(level);
}int __init_or_module do_one_initcall(initcall_t fn)
{int count = preempt_count();int ret;char msgbuf[64];if (initcall_blacklisted(fn))return -EPERM;if (initcall_debug)ret = do_one_initcall_debug(fn);elseret = fn();msgbuf[0] = 0;if (preempt_count() != count) {sprintf(msgbuf, "preemption imbalance ");preempt_count_set(count);}if (irqs_disabled()) {strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf));local_irq_enable();}WARN(msgbuf[0], "initcall %pF returned with %s\n", fn, msgbuf);return ret;
}
static bool __init_or_module initcall_blacklisted(initcall_t fn)
{struct list_head *tmp;struct blacklist_entry *entry;char *fn_name;fn_name = kasprintf(GFP_KERNEL, "%pf", fn);if (!fn_name)return false;list_for_each(tmp, &blacklisted_initcalls) {entry = list_entry(tmp, struct blacklist_entry, next);if (!strcmp(fn_name, entry->buf)) {pr_debug("initcall %s blacklisted\n", fn_name);kfree(fn_name);return true;}}kfree(fn_name);return false;
}

3、module_driver/module_i2c_driver

在device.h中:

#define module_driver(__driver, __register, __unregister, ...) \
static int __init __driver##_init(void) \
{ \return __register(&(__driver) , ##__VA_ARGS__); \
} \
module_init(__driver##_init); \
static void __exit __driver##_exit(void) \
{ \__unregister(&(__driver) , ##__VA_ARGS__); \
} \
module_exit(__driver##_exit);

在i2c.h中

#define module_i2c_driver(__i2c_driver) \module_driver(__i2c_driver, i2c_add_driver, \i2c_del_driver)

linux kernel中的module_init/initcall代码导读相关推荐

  1. linux kernel中local_irq_disable()、local_irq_enable()代码解读

    在armv8-arch64架构下,控制cpu是否响应IRQ,FIQ,SERROR,DEBUG中断,是由PSTATUS(daif寄存器)控制的. 在armv8-arch32或armv7架构下,控制cpu ...

  2. Linux kernel 中模块化的平台驱动代码介绍

    介绍 在linux kernel中通过module_platform_driver来实现模块化平台驱动.大量的设备驱动程序都基于该种方式来实现,使用频次非常的高,在linux kernel 5.4.1 ...

  3. linux kernel中的栈的介绍

    目录 1.linux kernel中的中断irq的栈stack (1).arm32体系的irq的栈 (2).arm64体系的irq的栈 2.linux kernel中的栈stack (1).概念介绍: ...

  4. linux kernel中的进程栈

    1.linux中的user mode的进程栈 在thread_info.h中,设置进程栈的大小为16k #define THREAD_SIZE 16384 #define THREAD_START_S ...

  5. Linux kernel中常见的宏整理

    0x00 宏的基本知识 // object-like #define 宏名 替换列表 换行符 //function-like #define 宏名 ([标识符列表]) 替换列表 换行符 替换列表和标识 ...

  6. 内存访问顺序 - part2: 屏障及Linux kernel中屏障的使用

    文章目录 屏障是什么 Linux Kernel 中的屏障 Linux 屏障 API 一般的屏障 强制性屏障 SMP 条件屏障 隐式屏障 其他屏障 屏障的开销 未来的文章 本文翻译自 Memory ac ...

  7. Linux Kernel中AEP的现状和发展

    阿里 石洋内核月谈Yesterday AEP简介 AEP是Intel推出的一种新型的非易失Optane Memory设备,又被称作Apache Pass,所以一般习惯称作AEP.在这之前也有类似的设备 ...

  8. linux kernel中的virt_to_phys代码解读

    假设VA_BITS = 48 (虚拟地址有效位), 那么kernel space的虚拟地址是:0xffff_0000_0000_0000 - 0xffff_ffff_ffff_ffff, usersp ...

  9. linux kernel中cache代码解读

    1. 在kernel中调用__dma_flush_range,底层是如何操作的呢? /* remove any dirty cache lines on the kernel alias */__dm ...

最新文章

  1. python中的类的成员变量以及property函数
  2. 网络推广软件介绍外链坚持七大原则助力网站排名“蹭蹭上涨”!
  3. PyTorch max()函数取最大值
  4. 用的fileupload组件实现的大文件上传
  5. CNN 手写数字识别
  6. 春节档总票房突破50亿元 《流浪地球》独占16亿!
  7. 基于selenium的钓鱼工具:关于ReelPhish神器的使用
  8. 1.13 Linux创建与删除用户
  9. php如何输入错误返回,php – 从函数返回“错误”的最佳做法
  10. 初中会考计算机flash,初中信息技术考试flash.doc
  11. 如何用一束激光欺骗神经网络
  12. cad里面f命令用不了_cad命令_CAD命令中 F 命令是什么作用?
  13. 弹幕游戏:Ryan 最近迷上了弹幕游戏。所谓弹幕游戏,指的是玩家操控一位角色对来袭的大量敌人进行攻击,并在过程中升级、强化自我的能力,最终打败 Boss 的一类游戏...
  14. Helm模版开发文档
  15. 智能空气净化器解决方案,飞睿科技无线WiFi芯片模块技术应用
  16. 如何保障微服务架构下的数据一致性
  17. mycat连接数据库8.0以上 处理程序连接query_cache_size报错信息 mycat升级数据库踩坑
  18. 【域渗透提权】CVE-2020-1472 NetLogon 权限提升漏洞
  19. windows防火墙开启后,设置准入端口
  20. BeyondCompare4 破解方法

热门文章

  1. 数据中心水冷系统备品备件管理新思路
  2. UPS远程监控系统的设计与实现
  3. 探讨计算机房的防火安全
  4. 成功解决matplotlib绘图的时候,自定义横坐标和纵坐标刻度数值(调整坐标轴刻度间隔)
  5. Python之pyecharts:利用pyecharts绘制地图十多个地区流动轨迹动态图
  6. 成功解决TypeError: 'float' object cannot be interpreted as an integer
  7. Funny:还是程序猿会玩——弹幕炸天学AI和区块链,玩起来!弹慕君,你也值得拥有!
  8. 自定义服务器控件ImageButton
  9. python3 获取cookie解决方案
  10. jQuery on()方法绑定动态元素的点击事件无效