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/[email protected]/blog/static/10996887520124741925773/

时间: 2024-10-13 00:22:41

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

linux子系统的初始化_subsys_initcall():那些入口函数【转】

内核选项的解析完成之后,各个子系统的初始化即进入第二部分—入口函数的调用.通常USB.PCI这样的子系统都会有一个名为subsys_initcall的入口,如果你选择它们作为研究内核的切入点,那么就请首先找到它. 朱德庸在<关于上班这件事>里说,要花前半生找入口,花后半生找出口.可见寻找入口对于咱们这一生,对于看内核代码这件事儿都是无比重要的. 但是很多时候,入口并不仅仅只有subsys_initcall一个,比如PCI. 以下代码来自 linux内核源码中 include/linux/ini

linux子系统的初始化_subsys_initcall()

概述 内核选项的解析完成之后,各个子系统的初始化即进入第二部分-入口函数的调用.通常USB.PCI这样的子系统都会有一个名为subsys_initcall的入口,如果你选择它们作为研究内核的切入点,那么就请首先找到它. section的声明 C 语言中attribute属性的section是在目标文件链接时可以用于主动定制代码的位置,具体可以WIKI,下面看linux kernel中是如何定义的. 以下代码来自 linux内核源码中 include/linux/init.h 文件.下面使用相同语

Linux内核(11) - 子系统的初始化之内核选项解析

首先感谢国家.其次感谢上大的钟莉颖,让我知道了大学不仅有校花,还有校鸡,而且很多时候这两者其实没什么差别.最后感谢清华女刘静,让我深刻体会到了素质教育的重要性,让我感到有责任写写子系统的初始化. 各个子系统的初始化是内核整个初始化过程必然要完成的基本任务,这些任务按照固定的模式来处理,可以归纳为两个部分:内核选项的解析以及那些子系统入口(初始化)函数的调用. 内核选项 Linux允许用户传递内核配置选项给内核,内核在初始化过程中调用parse_args函数对这些选项进行解析,并调用相应的处理函数

Linux内核(12) - 子系统的初始化之那些入口函数

内核选项的解析完成之后,各个子系统的初始化即进入第二部分-入口函数的调用.通常USB.PCI这样的子系统都会有一个名为subsys_initcall的入口,如果你选择它们作为研究内核的切入点,那么就请首先找到它. 朱德庸在<关于上班这件事>里说,要花前半生找入口,花后半生找出口.可见寻找入口对于咱们这一生,对于看内核代码这件事儿都是无比重要的. 但是很多时候,入口并不仅仅只有subsys_initcall一个,比如PCI. 117 #define pure_initcall(fn)      

【ASP.NET Core】准备工作:在 Windows 10 上配置 Linux 子系统

ASP.NET Core 其实比传统的 ASP.NET 要简单很多,而且也灵活很多,并且可以跨平台独立运行. 在 Windows 平台上,我们只要在安装 Visual Studio 的时候选择跨平台的 .NET Core 开发即可,基本无需什么配置就能测试 ASP.NET Core 应用,连 IIS 你也可以不启用(当然你也可以启用的),因为使用 dotnet 命令就能直接运行.当然了,在MacOS和 Linux 上也是通过 dotnet 命令运行的. 一般来说,在 Windows 平台上,你的

【ASP.NET Core】在Win 10 的 Linux 子系统中安装 .NET Core

在上一篇文章中,老周扯了一下在 Windows 10 中开启 Linux 子系统,并且进行了一些简单的设置.本篇咱们就往上面安装 .net core . 老周假设你从来没有用过 Linux,所以,接着上一次的博文,老周先给您介绍几个可能比较常用的东东. 切换到 root 用户上下文 当你启动 Ubuntu 子系统后,你会看到,在你的用户名.机器名.路径名后有个 $ 符号.如下图. 这表示当前用户的权限是受到限制的,如果想要执行某些需要高权限的命令(这个类似于 Windows 中的以管理员身份运行

(转)Windows10安装Linux子系统Ubuntu

原文地址:https://blog.csdn.net/zhouzme/article/details/78780479 先看看操作系统版本,之前看网上的安装说明很多都是比较早的系统beta版本和现在安装方法有些不一样 ,家庭版安装使用也是没有问题的 下面开始安装,首先确认下你C盘的剩余空间哈 一.开启开发者模式 顺序: -> 系统设置 -> 更新和安全 -> 针对开发人员 -> 选择开发者模式 点击后会自动安装环境 二.安装 Windows 10 的 Linux 子系统组件 顺序:

windows 下使用Linux 子系统-安装.net core 环境

在 Windows 上进行 web 开发,比较普遍的方案是使用 phpstudy 或者别的一些集成环境软件进行环境搭建,写好代码后将代码上传至版本管理工具 git/svn,再将代码同步到 Linux 服务器,这个过程当中开发者的开发环境(Windows)与代码最终执行的环境(Linux)不一致经常会导致一些奇奇怪怪的问题,想在 Windows 上进行 linux 下的 web 开发,不想用 mac(毕竟没钱买 mac),又不想使用虚拟机(虚拟机开机速度慢,添加站点需要重启,分配内存会导致机器变得

win10下Linux子系统开启ssh服务

原文地址:http://whosmall.com/?post=430 本文标签: 开启ssh Linux子系统 虽然win10自带的bash功能已经很丰富,操作也简便,不过习惯了用xshell, 还是选择用xshell来操作 直接用xshell连接127.0.0.1 端口22 提示连接失败.说明应该是ubuntu的sshd服务设置有问题: 解决方案如下: 安装ssh apt-get install openssh-server 备份sshd配置文件 sudo cp /etc/ssh/sshd_c