linux中init相关内容定义在include/linux/init.h

  1. initcall相关定义

先看下文件说明,此文件定义的宏主要用于初始化阶段标记函数或初始化数据,之后占用的资源会被释放掉。

/* These macros are used to mark some functions or

* initialized data (doesn't apply to uninitialized data)

* as `initialization' functions. The kernel can take this

* as hint that the function is used only during the initialization

* phase and free up used memory resources after

*

* Usage:

* For functions:

*

* You should add __init immediately before the function name, like:

*

* static void __init initme(int x, int y)

* {

*    extern int z; z = x * y;

* }

*

* If the function has a prototype somewhere, you can also add

* __init between closing brace of the prototype and semicolon:

*

* extern int initialize_foobar_device(int, int, int) __init;

*

* For initialized data:

* You should insert __initdata between the variable name and equal

* sign followed by value, e.g.:

*

* static int init_variable __initdata = 0;

* static char linux_logo[] __initdata = { 0x32, 0x36, ... };

*

* Don't forget to initialize data not at file scope, i.e. within a function,

* as gcc otherwise puts the data into the bss section and not into the init

* section.

*

* Also note, that this data cannot be "const".

*/

在内核中经常会看到arch_initcall()、subsys_initcall()、device_initcall()等,定义均在include/linux/init.h中:

#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_initcall()宏定义:

/* 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

*/

#define __define_initcall(level,fn,id) \

static initcall_t __initcall_##fn##id __used \

__attribute__((__section__(".initcall" level ".init"))) = fn

typedef int (*initcall_t)(void);

typedef void (*exitcall_t)(void);

*_initcall(fn)最终都是通过__define_initcall(level,fn,id)宏定义生成,而最终所有的initcall_t型函数都存放在.initcall”level”.init section中。.initcall”level”.init定义在vmlinux.lds内。

/* arch/arm/kernel/vmlinux.lds */

__initcall_start = .;

*(.initcallearly.init) __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_end = .;

正好包括了上面init.h里定义的从pure_initcall到late_initcall等8个level等级的.initcall”level”.init section. 因此通过不同的*_initcall声明的函数指针最终都会存放不同level等级的.initcall”level”.init section内。这些不同level的section按level等级高低依次存放。

附:模块相关定义

内核内置模块定义

/**

* 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);

/**

* module_exit() - driver exit entry point

* @x: function to be run when driver is removed

*

* module_exit() will wrap the driver clean-up code

* with cleanup_module() when used with rmmod when

* the driver is a module.  If the driver is statically

* compiled into the kernel, module_exit() has no effect.

* There can only be one per module.

*/

#define module_exit(x)  __exitcall(x);

单独模块定义#define MODULE

/* Each module must use one module_init(). */

#define module_init(initfn)                 \

static inline initcall_t __inittest(void)       \

{ return initfn; }                  \

