计算机启动过程详解


首先用一张图来大致了解一下计算机启动的整个过程。
在这里插入图片描述

boot的含义

先问一个问题,"启动"用英语怎么说?

回答是boot。可是,boot原来的意思是鞋子背带,"启动"与鞋子背带有什么关系呢? 原来,这里的boot是bootstrap(鞋子背带)的缩写,它来自一句谚语:

"pull oneself up by one's bootstraps"

在这里隐喻表示一种不需要外部帮助自己能够处理事情的情形。
pull oneself up by one’s bootstraps”最初来自于《The Surprising Adventures of Baron Munchausen》这本书里的一个故事:主人公Baron Munchausen不小心掉进了一片沼泽,他通过自己的bootstraps将自己拉了出来(当然有童话神奇的色彩)。事实上在19世纪初美国就有"pull oneself over a fence by one’s bootstraps"的语言,意思是“做荒谬不可能完成的事情”。
参考:http://en.wikipedia.org/wiki/Bootstrapping
字面意思是"拽着鞋带把自己拉起来",这当然是不可能的事情。最早的时候,工程师们用它来比喻,计算机启动是一个很矛盾的过程:必须先运行程序,然后计算机才能启动,但是计算机不启动就无法运行程序!
早期真的是这样,必须想尽各种办法,把一小段程序装进内存,然后计算机才能正常运行。所以,工程师们把这个过程叫做"拉鞋带",久而久之就简称为boot了。

计算机的整个启动过程分成四个阶段。

上电

按下主机的电源键后,计算机开始启动,主板上电后开始初始化其固件(firmware)。固件是一些固化在芯片组上的程序,它会试图去启动 CPU。如果启动失败(例如 CPU 坏了或没插好),计算机就会死机并给出错误提示(如某些版本的主板固件会发出蜂鸣警告)。这种状态称为 “zoombie-with-fans”

如果前一个阶段未出错,就开始加电工作,在多 CPU 或多核 CPU 情况下,某一个 CPU 会被随机选取作为启动 CPU(bootstrap processor,BSP)运行 BIOS 内部的程序。其余的 CPU(application processor,AP)保持停机直到操作系统内核显式地使用它们。

2000 年以前的计算机主板上均使用 BIOS,如今绝大多数计算机采用的是 EFI(Mac 用的就是 EFI)或 UEFI,BIOS 正在逐步被淘汰。基于 EFI、UEFI 的开机过程与传统的BIOS不尽相同,本文将以传统的 BIOS,Intel CPU 为例介绍开机过程。

此时 CPU 工作模式为实模式,该模式下地址总线是 20 位,寻址范围是 0x00000~0xFFFFF 的 1M 范围。这也就解释了为什么 BIOS 的容量只有 1MB。

Intel CPU 用三种运行模式: 实模式、32 位保护模式、64 位保护模式。实模式: Intel 8086 的寻址方案,为了商业连续性,兼容了这古老的方案;保护模式: 采用了虚实地址转换方案。

BIOS 启动之初,内存是空的。此时 CPU 处于实模式,内存的地址映射均为硬连接的设备。内存映射图如下图所示:
在这里插入图片描述

重置向量

CPU 启动后其大多数寄存器会被初始化为预定的值,包括指令寄存器(Instruction register,IR),它保存着 CPU 将要执行指令的内存地址。此时 CPU 会有一个特殊行为,其会对 IR 的初始值加上一个基址寄存器的值,生成一个 32 位的地址 0xFFFFFFF0。之所以称为特殊行为,是因为实模式下 CPU 只能寻址 1MB 地址空间,而这个 32 位地址已经大于 1MB 的内存限制。因此,0xFFFFFFF0 也被称为重置向量(reset vector),参考上图 0xFFFFFFF0 处的标识。

于是,CPU 开始执行 0xFFFFFFF0 地址处的指令,该地址处是一条 JUMP 指令,这条指令清空了基址寄存器的值,并让指令跳回到 BIOS 开始处(物理地址为 0xF0000,参考上图 0xF0000 处的标识)以执行 BIOS。

