分析kernel的initcall函数
 
来源: ChinaUnix博客  日期: 2008.07.19 21:24 (共有条评论) 我要评论
 
分析kernel的initcall函数
Author: Dongas
Data: 08-07-15

先来看看这些initcall函数的声明:
/* include/linux/init.h */
/* 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.
*/

#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)

#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 \
       __attribute_used__ __attribute__((__section__(".con_initcall.init")))=fn

#define security_initcall(fn) \
       static initcall_t __initcall_##fn \
       __attribute_used__ __attribute__((__section__(".security_initcall.init"))) = fn

#define module_init(x)   __initcall(x);    ß从这里知道module_init的等级为6,相对靠后
#define module_exit(x)  __exitcall(x);

可以发现这些*_initcall(fn)最终都是通过__define_initcall(level,fn)宏定义生成的。
__define_initcall宏定义如下:
#define __define_initcall(level,fn) \
       static initcall_t __initcall_##fn __attribute_used__ \
       __attribute__((__section__(".initcall" level ".init"))) = fn

这句话的意思为定义一个initcall_t型的初始化函数,函数存放在.initcall”level”.init section内。.initcall”level”.init section定义在vmlinux.lds内。
/* arch/arm/kernel/vmlinux.lds */
……
  __initcall_start = .;
   *(.initcall1.init)
   *(.initcall2.init)
   *(.initcall3.init)
   *(.initcall4.init)
   *(.initcall5.init)
   *(.initcall6.init)
   *(.initcall7.init)
  __initcall_end = .;
       ……
正好包括了上面init.h里定义的从core_initcall到late_initcall等7个level等级的.initcall”level”.init section. 因此通过不同的*_initcall声明的函数指针最终都会存放不同level等级的.initcall”level”.init section内。这些不同level的section按level等级高低依次存放。

下面我们再来看看,内核是什么时候调用存储在.initcall”level”.init section内的函数的。

内核是通过do_initcalls函数循环调用执行initcall.init section内的函数的,流程如下:
start_kernel -> rest_init -> kernel_thread -> init -> do_basic_setup -> do_initcalls

这里要分析两个函数: kernel_thread和do_initcalls,这两个函数都定义在init/main.c内
1)    kernel_thread
1.static void noinline rest_init(void)
2.    __releases(kernel_lock)
3.{
4.    system_state = SYSTEM_BOOTING_SCHEDULER_OK;
5.
6.    kernel_thread(init, NULL, CLONE_FS | CLONE_SIGHAND);
7.    numa_default_policy();
8.    unlock_kernel();
9.
10.  /*
11.  * The boot idle thread must execute schedule()
12.  * at least one to get things moving:
13.  */
14.  __preempt_enable_no_resched();
15.  schedule();
16.  preempt_disable();
17.
18.  /* Call into cpu_idle with preempt disabled */
19.  cpu_idle();
20.}
第6行通过kernel_thread创建一个内核线程执行init函数。(其实这里创建的即Linux的1号进程(init进程), 为linux中所有其他进程的父进程,有兴趣的可以自己查资料)

2)    do_initcalls
1.static void __init do_initcalls(void)
2.{
3.    initcall_t *call;
4.    int count = preempt_count();
5.
6.    for (call = __initcall_start; call 
7.           ……
8.           result = (*call)();
9.           ……
10.  }
11.}
其中, initcall_t类型如下:
typedef int (*initcall_t)(void);

__initcall_start和__initcall_end定义在vmlinux.lds内,表示initcall section的起始和结束地址。
/* arch/arm/kernel/vmlinux.lds */
……
  __initcall_start = .;
   *(.initcall1.init)
   *(.initcall2.init)
   *(.initcall3.init)
   *(.initcall4.init)
   *(.initcall5.init)
   *(.initcall6.init)
   *(.initcall7.init)
  __initcall_end = .;
       ……
因此,上面6-10行代码的作用为按initcall level等级的顺序,依次循环调用预先存储在initcall section内的所有各个级别的初始化函数。这样,kernel的initcall函数的原理我们就搞清楚了。

最后要注意的是rest_init是在start_kernel函数内最后部分才被调用执行的,rest_init前包含了kernel一系列的初始化工作。另外,这些不同level等级的initcall.init section本身有一定的执行顺序,因此如果你的驱动依赖于特定的执行顺序的话需要考虑到这一点。

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/60011/showart_1086523.html

