计算机系统的启动过程

CPU在加电之后,执行的第一条指令在内存中。

但是我们说过,停电之后,内存中的DRAM会丢失全部数据。所以CPU是如何启动的呢?

本节参考:

BIOS固件-电脑开机的启动流程 - tyong - 博客园www.cnblogs.com/tyong/articles/10141205.html

img

BIOS

内存中一部分存储是ROM,启动程序的代码存在ROM中。
计算机加电之后,首先读取(或许因此叫基本输入输出系统Basic IO System)并运行这部分程序。这部分程序叫BIOS启动固件,是一种固化到主板上的重要系统程序。

BIOS启动固件

  • 有20位地址信息,共1MB
  • 两个重要的寄存器CS:IP:加电稳定之后从0xf000:fff0(cs*16+ip)处读取第一条跳转指令。

更详细内容可参考0704:CS和IP

  • 系统处于实模式
  • 内容包括基本输入输出的程序、系统配置信息**、开机自检程序(POST)、系统自启动程序
img

BIOS首先检查内存、显卡等启动必须的重要部件。如果硬件出现问题通过蜂鸣器报错并停止启动。称为硬件自检(Power-On Self-Test)

查找并执行显卡等接口卡BIOS,进行设备初始化;执行系统BIOS,进行系统检测(即插即用设备);更新CMOS中的扩展配置数据(ESCD)

完成自检之后,BIOS把控制权交给下一阶段的启动程序,这时,BIOS需要知道,“下一阶段的启动程序”存放在那哪一个设备,也即BIOS需要一个外部存储设备的排序,谁排在前,谁将优先被转交控制权。这种排序叫做“启动顺序”(Boot Sequence)

关于BIOS的系统调用 BIOS以中断调用的方式提供了基本的IO功能:

  • INT 10h:字符显示
  • INT 13h:磁盘删去读写
  • INT 15h:检测内存大小
  • INT 16h:键盘输入

只能在x86的实模式下访问

主引导记录

BIOS按照启动顺序,将控制权转交给排在第一位的存储设备。然后从所选引导设备的硬盘驱动器加载前 512 个字节——这 512 个字节就是通常所说的 MBR—主引导记录。结构如下:

img

主引导记录由三个部分组成:

  • 第1-446字节:调用操作系统的机器码。
  • 第447-510字节:分区表(Partition table)。
  • 第511-512字节:主引导记录签名(0x55和0xAA)。

如果这512个字节的最后两个字节是0x55和0xAA(主引导记录签名),表明这个设备可以用于启动;如果不是,表明设备不能用于启动,控制权转交给启动顺序中的下一个设备。

引导代码(Bootstrap Code)

引导代码的目的是从磁盘中查找另一个文件并加载它,以执行实际的引导过程。因此,这个引导代码通常被称为“第一阶段引导加载程序”。“第一阶段引导加载程序”会指向“第二阶段引导加载程序”,根据操作系统不同,“第二阶段引导加载程序”的确切位置不同。

但在 Windows 上,“第一阶段引导加载程序”将在 MBR 的分区表中搜索标记为“活动”的分区,这个活动分区的开头在其起始扇区(也称为“引导扇区”)中包含引导代码的下一部分。在正确创建的 MBR 磁盘上,一次只能将一个分区标记为活动分区。

(硬盘)分区表(DPT)

“分区表”的作用,是将硬盘分成若干个区,硬盘分区有很多好处。考虑到每个区可以安装不同的操作系统,”主引导记录”因此必须知道将控制权转交给哪个区。每个主分区的16个字节,由6个部分组成:

  • 1:如果为0x80,则为激活分区,控制权要转交给这个分区,
  • 2-4:主分区第一个扇区的物理位置
  • 5:主分区类型
  • 6-8:主分区最后一个扇区的物理位置
  • 9-12:主分区第一个扇区的逻辑地址
  • 13-16:扇区总数(决定了主分区的长度不超过 $2^32$ )

引导签名

在 IBM 兼容的 PC(基本上就是所有的电脑)上,512 字节 MBR 的最后两个字节称为 引导签名,BIOS 使用它们来确定所选的引导驱动器(就是MBR所在的这个启动设备/启动盘/驱动器 0)是否实际可引导。如果这512个字节的最后两个字节是0x55和0xAA,表明这个设备可以用于启动;如果不是,表明设备不能用于启动,控制权转交给启动顺序中的下一个设备。

分区引导扇区(The Partition Boot Sector):

MBR 中的引导程序代码通常会从活动分区的开头加载一个字节序列。分区的确切布局取决于创建或格式化分区的文件系统,但通常看起来像这样

img

通过分区引导扇区,我们可以知道引导加载程度的位置并且在之后执行它。

除了BIOS-MBR之外,另外的启动规范有BIOS-GPT、PXE,以及最终的统一标准UEFI

引导加载程序(bootloader)

磁盘上的实际引导加载程序文件构成引导加载过程的最后部分。当人们谈论引导加载程序和引导文件时,他们通常指的是引导过程的最后一个关键步骤。

img

引导加载程序序列:

  • PC 的控制权从 BIOS 移交给 MBR 中的引导程序代码,
  • 然后从 MBR 移交给分区引导扇区中的引导程序代码,
  • 最后从那里移交给活动分区上的可执行引导文件,实际逻辑涉及确定要加载哪个操作系统、从哪里加载它、传递给它的参数/选项以及完成可能可用的与用户的任何交互,启动操作系统的实际过程就开始了。

