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

    文章

    574

    浏览量

    27036
  • CMD命令
    +关注

    关注

    0

    文章

    28

    浏览量

    8203
收藏 人收藏

    评论

    相关推荐

    第一个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

    求助 我的第一个程序

    第一个程序,出现了这样的问题,不会做了,怎么办,我是用ardublock写的程序
    发表于 02-28 16:50

    请问引导加载程序第一个和稍后的应用程序开始的过程是如何从USB角度看的

    在我们的应用中,我们将在USB树上大量的PSoC 3设备,并希望使用USB引导加载程序。现在,我想知道引导加载程序第一个和稍后的应用程序开始的过程是如何从USB角度看的。该设备枚举两
    发表于 05-14 09:56

    【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应用程序开发-(1)第一个嵌入式QT应用程序

    第一个嵌入式QT应用程序在成功安装 Qt Creator 开发环境后,我们通过一个简单的嵌入式Qt应用程序,来说明一下如何构建和编译一个Qt界面应用程序。关于如何安装并构建 Qt Cr
    发表于 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 8005次阅读
    如何编写<b class='flag-5'>第一个</b>hello world<b class='flag-5'>程序</b>

    linux内核启动过程会执行用户空间的init进程

    linux内核启动过程的后期,在kernel_init()函数代表的init线程中,会尝试执行用户空间的init进程
    的头像 发表于 10-14 09:12 837次阅读