转载: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. [LeetCode] Single Number III ( a New Questions Added today)

    Given an array of numbers nums, in which exactly two elements appear only once and all the other ele ...

  2. 时间,闰秒,及NTP

    1.时间 格林尼治时间 GMT,以地球自转为准的时间,也叫世界时UT,但是由于自转速度会变化,所以后来不被作为标准. 世界协调时UTC,以原子钟为准,现在时间校准的标准就是原子钟. 2.闰秒 是指地球 ...

  3. 深入理解jQuery插件开发(转)

    转自:http://blog.jobbole.com/30550/ 如果你看到这篇文章,我确信你毫无疑问会认为jQuery是一个使用简便的库.jQuery可能使用起来很简单,但是它仍然有一些奇怪的地方 ...

  4. Java多线程编程模式实战指南:Active Object模式(下)

    Active Object模式的评价与实现考量 Active Object模式通过将方法的调用与执行分离,实现了异步编程.有利于提高并发性,从而提高系统的吞吐率. Active Object模式还有个 ...

  5. C# 6.0 的新特性

    1. 自动的属性初始化器Auto Property initialzier 之前的方式: public class AutoPropertyBeforeCsharp6 { private string ...

  6. Linux 系统 root下目录结构

    /bin 用于存放普通用户可执行的命令./boot 用于存放Linux 启动所必需的文件,即我们建立的boot 分区的内容./dev 用于存放系统的设备文件./etc 用于存放系统的各种配置文件./h ...

  7. HDU 4562 守护雅典娜(dp)

    守护雅典娜 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submi ...

  8. HDU1973 http://acm.hdu.edu.cn/showproblem.php?pid=1973

    #include<stdio.h> #include<stdlib.h> #include<string.h> #include<queue> #inc ...

  9. BestCoder Round #73 (div.2)(hdu 5630)

    Rikka with Chess Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) ...

  10. BestCoder Round #68 (div.2) tree(hdu 5606)

    tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submis ...