Linux do_initcall_level()

来源:互联网 发布:salt算法和sha算法 编辑:程序博客网 时间:2024/06/05 06:03

1. do_initcalls()

路径:linux-3.10.x\init\main.c   start_kernel()-->rest_init()-->kernel_init()-->kernel_init_freeable()-->do_basic_setup()-->do_initcalls()-->do_initcall_level()-->do_one_initcall() 

do_initcalls()将按顺序从由__initcall_start开始,到__initcall_end结束的section中以函数指针的形式取出这些编译到内核的驱动模块中初始化函数起始地址,来依次完成相应的初始化。而这些初始化函数由__define_initcall(level,fn)指示编译器在编译的时候,将这些初始化函数的起始地址值按照一定的顺序放在这个section中。由于内核某些部分的初始化需要依赖于其他某些部分的初始化的完成,因此这个顺序排列常常非常重要。先看看调用源码:

static void __init do_initcalls(void){int level;for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)do_initcall_level(level); //依次调用不同等级的初始化函数}
extern initcall_t __initcall_start[];extern initcall_t __initcall0_start[];extern initcall_t __initcall1_start[];extern initcall_t __initcall2_start[];extern initcall_t __initcall3_start[];extern initcall_t __initcall4_start[];extern initcall_t __initcall5_start[];extern initcall_t __initcall6_start[];extern initcall_t __initcall7_start[];extern initcall_t __initcall_end[];static initcall_t *initcall_levels[] __initdata = {__initcall0_start,__initcall1_start,__initcall2_start,__initcall3_start,__initcall4_start,__initcall5_start,__initcall6_start,__initcall7_start,__initcall_end,};

static void __init do_initcall_level(int level){extern const struct kernel_param __start___param[], __stop___param[];initcall_t *fn;strcpy(static_command_line, saved_command_line);parse_args(initcall_level_names[level],   static_command_line, __start___param,   __stop___param - __start___param,   level, level,   &repair_env_string);for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)do_one_initcall(*fn);//初始化同一级别中的函数}

主要分析do_one_initcall(*fn),先要明白这些函数是如何注册的,什么时候注册的。

用加载的串口设备驱动举例:

module_init(nuc970serial_init);module_exit(nuc970serial_exit);

路径:linux-3.10.x\include\linux\init.h

#define module_init(x)__initcall(x);
#define __initcall(fn) device_initcall(fn)

#define device_initcall(fn)__define_initcall(fn, 6)

#define __define_initcall(fn, id) \static initcall_t __initcall_##fn##id __used \__attribute__((__section__(".initcall" #id ".init"))) = fn
这里主要分析__define_initcall, initcall_t为函数指针,定义为:

typedef int (*initcall_t)(void);typedef void (*exitcall_t)(void);

这个宏的目的是定义一个静态的函数指针,而属性__attribute__((__section__(x))表示将这个fn放到x这个section位置,所以这里的意思是将fn放到".initcall.6.init"的section中。展开该宏为:

#define __define_initcall(nuc970serial_init, 6) \static initcall_t __initcall_nuc970serial_init6 __used \__attribute__((__section__(".initcall.6.init"))) = nuc970serial_init
通过查找内核映射表system.map,可以看到__initcall_nuc970serial_init6函数指针:
c0437a10 t __initcall_pty_init6c0437a14 t __initcall_nuc970serial_init6c0437a18 t __initcall_rand_initialize6c0437a1c t __initcall_topology_sysfs_init6c0437a20 t __initcall_brd_init6c0437a24 t __initcall_at24_init6
而__initcall_nuc970serial_init6函数指针是指向驱动模块初始化函数nuc970serial_init,至此,但我们的驱动编译进内核时,内核在启动之后就是按照这个顺序注册驱动模块!

上面有两个for循环:

for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)do_initcall_level(level);for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)do_one_initcall(*fn);
第一个for循环表示初始的级别数,我们通过“static initcall_t *initcall_levels[]”指针数组,得知8级,而二个for循环是对每一个级别再进行驱动注册,可以看到for循环只会level+1就是在初始化一级,例如上面的moudle_init(nuc970serial_init)就是级别6,为了更加直观点,从system.map中可以看到级别5、级别6的区段划分如下:

