基于Omapl138开发板linux3.3系统分析do_initcall()函数

参考了网上的很多内容,网上的分析基本上是基于linux2.6或者3.1的内核,对于这个函数而言,其实大同小异,但是几乎没有哪篇文章能一次性把我想要了解的东西全部呈现,所以自己尝试整理如下:



do_initcalls()->

static void __init do_initcalls(void)

{

       	initcall_t *fn;
 	for (fn = __early_initcall_end; fn < __initcall_end; fn++)
 	do_one_initcall(*fn);

}


/linux-3.3/arm/kernel/vmlinux.lds中有下述定义:



__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 = .;


与之类似,

在include\asm-generic中有下述定义:



#define INITCALLS                                          \

       *(.initcallearly.init)                                    \

       VMLINUX_SYMBOL(__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)

#define INIT_CALLS                                                \

              VMLINUX_SYMBOL(__initcall_start)= .;                    \

              INITCALLS                                         \

              VMLINUX_SYMBOL(__initcall_end)= .;


由上面分析可以看出do_initcalls的作用就是遍历一个指针数组,数组内容是对应level的函数指针, 所以这里要干的事情就是依次取出各个level的函数指针fn执行(*fn)回调,
也就是实现了依次遍历各个level的驱动程序。

接着来看do_one_initcall(*fn)这个函数做了什么事情;

int __init_or module do_one_initcall(initcall_t fn)
{
	int count=preempt_count();
	int ret;
	if(initcall_debug)
	ret=do_one_initcall_debug(fn);
	else
	ret=fn();
	.......


省略的部分是发生错误后的处理函数。
我想要分析的主要是具体设备的驱动初始化过程,所以关注的是module_init()的过程,这对应上面指针数组的哪一段呢,可以从下面的分析中得到:



#define __initcall(fn) device_initcall(fn);

#define module_init(x) __initcall(x);

#define module_exit(x) __exitcall(x);



所以module_init(fn)与__initcall(fn)以及device_initcall(fn)这三者是等价的。



#define __define_initcall(level,fn,id) \

       static  initcall_t __initcall_##fn##id __used \

       __attribute__((__section__(".initcall"level ".init"))) = fn

->

#define __used            __attribute__((__unused__))


#define __used attribute((unused))

在gcc手册中找到了有关的解释:

unused:This attribute, attached to a function, means that the function is meant to be possibly unused. GCC will not produce a warning for this function.

表示该函数或变量可能不使用,这个属性可以避免编译器产生警告信息



->

__attribute__((__section__(".initcall"level ".init")))=fn;

__attribute__((section("section_name")))

其作用是将作用的函数或数据放入指定名为"section_name"对应的段中,这句话的意思就是把fn放在“.initcall”
level”.init”段中,

且定义__define_initcall(level,fn,id)与__initcall_##fn##id的意义一致。
具体驱动在内核中加载顺序可以从文件Omapl138/linux3.3/System.map中得到:
在这里用nandflash的驱动举例:



module_init(nand_davinci_init);

module_exit(nand_davinci_exit);

展开上面的宏:

module_init(nand_davinci_init)

->

__initcall(nand_davinci_init)

->

device_initcall(nand_davinci_init)

->

__define_initcall("6", nand_davinci_init,6)

->

static initcall_t __initcall_nand_davinvi_init6__used\

__attribue_((__section_(.”initcall6.init”)))=nand_davinci_init;


明天再具体分析其他驱动的加载流程

猜你喜欢

转载自blog.csdn.net/qq_40788950/article/details/83904424
今日推荐