linux子系统的初始化_subsys_initcall()【转】
转自:http://my.oschina.net/u/572632/blog/305492
目录[-]
概述
内核选项的解析完成之后,各个子系统的初始化即进入第二部分—入口函数的调用。通常USB、PCI这样的子系统都会有一个名为subsys_initcall的入口,如果你选择它们作为研究内核的切入点,那么就请首先找到它。
section的声明
C 语言中attribute属性的section是在目标文件链接时可以用于主动定制代码的位置,具体可以WIKI,下面看linux kernel中是如何定义的。
以下代码来自 linux内核源码中 include/linux/init.h 文件。下面使用相同语法规则的变量名存放了各个初始化函数的地址。
更重要的是其section属性也是按照一定规则构成的。
关于section见 http://lihuize123123.blog.163.com/blog/static/878290522010420111428109/
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
/* 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(level,fn,id) \ static initcall_t __initcall_##fn##id __used \ __attribute__((__section__(".initcall" level ".init"))) = fn/* * Early initcalls run before initializing SMP. * * Only for built-in code, not modules. */#define early_initcall(fn) __define_initcall("early",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. */#define pure_initcall(fn) __define_initcall("0",fn,0)#define core_initcall(fn) __define_initcall("1",fn,1)#define core_initcall_sync(fn) __define_initcall("1s",fn,1s)#define postcore_initcall(fn) __define_initcall("2",fn,2)#define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)#define arch_initcall(fn) __define_initcall("3",fn,3)#define arch_initcall_sync(fn) __define_initcall("3s",fn,3s)#define subsys_initcall(fn) __define_initcall("4",fn,4)#define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s)#define fs_initcall(fn) __define_initcall("5",fn,5)#define fs_initcall_sync(fn) __define_initcall("5s",fn,5s)#define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)#define device_initcall(fn) __define_initcall("6",fn,6)#define device_initcall_sync(fn) __define_initcall("6s",fn,6s)#define late_initcall(fn) __define_initcall("7",fn,7)#define late_initcall_sync(fn) __define_initcall("7s",fn,7s)#define __initcall(fn) device_initcall(fn)#define __exitcall(fn) \ static exitcall_t __exitcall_##fn __exit_call = fn#define console_initcall(fn) \ static initcall_t __initcall_##fn \ __used __section(.con_initcall.init) = fn#define security_initcall(fn) \ static initcall_t __initcall_##fn \ __used __section(.security_initcall.init) = fn |
注册
这些入口有个共同的特征,它们都是使用__define_initcall宏定义的。它们的调用也不是随便的,而是按照一定顺序的,这个顺序就取决于__define_initcall宏。__define_initcall宏用来将指定的函数指针放到.initcall.init节里。
.initcall.init节
内核可执行文件由许多链接在一起的对象文件组成。对象文件有许多节,如文本、数据、init数据、bass等等。这些对象文件都是由一个称为链接器脚本的文件链接并装入的。这个链接器脚本的功能是将输入对象文件的各节映射到输出文件中;换句话说,它将所有输入对象文件都链接到单一的可执行文件中,将该可执行文件的各节装入到指定地址处。 vmlinux.lds是存在于arch/<target>/目录中的内核链接器脚本,它负责链接内核的各个节并将它们装入内存中特定偏移量处。在vmlinux.lds文件里查找initcall.init就可以看到下面的内容
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#define INITCALLS \ *(.initcallearly.init) \ VMLINUX_SYMBOL(__early_initcall_end) = .; \ *(.initcall0.init) \ *(.initcall0s.init) \ *(.initcall1.init) \ *(.initcall1s.init) \ *(.initcall2.init) \ *(.initcall2s.init) \ *(.initcall3.init) \ *(.initcall3s.init) \ *(.initcall4.init) \ *(.initcall4s.init) \ *(.initcall5.init) \ *(.initcall5s.init) \ *(.initcallrootfs.init) \ *(.initcall6.init) \ *(.initcall6s.init) \ *(.initcall7.init) \ *(.initcall7s.init) |
这就告诉我们.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文件发现
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
/** * 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)/* Don't use these in modules, but some people do... */#define early_initcall(fn) module_init(fn)#define core_initcall(fn) module_init(fn)#define postcore_initcall(fn) module_init(fn)#define arch_initcall(fn) module_init(fn)#define subsys_initcall(fn) module_init(fn)#define fs_initcall(fn) module_init(fn)#define device_initcall(fn) module_init(fn)#define late_initcall(fn) module_init(fn) |
|
1
2
3
4
5
6
7
8
9
10
11
12
|
#define __define_initcall(level,fn) \ static initcall_t __initcall_##fn __used \ __attribute__((__section__(".initcall" level ".init"))) = fn/* Userspace initcalls shouldn't depend on anything in the kernel, so we'll * make them run first. */#define __initcall(fn) __define_initcall("1", fn)#define __exitcall(fn) static exitcall_t __exitcall_##fn __exit_call = fn#define __init_call __used __section(.initcall.init) |
这样推断 module_init 调用优先级为6低于subsys_initcall调用优先级4
调用
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
static void __init do_initcalls(void){ initcall_t *fn; for (fn = __early_initcall_end; fn < __initcall_end; fn++) do_one_initcall(*fn); /* Make sure there is no pending stuff from the initcall sequence */ flush_scheduled_work();}int __init_or_module do_one_initcall(initcall_t fn){ int count = preempt_count(); int ret; if (initcall_debug) ret = do_one_initcall_debug(fn); else ret = fn(); msgbuf[0] = 0; if (ret && ret != -ENODEV && initcall_debug) sprintf(msgbuf, "error code %d ", ret); if (preempt_count() != count) { strlcat(msgbuf, "preemption imbalance ", sizeof(msgbuf)); preempt_count() = count; } if (irqs_disabled()) { strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf)); local_irq_enable(); } if (msgbuf[0]) { printk("initcall %pF returned with %s\n", fn, msgbuf); } return ret;} |
IN BUILDING

