linux 内核启动进程分析

阅读数:325 评论数:0

跳转到新版页面

分类

Linux

正文

一、概述

在kernel进入c语言阶段后,会开始执行start_kernel函数,它负责进行kernel正式运行前各个功能的初始化:打印一些信息、内核工作城要的模块的初始化被依次调用(譬如内存管理、调试系统、异常处理...),最后末尾调用了一个rest_init函数启动了三个进程(idle、kernel_init、kthreadd),来开启操作系统的正式运行。

(1)idle是操作系统的空闲进程,当cpu空闲的时候会去运行它。其前身是系统创建的第一个进程,运行在内核态,也是唯一一个没有通过fork或者kernel_thread产生的进程。完成系统加载后,演变为进程调试。

(2)kernel_init最开始只是一个函数,这个函数作为进程被启动,但是之后它将读取根文件系统下的init程序,这个操作将完成从内核态转到用户态的转变,而这个init进程是所有用户态进程的父进程,它产生了大量的子进程,所以init进程将永远存在,其pid为1.

kernel_init进程由idle通过kernel_thread创建,完成系统的初始化。

(3)kthreadd是内核守护进程,其PID为2。

作用就是运行kthread_create_list全局链表中维护的kthread,当我们调用kernel_thread创建的内核线程会被加入到此链表中,因此所有的内核线程都是直接或者间接的以kthreadd为父进程。

 

分析kernel_init进程

1、打开控制台设备

if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
printk(KERN_WARNING "Warning: unable to open an initial console.\n");

(void) sys_dup(0);
(void) sys_dup(0);

(1)首先打开了/dev/console文件,在Linux中一切皆文件,所以/dev/console文件代表的是控制台设备(其实就是串口)

(2)在Linux中,进程打开文件后会获得该文件的文件描述符。这里kernel_init进程就得到了控制台的文件描述符,然后又使用sys_dup复制了2次,一共得到了3个文件描述符。这三个文件描述符分别是0、1、2这三个文件描述符就是所谓的:标准输入、标准输出、标准错误。

(3)之后kernel_init所有的子进程都将继承这3个文件描述符,也就是后面所有的进程一生出来,就默认有标准输入、标准输出、标准错误的文件描述符。

2、挂载根文件系统

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

(1)prepare_namespace这个函数负责挂载根文件系统

(2)一般来说,挂载根文件系统失败的原因有:U-boot的环境变量bootargs设置不对,导制传递了错误的参数给kernel。

3、启动init进程

f (ramdisk_execute_command) {
run_init_process(ramdisk_execute_command);
printk(KERN_WARNING "Failed to execute %s\n",
ramdisk_execute_command);
}

/*
* 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.
*/
if (execute_command) {
run_init_process(execute_command);
printk(KERN_WARNING "Failed to execute %s. Attempting "
"defaults...\n", execute_command);
}
run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");

panic("No init found. Try passing init= option to kernel. "
"See Linux Documentation/init.txt for guidance.");

(1)去根文件系统中寻找init程序,具体路径由U-boot的环境变量bootargs提供,一旦init程序被找到,就会启动init进程(该可执行程序的文件名不一定叫init),然后操作系统正运行。

(2)如果U-boot的环境变量bootargs没有传递过来路径,或者路径中找不到,或者执行出错,那么它会去run_init_process指定的的4个地方看有没有init程序,如果都不成功,就启动失败。

(3)其它这个init程序一般来说是根文件目录下的linuxrc,linuxrc是一个符号链接。




相关推荐

在bootloader的帮助下,内核被载入到内存中,内核映像被加载到内存并获得控制权之后,内核启动流程开始。通常,内核映像以压缩形式存储,并不是一个可以执行的内核。因此内核的首要工作是自解压内核映像。

X86_64:uefi-&gt;shimx64.efi-&gt;grubx64.efi=&gt;/boot/efi/EFI/centos/grub.cfg=&gt;vmlinuz&amp;ini

GRUB 1、BIOS最后会读取引导设备第一个扇区的前 512 字节(MBR),将其读入到内存 0x0000:7C00,并跳转至此处执行。而安装在MBR的一般是GRUB sta

一、概述 1、为什么Linus不使用GPLv3 在 PC 上,只要你得到了某个程序的源代码,就可以自行编译生成二进制程序,然后替换掉原有的二进制程序,你的程序自由很容易得到保证。然而 iPod、iPh

说明:这种方式只是用于方便阅读代码,因为可以在源代间快速索引跳跃。但是最后可能会有一些warning,可以不必关心,如果是强迫症,可以使用下面这种方式来去掉。

一、SHMMAX参数:Linux进程可以分配置的单独共享内存段的最大值。 1、检查系统内存的大小,以及当前shmmax的设置 # grep MemTotal /proc/meminfo # cat /

一、官网 https://www.kernel.org/ 二、源代码结构 arch目录 包含了所有硬件体系结构特定的内核代码,每种硬件平台占一个相应的目录。在x86体系结构下,包括kernel

二进制内核接口 假设我们有一个稳定的内核内部使用的接口,那么就一定会出现一个二进制接口吗? 依赖于你使用的C编译器版本,不同的内核数据结构会包含不同的结构形式,也可能以多种形式包含函数(如是否内联)

1) 缩进 --------------制表符是 8 个字符,所以缩进也是 8 个字符。有些异端运动试图将缩进变为 4 (甚至2!) 字符深,这几乎相当

一、概述 Linux 内核熵池是一个重要的安全特性,它提供了一个用于生成加密安全随机数的熵源。在计算机系统中,熵是随机性的度量,对于许多加密操作来说至关重要,比如生成密钥、随机数或者其他加密元素。由于