BIOS 内部可以分成两个区块: code block(普通程序)、boot block(引导程序)。上电后,boot block 会先被执行,它会检查 code block 的代码是否正确,如果正确,就会转到 code block 继续执行下去。

BIOS 初始化

0xF0000 地址实际上是 BIOS 中的 boot block 的开始处。在这个阶段,会初始化部分硬件。系统的 CPU、USB 只有部分被初始化。

BIOS POST(加电自检)

初始化完成后,CPU 跳转到 0xA0000 地址处(参考上图 640KB 处)进行 BIOS 加电自检(power on self test, POST)。这个过程会检查计算机的各项组件,如 CPU、显卡、内存、鼠标、键盘等。如果找不到内存或者键盘都有可能让BIOS停止工作并且打印一些相关的错误信息,如果找不到显卡 BIOS 会发出蜂鸣警告
当 CPU 执行到 0xC0000 地址处(参考上图 768KB 处),开始寻找其他设备的 ROM,如果找到任何其他设备的 BIOS,它们也会被执行。
下一步,显卡就会显示 BIOS 界面,并进行更深入的检查。

BIOS 记录系统设定值

检查完成后,BIOS 会根据自己的“系统资源表”,对系统进行进一步确认,从而确定计算机配有哪些资源或设备。例如 BIOS 支持随插即用,它会检测并配置随插即用设备。
然后 BIOS 会遵循高级配置电源接口(Advanced Configuration Power Interface,ACPI)在内存中设置好一系列的数据来描述硬件信息,以便被操作系统内核利用。

搜索 MBR

到这一步,BIOS 开始尝试加载操作系统。它会从硬盘,光驱,软驱,网络等几个地方依次寻找操作系统(用户可以在 BIOS 设定中修改查找的优先级)。如果找不到操作系统,BIOS 会停机并给出错误信息。

假设在硬盘上找到了操作系统,它会首先读取硬盘上的大小为 512 Bytes 的 0号扇区,这个扇区被称为 主引导记录(master boot record,MBR),其包含三部分:

  • 引导程序(Boot Loader)
  • 硬盘分区表(Partition Table)
  • 结束标志字
    BIOS 读完磁盘上的 MBR 之后会把它拷贝到内存 0x7C00 地址处,然后 CPU 跳转到该内存地址执行 MBR 里的指令。事实上,被复制到物理内存的内容就是 Boot Loader。常见的 Boot Loader 有 grub、lilo、spfdisk。下图可以帮助大家理解 MBR 的结构。

关于磁盘、分区表等基础知识,可参见 详解计算机磁盘系统

硬盘启动

这时,计算机的控制权就要转交给硬盘的某个分区了,这里又分成三种情况。

情况A:卷引导记录

上一节提到,四个主分区里面,只有一个是激活的。计算机会读取激活分区的第一个扇区,叫做"卷引导记录"(Volume boot record,缩写为VBR)。

"卷引导记录"的主要作用是,告诉计算机,操作系统在这个分区里的位置。然后,计算机就会加载操作系统了。

情况B:扩展分区和逻辑分区

随着硬盘越来越大,四个主分区已经不够了,需要更多的分区。但是,分区表只有四项,因此规定有且仅有一个区可以被定义成"扩展分区"(Extended partition)。

所谓"扩展分区",就是指这个区里面又分成多个区。这种分区里面的分区,就叫做"逻辑分区"(logical partition)。

计算机先读取扩展分区的第一个扇区,叫做"扩展引导记录"(Extended boot record,缩写为EBR)。它里面也包含一张64字节的分区表,但是最多只有两项(也就是两个逻辑分区)。

计算机接着读取第二个逻辑分区的第一个扇区,再从里面的分区表中找到第三个逻辑分区的位置,以此类推,直到某个逻辑分区的分区表只包含它自身为止(即只有一个分区项)。因此,扩展分区可以包含无数个逻辑分区。

