今天发现initramfs的产生比driver的加载早,感觉有点奇怪,仔细看了一下。
1.
init/initramfs.c
rootfs_initcall(populate_rootfs);
2.
include/linux/init.h
#define pure_initcall(fn) __define_initcall(fn, 0)
#define core_initcall(fn) __define_initcall(fn, 1)
#define core_initcall_sync(fn) __define_initcall(fn, 1s)
#define postcore_initcall(fn) __define_initcall(fn, 2)
#define postcore_initcall_sync(fn) __define_initcall(fn, 2s)
#define arch_initcall(fn) __define_initcall(fn, 3)
#define arch_initcall_sync(fn) __define_initcall(fn, 3s)
#define subsys_initcall(fn) __define_initcall(fn, 4)
#define subsys_initcall_sync(fn) __define_initcall(fn, 4s)
#define fs_initcall(fn) __define_initcall(fn, 5)
#define fs_initcall_sync(fn) __define_initcall(fn, 5s)
#define rootfs_initcall(fn) __define_initcall(fn, rootfs)
#define device_initcall(fn) __define_initcall(fn, 6)
#define device_initcall_sync(fn) __define_initcall(fn, 6s)
#define late_initcall(fn) __define_initcall(fn, 7)
#define late_initcall_sync(fn) __define_initcall(fn, 7s)
这样看来,rootfs_initcall视乎比device_init的linker顺序前面。
3.
include/asm-generic/vmlinux.lds.h
#define INIT_CALLS \
VMLINUX_SYMBOL(__initcall_start) = .; \
*(.initcallearly.init) \
INIT_CALLS_LEVEL(0) \
INIT_CALLS_LEVEL(1) \
INIT_CALLS_LEVEL(2) \
INIT_CALLS_LEVEL(3) \
INIT_CALLS_LEVEL(4) \
INIT_CALLS_LEVEL(5) \
INIT_CALLS_LEVEL(rootfs) \
INIT_CALLS_LEVEL(6) \
INIT_CALLS_LEVEL(7) \
VMLINUX_SYMBOL(__initcall_end) = .;
$OUT/arch/arm/kernel/vmlinux.lds
__initcall_start = .; *(.initcallearly.init) __initcall0_start = .; *(.initcall0.init) *(.initcall0s.init) __initcall1_start = .; *(.initcall1.init) *(.initcall1s.init) __initcall2_start = .; *(.initcall2.init) *(.initcall2s.init) __initcall3_start = .; *(.initcall3.init) *(.initcall3s.init) __initcall4_start = .; *(.initcall4.init) *(.initcall4s.init) __initcall5_start = .; *(.initcall5.init) *(.initcall5s.init)__initcallrootfs_start = .; *(.initcallrootfs.init) *(.initcallrootfss.init) __initcall6_start = .; *(.initcall6.init) *(.initcall6s.init) __initcall7_start = .; *(.initcall7.init) *(.initcall7s.init) __initcall_end = .;
上面是arm 平台上的linker script和结果, 果然如此啊。
4. init/main.c
823 static initcall_t *initcall_levels[] __initdata = {
824 __initcall0_start,
825 __initcall1_start,
826 __initcall2_start,
827 __initcall3_start,
828 __initcall4_start,
829 __initcall5_start,
830 __initcall6_start,
831 __initcall7_start,
832 __initcall_end,
833 }; 835 /* Keep these in sync with initcalls in include/linux/init.h */
836 static char *initcall_level_names[] __initdata = {
837 "early",
838 "core",
839 "postcore",
840 "arch",
841 "subsys",
842 "fs",
843 "device",
844 "late",
845 };
846
847 static void __init do_initcall_level(int level)
848 {
849 initcall_t *fn;
850
851 strcpy(initcall_command_line, saved_command_line);
852 parse_args(initcall_level_names[level],
853 initcall_command_line, __start___param,
854 __stop___param - __start___param,
855 level, level,
856 NULL, &repair_env_string);
857
858 for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
859 do_one_initcall(*fn);
860 }
861
862 static void __init do_initcalls(void)
863 {
864 int level;
865
866 for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
867 do_initcall_level(level);
868 }
869
虽然__initcallrootfs_start没有出现在initcall_levels的数组里,但这个不妨碍它的
执行,它比__initcall5_start大,比__initcall6_start小,所以,当__initcall5里的
都执行完后,__initcallrootfs段的函数就开始执行了。