Arm linux 内核移植及系统初始化过程分析
5.3.2. 初始化设备5.3.3. 驱动程序
linux/init/main.c
static void __init do_basic_setup(void)
{
/* drivers will send hotplug events */
init_workqueues();
usermodehelper_init();
driver_init(); /* 初始化驱动程序模型。调用驱动初始化函数初始化子系统。 */
#ifdef CONFIG_SYSCTL
sysctl_init();
#endif
do_initcalls();
}
linux/init/main.c
extern initcall_t __initcall_start[], __initcall_end[];
static void __init do_initcalls(void)
{
initcall_t *call;
int count = preempt_count();
for (call = __initcall_start; call < __initcall_end; call++) {
char *msg = NULL;
char msgbuf[40];
int result;
if (initcall_debug) {
printk("Calling initcall 0x%p", *call);
print_fn_descriptor_symbol(": %s()",
(unsigned long) *call);
printk("/n");
}
result = (*call)();
……
……
……
}
/* Make sure there is no pending stuff from the initcall sequence */
flush_scheduled_work();
}
分析上面一段代码可以看出,设备的初始化是通过do_basic_setup()函数调用do_initcalls()函数,实现__initcall_start, __initcall_end段之间的指针函数执行的。而到底是那些驱动函数怎么会被集中到这个段内的呢?我们知道系统内存空间的分配是由链接器ld读取链接脚本文件决定。链接器将同样属性的文件组织到相同的段里面去,如所有的.text段都被放在一起。在链接脚本里面可以获得某块内存空间的具体地址。我们来看下linux-2.6.18.8/arch/arm/kernel/vmlinux.lds.S文件。由于文件过长,只贴出和__initcall_start, __initcall_end相关的部分。
__initcall_start = .;
*(.initcall1.init)
*(.initcall2.init)
*(.initcall3.init)
*(.initcall4.init)
*(.initcall5.init)
*(.initcall6.init)
*(.initcall7.init)
__initcall_end = .;
从脚本文件中我们可以看出, 在__initcall_start, __initcall_end之间放置的是属行为(.initcall*.init)的函数数据 。在linux/include/linux/init.h文件中可以知道,(.initcall*.init)属性是由__define_initcall(level, fn)宏设定的。
#define __define_initcall(level,fn) /
static initcall_t __initcall_##fn __attribute_used__ /
__attribute__((__section__(".initcall" level ".init"))) = fn
#define core_initcall(fn) __define_initcall("1",fn)
#define postcore_initcall(fn) __define_initcall("2",fn)
#define arch_initcall(fn) __define_initcall("3",fn)
#define subsys_initcall(fn) __define_initcall("4",fn)
#define fs_initcall(fn) __define_initcall("5",fn)
#define device_initcall(fn) __define_initcall("6",fn)
#define late_initcall(fn) __define_initcall("7",fn)
#define __initcall(fn) device_initcall(fn)
由此可以判断,所有的设备驱动函数都必然通过*_initcall(fn)宏的处理。以此为入口,可以查询所有的设备驱动。
core_initcall(fn)
static int __init consistent_init(void) linux/arch/arm/mm/consistent.c
static int __init v6_userpage_init(void) linux/arch/arm/mm/copypage-v6.c
static int __init init_dma(void) linux/arch/arm/kernel/dma.c
static int __init s3c2410_core_init(void) linux/arch/arm/mach-s3c2410/s3c2410.c
postcore_initcall(fn)
static int ecard_bus_init(void) linux/arch/arm/kernel/ecard.c
arch_initcall(fn)
static __init int bast_irq_init(void) linux/arch/arm/mach-s3c2410/bast-irq.c
static int __init s3c_arch_init(void) linux/arch/arm/mach-s3c2410/cpu.c
static __init int pm_simtec_init(void) linux/arch/arm/mach-s3c2410/pm-simtec.c
static int __init customize_machine(void) linux/arch/arm/kernel/setup.c
subsys_initcall(fn)
static int __init ecard_init(void) linux/arch/arm/kernel/ecard.c
int __init scoop_init(void) linux/arch/arm/common/scoop.c
static int __init topology_init(void) linux/arch/arm/kernel/setup.c
fs_initcall(fn)
static int __init alignment_init(void) linux/arch/arm/mm/alignment.c
device_initcall(fn)
static int __init leds_init(void) linux/arch/arm/kernel/time.c
static int __init timer_init_sysfs(void) linux/arch/arm/kernel/time.c
late_initcall(fn)
static int __init crunch_init(void) arch/arm/kernel/crunch.c
static int __init arm_mrc_hook_init(void) linux/arch/arm/kernel/traps.c
Armlinux内核移植系统初始 相关文章:
- 浅谈分析Arm linux 内核移植及系统初始化的过程四(11-09)
- 浅谈分析Arm linux 内核移植及系统初始化的过程二(11-09)
- 浅谈分析Arm linux 内核移植及系统初始化的过程一(11-09)
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)