转载:http://blog.csdn.net/beatbean/article/details/8448623

1. Compile宏控制

位于include/linux/init.h

  1. /* These are for everybody (although not all archs will actually
  2. discard it in modules) */
  3. #define __init      __section(.init.text) __cold notrace
  4. #define __initdata  __section(.init.data)
  5. #define __initconst __section(.init.rodata)
  6. #define __exitdata  __section(.exit.data)
  7. #define __exit_call __used __section(.exitcall.exit)

·首先需要简要说明一下GCC的驱动程序:


#define __init __section(.init.text) __cold notrace
__init用于标记函数,放在.init.text section,标记为初始化的函数,表明该函数供在初始化期间使用。在模块装载之后,模块装载就会将初始化函数扔掉。这样可以将该函数占用的内存释放出来。__initdata用于标记数据
#define __cold   __attribute__((__cold__))
__cold告诉编译器这个函数很可能不被执行到
#define notrace __attribute__((no_instrument_function))
notrace如同GCC的-finstrument-functions() 参数的作用是在程序中加入hook,让它在每次进入和退出函数的时候分别调用这个函数
#define __used   __attribute__((__used__)) 意味着code必须发动附有该宏的函数
__exit修饰词标记函数,只在模块卸载时使用。如果模块被直接编进内核则该函数就不会被调用。如果内核编译时没有包含该模块,则此标记的函数将被简单地丢弃。

  1. #define __ref            __section(.ref.text) noinline
  2. #define __refdata        __section(.ref.data)
  3. #define __refconst       __section(.ref.rodata)

#define  noinline   __attribute__((noinline))  阻止该函数被内联

  1. #define __exit          __section(.exit.text) __exitused __cold notrace
  2. /* Used for HOTPLUG */
  3. #define __devinit        __section(.devinit.text) __cold notrace
  4. #define __devinitdata    __section(.devinit.data)
  5. #define __devinitconst   __section(.devinit.rodata)
  6. #define __devexit        __section(.devexit.text) __exitused __cold notrace
  7. #define __devexitdata    __section(.devexit.data)
  8. #define __devexitconst   __section(.devexit.rodata)
  9. /* Used for HOTPLUG_CPU */
  10. #define __cpuinit        __section(.cpuinit.text) __cold notrace
  11. #define __cpuinitdata    __section(.cpuinit.data)
  12. #define __cpuinitconst   __section(.cpuinit.rodata)
  13. #define __cpuexit        __section(.cpuexit.text) __exitused __cold notrace
  14. #define __cpuexitdata    __section(.cpuexit.data)
  15. #define __cpuexitconst   __section(.cpuexit.rodata)
  16. /* Used for MEMORY_HOTPLUG */
  17. #define __meminit        __section(.meminit.text) __cold notrace
  18. #define __meminitdata    __section(.meminit.data)
  19. #define __meminitconst   __section(.meminit.rodata)
  20. #define __memexit        __section(.memexit.text) __exitused __cold notrace
  21. #define __memexitdata    __section(.memexit.data)
  22. #define __memexitconst   __section(.memexit.rodata)

