Linux内核中的xx_initcall

本文编辑整理自:<wbr style="line-height:25px"><a rel="nofollow" href="http://www.linuxidc.com/Linux/2011-09/43354.htm" style="color:rgb(207,121,28); line-height:25px; text-decoration:none">http://www.linuxidc.com/Linux/2011-09/43354.htm</a> <div style="line-height:25px"> <div style="line-height:25px"><span style="color:#003366; line-height:25px">先看这些宏的定义(定义在文件include/linux/init.h中)</span></div> <div style="line-height:25px"> <span style="color:#0000ff; line-height:25px">#define</span>pure_initcall(fn) __define_initcall("0",fn,0) </div> <div style="line-height:25px"> <span style="color:#0000ff; line-height:25px">#define</span>core_initcall(fn) __define_initcall("1",fn,1) </div> <div style="line-height:25px"> <span style="color:#0000ff; line-height:25px">#define</span>core_initcall_sync(fn) __define_initcall("1s",fn,1s) </div> <div style="line-height:25px"> <span style="color:#0000ff; line-height:25px">#define</span>postcore_initcall(fn) __define_initcall("2",fn,2) </div> <div style="line-height:25px"> <span style="color:#0000ff; line-height:25px">#define</span>postcore_initcall_sync(fn) __define_initcall("2s",fn,2s) </div> <div style="line-height:25px"> <span style="color:#0000ff; line-height:25px">#define</span>arch_initcall(fn) __define_initcall("3",fn,3) </div> <div style="line-height:25px"> <span style="color:#0000ff; line-height:25px">#define</span>arch_initcall_sync(fn) __define_initcall("3s",fn,3s) </div> <div style="line-height:25px"> <span style="color:#0000ff; line-height:25px">#define</span>subsys_initcall(fn) __define_initcall("4",fn,4) </div> <div style="line-height:25px"> <span style="color:#0000ff; line-height:25px">#define</span>subsys_initcall_sync(fn) __define_initcall("4s",fn,4s) </div> <div style="line-height:25px"> <span style="color:#0000ff; line-height:25px">#define</span>fs_initcall(fn) __define_initcall("5",fn,5) </div> <div style="line-height:25px"> <span style="color:#0000ff; line-height:25px">#define</span>fs_initcall_sync(fn) __define_initcall("5s",fn,5s) </div> <div style="line-height:25px"> <span style="color:#0000ff; line-height:25px">#define</span>rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs) </div> <div style="line-height:25px"> <span style="color:#0000ff; line-height:25px">#define</span><span style="color:#ff00ff; line-height:25px">device_initcall(fn)</span><span style="color:#ff6600; line-height:25px"></span> <span style="color:#0000ff; line-height:25px"> __define_initcall("6",fn,6) </span> </div> <div style="line-height:25px"> <span style="color:#0000ff; line-height:25px">#define</span>device_initcall_sync(fn) __define_initcall("6s",fn,6s) </div> <div style="line-height:25px"> <span style="color:#0000ff; line-height:25px">#define</span>late_initcall(fn) __define_initcall("7",fn,7) </div> <div style="line-height:25px"> <span style="color:#0000ff; line-height:25px">#define</span>late_initcall_sync(fn) __define_initcall("7s",fn,7s) </div> <div style="line-height:25px"><span style="color:#003366; line-height:25px">这些宏都用到了__define_initcall(),再看看它的定义(同样定义在文件include/linux/init.h中)</span></div> </div> <div style="line-height:25px"> <div style="line-height:25px"> <span style="color:#0000ff; line-height:25px">#define</span>__define_initcall(level,<span style="color:#ff00ff; line-height:25px">fn</span>,id) \ </div> <div style="line-height:25px"> <span style="color:#ff0000; line-height:25px">static</span><span style="color:#ff9900; line-height:25px">initcall_t</span><span style="color:#99cc00; line-height:25px">__initcall_##fn##id</span><span style="color:#ff6600; line-height:25px">__used</span>\ </div> <div style="line-height:25px"> <span style="color:#ff6600; line-height:25px">__attribute__</span>((<span style="color:#ff6600; line-height:25px">__section__</span>(".<span style="color:#808000; line-height:25px">initcall</span>"<span style="color:#808000; line-height:25px">level</span>"<span style="color:#808000; line-height:25px">.init</span>"))) =<span style="color:#ff00ff; line-height:25px">fn</span> </div> </div> <div style="line-height:25px"> <div style="line-height:25px"> <span style="color:#000080; line-height:25px">这其中</span><span style="color:#ff9900; line-height:25px">initcall_t</span><span style="color:#000080; line-height:25px">是函数指针,原型如下,</span> </div> <div style="line-height:25px"><span style="color:#0000ff; line-height:25px">typedef int (*initcall_t)(void); </span></div> <div style="line-height:25px"> <span style="color:#000080; line-height:25px">而编译器宏</span><span style="color:#ff6600; line-height:25px">__attribute__((__section__()))</span><span style="color:#000080; line-height:25px">则表示把对象放在一个这个由括号中的名称所指代的section中。</span> </div> <div style="line-height:25px"> <span style="color:#000080; line-height:25px"><span style="line-height:25px; color:rgb(0,0,255)">__define_initcall("6",fn,6)</span>则是把fn的地址放到.</span><span style="color:#808000; line-height:22px">initcall</span><span style="color:#ff00ff; line-height:22px">6</span><span style="color:#808000; line-height:22px">.</span><span style="color:#808000; line-height:22px">init</span><span style="color:#000080; line-height:22px">这个selection中</span> </div> <div style="line-height:25px"> <span style="color:#000080; line-height:25px">另外,注意这里</span><span style="line-height:25px; color:rgb(255,0,0)">static</span><span style="line-height:25px; color:rgb(0,0,128)">的作用,只是当前编译单元可见,从全局来看的</span><span style="line-height:25px; color:rgb(153,204,0)">__initcall_##fn##id</span><span style="line-height:25px; color:rgb(0,0,128)">完整名字,是要加当前编译文件名(或称当前编译单位名)作为前缀的</span> </div> <div style="line-height:25px"><span style="color:#000080; line-height:25px">所以__define_initcall的含义是:</span></div> <div style="line-height:25px"> <span style="line-height:25px">1)</span><span style="color:#000080; line-height:25px">声明一个名称为__initcall_##fn的函数指针;</span> </div> <div style="line-height:25px"> <span style="line-height:25px">2)</span><span style="color:#000080; line-height:25px">将这个函数指针初始化为fn;</span> </div> <div style="line-height:25px"> <span style="line-height:25px">3)</span><span style="color:#000080; line-height:25px">编译的时候需要把这个函数指针变量放置到名称为</span><span style="color:#000080; line-height:25px">".</span><span style="color:#808000; line-height:25px">initcall</span><span style="color:#000080; line-height:25px">"</span><span style="color:#808000; line-height:25px">level</span><span style="color:#000080; line-height:25px">"</span><span style="color:#808000; line-height:25px">.init</span><span style="color:#000080; line-height:25px">"的section中</span> </div> </div> <div style="line-height:25px"> <div style="line-height:25px"> <span style="color:#003366; line-height:25px">明确了</span><span style="color:#ff6600; line-height:25px">__define_initcall</span><span style="color:#003366; line-height:25px">的含义,就知道了它其实是分别将这些初始化标号修饰的函数指针放到各自的section中的。</span> </div> <div style="line-height:25px"> <span style="color:#003366; line-height:25px">SECTION“</span><span style="color:#808000; line-height:25px">.initcall</span><span style="color:#003366; line-height:25px">”</span><span style="color:#808000; line-height:25px">level</span><span style="color:#003366; line-height:25px">”.</span><span style="color:#808000; line-height:25px">init</span><span style="color:#003366; line-height:25px">”被放入</span><span style="color:#ff6600; line-height:25px">INITCALLS</span><span style="color:#003366; line-height:25px">(</span><span style="color:#0000ff; line-height:25px">include/asm-generic/vmlinux.lds.h</span><span style="color:#003366; line-height:25px">)</span> </div> </div> <div style="line-height:25px"> <div style="line-height:25px"> <span style="color:#0000ff; line-height:25px">#define</span><span style="color:#ff6600; line-height:25px">INITCALLS</span><span style="color:#3366ff; line-height:25px"> \ </span> </div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"> *(.initcallearly.init) \ </span></div> <div style="line-height:25px"> <span style="color:#3366ff; line-height:25px"> VMLINUX_SYMBOL(</span><span style="color:#99cc00; line-height:25px">__early_initcall_end</span><span style="color:#ff6600; line-height:25px">)</span><span style="color:#3366ff; line-height:25px">=<span style="line-height:25px"></span></span><span style="color:#ff00ff; line-height:25px"><span style="line-height:25px">.</span></span><span style="color:#3366ff; line-height:25px">; \ </span> </div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"> *(.initcall0.init) \ </span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"> *(.initcall0s.init) \ </span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"> *(.initcall1.init) \ </span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"> *(.initcall1s.init) \ </span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"> *(.initcall2.init) \ </span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"> *(.initcall2s.init) \ </span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"> *(.initcall3.init) \ </span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"> *(.initcall3s.init) \ </span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"> *(.initcall4.init) \ </span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"> *(.initcall4s.init) \ </span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"> *(.initcall5.init) \ </span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"> *(.initcall5s.init) \ </span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"> *(.initcallrootfs.init) \ </span></div> <div style="line-height:25px"> <span style="color:#3366ff; line-height:25px"> </span><span style="color:#ff6600; line-height:25px">*(</span><span style="color:#ff00ff; line-height:25px">.initcall6.init</span><span style="color:#ff6600; line-height:25px">)</span><span style="color:#3366ff; line-height:25px"> \ </span> </div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"> *(.initcall6s.init) \ </span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"> *(.initcall7.init) \ </span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"> *(.initcall7s.init) </span></div> <div style="line-height:25px"> <span style="line-height:22px; color:rgb(0,0,255)">VMLINUX_SYMBOL(</span><span style="line-height:22px"><span style="color:#99cc00; line-height:25px">__early_initcall_end</span><span style="color:#0000ff; line-height:25px">)</span></span><span style="line-height:22px; color:rgb(0,0,255)">=<span style="line-height:22px"></span></span><span style="color:#ff6600; line-height:22px"><span style="line-height:22px">.</span></span><span style="line-height:22px; color:rgb(0,0,255)">;</span><span style="color:#3366ff; line-height:22px; color:rgb(0,0,0)"></span><span style="color:#000080; line-height:22px">这里的</span><span style="color:#3366ff; line-height:22px"><span style="line-height:22px"></span></span><span style="color:#ff00ff; line-height:22px"><span style="line-height:22px">.</span></span><span style="color:#000080; line-height:25px">是一个特殊的符号,它是定位器,一个位置指针,指向程序地址空间内的某位置(或某section内的偏移,如果它在SECTIONS命令内的某section描述内),该符号只能在SECTIONS命令内使用。</span> </div> <div style="line-height:25px"> <span style="color:#000080; line-height:25px">这句命令的意思,是对</span><span style="line-height:25px; color:rgb(153,204,0)">__early_initcall_end</span><span style="line-height:25px; color:rgb(0,0,128)">变量赋值为</span><span style="line-height:25px; color:rgb(0,0,128)">当前section内的偏移</span> </div> <div style="line-height:25px"> <span style="color:#ff6600; line-height:25px">*(</span><span style="color:#ff00ff; line-height:25px">.initcall7s.init</span><span style="color:#ff6600; line-height:25px">)</span><span style="color:#000080; line-height:25px">表示的是</span><span style="color:#0000ff; line-height:25px">所有输入文件</span><span style="color:#000080; line-height:25px">中的名为</span><span style="color:#ff00ff; line-height:25px">.initcall7s.init</span><span style="color:#000080; line-height:25px">的</span><span style="color:#ff6600; line-height:25px">SECTIONS</span> </div> <div style="line-height:25px"> <span style="color:#ff6600; line-height:25px">__initcall_start</span><span style="color:#000080; line-height:25px">和</span><span style="color:#ff6600; line-height:25px">__initcall_end</span><span style="color:#000080; line-height:25px">以及</span><span style="color:#ff6600; line-height:25px">INITCALLS</span><span style="color:#000080; line-height:25px">中定义的SECTION都是在arch/xxx/kernel/vmlinux.lds.S中放在</span><span style="color:#0000ff; line-height:25px">.init</span><span style="color:#000080; line-height:25px">段的。</span> </div> <div style="line-height:25px"> <span style="color:#993300; line-height:25px">SECTIONS</span><span style="color:#3366ff; line-height:25px"></span> </div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px">{ </span></div> <div style="line-height:25px"> <span style="color:#3366ff; line-height:25px"> .</span><span style="color:#ff6600; line-height:25px">init</span><span style="color:#3366ff; line-height:25px">: { </span> </div> <div style="line-height:25px"> <span style="color:#3366ff; line-height:25px"> </span><span style="color:#99cc00; line-height:25px">__initcall_start</span><span style="color:#3366ff; line-height:25px">=</span><span style="color:#ff6600; line-height:25px"><span style="line-height:25px">.</span></span><span style="color:#3366ff; line-height:25px">; </span> </div> <div style="line-height:25px"> <span style="color:#3366ff; line-height:25px"> </span><span style="color:#ff00ff; line-height:25px">INITCALLS</span><span style="color:#3366ff; line-height:25px"></span> </div> <div style="line-height:25px"> <span style="color:#3366ff; line-height:25px"> </span><span style="color:#99cc00; line-height:25px">__initcall_end</span><span style="color:#3366ff; line-height:25px">=</span><span style="line-height:25px"><span style="color:#ff6600; line-height:25px">.</span></span><span style="color:#3366ff; line-height:25px">; </span> </div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"> } </span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px">}</span></div> <div style="line-height:25px"> <span style="color:#3366ff; line-height:22px">.</span><span style="color:#ff6600; line-height:22px">init</span><span style="color:#000080; line-height:25px"><span style="line-height:22px">只是用于对</span></span><span style="line-height:25px; color:rgb(153,51,0)">SECTIONS</span><span style="line-height:25px; color:rgb(0,0,128)"><span style="line-height:22px">进行分类</span><span style="line-height:22px"></span></span> </div> <div style="line-height:25px"> <span style="color:#99cc00; line-height:22px">__initcall_start</span><span style="color:#3366ff; line-height:22px">=</span><span style="color:#ff6600; line-height:22px"><span style="line-height:22px">.</span></span><span style="color:#3366ff; line-height:22px">; </span><span style="color:#000080; line-height:25px">和</span><span style="color:#99cc00; line-height:22px">__initcall_end</span><span style="color:#3366ff; line-height:22px">=</span><span style="line-height:22px"><span style="color:#ff6600; line-height:22px">.</span></span><span style="color:#3366ff; line-height:22px">; </span><span style="color:#000080; line-height:25px">表示分别对变量</span><span style="line-height:25px; color:rgb(153,204,0)">__initcall_start</span><span style="color:#000080; line-height:25px">和</span><span style="color:#99cc00; line-height:22px">__initcall_end</span><span style="color:#3366ff; line-height:22px"></span><span style="line-height:22px; color:rgb(0,0,128)">赋值为</span><span style="line-height:22px; color:rgb(0,0,128)">当前section内的偏移。</span> </div> <div style="line-height:25px"> <span style="color:#000080; line-height:25px">而这些</span><span style="color:#0000ff; line-height:25px">SECTION</span><span style="color:#000080; line-height:25px">里的函数在初始化时被顺序执行(init内核线程-&gt;</span><span style="color:#ff9900; line-height:25px">do_basic_setup()</span><span style="color:#000080; line-height:25px">[main.c#778]-&gt;</span><span style="color:#ff9900; line-height:25px">do_initcalls()</span><span style="color:#000080; line-height:25px">)。</span> </div> <div style="line-height:25px"> <span style="color:#000080; line-height:25px">程序(</span><span style="color:#0000ff; line-height:25px">init/main.c</span><span style="color:#000080; line-height:25px">文件</span><span style="color:#ff6600; line-height:25px">do_initcalls()</span><span style="color:#000080; line-height:25px">函数)如下,</span><span style="color:#ff6600; line-height:25px">do_initcalls()</span><span style="color:#000080; line-height:25px">把</span><span style="color:#ff6600; line-height:25px">XX.initcallXX.init</span><span style="color:#000080; line-height:25px">中的函数按顺序都执行一遍。</span> </div> <div style="line-height:25px"> <span style="color:#800000; line-height:25px">for</span><span style="color:#3366ff; line-height:25px">(call =</span><span style="color:#99cc00; line-height:25px">__early_initcall_end</span><span style="color:#3366ff; line-height:25px">; call &lt;</span><span style="color:#ff6600; line-height:25px">_</span><span style="color:#99cc00; line-height:25px">_initcall_end</span><span style="color:#3366ff; line-height:25px">; call++) </span> </div> <div style="line-height:25px"> <span style="color:#3366ff; line-height:25px"> </span><span style="color:#0000ff; line-height:25px">do_one_initcall(*call);</span> </div> </div> <div style="line-height:25px">关于SECTION的更多内容请参考《<strong><a title="阅读全文" target="_blank" href="http://hubingforever.blog.163.com/blog/static/171040579201192472552886/" style="color:rgb(207,121,28); line-height:25px; text-decoration:none">Linux下的lds链接脚本简介</a></strong>》</div> <div><br></div> </wbr>
<think>好的,我现在需要解释Linux内核中的一系列驱动加载宏,包括pure_initcall、pure_initcall_sync以及它们的各个变种。首先,我得回忆一下这些宏的作用和它们在启动过程中的顺序。 我记得Linux内核的初始化是通过一系列初始化函数(initcalls)来完成的,这些函数按照优先级顺序执行。每个宏对应不同的优先级,确保内核组件和驱动程序按正确的顺序初始化。例如,有些硬件需要先初始化,其他驱动才能依赖它们。 接下来,我需要确定每个宏的具体名称和对应的顺序。常见的initcall级别包括pure、core、postcore、arch等。每个级别可能有对应的_sync版本,这可能与并行初始化有关。 pure_initcall应该是最早执行的,用于那些不依赖其他服务的纯初始化函数。而core_initcall可能在pure之后,处理核心子系统。postcore_initcall可能跟在核心之后,处理后续的驱动。arch_initcall可能和架构相关的初始化有关,比如特定于ARM或x86的代码。 关于_sync后缀,可能表示这些初始化函数需要在多核环境下同步执行,或者必须在前一阶段所有函数完成后再执行,而不是并行处理。这可能用于需要严格顺序的初始化步骤。 然后,我需要验证每个宏的具体定义。例如,在Linux内核代码中,这些宏通常通过__define_initcall宏来定义,参数指定优先级。例如,pure_initcall可能是0级,core是1,postcore是2,arch是3,等等。 应用场景方面,pure_initcall可能用于非常早期的初始化,比如内存管理系统的设置。core_initcall用于核心子系统,如总线或中断控制器。arch_initcall用于架构特定的初始化,比如设置CPU特定的功能。 同时,需要说明用户何时应该选择这些宏。比如,当开发一个不依赖其他子系统的基础驱动时,使用pure_initcall;如果是设备驱动,可能需要根据依赖关系选择core、postcore或arch级别。 另外,需要注意同步版本的应用场景。例如,当某个初始化函数必须等待同一级别的所有其他函数完成后才能执行,这时使用_sync版本,确保顺序执行,避免竞态条件。 最后,需要确保解释清晰,结构合理,帮助用户理解这些宏的作用和正确使用方式。</think>Linux内核的驱动加载宏用于控制初始化函数的执行顺序,以下是逐级说明和应用场景分析: --- ### 一、层级关系(按执行顺序排列) 1. **pure_initcall** - **级别**:最高优先级(LEVEL=0) - **特点**:最早执行的初始化函数 - **应用场景**:不依赖任何其他内核服务的纯初始化(如内存池、基础算法库) 2. **core_initcall** - **级别**:LEVEL=1 - **特点**:核心子系统初始化 - **应用场景**:内核核心组件(如调度器、中断控制器) 3. **postcore_initcall** - **级别**:LEVEL=2 - **特点**:核心初始化完成后执行 - **应用场景**:依赖核心子系统的早期驱动(如总线类型注册) 4. **arch_initcall** - **级别**:LEVEL=3 - **特点**:架构相关初始化 - **应用场景**:CPU/SoC特定功能(如ARM的缓存配置、x86的ACPI表解析) --- ### 二、同步与非同步版本差异 所有宏均有 `*_sync` 变体(如 `core_initcall_sync`): - **非同步版本**:允许同一级别的初始化函数并行执行(若内核配置了 `CONFIG_SMP`) - **同步版本**:强制同一级别的所有函数完成后,再执行下一级别 - **典型用途**: ```c // 并行初始化可能引发竞态时使用同步版本 core_initcall_sync(init_func); // 确保所有core_initcall完成 ``` --- ### 三、技术实现原理 通过 `__define_initcall` 宏定义优先级: ```c #define pure_initcall(fn) __define_initcall(fn, 0) #define core_initcall(fn) __define_initcall(fn, 1) #define postcore_initcall(fn) __define_initcall(fn, 2) #define arch_initcall(fn) __define_initcall(fn, 3) ``` 内核启动时遍历 `initcall` 段,按优先级顺序执行函数。 --- ### 四、实际开发建议 1. **避免滥用高级别宏**:非必要不使用 `pure_initcall`,减少启动延迟 2. **依赖关系管理**: - 若驱动依赖总线子系统,使用 `postcore_initcall` - 若驱动与硬件架构强相关,使用 `arch_initcall` 3. **调试技巧**:通过内核参数 `initcall_debug` 跟踪执行顺序: ```bash sudo dmesg | grep "initcall" ``` --- ### 五、完整执行顺序参考 完整层级(共8级): $$ \text{pure} \rightarrow \text{core} \rightarrow \text{postcore} \rightarrow \text{arch} \rightarrow \text{subsys} \rightarrow \text{fs} \rightarrow \text{device} \rightarrow \text{late} $$ 每个层级对应不同子系统,合理选择可优化启动速度和稳定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值