操作系统启动过程

 Max.C     2020-02-15   8071 words    & views

操作系统启动过程

零、操作系统

计算机由一系列硬件组成,而为了让计算机实现某种功能,我们需要软件作为用户与计算机硬件的桥梁,让用户操控计算机硬件,完成必要的工作。

那么,总有这么一款软件需要起着承上启下的作用,它需要直接来操作硬件,与此同时,承载着在其之上的软件。换句话说,它要为别的软件提供一个平台,它自己来操作计算机硬件,然后别的软件来操作它

并且,还要有一个理念,那就是让其他软件具有高度可移植性,操作具体硬件的工作在不同体系的计算机上实现的方式是不同的,但是这款软件却可以把它们统一起来,提供一个相对应的接口,之后,所有的软件都基于这个软件所提供的接口上进行设计,也就可以让同一款软件间接地操控不同体系的计算机

而这样的软件,就被称为操作系统内核(OS Core),它可以直接驱动计算机硬件,而基于操作系统内核之上开发出的软件就叫做应用软件。

一些常用的应用软件和通用设备的驱动软件就应当与操作系统内核集成在一起,形成一套成熟的用户交互平台,这就有了我们今天的操作系统(Operating System)。

而操作计算机硬件,其核心为操作计算机CPU和内存。内存一般是与CPU相匹配的,因此我们决定操作系统架构的主导因素就是CPU。CPU的硬件设计理念决定了其硬件的工作方式,硬件的工作方式决定了它支持哪些微命令(直接操作硬件的逻辑指令),而支持的微命令决定了它的指令集。

目前主流的CPU指令集有RISC和SISC,由于SISC诞生时间较早,应用较广泛,所以也较为基础。目前90%以上的桌面端计算机都使用的是SISC指令集,而SISC指令集中最具有影响力的就属Intel x86架构了。x86架构指的是Intel 80386上所使用的架构,Intel 80386是一款32位处理器。现在大多数的计算机都是x86或x64架构的,而x64架构是兼容x86架构的,所以我们进行实验会比较方便。

那么,从计算机硬件本身到启动操作系统的过程又是如何实现,接下来开始探讨:

当我们启动计算机时,电源就开始向设备供电,此时电压还不太稳定。CPU首先进行初始化,当芯片组检测到电源已经开始稳定供电了,CPU马上就从初始化的位置开始执行指令,执行的指令地址保存在寄存器中。

以8086CPU为例,寄存器CS和IP用于保存CPU接下来需要执行的指令地址,CPU会开始执行该位置的指令。

在计算机刚启动时,CS和IP会被初始化成固定的默认值,这个位置被固化了BIOS系统,即计算机启动时会默认开始加载BIOS到内存中并开始执行。此时,硬件的状态是完全暴露出来的,我们的任何行为都是直接对硬件进行操作的,所以此时的计算机是实模式运行,在实模式下我们操作的内存地址就是内存实际的物理地址。

上述对操作系统概念的介绍来自博客:发生在操作系统之前的事情,感谢。

一、BIOS

BIOS(Basic Input Output System)称为“基本输入输出系统”,是一组固化到计算机内主板上一个BIOS芯片中的程序,它保存着计算机最重要的基本输入输出的程序、开机后自检程序和系统自启动程序,它可从CMOS中读写系统设置的具体信息,是连接软件与硬件的一座“桥梁”,主要功能是为计算机提供最底层的、最直接的硬件设置和控制。

在计算机启动时,会立即读取BIOS芯片中的程序段到内存的0xF0000-0xFFFFF位置,然后开始执行BIOS系统,进行自检及初始化。简单来说,BIOS的实现了对 CPU、内存等硬件设备进行检测和初始化,把安装在磁盘中的操作系统(如Windows,linux)加载到内存中,然后把CPU的执行控制权交给操作系统。

BIOS系统的执行会有以下几个阶段:

1、加电自检(POST)

加电自检(Power On Self Test,简称POST)用于电脑刚接通电源时对硬件部分的检测,功能是检查电脑是否良好,通常完整的POST自检将包括对CPU,基本内存,扩展内存,ROM,主板,CMOS存储器,串并口,显示卡,软硬盘子系统及键盘进行测试。一旦在自检中发现问题,系统会根据检测代码给出提示信息或鸣笛警告。(因为在自检的时候显卡还没有初始化,无法将错误信息显示在屏幕上,只能通过声音报告错误)

自检中如发现有错误,将按两种情况处理:对于严重故障(致命性故障)则停机,此时由于各种初始化操作还没完成,不能给出任何提示或信号;对于非严重故障则给出提示或声音报警信号,等待用户处理。

2、各设备自检

POST结束之后就会调用其它代码来进行更完整的硬件检测。这一过程的实现方法如下:系统BIOS调用各个设备的BIOS, 执行内部的初始化代码,对各个设备进行检测和初始化。

