Linux教程

[自制操作系统] 第01回 计算机启动过程

本文主要是介绍[自制操作系统] 第01回 计算机启动过程,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

目录
一、前言
二、准备工作
三、软件接力第一棒BIOS

 

一、前言

  我在学习操作系统的时候,看的是汤子瀛版的《计算机操作系统》第四版,这本书总的来说我觉得是写的还不错的,语言讲解通俗易懂。只不过看书终归是纸上谈兵,缺少实操的部分,就会导致自己以为懂得的知识点其实是经不起推敲的,无法清楚地复述出来的。所以后来我又查阅了一些其他的资料,其中郑钢的《操作系统真象还原》是我最喜欢的一本书,手把手教你写一个简单的操作系统,使我对之前书上的概念有了更加清晰的认识,本系列的所有文章是笔者在学习本书时的一些学习笔记,虽然这本书有一些小小的错误,但是瑕不掩瑜,依旧是我认为学习操作系统最好的一本书之一。此外,还要感谢博客园博主闪客,我在写这一个操作系统系列笔记时也大量参考了他的帖子,感兴趣的读者,我强烈推荐也去阅读一下他的帖子。

  回到正题,我为什么会想着写这么一个系列呢?其实我本人是喜欢做一些Linux嵌入式开发的工作的,以后也想从事这方面的工作,所以在日常学习中,难免就会与操作系统打一些交道。我不是科班出身的,因此需要自己补一下这方面的基础,所以也就有了这么一个系列的出现,写的不好,希望读者见谅,我只是把它当做自己学习的一个笔记,日后方便回来复习,不敢标称是什么教程。如果能帮助到别人那是我的幸运。对于帖子中出现的错误,我虚心接受读者的批评与指正。

二、准备工作

  本系列是基于Bochs平台编写基于x86架构的32位操作系统,所以我们有必要对x86架构有一个简单的认识。

  在1978年6月8日,Intel发布了新款16位微处理器“8086”,也同时开创了一个新时代:x86架构诞生了。x86指的是特定微处理器执行的一些计算机语言指令集,定义了芯片的基本使用规则。后来随着人们对性能需求的不断增长,Intel推出了越来越多性能更加强悍的处理器,如80286、80386、80486以及后面的奔腾系列等等。这些处理器有什么区别呢,我就只拿这三款处理器做一个简单的介绍。

   

  上图可以看到,CPU升级后,地址总线宽度和寄存器的宽度都相应地得到了提高,这样的好处便是CPU的运算速度较之从前有着明显的提高。

  可以看到里面有提到实模式,保护模式的概念,其实这个概念是人们后来为了区分CPU的运行模式人为加上去的。

  最初的x86架构的CPU是8086,它的所有寄存器都是16位的,只有地址线是20位,所以它访问空间的方式是段基址寄存器左移4位再加上段偏移地址,这样最终形成一个物理地址送上地址总线。这个寻址方式在我们现在看来有点奇怪,其实也是当时工程师提出的一种解决寄存器位数与地址总线宽度不匹配的方法。

  这有两个坏处,第一就是可访问的空间太小,跟不上计算机发展的需要。第二就是缺少保护机制,程序可以随意访问这 1M 的地址空间,甚至覆盖掉操作系统本身的代码和数据。

  这样操作系统的发展和需求,就倒逼着CPU的发展,于是有了80286,80286地址总线拓宽到了24位,拥有16MB的寻址空间,除此之外,80286通过对段选择子的方式对内存进行了保护,有了很多新的特性。但为了兼容老程序,必须还要支持16位机的特征,所以就有了两个模式,并且程序还要通过调用一些 CPU 的指令从一个模式切换到另一个模式,比如经典的打开A20地址线。

  80286虽然有了保护模式,但是依然是16位的CPU,其通用寄存器还是16位宽,即单独的一个寄存器还是只能访问64KB的空间,如果用寄存器作为段内偏移地址,段的大小还是64KB,要想访问完整的16MB内存,依然要不断地变换段基址,所以本质上和8086没有太大区别,也就导致80286比较鸡肋,很快就被淘汰了。后面80386出现了,32位地址线和32位寄存器直接一步到位解决问题,并且也支持保护模式。

  这两个模式,其实我们完全可以按照更准确的理解,叫做16位模式和32位模式,然后补充一句说32位模式比16位模式有了更大的寻址空间(这是自然的)和更好的内存保护机制。但由于CPU厂商希望凸显他们新模式的优势,所以直接把最关键的优势“保护”给放到了名字里,叫保护模式。而为了对比也要给之前的模式起一个名字,之前的模式比较实在,给出什么地址就直接是物理地址,也没有转换也没有安全保护,那就叫它实模式吧。

  现在我们只需要知道8086处理器是运行在实模式下的,而随着处理器的升级,后面的处理器可以运行在保护模式下,至于为什么80386一开始是运行在实模式下,后面再转换为保护模式呢,其实它也说到了,为了兼容,因为每一款产品必须兼容之前的设计,这样才会让顾客买单。

  对于Intel8086,我们可以看到它20条地址线,故可以访问到2^20=1048576=1MB的内存空间,若是按照十六进制来表示,则是0x00000~0xFFFFF。下面是实模式下的1MB内存布局。

   

  这里着重解释一个问题,也是以前我的一个认识的误区,我以前以为我们插在主板上的内存就是CPU眼中的内存,其实这个认识是错误的。首先我们知道地址总线宽度决定CPU可以访问的内存大小,如8086的地址总线是20位,那么可以访问的内存大小为1MB,80386的地址总线是32位,那么可以访问的内存大小为4GB。但是以上的地址范围是指地址总线可以触及到的边界,是指计算机在寻址上可以到达的疆域。并不是说寻址范围取决于内存条的大小,归根结底的原因是:在计算机中,并不是只有我们插在主板上的内存条需要通过地址总线来访问,还有一些外设同样是需要通过地址总线来访问的。所以,实际上CPU眼中的内存分布应该是这样的:

         

  关于其中提到的地址映射,这是在硬件层面完成的工作,对操作系统来讲是透明的。