中断、异常和系统调用

背景

内核是被信任的第三方,只有内核才可以执行特权指令(比如Win中的Admin,Linux中的root、sudo)。

CPU执行操作系统代码时,CPU处于内核态(又称管态),2.2介绍的三种机制都是在内核态下运行的

安全-功能权衡:既要隔离kernel保障安全,又要让用户态的应用程序得到系统服务:

  • 中断:处理外设回调类的事件,比如键盘按键,负责有序提供服务
  • 异常:防止应用程序处理意外情况,保证内核安全
  • 系统调用:系统调用和功能调用(函数接口)

定义

正规的定义如下:

  • 系统调用(system call):应用程序主动向操作系统发出的服务请求
  • 异常(exception):非法指令或者其他原因导致当前指令执行失败
  • 中断(hardware interrupt):来自硬件外设的处理请求

在下图中对应关系:

  • 中断:外设发送信号,设备驱动双向处理数据
  • 异常:中断向量表→异常服务例程→程序处理(也可能导致中止;另外也可能是因为内核运行出错)
  • 调用:系统调用接口,函数库(功能调用接口)
img

三种机制的对比

源头:

  • 中断:外设
  • 异常:应用程序意想不到的行为
  • 系统调用:应用程序请求提供服务

响应方式:

  • 中断:异步
  • 异常:同步
  • 系统调用:异步或同步

处理机制:

  • 中断:持续,对用户态不可见
  • 异常:kill或re-execute意外指令
  • 系统调用:等待或持续

中断

在操作系统中,有三种特殊的中断事件。由CPU外部设备引起的外部事件如I/O中断、时钟中断、控制台中断等是异步产生的(即产生的时刻不确定),与CPU的执行无关,我们称之为异步中断(asynchronous interrupt)也称外部中断,简称中断(interrupt)。而把在CPU执行指令期间检测到不正常的或非法的条件(如除零错、地址访问越界)所引起的内部事件称作同步中断(synchronous interrupt),也称内部中断,简称异常(exception)。把在程序中使用请求系统服务的系统调用而引发的事件,称作陷入中断(trap interrupt),也称软中断(soft interrupt),系统调用(system call)简称trap。

硬件处理:在CPU初始化时设置中断使能标志

  • 依据内部或外部事件设置中断标志(比如键盘就对应着一个阵列通断对应的高低电平)
  • 依据中断向量调用相应中断服务例程(相当于是一个回调机制)

软件处理:

  • 现场保存(编译器)
  • 中断服务处理(服务例程)
  • 清除中断标记(服务例程)
  • 现场恢复(编译器)

硬件中断服务例程可以被打断

  • 不同硬件中断源可能在中断处理时出现
  • 硬件中断服务例程中需要临时禁止中断请求
  • 中断请求会会保持到CPU做出响应

异常服务例程可以被硬件中断打断
异常服务例程可以嵌套,出现缺页(可以发生在用户态)

系统调用

下图是系统调用的模式图,从中可以看出系统调用的一个基本点,即内核态与用户态的隔离。

img

背景:应用程序一般无法直接访问硬件,也无法执行特权指令。所以,需要通过操作系统来间接完成相关的工作。而基于安全和可靠性的需求,应用程序运行在用户态,操作系统内核运行在内核态,导致应用程序无法通过函数调用来访问操作系统提供的各种服务,于是通过系统调用的方式就成了应用程序向OS发出请求并获得服务反馈的唯一通道和接口。

定义

  • 操作系统服务的编程接口
  • 通常由高级语言编写
  • 程序访问通常是通过高层次的API接口(函数调用),而不是直接进行系统调用。

三种最常访问的API:

  • Win32 API
  • POSIX API用于POSIX-based systems(类UNIX,包括Linux和MacOS X的所有版本)
  • Java API用于Java虚拟机(JVM)

实现

  • 每个系统调用对应一个系统调用编号:来维护系统调用表的索引
  • 调用内核态中的系统调用功能实现,并返回系统调用的状态和结果
  • 黑盒性,用户不需要知道系统调用的实现

系统调用与函数调用的不同

  • INT和IRET用于系统调用:堆栈切换和特权级转换
  • CALL和RET用于常规调用(不用堆栈切换

系统调用的开销

超过函数调用的原因是系统调用的:

  • 引导机制
  • 内核堆栈
  • 验证参数
  • 映射到用户态的地址空间
  • 内核态独立地址空间:TLB

一些测试题

  • (2012统考)中断处理和子程序调用都需要压栈以保护现场。中断处理一定会保存而子程序调用不需要保存其内容的是程序状态字寄存器。程序状态字(PSW)寄存器用于记录当前处理器的状态和控制指令的执行顺序,并且保留与运行程序相关的各种信息,主要作用是实现程序状态的保护和恢复。所以中断处理程序要将PSW保存,子程序调用在进程内部执行,不会更改PSW。
  • 中断向量地址是中断服务例程入口的地址
  • 即便是管理员用户的程序,也运行在用户态,不能执行特权指令
  • (西北工业大学)CPU执行操作系统代码的时候称为处理机处于内核态(又称管态)