检测完所有其它设备之后,系统BIOS将显示出它自己的启动画面,其中包括有系统BIOS的类型、序列号和版本号等内容。

3、引导启动

当所有的硬件都检测完毕并没有问题后,BIOS会进入引导程序,交给引导程序让其引导启动。

如果我们自己安装过操作系统,我们就知道在安装系统的时候,有一道步骤是需要手动修改启动顺序,将启动引导向U盘/光盘中的安装程序上。而这也就是BIOS的启动代码的最后一项工作,即根据用户指定的启动顺序从软盘、硬盘或光驱启动。

也就是说,BIOS需要知道的是”下一阶段的启动程序”位于哪个设备。也就是说,BIOS需要有一个外部储存设备的排序,排在前面的设备就是优先转交控制权的设备。

二、主引导记录(MBR)

根据“启动顺序”,BIOS把控制器交给位于首位的存储设备,即根据用户指定的启动顺序从软盘、硬盘或光驱读取启动设备的引导记录(MBR)。如果没有找到,表明设备不能用于启动,控制权于是被转交给”启动顺序”中的下一个设备,如果找到引导记录,就会把电脑的控制权转给引导记录。

简单来说,MBR的功能如下:

  1. 扫描分区表查找活动分区
  2. 寻找活动分区的起始扇区
  3. 将活动分区的引导扇区读到内存
  4. 执行引导扇区的运行代码(启动操作系

磁盘的存储是以扇区为基本单位的,我们的系统信息,包括系统启动引导代码(MBR),都存储在这些扇区中,其中硬盘的0柱面、0磁头、1扇区称为主引导扇区,也叫主引导记录MBR。这一部分共有512个字节,简单来说,就是硬盘最前面的512个字节。

这512个字节就称为主引导记录(MBR),它不属于任何一个操作系统,也不能用操作系统提供的磁盘操作命令来读取它。

主引导扇区由三个部分组成(共512字节):

  1. 启动代码(共446字节)

    用于检查分区表的正确性,在硬盘启动时检查分区表是否正确,并将系统控制转给用户指定的并在分区表中登记了的某个操作系统;或者将控制权交给硬盘上的引导程序(如Grub)

  2. 磁盘分区表(DPT) 由四个分区表项构成(每个16字节),负责说明磁盘上的分区情况

  3. 结束标志(共2个字节) 偏移地址01FE–01FF的2个字节值为结束标志0x55和0xAA,是主引导记录的有效标志,如果该标志错误系统就不能启动。

分区表:

硬盘分区表占据主引导扇区的64个字节(偏移01BE–01FD),可以对四个分区的信息进行描述,每个分区16字节。

每个分区的信息如下:

长度 (字节、位) 意义
1字节 引导标志(Boot Indicator):00–>非活动分区;80–> 活动分区;其它数值没有意义
1字节 开始磁头(Start Head)
6位 起始扇区(Start Sector):使用1个字节中的低6位,即0~5位
10位 起始柱面(Start Cylinder):使用上个字节中的高2位,再加上1个字节8位,共10位
1字节 分区类型描述(Partition type indicator):定义了分区的类型
1字节 结束磁头(End Head)
6位 结束扇区(End Sector ) 使用1个字节中的低6位,即0~5位
10位 结束柱面(End Cylinder )使用上个字节中的高2位,再加上1个字节8位,共10位
4字节 本分区之前使用的扇区数(Sector preceding partition):该分区的起始物理扇区地址
4字节 本分区的总扇区数(Sector in partition):该分区所包含的扇区总数

找到主引导记录后,计算机会将其放入内存的指定位置中并开始执行,实现以下功能:

  • 检查硬盘分区表是否完好。
  • 在分区表中寻找可引导的“活动”分区。
  • 将活动分区的第一逻辑扇区内容装入内存。

主引导记录会将计算机的控制权转交给硬盘的某个分区,具体操作为:读取分区表,找到其中的活动分区,读取该活动分区的第一个分区(分区引导记录PBR),并将其加载到内存中。

通过分区引导记录,计算机可以得到操作系统在该分区的位置,计算机就会开始加载操作系统了。这种启动方式适用于一般单操作系统的启动过程。

如果计算机安装了多个操作系统,除了直接通过分区引导记录加载操作系统之外,MBR还可以将控制权交给启动引导程序(boot loader),在启动引导程序中决定启动哪一个操作系统。

三、启动引导程序(boot loader)

启动引导程序用来加载操作系统内核文件,通过boot loader,用户可以选择计算机安装好的不同的操作系统。boot loader可以存在MBR中,也可以存在文件系统的引导扇区中。

1、以Windows为例,在安装Windows的时候,Windows系统会默认在MBR内会安装一份boot loader,并且在系统的引导扇区内也会安装有boot loader。

Windows Boot Manager

Windows系统的boot loader —— Windows Boot Manager,中文名称为Windows开机管理程序或Windows启动管理器。

当电脑执行完POST后,传BIOS会根据启动磁区寻找开机硬盘中标记”启动”分区下的BOOTMGR档案;接著BOOTMGR会读取启动配置信息数据库(BCD, Boot Configuration Database)中的启动配置参数,接著根据其中的配置加载预设或使用者所选择的操作系统。

2、在安装Linux的时候,我们可以选择将boot loader安装在MBR,也可以选择不安装在MBR中,目前Linux常用的boot loader为Grub。

Grub:

Grub是一个来自GNU项目的多操作系统启动程序,它允许用户可以在计算机内同时拥有多个操作系统,并在计算机启动时选择希望运行的操作系统。

Grub可用于选择操作系统分区上的不同内核,也可用于向这些内核传递启动参数。

如果是通过Grub启动操作系统,MBR会引导将Grub装载至内存,启动Grub的开始执行程序:

grub被载入通常包括以下步骤:

(1)装载基本的引导装载程序——stage1,主要功能就是装载第二引导程序:stage2。

(2)装载第二引导装载程序——stage2,这第二引导装载程序实际上是引出更高级的功能, 以允许用户装载入一个特定的操作系统。在GRUB中,这步是让用户显示一个菜单或是输入命令。该阶段引导的最终状态就是执行boot命令,将操作系统内核加载进入内存中,进而将控制权转交给内核。

Grub一般位于/boot/grub目录中,如图所示:

四、操作系统

控制权转交给操作系统后,首先会把操作系统内核载入内存,通过一系列的步骤完成操作系统的启动。

以Linux系统为例,系统将内核放置在内存之中,并调用start_kernel()函数来启动一系列的初始化函数并初始化各种设备,完成Linux核心环境的建立。

内核加载完毕,会启动Linux操作系统第一个守护进程init,然后通过该进程读取/etc/inittab文件,/etc/inittab文件的作用是设定Linux的运行等级,决定进程运行模式。

读取完运行级别,Linux系统执行第一个用户层文件/etc/rc.d/rc.sysinit,该文件功能包括:设定PATH运行变量、设定网络配置、启动swap分区、设定/proc、系统函数等。

然后,系统读取/etc/modules.conf文件及/etc/modules.d目录下的文件来加载系统内核模块。

根据之前读取的运行级别,操作系统还会运行rc0.d到rc6.d中的相应的脚本程序,来完成相应的初始化工作和启动相应的服务。

启动完相应服务之后,会读取执行/etc/rc.d/rc.local文件,系统会逐行去执行并启动相应命令。

在加载完系统的各个模块之后,最终执行/bin/login程序,启动到系统登录界面,操作系统等待用户输入用户名和密码,即可完成操作系统的启动。

五、实模式与保护模式

1、实模式 

在计算机上面,实模式存在的时间非常短,所以一般我们是感觉不到它的存在的。CPU复位(reset)或加电(power on)的时候就是以实模式启动,在这个时候处理器以实模式工作,不能实现权限分级,也不能访问20位以上的地址线,只能访问1M内存。之后一般就加载操作系统模块,进入保护模式。

处理器8086 有 20 根地址线,可以寻址 1MB 内存。但是,它内部的寄存器16 位的,无法在程序中访问整个 1MB 内存。所以,它也是第一款支持内存分段模型的处理器。还有, 8086 处理器只有一种工作模式,即实模式。当然,在那时,还没有实模式这一说。

由于 8086 处理器的成功,推动着 Intel 公司不断地研发更新的处理器, 32 位的时代就这样到来了。尽管 8086 是 16 位的处理器,但它也是 32位架构内的一部分。原因在于, 32 位的处理器架构是从 8086 那里发展来的,是基于 8086 的,具有延续性和兼容性。

32位处理器有自己的 32 位工作模式。保护模式其实就是32位模式。在这种模式下,可以完全、充分地发挥处理器的性能。同时,在保护模式下,处理器可以使用它全部的 32根地址线,能够访问4GB 内存。

实模式的寻址方式与工作机理

其实,8086的段寄存器和IP寄存器都是16位的,如果按照原先的方式,把段寄存器的内容和偏移地址直接相加来形成物理地址的话,也只能得到 16 位的物理地址。麻烦的是,8086却提供了20根地址线。换句话说,它提供的是20位的物理地址。

8086 处理器在形成物理地址时,先将段寄存器的内容左移 4 位(相当于乘以十六进制的10,或者十进制的 16),形成 20 位的段地址,然后再同16位的偏移地址相加,得到20位的物理地址。

因为段寄存器是16位的,在段不重叠的情况下,最多可以将1MB的内存分成65536个段,段地址分别是0000H、0001H、0002H、0003H,……,一直到FFFFH。

计算公式为:

物理地址(physicaladdress)=段(segment) «4 + 偏移(offset)

segment和offset都是16位的。

2、保护模式

最开始的程序寻址是“段:偏移”模式,这样的好处是所见即所得,程序员指定的地址就是物理地址,物理地址对程序员是可见的。这就带来一些问题:

1)无法支持多任务

