深入剖析Linux中断机制_第1页
深入剖析Linux中断机制_第2页
深入剖析Linux中断机制_第3页
深入剖析Linux中断机制_第4页
深入剖析Linux中断机制_第5页
已阅读5页,还剩42页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、深入剖析Linux中断机制中断概述【摘要】本文详解了Linux内核的中断实现机制。首先介绍了中断的一些基本概念,然后分析了面向对象的Linux中断的组织形式、三种主要数据结构及其之间的关系。随后介绍了Linux处理异常和中断的基本流程,在此基础上分析了中断处理的详细流程,包括保存现场、中断处理、中断退出时的软中断执行及中断返回时的进程切换等问题。最后介绍了中断相关的API,包括中断注册和释放、中断关闭和使能、如何编写中断ISR、共享中断、中断上下文中断状态等。【关键字】中断,异常,hw_interrupt_type,irq_desc_t,irqaction,asm_do_IRQ,软中断,进程切

2、换,中断注册释放request_irq,free_irq,共享中断,可重入,中断上下文1 中断概述1.1 为什么需要中断?处理器的速度跟外围硬件设备的速度往往不在一个数量级上,因此,如果内核采取让处理器向硬件发出一个请求,然后专门等待回应的办法,显然差强人意。既然硬件的响应这么慢,那么内核就应该在此期间处理其他事务,等到硬件真正完成了请求的操作之后,再回过头来对它进行处理。想要实现这种功能,轮询(polling可能会是一种解决办法。可以让内核定期对设备的状态进行查询,然后做出相应的处理。不过这种方法很可能会让内核做不少无用功,因为无论硬件设备是正在忙碌着完成任务还是已经大功告成,轮询总会周期性

3、地重复执行。更好的办法是由我们来提供一种机制,让硬件在需要的时候再向内核发出信号(变内核主动为硬件主动。这就是中断机制。1.2 中断的表示形式硬件设备生成中断的时候并不考虑与处理器的时钟同步换句话说就是中断随时可以产生。因此,内核随时可能因为新到来的中断而被打断。从物理学的角度看,中断是一种电信号,由硬件设备生成,并直接送入中断控制器的输入引脚上。然后再由中断控制器向处理器发送相应的信号。处理器一经检测到此信号,便中断自己的当前工作转而处理中断。此后,处理器会通知操作系统已经产生中断,这样,操作系统就可以对这个中断进行适当的处理了。不同的设备对应的中断不同,而每个中断都通过一个惟一的数字标识。

4、因此,来自键盘的中断就有别干来自硬盘的中断,从而使得操作系统能够对中断进行区分,并知道哪个硬件设备产生了哪个中断。这样,操作系统才能给不同的中断提供不同的中断处理程序。这些中断值通常被为中断请求(IRQ线。通常IRQ都是一些数值量。例如在PC上,IRQ0是时钟中断,而IRQ 1是键盘中断。但并非所有的中断号都是这样严格定义的。例如,对于连接在PCI总线上的设备而言,中断是动态分配的。而在嵌入式系统中,由于中断线有限,一般外设和中断都是一一匹配的,很少有动态分配中断的。不管怎样,重点在于特定的中断总是与特定的设备相关联,并且内核要知道这些信息。1.3 异常在操作系统中,讨论中断就不能不提及异常。

5、广义的中断可分为同步(synchronous)中断和异步(asynchronous)中断:同步中断:是当指令执行时由 CPU 控制单元产生,之所以称为同步,是因为只有在一条指令执行完毕后 CPU 才会发出中断,而不是发生在代码指令执行期间,比如系统调用。异步中断:是指由其他硬件设备依照 CPU 时钟信号随机产生,即意味着中断能够在指令之间发生,例如键盘中断。一般由处理器本身产生的同步中断称为异常(exception),异步中断被称为中断(interrupt)。中断可分为可屏蔽中断(Maskable interrupt)和非屏蔽中断(Nomaskable interrupt)。异常可分为故障(f

6、ault)、陷阱(trap)、终止(abort)三类。表 1:中断类别及其行为类别原因异步/同步返回行为中断来自I/O设备的信号异步总是返回到下一条指令陷阱有意的异常同步总是返回到下一条指令故障潜在可恢复的错误同步返回到当前指令终止不可恢复的错误同步不会返回在处理器执行到由于编程失误而导致的错误指令(例如被0除的时候,或者是在执行期间出现特殊情况(例如缺页,必须靠内核来处理的时候,处理器就会产生一个异常。因为许多处理器体系结构处理异常与处理中断的方式类似,因此,内核对它们的处理也很类似。通过软中断实现系统调用,那就是陷人内核,然后引起一种特殊的异常系统调用处理程序异常。你将会看到,中断的工作方

7、式与之类似,其差异只在于中断是由硬件而不是软件引起的。1.4 中断处理程序在响应一个特定中断的时候,内核会执行一个函数,该函数叫做中断处理程序(interrupt handler或中断服务例程(interrupt service routine, ISR。产生中断的每个设备都有一个相应的中断处理程序。在Linux中,中断处理程序看起来就是普普通通的C函数。只不过这些函数必须按照特定的类型声明,以便内核能够以标准的方式传递处理程序的信息。中断处理程序与其他内核函数的真正区别在于:中断处理程序是被内核调用来响应中断的,而它们运行于我们称之为中断上下文的特殊上下文中。中断可能随时发生,因此中断处理程

8、序也就随时可能执行。所以必须保证中断处理程序能够快速执行,这样才能保证尽可能快地恢复中断代码的执行。因此,尽管对硬件而言,迅速对其中断进行服务非常重要,但对系统的其他部分而言,让中断处理程序在尽可能短的时间内完成运行也同样重要。即使是最精简版的中断服务程序,它也要与硬件进行交互,告诉该设备中断已被接收。我们可以考虑一下网络设备的中断处理程序面临的挑战。该处理程序除了要对硬件应答,还要把来自硬件的网络数据包拷贝到内存,对其进行处理后再交给合适的协议栈或应用程序。显而易见,这种工作量不会太小,尤其对于如今的千兆比特和万兆比特以太网卡而言。因此我们一般把中断处理切为两个部分或两半。中断处理程序是上半

9、部 (top half接收到一个中断,它就立即开始执行,但只做有严格时限的工作,例如对接收的中断进行应答或复位硬件,这些工作都是在所有中断被禁止的情况下完成的。能够被允许稍后完成的工作会推迟到下半部(bottom half去。此后,在合适的时机,下半部会被开中断执行。以网卡作为实例,当网卡接收流入网络的数据包时,需要通知内核数据包到了。网卡需要立即完成这件事,从而优化网络的吞吐量和传输周期,以避免超时。因此,网卡立即发出中断:嘀,内核,我这里有最新数据包了。内核通过执行网卡已注册的中断处理程序来做出应答。中断开始执行,应答硬件,拷贝最新的网络数据包到内存,然后读取网卡更多的数据包。这些都是重要

10、、紧迫而又与硬件相关的工作。处理和操作数据包的其他工作在随后的下半部中进行。深入剖析Linux中断机制之二Linux中断的组织形式【摘要】本文详解了Linux内核的中断实现机制。首先介绍了中断的一些基本概念,然后分析了面向对象的Linux中断的组织形式、三种主要数据结构及其之间的关系。随后介绍了Linux处理异常和中断的基本流程,在此基础上分析了中断处理的详细流程,包括保存现场、中断处理、中断退出时的软中断执行及中断返回时的进程切换等问题。最后介绍了中断相关的API,包括中断注册和释放、中断关闭和使能、如何编写中断ISR、共享中断、中断上下文中断状态等。【关键字】中断,异常,hw_interr

11、upt_type,irq_desc_t,irqaction,asm_do_IRQ,软中断,进程切换,中断注册释放request_irq,free_irq,共享中断,可重入,中断上下文1 Linux中断的组织形式1.1 IRQ描述符irq_desc对于每个IRQ中断线,Linux都用一个irq_desc_t数据结构来描述,我们把它叫做IRQ描述符,NR_IRQS个IRQ形成一个全局数组irq_desc,其定义在/include/linux/irq.h中:struct irq_desc 中断描述符148struct irq_desc 149 irq_flow_handler_t handle_ir

12、q;150 struct irq_chip *chip;151 void *handler_data;152 void *chip_data;153 struct irqaction *action; /* IRQ action list */154 unsigned int status; /* IRQ status */155156 unsigned int depth; /* nested irq disables */157 unsigned int wake_depth; /* nested wake enables */158 unsigned int irq_count; /*

13、For detecting broken IRQs */159 unsigned int irqs_unhandled;160 spinlock_t lock;161#ifdef CONFIG_SMP162 cpumask_t affinity;163 unsigned int cpu;164#endif171 const char *name;172 _cacheline_aligned;173174extern struct irq_desc irq_descNR_IRQS;handle_irq:上层的通用中断处理函数指针,如果未设置则默认为_do_IRQ(。通常针对电平触发或者边沿触发有

14、不同的处理函数。每个中断线可分别设置;chip:底层中断的各种控制访问方法集合,各个CPU实现的都不同,这属于面向对象的中断处理方式中最底层的一部分;handler_data:附加参数,用于handle_irq;chip_data:平台相关的附加参数,用于chip;action:指向一个单向链表的指针,这个链表就是对中断服务例程进行描述的irqaction结构;status:中断当前的状态;depth:中断关闭打开的层数。如果启用这条IRQ中断线,depth则为0,如果禁用这条IRQ中断线不止一次,则为一个正数。如果depth等于0,每当调用一次disable_irq( ,该函数就对这个域的值

15、加1,同时该函数就禁用这条IRQ中断线。相反,每当调用enable_irq( 函数时,该函数就对这个域的值减1;如果depth变为0,该函数就启用这条IRQ中断线。Lock:此中断描述符为全局共享暑假,对于SMP需要互斥访问Dir: /proc/irq/ 入口Name: /proc/interrupts 中显示的中断名称“_cacheline_aligned”表示这个数据结构的存放按32字节(高速缓存行的大小)进行对齐,以便于将来存放在高速缓存并容易存取157void _init init_IRQ(void158159 int irq;160161 for (irq = 0; irq <

16、 NR_IRQS; irq+162 irq_descirq.status |= IRQ_NOREQUEST | IRQ_DELAYED_DISABLE |163 IRQ_NOPROBE;164165#ifdef CONFIG_SMP166 bad_irq_desc.affinity = CPU_MASK_ALL;167 bad_irq_desc.cpu = smp_processor_id(;168#endif169 init_arch_irq(;1701.2 中断控制器描述符irq_chip 由于CPU不同,故每个处理器对于中断的处理方式不一样。Linux为了实现统一的中断处理,提供了底层的

17、中断处理抽象接口,对于每个平台都需要实现底层的接口函数。这样对于上层的中断通用处理程序就无需任何改动。struct irq_chip 片级的中断描述符94struct irq_chip 95 const char *name;96 unsigned int (*startup(unsigned int irq;97 void (*shutdown(unsigned int irq;98 void (*enable(unsigned int irq;99 void (*disable(unsigned int irq;100101 void (*ack(unsigned int irq;102

18、void (*mask(unsigned int irq;103 void (*mask_ack(unsigned int irq;104 void (*unmask(unsigned int irq;105 void (*eoi(unsigned int irq;106107 void (*end(unsigned int irq;108 void (*set_affinity(unsigned int irq, cpumask_t dest;109 int (*retrigger(unsigned int irq;110 int (*set_type(unsigned int irq, u

19、nsigned int flow_type;111 int (*set_wake(unsigned int irq, unsigned int on;121 const char *typename;122;Name:用于/proc/interruptsStartup:默认为enable if NULLShutdown:默认为 disable if NULLEnable:允许中断,默认为unmask if NULLDisable:禁止中断,默认为mask if NULLAck:响应一个中断Mask:mask 一个中断源,通常是关闭中断mask_ack:响应并mask中断源unmask:unma

20、sk中断源set_type:设置中断触发方式IRQ_TYPE_LEVEL大多数控制方法都是重复的,基本上只要有中断响应、中断屏蔽、中断开启、中断触发类型设置等方法就可以满足要求了。其他各种方法基本上和这些相同。提供了中断响应、打开、关闭、设置触发类型等底层方法的接口static struct irq_chip at91_aic_chip = .name = "AIC",.ack = at91_aic_mask_irq,.mask = at91_aic_mask_irq,.unmask = at91_aic_unmask_irq,.set_type = at91_aic_se

21、t_type,.set_wake = at91_aic_set_wake,;124/*125 * Initialize the AIC interrupt controller.126 */127void _init at91_aic_init(unsigned int priorityNR_AIC_IRQS128129 unsigned int i;130131 /*132 * The IVR is used by macro get_irqnr_and_base to read and verify.133 * The irq number is NR_AIC_IRQS when a sp

22、urious interrupt has occurred.134 */135 for (i = 0; i < NR_AIC_IRQS; i+ 136 /* Put irq number in Source Vector Register: */137 at91_sys_write(AT91_AIC_SVR(i, i;138 /* Active Low interrupt, with the specified priority */139 at91_sys_write(AT91_AIC_SMR(i, AT91_AIC_SRCTYPE_LOW | priorityi;140141 set

23、_irq_chip(i, &at91_aic_chip;142 set_irq_handler(i, do_level_IRQ;143 set_irq_flags(i, IRQF_VALID | IRQF_PROBE;144145 /* Perform 8 End Of Interrupt Command to make sure AIC will not Lock out nIRQ */146 if (i < 8147 at91_sys_write(AT91_AIC_EOICR, 0;148 149150 /*151 * Spurious Interrupt ID in Spu

24、rious Vector Register is NR_AIC_IRQS152 * When there is no current interrupt, the IRQ Vector Register reads the value stored in AIC_SPU153 */154 at91_sys_write(AT91_AIC_SPU, NR_AIC_IRQS;155156 /* No debugging in AIC: Debug (Protect Control Register */157 at91_sys_write(AT91_AIC_DCR, 0;158159 /* Disa

25、ble and clear all interrupts initially */160 at91_sys_write(AT91_AIC_IDCR, 0xFFFFFFFF;161 at91_sys_write(AT91_AIC_ICCR, 0xFFFFFFFF;162163以下这些宏定义都是为保持兼容性而设置的,后续版本中将彻底删除47#define do_level_IRQ handle_level_irq48#define do_edge_IRQ handle_edge_irq49#define do_simple_IRQ handle_simple_irq50#define irqdes

26、c irq_desc51#define irqchip irq_chip55#define SA_INTERRUPT IRQF_DISABLED57#define SA_SHIRQ IRQF_SHARED6061#define SA_TRIGGER_LOW IRQF_TRIGGER_LOW62#define SA_TRIGGER_HIGH IRQF_TRIGGER_HIGH63#define SA_TRIGGER_FALLING IRQF_TRIGGER_FALLING64#define SA_TRIGGER_RISING IRQF_TRIGGER_RISING65#define SA_TRI

27、GGER_MASK IRQF_TRIGGER_MASKlinux/kernel/irq/chip.chandle_level_irq1.3 中断服务例程描述符irqaction在IRQ描述符中我们看到指针action的结构为irqaction,它是为多个设备能共享一条中断线而设置的一个数据结构,代表了每个注册中断对应的信息。在include/linux/interrupt.h中定义如下:67typedef irqreturn_t (*irq_handler_t(int, void *;6869struct irqaction 70 irq_handler_t handler;71 unsign

28、ed long flags;72 cpumask_t mask;73 const char *name;74 void *dev_id;75 struct irqaction *next;76 int irq;77 struct proc_dir_entry *dir;78;Handler:指向一个具体I/O设备的中断服务例程。这是允许多个设备共享同一中断线的关键域,中断线可以相同,但处理函数可以不一样。Flags:用一组标志描述中断线与I/O设备之间的关系。SA_INTERRUPT 中断处理程序必须以禁用中断来执行。此标志表明给定的中断处理程序是一个快速中断处理程序(fast interru

29、pt handler。过去,Linux将中断处理程序分为快速和慢速两种。那些可以迅速执行但调用频率可能会很高的中断服务程序,会被贴上这样的标签。通常这样做需要修改中断处理程序的行为,使它们能够尽可能快地执行。现在,加不加此标志的区别只剩下一条了:在本地处理器上,快速中断处理程序在禁止所有中断的情况下运行。这使得快速中断处理程序能够不受其他中断干扰,得以迅速执行。而默认情况下(没有这个标志,除了正运行的中断处理程序对应的那条中断线被屏蔽外,其他所有中断都是激活的。除了时钟中断外,绝大多数中断都不使用该标志。SA_SHIRQ 此标志表明可以在多个中断处理程序之间共享中断线。在同一个给定线上注册的每

30、个处理程序必须指定这个标志:否则,在每条线上只能有一个处理程序。各项该中断线的每一个例程都需要设置此标志。Name:I/O设备名(通过读取/proc/interrupts文件,可以看到,在列出中断号时也显示设备名。)dev_id:对于共享中断,此特定值用来区分各中断。当一个中断处理程序需要释放时,dev_id将提供惟一的标志信息(cookie,以便从共享中断线的诸多中断处理程序中删除指定的那一个。如果没有这个参数,那么内核不可能知道在给定的中断线上到底要删除哪一个处理程序。如果无需共享中断线,那么将该参数赋为空值(NULL就可以了,但是,如果中断线是被共享的,那么就必须传递惟一的信息。另外,内

31、核每次调用中断处理程序时,都会把这个指针传递给它。实践中往往会通过它传递驱动程序的设备结构:这个指针是惟一的,而且有可能在中断处理程序内及设备模式中被用到。Next:指向irqaction描述符链表的下一个元素。共享同一中断线的每个硬件设备都有其对应的中断服务例程,链表中的每个元素就是对相应设备及中断服务例程的描述。Irq:对应的中断号dir:proc文件系统对应的入口1.4 三者的关系三个主要的数据结构包含了与 IRQ 相关的所有信息:hw_interrupt_type、irq_desc_t 和 irqaction,下图解释了它们之间是如何关联的。中断服务例程ISR是irqaction 的H

32、andler成员。中断的处理是一种面向对象的机制,通过三个数据结果实现了三层结构,底层是和具体硬件相关的中断处理响应等,中间层是统一的中断处理流程,最上层是特定的中断处理例程。IRQ 结构之间的关系深入剖析Linux中断机制之三Linux对异常和中断的处理Sailor_forever sailing_9806 转载请注明【摘要】本文详解了Linux内核的中断实现机制。首先介绍了中断的一些基本概念,然后分析了面向对象的Linux中断的组织形式、三种主要数据结构及其之间的关系。随后介绍了Linux处理异常和中断的基本流程,在此基础上分析了中断处理的详细流程,包括保存现场、中断处理、中断退出时的软中

33、断执行及中断返回时的进程切换等问题。最后介绍了中断相关的API,包括中断注册和释放、中断关闭和使能、如何编写中断ISR、共享中断、中断上下文中断状态等。【关键字】中断,异常,hw_interrupt_type,irq_desc_t,irqaction,asm_do_IRQ,软中断,进程切换,中断注册释放request_irq,free_irq,共享中断,可重入,中断上下文1 Linux对异常和中断的处理1.1 异常处理Linux利用异常来达到两个截然不同的目的:² 给进程发送一个信号以通报一个反常情况² 管理硬件资源对于第一种情况,例如,如果进程执行了一个被0除的操作,CP

34、U则会产生一个“除法错误”异常,并由相应的异常处理程序向当前进程发送一个SIGFPE信号。当前进程接收到这个信号后,就要采取若干必要的步骤,或者从错误中恢复,或者终止执行(如果这个信号没有相应的信号处理程序)。内核对异常处理程序的调用有一个标准的结构,它由以下三部分组成:² 在内核栈中保存大多数寄存器的内容(由汇编语言实现)² 调用C编写的异常处理函数² 通过ret_from_exception(函数从异常退出。1.2 中断处理当一个中断发生时,并不是所有的操作都具有相同的急迫性。事实上,把所有的操作都放进中断处理程序本身并不合适。需要时间长的、非重要的操作应该推

35、后,因为当一个中断处理程序正在运行时,相应的IRQ中断线上再发出的信号就会被忽略。另外中断处理程序不能执行任何阻塞过程,如I/O设备操作。因此,Linux把一个中断要执行的操作分为下面的三类:² 紧急的(Critical)这样的操作诸如:中断到来时中断控制器做出应答,对中断控制器或设备控制器重新编程,或者对设备和处理器同时访问的数据结构进行修改。这些操作都是紧急的,应该被很快地执行,也就是说,紧急操作应该在一个中断处理程序内立即执行,而且是在禁用中断的状态下。² 非紧急的(Noncritical)这样的操作如修改那些只有处理器才会访问的数据结构(例如,按下一个键后,读扫描码

36、)。这些操作也要很快地完成,因此,它们由中断处理程序立即执行,但在启用中断的状态下。² 非紧急可延迟的(Noncritical deferrable)这样的操作如,把一个缓冲区的内容拷贝到一些进程的地址空间(例如,把键盘行缓冲区的内容发送到终端处理程序的进程)。这些操作可能被延迟较长的时间间隔而不影响内核操作,有兴趣的进程会等待需要的数据。所有的中断处理程序都执行四个基本的操作:² 在内核栈中保存IRQ的值和寄存器的内容。² 给与IRQ中断线相连的中断控制器发送一个应答,这将允许在这条中断线上进一步发出中断请求。² 执行共享这个IRQ的所有设备的中断服务

37、例程(ISR)。² 跳到ret_to_usr( 的地址后终止。1.3 中断处理程序的执行流程现在,我们可以从中断请求的发生到CPU的响应,再到中断处理程序的调用和返回,沿着这一思路走一遍,以体会Linux内核对中断的响应及处理。假定外设的驱动程序都已完成了初始化工作,并且已把相应的中断服务例程挂入到特定的中断请求队列。又假定当前进程正在用户空间运行(随时可以接受中断),且外设已产生了一次中断请求,CPU就在执行完当前指令后来响应该中断。中断处理系统在Linux中的实现是非常依赖于体系结构的,实现依赖于处理器、所使用的中断控制器的类型、体系结构的设计及机器本身。设备产生中断,通过总线把

38、电信号发送给中断控制器。如果中断线是激活的,那么中断控制器就会把中断发往处理器。在大多数体系结构中,这个工作就是通过电信号给处理器的特定管脚发送一个信号。除非在处理器上禁止该中断,否则,处理器会立即停止它正在做的事,关闭中断系统,然后跳到内存中预定义的位置开始执行那里的代码。这个预定义的位置是由内核设置的,是中断处理程序的入口点。对于ARM系统来说,有个专用的IRQ运行模式,有一个统一的入口地址。假定中断发生时CPU运行在用户空间,而中断处理程序属于内核空间,因此,要进行堆栈的切换。也就是说,CPU从TSS中取出内核栈指针,并切换到内核栈(此时栈还为空)。若当前处于内核空间时,对于ARM系统来

39、说是处于SVC模式,此时产生中断,中断处理完毕后,若是可剥夺内核,则检查是否需要进行进程调度,否则直接返回到被中断的内核空间;若需要进行进程调度,则svc_preempt,进程切换。190 .align 5191_irq_svc:192 svc_entry197#ifdef CONFIG_PREEMPT198 get_thread_info tsk199 ldr r8, tsk, #TI_PREEMPT get preempt count200 add r7, r8, #1 increment it201 str r7, tsk, #TI_PREEMPT202#endif203204 irq_

40、handler205#ifdef CONFIG_PREEMPT206 ldr r0, tsk, #TI_FLAGS get flags207 tst r0, #_TIF_NEED_RESCHED208 blne svc_preempt209preempt_return:210 ldr r0, tsk, #TI_PREEMPT read preempt value211 str r8, tsk, #TI_PREEMPT restore preempt count212 teq r0, r7213 strne r0, r0, -r0 bug(214#endif215 ldr r0, sp, #S_

41、PSR irqs are already disabled216 msr spsr_cxsf, r0221 ldmia sp, r0 - pc load r0 - pc, cpsr222223 .ltorg当前处于用户空间时,对于ARM系统来说是处于USR模式,此时产生中断,中断处理完毕后,无论是否是可剥夺内核,都调转到统一的用户模式出口ret_to_user,其检查是否需要进行进程调度,若需要进行进程调度,则进程切换,否则直接返回到被中断的用户空间。404 .align 5405_irq_usr:406 usr_entry407411 get_thread_info tsk412#ifdef

42、 CONFIG_PREEMPT413 ldr r8, tsk, #TI_PREEMPT get preempt count414 add r7, r8, #1 increment it415 str r7, tsk, #TI_PREEMPT416#endif417418 irq_handler419#ifdef CONFIG_PREEMPT420 ldr r0, tsk, #TI_PREEMPT421 str r8, tsk, #TI_PREEMPT422 teq r0, r7423 strne r0, r0, -r0 bug(424#endif428429 mov why, #0430 b

43、ret_to_user432 .ltorg105/*106 * SVC mode handlers107 */108115 .macro svc_entry116 sub sp, sp, #S_FRAME_SIZE117 SPFIX( tst sp, #4 118 SPFIX( bicne sp, sp, #4 119 stmib sp, r1 - r12120121 ldmia r0, r1 - r3122 add r5, sp, #S_SP here for interlock avoidance123 mov r4, #-1 "" "" "

44、;" ""124 add r0, sp, #S_FRAME_SIZE "" "" "" ""125 SPFIX( addne r0, r0, #4 126 str r1, sp save the "real" r0 copied127 from the exception stack128129 mov r1, lr130131 132 We are now ready to fill in the remaining blanks on the stack:133

45、 134 r0 - sp_svc135 r1 - lr_svc136 r2 - lr_ , already fixed up for correct return/restart 137 r3 - spsr_ 138 r4 - orig_r0 (see pt_regs definition in ptrace.h139 140 stmia r5, r0 - r4141 .endm因为C的调用惯例是要把函数参数放在栈的顶部,因此pt- regs结构包含原始寄存器的值,这些值是以前在汇编入口例程svc_entry中保存在栈中的。18 .macro get_irqnr_and_base, irqnr

46、, irqstat, base, tmp19 ldr base, =(AT91_VA_BASE_SYS base virtual address of SYS peripherals20 ldr irqnr, base, #AT91_AIC_IVR read IRQ vector register: de-asserts nIRQ to processor (and clears interrupt21 ldr irqstat, base, #AT91_AIC_ISR read interrupt source number22 teq irqstat, #0 ISR is 0 when no

47、 current interrupt, or spurious interrupt23 streq tmp, base, #AT91_AIC_EOICR not going to be handled further, then ACK it now.24 .endm26/*27 * Interrupt handling. Preserves r7, r8, r928 */29 .macro irq_handler301: get_irqnr_and_base r0, r6, r5, lr31 movne r1, sp32 33 routine called with r0 = irq num

48、ber, r1 = struct pt_regs *34 35 adrne lr, 1b36 bne asm_do_IRQ58 .endm中断号的值也在irq_handler初期得以保存,所以,asm_do_IRQ可以将它提取出来。这个中断处理程序实际上要调用do_IRQ(,而do_IRQ(要调用handle_IRQ_event(函数,最后这个函数才真正地执行中断服务例程(ISR)。下图给出它们的调用关系:asm_do_IRQdo_IRQ(handle_IRQ_event(中断服务例程1例程中断服务例程2例程中断处理函数的调用关系112asmlinkage void asm_do_IRQ(un

49、signed int irq, struct pt_regs *regs113114 struct pt_regs *old_regs = set_irq_regs(regs;115 struct irqdesc *desc = irq_desc + irq;116121 if (irq >= NR_IRQS122 desc = &bad_irq_desc;123124 irq_enter(; /记录硬件中断状态,便于跟踪中断情况确定是否是中断上下文125126 desc_handle_irq(irq, desc;/desc_handle_irq33static inline v

50、oid desc_handle_irq(unsigned int irq, struct irq_desc *desc3435 desc->handle_irq(irq, desc; /通常handle_irq指向_do_IRQ36/desc_handle_irq130131 irq_exit(; /中断退出前执行可能的软中断,被中断前是在中断上下文中则直接退出,这保证了软中断不会嵌套132 set_irq_regs(old_regs;133157 * _do_IRQ - original all in one highlevel IRQ handler167fastcall unsig

51、ned int _do_IRQ(unsigned int irq168169 struct irq_desc *desc = irq_desc + irq;170 struct irqaction *action;171 unsigned int status;172173 kstat_this_cpu.irqsirq+;186187 spin_lock(&desc->lock;188 if (desc->chip->ack /首先响应中断,通常实现为关闭本中断线189 desc->chip->ack(irq;190 194 status = desc-&

52、gt;status & (IRQ_REPLAY | IRQ_WAITING;195 status |= IRQ_PENDING; /* we _want_ to handle it */196201 action = NULL;202 if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS 203 action = desc->action;204 status &= IRQ_PENDING; /* we commit to handling */205 status |= IRQ_INPROGRESS; /* w

53、e are handling it */206 207 desc->status = status;208215 if (unlikely(!action216 goto out;217218 /*219 * Edge triggered interrupts need to remember220 * pending events.227 */228 for (; 229 irqreturn_t action_ret;230231 spin_unlock(&desc->lock;/解锁,中断处理期间可以响应其他中断,否则再次进入_do_IRQ时会死锁233 action_

54、ret = handle_IRQ_event(irq, action;237 spin_lock(&desc->lock;238 if (likely(!(desc->status & IRQ_PENDING239 break;240 desc->status &= IRQ_PENDING;241 242 desc->status &= IRQ_INPROGRESS;243244out:249 desc->chip->end(irq;250 spin_unlock(&desc->lock;251252 retur

55、n 1;253该函数的实现用到中断线的状态,下面给予具体说明:#define IRQ_INPROGRESS 1 /* 正在执行这个IRQ的一个处理程序*/#define IRQ_DISABLED 2 /* 由设备驱动程序已经禁用了这条IRQ中断线 */#define IRQ_PENDING 4 /* 一个IRQ已经出现在中断线上,且被应答,但还没有为它提供服务 */#define IRQ_REPLAY 8 /* 当Linux重新发送一个已被删除的IRQ时 */#define IRQ_WAITING 32 /*当对硬件设备进行探测时,设置这个状态以标记正在被测试的irq */#define IR

56、Q_LEVEL 64 /* IRQ level triggered */#define IRQ_MASKED 128 /* IRQ masked - shouldn't be seen again */#define IRQ_PER_CPU 256 /* IRQ is per CPU */这8个状态的前5个状态比较常用,因此我们给出了具体解释。经验表明,应该避免在同一条中断线上的中断嵌套,内核通过IRQ_PENDING标志位的应用保证了这一点。当do_IRQ(执行到for (;循环时,desc->status 中的IRQ_PENDING的标志位肯定为0。当CPU执行完handle_IRQ_event(函数返回时,如果这个标志位仍然为0,那么循环就此结束。如果这个标志位变为1,那就说明这条中断线上又有中断产生(对单CPU而言),所以循环又执行一次。通过这种循环方式,就把可能发生在同一中断线上的嵌套循环化解为“串行”。在循环结束后调用desc->handler->end(函数,具体来说,如果没有设置IRQ_DISABLED标志位,就启用这条中断线。当

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论