c0437880 T __initcall5_start
c0437880 t __initcall_proc_cpu_init5
c0437884 t __initcall_dma_debug_do_init5
c0437888 t __initcall_alignment_init5
c043788c t __initcall_clocksource_done_booting5
c0437890 t __initcall_init_pipe_fs5
c0437894 t __initcall_eventpoll_init5
c0437898 t __initcall_anon_inode_init5
c043789c t __initcall_blk_scsi_ioctl_init5
c04378a0 t __initcall_chr_dev_init5
c04378a4 t __initcall_firmware_class_init5
c04378a8 t __initcall_sysctl_core_init5
c04378ac t __initcall_inet_init5
c04378b0 t __initcall_ipv4_offload_init5
c04378b4 t __initcall_af_unix_init5
c04378b8 t __initcall_ipv6_offload_init5
c04378bc t __initcall_init_sunrpc5
c04378c0 t __initcall_default_rootfsrootfs
c04378c0 T __initcallrootfs_start
c04378c4 T __initcall6_start
c04378c4 t __initcall_fpe_init6
c04378c8 t __initcall_sched_clock_syscore_init6
c04378cc t __initcall_proc_execdomains_init6
c04378d0 t __initcall_ioresources_init6
c04378d4 t __initcall_uid_cache_init6
c04378d8 t __initcall_init_posix_timers6
c04378dc t __initcall_init_posix_cpu_timers6
c04378e0 t __initcall_timekeeping_init_ops6
c04378e4 t __initcall_init_clocksource_sysfs6
c04378e8 t __initcall_init_timer_list_procfs6
c04378ec t __initcall_alarmtimer_init6
c04378f0 t __initcall_futex_init6
c04378f4 t __initcall_proc_modules_init6
c04378f8 t __initcall_kallsyms_init6
c04378fc t __initcall_crash_save_vmcoreinfo_init6
c0437900 t __initcall_crash_notes_memory_init6
c0437904 t __initcall_pid_namespaces_init6
c0437908 t __initcall_utsname_sysctl_init6
c043790c t __initcall_perf_event_sysfs_init6
c0437910 t __initcall_init_per_zone_wmark_min6
c0437914 t __initcall_kswapd_init6
c0437918 t __initcall_extfrag_debug_init6
c043791c t __initcall_setup_vmstat6
c0437920 t __initcall_mm_sysfs_init6
c0437924 t __initcall_slab_proc_init6
c0437928 t __initcall_init_reserve_notifier6
c043792c t __initcall_init_admin_reserve6
c0437930 t __initcall_init_user_reserve6
c0437934 t __initcall_proc_vmalloc_init6
c0437938 t __initcall_memblock_init_debugfs6
c043793c t __initcall_procswaps_init6
c0437940 t __initcall_slab_sysfs_init6
c0437944 t __initcall_fcntl_init6
c0437948 t __initcall_proc_filesystems_init6
c043794c t __initcall_dio_init6
c0437950 t __initcall_aio_setup6
c0437954 t __initcall_proc_locks_init6
c0437958 t __initcall_proc_cmdline_init6
c043795c t __initcall_proc_consoles_init6
c0437960 t __initcall_proc_cpuinfo_init6
c0437964 t __initcall_proc_devices_init6
c0437968 t __initcall_proc_interrupts_init6
c043796c t __initcall_proc_loadavg_init6
c0437970 t __initcall_proc_meminfo_init6
c0437974 t __initcall_proc_stat_init6
c0437978 t __initcall_proc_uptime_init6
c043797c t __initcall_proc_version_init6
c0437980 t __initcall_proc_softirqs_init6
c0437984 t __initcall_proc_kmsg_init6
c0437988 t __initcall_proc_page_init6
c043798c t __initcall_init_devpts_fs6
c0437990 t __initcall_init_ramfs_fs6
c0437994 t __initcall_init_fat_fs6
c0437998 t __initcall_init_vfat_fs6
c043799c t __initcall_init_msdos_fs6
c04379a0 t __initcall_init_nfs_fs6
c04379a4 t __initcall_init_nfs_v26
c04379a8 t __initcall_init_nfs_v36
c04379ac t __initcall_init_nlm6
c04379b0 t __initcall_init_nls_cp4376
c04379b4 t __initcall_init_nls_iso8859_16
c04379b8 t __initcall_init_romfs_fs6
c04379bc t __initcall_init_yaffs_fs6
c04379c0 t __initcall_ipc_init6
c04379c4 t __initcall_ipc_sysctl_init6
c04379c8 t __initcall_crypto_wq_init6
c04379cc t __initcall_crypto_algapi_init6
c04379d0 t __initcall_skcipher_module_init6
c04379d4 t __initcall_chainiv_module_init6
c04379d8 t __initcall_eseqiv_module_init6
c04379dc t __initcall_crypto_ecb_module_init6
c04379e0 t __initcall_aes_init6
c04379e4 t __initcall_arc4_init6
c04379e8 t __initcall_michael_mic_init6
c04379ec t __initcall_krng_mod_init6
c04379f0 t __initcall_proc_genhd_init6
c04379f4 t __initcall_bsg_init6
c04379f8 t __initcall_noop_init6
c04379fc t __initcall_deadline_init6
c0437a00 t __initcall_cfq_init6
c0437a04 t __initcall_nuc970_gpio_driver_init6
c0437a08 t __initcall_fb_console_init6
c0437a0c t __initcall_nuc970fb_driver_init6
c0437a10 t __initcall_pty_init6
c0437a14 t __initcall_nuc970serial_init6
c0437a18 t __initcall_rand_initialize6
c0437a1c t __initcall_topology_sysfs_init6
c0437a20 t __initcall_brd_init6
c0437a24 t __initcall_at24_init6
c0437a28 t __initcall_init_sd6
c0437a2c t __initcall_init_mtd6
c0437a30 t __initcall_init_mtdblock6
c0437a34 t __initcall_nand_base_init6
c0437a38 t __initcall_nuc970_nand_init6
c0437a3c t __initcall_spidev_init6
c0437a40 t __initcall_nuc970_spi0_driver_init6
c0437a44 t __initcall_nuc970_spi1_driver_init6
c0437a48 t __initcall_net_olddevs_init6
c0437a4c t __initcall_icplus_init6
c0437a50 t __initcall_nuc970_ether_init6
c0437a54 t __initcall_ehci_hcd_init6
c0437a58 t __initcall_ohci_hcd_mod_init6
c0437a5c t __initcall_ohci_hcd_nuc970_init6
c0437a60 t __initcall_usb_storage_driver_init6
c0437a64 t __initcall_serport_init6
c0437a68 t __initcall_evdev_init6
c0437a6c t __initcall_nuc970adc_driver_init6
c0437a70 t __initcall_atkbd_init6
c0437a74 t __initcall_nuc970_keypad_driver_init6
c0437a78 t __initcall_i2c_dev_init6
c0437a7c t __initcall_nuc970_i2c0_driver_init6
c0437a80 t __initcall_nuc970_i2c1_driver_init6
c0437a84 t __initcall_sock_diag_init6
c0437a88 t __initcall_sysctl_ipv4_init6
c0437a8c t __initcall_cubictcp_register6
c0437a90 t __initcall_unix_diag_init6
c0437a94 t __initcall_packet_init6
c0437a98 t __initcall_packet_diag_init6
c0437a9c T __initcall7_start