(转)分析kernel的initcall函数的更多相关文章

  1. 第3阶段——内核启动分析之start_kernel初始化函数(5)

    内核启动分析之start_kernel初始化函数(init/main.c) stext函数启动内核后,就开始进入start_kernel初始化各个函数, 下面只是浅尝辄止的描述一下函数的功能,很多函数 ...

  2. MediaInfo源代码分析 2:API函数

    本文主要分析MediaInfo的API函数.它的API函数位于MediaInfo.h文件中的一个叫做MediaInfo的类中. 该类如下所示,部分重要的方法已经加上了注释: //MediaInfo类 ...

  3. 实验作业:使gdb跟踪分析一个系统调用内核函数

    实验作业:使gdb跟踪分析一个系统调用内核函数(我使用的是getuid) 20135313吴子怡.北京电子科技学院 [第一部分] 根据视频演示的步骤,先做第一部分,步骤如下 ①更新menu代码到最新版 ...

  4. LInux设备驱动分析—— kmalloc和kzalloc函数

    今晚在研究EVM5728开发板上面Linux系统的IIC设备驱动程序,偶然之间看到驱动程序中有一处使用了kzalloc函数,本人之前都是使用Linux内核提供的kmalloc / kfree函数来给设 ...

  5. 网络游戏逆向分析-3-通过发包函数找功能call

    网络游戏逆向分析-3-通过发包函数找功能call 网络游戏和单机游戏的分析有相似点,但是区别还是很大的. 网络游戏和单机游戏的区别: 网络游戏是需要和服务器进行交互的,网游中的所有功能几乎都会先发送封 ...

  6. 6.分析request_irq和free_irq函数如何注册注销中断

    上一节讲了如何实现运行中断,这些都是系统给做好的,当我们想自己写个中断处理程序,去执行自己的代码,就需要写irq_desc->action->handler,然后通过request_irq ...

  7. 第3阶段——内核启动分析之创建si工程和分析stext启动内核函数(4)

    目标: (1)创建Source Insight 工程,方便后面分析如何启动内核的 (2)分析uboot传递参数,链接脚本如何进入stext的  (3) 分析stext函数如何启动内核:  (3.1) ...

  8. 6.分析request_irq和free_irq函数如何注册注销中断(详解)

    上一节讲了如何实现运行中断,这些都是系统给做好的,当我们想自己写个中断处理程序,去执行自己的代码,就需要写irq_desc->action->handler,然后通过request_irq ...

  9. Windows系统调用架构分析—也谈KiFastCallEntry函数地址的获取

    为什么要写这篇文章 1.      因为最近在学习<软件调试>这本书,看到书中的某个调试历程中讲了Windows的系统调用的实现机制,其中讲到了从Ring3跳转到Ring0之后直接进入了K ...

随机推荐

  1. [转]Win7独立语言包下载

    想找个语言包太不容易了 ,全是旧版的,最后不得以...在国外网站找到了下载地址,全部是最新的语言包!自己找对应语言的缩写吧 64-bit (x64) Windows 7 SP1: http://dow ...

  2. ubuntu16安装配置nginx

    Nginx ("engine x") 是一个高性能的 HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器. Nginx 是由 Igor Sysoev ...

  3. TCP协议具体解释(上)

     TCP协议具体解释 3.1 TCP服务的特点 TCP协议相对于UDP协议的特点是面向连接.字节流和可靠传输. 使用TCP协议通信的两方必须先建立链接.然后才干開始数据的读写.两方都必须为该链接分 ...

  4. vim+cscope简易教程

    Cscope具有纯正的Unix血统,它最早是由贝尔实验室为PDP-11计算机开发的,后来成为商用的AT&T Unix发行版的组成部分.直到2000年4月,这个工具才由SCO公司以BSD lic ...

  5. ISE和Modelsim联合仿真(详细步骤讲解)

    ISE和Modelsim联合仿真(转) 地址:http://www.cnblogs.com/feitian629/archive/2013/07/13/3188192.html 相信很多人会遇到过这个 ...

  6. 【Android】20.2 视频播放

    分类:C#.Android.VS2015: 创建日期:2016-03-11 一.简介 本节例子和上一节的音频播放例子相似,也是最简单的示例,比如并没有考虑视频播放过程中电话打入的情况,也没有考虑复杂的 ...

  7. 【Android】2.1 PhonewordApp—第1个Android应用程序

    分类:C#.Android.VS2015:  创建日期:2016-02-04 本例子演示如何添加一个简单的单页导航,在此基础上,再演示如何在第2个页面中显示第1个页面中拨打过的所有电话号码. (1)通 ...

  8. 将一个4X4的数组进行逆时针旋转90度后输出,要求原数组数据随机输入

    //将一个4X4的数组进行逆时针旋转90度后输出,要求原数组数据随机输入 #include<stdio.h> int main() { int a[4][4],b[4][4],i,j;// ...

  9. 在windows环境下编译hadoop

    1.环境准备 1.1 JDK的安装 下载jdk1.6.0_43(这里务必要使用jdk的1.6版本,因为使用JDK1.7版本编译hadoop的时候,很多Maven依赖下载不完整,最终会报错)解压到,并将 ...

  10. HttpClient 教程 (四)

    第四章 HTTP认证 HttpClient提供对由HTTP标准规范定义的认证模式的完全支持.HttpClient的认证框架可以扩展支持非标准的认证模式,比如NTLM和SPNEGO. 4.1 用户凭证 ...