Chinaunix首页 | 论坛 | 博客
  • 博客访问: 29283
  • 博文数量: 7
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 14
  • 用 户 组: 普通用户
  • 注册时间: 2016-02-25 10:58
个人简介

只有不断学习才能站住脚跟。(不是我不明白是世界变化快) ————刚刚入门的驱动工程师

文章分类
文章存档

2017年(1)

2016年(6)

我的朋友

分类: 嵌入式

2016-02-25 11:02:03

原文地址:驱动入口--init_call 族 作者:cuteyoung

1)调用 initcall流程         
        分析驱动首先从模块入口,这些模块在什么时候由系统注册进去的呢?
        对于动态模块经常用 insmod  xxx.ko,当你写的驱动依赖的了一些系统 i2c、时钟等等,另外基于platform 子系统等模块时,其注册时有先后顺序的。 在进入 kernel的第二阶段完成后,进入了 kernel_init 完成对系统的初始化,在 kernel_init 进程最重要的是完成对模块的注册及加载。
    __init start_kernel(void)   (init/main.c)
            __init_refok rest_init(void)
            kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);  //创建一个kernel_init进程
                    __init kernel_init(void * unused)
                            __init do_basic_setup(void)   // 完成最基本的初始话,basic也是最重要的
                            driver_init();
                                    __init driver_init(void)
                                    devices_init();    // 设备驱动最核心容器初始化
                                    buses_init();
                                    classes_init();
                                    platform_bus_init();  // 注册平台总线
                                    system_bus_init();
                                    cpu_dev_init();
                            do_initcalls();
                                     __init do_initcalls(void)
       在 do_initcalls 里面完成 init函数族的调用                      
                            for (fn = __early_initcall_end; fn < __initcall_end; fn++)
                                    do_one_initcall(*fn);
2)驱动入口:        
        动态加载的驱动,需要通过 module_init 进行声明,继续跟下代码,可以看到
              #define module_init(x) __initcall(x);  /kernel/linux/init.h
              #define __initcall(fn) device_initcall(fn)
              #define device_initcall(fn) __define_initcall("6",fn,6)              
                    #define __define_initcall(level,fn,id) \
                        static initcall_t __initcall_##fn##id __used \
                        __attribute__((__section__(".initcall" level ".init"))) = fn
        这里, typedef int (*initcall_t)(void); 就是声明一个函数指针
        可以看到最后调用到  __define_initcall 宏函数, 根据 GNU中的 attribute机制,可以知道就是将这个模块定位到
     .initcallxxx.init 段里面,所有的驱动都定位到这个段里面。这个initcall 族如下:
                #define pure_initcall(fn) __define_initcall("0",fn,0)
                #define core_initcall(fn) __define_initcall("1",fn,1)
#define core_initcall_sync(fn) __define_initcall("1s",fn,1s)
#define postcore_initcall(fn) __define_initcall("2",fn,2)
#define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)
#define arch_initcall(fn) __define_initcall("3",fn,3)
#define arch_initcall_sync(fn) __define_initcall("3s",fn,3s)
#define subsys_initcall(fn) __define_initcall("4",fn,4)
#define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s)
#define fs_initcall(fn) __define_initcall("5",fn,5)
#define fs_initcall_sync(fn) __define_initcall("5s",fn,5s)
#define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)
#define device_initcall(fn) __define_initcall("6",fn,6)
#define device_initcall_sync(fn) __define_initcall("6s",fn,6s)
#define late_initcall(fn) __define_initcall("7",fn,7)
#define late_initcall_sync(fn) __define_initcall("7s",fn,7s)
3)链接脚本中的段:(/arch/arm/kernel/vmlinux.lds)
                  __arch_info_begin = .;
                  *(.arch.info.init)
                  __arch_info_end = .;
  __tagtable_begin = .;
   *(.taglist.init)
  __tagtable_end = .;
  __pv_table_begin = .;
   *(.pv_table)
  __pv_table_end = .;
  . = ALIGN(16); __setup_start = .; *(.init.setup) __setup_end = .;
  __initcall_start = .; *(.initcallearly.init) __early_initcall_end = .; *(.initcall0.init) *(.initcall0s.init) *(.initcall1.init) *(.initcall1s.init) *(.initcall2.init) *(.initcall2s.init) *(.initcall3.init) *(.initcall3s.init) *(.initcall4.init) *(.initcall4s.init) *(.initcall5.init) *(.initcall5s.init) *(.initcallrootfs.init) *(.initcall6.init) *(.initcall6s.init) *(.initcall7.init) *(.initcall7s.init) __initcall_end = .;
在运行是会链接到这个   __initcall_start  ~  __initcall_end 段区间的,这系列 initcall_end完成对系统驱动的加载
4)对这些段进行分组
        可以根据前面几个进行分组:根据其调用流程来看,其实就是按顺序来的,从小数字开始:
                pure 、core、postcore 、archsubsysfsdevicelate
        貌似也没有特殊的意义,在 Android的 init.xxx.rx 里面也有很多的类似大的 Action,我们经常跟那个 device这个打交道。
        #define __init            __section(.init.text)    __cold notrace
#define __initdata      __section(.init.data)
#define __initconst     __section(.init.rodata)
#define __exitdata      __section(.exit.data)
#define __exit_call     __used __section(.exitcall.exit)

5)几个问题:
【1】 这个函数族中的s虽然说是 sync即同步的意思,貌似看不出什么特殊意思
【2】 入口这么多,那么出口却只有一个 module_exit,这个是什么机制呢









阅读(1346) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:神秘的subsys_initcall

给主人留下些什么吧!~~