内核初始化的过程

简介: 【9月更文挑战第13天】内核启动始于函数 `start_kernel()`,该函数位于 `init/main.c` 文件中,包含各类初始化函数。操作系统首先创建 0 号进程 `init_task`,随后初始化中断处理、内存管理、调度模块及虚拟文件系统 VFS。

内核的启动从入口函数 start_kernel() 开始。在 init/main.c 文件中,start_kernel 相当于内核的 main 函数。打开这个函数,你会发现,里面是各种各样初始化函数 XXXX_init。

image.png

在操作系统里面,先要有个创始进程,有一行指令 set_task_stack_end_magic(&init_task)。这里面有一个参数 init_task,它的定义是 struct task_struct init_task = INIT_TASK(init_task)。它是系统创建的第一个进程,我们称为 0 号进程。这是唯一一个没有通过 fork 或者 kernel_thread 产生的进程,是进程列表的第一个。

第二个要初始化的就是办事大厅。有了办事大厅,我们就可以响应客户的需求。

这里面对应的函数是 trap_init(),里面设置了很多中断门(Interrupt Gate),用于处理各种中断。其中有一个 set_system_intr_gate(IA32_SYSCALL_VECTOR, entry_INT80_32),这是系统调用的中断门。系统调用也是通过发送中断的方式进行的。

接下来要初始化的是咱们的会议室管理系统。对应的,mm_init() 就是用来初始化内存管理模块。

项目需要项目管理进行调度,需要执行一定的调度策略。sched_init() 就是用于初始化调度模块。

vfs_caches_init() 会用来初始化基于内存的文件系统 rootfs。在这个函数里面,会调用 mnt_init()->init_rootfs()。这里面有一行代码,register_filesystem(&rootfs_fs_type)。在 VFS 虚拟文件系统里面注册了一种类型,我们定义为 struct file_system_type rootfs_fs_type。

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

最后,start_kernel() 调用的是 rest_init(),用来做其他方面的初始化,这里面做了好多的工作。

rest_init 的第一大工作是,用 kernel_thread(kernel_init, NULL, CLONE_FS) 创建第二个进程,这个是 1 号进程。

1 号进程对于操作系统来讲,有“划时代”的意义。因为它将运行一个用户进程,x86 提供了分层的权限机制,把区域分成了四个 Ring,越往里权限越高,越往外权限越低。

image.png


操作系统很好地利用了这个机制,将能够访问关键资源的代码放在 Ring0,我们称为内核态(Kernel Mode);将普通的程序代码放在 Ring3,我们称为用户态(User Mode)。

当一个用户态的程序运行到一半,要访问一个核心资源,例如访问网卡发一个网络包,就需要暂停当前的运行,调用系统调用,接下来就轮到内核中的代码运行了。

首先,内核将从系统调用传过来的包,在网卡上排队,轮到的时候就发送。发送完了,系统调用就结束了,返回用户态,让暂停运行的程序接着运行。

image.png

这个过程就是这样的:用户态 - 系统调用 - 保存寄存器 - 内核态执行系统调用 - 恢复寄存器 - 返回用户态,然后接着运行。

image.png

内存访问是不需要驱动的,这个就是 ramdisk。这个时候,ramdisk 是根文件系统。

然后,我们开始运行 ramdisk 上的 /init。等它运行完了就已经在用户态了。/init 这个程序会先根据存储系统的类型加载驱动,有了驱动就可以设置真正的根文件系统了。有了真正的根文件系统,ramdisk 上的 /init 会启动文件系统上的 init。

接下来就是各种系统的初始化。启动系统的服务,启动控制台,用户就可以登录进来了。




相关文章
|
6月前
|
传感器 Linux API
如何实现 MCU软件中多个模块初始化函数的优雅调用
如何实现 MCU软件中多个模块初始化函数的优雅调用
|
1月前
|
缓存 小程序 UED
如何利用小程序的生命周期函数实现数据的加载和更新?
如何利用小程序的生命周期函数实现数据的加载和更新?
54 4
|
2月前
|
编译器
【收藏】内核级利用通用Hook函数方法检测进程
【收藏】内核级利用通用Hook函数方法检测进程
【STM32】详解独立看门狗的本质和使用步骤&代码
【STM32】详解独立看门狗的本质和使用步骤&代码
|
Linux
编译进内核的驱动是如何工作的
编译进内核的驱动是如何工作的
103 0
编译进内核的驱动是如何工作的
|
API
驱动开发:内核远程堆分配与销毁
在开始学习内核内存读写篇之前,我们先来实现一个简单的内存分配销毁堆的功能,在内核空间内用户依然可以动态的申请与销毁一段可控的堆空间,一般而言内核中提供了`ZwAllocateVirtualMemory`这个函数用于专门分配虚拟空间,而与之相对应的则是`ZwFreeVirtualMemory`此函数则用于销毁堆内存,当我们需要分配内核空间时往往需要切换到对端进程栈上再进行操作,接下来`LyShark`将从API开始介绍如何运用这两个函数实现内存分配与使用,并以此来作为驱动读写篇的入门知识。
228 0
|
网络安全
服务器初始化及内核调优脚本
服务器初始化及内核调优脚本
嵌入式程序调用函数的内部过程和机制
嵌入式程序调用函数的内部过程和机制
嵌入式程序调用函数的内部过程和机制
|
存储 小程序 Android开发
技术干货 | 轻松两步完成向 mPaaS 小程序传递启动参数
以传递 name 和 pwd 参数为例,分别介绍此场景在 Android 小程序和 iOS 小程序中的实现过程。
9140 0
技术干货 | 轻松两步完成向 mPaaS 小程序传递启动参数