Linux内核启动中驱动初始化过程
Linux内核启动时驱动初始化过程
一、驱动模块存在形式
内核源码树中大部分内容为驱动代码,那么在内核中,每个驱动在内核编译时都是以如下的两种形式进行编译的:
1、静态编译
将驱动编译进内核;
2、动态编译
将驱动编译成可以在需要时动态插入到内核中的模块,即ko的形式;
二、内核初始化时驱动是如何加载的?
整体的流程为先加载内嵌驱动,后加载模块形式的驱动;
1、内嵌驱动加载
start_kernel中会去创建1号进程,此时1号进程执行的函数为kernel_init,kernel_init负责完成大部分的初始化功能;驱动的初始化加载的函数在do_initcalls中;
kernel_init->kernel_init_freeable->do_basic_setup->do_initcalls->async_synchronize_full //需要等待所有的initcalls完成
在do_initcalls中按照顺序依次加载内嵌驱动,一共定义了如下几种level,在编写时可以自定义驱动初始化函数的level,例如scsi驱动的初始化函数的定义如下所示:
/*drivers/scsi/scsi.c*/
//定义init_scsi为subsys_initcall,level4,会优先于module_init的驱动执行
subsys_initcall(init_scsi);
*//* 数字越小,优先级越高 */
#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)
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);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);//level 0->7依次执行}kfree(command_line);
}
相同的level下执行函数为do_initcall_level,那么当level相同时如何执行呢?链接顺序有关,即顺序与makefile文件中的排序有关
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));//执行一个初始化函数
}
2、外部模块加载
async_synchronize_full 等待所有的内嵌驱动初始化完成后kernel_init才开始继续执行。此时1号进程还处于内核态,直到kernel_init通过run_init_process去加载用户态的init程序(centos 7以后为systemd进程:/sbin/init->systemd),此时由内核态转为用户态;
外部模块加载,此时是由systemd-udev负责监控uevent并根据规则去modporbe驱动来加载的
3、debug
cmdline中打开initcall_debug即可打印出kernel启动时的信息,可以直观的看到驱动的初始化顺序。
至于为何通过modprobe形式加载的外部模块也会存在initall的信息,原因在于module_init也是一种device_initcall;调用的循序为module_init(x)->__initcall(x)->device_initcall(x);
#ifndef MODULE
/*** module_init() - driver initialization entry point* @x: function to be run at kernel boot time or module insertion** module_init() will either be called during do_initcalls() (if* builtin) or at module insertion time (if a module). There can only* be one per module.*/
#define module_init(x) __initcall(x);//#define __initcall(fn) device_initcall(fn)
Linux内核启动中驱动初始化过程相关推荐
- c++ map 初始化_如何调整Linux内核启动中的驱动初始化顺序?
如何调整Linux内核启动中的驱动初始化顺序?[问题] 此处我要实现的是将芯片的ID用于网卡MAC地址,网卡驱动是enc28j60_init. 但是,读取芯片ID的函数,在as352x_afe_ini ...
- 如何调整Linux内核启动中的驱动初始化顺序
[问题] 此处我要实现的是将芯片的ID用于网卡MAC地址,网卡驱动是enc28j60_init. 但是,读取芯片ID的函数,在as352x_afe_init模块中,所以要先初始化as352x_afe_ ...
- Linux内核学习:EXT4 文件系统在 Linux 内核系统中的读写过程
目录 1 概述 2 虚拟文件系统 与 Ext4 文件系统 2.1 sys_write( ) 代码跟踪 2.2 sys_write( ) 过程分析 2.3 sys_write( ) 的核心部分 vfs_ ...
- 内核logo 前闪 linux,Linux内核启动中显示的logo的修改
1.配置内核 使内核启动时加载logo,在源代码的主目录下make menuconfig Device Drivers ---> Graphics support ---> 选上 并 ...
- AR9331中Linux内核启动中与IRQ中断相关的文件
先列出框架,具体后继再来分析. 首先是lds文件,该文件设置了各个section在FLASH或RAM中的先后顺序. 位于~/openwrt1407/build_dir/target-mips_34kc ...
- linux内核启动以及文件系统的加载过程
Linux 内核启动及文件系统加载过程 当u-boot 开始执行 bootcmd 命令,就进入 Linux 内核启动阶段.普通 Linux 内核的启动过程也可以分为两个阶段.本文以项目中使用的 lin ...
- Linux内核启动及文件系统加载过程
当u-boot开始执行bootcmd命令,就进入linux内核启动阶段 与 u-boot 类似,普通 Linux 内核的启动过程也可以分为两个阶段,但针对压缩了的内核如 uImage 就要包括内核自解 ...
- linux内核启动第一个进程,linux内核启动流程
描述 Linux的启动代码真的挺大,从汇编到C,从Makefile到LDS文件,需要理解的东西很多.毕竟Linux内核是由很多人,花费了巨大的时间和精力写出来的.而且直到现在,这个世界上仍然有成千上万 ...
- linux内核启动过程3:内核初始化阶段
上一篇<<linux内核启动过程2:保护模式执行流程>>分析了保护模式启动过程以及bzImage的解压入口函数,本篇继续分析内核启动过程,从保护模式到C代码初始化. start ...
- linux内核中启动页面,Linux内核启动过程分析
下面给出内核映像完整的启动过程: arch/x86/boot/header.S: --->header第一部分(以前的bootsector.S): 载入bootloader到0x7c00处,设 ...
最新文章
- HTTP2 基础知识点总结
- 【ASP】简单Url编码和Url解码实例
- 终于找到你!如何将前端console.log的日志保存成文件?
- CSS实现背景透明而背景上的文字不透明
- 标签传播(阅读笔记)
- 【电路】简易的桥式整流电路---选取滤波电容
- 《深入浅出DPDK》读书笔记(三):NUMA - Non Uniform Memory Architecture 非统一内存架构
- Spring Cloud与微服务学习总结(8)——Spring Boot、微服务架构和大数据治理三者之间的故事
- 程序阅读理解题目(高中语文版,附答案)
- mysql 虚拟表 分页_MySql大表分页(附独门秘技)
- java 计算限行尾号(北京)
- psp3000 java_psp上的python
- centos7+docker+安装mysql5.7
- Python期末复习题及代码
- 上帝永远不会问你的十件事
- 十款浏览器插件,让你拥有更好的浏览器体验
- 携程、飞猪?大数据杀熟的背后,到底杀死了谁?
- _access()函数的使用
- java1.8 list stream求平均数
- 整数运算(加减法)详解