init源码在:android/system/core/init/,编译出来的init二进制可执行文件在:android/out/target/product/s900_vr/root/,系统运行起来后,这个root/目录里面的内容都是在根目录下的,也就是说,要想实现从kernel到android的跳转,就需要有地方启动这个完整路径是 "/init"的init进程。
1,机器上电
2,bootloader启动过程
一般做法是到地址为0x00000000处执行bootloader的第一阶段的汇编代码(意思就是bootloader就放到0x00000000的地址处),初始化硬件设备,比如内存等,拷贝bootloader的第二阶段C代码到内存,然后执行第二阶段C代码,第二阶段代码会拷贝kernel到RAM并跳转到kernel的入口处执行;(我们公司的bootloader采用的是u-boot,分为5个阶段,firsMBR/secMBRC/APP/BL31/B32,上电先跑brom代码,brom是固化在CPU内部的0xffff0000处的代码,一般arm启动地址是0x00000000或0xffff0000,我们公司选用的是0xffff0000,然后brom从flash(sd、emmc或nand)加载1stMbrc启动代码到shareRam,shareRam是CPU内部的ram空间,然后运行secMBRC,APP/BL31/B32都是在DDR上跑)
3,u-boot中有指定kernel的入口函数start_kernel():
u-boot/arch/arm/lib/bootm.c
72 static void announce_and_cleanup(int fake)
73 {
74 printf("\nStarting kernel ...%s\n\n", fake ?
75 "(fake run for tracing)" : "");
76 bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
77 #ifdef CONFIG_BOOTSTAGE_FDT
78 bootstage_fdt_add_report();
79 #endif
80 #ifdef CONFIG_BOOTSTAGE_REPORT
81 bootstage_report();
82 #endif
84 #ifdef CONFIG_USB_DEVICE
85 udc_disconnect();
86 #endif
87 cleanup_before_linux();
88 }
4,kernel的start_kernel()里面的每个函数都是重量级的,这里不讨论,我们关注的是大的流程:
kernel/init/main.c
472 asmlinkage void __init start_kernel(void)
473 {
474 char * command_line;
475 extern const struct kernel_param __start___param[], __stop___param[];
481 lockdep_init();
482 smp_setup_processor_id();
483 debug_objects_early_init();
484 //此处省略一万行
647 rest_init();
648 }
4.1,直接看rest_init(),这里新开了一个thread执行kernel_init:
366 static noinline void __init_refok rest_init(void)
367 {
368 int pid;
370 rcu_scheduler_starting();
376 kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
377 numa_default_policy();
378 pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
379 rcu_read_lock();
380 kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
381 rcu_read_unlock();
382 complete(&kthreadd_done);
388 init_idle_bootup_task(current);
389 schedule_preempt_disabled();
391 cpu_startup_entry(CPUHP_ONLINE);
392 }
4.2,kernel执行到kernel_init函数后,整个kernel该干的活差不多都已经完成,剩下的就是要启动用户空间的第一个进程init:
819 static int __ref kernel_init(void *unused)
820 {
821 kernel_init_freeable();
823 async_synchronize_full();
824 free_initmem();
825 mark_rodata_ro();
826 system_state = SYSTEM_RUNNING;
827 numa_default_policy();
828
829 flush_delayed_fput();
830
831 if (ramdisk_execute_command) {
832 if (!run_init_process(ramdisk_execute_command))
833 return 0;
834 pr_err("Failed to execute %s\n", ramdisk_execute_command);
835 }
836
843 if (execute_command) {
844 if (!run_init_process(execute_command))
845 return 0;
846 pr_err("Failed to execute %s. Attempting defaults...\n",
847 execute_command);
848 }
849 if (!run_init_process("/sbin/init") ||
850 !run_init_process("/etc/init") ||
851 !run_init_process("/bin/init") ||
852 !run_init_process("/bin/sh"))
853 return 0;
854
855 panic("No init found. Try passing init= option to kernel. "
856 "See Linux Documentation/init.txt for guidance.");
857 }
859 static noinline void __init kernel_init_freeable(void)
860 {
900 //此处省略n行代码
901 if (!ramdisk_execute_command)
902 ramdisk_execute_command = "/init";
903 //此处省略n行代码
904 }
上面821行的kernel_init_freeable函数给ramdisk_execute_command赋值为init的完整路径名称,然后832行就正式启动init进程了。