但是,似乎很少通过这种方式启动操作系统。如果操作系统确实安装在扩展分区,一般采用下一种方式启动。

情况C:启动管理器

在这种情况下,计算机读取"主引导记录"前面446字节的机器码之后,不再把控制权转交给某一个分区,而是运行事先安装的"启动管理器"(boot loader),由用户选择启动哪一个操作系统。

操作系统

控制权转交给操作系统后,操作系统的内核首先被载入内存。

以Linux系统为例,先载入/boot目录下面的kernel。内核加载成功后,第一个运行的程序是/sbin/init。它根据配置文件(Debian系统是/etc/initab)产生init进程。这是Linux启动后的第一个进程,pid进程编号为1,其他进程都是它的后代。

然后,init线程加载系统的各个模块,比如窗口程序和网络程序,直至执行/bin/login程序,跳出登录界面,等待用户输入用户名和密码。
至此,全部启动过程完成。

举例说明

Boot Loader 执行

以常见的 Linux Boot Loader —— grub 为例。

Grub 加载后首先进行 内存盘初始化。Boot Loader 会将存储介质中的 initrd 文件加载到内存,内核启动时会在访问真正的根文件系统之前先访问内存中的 initrd 文件系统。

关于 initrd

Linux 内核需要适应多种不同的硬件架构,但是将所有的硬件驱动编入内核是不切实际的,而且内核也不可能每新出一种硬件结构,就将该硬件的设备驱动写入内核。实际上,Linux 的内核镜像仅包含了基本的硬件驱动,在系统安装过程中检测系统的硬件信息,根据安装信息和系统硬件信息将一部分设备驱动写入 initrd(bootloader initialized RAM disk。

内存盘初始化完毕之后, grub 会根据配置文件 /boot/grub/grub.cfg 设定的内核镜像 vmlinuz 所在的路径,加载内核镜像,并进行解压缩操作。此时,屏幕一般会出现 “Uncompressing Linux” 的提示。当解压缩内核完成后,屏幕一般会输出 “OK, booting the kernel”。

内核加载至内存完成后,grub 将控制权转交给内核。

内核启动

在 Boot Loader 配置了 initrd 的情况下,内核启动被分成了两个阶段:

执行 initrd 的文件系统中的 init 脚本。此阶段,内核会将控制权交给 init 文件处理。init 主要是加载各种存储介质相关的设备驱动。当所需的驱动程序加载完毕,就会创建一个根设备,然后将根文件系统 rootfs 以只读的方式挂载。这一步完成后,释放未使用的内存,并转换到真正的根文件系统中,进行第 2 阶段的处理。
执行真正的根文件系统中的 /sbin/init 进程,即系统的 1 号进程。此后,系统的控制权就全权交给 /sbin/init 进程了。
系统初始化
/sbin/init 进程是系统其它所有进程的父进程,当它接管了系统控制权后,它会根据 /etc/inittab 文件来执行相应的脚本,从而完成一系列的系统初始化操作。主要包括以下步骤:

  1. 设置运行等级。Linux 有运行等级如下:
- 0:关机
- 1:单用户模式
- 2:无网络支持的多用户模式
- 3:有网络支持的多用户模式
- 4:保留,未使用
- 5:有网络支持、有 X-Window 支持的多用户模式
- 6:重新引导系统,即重启
  1. 执行 rc.sysinit。运行等级设置完成后,Linux 系统执行的第一个用户层文件是 /etc/rc.d/rc.sysinit 脚本程序,其完成的初始化操作主要包括:设置 PATH、设置网络配置/etc/sysconfig/network、启动 swap 分区、设置 /proc 等。
  2. 执行不同运行级别的脚本程序。根据运行级别的不同,系统会运行 rc0.d ~ rc6.d 中对应的脚本,从而完成对应的初始化工作,启动对应的服务。
  3. 执行 /etc/rc.d/rc.localrc.local 是 Linux 运行用户进行个性化设置的脚本。
  4. 执行 /bin/login。进入登录状态。此时,系统已经进入到等待用户输入 usernamepassword 的阶段。

看看百度知道上面的回答

第一步: 当我们按下电源开关时,电源就开始向主板和其它设备供电,此时电压还不太稳定,主板上的控制芯片组会向CPU发出并保持一个RESET(重置)信号,让CPU内部自动恢复到初始状态,但CPU在此刻不会马上执行指令。当芯片组检测到电源已经开始稳定供电了(当然从不稳定到稳定的过程只是一瞬间的事情),它便撤去RESET信号(如果是手工按下计算机面板上的Reset按钮来重启机器,那么松开该按钮时芯片组就会撤去RESET信号),CPU马上就从地址FFFF0H处开始执行指令,从前面的介绍可知,这个地址实际上在系统BIOS的地址范围内,无论是Award BIOS还是AMI BIOS,放在这里的只是一条跳转指令,跳到系统BIOS中真正的启动代码处。
第二步: 系统BIOS的启动代码首先要做的事情就是进行POST(Power-On Self Test,加电后自检),POST的主要任务是检测系统中一些关键设备是否存在和能否正常工作,例如内存和显卡等设备。由于POST是最早进行的检测过程,此时显卡还没有初始化,如果系统BIOS在进行POST的过程中发现了一些致命错误,例如没有找到内存或者内存有问题(此时只会检查640K常规内存),那么系统BIOS就会直接控制喇叭发声来报告错误,声音的长短和次数代表了错误的类型。在正常情况下,POST过程进行得非常快,我们几乎无法感觉到它的存在,POST结束之后就会调用其它代码来进行更完整的硬件检测。
第三步: 接下来系统BIOS将查找显卡的BIOS,前面说过,存放显卡BIOS的ROM芯片的起始地址通常设在C0000H处,系统BIOS在这个地方找到显卡BIOS之后就调用它的初始化代码,由显卡BIOS来初始化显卡,此时多数显卡都会在屏幕上显示出一些初始化信息,介绍生产厂商、图形芯片类型等内容,不过这个画面几乎是一闪而过。系统BIOS接着会查找其它设备的BIOS程序,找到之后同样要调用这些BIOS内部的初始化代码来初始化相关的设备。
第四步: 查找完所有其它设备的BIOS之后,系统BIOS将显示出它自己的启动画面,其中包括有系统BIOS的类型、序列号和版本号等内容。
第五步: 接着系统BIOS将检测和显示CPU的类型和工作频率,然后开始测试所有的RAM,并同时在屏幕上显示内存测试的进度,我们可以在CMOS设置中自行决定使用简单耗时少或者详细耗时多的测试方式。
第六步: 内存测试通过之后,系统BIOS将开始检测系统中安装的一些标准硬件设备,包括硬盘、CD-ROM、串口、并口、软驱等设备,另外绝大多数较新版本的系统BIOS在这一过程中还要自动检测和设置内存的定时参数、硬盘参数和访问模式等。
第七步: 标准设备检测完毕后,系统BIOS内部的支持即插即用的代码将开始检测和配置系统中安装的即插即用设备,每找到一个设备之后,系统BIOS都会在屏幕上显示出设备的名称和型号等信息,同时为该设备分配中断、DMA通道和I/O端口等资源。
第八步: 到这一步为止,所有硬件都已经检测配置完毕了,多数系统BIOS会重新清屏并在屏幕上方显示出一个表格,其中概略地列出了系统中安装的各种标准硬件设备,以及它们使用的资源和一些相关工作.
第九步: 接下来系统BIOS将更新ESCD(Extended System Configuration Data,扩展系统配置数据)。ESCD是系统BIOS用来与操作系统交换硬件配置信息的一种手段,这些数据被存放在CMOS(一小块特殊的RAM,由主板上的电池来供电)之中。通常ESCD数据只在系统硬件配置发生改变后才会更新,所以不是每次启动机器时我们都能够看到“Update ESCD… Success”这样的信息,不过,某些主板的系统BIOS在保存ESCD数据时使用了与Windows 9x不相同的数据格式,于是Windows 9x在它自己的启动过程中会把ESCD数据修改成自己的格式,但在下一次启动机器时,即使硬件配置没有发生改变,系统BIOS也会把ESCD的数据格式改回来,如此循环,将会导致在每次启动机器时,系统BIOS都要更新一遍ESCD,这就是为什么有些机器在每次启动时都会显示出相关信息的原因。
第十步: ESCD更新完毕后,系统BIOS的启动代码将进行它的最后一项工作,即根据用户指定的启动顺序从软盘、硬盘或光驱启动。以从C盘启动为例,系统BIOS将读取并执行硬盘上的主引导记录,主引导记录接着从分区表中找到第一个活动分区,然后读取并执行这个活动分区的分区引导记录,而分区引导记录将负责读取并执行IO.SYS,这是DOS和Windows 9x最基本的系统文件。Windows 9x的IO.SYS首先要初始化一些重要的系统数据,然后就显示出我们熟悉的蓝天白云,在这幅画面之下,Windows将继续进行DOS部分和GUI(图形用户界面)部分的引导和初始化工作。
如果系统之中安装有引导多种操作系统的工具软件,通常主引导记录将被替换成该软件的引导代码,这些代码将允许用户选择一种操作系统,然后读取并执行该操作系统的基本引导代码(DOS和Windows的基本引导代码就是分区引导记录)。 上面介绍的便是计算机在打开电源开关(或按Reset键)进行冷启动时所要完成的各种初始化工作,如果我们在DOS下按Ctrl+Alt+Del组合键(或从Windows中选择重新启动计算机)来进行热启动,那么POST过程将被跳过去,直接从第三步开始,另外第五步的检测CPU和内存测试也不会再进行。我们可以看到,无论是冷启动还是热启动,系统BIOS都一次又一次地重复进行着这些我们平时并不太注意的事情,然而正是这些单调的硬件检测步骤为我们能够正常使用电脑提供了基础。
现在市场上主流的品牌机随机安装的操作系统一般为Windows XP,但是,部分用户可能仍然对Windows 98、Windows ME或Windows 2000等操作系统情有独钟,希望能在不破坏原操作系统的前提下,再安装一下以上操作系统。按常规来说,如不使用第三方的软件,我们在安装微软的Windows系列操作系统时,应该按照从低版本到高版本的顺序来依次安装;如果使用第三方的软件,又会涉及到所使用的软件的版权及用法问题,对一般用户来说显然是不太合适的。其实,按我们在本文提供的方法,不使用第三方的任何软件也能实现操作系统反着装,而且十分简单!

注意:

bios不一定存在,bios只是提供了一个固定的方式,去访问其他输入输出设备,存在的目的是可以将硬件的变化简化,这样内核就可以通过和固定的bios通信来获取基本的硬件地址信息,然后再获得更充分的硬件地址信息。没有bios的计算机,就没有这么一个固定的方式,随着硬件的改变,就要静态的改变内核内部设备的入口地址,然后重新编译。可以这么说bios是使得现在操作系统变得通用的一个利器。比如现在不同的arm手机的内核不能随便换着用,而有bios的计算机内核即使硬件不那么一样,却可以用同样的内核。还比如现在很多时候都会将硬件地址的map独立于内核写到一个单独的文件中,内核载入的时候会从这些文件中读取硬件的入口地址。
从上电开始,处理器的指令计数器会被初始化成一个值(这个值不一定是0x0000H,因为一般还会在前面放中断向量表),然后从这个地址开始执行程序。这些程序有可能放到片内的flash,有可能放到片外的flash,或是RAM里面。由于RAM是掉电易失的,所以可能需要先从其他存储设备中载入内存然后再从内存中调入片内进行运算。

参考:

https://www.youtube.com/watch?v=ois-Ilfh5xg相信看完这个视频会有不一样的收获!!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值