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赞

原文地址:http://blog.163.com/liuqiang_mail@126/blog/static/10996887520124741925773/

时间: 2024-10-13 14:35:27

linux子系统的初始化_subsys_initcall()【转】的相关文章

Linux操作系统的内核初始化过程详解

概况 系统的引导和初始化是操作系统实现控制的第一步,也是集中体现系统优劣的重要部分.LINUX作为一个免费的准UNIX操作系统,在众多业余爱好者以及小型商业处理市场表现不俗,成为继WINDOWS系列后的另一个主流.了解LINUX系统的初始化,对于进一步掌握UNIX系统是十分有帮助的. 通常,LINUX系统的初始化可以分为两部分:内核部分和init程序部分.内核主要完成系统的硬件检测和初始化,init程序则主要完成系统的各项配置. 内核初始化详解 通常情况下,计算机首先用LILO程序引导内核的一部

.NET Core多平台开发体验[3]: Linux (Windows Linux子系统)

如果想体验Linux环境下开发和运行.NET Core应用,我们有多种选择.一种就是在一台物理机上安装原生的Linux,我们可以根据自身的喜好选择某种Linux Distribution,目前来说像RHEL.Ubuntu.Debian.Fedora.CentOS和SUSE这些主流的Distribution都是支持的.如果读者朋友们觉得这种方式比较麻烦,我们也可以采用虚拟机的形式安装相应的Linux Distribution,比如我经常使用的都是安装在VirtualBox上的Ubuntu.对于64

玩转 Windows 10 中的 Linux 子系统

在今年的 Build 2016 上,微软向全世界介绍了他们还处于 Beta 阶段的 Windows 下的 Linux 子系统Windows Subsystem for Linux(WSL),它可以让开发者们在 Windows 10 下通过 Bash shell 运行原生的 Ubuntu 用户态二进制程序.如果你参与了 Windows Insider 计划,你就可以在最新的 Windows 10 年度升级版的 Insider 构建版中体验这个功能了. Web 开发人员们不用再苦恼所用的 Windo

上手指南:开启你的Windows平台Linux子系统之路

在我的Windows开发者PC端安装了两个Linux发行版,它们不是虚拟机或双启动系统,也没有去寻找下载页面和解压缩安装文件通常路线,而是到Windows商店搜索Linux,选择想要的发行版并且安装上.下载完毕之后,打开终端窗口并填写用户名和密码,开始安装. 我运行了最新版本的Windows10系统,添加了Windows平台Linux子系统最新功能.引入了Windows10周年升级版和Windows10最新升级版本.Windows平台Linux子系统(WSL)是微软对于"如何让开发人员再次使用W

现代Linux的五大初始化系统(1992-2015)

在 Linux 和其他类 Uniux 系统中,init(初始化)进程是系统启动时由内核执行的第一个进程,其进程 ID(PID)为 1,并静默运行在后台,直到系统关闭. init 进程负责启动其他所有的进程,比如守护进程.服务和其他后台进程,因此,它是系统中其它所有进程之母(偏偏叫做"父进程").某个进程可以启动许多个子进程,但在这个过程中,某个子进程的父进程结束之后,该子进程的父进程会变成 init 进程. 这么多年过去了,许多的初始化系统在主流 Linux 脱颖而出,和本文中,我将你

现代 Linux 的五大初始化系统(1992-2015)

在 Linux 和其他类 Uniux 系统中,init(初始化)进程是系统启动时由内核执行的第一个进程,其进程 ID(PID)为 1,并静默运行在后台,直到系统关闭. init 进程负责启动其他所有的进程,比如守护进程.服务和其他后台进程,因此,它是系统中其它所有进程之母(偏偏叫做"父进程").某个进程可以启动许多个子进程,但在这个过程中,某个子进程的父进程结束之后,该子进程的父进程会变成 init 进程. 这么多年过去了,许多的初始化系统在主流 Linux 脱颖而出,和本文中,我将你

微软选择 Ubuntu 放到 Windows 10 的 Linux 子系统中,或许“错”了

虽然并非微软官方出品,不过你现在可以在 Windows 10 的  Linux 子系统(WSL)中使用 openSUSE Leap 或 SUSE Linux 企业版(SLES)了. 正如你所知道的,最新的 Windows 10 版本中含有一个完整的.基于 Ubuntu 的 Bash,开发者们可以在 Windows 桌面中直接运行 Linux 软件或命令.这被称为"Bash on Ubuntu on Windows"--一个啰嗦的名字--现在可以从 Windows 的开始菜单直接访问到了

什么鬼?Windows 10暗藏神秘Linux子系统

Windows 10 Mobile手机系统上曾经一度集成Android子系统,目的是将Android应用移植过来,也就是所谓的Project Astoria,但是这个项目已经基本被放弃,Android子系统也很快就消失了. 但是在最新的Windows 10 Redstone Build 14251系统里,竟然又出现了一个类似的Linux子系统. 国外黑客WalkingCat研究后发现,新系统里竟然有lxcore.sys.lxss.sys等系统文件,都是来源于Linux,并非Windows本身所有

OpenBSD 6.0 将移除 Linux 子系统以改进安全

OpenBSD 6.0 预计将在9月1日发布.OpenBSD以安全著称,而OpenBSD 6.0在安全方面的最大变化是移除Linux子系统.OpenBSD之前的版本引入Linux兼容层是为了运行Linux应用,但Linux上流行的应用程序多数也有OpenBSD版本,因此对Linux兼容层的需求并不高. 为了改进安全,OpenBSD还淘汰了 systrace 系统策略实施工具,移除了usermount选项--如果启用将允许非特权用户装载文件系统. 文章转载自 开源中国社区[http://www.o