5.5.1 通过initcall初始化
当创建init()之后,它会调用do_initcalls()函数,而do_initcalls()函数是用来调用所有被*_initcall宏系列所注册的初始化函数的,其实现代码如代码清单5-10所示。
代码清单5-10 使用initcalls初始化static void __init do_initcalls(void)
{
initcall_t *call;
for(call= &__initcall_start; call
if (initcall_debug) {
printk(KERN_DEBUG "Calling initcall 0x%p", *call);
print_symbol(":%s()", (unsigned long) *call);
printk("\n");
}
(*call)();
}
除了两个用于指示循环范围的标签__initcall_start和__initcall_end之外,该段代码很好理解。在C源代码和头文件中不会看到这样的标签,它们是在vmlinux链接阶段所用的链接脚本文件中定义的,用来表示使用*_initcall宏系列所生成的初始化函数列表的起始和结束位置。你可以在Linux内核顶层目录下的System.map文件中看到每一个这样的标签,这些标签以字符串__initcall开始,就像代码清单5-8中所表示的那样。
你如果对do_initcalls()函数中的调试打印信息感到疑惑的话,可以看一下由在引导过程中设置的内核命令行参数initcall_debug所执行的系统调用,该命令行参数允许打印如代码清单5-10所示的调试信息。内核只需简单地以内核命令行参数initcall_debug开始就可以实现这些调试信息的输出 。
下面是一个启用了这些调试语句时的输出的例子:...
Calling initcall 0xc00168f4: tty_class_init+0x0/0x3c()
Calling initcall 0xc000c32c: customize_machine+0x0/0x2c()
Calling initcall 0xc000c4f0: topology_init+0x0/0x24()
Calling initcall 0xc000e8f4: coyote_pci_init+0x0/0x20()
PCI: IXP4xx is host
PCI: IXP4xx Using direct access for memory space
...
注意在代码清单5-7中对customize_machine()的调用,调试信息的输出包括了函数的虚拟内核地址(在该例中是0xc000c32c)和函数大小(在这里是0x2c)。这是了解内核初始化的一个有效方法,特别是对不同子系统和模块的调用次序的理解。即使是在一个具有相当配置的嵌入式系统之上,也有几十个这样的初始化函数通过这种方式调用。在这个以嵌入式ARM XScale为平台的例子中,共有92个这样不同的内核初始化程序。
【责任编辑:云霞 TEL:(010)68476606】
点赞 0