数字营销 · Web开发 · 基础设施

计算机是如何启动的?

从 CPU 复位、ROM、BIOS 和 MBR 出发,逐步分析传统 x86 计算机的启动过程,并通过自己编写一个简单的 MBR,理解计算机从按下电源键到启动操作系统之间发生了什么。

相信很多人和我一样,从接触计算机开始,就一直在思考这个问题:当按下电脑的开机键之后,到底发生了什么?为什么这样就能启动电脑?

这篇文章我试着分析一下计算机的启动原理和过程

计算机起动流程

CPU

CPU 全称是中央处理器,是计算机的核心部件之一,包括控制单元、运算单元、寄存器以及时钟等部分,它的主要功能是执行计算机指令以及处理各种数据,包括进行基本的算术运算,以及从存储器或者各种接口设备中读取、写入数据。

CPU 内部包含若干个寄存器,用来暂存数据或者控制 CPU 的运行。以早期的 8086 为例,常见的寄存器有 AX、BX、CX、DX、CS、DS、SS、ES、DI、SI、SP、BP、IP、FLAGS 等。

我们都知道,计算机最终执行的是二进制形式的机器指令。例如某条机器指令可以表示将一个值加载到寄存器 AX 中。由于直接阅读二进制指令非常困难,因此人们发明了汇编语言。

例如,用 Intel 语法表示:

mov ax, 0

存储器

存储器就是我们通常所说的内存。CPU 是计算机的核心,但没有存储器也是无法工作的,因为 CPU 需要执行的指令和处理的数据都需要有地方存放。

CPU 通过地址总线、数据总线和控制总线与存储器进行连接,从而可以从指定的内存地址读取或者写入数据。

上课的时候,老师经常会告诉我们,内存属于易失性存储器(RAM),必须保持供电才能保存其中的数据,断电之后数据就会丢失。

于是这里就产生了一个问题:

既然内存断电之后没有数据,而 CPU 又不能凭空产生指令,那么计算机刚开机的时候,CPU 到底从哪里获得第一条指令?

答案就是非易失性存储器

非易失性存储器

说到非易失性存储器,我们可能首先想到 U 盘、硬盘或者光盘等设备。它们都可以在断电之后保留数据。

除此之外,还有一类非常重要的非易失性存储器——ROM。

ROM 断电之后仍然可以保存其中的数据,因此早期计算机通常利用 ROM 保存一些必须长期存在的程序。

计算机中的很多设备都包含 ROM,例如显卡,而在传统 PC 中,主板上的 ROM 通常用于保存 BIOS(基本输入输出系统)。

ROM 同样属于存储器的一种,CPU 可以直接读取其中的数据。不同的是,传统意义上的 ROM 不能像普通 RAM 一样随意写入数据。

计算机的启动

说到这里,问题似乎就容易理解了:

只要事先把一段启动程序写入 ROM,计算机通电以后,让 CPU 从 ROM 中执行这段程序,不就可以启动了吗?

实际上,早期 x86 PC 的启动过程正是建立在这样的机制之上。

以传统的 BIOS 和 x86 实模式启动过程为例,大致可以分成下面几个阶段:

  1. 按下电源键之后,主板完成基本的供电和初始化。CPU 复位后,会从预先规定的地址开始取指令。
  2. 在 8086 的实模式下,CPU 复位后 CS=0xFFFFIP=0x0000,因此形成的物理地址为 0xFFFF0。这个地址对应主板上的 ROM 区域。
  3. 0xFFFF0 处通常是一条跳转指令,用来跳转到 BIOS 中真正的初始化代码。
  4. BIOS 开始执行加电自检(POST),检查 CPU、内存、键盘、显卡等基本硬件是否能够正常工作。
  5. 完成基本硬件检查后,BIOS 按照启动顺序寻找可启动设备。
  6. 找到启动设备后,BIOS 将设备的第一个扇区读取到内存 0x7C00,然后把执行权交给这段代码。

