想写好操作系统,必须得先学明白从计算机开机到运行操作系统中间发生的所有事情
计算机开机那点事:从按下电源键到运行操作系统
1. 一切从主板开始说起
CPU
不是一个可以单独工作的部件,需要内存、显卡、键盘、鼠标等等的设备支持,还需要供电、散热等等东西才能够正常的运行。
CPU
的背部有很多的金属触点,这些金属触点就是CPU
的供电来源、地址线、数据线等等。这些金属触点,我们称之为引脚
而为了把CPU
和内存、硬盘、屏幕还有鼠标键盘连接在一起,让数据能够互相流通,人们设计了一块可以连接所有设备的电路板,这个板子就是主板
(Mother Board
)
不仅电脑中有主板
,手机上也有主板
,乃至于微波炉、洗衣机等等计算机或者由计算机控制的设备上,都有主板
。只不过手机上的和微波炉、洗衣机中的主板比电脑上的主板小得多的说,而且连接到上面的设备也少的多得多。
主板
上实际有很多层电路,而层与层之间又绝缘胶相互隔绝。因此每一层都可以视为是不同的电路,或者说具有特殊功能的导线。
因此,主板
就可以将各种各样的设备连接起来。
所以我们如果要把CPU
链接到当前主板
上去的话,那么我们只需要把CPU
放到主板
上的内存插槽中,那么CPU
就通过底部的N多个金属触点,连接到了主板
上N多个导线上。
同理,主板
上也提供了内存插槽,我们把内存
插到内存插槽
上,那么通过主板内部的某一层电路,CPU
就和内存建立了联系,他们之间就可以交换数据了
而为了显示,我们插上显卡,并且连接显示器
为了获取用户输入输出,我们插上鼠标键盘
当然,如果没有电,那么计算机是没有办法工作的,而CPU工作的第一个要求就是有供电。所以我们还需要给主板接上电,所以还需要给主板接上电源模块。
最终,一台像模像样的计算机就搭建起来了。
上面我们讲解了一台计算机中的硬件,接下来我们将讲解计算机开机的整个流程。
2. 开机第一步:接通电源
有人可能会问,计算机开机不是应该在按下电源键之后才开始的么?错了,其实计算机开机在接通电源之后就已经开始了
我们接下来将讲解开机的第一步:接通电源
。
1. 什么是接通电源?
有人可能会问,为什么连接通电源都要讲,难道不是把计算机的插头插到插座上么?错了,其实针对台式机这种没有内部供电的计算机,把插头插到插座上是接通电源。
而对于手机、笔记本这种有内置供电的计算机,把电池接上计算机才是接通电源。
总之,在我们为计算机接通电源的那一刹那,电力供应就源源不断的来到了主板,但是此时,电力还没有输送到各个硬件上。
2. 第一步:时钟芯片上电
在接通电源之后,上电的第一个模块就是计算机中的时钟模块
。时钟模块
是一种特殊的电路,只要接通电源,电路就会发出高——低——高——低
的信号。
这个信号称为时钟信号
,主板上不同的芯片,只要检测时钟信号中的上升沿,就可以同步的进行操作,这样通过时钟信号就实现了让整个系统中的所有的电路同步运行。(计算机中的电路其实是异步时钟电路,这里主要是为了方便讲解)
时钟电路主要由时钟发生器(时钟芯片)、14.318MHz晶振、电容、电阻和电感等组成。当然,我们这里不需要知道时钟电路具体是如何实现的,我们这里需要明白的是,计算机中各个电路和硬件想要正常工作就需要先有时钟信号。所以接通电源之后第一个开始工作的模块就是时钟模块。
但是注意,时钟芯片上电只是表示时钟芯片准备好工作,正式开始工作,向各个硬件发出不同频率的信号还得等我们按下开机键
3. 第二步:开机电路工作
时钟电路上电之后,接下来开始工作的就是开机电路了。此时计算机中的其他硬件,例如显卡、内存什么的都还没有上电。
开机电路的主要功能,就是侦测我们是否按下了开机键,在我们按下了开机键之后,开机电路导通了,此后就开启了我们原先理解的开机流程。
3. 开机第二步:按下开机键
我们上面介绍了接通电源后,按下开机键之前计算机系统发生的事情。接下来我们讲解接通电源后、按下开机键之后发生的事情。
1. 第一步:系统自检
在我们按下了开机键后,当开机电路侦测到了我们按下开机键,这个时候主板就会接收到我们按下了开机键这个信号。
而主板在接收到按下开机键的信号后,会检查自己身上有没有短路、漏电的部分,如果有则会中断开启并且切断供电,没有则继续供电,继续开机流程。
在供电自检完成300~500毫秒后,电源会发出一个PowerGood
信号,时钟芯片在接收到这个信号后,就会开始工作,向主板上的各个部件发出不同频率的时钟信号。
2. 第二步:CPU上电复位
在时钟开始发出时钟信号后,接下来供电就会来到CPU
。CPU
获得供电后,干的第一件事情就是复位
CPU
复位的时候会初始化CS
、IP
寄存器,即将CS
、IP
的值设置为某一个特定的值。具体是怎么复位的,其实还是硬件电路实现的。类似于时钟电路能够发出时钟信号,CPU的复位电路能够将CS
、IP
设定为特定的值,
我们下面使用
bochs
来看看CPU
复位时CS
、IP
被设置成什么值了。从下面的两个图中,最后可以看到
CS:IP
的值被设置成了0xf000:0xfff0
,实模式下指向的物理地址就是0xffff0
3. 第三步:各个部件复位
其实在时钟芯片开始向各个部件输出时钟信号后,不仅仅是CPU
会初始化,主板上的各个部件也会开始初始化。我们上面是为了给后面开始运行操作系统铺垫,所以强调了CPU
的复位。
4. 第四步:运行BIOS程序
在主板上所有的硬件复位之后,CPU
此时就可以开始运行了。但是这个时候有一个问题,我们该运行那个程序?
因为我们现在的计算机都是冯·诺依曼模型。而冯诺依曼模型的计算机中,CPU
(运算器和控制器)只负责取指令、解释指令、运行指令而指令都是储存在内存(存储器)中的。
PS: 不要问CPU是如何取指、解释、执行的,因为那是硬件电路设计的事情。也不要问为什么冯诺依曼体系结构的计算机是
CPU
取指执行,指令存储在存储器。这个是冯诺依曼体系结构计算机的定义,你费尽千辛万苦,设计出来的硬件电路只要满足冯诺依曼体系结构的要求,那么你设计的计算机就是冯诺依曼体系结构计算机中的一种。
可是,内存在复位后,其中是没有任何指令的。换而言之,在复位后,内存中是没有任何程序的,那么这个时候CPU到底该运行那个程序呢?
所以,这个时候我们就需要在计算机中内置一套程序,这个程序的作用就是把其他的程序从磁盘读取到内存中,此时内存中就有了新的程序。最后该程序结束运行,并让CPU
去执行新的程序即可。
并且由于内存断电后其中的数据就没了,所以这个程序必须要在主板断电后依旧存在。这个程序就是BIOS
。关于BIOS我们后面再介绍。这里主要介绍开机流程。
上个世纪70年代,人们发明了一种称为ROM
(Read Only Memory
)的芯片,ROM
芯片和内存(RAM
芯片)一样,可以被CPU
读取,但是其中的数据在断电之后不会丢失,并且CPU
也不能向ROM
中写入数据。
那么计算机是把ROM
中的数据复制到内存RAM
中然后运行么?错了,让CPU
复制数据也是需要程序的,这个时候啥程序都没有,更别说复制了。所以这个时候内存映射IO
就来了。
内存映射IO
实际上我在之前的计算机基础知识里面有讲,想详细了解的可以去看看。内存映射IO
的基本意思就是把寻址空间的一部分映射到ROM中去,这样CPU
认为自己在访问内存的某个区域,实际上实在访问ROM
中的存储单元。
形象的理解,就是让
ROM
假装内存,然后让CPU
以读取内存的方式去读取ROM
中的指令
我们前面特地强调了CPU
复位,其中特地说到CPU
复位的时候会把CS
、IP
寄存器初始化为CS:IP=0xf000:0xfff0
,即指向0xffff0
这个物理地址,所以其实寻址空间中的0xffff0
这个地址,最后经过地址总线
翻译后,指向的就是ROM
。
所以这个时候,我们就可以开始运行ROM
中的BIOS
这个程序了。
既然BIOS
实在ROM中的,那么换而言之,我们开机的时候其实没有内存,也还是能够运行BIOS
这个程序的,毕竟ROM
这个程序是在主板上的。
当然,没有内存条的话,后面的操作系统也就没有办法运行了,所以计算机还是没有办法运行,但是此时检测到计算机中没有内存条而终止开机的就是BIOS
了。具体BIOS
是干什么的,我在另外一篇讲解BIOS
的文章里面有讲。
BIOS
这个程序已经存在快四五十年了,所以后来升级了一次,升级后的程序叫UEFI
,作用和BIOS
基本上是一样的
最后,BIOS
运行的最后,会在硬盘上寻找操作系统,找到了就会把操作系统从硬盘中读取到内存,而后就开始运行操作系统。
4. 开机第三步:运行操作系统
1. 第一步:加载BootLoader
其实BIOS
在运行的最后,在硬盘上会寻找、并且读取到内存的是一个称为BootLoader
的程序。这个程序是由开发操作系统的人提供的。
BootLoader
这个程序的作用就是负责从磁盘上读取操作系统,然后运行操作系统。
可是这个时候有人可能就会问,BIOS
为什么不能直接读取到操作系统然后运行操作系统呢?而非要读取、运行BootLoader
这个程序?
这其实是因为操作系统启动的代码很复杂,而BIOS
这个程序很小,没有办法胜任。而且不同的操作系统启动流程是不一样的。所以与其BIOS
来启动操作系统。倒不如让操作系统的编写者来自己写程序启动自己的程序,而BIOS
只需要去统一的读取BootLoader
到内存即可。
PS:所以如果想要自己写一个操作系统的话,那么出了系统本身,还得写一个
BootLoader
程序
程序从外存复制到内存的过程称为加载,因此操作系统运行的第一步就是BIOS
在外存中寻找到BootLoader
,而后开始把BootLoader
加载到内存中。
BIOS
会把BootLoader
读取到内存中的0x70c00
这个地方,而关于为什么会读取到这个地方,在讲解BIOS
的文章中会讲解。
BootLoader
为什么叫BootLoader
BootLoader程序本身是操作系统的一部分,运行它就能够运行操作系统,因此有点像操作系统自己把自己运行起来了。中文称这个为自举。但是英文里称为
Bootstarp
。
BootStarp
最早是来自一个谚语:pull oneself up by one’s bootstraps
字面意思就是“拽着鞋带自己把自己拉起来”,这当然是不可能的。工程师用这个来比喻操作系统启动是一个很矛盾的事情:必须先运行程序,然后才能启动计算机,但是不启动计算机就没法运行操作系统。
计算机的早期确实是这样,必须想尽办法办法把一小段程序塞入内存中,然后计算机才能正常运行,所以工程师把计算机开机的引导称为拉鞋带。计算机启动就简称为
Boot
了而启动操作系统的程序就称为
BootLoader
了
2. 第二步:运行操作系统
BIOS
中的最后一条指令,就是jmp 0000:0x7c00
,此时就会跳转到被加载到内存中的BootLoader
去运行。
计算机运行的最后一步就是运行操作系统,因为操作系统本身就是一个无限循环的程序。下面XV6
这个操作系统的main
函数的最后一个函数mpmain
里有一个while(1)
循环(其实就是Scheduler
)
至此,我们就完成了整个开机的开机的流程,计算机就一直运行操作系统了。直到我们关机。而后在下一次开机,又会重复上面开机的过程。