2. 启动、中断、异常和系统调用
文章目录
2.1 计算机系统的启动过程
CPU在加电之后,执行的第一条指令在内存中。
但是我们说过,停电之后,内存中的DRAM会丢失全部数据。所以CPU是如何启动的呢?
本节参考:https://www.cnblogs.com/tyong/articles/10141205.html
2.1.1 BIOS
内存中一部分存储是ROM,启动程序的代码存在ROM中。
计算机加电之后,首先读取(或许因此叫基本输入输出系统Basic IO System)并运行这部分程序。这部分程序叫BIOS启动固件,是一种固化到主板上的重要系统程序。
BIOS固件
- 有20位地址信息,共1MB
- 两个重要的寄存器CS:IP:加电稳定之后从0xf0000:fff0处读取第一条跳转指令。https://zhuanlan.zhihu.com/p/258863021
- 系统处于实模式
- 内容包括基本输入输出、配置信息、开机自检程序(POST)、自启动程序
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的实模式下访问
2.1.2 主引导记录
BIOS按照启动顺序,将控制权转交给排在第一位的存储设备。这是计算机读取该设备的第一个扇区,也就是最前面的512个字节。结构如下:
如果这512个字节的最后两个字节是0x55和0xAA(主引导记录签名),表明这个设备可以用于启动;如果不是,表明设备不能用于启动,控制权转交给启动顺序中的下一个设备。
(硬盘)分区表(DPT):
硬盘分区有很多好处。考虑到每个区可以安装不同的操作系统,"主引导记录"因此必须知道将控制权转交给哪个区。每个主分区的16个字节,由6个部分组成:
- 1:如果为0x80,则为激活分区,控制权要转交给这个分区,
- 2-4:主分区第一个扇区的物理位置
- 5:主分区类型
- 6-8:主分区最后一个扇区的物理位置
- 9-12:主分区第一个扇区的逻辑地址
- 13-16:扇区总数(决定了主分区的长度不超过 2 32 2^{32} 232)
分区/活动引导扇区(DBR):
除了BIOS-MBR之外,另外的启动规范有BIOS-GPT、PXE,以及最终的统一标准UEFI
2.1.3 加载操作系统
而后硬盘启动:
- 卷引导记录:哪里装着操作系统
- 扩展分区和逻辑分区:四个分区再分,成为逻辑分区
- 启动管理器(Boot loader)
2.2 中断、异常和系统调用
这一节真的讲得非常清楚,强烈建议一听,原课程对应3.3
2.2.1 背景
内核是被信任的第三方,只有内核才可以执行特权指令(比如Win中的Admin,Linux中的root、sudo)。
CPU执行操作系统代码时,CPU处于内核态(又称管态),2.2介绍的三种机制都是在内核态下运行的
安全-功能权衡:既要隔离kernel保障安全,又要让用户态的应用程序得到系统服务:
- 中断:处理外设回调类的事件,比如键盘按键,负责有序提供服务
- 异常:防止应用程序处理意外情况,保证内核安全
- 系统调用:系统调用和功能调用(函数接口)
2.2.2 定义
正规的定义如下:
- 系统调用(system call):应用程序主动向操作系统发出的服务请求
- 异常(exception):非法指令或者其他原因导致当前指令执行失败
- 中断(hardware interrupt):来自硬件外设的处理请求
在下图中对应关系:
- 中断:外设发送信号,设备驱动双向处理数据
- 异常:中断向量表→异常服务例程→程序处理(也可能导致中止;另外也可能是因为内核运行出错)
- 调用:系统调用接口,函数库(功能调用接口)
2.2.3 三种机制的对比
源头:
- 中断:外设
- 异常:应用程序意想不到的行为
- 系统调用:应用程序请求提供服务
响应方式:
- 中断:异步
- 异常:同步
- 系统调用:异步或同步
处理机制:
- 中断:持续,对用户态不可见
- 异常:kill或re-execute意外指令
- 系统调用:等待或持续
2.2.4 中断
硬件处理:在CPU初始化时设置中断使能标志
- 依据内部或外部事件设置中断标志(比如键盘就对应着一个阵列通断对应的高低电平)
- 依据中断向量调用相应中断服务例程(相当于是一个回调机制)
软件处理:
- 现场保存(编译器)
- 中断服务处理(服务例程)
- 清除中断标记(服务例程)
- 现场恢复(编译器)
对于服务例程:
- 中断例程→设备驱动
- 异常→异常服务例程
- 系统调用→不同系统调用
硬件中断服务例程可以被打断
- 不同硬件中断源可能在中断处理时出现
- 硬件中断服务例程中需要临时禁止中断请求
- 中断请求会会保持到CPU做出响应
异常服务例程可以被硬件中断打断
异常服务例程可以嵌套,出现缺页(可以发生在用户态)
2.2.5 系统调用
系统调用的模式图,从中可以看出系统调用的一个基本点,即内核态与用户态的隔离:
背景:应用程序一般无法直接访问硬件,也无法执行特权指令。所以,需要通过操作系统来间接完成相关的工作。而基于安全和可靠性的需求,应用程序运行在用户态,操作系统内核运行在内核态,导致应用程序无法通过函数调用来访问操作系统提供的各种服务,于是通过系统调用的方式就成了应用程序向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执行操作系统代码的时候称为处理机处于内核态(又称管态)