以tiny4412为例:
arch/arm/mach-exynos/mach-tiny4412.c
MACHINE_START(TINY4412, "TINY4412") /* Maintainer: FriendlyARM (www.arm9.net) */ .boot_params = S5P_PA_SDRAM + 0x100, .init_irq = exynos4_init_irq, .map_io = smdk4x12_map_io, .init_machine = smdk4x12_machine_init, .timer = &exynos4_timer, .reserve = &exynos4_reserve, MACHINE_END
其中:
#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 \ };
启动时:
start_kernel ----- init/main.c
----> setup_arch ---- arch/arm/kernel/setup.c
----> mdesc = setup_machine_tags(machine_arch_type); 到这里,根据machine_arch_type就找到上面这个结构体了。
----> machine_desc = mdesc;
----> paging_init(mdesc) (arch/arm/mm/mmu.c)
----> devicemaps_init(mdesc)
----> mdesc->map_io() 调用了函数 smdk4x12_map_io
----> init_IRQ() (arch/arm/kernel/irq.c)
----> machine_desc->init_irq() 调用 exynos4_init_irq
----> time_init()
----> system_timer = machine_desc->timer; 其中, system_timer 就是 exynos4_timer
----> system_timer->init(); 其中, init 是 exynos4_timer_init
----> rest_init()
----> kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND)
----> kernel_init
----> do_basic_setup()
----> driver_init()
----> platform_bus_init();
----> do_initcalls()
---->
static void __init do_initcalls(void) { initcall_t *fn; for (fn = __early_initcall_end; fn < __initcall_end; fn++) do_one_initcall(*fn); }
在arch/arm/kernel/vmlinux.lds中:
__initcall_start = .; *(.initcallearly.init) __early_initcall_end = .; *(.initcall0.init) *(.initcall0s.init) *(.initcall1.init) *(.initcall1s.init) *(.initcall2.init) *(.initcall2s.init) *(.initcall3.init) *(.initcall3s.init) *(.initcallbresume.init) *(.initcallresume.init) *(.initcall4.init) *(.initcall4s.init) *(.initcall5.init) *(.initcall5s.init) *(.initcallrootfs.init) *(.initcall6.init) *(.initcall6s.init) *(.initcall7.init) *(.initcall7s.init) __initcall_end = .;
即: do_initcalls 会一次执行上面的链接脚本指定的段中的函数,其中在arch/arm/kernel/setup.c中:
static int __init customize_machine(void) { /* customizes platform devices, or adds new ones */ if (machine_desc->init_machine) machine_desc->init_machine(); // 执行了smdk4x12_machine_init
return 0; } arch_initcall(customize_machine);
其中在include/linux/init.h中:
#define __define_initcall(level,fn,id) \ static initcall_t __initcall_##fn##id __used \ __attribute__((__section__(".initcall" level ".init"))) = fn #define arch_initcall(fn) __define_initcall("3",fn,3)
所以, customize_machine 被链接到了 ".initcall3.init" 段, 会被 do_initcalls执行。