2)程序的安全性无法得到保证。

在windows的旧版本中,我们时不时就死机或者蓝屏,其实发生这些问题大部分就是由于内存被破坏引起的。因为在实模式中,将整个物理内存看成分段的区域,程序代码和数据位于不同区域,系统程序和用户程序没有区别对待,而且每一个指针都是指向”实在”的物理地址。这样一来,如果用户程序的访问了系统程序区域或其他用户程序区域,并改变了值,那么对于这个被修改的系统程序或用户程序,容易造成软件甚至系统崩溃。

而在保护模式下,全部32条地址线有效,可寻址高达4G字节的物理地址空间。扩充的存储器分段管理机制和可选的存储器分页管理机制,不仅为存储器共享和保护提供了硬件支持,而且为实现虚拟存储器提供了硬件支持,支持多任务,能够快速地进行任务切换和保护任务环境,4个特权级和完善的特权检查机制,既能实现资源共享又能保证代码和数据的安全和保密及任务的隔离,支持虚拟8086方式,便于执行8086程序。

保护模式出现的原因是:保护进程地址空间

这样,就产生了一个结果:两种模式下程序的寻址方式发生了变化。

保护模式的寻址方式和工作原理

在保护模式下的寻址相对实模式来说是比较复杂的,而且涉及到一些概念问题,下面先来简单介绍一下。

