Linux内核初始化定义

转载: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的驱动程序:

Linux内核初始化定义
#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):
Linux内核初始化定义

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
Linux内核初始化定义

  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. }
上一篇:grumble.js


下一篇:PHP手机获取6为不反复验证码