这里需要注意,POST 完成并不意味着操作系统已经启动。这只是 BIOS 完成了硬件初始化和基本检查,接下来还需要加载操作系统的启动程序。

MBR

在传统 BIOS 启动方式中,BIOS 会按照设置好的启动顺序检查硬盘、U 盘或者光盘等设备。

以传统硬盘 MBR 启动方式为例,BIOS 会读取启动设备的第一个扇区,也就是前 512 字节的内容,并检查其最后两个字节是否为:

0x55 0xAA

如果存在这个签名,BIOS 就认为这是一个有效的启动扇区,并将其加载到内存 0x7C00,然后从这里开始执行。

启动设备的第一个扇区就是我们常说的 MBR(Master Boot Record,主引导记录)。传统 MBR 中除了启动代码之外,还包含分区表以及最后的 0x55AA 启动签名。

MBR 的主要任务之一就是继续加载更完整的引导程序,然后由引导程序进一步加载操作系统。

所以整个启动过程可以简单理解为:

CPU复位

执行ROM中的BIOS代码

POST硬件自检

寻找启动设备

读取启动扇区到0x7C00

执行MBR/启动代码

加载操作系统引导程序

加载操作系统

更详细的启动流程,请看下图:

启动流程

综上,计算机启动过程中有几个关键点:

  1. ROM 中预先保存了最初的启动程序;
  2. CPU 复位之后,会从一个预先规定的位置开始执行指令;
  3. BIOS 完成最基本的硬件初始化之后,会寻找可启动设备;
  4. 启动设备上的 MBR 或启动扇区负责继续加载后面的启动程序;
  5. 最终由引导程序加载操作系统。

对于我们来说,CPU 和最初的固件已经由硬件系统确定,真正有意思的部分则是启动设备上的第一段代码到底是如何工作的

下面我们自己完成一个简单的 MBR,不依赖操作系统,在计算机启动时直接显示:

Welcome to https://www.hitoy.org/

DISADDR  EQU 0xb800
DISCOLOR EQU 0x02
LOADADDR EQU 0x7c00

section .code vstart=LOADADDR

_start:
; 注意:实模式下不能直接设置 CS
; mov ax,LOADADDR
; mov cs,ax

; data addr
mov ax,string
mov si,ax

; display segment
mov ax,DISADDR
mov ds,ax
mov bx,0

show:
; Copy Char to CL
mov cl,[cs:si]
mov ch,0

cmp cx,0
je end

mov ch,DISCOLOR
mov [ds:bx],cx

inc si
add bx,2

jmp show

end:
jmp $

string:
db "Welcome to https://www.hitoy.org/",0

times 510-($-$$) db 0
db 0x55,0xaa

这里最后的:

times 510-($-$$) db 0
db 0x55,0xaa

就是把整个启动代码填充到 512 字节,并在最后两个字节写入传统 MBR 的启动签名。

使用 NASM 编译成 bin 格式文件,再将其写入启动设备的第一个扇区,启动计算机之后,就可以直接看到我们自己编写的文字。

用MBR开机显示文字

从这个实验可以看到,计算机启动并没有什么神秘之处。最开始只是 CPU 从一个固定的位置开始执行指令,然后一级一级地把控制权交给后面的程序,最终由引导程序把操作系统加载起来。

评论1

欢迎分享你的看法,也欢迎补充不同的实践经验。

看了标题我第一个想到的是boot!boot原来的意思是靴子,“启动”与靴子有什么关系呢?原来,这里的boot是bootstrap(鞋带)的缩写,它来自一句谚语:"pull oneself up by one’s bootstraps"字面意思是“拽着鞋带把自己拉起来”,这当然是不可能的事情。最早的时候,工程师们用它来比喻,计算机启动是一个很矛盾的过程:必须先运行程序,然后计算机才能启动,但是计算机不启动就无法运行程序!久而久之就简称为boot了。