2. 初始化宏

  1. /* initcalls are now grouped by functionality into separate
  2. * subsections. Ordering inside the subsections is determined
  3. * by link order.
  4. * For backwards compatibility, initcall() puts the call in
  5. * the device init subsection.
  6. *
  7. * The `id' arg to __define_initcall() is needed so that multiple initcalls
  8. * can point at the same handler without causing duplicate-symbol build errors.
  9. */
  10. #define __define_initcall(level,fn,id) \
  11. static initcall_t __initcall_##fn##id __used \
  12. __attribute__((__section__(".initcall" level ".init"))) = fn
  13. /*
  14. * Early initcalls run before initializing SMP.
  15. *
  16. * Only for built-in code, not modules.
  17. */
  18. #define early_initcall(fn)      __define_initcall("early",fn,early)
  19. /*
  20. * A "pure" initcall has no dependencies on anything else, and purely
  21. * initializes variables that couldn't be statically initialized.
  22. *
  23. * This only exists for built-in code, not for modules.
  24. */
  25. #define pure_initcall(fn)       __define_initcall("0",fn,0)
  26. #define core_initcall(fn)       __define_initcall("1",fn,1)
  27. #define core_initcall_sync(fn)      __define_initcall("1s",fn,1s)
  28. #define postcore_initcall(fn)       __define_initcall("2",fn,2)
  29. #define postcore_initcall_sync(fn)  __define_initcall("2s",fn,2s)
  30. #define arch_initcall(fn)       __define_initcall("3",fn,3)
  31. #define arch_initcall_sync(fn)      __define_initcall("3s",fn,3s)
  32. #define subsys_initcall(fn)     __define_initcall("4",fn,4)
  33. #define subsys_initcall_sync(fn)    __define_initcall("4s",fn,4s)
  34. #define fs_initcall(fn)         __define_initcall("5",fn,5)
  35. #define fs_initcall_sync(fn)        __define_initcall("5s",fn,5s)
  36. #define rootfs_initcall(fn)     __define_initcall("rootfs",fn,rootfs)
  37. #define device_initcall(fn)     __define_initcall("6",fn,6)
  38. #define device_initcall_sync(fn)    __define_initcall("6s",fn,6s)
  39. #define late_initcall(fn)       __define_initcall("7",fn,7)
  40. #define late_initcall_sync(fn)      __define_initcall("7s",fn,7s)
  41. #define __initcall(fn) device_initcall(fn)
  42. #define __exitcall(fn) \
  43. static exitcall_t __exitcall_##fn __exit_call = fn
  44. #define console_initcall(fn) \
  45. static initcall_t __initcall_##fn \
  46. __used __section(.con_initcall.init) = fn
  47. #define security_initcall(fn) \
  48. static initcall_t __initcall_##fn \
  49. __used __section(.security_initcall.init) = fn

首先,

__define_initcall声明一个__initcall_##fn##id的initcall_t类型静态函数指针,并设置好属性,定义如下:
typedef int (*initcall_t)(void);
typedef void (*exitcall_t)(void);

然后,初始化为fn,编译的时候就会放在__section__(".initcall" level ".init")里面

3. .initcall.init section

在include/asm-generic/vmlinux.lds.h中定义:

  1. #define INITCALLS                           \
  2. *(.initcallearly.init)                      \
  3. VMLINUX_SYMBOL(__early_initcall_end) = .;           \
  4. *(.initcall0.init)                      \
  5. *(.initcall0s.init)                     \
  6. *(.initcall1.init)                      \
  7. *(.initcall1s.init)                     \
  8. *(.initcall2.init)                      \
  9. *(.initcall2s.init)                     \
  10. *(.initcall3.init)                      \
  11. *(.initcall3s.init)                     \
  12. *(.initcall4.init)                      \
  13. *(.initcall4s.init)                     \
  14. *(.initcall5.init)                      \
  15. *(.initcall5s.init)                     \
  16. *(.initcallrootfs.init)                     \
  17. *(.initcall6.init)                      \
  18. *(.initcall6s.init)                     \
  19. *(.initcall7.init)                      \
  20. *(.initcall7s.init)
  21. #define INIT_CALLS                          \
  22. VMLINUX_SYMBOL(__initcall_start) = .;           \
  23. INITCALLS                       \
  24. VMLINUX_SYMBOL(__initcall_end) = .;
  25. #define CON_INITCALL                            \
  26. VMLINUX_SYMBOL(__con_initcall_start) = .;       \
  27. *(.con_initcall.init)                   \
  28. VMLINUX_SYMBOL(__con_initcall_end) = .;
  29. #define SECURITY_INITCALL                       \
  30. VMLINUX_SYMBOL(__security_initcall_start) = .;      \
  31. *(.security_initcall.init)              \
  32. VMLINUX_SYMBOL(__security_initcall_end) = .;

在arm中section定义如下(arch/arm/kernel/vmlinux.lds.s):

