Linux系统启动过程很复杂,因为它既需要支持模块静态加载机制也要支持动态加载机制。模块动态加载机制给系统提供了极大的灵活性,驱动程序既可支持静态编译进内核,也可以支持动态加载机制。Linux系统中对设备和子系统的初始化在最后进行,主要过程可以用下图表示。

图1

进入子系统初始化时,在内核init进程中进行设备初始化,最为复杂、诡异的机制莫过于do_initcalls()函数调用,该函数完成了所有需要静态加载模块的初始化,需要进行静态加载的内核模块,需要使用一些特定的宏进行处理,下面详细来说明一些linux内核中initcalls机制。

先来看看do_initcalls()函数原型:

图2

核心部分是639~671之间,该部分是一个函数指针调用,遍历_initcall_start~_initcall_end范围,逐个调用函数指针。

那_initcall_start~_initcall_end之间存放的是什么呢,可以以下面一幅示意图来说明。

图3

图左边是地址指针,右边是相关宏,使用相关宏处理函数指针,可以将被处理的函数指针放在特定的指针范围内。例如,网络设备层初始化函数是net_dev_init(),定义在net/core/dev.c中,在该函数下方有条宏处理subsys_initcall(net_dev_init),该宏完成将net_dev_init函数指针放在上图中.initcall4.init段中,在do_initcalls()函数调用时,其处于_initcall_start~_initcall_end直接,所以net_dev_init()就这样被调用了。

这种机制真是比较巧妙,也比较难以理解,设计初衷就是为了实现一个通用的启动流程,使移植或扩展时,只需要对需要启动加载的模块进行宏处理即可。

下面来详细了解这种机制的实现方法。

先说一说gcc对手动定位代码段位置的支持,_attribute_是gcc的关键字,指示编译器给符号设置特定属性。编译完成后输入到链接器的是各个带有符号表的文件,链接器对各个文件中符号进行重定位,_attribute_在该阶段进行处理,将指定符号放在链接生成文件段中特定位置,不单只指代码段,也包括数据段,如系统初始化中经常见到的_initdata,即将指定符号放到数据段特定位置。

当然,具体这些段是如何生成的,也是有文件进行配置,即在链接配置文件arch/xxx/vmlinux.ds.S.中,如下

图4

在2.6.16内核中INITCALLS已直接被替换为

*(.initcall1.init)
*(.initcall2.init)
*(.initcall3.init)
*(.initcall4.init)
*(.initcall5.init)
*(.initcall6.init)
*(.initcall7.init)

这和图3中的结构是对应的。接下来看看内核提供了哪些宏定义用来处理特定函数指针和数据。在include/linux/init.h文件中,包括各种常见的包装。

#define __define_initcall(level,fn) \
static initcall_t __initcall_##fn __attribute_used__ \
__attribute__((__section__(".initcall" level ".init"))) = fn #define core_initcall(fn) __define_initcall("1",fn)
#define postcore_initcall(fn) __define_initcall("2",fn)
#define arch_initcall(fn) __define_initcall("3",fn)
#define subsys_initcall(fn) __define_initcall("4",fn)
#define fs_initcall(fn) __define_initcall("5",fn)
#define device_initcall(fn) __define_initcall("6",fn)
#define late_initcall(fn) __define_initcall("7",fn)

可以看出,内核为满足不同初始化等级,设计了1~7共7个等级,不同等级初始化代码用对应的宏进行处理,读者可以对照上表进行理解一下。还有其它一些宏,用于各种任务需求,如模块加载宏module_init(),module_exit(),其处理又略有不同,读者可以自己理解一下。

总的来说,initcalls机制提供给内核开发者或驱动开发者一个借口,方便将自己的函数添加到内核初始化列表中,在内核初始化最后阶段进行处理。

原文链接: http://blog.csdn.net/u012497906/article/details/46234675

