MSM8909+Android5.1.1启动流程(9) ---start_kernel()到init进程
上一篇:MSM8909+Android5.1.1启动流程(8)---boot_linux()和kernel入口
由上面可知kernel的入口是arch/arm/kernel/head.S中stext, head.S包含同目录文件head-common.S,其调用kernel\init\main.c函数start_kernel()。
从start_kernel函数开始,内核即进入了C语言部分,它完成了内核的大部分初始化工作。实际上,可以将start_kernel函数看做内核的main函数,调用大量的init函数来对内核环境进行初始化;包括CPU初始化、内存管理初始化、进程管理初始化、文件系统初始化、中断、同步互斥等
调用流程:
start_kernel()--->rest_init()--->kernel_init()
rest_init()来初始化0号进程和1号用户态的进程。
static noinline void __init_refokrest_init(void)
{
intpid;
conststruct sched_param param = { .sched_priority = 1 };
rcu_scheduler_starting();
/*
* We need to spawn init first so that itobtains pid 1, however
* the init task will end up wanting to createkthreads, which, if
* we schedule it before we create kthreadd,will OOPS.
*/
kernel_thread(kernel_init,NULL, CLONE_FS | CLONE_SIGHAND);
numa_default_policy();
pid= kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
rcu_read_lock();
kthreadd_task= find_task_by_pid_ns(pid, &init_pid_ns);
rcu_read_unlock();
sched_setscheduler_nocheck(kthreadd_task,SCHED_FIFO, ¶m);
complete(&kthreadd_done);
/*
* The boot idle thread must execute schedule()
* at least once to get things moving:
*/
init_idle_bootup_task(current);
schedule_preempt_disabled();
/*Call into cpu_idle with preempt disabled */
cpu_startup_entry(CPUHP_ONLINE);
}
kernel_thread函数调用do_fork创建了2号内核线程kthreadd、1号内核线程init,他们的父进程是内核0号进程,2号内核线程kthreadd作用是管理调度其他内核线程,而init内核线程通过调用init可执行程序转变成init进程,进程号还是1。
kernel_thread函数第一个参数就是kernel_init函数,kernel\init\main.c文件
static int __ref kernel_init(void *unused)
{
kernel_init_freeable();
/*need to finish all async __init code before freeing the memory */
async_synchronize_full();
free_initmem();
mark_rodata_ro();
system_state= SYSTEM_RUNNING;
numa_default_policy();
flush_delayed_fput();
/*一开始,ramdisk_execute_command为空,被初始化为”/init”,默认init进程的路径在根目录下,ramdisk_execute_command已经被赋值为”/init”不为空,调用run_init_process处理init可执行程序,run_init_process函数中的do_execve就是系统调用execve的具体实现,作用是运行可执行程序。*/
if(ramdisk_execute_command) {
if(!run_init_process(ramdisk_execute_command))
return0;
pr_err("Failedto execute %s\n", ramdisk_execute_command);
}
/*
* We try each of these until one succeeds.
*
* The Bourne shell can be used instead of initif we are
* trying to recover a really broken machine.
*/
/*如果根目录下没有init可执行程序,就会在”/sbin”、”/etc”、”/bin”下查找,直到找到后执行,如果都没有找到,系统尝试建立一个交互的shell命令可执行程序,让管理员尝试修复。如果sh也没有,此时Android系统启动失败,调用panic把错误提示保存到磁盘中,待重启后显示。*/
if(execute_command) {
if(!run_init_process(execute_command))
return0;
pr_err("Failedto execute %s. Attemptingdefaults...\n",
execute_command);
}
if(!run_init_process("/sbin/init") ||
!run_init_process("/etc/init") ||
!run_init_process("/bin/init") ||
!run_init_process("/bin/sh"))
return0;
panic("Noinit found. Try passing init= option tokernel. "
"See Linux Documentation/init.txtfor guidance.");
}
内核启动init可执行程序,内核把控制权交到了用户空间,开始真正的Android之旅!init进程源码所在路径:system\core\init, Android.mk文件,相关内容:
// 编译后生成的模块的名字,具体是什么模块,看include关键字编译成什么
LOCAL_MODULE:= init
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
…
include $(BUILD_EXECUTABLE) //编译成可执行程序
生成的可执行程序init在out/target/product/msm8909/root目录下,此路径由\build\core\envsetup.mk定义
# the target build type defaults to release
ifneq ($(TARGET_BUILD_TYPE),debug)
TARGET_BUILD_TYPE := release
endif
# ---------------------------------------------------------------
# figure out the output directories
ifeq (,$(strip $(OUT_DIR)))
ifeq (,$(strip $(OUT_DIR_COMMON_BASE)))
OUT_DIR := $(TOPDIR)out
else
OUT_DIR := $(OUT_DIR_COMMON_BASE)/$(notdir$(PWD))
endif
endif
DEBUG_OUT_DIR := $(OUT_DIR)/debug
# Move the host or target under the debug/directory
# if necessary.
TARGET_OUT_ROOT_release :=$(OUT_DIR)/target
TARGET_OUT_ROOT_debug :=$(DEBUG_OUT_DIR)/target
TARGET_OUT_ROOT :=$(TARGET_OUT_ROOT_$(TARGET_BUILD_TYPE))
TARGET_PRODUCT_OUT_ROOT :=$(TARGET_OUT_ROOT)/product
PRODUCT_OUT :=$(TARGET_PRODUCT_OUT_ROOT)/$(TARGET_DEVICE)
TARGET_COPY_OUT_ROOT := root
TARGET_ROOT_OUT :=$(PRODUCT_OUT)/$(TARGET_COPY_OUT_ROOT)
init进程主要代码是init.c,标准c语言写的程序,其main函数是入口,main()函数下部分再学习。
参考链接:
arm linux kernel 从入口到start_kernel 的代码分析
Android系统开机启动流程及init进程浅析