TCM是紧密耦合存储器,速度比 SDRAM 快很多,使得处理器能直接访问独立的指令和数据TCM(ITCM和DTCM)。TCM被用于存储实时性和性能要求极高的代码,它还提供一个DMA支持机制。不像AHP访问外部存储器,访问TCM是快速的,确定的,不造成总线负荷。

  1. .init : {           /* Init code and data       */
  2. _stext = .;
  3. _sinittext = .;
  4. HEAD_TEXT
  5. INIT_TEXT
  6. ARM_EXIT_KEEP(EXIT_TEXT)
  7. _einittext = .;
  8. ARM_CPU_DISCARD(PROC_INFO)
  9. __arch_info_begin = .;
  10. *(.arch.info.init)
  11. __arch_info_end = .;
  12. __tagtable_begin = .;
  13. *(.taglist.init)
  14. __tagtable_end = .;
  15. #ifdef CONFIG_SMP_ON_UP
  16. __smpalt_begin = .;
  17. *(.alt.smp.init)
  18. __smpalt_end = .;
  19. #endif
  20. __pv_table_begin = .;
  21. *(.pv_table)
  22. __pv_table_end = .;
  23. INIT_SETUP(16)
  24. <span style="color:#ff0000;">INIT_CALLS
  25. </span>     CON_INITCALL
  26. SECURITY_INITCALL
  27. INIT_RAM_FS
  28. #ifndef CONFIG_XIP_KERNEL
  29. __init_begin = _stext;
  30. INIT_DATA
  31. ARM_EXIT_KEEP(EXIT_DATA)
  32. #endif
  33. }

#define INIT_CALLS       \
  VMLINUX_SYMBOL(__initcall_start) = .;   \
  INITCALLS      \
  VMLINUX_SYMBOL(__initcall_end) = .;

4. 初始化.initcallxx.init函数

位于init/main.c

  1. extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];
  1. static void __init do_pre_smp_initcalls(void)
  2. {
  3. initcall_t *fn;
  4. for (fn = <span style="color:#ff0000;">__initcall_start</span>; fn < <span style="color:#ff0000;">__early_initcall_end</span>; fn++)
  5. do_one_initcall(*fn);
  6. }
  1. static void __init do_initcalls(void)
  2. {
  3. initcall_t *fn;
  4. for (fn = <span style="color:#ff0000;">__early_initcall_end</span>; fn < <span style="color:#ff0000;">__initcall_end</span>; fn++)
  5. do_one_initcall(*fn);
  6. }
    1. int __init_or_module do_one_initcall(initcall_t fn)
    2. {
    3. int count = preempt_count();
    4. int ret;
    5. if (initcall_debug)
    6. ret = do_one_initcall_debug(fn);
    7. else
    8. <span style="color:#ff0000;">ret = fn();
    9. </span>
    10. msgbuf[0] = 0;
    11. if (ret && ret != -ENODEV && initcall_debug)
    12. sprintf(msgbuf, "error code %d ", ret);
    13. if (preempt_count() != count) {
    14. strlcat(msgbuf, "preemption imbalance ", sizeof(msgbuf));
    15. preempt_count() = count;
    16. }
    17. if (irqs_disabled()) {
    18. strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf));
    19. local_irq_enable();
    20. }
    21. if (msgbuf[0]) {
    22. printk("initcall %pF returned with %s\n", fn, msgbuf);
    23. }
    24. return ret;
    25. }

