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();}
12-09 22:16
查看更多