代码改变世界

内核初始化

2019-04-27 23:44  JaPer  阅读(728)  评论(0编辑  收藏  举报

内核启动的入口函数  start_kernel()   {init/main.c配置文件} , 里面有XXXX_init的初始化函数

 

 

 

1)在操作系统中有个创始进程,set_task_stack_end_magic(&init_task)。 有一个参数 init_task 定义是struct task_struct init_task = INIT_TASK(init_task)  是系统默认创建的第一进程(0号进程) 唯一一个没有通过fork或者Kernel_thread 产生的进程

(Procese List) 项目管理进程 , 内有所有项目

2)办事大厅:  函数(trap_init())  其中设置了很多中断门(Interrupt Gate)

其中 set_system_intr_gate(IA32_SYSCALL_VECTOR,entry_INT80_32)  为系统调用的中断门。 并且通过发送中断的方式进行的。 (64位有另外的系统调用方法)

3) 会议室管理系统: 初始化内存管理模块【mm_init()】 

           初始化调度模块【 sched_init()】    进行调度时则需要执行一定的调度策略

   文件系统 rootfs   初始化基于内存的文件系统【 vfs_caches_init()】 

             函数里调用 mnt_init()-> init_rootfs() 

              register_filesystem(&rootfs_fs_type) ,在VFS 虚拟文件系统里注册了一种类型  定义为 struct file_system_type rootfs_fs_type 

    文件系统即为项目资料库。首先要兼容所有的文件系统,需将文件的相关数据结构和操作抽象出来,形成一个对上提供统一的接口。这个抽象层就是VFS ( Virtual File System) 。虚拟文件系统

  此时,rootfs 还有其他用处。 

   start_kernel() 调用的是 rest_init() 。 是做其他方面的初始化

           

4) rest_init 为原始进程 要创建第二个进程则用 kernel_thread(kernel_init,NULL,CLONE_FS) 

  当进程出现的时候就要考虑安全性,并将进程做一些主要的权限区分等级,比如哪些是核心资源,那些事非核心资源。

 核心关键资源放在内部,则称为内核态(Kernel Mode)

 普通的程序资源则可放在应用里,则称为用户态(User Mode)

系统启动时已经处于保护模式。则用户的权限直接导致当前用户的访问空间以及读写等操作空间。

若普通用户想访问核心资源,则需要提供系统调用的办事大厅,可在此请求。然后就是内核态, 等用户态代码做完了返回结果就可以了。

若用户态的程序运行一半的时候需要访问内核资源,则暂停当前运行,调用系统调用,然后转到内核中的代码继续运行。然后再内核网卡上进行排队处理。等处理完成后也就是系统调用结束,则返回到用户态,继续暂停的程序

程序过程: 用户态 — 系统调用 — 保持寄存器 — 内核态执行系统调用 — 恢复寄存器 — 返回用户态,然后接着运行。

5) 从内核态到用户态

当执行 kernel_thread 函数时,我们处于内核态,kernel_thread 的参数是一个函数 kernel_init 并且会此进程会运行此函数, 在此里面会调用 kernel_init_freeable() :

            if (!ramdisk_execute_command)

            ramdisk_execute_command = "/init";

 进程运行的是一个文件,若打开run_init_process函数。则发现它调用的是 do_execve 。 (execve 是系统调用,作用是运行一个执行文件,加一个do_ 则是内核系统调用的实现。  并且会尝试运行 ramdisk 的 “/init“ 或者 ”/sbin/init" , "/etc/init"  , "/bin/init" , "/bin/sh"  。 不同的Linux版本会选择不同的文件启动,但只需要有一个启动即可。

则调用过程 do_execve -> do_execveat_common -> exec_binprm -> search_binary_handler, 

运行加载二进制文件,则需要Linux下常用的格式 ELF ( Executable and Linkable Format,可执行与可链接格式)

6) Ramdisk 的作用

当访问一个U盘或存储系统的时候,则需要安装驱动才能访问,若存储系统过多,则安装的驱动也多。此时则先弄一个基于内存的文件系统,内存访问则不需要驱动。这个就叫 ramdisk。 ramdisk 则是根文件系统 

然后运行 ramdisk 上的 /init 。运行完了就已经在用户态上了。 /init 程序会先根据存储系统的类型加载驱动,然后设置真正的根文件系统, 然后ramdisk上的 /init 会启动文件系统上的 init,然后就是各种系统初始化,启动系统的服务,启动控制台,用户登陆等等。。。

7) 创建 2号进程

Kernel_thread(kthreadd,NULL,ClONE_FS | CLONE_FILES)  使用kernel_thread 函数创建进程 【函数名 thread 可翻译为 “线程” 】

从用户态来看,创建进程即为立项,也就是启动项目,此项目包含会议室,资料库等。 但项目需要人去执行,若有多个人并行执行不同的部分,则称为多线程 (Multithreading),若只有一个人,那则是此项目的主线程。

从内核看,无论进程还是线程,统称为任务(Task),使用相同的数据结构,平放在同一个链表中。 

于此,函数 kthreadd 负责所有内核态的线程的调度和管理,是内核态所有线程运行的祖先