操作系统的启动过程详解

目录

  • 1.先有鸡还是先有蛋
  • 2.什么是MBR
  • 3.BIOS基本原理
  • 4.BIOS深入理解
  • 5.0x7c00 是啥
  • 6.总结

1.先有鸡还是先有蛋

什么是操作系统?定义有很多,我最喜欢的定义就是:操作系统是管理底层硬件资源,并为上层软件提供服务的软件。说到底操作系统就是一个C语言程序,这个C语言程序能启动和终止其他软件程序。那么问题来了,操作系统这个C程序又是怎么启动的,这个问题很像先有鸡还是先有蛋的问题,好像永远陷入了死循环。

2.什么是MBR

想要知道答案还得要了解一些计算机组成原理的知识。第一个要解决的问题是什么是MBR。

先来看看磁盘的组成原理。磁盘的组成主要有盘片、机械手臂、磁头与主轴马达所组成, 而数据的写入其实是在盘片上面。盘片上面又可细分出扇区与磁道两种单位, 其中扇区的物理量设计有两种大小,分别是 512字节与 4K字节(高级磁盘)。那么是否每个扇区都一样重要呢?其实整个磁盘的第一个扇区特别的重要,因为他记录了整个磁盘的重要信息,第一个扇区也叫主引导扇区。它在硬盘上的三维地址为(磁盘,磁道,扇区)这个三元组。这个三元组和我们的逻辑地址会有一个一对一的映射关系。

主引导扇区由三部分构成:

  • 主引导记录(Master Boot Record, MBR): 可以安装开机管理程序,有446字节。
  • 磁盘分区表(Disk Partition Table, DPT): 记录整个磁盘分区状态,有64 字节。
  • 主引导扇区结束标志(MN) 0XAA55, 有2字节 。

446+64+2=512字节。所以MBR(Master Boot Record)主引导记录的作用就是安装启动引导程序的地方,并且MBR的位置就是(0,0,1)。

这里是一些扩展部分,可以不看。
由于分区表所在区块仅有64 字节容量,因此最多仅能有四组记录区,每组记录区记录了该区段的启始与结束的柱面号码,四个分区的大小可以不一样, 这四个分区的被称为主要分区或扩展分区。重点来了,第一个分区存放了主引导扇区的内容和一些数据内容,这没话说。那么就还剩三个分区可以使用,如果第二个分区和第三个分区被使用后,那么最后一个分区就是扩展分区。注意主要分区可以被格式化,但是扩展分区不能被格式化。扩展分区可以分成很多更小的分区,这些小分区叫逻辑分区,逻辑分区可以被格式化。
操作系统的启动过程详解_第1张图片

3.BIOS基本原理

BIOS是一个写入到主板上的一个固件( 固件就是写入到硬件上的一个软件程序)。BIOS就是在开机的时候,计算机系统会主动执行的第一个程序。接下来BIOS会去分析计算机里面有哪些硬件设备,并进行硬件自检,如果硬件接口不匹配就会报错。之后BIOS会在硬盘中查找启动设备,并且到硬盘里面去读取第一个扇区的MBR位置。 MBR这个仅有446 字节的硬盘容量里面会放置最基本的开机管理程序,此时BIOS就功成圆满,而接下来就是MBR内的开机管理程序的工作了。这个开机管理程序的目的是在加载核心文件,由于开机管理程序是操作系统在安装的时候所提供的,所以他会认识硬盘内的文件系统格式,因此就能够读取核心文件。这个核心文件就是操作系统内核, 然后接下来核心文件加载成功意味着操作系统成功启动,BIOS将硬件的控制权交给操作系统。

4.BIOS深入理解

看完前面的BIOS基本原理,大部分人基本上还是一头雾水,为什么BIOS就是计算机执行的第一个程序?BIOS这个程序里面写了什么?等等一系列问题。

要解释这些问题需要有一些前置知识,我总不可能从原子组成分子开始讲起吧。这些前置知识就是:

  1. 内存是存储数据的地方,给出一个地址信号,内存可以返回该地址所对应的数据。
  2. CPU 的工作方式就是不断从内存中取出指令,并执行,是一个无情的执行指令的机器。
  3. CPU 从内存的哪个地址取出指令,是由一个寄存器中的值决定的,这个值会不断进行 “+1” 操作,或者由某条跳转指令指定其值是多少。

以上知识就是计算机组成原理的一些基本知识,只需要知道这三点前置知识,你就能专业地解释计算机的启动过程了。

先来理解一下内存映射,CPU 地址总线的宽度决定了可访问的内存空间的大小。32 位的 CPU 地址总线宽度为 32 位,地址范围是 4G。64 位的 CPU 地址总线宽度为 64 位,理论上地址范围是16384PB 或16777216TB。但实际上很多64位CPU使用40位地址线,最大寻址空间仅为1TB。

但是可访问的内存空间这么大,并不等于说全都给内存使用,也就是说寻址的对象不只有内存,还有一些外设也要通过地址总线的方式去访问,那怎么去访问这些外设呢?就是在地址范围中划出一片片的区域,这块给显存使用,那块给硬盘控制器使用,等等 。就相当于在显存等外设的相应位置上读取或者写入,就好像这些外设的存储区域,被映射到了内存中的某一片区域一样。这样我们就不用管那些外设,关注点仍然是一个简简单单的内存。这就是所谓的内存映射。

小总结:就是当你按下电源键的那一刻,整台计算机的硬件开始通电,硬件上的固件就映射到内存当中。以磁盘为例,磁盘上的BIOS这个固件被映射到的内存位置为0xC0000 - 0xFFFFF 。0xFFFFF-0xC0000=256kB。这个256KB的固件程序包括了显卡BIOS、IDE控制器BIOS和最重要的系统BIOS。其中,系统BIOS在内存的 0xF0000 - 0xFFFFF位置。

