博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux内核初始化定义
阅读量:5262 次
发布时间:2019-06-14

本文共 7696 字,大约阅读时间需要 25 分钟。

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

 

1. Compile宏控制

位于include/linux/init.h

[cpp] 
 
  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修饰词标记函数,只在模块卸载时使用。如果模块被直接编进内核则该函数就不会被调用。如果内核编译时没有包含该模块,则此标记的函数将被简单地丢弃。

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

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

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

2. 初始化宏

[cpp] 
 
  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.   
  11. #define __define_initcall(level,fn,id) \  
  12.     static initcall_t __initcall_##fn##id __used \  
  13.     __attribute__((__section__(".initcall" level ".init"))) = fn  
  14.   
  15. /* 
  16.  * Early initcalls run before initializing SMP. 
  17.  * 
  18.  * Only for built-in code, not modules. 
  19.  */  
  20. #define early_initcall(fn)      __define_initcall("early",fn,early)  
  21.   
  22. /* 
  23.  * A "pure" initcall has no dependencies on anything else, and purely 
  24.  * initializes variables that couldn't be statically initialized. 
  25.  * 
  26.  * This only exists for built-in code, not for modules. 
  27.  */  
  28. #define pure_initcall(fn)       __define_initcall("0",fn,0)  
  29.   
  30. #define core_initcall(fn)       __define_initcall("1",fn,1)  
  31. #define core_initcall_sync(fn)      __define_initcall("1s",fn,1s)  
  32. #define postcore_initcall(fn)       __define_initcall("2",fn,2)  
  33. #define postcore_initcall_sync(fn)  __define_initcall("2s",fn,2s)  
  34. #define arch_initcall(fn)       __define_initcall("3",fn,3)  
  35. #define arch_initcall_sync(fn)      __define_initcall("3s",fn,3s)  
  36. #define subsys_initcall(fn)     __define_initcall("4",fn,4)  
  37. #define subsys_initcall_sync(fn)    __define_initcall("4s",fn,4s)  
  38. #define fs_initcall(fn)         __define_initcall("5",fn,5)  
  39. #define fs_initcall_sync(fn)        __define_initcall("5s",fn,5s)  
  40. #define rootfs_initcall(fn)     __define_initcall("rootfs",fn,rootfs)  
  41. #define device_initcall(fn)     __define_initcall("6",fn,6)  
  42. #define device_initcall_sync(fn)    __define_initcall("6s",fn,6s)  
  43. #define late_initcall(fn)       __define_initcall("7",fn,7)  
  44. #define late_initcall_sync(fn)      __define_initcall("7s",fn,7s)  
  45.   
  46. #define __initcall(fn) device_initcall(fn)  
  47.   
  48. #define __exitcall(fn) \  
  49.     static exitcall_t __exitcall_##fn __exit_call = fn  
  50.   
  51. #define console_initcall(fn) \  
  52.     static initcall_t __initcall_##fn \  
  53.     __used __section(.con_initcall.init) = fn  
  54.   
  55. #define security_initcall(fn) \  
  56.     static initcall_t __initcall_##fn \  
  57.     __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中定义:

[cpp] 
 
  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.   
  22. #define INIT_CALLS                          \  
  23.         VMLINUX_SYMBOL(__initcall_start) = .;           \  
  24.         INITCALLS                       \  
  25.         VMLINUX_SYMBOL(__initcall_end) = .;  
  26.   
  27. #define CON_INITCALL                            \  
  28.         VMLINUX_SYMBOL(__con_initcall_start) = .;       \  
  29.         *(.con_initcall.init)                   \  
  30.         VMLINUX_SYMBOL(__con_initcall_end) = .;  
  31.   
  32. #define SECURITY_INITCALL                       \  
  33.         VMLINUX_SYMBOL(__security_initcall_start) = .;      \  
  34.         *(.security_initcall.init)              \  
  35.         VMLINUX_SYMBOL(__security_initcall_end) = .;  

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

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

[cpp] 
 
  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.   
  21.         __pv_table_begin = .;  
  22.             *(.pv_table)  
  23.         __pv_table_end = .;  
  24.   
  25.         INIT_SETUP(16)  
  26.   
  27.         <span style="color:#ff0000;">INIT_CALLS  
  28. </span>     CON_INITCALL  
  29.         SECURITY_INITCALL  
  30.         INIT_RAM_FS  
  31.   
  32. #ifndef CONFIG_XIP_KERNEL  
  33.         __init_begin = _stext;  
  34.         INIT_DATA  
  35.         ARM_EXIT_KEEP(EXIT_DATA)  
  36. #endif  
  37.     }  

#define INIT_CALLS       \

  VMLINUX_SYMBOL(__initcall_start) = .;   \
  INITCALLS      \
  VMLINUX_SYMBOL(__initcall_end) = .;

4. 初始化.initcallxx.init函数

位于init/main.c

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

转载于:https://www.cnblogs.com/pengdonglin137/p/3533861.html

你可能感兴趣的文章
161017、SQL必备知识点
查看>>
kill新号专题
查看>>
MVC学习系列——Model验证扩展
查看>>
C# GC 垃圾回收机制
查看>>
mysqladmin 修改和 初始化密码
查看>>
字符串
查看>>
vue2.x directive - 限制input只能输入正整数
查看>>
实现MyLinkedList类深入理解LinkedList
查看>>
自定义返回模型
查看>>
C#.NET 大型通用信息化系统集成快速开发平台 4.1 版本 - 客户端多网络支持
查看>>
HDU 4122
查看>>
Suite3.4.7和Keil u3自带fx2.h、fx2regs.h文件的异同
查看>>
打飞机游戏【来源于Crossin的编程教室 http://chuansong.me/account/crossincode 】
查看>>
[LeetCode] Merge Intervals
查看>>
【翻译自mos文章】当点击完 finishbutton后,dbca 或者dbua hang住
查看>>
Linux编程简介——gcc
查看>>
一种高效的序列化方式——MessagePack
查看>>
2019年春季学期第四周作业
查看>>
2019春第十周作业
查看>>
解决ThinkPHP关闭调试模式时报错的问题汇总
查看>>