在保护模式下地址的表示方式与实模式是一样的,都是:段(segment):偏移(offset),不过保护模式下,“段”的概念发生了根本性的改变。

实模式下,段值还是可以看作是地址的一部分,比如段值为xxxxh表示以xxxx0h开始的一段内存。而保护模式下,虽然段值仍然由原来的cs、ds等寄存器表示,但此时它仅仅变成了一个索引,这个索引指向了一个数据结构的一个表项,表项中详细定义了段的起始地址、界限、属性等内容。

这个数据结构就是全局描述符GDT。

GDT的作用是用来提供段式存储机制,这种机制是段寄存器和GDT中的描述符共同提供的。每个描述符在GDT中占8字节,也就是 2 个双字,或者说是 64 位。下图中,下面是低32位,上面是高32位。

img

很明显,描述符中指定了 32 位的段起始地址,以及 20 位的段边界。在实模式下,段地址并非真实的物理地址,在计算物理地址时,还要左移 4 位(乘以 16)。和实模式不同,在 32 位保护模式下,段地址是 32 位的线性地址,如果未开启分页功能,该线性地址就是物理地址。

六、补充(UEFI启动)

除了BIOS引导开机,现在的很多计算机都使用了UEFI引导系统,省去了bios自检过程,所以可加快开机启动速度。我们也可以查询自己的计算机的引导模式,以我自己的计算机为例,这台电脑的引导模式也是UEFI引导。

UEFI,全称“统一的可扩展固件接口”,这是 Intel 为个人电脑固件提出的启动系统的建议标准。其主要目的是为了在windows系统加载(启动)之前,提供操作系统启动服务。

BIOS先要对CPU初始化,然后跳转到BIOS启动处进行POST自检,此过程如有严重错误,则电脑会用不同的报警声音提醒,接下来采用读中断的方式加载各种硬件,完成硬件初始化后进入操作系统启动过程。

而UEFI引导的流程是开机初始化UEFI,然后引导操作系统,进入操作系统,和BIOS引导相比,少了一道BIOS自检过程,节省了加载系统时间。

UEFI直接运行预加载环境先直接初始化CPU和内存,CPU和内存若有问题则直接黑屏,其后启动PXE,采用枚举方式搜索各种硬件并加载驱动,完成硬件初始化,之后同样进入操作系统启动过程。

传统BOIS是由硬件及软件构成,同样,UEFI也是由硬件和软件构成。从使用者的角度分析,UEFI的操作界面更加的人性化、布局更加的合理。目前,集成UEFI的笔记本基本上是具备UEFI的基础功能,设置界面和传统BIOS设置界面集成在一起。只有一些高端主板才具备完整的UEFI设置界面。同时,UEFI具备以下优点。

1:可以支持2TB及以上硬盘引导操作系统。

2:UEFI可以快速的引导系统或者从休眠状态恢复。

3:UEFI可以和传统BIOS集成使用。

4:UEFI必须配合GPT分区才可以引导win10操作系统。

参考资料

计算机启动过程

BIOS基本流程

Windows启动过程(MBR引导过程分析)