计算机的启动

前言

本文并非从本质上去讲解计算机的启动过程,而是站在汇编程序执行的角度去理解计算机在启动过程中是如何执行最底层的汇编程序的,并进一步了解这些汇编程序是从哪里来的。

注:本文内容以 x86 体系计算机为例

硬件

  1. CPU:负责读取和执行被加载(或映射)到内存中的指令或数据;
  2. ROM:只读存储器,存储在一个非易失芯片上,即在关机后内容仍然可以被保存。主要用来存储计算机启动的引导系统 BIOS(Basic Input/Output System);
  3. 内存:存储(或映射)正在执行的程序所编译好的指令或数据;
  4. 硬盘:存储数据或程序可执行文件;
  5. 其他硬件:显示器、显卡、键盘等等。

提前了解

想要完整的理解计算机启动过程需要有一定的前置知识积累,这里简单的罗列和解释了一些前置知识点。选择自己不熟悉的内容查看即可。

CPU 工作模式

CPU 在上电之后会反复重复两个动作:

  1. 从内存读取指令;
  2. 执行刚刚读取的指令。

注:当然具体工作原理要比这个复杂的多,这里仅是解释一下 CPU 简单的工作模式

ROM 中的 BIOS

只读存储器(Read Only Memory,ROM):是一种半导体存储器,其特性是一旦存储资料就无法再将之改变或删除,且内容不会因为电源关闭而消失。正是由于这种特性 ROM 被用在在计算机中存储启动引导程序。

基本输入输出系统(Basic Input/Output System,BIOS),也成为 ROM BIOS、System BIOS、PC BIOS,是在计算机通电引导阶段运行硬件初始化以及为操作系统提供运行时服务的固件。BIOS 预安装在计算机的主板上是计算机启动时加载的第一个软件。

注:这边讲的都是一个大概,并非具体细节,如果想了解具体细节的话可以自己搜索资料深入了解。

寻址空间、寻址、物理地址、逻辑地址

寻址空间(最大内存容量)

寻址空间一般指的是 CPU 对于内存的寻址能力,通俗来说就是 CPU 可以最多可以支持多大的内存容量,以字节为单位。寻址空间的大小由地址总线的地址寄存器宽度(位数)决定,假设地址总线位数为 N 位,则寻址空间为 2 的 N 次方字节(因为计算机使用的是二进制所以是 2 的 N 次方)。

小知识
目前(2015年5月),Intel 的 32位架构下,可使用的地址线是 36个,可使用的最大物理地址是 2^36B,折合 64GB,可用的地址空间是 4GB。
64位架构下,地址线是 46个,所以最大的物理地址是 2^46B,折合 64TB,可用地址空间也是这么大(目前为止)

知乎:北极就「32位系统只能寻址4G空间,64位则是128G,这些是怎么算出来的?
」这一问题的回答节选

寻址

内存中每一个字节都有一个对应的内存地址,CPU 去访问某一具体内存地址的过程称为寻址。

物理地址

CPU 地址总线传来的地址,大部分是留给内存对应了内存的内存地址,但也常被映射到其他存储器上(如显存、BIOS 等)。

逻辑地址

为了方便编程,进一步的将内存划分成不同的段,在这种模式下内存地址的表达形式为:段地址:偏移地址,逻辑地址仅在汇编编程的过程中使用,在汇编程序经过编译之后逻辑地址会转化成物理地址。

所以,无论是物理地址还是逻辑地址都是指的内存地址,只是两种不同的表达方式,逻辑地址的出现也只是为了方便编程。

I/O、MMIO

I/O

I/O 为 Input & Output 的简写,这里指的是 I/O 设备。

所谓 I/O 设备指的是计算机的输入和输出设备,常见的有:
输出设备:显示器、打印机;
输入设备:键盘、鼠标。

而控制这些 I/O 设备的原理其实就是控制设备内部寄存器的读写,这些 I/O 设备的寄存器被称为 I/O 端口,通常包括:控制寄存器、状态寄存器和数据寄存器三大类。

MMIO

内存映射 I/O(Memory mapping I/O,MMIO),通过将 I/O 端口映射到内存空间便于 CPU 访,在映射之后就可以实现 CPU 通过操控内存间接控制 I/O 设备,这样访问 AGP/PCI-E 显卡上的帧缓存、BIOS、PCI 设备等就可以使用读写内存一样的汇编指令完成,简化了程序设计的难度和接口的复杂性。

从按下开关键那一刻开始

上电

在按下开机键之后,电源开始向计算机主板和其他设备供电,在芯片组检测到电源稳定供电后(一瞬间的事情)CPU 开始工作(即读取和执行指令)。

