好贷网好贷款

linux子系统的初始化_subsys_initcall():那些入口函数

发布时间:2016-12-4 18:35:51 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"linux子系统的初始化_subsys_initcall():那些入口函数",主要涉及到linux子系统的初始化_subsys_initcall():那些入口函数方面的内容,对于linux子系统的初始化_subsys_initcall():那些入口函数感兴趣的同学可以参考一下。

内核选项的解析完成之后,各个子系统的初始化即进入第二部分—入口函数的调用。通常USB、PCI这样的子系统都会有一个名为subsys_initcall的入口,如果你选择它们作为研究内核的切入点,那么就请首先找到它。 朱德庸在《关于上班这件事》里说,要花前半生找入口,花后半生找出口。可见寻找入口对于咱们这一生,对于看内核代码这件事儿都是无比重要的。 但是很多时候,入口并不仅仅只有subsys_initcall一个,比如PCI。 以下代码来自linux内核源码中include/linux/init.h文件 117#definepure_initcall(fn)__define_initcall("0",fn,1) 118 119#definecore_initcall(fn)__define_initcall("1",fn,1) 120#definecore_initcall_sync(fn)__define_initcall("1s",fn,1s) 121#definepostcore_initcall(fn)__define_initcall("2",fn,2) 122#definepostcore_initcall_sync(fn)__define_initcall("2s",fn,2s) 123#definearch_initcall(fn)__define_initcall("3",fn,3) 124#definearch_initcall_sync(fn)__define_initcall("3s",fn,3s) 125#definesubsys_initcall(fn)__define_initcall("4",fn,4) 126#definesubsys_initcall_sync(fn)__define_initcall("4s",fn,4s) 127#definefs_initcall(fn)__define_initcall("5",fn,5) 128#definefs_initcall_sync(fn)__define_initcall("5s",fn,5s) 129#definerootfs_initcall(fn)__define_initcall("rootfs",fn,rootfs) 130#definedevice_initcall(fn)__define_initcall("6",fn,6) 131#definedevice_initcall_sync(fn)__define_initcall("6s",fn,6s) 132#definelate_initcall(fn)__define_initcall("7",fn,7) 133#definelate_initcall_sync(fn)__define_initcall("7s",fn,7s) 134 135#define__initcall(fn)device_initcall(fn) 这些入口有个共同的特征,它们都是使用__define_initcall宏定义的。它们的调用也不是随便的,而是按照一定顺序的,这个顺序就取决于__define_initcall宏。__define_initcall宏用来将指定的函数指针放到.initcall.init节里。 .initcall.init节 内核可执行文件由许多链接在一起的对象文件组成。对象文件有许多节,如文本、数据、init数据、bass等等。这些对象文件都是由一个称为链接器脚本的文件链接并装入的。这个链接器脚本的功能是将输入对象文件的各节映射到输出文件中;换句话说,它将所有输入对象文件都链接到单一的可执行文件中,将该可执行文件的各节装入到指定地址处。vmlinux.lds是存在于arch/<target>/目录中的内核链接器脚本,它负责链接内核的各个节并将它们装入内存中特定偏移量处。在vmlinux.lds文件里查找initcall.init就可以看到下面的内容 __inicall_start=.; .initcall.init:AT(ADDR(.initcall.init)– 0xC0000000){ *(.initcall1.init) *(.initcall2.init) *(.initcall3.init) *(.initcall4.init) *(.initcall5.init) *(.initcall6.init) *(.initcall7.init) } __initcall_end=.; 这就告诉我们.initcall.init节又分成了7个子节,而xxx_initcall入口函数指针具体放在哪一个子节里边儿是由xxx_initcall的定义中,__define_initcall宏的参数决定的,比如core_initcall将函数指针放在.initcall1.init子节,device_initcall将函数指针放在了.initcall6.init子节等等。各个子节的顺序是确定的,即先调用.initcall1.init中的函数指针再调用.initcall2.init中的函数指针,等等。不同的入口函数被放在不同的子节中,因此也就决定了它们的调用顺序。 注意:设备驱动程序中常见的module_init(x)函数,查看init.h文件发现, #definemodule_init(x)__initcall(x); #define__initcall(fn) device_initcall(fn) #definedevice_initcall(fn) __define_initcall("6",fn,6) 这样推断module_init调用优先级为6低于subsys_initcall调用优先级4. do_initcalls()函数 那些入口函数的调用由do_initcalls函数来完成。 do_initcall函数通过for循环,由__initcall_start开始,直到__initcall_end结束,依次调用识别到的初始化函数。而位于__initcall_start和__initcall_end之间的区域组成了.initcall.init节,其中保存了由xxx_initcall形式的宏标记的函数地址,do_initcall函数可以很轻松的取得函数地址并执行其指向的函数。 .initcall.init节所保存的函数地址有一定的优先级,越前面的函数优先级越高,也会比位于后面的函数先被调用。 由do_initcalls函数调用的函数不应该改变其优先级状态和禁止中断。因此,每个函数执行后,do_initcalls会检查该函数是否做了任何变化,如果有必要,它会校正优先级和中断状态。 另外,这些被执行的函数有可以完成一些需要异步执行的任务,flush_scheduled_work函数则用于确保do_initcalls函数在返回前等待这些异步任务结束。 666staticvoid__init do_initcalls(void) 667{ 668initcall_t *call; 669intcount =preempt_count(); 670 671for(call=__initcall_start;call <__initcall_end;call++){ 672ktime_t t0,t1,delta; 673char*msg=NULL; 674charmsgbuf[40]; 675intresult; 676 677if(initcall_debug){ 678printk("Callinginitcall 0x%p",*call); 679print_fn_descriptor_symbol(":%s()", 680(unsignedlong)*call); 681printk("/n"); 682t0 =ktime_get(); 683} 684 685result =(*call)(); 686 687if(initcall_debug){ 688t1 =ktime_get(); 689delta =ktime_sub(t1,t0); 690 691printk("initcall0x%p",*call); 692print_fn_descriptor_symbol(":%s()", 693(unsignedlong)*call); 694printk("returned %d./n",result); 695 696printk("initcall0x%p ran for %Ld msecs: ", 697*call,(unsignedlonglong)delta.tv64>>20); 698print_fn_descriptor_symbol("%s()/n", 699(unsignedlong)*call); 700} 701 702if(result&&result !=-ENODEV&&initcall_debug){ 703sprintf(msgbuf,"errorcode %d",result); 704msg =msgbuf; 705} 706if(preempt_count()!=count){ 707msg ="preemptionimbalance"; 708preempt_count()=count; 709} 710if(irqs_disabled()){ 711msg ="disabledinterrupts"; 712local_irq_enable(); 713} 714if(msg){ 715printk(KERN_WARNING"initcallat 0x%p",*call); 716print_fn_descriptor_symbol(":%s()", 717(unsignedlong)*call); 718printk(":returned with %s/n",msg); 719} 720} 721 722/*Make sure there is no pending stuff from the initcall sequence */ 723flush_scheduled_work(); 724}

上一篇:设计模式C++ 笔记二 结构型模式
下一篇:Atlassian Confluence - Sensitive Information Leakage

相关文章

相关评论