1、中断机制
(1)中断机制需要硬件的支持,eg:中断控制器、CPU现场保存与恢复机制、IDT表。
eg:完成I/O操作之后,设备通过中断控制器将中断信号递交给CPU,CPU自动保存现场与恢复现场,CPU通过IDT表自动转入中断处理程序。
每条指令处理完之后CPU就看一下有木有中断。
CPU可以关闭中断。最简单的方式是处理器不响应中断 CLI/STI 。
(2)中断嵌套:中断处理程序再次被中断(因为中断处理程序可以打开中断)。
高优先级可以中断低优先级的中断处理程序。
程序重入:统一中断程序的嵌套。 --> 保存现场不会出问题、局部变量保存在堆栈中不会出问题、全局变量有问题。
(3)中断的种类:外部中断、异常、陷入。均可通过IDT表进入内核 中的处理程序。
①设备产生的中断称为外部中断。
②在CPU执行指令的过程中,不正常或非法条件引起的事件引起的叫异常。
③通过特殊的指令陷入到内核,叫陷入。eg:系统调用
中断处理程序不能放在用户空间。应用程序无权直接访问内核的数据、调用内核程序,要想请求内核服务,就通过系统调用。
获取向量号 --> 检索 IDT 表 --> 保护现场 --> 进入中断处理程序
2、IDT设置(中断向量表)
(1)每个外部中断或者异常都有一个向量号,陷入指令指定向量号(eg:int n 的那个n)。
异常和陷入的向量号和意义是固定的;外部中断的向量号由设备、中断控制器确定,意义由驱动程序决定。
Intel定义了256个中断向量,0~31为异常和不可屏蔽中断(NMI),32到255为用户定义的中断。
(2)IDT中断向量表:中断向量与中断处理程序间的对应关系。
门描述符是中断处理程序的入口。
(3)IDT可以驻留在线性地址空间的任何位置。IDTR记录IDT的基址和界限信息。
(4)IDT中常用的是中断门和陷阱门。
①通过中断门进入,处理器清楚EFLAGS的IF标志,关闭中断。②通过陷阱门进入时,不改变IF标志,不屏蔽中断。
(5)中断向量表的设置方法
①为每个中断定义一个真处理程序,用真程序入口创建门描述符,并填入IDT表。(对异常还可以,对外部中断和陷入比较困难)
②为每个中断定义一个伪处理程序,用伪程序入口创建门描述符,并填入IDT表。(ucore的做法)
③为异常定义真处理程序,其余用伪程序。(Linux的做法)
3、堆栈切换
(1)Intel处理器提供4个特权级。代码只能使用与其特权级相同的堆栈。特权级切换时中断也要切换。
中断处理程序只能使用第0级堆栈,中断之前的现场保存在第0级堆栈中。
(2)如果中断发生前系统运行在核心态,中断处理程序直接使用当前的堆栈,不需要切换。如果运行在用户态,需要从当前用户栈切换到系统栈。
堆栈切换时,压栈时多压入两个,吧原来的栈顶SS和ESP压入(iret指令会将他们弹出)。
向量号 为10~14的会压 error-code;对于不自动压入 error-code 的中断,处理程序应在栈顶压入一个值,如0。
(3)如何找到系统堆栈的栈底:TR -->指向当前使用的 TSS 描述符-->保存的是当前进程的系统堆栈的栈底
TR 中的任务状态段是预先设置好的,由 GDT 中的一个系统段描述符描述。
①可以为每个进程创建一个 TSS,进程切换时改 TR;
②也可以让所有进程公用一个 TSS,TR 保持不变,进程切换时改ESP0(SS0)不变。(ucore 做法)
4、中断处理流程
三类中断的处理流程大致相同。
善后处理程序中有开中断没有开中断,因为善后处理时不再中断,且善后处理中会恢复恢复 EFLAGS、IF。
中断返回时:弹出中断处理程序压入到堆栈中的数据;iret。
5、异常处理
(1)异常分为三类:故障、陷阱、中止
①故障:可更正,故障处理完 CPU 会重新执行产生故障的指令(EIP 还是那条指令的地址,不是下一地址)
②陷阱:由特殊指令产生(eg:INT 3,INTO),陷阱处理完 CPU 会执行陷阱指令后面的指令
③中止:严重的错误,无法保证程序能够继续执行(不一定能继续,不确定)
(2)most 异常表示系统出问题,处理方式:通知并杀掉出现异常的进程。
INT 3是陷阱类异常,用于设置断点,实际也是一种陷入,由指令 int 3引起。
最重要的异常是页故障(Page Fault),是操作系统实现虚拟内存管理的基础。
6、系统调用
(1)进程的地址空间分为:用户空间、内核空间。
用户和内核区分 --> 放的段不同,特权级不同
由于保护级别(特权级)不同,用户程序只能用过系统调用请求内核服务。系统调用是通过陷入指令进入内核。
(2)系统调用时预先定义好的(很多),每个系统调用一个编号,内核中有一个对应的服务函数,有一个向量表,记录系统调用的处理程序。
(3)系统调用时传参:堆栈要切换所以用寄存器;ucore 用 edx、ecx 、ebx、edi、esi 传参0到4,eax 传系统调用号,返回值在 eax 中。
(5)ucore 中系统调用 T_SWITCH_TOU(120)、T_SWITCH_TOK(121)
①T_SWITCH_TOU从内核态切换到用户空间,执行int 120前系统在核心态,int 不会引起切换,切换工作需在 iret 中完成。
执行中断各种压栈,esp 指向新栈(用户栈),所以一执行 iret 返回,就返回到了新栈中。
②T_SWITCH_TOK从用户态切换到核心态,执行 int 121前系统在用户态,int 引起切换,iret 无需再切换。
拷回去的,上面的SS、ESP都不要了。
7、外部中断处理
(1)外部中断由设备产生,经中断控制器递交,由设备驱动程序处理,需要与硬件打交道。
PIC 可编程中断控制器。
(2)16个管脚,共15个 IRQ(因为 IRQ9不能用)。IRQ 中断请求。
CPU 未屏蔽中断时,每执行完一条指令,通过INTA应答中断,读取中断向量号,有的话就处理。
开始把16个管脚都屏蔽了,哪个优先级高就打开哪个。有一个位图记录中毒控制器中各 IRQ 的屏蔽状态。
(3)多处理器环境,引入 APIC,由 Local APIC 和 I/O APIC 通过专用或系统总线互连构成。
每个 CPU 都有一个 Local APIC,可以互相中断。
(4)允许多个设备用用一个 IRQ 号,解决 PIC 管脚短缺的问题。
CPU 无法分辨中断是那个设备产生的 --> CPU 顺序调用共用同一 IRQ 号的所有设备的中断处理程序,由各中断处理程序自己决定处理方法。
每个设备中断预先建立一个入口程序,用此入口程序创建中断门,填入 IDT。入口程序完成基本的准备工作,转入统一的中断分派程序。中断分派程序管理真正的设备中断处理程序,避免让驱动直接操作 IDT 表。
每个IRQ 定义一个处理程序队列。
(5)IDT 表中外部中断的描述符是中断门。
中断处理程序分为:①硬处理 --> 由硬件进入,必须子啊关中断状态下处理的;完成最急需处理的。②软中断 --> 由软件进入,可在开中断状态下处理的。
硬处理没做完的推迟了,软处理来做。
Linux 上 softirq锁、hardirq 锁,防止重入。
8、时钟管理
(1)时钟设备不能输入输出,就是产生中断。
传统的时钟设备是 PIT,由三个计数器组成:第0号计数器、第1号计数器、第2号计数器。可以独立配置工作。
各计数器的初值由操作系统设定,随输入脉冲递减。来一个脉冲就减,减到0时就中断了。
①周期单中断模式:计数器减到0输出一个脉冲,计数器恢复初值,重新计数。②单发中断模式:计数器减到0输出一个脉冲,计数器不恢复初值,停止计数。
(2)两个时钟中断之间的时间间隔称为滴答 ticks。(不精确)
PIT 只产生中断,不提供时间。传统计算机中的定时器 --> RTC,还有定时功能(到时见产生一个外部中断),精度较低。
Linux 将定时器队列分为5组,合成队列组集合。定时器在一个队列组中的位置取决于它的到期时间(expires)。定时器的到期时间是32位无符号整数,分成5段,对应五个队列组。
定时器由周期性的时钟中断驱动
网友评论