• postcore_initcall(), arch_initcall(), subsys_initcall(), device_initcall() 调用顺序



    http://blog.csdn.net/thl789/article/details/6581146


    在内核源代码中,platform 设备的初始化(注册)用arch_initcall()调用,它的initcall 的level为3;
    
    而驱动的注册用module_init()调用,即device_initcall(),它的initcall 的level为6。
    #define module_init(x) __initcall(x);
    #define __initcall(fn) device_initcall(fn)
    
     kernel 初始化时(kernel_init@init/main.c),按照内核链接文件中(arm系统:kernel/arch/arm/vmlinux.lds)的__init call_start段的序列依次执行,
    这样level小的初始化函数先于level大的初始化函数被调用。
        所以platform设备先被注册,驱动加载时会调用驱动程序中的probe(),扫描系统中已注册的设备,找到匹配设备后将驱动和设备绑定。

    比如I2C,适配器先需要 设备注册;


    =============================

    LINUX内核中有很多的初始化指示标志postcore_initcall(), arch_initcall(), subsys_initcall(), device_initcall(), etc. 这些起什么作用呢?


    1. 初始化标号

    先看这些宏的定义(定义在文件include/linux/init.h中)

    1. #define pure_initcall(fn)               __define_initcall("0",fn,0)  
    2. #define core_initcall(fn)               __define_initcall("1",fn,1)  
    3. #define core_initcall_sync(fn)          __define_initcall("1s",fn,1s)  
    4. #define postcore_initcall(fn)           __define_initcall("2",fn,2)  
    5. #define postcore_initcall_sync(fn)      __define_initcall("2s",fn,2s)  
    6. #define arch_initcall(fn)               __define_initcall("3",fn,3)  
    7. #define arch_initcall_sync(fn)          __define_initcall("3s",fn,3s)  
    8. #define subsys_initcall(fn)             __define_initcall("4",fn,4)  
    9. #define subsys_initcall_sync(fn)        __define_initcall("4s",fn,4s)  
    10. #define fs_initcall(fn)                 __define_initcall("5",fn,5)  
    11. #define fs_initcall_sync(fn)            __define_initcall("5s",fn,5s)  
    12. #define rootfs_initcall(fn)             __define_initcall("rootfs",fn,rootfs)  
    13. #define device_initcall(fn)             __define_initcall("6",fn,6)  
    14. #define device_initcall_sync(fn)        __define_initcall("6s",fn,6s)  
    15. #define late_initcall(fn)               __define_initcall("7",fn,7)  
    16. #define late_initcall_sync(fn)          __define_initcall("7s",fn,7s)  

    2、__define_initcall

    这些宏都用到了__define_initcall(),再看看它的定义(同样定义在文件include/linux/init.h中)

    1. #define __define_initcall(level,fn,id)   
    2.         static initcall_t __initcall_##fn##id __used   
    3.         __attribute__((__section__(".initcall" level ".init"))) = fn  

    这其中initcall_t是函数指针,原型如下,

    1. typedef int (*initcall_t)(void);  

    而属性 __attribute__((__section__())) 则表示把对象放在一个这个由括号中的名称所指代的section中。

    所以__define_initcall的含义是:

    1) 声明一个名称为__initcall_##fn的函数指针;

    2) 将这个函数指针初始化为fn;

    3) 编译的时候需要把这个函数指针变量放置到名称为 ".initcall" level ".init"的section中。


    3.放置.initcall.init SECTION

    明确了__define_initcall的含义,就知道了是分别将这些初始化标号修饰的函数指针放到各自的section中的。

    SECTION“.initcall”level”.init”被放入INITCALLS(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)  

    __initcall_start和__initcall_end以及INITCALLS中定义的SECTION都是在arch/xxx/kernel/vmlinux.lds.S中放在.init段的。

    1. SECTIONS  
    2. {  
    3.         .init : {  
    4.                 __initcall_start = .;  
    5.                         INITCALLS  
    6.                 __initcall_end = .;  
    7.         }  
    8. }  

    4.   初始化.initcallxx.init里的函数

    而这些SECTION里的函数在初始化时被顺序执行(init内核线程->do_basic_setup()[main.c#778]->do_initcalls())。

    程序(init/main.c文件do_initcalls()函数)如下,do_initcalls()把.initcallXX.init中的函数按顺序都执行一遍。

    1. for (call = __early_initcall_end; call < __initcall_end; call++)  
    2.         do_one_initcall(*call); 

    =======================

    http://blog.csdn.net/fenzhikeji/article/details/6860143







  • 相关阅读:
    KAFKA基础(四):Kafka架构深入(2)Kafka 生产者
    逆向工程,调试Hello World !程序(更新中)
    关于网络初级基础知识总结
    真!阿里P10整理的Java面试宝典,学了60%成功砍下了P8级Offer,真爽!
    【专升本计算机】甘肃省2020年专升本计算机测试题
    真!阿里P10整理的Java面试宝典,学了60%成功砍下了P8级Offer,真爽!
    python利用numpy存取文件
    泛在网技术考点整理
    [Python图像处理] 三十二.傅里叶变换(图像去噪)与霍夫变换(特征识别)万字详细总结
    汉诺塔问题
  • 原文地址:https://www.cnblogs.com/liulaolaiu/p/11744590.html
Copyright © 2020-2023  润新知