linux initcall机制的更多相关文章

  1. linux的initcall机制

    linux的initcall机制(针对编译进内核的驱动) initcall机制的由来 我们都知道,linux对驱动程序提供静态编译进内核和动态加载两种方式,当我们试图将一个驱动程序编译进内核时,开发者 ...

  2. initcall机制

    参考:initcall机制 /* include/linux/init.h: */ /* For assembly routines */ #define __HEAD .section " ...

  3. Linux模块机制浅析

    Linux模块机制浅析   Linux允许用户通过插入模块,实现干预内核的目的.一直以来,对linux的模块机制都不够清晰,因此本文对内核模块的加载机制进行简单地分析. 模块的Hello World! ...

  4. android & Linux uevent机制

    Linux uevent机制 Uevent是内核通知android有状态变化的一种方法,比如USB线插入.拔出,电池电量变化等等.其本质是内核发送(可以通过socket)一个字符串,应用层(andro ...

  5. 利用linux信号机制调试段错误(Segment fault)

    在实际开发过程中,大家可能会遇到段错误的问题,虽然是个老问题,但是其带来的隐患是极大的,只要出现一次,程序立即崩溃中止.如果程序运行在PC中,segment fault的调试相对比较方便,因为可以通过 ...

  6. Linux 内存机制详解宝典

    Linux 内存机制详解宝典 在linux的内存分配机制中,优先使用物理内存,当物理内存还有空闲时(还够用),不会释放其占用内存,就算占用内存的程序已经被关闭了,该程序所占用的内存用来做缓存使用,对于 ...

  7. Linux Namespaces机制——实现

    转自:http://www.cnblogs.com/lisperl/archive/2012/05/03/2480573.html 由于Linux内核提供了PID,IPC,NS等多个Namespace ...

  8. Linux Namespaces机制

    转自:http://www.cnblogs.com/lisperl/archive/2012/05/03/2480316.html Linux Namespaces机制提供一种资源隔离方案.PID,I ...

  9. Linux分页机制之概述--Linux内存管理(六)

    1 分页机制 在虚拟内存中,页表是个映射表的概念, 即从进程能理解的线性地址(linear address)映射到存储器上的物理地址(phisical address). 很显然,这个页表是需要常驻内 ...

随机推荐

  1. df: `/root/.gvfs': Permission denied

    在使用oracle账户检查本地磁盘情况时,总是出现df: `/root/.gvfs': Permission denied信息提示. [oracle@rac1 ~]$ df -h Filesystem ...

  2. laravel相关插件

    1. Laravel-4-Generators Rapidly speed up your Laravel workflow with generators  https://packagist.or ...

  3. Java Web专题

  4. HDU - 6321 Problem C. Dynamic Graph Matching (状压dp)

    题意:给定一个N个点的零图,M次操作,添加或删除一条边,每一次操作以后,打印用1,2,...N/2条边构成的匹配数. 分析:因为N的范围很小,所以可以把点的枚举状态用二进制表示集合.用一维数组dp[S ...

  5. CodeForces - 986A Fair (BFS+贪心)

    题意:有N个点M条边的无向图,每个点有给定的ai(1<=ai<=K,K<=200)表示该点拥有的物品编号,保证1-K在N个点全部出现.求每个点收集S个不同的物品所要走过的最短路程(边 ...

  6. Linux下SSH中配置说明

    SSH 协议:安全外壳协议.为 Secure Shell 的缩写.SSH 为建立在应用层和传输层基础上的安全协议. sshd服务使用SSH协议可以用来进行远程控制,或在计算机之间传送文件.而实现此功能 ...

  7. WPF MVVM模式下ComboBox级联效果 选择第一项

    MVVM模式下做的省市区的级联效果.通过改变ComboBox执行命令改变市,区. 解决主要问题就是默认选中第一项 1.首先要定义一个属性,继承自INotifyPropertyChanged接口.我这里 ...

  8. c语言网络通信杂笔记

    1.sin_addr.s_addr = INADDR_ANY;设置成本地IP 2.pthread_create();线程生成函数 3.在linux下,sleep(1)是睡眠1s

  9. 把Arch Linux安装到U盘上的具体教程

    Arch Linux简介 Arch Linux(或称Arch)是一种以轻量简洁为设计理念的Linux发行版.其开发团队秉承简洁.优雅.正确和代码最小化的设计宗旨.Arch Linux 项目受 CRUX ...

  10. Percona 工具包 pt-online-schema-change 简介

    mysql的在线表结构修改,因为低效和阻塞读写.一直被诟病.至于ALTER TABLE 的原理,参看我上一篇文章.MySQL在线修改大表结构.看完后,发现的问题是还是会锁的,且对于在线更新的这块也是不 ...