启动第一个应用进程
- RISC-V
- 2024-07-07
- 118热度
- 0评论
start_kernel
......
arch_call_rest_init()
rest_init();
pid = kernel_thread(kernel_init, NULL, CLONE_FS);
static int __ref kernel_init(void *unused)
{
int ret;
kernel_init_freeable();
/* need to finish all async __init code before freeing the memory */
async_synchronize_full();
ftrace_free_init_mem();
free_initmem();
mark_readonly();
/*
* Kernel mappings are now finalized - update the userspace page-table
* to finalize PTI.
*/
pti_finalize();
system_state = SYSTEM_RUNNING;
numa_default_policy();
rcu_end_inkernel_boot();
创建1号进程的3种方式,如下:
1.方式①
if (ramdisk_execute_command) {
ret = run_init_process(ramdisk_execute_command);
if (!ret)
return 0;
pr_err("Failed to execute
ramdisk_execute_command, ret);
}
/*
* We try each of these until one succeeds.
*
* The Bourne shell can be used instead of init if we are
* trying to recover a really broken machine.
*/
2.方式②
if (execute_command) {
ret = run_init_process(execute_command);
if (!ret)
return 0;
panic("Requested init
execute_command, ret);
}
3.方式③
if (!try_to_run_init_process("/sbin/init") ||
!try_to_run_init_process("/etc/init") ||
!try_to_run_init_process("/bin/init") ||
!try_to_run_init_process("/bin/sh"))
return 0;
panic("No working init found. Try passing init= option to kernel. "
"See Linux Documentation/admin-guide/init.rst for guidance.");
}
从上述代码种可知,启动1号进程init一共有3种方式,分别是ramdisk的方式、execute_command的方式、默认方式。第一种是基于ramdisk的方式,将ram作为启动盘挂载根文件系统。第二种通常用于用户指定第一个init进程启动在根文件系统的位置。如果第一个和第二都没有就会使用默认。
ramdisk方式
static int __init rdinit_setup(char *str)
{
unsigned int i;
ramdisk_execute_command = str;
/* See "auto" comment in init_setup */
for (i = 1; i < MAX_INIT_ARGS; i++)
argv_init[i] = NULL;
return 1;
}
__setup("rdinit=", rdinit_setup);
__setup(str,fn)的作用是,在系统开机时解析cmdline中是否有str字段,如果有就会调用fn函数,因此上面的函数意思就是当cmdline中有rdinit=字段时,就会调用rdinit_setup函数,将rdinit=后面的内容赋值给ramdisk_execute_command。
execute_command方式
static int __init init_setup(char *str)
{
unsigned int i;
execute_command = str;
/*
* In case LILO is going to boot us with default command line,
* it prepends "auto" before the whole cmdline which makes
* the shell think it should execute a script with such name.
* So we ignore all arguments entered _before_ init=... [MJ]
*/
for (i = 1; i < MAX_INIT_ARGS; i++)
argv_init[i] = NULL;
return 1;
}
__setup("init=", init_setup);
上述代码同理,当cmdline中存在\"init=\"时,调用init_setup,将参数赋值给execute_command。这种情况一般是可以让用户指定启动的第一个进程。
默认方式
static int __ref kernel_init(void *unused)
{
......
if (!try_to_run_init_process("/sbin/init") ||
!try_to_run_init_process("/etc/init") ||
!try_to_run_init_process("/bin/init") ||
!try_to_run_init_process("/bin/sh"))
return 0;
......
}
当cmdline中既没有rdinit和init字段时,就是直接使用默认的方式。