中断与异常详解(三)

再次梳理会用到的一些数据结构和名词


中断向量表(中断描述符表)


idt_table


全局,8字节64位,从低到高位16位段选择符,32位偏移量,16位状态信息


256项


起始地址在内核数据节的idt中

用于寻找各种门,门的作用是防止用户程序访问陷阱门、中断门等特殊资源,出于安全考虑,linux为用户留有3,4,5,128号系统调用门供用户使用


中断描述符表寄存器


IDTR


寄存器,6字节48位,低16位界限,高32位基址


1项


用于快速寻找中断描述符,linux定义的16位界限为8*256-1,即使用了2048字节来存储中断向量表;32位基址就是idt地址,整个48位内容在内存的位置为idt地址-2


中断服务程序数组


Irq_desc


全局,20字节160位,5个unsigned int


224项


中断线状态status,中断控制器描述符hw_irq_controller和中断服务例程链表irqaction,中断嵌套depth和多cpu锁lock,通过这些信息可以对中断线进行管理


中断服务例程描述符


irqaction


结构体,24字节,6个32位


用于挂载到中断线服务例程链表上的结构体,真正的对中断进行个性化处理,也是设备驱动程序主要实现内容


现场寄存器结构


pt_regs


函数参数,60字节,15个32位


通常作为中断或异常处理程序的参数,这些函数前面通常有asmlinkage,通过栈传参数,即第一个参数就是ESP

《深入分析linux内核》一书74页对request_irq()函数解释为“将对应的中断服务例程挂入中断请求队列”,我产生了一些误解,个人认为解释为“请求将中断服务例程挂入中断服务队列(单链表)”更好理解一点,因为内核初始化挂载中断服务例程都是直接操作断服务例程的指针的,服务例程在内核而且肯定存在内存,所以不用管这些,但其他设备初始化的时候,挂载操作就需要严格要求,比如全局唯一div_id,中断号大小,申请空间存储中断服务例程指针等都需要确认,所以需要先请求,这也就是对挂载操作封装一层request_irq()的原因吧,所以只留一个中断服务队列的说法,请求队列容易误解。

接下来就说说do_irq()

asmlinkage unsigned int do_IRQ(struct pt_regs regs)

{


/*


* We ack quickly, we don‘t want the irq controller


* thinking we‘re snobs just because some other CPU has


* disabled global interrupts (we have already done the


* INT_ACK cycles, it‘s too late to try to pretend to the


* controller that we aren‘t taking the interrupt).


*


* 0 return value means that this irq is already being


* handled by some other CPU. (or is disabled)


*/


int irq = regs.orig_eax & 0xff;


/* high bits used in ret_from_ code  */因为之前压栈压的irq-256,所以这里需要& 0xff来恢复,真是神奇,&可以这样用,irq在0-223之间


int cpu = smp_processor_id();


获取cpu号


irq_desc_t *desc = irq_desc + irq;


获取中断服务描述符(中断服务程序)的入口,不是中断服务例程描述符哦


struct irqaction * action;


unsigned int status;


kstat.irqs[cpu][irq]++;


记录中断请求次数


spin_lock(&desc->lock);


锁cpu,中断设计成单cpu不可重入,因而一条中断线在一个时间点只能由一个cpu来处理


desc->handler->ack(irq);


对中断请求给予确认,也不知道确认什么,8259A控制器里面都没这个函数。。


/*


REPLAY is when Linux resends an IRQ that was dropped earlier


WAITING is used by probe to mark irqs that are being tested


*/


status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);


设置状态为未删除,非探测,因为是由硬件真正发出的中断请求


status |= IRQ_PENDING;


/* we _want_ to handle it */接受中断,并准备处理


/*


* If the IRQ is disabled for whatever reason, we cannot


* use the action we have.


*/


action = NULL;


中断服务例程队列(单链表)初始为空


if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {


如果不是中断线被禁用或者有中断服务例程正在处理


action = desc->action;


获得中断服务例程队列


status &= ~IRQ_PENDING;


/* we commit to handling */提交处理


status |= IRQ_INPROGRESS;


/* we are handling it */开始处理


}


desc->status = status;


更新中断线状态


/*


* If there is no IRQ handler or it was disabled, exit early.


Since we set PENDING, if another processor is handling


a different instance of this same irq, the other processor


will take care of it.


*/


if (!action)


如果获取中断服务队列失败


goto out;


退出


/*


* Edge triggered interrupts need to remember


* pending events.


* This applies to any hw interrupts that allow a second


* instance of the same irq to arrive while we are in do_IRQ


* or in the handler. But the code here only handles the _second_


* instance of the irq, not the third or fourth. So it is mostly


* useful for irq hardware that does not mask cleanly in an


* SMP environment.


*/


for (;;) {


循环


spin_unlock(&desc->lock);


释放多cpu锁,但此时中断线状态是IRQ_INPROGRESS,所以即使其他cpu无法获取当前中断线的中断服务例程队列,而且此时应该是关中断状态吧,这里有些疑问


handle_IRQ_event(irq, &regs, action);


中断服务例程队列对中断进行处理,就是让队列里的每个例程都去试着处理一下


spin_lock(&desc->lock);


获取多cpu锁,由于上面的中断服务例程处理会先关中断,然后再开中断,就有可能在关中断后获取锁之前再发生一次中断,也就是中断嵌套,虽然这应该尽量避免。但不理解的是即使这条中断线再次发生中断,也因为status为IRQ_INPROCESS而无法设置status为IRQ_PENDING啊,难道是怕驱动程序设置这个status?反正操作系统为我们考虑很全面了,有嵌套也能在这儿串行执行


if (!(desc->status & IRQ_PENDING))


再检测中断线是否有中断请求,如果没有嵌套


break;


退出


desc->status &= ~IRQ_PENDING;


提交请求


}


