转自:http://blog.chinaunix.net/uid-12617001-id-3767393.html
玩过或者移植过arm-linux的都应该知道在/arch/arm目录下有许多与具体处理器相关的目录,当然对于s3c2440的话所对应的目录就是 arch/arm/mach-s3c2440/,在里面找到与具体板子相关的文件mach-mini2440.c,这个文件大部分内容是对平台设备(例如串口,LCD,Nand falsh等)的结构体初始化,在这个文件的最后有一个非常重要的宏:
- MACHINE_START(MINI2440, "MINI2440")
- /* Maintainer: Michel Pollet <buserror@gmail.com> */
- .atag_offset = 0x100,
- .map_io = mini2440_map_io,
- .init_machine = mini2440_init,
- .init_irq = s3c24xx_init_irq,
- .timer = &s3c24xx_timer,
- .restart = s3c244x_restart,
- MACHINE_END
- mini2440 MACH_MINI2440 MINI2440 1999
- /*
- * Set of macros to define architecture features. This is built into
- * a table by the linker.
- */
- #define MACHINE_START(_type,_name) \
- static const struct machine_desc __mach_desc_##_type \
- __used \
- __attribute__((__section__(".arch.info.init"))) = { \
- .nr = MACH_TYPE_##_type, \
- .name = _name,
-
- #define MACHINE_END \
- };
- void __init setup_arch(char **cmdline_p)
- {
- struct machine_desc *mdesc;
-
- setup_processor();
- mdesc = setup_machine_fdt(__atags_pointer);
- if (!mdesc)
- mdesc = setup_machine_tags(machine_arch_type);
- machine_desc = mdesc;
- machine_name = mdesc->name
- ...........
- ...........
- #ifdef CONFIG_ARCH_S3C2440
- # ifdef machine_arch_type
- # undef machine_arch_type
- # define machine_arch_type __machine_arch_type
- # else
- # define machine_arch_type MACH_TYPE_S3C2440
- # endif
- # define machine_is_s3c2440() (machine_arch_type == MACH_TYPE_S3C2440)
- #else
- # define machine_is_s3c2440() (0)
- #endif
-
#define MACH_TYPE_S3C2440 362
到这里,知道了在/init/main.c的start_kernel()函数里调用了setup_arch(),在setup_arch()里找到了具体的struct machine_desc类型的变量,但是在哪里通过这个变量调用里面的成员或成员函数的呢?继续找。还是在setup.c里,看到了这样一个函数:
- static int __init customize_machine(void)
- {
- /* customizes platform devices, or adds new ones */
- if (machine_desc->init_machine)
- machine_desc->init_machine();
- return 0;
- }
- arch_initcall(customize_machine);
-
- #define arch_initcall(fn) __define_initcall("3",fn,3)
-
- __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 = .;
成员函数init_machine就是在这里被调用的。但是它没有被显式调用,而是放在了arch_initcall这个宏里,它被链接到了.initcall段里,现在简单看看 arch/arm/kernel/vmlinux.lds这个链接脚本里关于initcall的定义:可以看到customize_machine()被放到了.initcall3.init里。说了那么多定义,究竟它在哪里被调用啊?好吧,它是在/init/main.c里一个叫do_initcalls()的函数里被调用,去看看呗:
- extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];
-
- static void __init do_initcalls(void)
- {
- initcall_t *fn;
-
- for (fn = __early_initcall_end; fn < __initcall_end; fn++)
- do_one_initcall(*fn);
- }
好了,到这里差不多该结束了,最后总结一下这些函数调用顺序:
start_kernel()--->setup_arch()--->do_initcalls()--->customize_machine()--->mini2440_init()