读取 BIOS

注:这里涉及到一些汇编基础,我就不过多解释了

在刚开机初始阶段计算机内存中是没有任何内容的,此时 CPU 通过读取 CS 和 IP 寄存器的内容来获取自己需要执行的指令,而此时寄存器 CS 存储内容为 0xFFFF,寄存器 IP 存储内容为 0x0000,即计算机会从 0xFFFF:0x0000(实际对应地址为:0xFFFF0)开始读取并执行指令。0xFFFF0 正是 ROM 中 BIOS 经过 MMIO 后所对应的内存地址。

即计算机在开机初始阶段会先读取 BIOS 中内置的程序指令,而 BIOS 内置程序指令主要完成了一下工作:

  1. 硬件自检(Power-On Self-Test, POST):查看计算机硬件能否满足运行的基本条件
  2. 启动顺序(Boot Sequence):程序读取启动顺序表,按照内容依次尝试并在成功后停止继续尝试

主引导扇区

主引导扇区(Main Boot Sector,MBR):硬盘的第 0 扇面、第 0 磁道、第 1 扇区。

这里我们假设我们设置的启动顺序第一位是硬盘并且硬盘实际存在,BIOS 程序会硬盘的主引导扇区读入物理地址为 0x07C00 起始的内存区域并继续执行其中内容。

为什么是 0x07C00?貌似是历史原因,没什么特别之处,可以自己去百度了解一下。

主引导扇区共 512字节,只有在这 512字节的最后两个字节为 0x55 和 0xAA 时才能被用于计算机启动,如果不是就表明此硬盘不可用于计算机启动,BIOS 则会继续读取启动顺序中记录的下一个设备。

正常情况下这 512字节的主要作用为:

  1. 1-446字节:调用操作系统的机器码
  2. 447-510字节:分区表(Partition table)
  3. 511-512字节:主引导扇区签名(0x55AA)

分区表

分区表的长度为 64字节,具体分为四项,每项 16字节。所以,一个硬盘最多可分为四个一级分区,又叫做「主分区」,每个主分区的 16字节由 6 部分组成:

  1. 第 1字节:如果是 0x80,标识主分区是激活分区,控制权要转交给这个分区(四个主分区里只能有一个是激活的);
  2. 第 2-4 字节:主分区第一个扇区的物理位置(柱面,磁头、扇区号等);
  3. 第 5字节:主分区类型;
  4. 第 6-8字节:主分区最后一个扇区的物理位置;
  5. 第 9-12字节:主分区的第一个扇区的物理位置;
  6. 第 13-16字节:主分区的扇区总数。

分出主分区后其余部分可以分成拓展分区,一般是剩下的部分全部分成拓展分区,也可以不全分,但剩下的部分就浪费了。拓展分区不能直接使用,必须分成若干逻辑分区,所有逻辑分区都是拓展分区的一部分。

磁盘的容量 = 主分区容量 + 拓展分区容量 + 空闲分区容量
拓展分区容量 = 各个逻辑分区容量之和 + 空闲分区容量

硬盘启动

卷引导记录

如果操作系统安装在激活的主分区中,计算机会读取激活分区的第一个扇区,叫做「卷引导记录(Volume Boot Record,VBR)」。

卷引导记录负责告诉计算机操作系统在这个分区的具体位置,然后计算机就会加载操作系统完成开机行为。

拓展分区和逻辑分区

我们一般不将操作系统安装在拓展分区或逻辑分区中,如果有这种情况一般也采用下面一种启动方式。

启动管理器

在这种情况下,计算机读取主引导扇区的前 446字节后不再将控制权转交给某一个分区,而是运行事先安装好的启动管理器(Boor Loader),由用户选择具体启动哪一个操作系统。

操作系统

进行完前面的流程后,进入操作系统启动流程,本文对这一部分不作出详细介绍,如果感兴趣的话可以自己百度搜索。

参考

  1. 百度百科:寻址空间
  2. 知乎:北极回答
  3. 百度百科:地址总线
  4. CSDN-JeanChen:深入理解计算机系统……
  5. CSDN-颇锐克:逻辑地址、线性地址和物理地址的关系
  6. CSDN-langb2014:IO端口和IO内存的区别及分别使用的函数接口
  7. MCU 中文技术社区-judy:详解io端口与io内存
  8. 知乎-围城:内存映射IO (MMIO) 简介
  9. 百度知道-笑脸蓝雨:电脑的开机原理是什么?
  10. 思维之际:计算机加电后操作系统启动过程
  11. 阮一峰的网络日志:计算机是如何启动的?
  12. Adam’s blog:计算机启动过程