0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

kernel执行第一个init应用程序的实现原理

冬至子 来源:linux与SoC 作者:linux与SoC 2023-06-05 14:53 次阅读

1. 概述

Linux系统启动过程中通过init_task创建0号idle进程。然后通过kernel_thread创建1号init进程。创建该进程时通过系统调用,在内核空间执行用户空间的/sbin/init程序,通过该程序产生出shell,并依赖init衍生出其他进程。通过top命令查看当前系统环境下的进程列表,可以发现1号进程的为{linuxrc} init

[root@iTOP-4412]# top
Mem: 26404K used, 948572K free, 0K shrd, 3199543672K buff, 0K cached
CPU:  0.0% usr  6.0% sys  0.0% nic 94.0% idle  0.0% io  0.0% irq  0.0% sirq
Load average: 0.00 0.00 0.00 1/78 162
  PID  PPID USER     STAT   VSZ %VSZ CPU %CPU COMMAND
  162   132 root     R     3264  0.3   0  4.5 top
    3     2 root     IW       0  0.0   0  1.5 [kworker/0:0]
  132     1 root     S     3268  0.3   2  0.0 -/bin/sh
    1     0 root     S     3264  0.3   2  0.0 {linuxrc} init
...

我们在kernel代码中会发现,创建1号init进程的方式,主要包括以下3种,如下图所示:

图片

2. 创建init进程的方式

2.1 ramdisk方式

在ramdisk环境下创建init进程时,需要在kernel CMDLINE中设置init程序的路径位置,如下所示:

CONFIG_CMDLINE="...root=/dev/ram rdinit=/sbin/init..."

在kernel代码中通过rdinit_setup()解析kernel CMDLINErdinit=字符串,赋值给全局变量ramdisk_execute_command

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);

当完成ramdisk_execute_command赋值后,在kernel_init_freeable()ramdisk_execute_command进行检查,若未检查到有效的字符串,则将ramdisk_execute_command赋值为/init。然后,对ramdisk_execute_command进行访问权限检查,若失败,则进行rootfs挂载。

static noinline void __init kernel_init_freeable(void)
{
...
 if (!ramdisk_execute_command)
  ramdisk_execute_command = "/init";

 if (ksys_access((const char __user *)
   ramdisk_execute_command, 0) != 0) {
  ramdisk_execute_command = NULL;
  prepare_namespace();
 }
...
}

ramdisk_execute_command检查成功,则进入kernel_init()中,执行指定的init程序。

static int __ref kernel_init(void *unused)
{
 int ret;

 kernel_init_freeable();
 ...
 if (ramdisk_execute_command) {
  ret = run_init_process(ramdisk_execute_command);
  if (!ret)
   return 0;
  pr_err("Failed to execute %s (error %d)\\n",
         ramdisk_execute_command, ret);
 }
...
}

2.2 execute_command方式

通过kernel CMDLINE可以设定执行的init程序,例如:

CONFIG_CMDLINE="root=/dev/mmcblk1p2 rw console=ttySAC2,115200 init=/linuxrc rootwait"

在kernel代码中通过init_setup()解析命令行参数"init=",并赋值给execute_command

static int __init init_setup(char *str)
{
 unsigned int i;

 execute_command = str;
 ...
 for (i = 1; i < MAX_INIT_ARGS; i++)
  argv_init[i] = NULL;
 return 1;
}
__setup("init=", init_setup);

最后,在kernel_init()中执行execute_command所指定的init程序。

static int __ref kernel_init(void *unused)
{
...
 if (execute_command) {
  ret = run_init_process(execute_command);
  if (!ret)
   return 0;
  panic("Requested init %s failed (error %d).",
        execute_command, ret);
 }
...
 panic("No working init found.  Try passing init= option to kernel. "
       "See Linux Documentation/admin-guide/init.rst for guidance.");
}

2.3 默认方式

若以上两种指定init程序的方式均以失败告终,那么内核代码kernel_init()会执行如下4个默认的init程序,若也失败,则内核上报panic。

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;

 panic("No working init found.  Try passing init= option to kernel. "
       "See Linux Documentation/admin-guide/init.rst for guidance.");
}
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux系统
    +关注

    关注

    4

    文章

    591

    浏览量

    27345
  • CMD命令
    +关注

    关注

    0

    文章

    28

    浏览量

    8298
