中断的分类
硬件中断(Hardware Interrupt): 一般是由外部(相对CPU内核而言)的硬件引起的事件,比如串口来数据,键盘击键等;
软件中断(Soft Interrupt): 通过在程序中执行的中断指令引起的中断,又叫软陷;
- 80X86: int指令
- 68000:trap指令
- ARM: SWI指令
软中断指令一般用于操作系统的系统调用入口;
异常(Exception): 由于CPU内部在运行过程中引起的事件,比如指令预取错,数据中止,未定义指令等等,异常事件一般由操作系统接管。
中断的处理过程
虽然中断产生的原因不同,但是中断响应的硬件过程基本上是相同的
硬件完成
- 拷贝CPSR到SPSR_<mode>
- 设置正确的CPSR位(切换到ARM状态、切换到异常模式、禁止中断)
- 保存返回地址在LR_<mode>
- 设置PC到异常向量地址
中断服务程序完成
- 中断服务程序可能保存需要使用的寄存器(堆栈中)
- 用户服务程序可以打开中断,以接受中断嵌套
- 恢复保存的寄存器
- 通过调用Reti(或其它相应指令)指令将PSR和PC出栈,从而恢复原来的执行流程。
中断的重要性!!!
- 理解处理器对中断的管理以及这其中的堆栈管理对于理解操作系统是至关重要的!
- 中断是操作系统的入口,用户访问操作系统提供的服务的唯一途径是依靠中断来实现的。
- 实时系统对异步事件的处理,依靠的是中断!
- 任务的调度靠的是中断
- 系统调用的实现靠的是中断
- 在有MMU的系统中,虚存的管理也靠的是中断
- 中断是理解操作系统的入口!
调用栈和中断栈的不同
暂略...
C语言中的中断处理
- 在标准C中不包含中断。许多编译开发商在标准C上增加了对中断的支持,提供新的关键字用于标示中断
服务程序(ISR),类似于__interrupt、#program interrupt - 当一个函数被定义为ISR的时候,编译器会自动为该函数增加中断服务程序所需要的中断现场入栈和出栈代码
用C编写的中断服务程序应该注意的
- 不能返回值;
- 不能向ISR传递参数;
- ISR应该尽可能的短小精悍;
- printf(char *lpFormatString,...)函数会带来重入和性能问题题,不能再ISR中采用。(在ARM平台上由于半主机机制,该函数的速度更慢!)
- 其实还包括所有的不可重入的函数都不应该在中断中使用。程序员应该仔细地评估ANSI C库函数和OS的系统调用
- 浮点运算以及其他的消耗时间操作都不应该在中断服务程序中使用
加快中断处理程序的方法
- 在中断处理程序中只进行最基本的硬件操作,比如读出硬件寄存器的数据,或者改变状态寄存器的值
- 然后通过一定的方法将中断的事件做一个标志,在离开中断处理程序后,由其他代码根据中断标志进行后续的处理
这样做的好处是大大加快了中断的处理时间,常见的方法:
在没有OS的情况下可以使用自定义的队列,在中断处理程序之外的主循环中对中断事件进行处理。
Linux下的Bottom half & Top half
ASIX OS中的系统任务
没有OS的中断服务队列
/*存放中断的队列*/ typedef struct tagIntQueue { int intType;/*中断类型*/ struct tagIntQueue *next; }IntQueue; IntQueue lpIntQueueHead; __interrupt ISRexample() { int intType; intType = GetSystemType(); QueueAddTail(lpIntQueueHead);//新的中断 } while(1)//在主循环中检查中断并处理之 { if(!IsIntQueueEmpty()) { intType = GetFirstInt(); switch(intType)/*是不是很像WIN32程序的消息解析函数*/ { /*对,我们的中断类型解析很类似于消息驱动*/ case xxx:/*我们中其位“中断驱动”吧?*/ ... break; case xxx: ... break; ... } } }
有OS的情况下中断将变得更复杂
- 一般而言OS将接管中断向量表,中断发生时,首先由OS接管中断
- OS将检查真正的中断源是什么,然后才用真正的中断处理程序
通知内核!
- 为了通知中断的发生,往往需要在用户的中断服务程序中显示地调用OS提供的系统调用
- Ent_int()通知内核我们现在中断中
- Ret_int()通知内核我们离开中断了,如果系统允许则进行调度,否则按照中断放的方式离开-返回