这部分很重要!
1.CPU状态
cpu→寄存器→控制状态寄存器(用于控制处理器的操作)→程序状态字寄存器(PSW:记录cpu的运行状态如条件码、模式、控制位等)
由于操作系统具有并发、共享的特征,为了保证用户成序与用户程序、用户程序与操作系统之间互不干扰,所以操作系统需求cpu提供保护与控制
为了实现对操作系统的保护,cpu在PSW中留了一位来表示cpu的不同的状态权限
操作系统根据cpu提供两种权限状态,来分别运行不同的指令集合
内核态(Kernel Mode):运行操作系统程序
用户态(User Mode):运行用户程序
特权指令:只能由操作系统使用、用户程序不能使用的指令
非特权指令:用户程序可以使用的指令
例:x86架构处理器
其在PSW中预留了两位来表示cpu状态,所以它有4个特权环:R0、R1、R2、R4。R0相当于内核态,R3相当于用户态。
目前大多数基于x86处理器的操作系统只用了R0和R3两个特权级别
CPU状态之间的转换:
用户态→内核态:唯一途径→中断/异常/陷入机制&emsp ;关于访管指令(陷入指令):提供给用户程序的接口,用于调用操作系统的功能服务
内核态→用户态:设置PSW
2.中断与异常机制
操作与异常机制是操作系统的驱动力,可以说操作系统是由中断驱动的
主要作用:
及时处理设备发来的中断请求
可使操作系统捕获 用户程序提出的服务请求
防止用户程序执行过程中的破坏性活动
概念:
CPU对系统发生的某个事件作出的一种反应。
中断/异常发生之后,CPU控制流的变化:
CPU暂停正在执行的程序,保留现场自动转去执行相应事件的处理程序,处理完成之后返回断点继续执行被打断的程序
特点:
是随机发生的
是自动处理的
是可恢复的
为什么引入中断/异常机制?
事件:
中断(外中断):外部事件,正在运行的程序所不期望的
I/O中断
时钟中断
硬件故障
异常(内中断):由正在执行的指令引发
系统调用
页故障/也错误
保护性异常
断点指令
其他程序性异常(算出溢出等)
中断/异常的小结:
3.中断/异常机制的工作原理
中断/异常机制的功能作用:通过软件和硬件相互配合而使计算机系统得以充分发挥能力
硬件的作用——中断/异常响应:
捕获中断源发出的中断/异常请求,以一定方式响应,将处理器控制权交给特定的处理程序
中断响应:
发现中断、接收中断的过程
由中断硬件部件完成
中断响应过程示意:
中断向量表:
中断向量表是一个软硬件结合的数据结构;中断向量表由一行行中断向量组成
中断向量:一个内存单元,存放中断处理程序入口地址和程序运行时所需的处理机状态字
执行流程按中断号/异常类型的不同,通过中断向量表转移控制权给中断处理程序
以Linux的中断向量表为例:
中断响应示意图:
软件的作用——中断/异常处理程序:
识别中断/异常类型并完成相应的处理
中断处理程序:
设计操作系统时,为每一类中断/异常事件编好相应的处理程序,并设置好中断向量表
系统运行时若响应中断,中断硬件部件将CPU控制权转给中断处理程序:
保存相关寄存器信息
分析中断/异常的具体原因
执行对应的处理功能
恢复现场,返回被事件打断的程序
中断/异常机制小结
以输入输出设备为例:
打印机给CPU发中断信号(硬件)
CPU处理完当前指令后检测到中断,判断出中断来源并向相关设备发送确认信号(硬件)
CPU开始为软件处理中断做准备(硬件):
处理器状态被切换到内核态
在系统栈中保存被中断程序的重要上下文环境,主要是程序计数器PC(入口地址)、程序状态字寄存器PSW
CPU根据中断码查中断向量表,获得与该中断相关的处理程序的入口地址,并将PC设置成该地址,新的指令周期开始时,CPU控制转移到中断处理程序(硬件)
中断处理程序开始工作(软件):
在系统中保存现场信息
检查I/O设备的状态信息,操纵I/O设备或者在设备和内存之间传送数据等等
中断处理结束时,CPU检测到中断返回指令,从系统栈中恢复被中断程序的上下文环境,CPU状态恢复成原来的状态,PSW和PC恢复成终端前的值,CPU开始一个新的指令周期(硬件)
举例:I/O中断处理程序
通常分为两类:
I/O操做正常结束:
若有程序正等待此次I/O的结果,则应将其唤醒
若要继续I/O操作,需要准备好数据重新启动I/O
I/O操作出现错误:
需要重新执行失败的I/O操作
重新次数有上限,达到时系统将判定硬件故障
4.中断异常机制实例
——x86处理器对中断/异常的支持
通过IDTR寄存器得到中断描述符表IDT的地址结合中断向量i,获得中断描述符(中断描述符表的每一行叫门描述符/中断描述符),通过中断描述符得到偏移量和段选择符,通过段选择符结合GDTR寄存器中得到的GDT地址中的查全局描述符表GDT得到段描述符,通过段描述符获得段基址
检查是否发生了特权级变化,如果是,则进行堆栈切换(必须使用与新的特权级相关的栈);硬件压栈,保存上下文环境,如果产生了硬件出错码,也将它保存在栈中;如果是,中断,清IF位。
中断处理程序入口地址=段基址+偏移量
5.系统调用机制
——操作系统向用户程序提供的接口
系统调用:
什么是系统调用?
系统调用:用户在编程时可以调用的操作系统功能
系统调用的作用:
系统调用是操作系统提供给编程人员的唯一接口
使CPU状态从用户态陷入内核态
典型系统调用举例
每个操作系统都提供几百种系统调用(进程控制、进程通信、文件使用、目录操作、设备管理、信息维护等)
系统调用、库函数、API、内核函数的关系:
应用程序往往通过调用函数,函数执行过程中变成系统调用,然后进入内核态完成
系统调用机制设计:
1.中断/异常机制:支持系统调用服务的实现
2.选择一条特殊指令:陷入指令(亦称访管指令):引发异常,完成用户态到内核态
3.系统调用号和参数:每个系统调用都事先给定一个编号(功能号)
4.系统调用:存放系统调用服务例程的入口地址
参数传递过程问题:
怎样实现用户程序的参数传递给内核?
常用的3种实现方法:
由陷入指令自带参数:陷入指令的长度有限,且还要携带系统调用功能号,只能自带有限的参数
通过通用寄存器传递参数:这些寄存器是操作系统和用户程序都能访问的,但寄存器的个数会限制传递参数的数量(通常采用这种方法)
在内存中开辟专用堆栈区来传递参数
系统调用的执行过程:
当CPU执行到特殊的陷入指令时:
中断/异常机制:硬件保护现场:通过查中断向量表把控制权转给系统调用入口程序
系统调用总入口程序:保存现场;将参数保存在内核堆栈里;通过查系统调用表把控制权转给相应的系统调用处理例程或内核函数
执行系统调用
恢复现场,返回用户程序
6.Linux系统调用实现
——基于x86处理器
LINUX的系统调用实现——基于x86处理器
陷入指令选择128号
int $0x80
门描述符
系统初始化时:对IDT表中的128号门初始化
门描述符的2、3两个字节:内核代码段选择符
0、1、6、7四个字节:偏移量(指向system_call())
&emsp:门类型:15,陷阱门,执行系统调用过程中允许接收中断
DPL特权级:3,与用户级别相同,允许用户进程使用该门描述符
系统执行INT$0x80指令:
由于特权级的改变,要切换栈:
用户栈→内核栈
CPU从任务状态段TSS中装入新的栈指针(SS:ESP),指向内核栈
用户栈的信息(SS:ESP)、EFLAGS、用户态CS、EIP寄存器的内容压栈(返回用)
将EFLAGS压栈后,复位TF,IF位保持不变
用128在IDT中找到该门描述符,从中找出段选择符装入代码段寄存器CS
代码段描述符中的基地址+陷阱门描述中的偏移量→定位system_call()的入口地址
中断发生后OS底层工作步骤
1.硬件压栈:程序计数器等
2.硬件从中断向量装入新的程序计数器等
3.汇编语言过程保存寄存器值
4.汇编语言过程设置新的堆栈
5.C语言中断服务程序运行(例:读并缓冲输入)
6.进程调度程序决定下一个将运行的进程
7.C语言过程返回至汇编代码