Linux内核初始化定义的更多相关文章

  1. Linux内核中链表实现

    关于双链表实现,一般教科书上定义一个双向链表节点的方法如下: struct list_node{ stuct list_node *pre; stuct list_node *next; ElemTy ...

  2. [翻译] Linux 内核中的位数组和位操作

    目录 Linux 内核里的数据结构 原文链接与说明 Linux 内核中的位数组和位操作 位数组声明 体系结构特定的位操作 通用位操作 链接 Linux 内核里的数据结构 原文链接与说明 https:/ ...

  3. Linux 内核里的数据结构:位图(bitmap)

    注: 本文由 LCTT 原创翻译,Linux中国 荣誉推出 Linux 内核中的位数组和位操作 除了不同的基于链式和树的数据结构以外,Linux 内核也为位数组(或称为位图(bitmap))提供了 A ...

  4. linux内核分析第三周

    20135103王海宁 linux内核分析第三周 http://mooc.study.163.com/course/USTC-1000029000  按照课堂提供的方法,命令行一行行敲上去,我是手机缓 ...

  5. Linux内核的启动过程分析

    秦鼎涛 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.实验目的及要求: 使用gdb跟踪调试内核从s ...

  6. linux内核分析(网课期末&地面课期中)

    堆栈变化过程: Linux内核分析——计算机是如何工作的 计算机是如何工作的?(总结)——三个法宝 存储程序计算机工作模型,计算机系统最最基础性的逻辑结构: 函数调用堆栈,高级语言得以运行的基础,只有 ...

  7. Linux内核中断处理体系分析

    前一篇博文中:linux内核初始化阶段通过early_trap_init()函数完毕了把异常向量复制到0xFFFF0000開始的地方,这些异常向量大部分指向通过vector_stub宏定义的那段代码. ...

  8. Linux内核设计第三周学习总结 跟踪分析Linux内核的启动过程

    陈巧然 原创作品 转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 实验步骤 登陆实验楼虚 ...

  9. Linux内核分析(三)内核启动过程分析——构造一个简单的Linux系统

    一.系统的启动(各历史节点) 在最开始的时候,计算机的启动实际上依靠一段二进制码,可以这么理解,他并不是一个真正的计算机启动一道程序.计算机在开始加电的时候几乎是没有任何用处的,因为RAM芯片中包括的 ...

随机推荐

  1. 选择学习Pomelo

    我之前的项目都是基于http做网络通信,但是做多玩家同时对战的游戏,http短连接不支持服务器的push是个问题,这样客户端就没办法收到服务器的消息. 最简单的方法是定时发起request询问服务器, ...

  2. UTF编码问题小结

    在编程当中经常出现乱码的问题,而由此一般会引发很多惨剧,如读文件不成功.用户名显示乱码等,所以端午节抽了一小点时间好好看了一下编码问题,以备遗忘. 首先是中文编码,除了台湾和香港常用的BIG5,国内大 ...

  3. C++ 我想这样用(七)

    话接前篇,继续基于对象编程语法的剩余部分: 6.类的const成员函数和const对象 const数据成员:跟const常量一样,只是一个在类里(而且是在构造函数里),一个在类外而已,都必须初始化. ...

  4. Hadoop上路-02_Hadoop FS Shell

    一.上传文件/目录 1)put 从本地文件系统中复制N个源路径到目标文件系统. 2)copyFromLocal 源路径须是一个本地文件. 二.下载文件/目录 1)get 复制文件到本地文件系统. 2) ...

  5. usb mass storage device

    Problem adding USB host device to KVM Windows guest machine. Status: CLOSED CURRENTRELEASE   Aliases ...

  6. UVALive 7464 Robots (贪心)

    Robots 题目链接: http://acm.hust.edu.cn/vjudge/contest/127401#problem/K Description http://7xjob4.com1.z ...

  7. URAL 2040 Palindromes and Super Abilities 2 (回文自动机)

    Palindromes and Super Abilities 2 题目链接: http://acm.hust.edu.cn/vjudge/contest/126823#problem/E Descr ...

  8. c# socket编程简单例子

    服务器端代码 using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Thr ...

  9. Local host name unknown: java.net.UnknownHostException:

    在Linux下安装完resin后,每次启动都出现如下错误: [11:06:45.617] {watchdog-} WatchdogProcess[Watchdog[],7] starting Resi ...

  10. App启动加载广告页面思路

    需求 很多app(如淘宝.美团等)在启动图加载完毕后,还会显示几秒的广告,一般都有个跳过按钮可以跳过这个广告,有的app在点击广告页之后还会进入一个广告页面,点击返回进入首页.今天我们就来开发一个广告 ...