再次处理中断


desc->status &= ~IRQ_INPROGRESS;


恢复中断线为没有中断例程正在服务状态

out:


/*


* The ->end() handler has to deal with interrupts which got


中断控制器的end()函数需要处理自身被打


* disabled while the handler was running.


断的特殊情形


*/


desc->handler->end(irq);


不明,根据标志位是否启用中断线吧?


spin_unlock(&desc->lock);


释放多cpu锁


if (softirq_pending(cpu))


不明,64位cpu才有的数据结构


do_softirq();


处理软中断


return 1;

}

时间: 2024-10-01 06:42:17

中断与异常详解(三)的相关文章

中断与异常详解(二)

中断或异常发生之前 当 CPU 执行了当前指令之后,CS 和 EIP 这对寄存器中所包含的内容就是下一条将要执行 指令的逻辑地址.在对下一条指令执行前,CPU 先要判断在执行当前指令的过程中是否发生 了中断或异常. 如果发生了一个中断或异常 那么 CPU 将做以下事情 • 确定所发生中断或异常的向量i(在 0-255 之间). • 通过 IDTR 寄存器找到 IDT 表,读取 IDT 表第i项(或叫第i个门). • 分两步进行有效性检查:首先是“段”级检查,将 CPU 的当前特权级 CPL(存放

中断与异常详解(五)

随着看的东西的增多,之前不明白的地方也开始有了眉目,所以更新前几节的东西,欢迎指正.想想马上就中断返回,进入进程描述了,还是挺激动的呢. 不得不推荐一篇写得很好的文章<spinlock的剖析与改进> http://www.searchtb.com/2011/06/spinlock%E5%89%96%E6%9E%90%E4%B8%8E%E6%94%B9%E8%BF%9B.html 中断向量表多达256项 虽然默认使用的只有49条,但很明显中断服务程序必须支持SMP,这也是在第三节为什么在 han

java异常详解

1. java中throw和throws:throw用在方法内部实际抛出异常的时候:throws用在方法头部(参数后面,方法体前面). public class Test{ public static void main(String[] args) { try { f(); } catch(NoSuchMethodException e) { System.out.println("test2"); } //用try-catch捕获并处理之后,后面的语句可以正常执行 System.o

java笔记--异常详解与处理

一.异常概念 Throwable类是Java中所有错误或异常的超类. 1.只有当对象是此类(或其子类)的实例时,才能通过Java虚拟机或着Java throw语句抛出.     2.只有此类或其子类才可以是catch字句中的参数类型.     3.有两个直接子类:Error和Exception         Error--指应用程序不应该去处理捕获的一种严重问题,常表示系统级的错误,如内存溢出        Exception--指程序需要捕获,需要处理的异常,是一种设计或实现方面的问题.  

spark2.x由浅入深深到底系列六之RDD java api详解三

学习任何spark知识点之前请先正确理解spark,可以参考:正确理解spark 本文详细介绍了spark key-value类型的rdd java api 一.key-value类型的RDD的创建方式 1.sparkContext.parallelizePairs JavaPairRDD<String, Integer> javaPairRDD =         sc.parallelizePairs(Arrays.asList(new Tuple2("test", 3

php学习之道:WSDL详解(三)

通过声明方式定义绑定(binding)属性 如果你在服务中采用SOAP binding,你可以使用JAX-WS来指定一定数量的属性binding.这些属性指定对应你在WSDL中指定的属性.某些设置,比如参数类型,可以约束你实现的方法,这些设置也影响声明的效用. @SOAPBinding声明,定义在javax.jws.soap.SOAPBinding接口中.它提供发布时的SOAP Binding细节.如果@SOAPBinding没有被指定,则用缺省的doc/literal SOAPBinding.

UINavigationController详解三(转)ToolBar

原文出自:http://blog.csdn.net/totogo2010/article/details/7682641,特别感谢. 1.显示Toolbar  在RootViewController.m的- (void)viewDidLoad方法中添加代码,这样Toobar就显示出来了. [cpp] view plaincopy [self.navigationController  setToolbarHidden:NO animated:YES]; 2.在ToolBar上添加UIBarBut

logback -- 配置详解 -- 三 -- &lt;encoder&gt;

附: logback.xml实例 logback -- 配置详解 -- 一 -- <configuration>及子节点 logback -- 配置详解 -- 二 -- <appender> logback -- 配置详解 -- 三 -- <encoder> logback -- 配置详解 -- 四 -- <filter> -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

Android基础入门教程——8.3.6 Paint API之—— Xfermode与PorterDuff详解(三)

Android基础入门教程--8.3.6 Paint API之-- Xfermode与PorterDuff详解(三) 标签(空格分隔): Android基础入门教程 本节引言: 上一节,我们学习了Xfermode中的三儿子:PorterDuffXfermode构造方法中的为一个参数: PorterDuff.Mode,我们在观看了16种图片混排模式后,又自己写代码来验证了一下文档中 18种不同的混排模式,18种是新增了ADD和OVERLAY两种模式!当然,仅仅验证知道是不够的, 本节我们来写个例子