0赞linux子系统的初始化_subsys_initcall()【转】的更多相关文章
- linux子系统的初始化_subsys_initcall()
http://my.oschina.net/u/572632/blog/305492#OSC_h1_3
- Linux内核(11) - 子系统的初始化之内核选项解析
首先感谢国家.其次感谢上大的钟莉颖,让我知道了大学不仅有校花,还有校鸡,而且很多时候这两者其实没什么差别.最后感谢清华女刘静,让我深刻体会到了素质教育的重要性,让我感到有责任写写子系统的初始化. 各个 ...
- linux 输入子系统(4)---- input子系统的初始化
Input子系统的初始化函数为input_init(),如下: static int __init input_init(void) { int err; input_init_abs_bypass( ...
- Linux内核(12) - 子系统的初始化之那些入口函数
内核选项的解析完成之后,各个子系统的初始化即进入第二部分—入口函数的调用.通常USB.PCI这样的子系统都会有一个名为subsys_initcall的入口,如果你选择它们作为研究内核的切入点,那么就请 ...
- linux PCI设备初始化过程
linux PCI设备初始化过程 start_kernel->rest_init 这个函数会启动一个核心线程0, 核心线程然后调用init -> do_basic_setup. 然后我们开 ...
- 【ASP.NET Core】准备工作:在 Windows 10 上配置 Linux 子系统
ASP.NET Core 其实比传统的 ASP.NET 要简单很多,而且也灵活很多,并且可以跨平台独立运行. 在 Windows 平台上,我们只要在安装 Visual Studio 的时候选择跨平台的 ...
- 【ASP.NET Core】在Win 10 的 Linux 子系统中安装 .NET Core
在上一篇文章中,老周扯了一下在 Windows 10 中开启 Linux 子系统,并且进行了一些简单的设置.本篇咱们就往上面安装 .net core . 老周假设你从来没有用过 Linux,所以,接着 ...
- Win 10 启用Linux子系统---Kali 和Ubuntu子系统
注:转载请注明出处,谢谢!!! 一.Linux on Windows简介 Win10一周年版推出了用于Windows的Linux子系统这一功能.Linux子系统和Windows的结合真是有一种神互补. ...
- windows 下使用Linux子系统
在 Windows 上进行 web 开发,比较普遍的方案是使用 phpstudy 或者别的一些集成环境软件进行环境搭建,写好代码后将代码上传至版本管理工具 git/svn,再将代码同步到 Linux ...
随机推荐
- winform中文本框添加拖拽功能
对一个文本框添加拖拽功能: private void txtFolder_DragEnter(object sender, DragEventArgs e) { if (e.Data.GetDataP ...
- 在js中对日期的加减法
以在某个日期上加减天数来说,其实只要调用Date对象的setDate()函数就可以了,对月份来说,使用setMonth(),具体方法如下: function addDate(date, da ...
- codeforces 730 j.bottles
J. Bottles time limit per test 2 seconds memory limit per test 512 megabytes input standard input ou ...
- 【以前的空间】bzoj [ZJOI2007]棋盘制作
具体可以去跪<浅谈用极大化思想解决最大子矩形问题>(p.s. 蒟蒻跪了还是很晕,不过想到之前usaco好像是最后一章的一道题……看了下代码顿然醒悟) 也就是如果用o(nm)的方法维护一个极 ...
- 算法学习 并查集(Union-Find) (转)
并查集是我暑假从高手那里学到的一招,觉得真是太精妙的设计了.以前我无法解决的一类问题竟然可以用如此简单高效的方法搞定.不分享出来真是对不起party了.(party:我靠,关我嘛事啊?我跟你很熟么?) ...
- Android C语言_init函数和constructor属性及.init/.init_array节探索
本篇文章主要介绍了"Android C语言_init函数和constructor属性及.init/.init_array节探索",主要涉及到Android C语言_init函数和c ...
- JavaScript闭包的特性
先看一下代码: 01 <ul> 02 <li>1111</li> 03 <li>2222</li> 04 <l ...
- crontab使用进程锁解决冲突
想到一个问题,如果在crontab里有个定时任务设置为一分钟执行一次,但是它执行的时间可能会超过一分钟,此时crontab一分钟后会再次运行该脚本吗?这样会不会出现冲突呢?网上找了下,说可以用Linu ...
- Connections between cities LCA
Problem Description After World War X, a lot of cities have been seriously damaged, and we need to r ...
- sudoers文件配置
http://note.drx.tw/2008/01/linuxsudo.html foobar ALL=(ALL) ALL 現在讓我們來看一下那三個 ALL 到底是什麼意思.第一個 ALL 是指網路 ...