int init_module(void) __attribute__((alias(#initfn)));

/* This is only required if you want to be unloadable. */

#define module_exit(exitfn)                 \

static inline exitcall_t __exittest(void)       \

{ return exitfn; }                  \

void cleanup_module(void) __attribute__((alias(#exitfn)));

#define __setup_param(str, unique_id, fn)   /* nothing */

#define __setup(str, func)          /* nothing */

2.initcall相关调用

内核是通过do_initcalls函数循环调用执行initcall.init section内的函数的,流程如下(init/main.c):

start_kernel -> rest_init -> kernel_thread -> kernel_init -> do_basic_setup -> do_initcalls

kernel_thread创建一个内核线程执行kernel_init函数(linux的1号进程-init进程)

extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];

static void __init do_initcalls(void)

{

initcall_t *call;

for (call = __early_initcall_end; call < __initcall_end; call++)

do_one_initcall(*call);

/* Make sure there is no pending stuff from the initcall sequence */

flush_scheduled_work();

}

do_initcalls()遍历.initcall*.init段,依次执行各个级别的函数。

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

参考:http://linux.chinaunix.net/techdoc/develop/2008/07/19/1018489.shtml

内核initcall分析的更多相关文章

  1. MINIX3 内核时钟分析

    MINIX3 内核时钟分析  4.1 内核时钟概要  先想想为什么 OS 需要时钟?时钟是异步的一个非常重要的标志,设想一下,如 果我们的应用程序需要在多少秒后将触发某个程序或者进程,我们该怎么做到? ...

  2. mkimage工具 加载地址和入口地址 内核启动分析

    第三章第二节 mkimage工具制作Linux内核的压缩镜像文件,需要使用到mkimage工具.mkimage这个工具位于u-boot-2013. 04中的tools目录下,它可以用来制作不压缩或者压 ...

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

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

  4. 几个常用内核函数(《Windows内核情景分析》)

    参考:<Windows内核情景分析> 0x01  ObReferenceObjectByHandle 这个函数从句柄得到对应的内核对象,并递增其引用计数. NTSTATUS ObRefer ...

  5. [1]windows 内核情景分析---说明

    本文说明:这一系列文章(笔记)是在看雪里面下载word文档,现转帖出来,希望更多的人能看到并分享,感谢原作者的分享精神. 说明 本文结合<Windows内核情景分析>(毛德操著).< ...

  6. windows内核情景分析之—— KeRaiseIrql函数与KeLowerIrql()函数

    windows内核情景分析之—— KeRaiseIrql函数与KeLowerIrql()函数 1.KeRaiseIrql函数 这个 KeRaiseIrql() 只是简单地调用 hal 模块的 KfRa ...

  7. Linux内核源代码分析方法

    Linux内核源代码分析方法   一.内核源代码之我见 Linux内核代码的庞大令不少人"望而生畏",也正由于如此,使得人们对Linux的了解仅处于泛泛的层次.假设想透析Linux ...

  8. Netlink 内核实现分析(二):通信

    在前一篇博文<Netlink 内核实现分析(一):创建>中已经较为具体的分析了Linux内核netlink子系统的初始化流程.内核netlink套接字的创建.应用层netlink套接字的创 ...

  9. 《LINUX3.0内核源代码分析》第二章:中断和异常 【转】

    转自:http://blog.chinaunix.net/uid-25845340-id-2982887.html 摘要:第二章主要讲述linux如何处理ARM cortex A9多核处理器的中断.异 ...

随机推荐

  1. postgres基础知识

    postgres是连接到具体的库:   ./psql -U postgres  不指定库,默认就是用户名的同名库   ./psql -d chat -U postgres  指定chat库   pos ...

  2. Kali Linux Wine32英文字体不显示问题

     Kali Linux Wine32英文字体不显示问题 Kali Linux提供了Wine32工具.在运行Wine32后,界面可以显示中文,但不能显示英文文字.英文文字均显示为方块.这是由于缺少对应的 ...

  3. 又是一年NOIP然鹅我考的是高数(虽然我没打并且内容与NOIP无关)(手动滑稽)

    好长时间没有写过总结了.也是高三结束,自招结束.成功的由国宝变为四害,整个人也是完全放松的,或者说是放肆的. 整个暑假都是游戏睡觉,游戏睡觉,也没有干什么有意义的事.有人说别人都在学习大一课程的时候我 ...

  4. Android访问WCF服务(使用json实现参数传递)

    经过多日努力, 终于勉强弄明白了Android访问WCF服务的方法. 服务端实现 一, 实现服务. 操作契约 [ServiceContract] public interface IService { ...

  5. DELPHI7下SUPPEROBJECT遍历子对象的name和value

    DELPHI7下SUPPEROBJECT遍历子对象的name和value var ite: TSuperAvlIterator; while ite.MoveNext do begin if ite. ...

  6. 深入理解brew link命令

    来源:https://newsn.net/say/brew-link-php71.html brew是mac机上面程序猿非常常用的软件包安装方式,其中有两组命令是需要大家知晓的.分别是: 第一组:br ...

  7. 开源 java CMS - FreeCMS2.3会员我的留言

    原文地址:http://javaz.cn/site/javaz/site_study/info/2015/29631.html​ 项目地址:http://www.freeteam.cn/ 我的留言 从 ...

  8. OpenGL帧缓存对象(FBO:Frame Buffer Object) 【转】

    http://blog.csdn.net/dreamcs/article/details/7691690 原文地址http://www.songho.ca/opengl/gl_fbo.html 但有改 ...

  9. 新人补钙系列教程之:AS3 与 PHP 简单通信基础

    package { import flash.display.Loader; import flash.events.Event; import flash.net.URLLoader; import ...

  10. hdu 4512 吉哥系列故事——完美队形I(最长公共上升自序加强版)

    首先要去学习最长公共上升子序列LCIS.然后是对n*n效率的算法进行优化,这里要注意的是能够求出来的序列中间能够有一个最高的.刚開始将输入的数组进行逆置,写下来发现这可能存在问题. 只是详细是什么也没 ...