我们要用到另一个前置知识了,就是 CPU 从内存的哪个位置取出执行并执行呢?是 PC 寄存器中的地址值。BIOS 程序的入口地址也就是开始地址是 0xFFFF0(人家就那么写的),也就是开机键一按下,将 pc 寄存器中的值变成 0xFFFF0,然后 CPU 就开始马不停蹄地跑了起来。

小总结:在你开机的一瞬间,CPU通电之后,CPU 的 PC 寄存器被强制初始化为 0xFFFF0。如果再说具体些,CPU 将段基址寄存器 cs 初始化为 0xF000,将偏移地址寄存器 IP 初始化为 0xFFF0,根据实模式下的最终地址计算规则,将段基址左移 4 位,加上偏移地址,得到最终的物理地址也就是抽象出来的 PC 寄存器地址为 0xFFFF0。

上面就分析完了BIOS程序是如何映射到内存以及CPU是如何知道BIOS程序在内存中的位置。

那接下来的问题似乎也非常自然地就问出来了,那就是 BIOS 程序里到底写了啥?我们先来简单分析一下,你看系统BIOS程序的入口地址是 0xFFFF0,说明程序是从这执行的。实模式下内存的下边界就是 0xFFFFF,也就是只剩下 16 个字节的空间可以写代码了,这够干啥的呢?如果你有心的话应该能猜出,入口地址处可能是个跳转指令,跳到一个更大范围的空间去执行自己的任务。没错就是这样,0xFFFF0 处存储的机器指令,翻译成汇编语言是:

jmp far f000:e05b

意思是跳转到物理地址 0xfe05b 处开始执行。地址 0xfe05b 处开始,便是 BIOS 真正发挥作用的代码了,这块代码会检测一些外设信息,并初始化好硬件,建立中断向量表并填写中断例程。这里的部分不要展开,这只是一段写死的程序而已,而且对理解开机启动过程无帮助,我们看后面精彩的部分,也就是 BIOS 的最后一项工作:加载启动区。

5.0x7c00 是啥

加载在计算机领域就是指,把某设备上(比如硬盘)的程序复制到内存中的过程。那加载启动区这个过程,翻译过来就是,BIOS 程序把启动区的内容复制到了内存中的某个区域。好了,问题又自然出来了,启动区是哪里?被复制到了内存的哪个位置?

BIOS 会按照顺序,读取这些启动盘中位于 0 盘 0 道 1 扇区的内容。 这 0 盘 0 道 1 扇区的内容一共有 512 个字节,如果末尾的两个字节分别是 0x55 和 0xAA,那么 BIOS 就会认为它是个启动区。如果不是,那么按顺序继续向下个设备中寻找位于 0 盘 0 道 1 扇区的内容。如果最后发现都没找到符合条件的,那直接报出一个无启动区的错误。

注释:看看第二段的内容,有一句话是“主引导扇区结束标志(MN) 0XAA55, 有2字节”,但刚刚又说“BIOS如果读取到末尾的两个字节分别是 0x55 和 0xAA,那么 BIOS 就会认为它是个启动区。”好像写反了,但其实并没有,因为机器使用的是小端法。现在Intel和arm系列的处理器使用的是小端法;IBM,sun系列的处理器使用的是大端法。

BIOS 找到了这个启动区之后干嘛呢?当然是把这 512 个字节的内容,一个比特都不少的全部复制到内存的 0x7c00 这个位置。启动区内容此时已经被 BIOS 程序复制到了内存的 0x7c00 这个位置,然后呢?这个其实也不难猜测,启动区的内容就是我们自己写的代码了,复制到这里之后,就开始执行呗,之后我们的程序就接管了接下来的流程,BIOS 的使命也就结束了。所以复制完之后,接下来应该是一个跳转指令,PC 寄存器的值变为 0x7c00,指令开始从这里执行。

对了,现在似乎就剩下一个问题了,为什么非要是 0x7c00 呢?这个问题答案也很简单,那就是人家 BIOS 开发团队就是这样定的,之后也不好改了,不然不兼容。正因为 BIOS 将启动区的代码加载到了0x7c00,因此有了一个偏移量,所以所有写启动区代码的人就需要在开头写死一个这样的代码,不然全都串位了。然后正因为所有写操作系统的,启动区的第一行汇编代码都写死了这个数字,那 BIOS 开发者最初定的这个数字就不好改了,否则它得挨个联系各个操作系统的开发厂商,说唉我这个地址改一下哈,你们跟着改改。在公司推动另一个团队改个代码都得大费周折,想想看这样的推动得耗费多大人力。况且即使改了,之前的代码也都不兼容了。

所以 BIOS 负责加载了启动区,而启动区又负责加载真正的操作系统内核。

6.总结

现在经过好几轮跳跳跳,终于跳到内核代码,我们来回顾一下:

  1. 按下开机键,CPU 将 PC 寄存器的值强制初始化为 0xffff0,这个位置是 BIOS 程序的入口地址(一跳)
  2. 该入口地址处是一个跳转指令,跳转到 0xfe05b 位置,开始执行(二跳)
  3. 执行了一些硬件检测工作后,最后一步将启动区内容加载到内存 0x7c00,并跳转到这里(三跳)
  4. 启动区代码主要是加载操作系统内核,并跳转到加载处(四跳)

经过这连续的四次跳跃,操作系统就成功启动了。终于来到了操作系统的世界了,剩下的内容,可以说是整个操作系统课程所讲述的原理,分段、分页、建立中断、设备驱动、内存管理、进程管理、文件系统、用户态接口、TCP\IP协议栈等等。

你可能感兴趣的:(操作系统,linux)