include/linux/init.h/* initcalls are now grouped by functionality into separate * subsections. Ordering inside the subsections is determined * by link order. * For backwards compatibility, initcall() puts the call in * the device init subsection. * * The `id' arg to __define_initcall() is needed so that multiple initcalls * can point at the same handler without causing duplicate-symbol build errors. */#define __define_initcall(level,fn,id) \ static initcall_t __initcall_##fn##id __used \ __attribute__((__section__(".initcall" level ".init"))) = fn /* * A "pure" initcall has no dependencies on anything else, and purely * initializes variables that couldn't be statically initialized. * * This only exists for built-in code, not for modules. */#define pure_initcall(fn) __define_initcall("0",fn,0)#define core_initcall(fn) __define_initcall("1",fn,1)#define core_initcall_sync(fn) __define_initcall("1s",fn,1s)#define postcore_initcall(fn) __define_initcall("2",fn,2)#define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)#define arch_initcall(fn) __define_initcall("3",fn,3)#define arch_initcall_sync(fn) __define_initcall("3s",fn,3s)#define subsys_initcall(fn) __define_initcall("4",fn,4)#define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s)#define fs_initcall(fn) __define_initcall("5",fn,5)#define fs_initcall_sync(fn) __define_initcall("5s",fn,5s)#define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)#define device_initcall(fn) __define_initcall("6",fn,6)#define device_initcall_sync(fn) __define_initcall("6s",fn,6s)#define late_initcall(fn) __define_initcall("7",fn,7)#define late_initcall_sync(fn) __define_initcall("7s",fn,7s)#define __initcall(fn) device_initcall(fn)/** * module_init() - driver initialization entry point * @x: function to be run at kernel boot time or module insertion * * module_init() will either be called during do_initcalls() (if * builtin) or at module insertion time (if a module). There can only * be one per module. *//include/linux/init.h#define module_init(x) __initcall(x);可以发现这些*_initcall(fn)最终都是通过__define_initcall(level,fn)宏定义生成的。//这个版本少了id项__define_initcall宏定义如下:#define __define_initcall(level,fn,id) \ static initcall_t __initcall_##fn##id __used \ __attribute__((__section__(".initcall" level ".init"))) = fn/include/linux/init.h typedef int (*initcall_t)(void);initcall_t是个函数指针__initcall_##fn##id = fn;__initcall_##fn##id是放在__section__(".initcall" level ".init"))段里的。 这句话的意思为定义一个 int (*initcall_t)(void)型的函数指针,函数存放在.initcall”level”.init section内。.initcall”level”.init section定义在vmlinux.lds内。/* 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) *(.initcall4.init) *(.initcall4s.init)*(.initcall5.init) *(.initcall5s.init) *(.initcallrootfs.init)*(.initcall6.init) *(.initcall6s.init) *(.initcall7.init)*(.initcall7s.init) __initcall_end = .;正好包括了上面init.h里定义的从core_initcall到late_initcall等7个level等级的.initcall”level”.init section.因此通过不同的*_initcall声明的函数指针最终都会存放不同level等级的.initcall”level”.initsection内。这些不同level的section按level等级高低依次存放。下面我们再来看看,内核是什么时候调用存储在.initcall”level”.init section内的函数的。内核是通过do_initcalls函数循环调用执行initcall.init section内的函数的,流程如下:main.cstart_kernel -> rest_init -> kernel_thread -> kernel_init -> do_basic_setup -> do_initcalls/* * We need to finalize in a non-__init function or else race conditions * between the root thread and the init thread may cause start_kernel to * be reaped by free_initmem before the root thread has proceeded to * cpu_idle. * * gcc-3.4 accidentally inlines this function, so use noinline. */init/main.cstatic void noinline __init_refok rest_init(void) __releases(kernel_lock){ int pid; kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND); numa_default_policy(); pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES); kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns); unlock_kernel(); /* * The boot idle thread must execute schedule() * at least once to get things moving: */ init_idle_bootup_task(current); preempt_enable_no_resched(); schedule(); preempt_disable(); /* Call into cpu_idle with preempt disabled */ cpu_idle();}/* * Ok, the machine is now initialized. None of the devices * have been touched yet, but the CPU subsystem is up and * running, and memory and process management works. * * Now we can finally start doing some real work.. */init/main.cstatic void __init do_basic_setup(void){ rcu_init_sched(); /* needed by module_init stage. */ init_workqueues(); usermodehelper_init(); driver_init(); init_irq_proc(); do_initcalls();}////////////////////////////init/main.cextern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];static void __init do_initcalls(void){ initcall_t *call;//批量执行initcallx.init段中的函数指针 (arch/arm/kernel/vmlinux.lds链接脚本)//执行了所有驱动的入口函数 for (call = __early_initcall_end; call do_one_initcall(*call); //回调函数 /* Make sure there is no pending stuff from the initcall sequence */ flush_scheduled_work();}