收藏 人收藏

    评论

    相关推荐

    编写第一个QT程序

    学习种编程语言或编程环境,通常会先编写“Hello World”程序。我们也用 Qt Creator 编写
    发表于 11-21 10:41 1007次阅读

    第一个arm9的应用程序helloworld需要掌握哪些内容?

    arm9的第一个应用程序 helloworld 的软件 硬件平台都有哪些?比如软件开发环境需要搭建什么平台 等等 ,路过的朋友不妨看看,谢谢。
    发表于 11-12 14:41

    【MiCOKit试用体验】+第一个 MiCO 应用程序

    【MiCOKit试用体验】+第一个 MiCO 应用程序对于开发板程序设计,第一个程序,hello world 是少不了的,今天我们来研究下
    发表于 10-23 21:50

    【Intel Edison试用体验】+第一个应用程序“Hello World!”(3)

    本帖最后由 满嘴谗言 于 2016-7-1 21:54 编辑 刷好了系统,我们就来配置交叉编译环境和编写第一个应用程序。1.第一步,下载交叉编译工具链。因为我要在Linux的虚拟机下操作,所以
    发表于 07-01 21:49

    【HarmonyOS HiSpark IPC DIY Camera试用连载 】鸿蒙OS内核如何启动第一个用户进程init_lite

    和源码位置,包括了kernel、startup子系统。Startup中的init_lite是kernel调用的第一个用户态进程; 3.第一个
    发表于 11-20 10:27

    [文章] 【HarmonyOS HiSpark IPC DIY Camera试用连载 】鸿蒙OS内核如何启动第一个用户进程init_lite

    位置,包括了kernel、startup子系统。Startup中的init_lite是kernel调用的第一个用户态进程;3.第一个用户态进
    发表于 11-20 16:44

    鸿蒙liteos-a如何启动第一个用户进程init_lite

    init_lite是kernel调用的第一个用户态进程; 3. 第一个用户态进程init_liteInit_lite的位置: 官方手册中对
    发表于 12-10 12:04

    鸿蒙liteos-a如何启动第一个用户进程init_lite

    init_lite是kernel调用的第一个用户态进程; 3. 第一个用户态进程init_liteInit_lite的位置: 官方手册中对
    发表于 12-10 15:02

    Niobe第一个应用程序

    Niobe第一个应用程序HelloWorld沿袭程序界的传统,第一个程序都是Hello World。在Niobe WiFi IoT开发板中,
    发表于 12-08 14:39

    Niobe第一个应用程序

    Niobe第一个应用程序HelloWorld沿袭程序界的传统,第一个程序都是Hello World。在Niobe WiFi IoT开发板中,
    发表于 12-08 17:36

    使用单片机STM32执行第一个程序是什么

    使用单片机STM32执行第一个程序是startup_stm32f407xx.s指令名称含义EQU给数字常量取符号名,相当于C语言中的d
    发表于 01-21 12:13

    Linux系统下init进程的前世今生

    kernel_thread产生的进程,其开始在内核态执行,然后通过系统调用,开始执行用户空间的/sbin/
    发表于 04-28 17:23 961次阅读

    第一个Xilinx Vitis IDE入门helloworld程序

    第一个Xilinx Vitis IDE入门helloworld程序
    发表于 01-23 06:37 8次下载
    <b class='flag-5'>第一个</b>Xilinx Vitis IDE入门helloworld<b class='flag-5'>程序</b>

    嵌入式Linux应用程序开发-(1)第一个嵌入式QT应用程序

    第一个嵌入式QT应用程序在成功安装 Qt Creator 开发环境后,我们通过简单的嵌入式Qt应用程序,来说明
    发表于 11-01 17:21 16次下载
    嵌入式Linux<b class='flag-5'>应用程序</b>开发-(1)<b class='flag-5'>第一个</b>嵌入式QT<b class='flag-5'>应用程序</b>

    如何编写第一个hello world程序

    本文简单介绍如何编写第一个hello world程序,以及程序是如何被执行
    的头像 发表于 03-02 17:31 8334次阅读
    如何编写<b class='flag-5'>第一个</b>hello world<b class='flag-5'>程序</b>