Linux内核基础篇——initcall

简介: 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对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是一样的。

end

猜你喜欢

RISC-V SiFive U64内核——HPM硬件性能监视器

RISC-V SiFive U64内核——L2 Prefetcher预取器

RISC-V SiFive U54内核——PMP物理内存保护

RISC-V SiFive U54内核——PLIC平台级中断控制器

RISC-V SiFive U54内核——CLINT中断控制器

RISC-V SiFive U54内核——中断和异常详解

系统明明有很多内存,却无法分配出一片大块内存?

实战 | RISC-V Linux入口地址2M预留内存优化

RISC-V Linux启动之页表创建分析

RISC-V Linux汇编启动过程分析

RISC-V 入门笔记(新手必看!)

教你在QEMU上运行RISC-V Linux

OpenSBI三种固件的区别

写给新手的MMU工作原理

内核调试之devmem直接读写寄存器

相关文章
|
8月前
|
安全 网络协议 Linux
深入理解Linux内核模块:加载机制、参数传递与实战开发
本文深入解析了Linux内核模块的加载机制、参数传递方式及实战开发技巧。内容涵盖模块基础概念、加载与卸载流程、生命周期管理、参数配置方法,并通过“Hello World”模块和字符设备驱动实例,带领读者逐步掌握模块开发技能。同时,介绍了调试手段、常见问题排查、开发规范及高级特性,如内核线程、模块间通信与性能优化策略。适合希望深入理解Linux内核机制、提升系统编程能力的技术人员阅读与实践。
728 1
|
8月前
|
Ubuntu Linux
Ubuntu 23.04 用上 Linux 6.2 内核,预计下放到 22.04 LTS 版本
Linux 6.2 带来了多项内容更新,修复了 AMD 锐龙处理器设备在启用 fTPM 后的运行卡顿问题,还增强了文件系统。
|
8月前
|
Ubuntu Linux
Ubuntu 23.10 现在由Linux内核6.3提供支持
如果你想在你的个人电脑上测试一下Ubuntu 23.10的最新开发快照,你可以从官方下载服务器下载最新的每日构建ISO。然而,请记住,这是一个预发布版本,所以不要在生产机器上使用或安装它。
|
8月前
|
传感器 监控 Ubuntu
10 月发布,Ubuntu 23.10 已升级到 Linux Kernel 6.3 内核
硬件方面,Linux 6.3 引入了在 HID 中引入了原生的 Steam Deck 控制器接口,允许罗技 G923 Xbox 版赛车方向盘在 Linux 上运行;改善 8BitDo Pro 2 有线控制器的行为;并为一系列华硕 Ryzen 主板添加传感器监控。
|
8月前
|
Ubuntu Linux
Ubuntu24.04LTS默认采用Linux 6.8内核,实验性版本可通过PPA获得
IT之家提醒,当下的 Ubuntu 23.10 也是一个“短期支持版本”,该版本将在今年 7 月终止支持,而今年 4 月推出的 Ubuntu 24.04 LTS 长期支持版本将获得 5 年的更新支持。
|
8月前
|
监控 Ubuntu Linux
什么Linux,Linux内核及Linux操作系统
上面只是简单的介绍了一下Linux操作系统的几个核心组件,其实Linux的整体架构要复杂的多。单纯从Linux内核的角度,它要管理CPU、内存、网卡、硬盘和输入输出等设备,因此内核本身分为进程调度,内存管理,虚拟文件系统,网络接口等4个核心子系统。
880 0
|
8月前
|
Web App开发 缓存 Rust
|
8月前
|
Ubuntu 安全 Linux
Ubuntu 发行版更新 Linux 内核,修复 17 个安全漏洞
本地攻击者可以利用上述漏洞,攻击 Ubuntu 22.10、Ubuntu 22.04、Ubuntu 20.04 LTS 发行版,导致拒绝服务(系统崩溃)或执行任意代码。
|
8月前
|
Ubuntu 机器人 物联网
Linux Ubuntu 22.04 LTS 测试版实时内核已可申请
请注意,在启用实时内核后您需要手动配置 grub 以恢复到原始内核。更多内容请参考:

热门文章

最新文章