三、软件接力第一棒BIOS

  我之前挺好奇每次一按主机上的电源键,电脑是怎么启动并运行的。所以我去百度了一下:当电源打开后,PC做的第一件事情就是CPU从内置的芯片中加载一个最简单程序,这个程序叫做BIOS(基本输入输出系统,随后BIOS程序启动后就会检测并初始化硬件设备,比如显卡,内存等,随后将控制权交给硬盘,在硬盘中寻找主引导记录的分区,这个分区告诉电脑操作系统在哪里,最后CPU从硬盘上加载操作系统完成启动过程。

  所以接下来的工作先从BIOS开始。

  BIOS全称叫做Base Input & Output System,即基本输入输出系统,它是被固化在计算机ROM芯片上的一组程序。它的主要工作是检测、初始化硬件。如何初始化的呢?这里说一下题外话,硬件厂商会事先实现这些初始化功能,最后在外部提供调用接口就行了,BIOS只需要通过这些调用接口就能完成硬件的初始化。BIOS还建立了中断向量表,这样CPU就可以通过“int 中断号”的方式来实现相关的硬件调用。

  在前面提到的实模式下的内存布局中,我们知道BIOS代码就存放在0xF0000~0xFFFFF。访问这个地址便是访问BIOS,那么BIOS代码是如何被执行的呢?换句话说就是CPU是如何知道BIOS代码存放于此的呢?其实这是事先通过硬件电路实现的,没错,就是这么魔幻。当上电后,CPU的cs:ip寄存器自动被赋值为0xf000:0xfff0,这个组合出来的地址便是0xffff0,这是处理器下一条待执行指令的地址。这个地址就是我们的BIOS代码的存放地址。这个地址存放的代码如下:

  jmp far f000:e05b

  这是一条跳转指令,cpu跳转到0xfe05b地址处执行,其实也在意料之中,因为在内存布局图中可以看到,0xffff0距离0xfffff也就只有16字节的空间,这么小的空间怎么能够完成BIOS的一系列初始化工作呢?

  所以跳转到0xfe05b才是BIOS真正开始执行的地方。接下来BIOS便开始马不停蹄地检测内存、显卡等外设的信息,当检测通过并初始化好硬件后,在内存中0x000~0x3FF处建立中断向量表IVT并且填写中断例程。至此,BIOS的使命也就结束了,我觉得没有必要去深究BIOS的代码。因为底层无非就是一些调用接口完成初始化的代码。

  虽然BIOS完成了它的使命,但是我们还需要继续走下去,这里提一句,BIOS最后会检查启动盘的第一个扇区中的内容,如果此扇区中末尾两个字节分别是魔数0x55和0xaa,那么BIOS便认为此扇区中存在可执行程序(也就是后面我们要讲解的主引导记录MBR),便将此扇区的内容全部加载到物理地址0x7c00处执行。

  关于为什么是检查第一个扇区、为什么是魔数0x55和0xaa以及为什么是地址0x7c00?

  这里我就借用一下书上的解释:第一个扇区和魔数的问题,其实就是为了方便,一个约定俗成的规定罢了;那为什么是地址0x7c00呢?其实是取决于当时操作系统本身所占的内存大小和内存布局罢了。也就是工程师们绞尽脑汁想要榨取每一块内存区域的利用价值导致最后遗留下的结果。这个区域也许现在看来有点奇怪或者不合适,但是为了系统兼容性问题,这个0x7c00的地址就一直沿用到现在。

  总结一下计算机的启动过程:

  1. 首先按下开机键后,CPU将cs:ip寄存器强制初始化为0xf000:0xfff0,这样得到的组合地址便是0xffff0,这个地址便是BIOS程序所在位置。
  2. BIOS程序所在位置是一条跳转指令,CPU跳转到地址0xfe05b处开始执行。
  3. 0xfe05b处才算是BIOS真正开始的地方,在此处的程序中BIOS完成硬件检测工作以及建立中断向量表后,将启动盘中的主引导记录加载到内存0x7c00处并跳转执行。
  4. 主引导记录中的代码主要是加载操作系统内核,并跳转到加载处执行。
  5. 最后操作系统便开始执行了,最终呈现在我们的面前的便是图形化的操作界面等等。

  现在我们已经知道BIOS将控制权递交给了MBR,那么接下来我们便开始动手写一个自己的MBR程序,欲知后事如何,请看下回分解。

 

这篇关于[自制操作系统] 第01回 计算机启动过程的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!