操作系统的启动流程

第一步  

当我们按下电脑的电源键之后,主板就开始上电了,CPU就开始工作了。CPU在计算机刚刚启动时,是处于实模式状态下,他的一个寻址范围只有1M,而在这1M大小的地址空间中,最上面的64kb是,是映射到主板的一块ROM中,这一块ROM中固化的其实就是BIOS程序,而且电脑在启动的时候会将CPU的cs寄存器的值设置为0xffff,ip寄存器的值设置为0x0000,这样CPU第一条要执行的指令的地址就是0xffff0,这一个地址是在映射到ROM的那块空间中的,通过这种方式让CPU在计算器启动时去执行BIOS。BIOS首先就是检查硬件是否都是好的,然后还会创建一个中断向量表和一些中断处理程序,因为我们现在需要用到鼠标、键盘之类的,这些都是通过中断来进行的。BIOS做完了这些工作之后,他要做的事情基本就差不多完成了,接下来他到磁盘的启动盘上查找一个叫boost.img的文件,将它加载进内存并执行它。boost.img是由grub2工具写入到启动盘中去,大小是512字节。boost.img由于它只有512字节,所以他其实做不了太多事情,它的主要工作就是将grub2的另外一个叫做core.img的镜像加载进入内存。core.img这个文件中有很多小文件,如diskboost.img、kernel.img和一些模块文件等,所以boost.img首先会将core.img中的diskboost.img给加载进入内存,然后将控制权交给这他。diskboost.img他就负责将core.img下的其他文件给加载进入内存,在加载的过程中由于需要的内存空间越来越多,实模式下的1M大小的内存空间不够用了,于是在加载kernel.img之前,CPU会从实模式切花到保护模式,切换到保护模式就需要涉及到启动分段、启动分页以及打开地址总线等。切换完成之后,就会继续将core.img中的kernel.img给加载进入内存,然后执行它,kernel.img对应的代码中包含了grub工具kernel的主函数,它最开始会加载grub.conf这个配置文件,然后才往下执行,如果是正常启动的话,最终就会出现让我们选择操作系统封的界面,用户在选择之后接下来就涉及到根据我们选择的OS,加载对应的内核(vmlinuz)和以及临时内存文件系统(initrd.img/initramfs.img),最终会调用对应内核的启动函数。

第二步  操作系统的启动

操作系统内核的启动函数start_kernel.该函数的话,我们可以将它理解为是内核的main函数,该函数中包含了各种各样的初始化函数,负责对内核的各个模块进行初始化。首先就会初始化进程管理模块进行初始化,比如会创建0号进程,0号进程是OS中的第一个进程,也是OS中唯一没有通过fork/kernel_thread来创建的进程。然后接下来会调用trap_init来对CPU中的中断向量表进行初始化,它会将中断向量表中的前32号中断+一个32位系统调用的中断进行初始化。然后接下来会调用mm_init来对内存管理模块进行初始化,比如内核会创建一个mm_struct类型的结构体来对内核空间进行管理,然后还会创建和初始化内核页表。接下来会调用sched_init来对调度模块进行初始化。这些做完之后,最后会调用rest_init来做其他方面的一些初始化工作,比如会通过kernel_thread来创建1号进程,1号进程在启动时,由于是通过kernel_thread创建的,所以最开始是处于内核态的,之后1号进程会通过调用do_execve去执行刚刚加载进入内存的临时文件系统的init文件,这个可执行文件需要在用户态执行,所以在真正执行之前,会先对pt_regs中的值进行设置,然后通过iret指令返回用户态,返回用户态之后,根据刚刚设置的pt_regs中的值,1号进程就会去执行临时内存文件系统中的init可执行文件,最后再由该可执行文件调用真正根文件系统的init脚本,下来就是各种系统的初始化,启动系统的服务,启动控制台,用户就可以登录进来了。 OS之所以在启动的时候要先加载一个临时内存文件系统,由这个临时内存文件系统去加载真正的根文件系统的原因是 根文件系统一般是存储在硬件存储设备上的,而OS要访问硬件存储设备需要通过驱动才能够访问,如果存储系统数目很有限,那驱动可以直接放到内核里面,反正前面我们加载过内核到内存里了,现在可以直接对存储系统进行访问,但是存储系统越来越多之后,如果我们还是将对应的驱动全部编译到内核中去的话,那么内核就太臃肿了,于是就引入了这个临时内存文件系统,由于是内存文件系统,所以OS在访问时是不需要驱动的,在这个临时内存文件系统中通常会有许多的驱动文件,其中就包含根文件系统所在存储设备的驱动,临时内存文件系统的init可执行文件他要做的事情就是依次对这些驱动进行加载,加载完驱动之后,就可以访问真正的根文件系统了,所以他最后会去执行根文件系统的init脚本,从而完成对真正根文件系统的启动。通过这种方式,既保证的内核的小巧,同时也增强了灵活新,可以在保证内核不变的情况下通过修改initrd中的内容就可以灵活的支持不同的硬件       rest_init第二件要做的事情是调用kernel_thread创建出一个2号进程,2号进程是内核进程的祖先,他负责内核所有进程的调度和管理。
全部评论
大佬这些os知识从哪学的有资料推荐吗
点赞 回复 分享
发布于 2023-06-01 19:57 广东

相关推荐

04-11 23:51
门头沟学院 Java
坚定的芭乐反对画饼_许愿Offer版:人人都能过要面试干嘛,发个美团问卷填一下,明天来上班不就好了
点赞 评论 收藏
分享
咖啡不掺水:团子一志愿嵌入式今日已挂,等捞😭
投递美团等公司10个岗位 美团求职进展汇总
点赞 评论 收藏
分享
评论
2
7
分享

创作者周榜

更多
牛客网
牛客企业服务