您好,欢迎访问三七文档
当前位置:首页 > IT计算机/网络 > 其它相关文档 > 深入剖析Linux中断机制
深入剖析Linux中断机制--中断概述【摘要】本文详解了Linux内核的中断实现机制。首先介绍了中断的一些基本概念,然后分析了面向对象的Linux中断的组织形式、三种主要数据结构及其之间的关系。随后介绍了Linux处理异常和中断的基本流程,在此基础上分析了中断处理的详细流程,包括保存现场、中断处理、中断退出时的软中断执行及中断返回时的进程切换等问题。最后介绍了中断相关的API,包括中断注册和释放、中断关闭和使能、如何编写中断ISR、共享中断、中断上下文中断状态等。【关键字】中断,异常,hw_interrupt_type,irq_desc_t,irqaction,asm_do_IRQ,软中断,进程切换,中断注册释放request_irq,free_irq,共享中断,可重入,中断上下文1中断概述1.1为什么需要中断?处理器的速度跟外围硬件设备的速度往往不在一个数量级上,因此,如果内核采取让处理器向硬件发出一个请求,然后专门等待回应的办法,显然差强人意。既然硬件的响应这么慢,那么内核就应该在此期间处理其他事务,等到硬件真正完成了请求的操作之后,再回过头来对它进行处理。想要实现这种功能,轮询(polling)可能会是一种解决办法。可以让内核定期对设备的状态进行查询,然后做出相应的处理。不过这种方法很可能会让内核做不少无用功,因为无论硬件设备是正在忙碌着完成任务还是已经大功告成,轮询总会周期性地重复执行。更好的办法是由我们来提供一种机制,让硬件在需要的时候再向内核发出信号(变内核主动为硬件主动)。这就是中断机制。1.2中断的表示形式硬件设备生成中断的时候并不考虑与处理器的时钟同步—换句话说就是中断随时可以产生。因此,内核随时可能因为新到来的中断而被打断。从物理学的角度看,中断是一种电信号,由硬件设备生成,并直接送入中断控制器的输入引脚上。然后再由中断控制器向处理器发送相应的信号。处理器一经检测到此信号,便中断自己的当前工作转而处理中断。此后,处理器会通知操作系统已经产生中断,这样,操作系统就可以对这个中断进行适当的处理了。不同的设备对应的中断不同,而每个中断都通过一个惟一的数字标识。因此,来自键盘的中断就有别干来自硬盘的中断,从而使得操作系统能够对中断进行区分,并知道哪个硬件设备产生了哪个中断。这样,操作系统才能给不同的中断提供不同的中断处理程序。这些中断值通常被为中断请求(IRQ)线。通常IRQ都是一些数值量。例如在PC上,IRQ0是时钟中断,而IRQ1是键盘中断。但并非所有的中断号都是这样严格定义的。例如,对于连接在PCI总线上的设备而言,中断是动态分配的。而在嵌入式系统中,由于中断线有限,一般外设和中断都是一一匹配的,很少有动态分配中断的。不管怎样,重点在于特定的中断总是与特定的设备相关联,并且内核要知道这些信息。1.3异常在操作系统中,讨论中断就不能不提及异常。广义的中断可分为同步(synchronous)中断和异步(asynchronous)中断:同步中断:是当指令执行时由CPU控制单元产生,之所以称为同步,是因为只有在一条指令执行完毕后CPU才会发出中断,而不是发生在代码指令执行期间,比如系统调用。异步中断:是指由其他硬件设备依照CPU时钟信号随机产生,即意味着中断能够在指令之间发生,例如键盘中断。一般由处理器本身产生的同步中断称为异常(exception),异步中断被称为中断(interrupt)。中断可分为可屏蔽中断(Maskableinterrupt)和非屏蔽中断(Nomaskableinterrupt)。异常可分为故障(fault)、陷阱(trap)、终止(abort)三类。表1:中断类别及其行为类别原因异步/同步返回行为中断来自I/O设备的信号异步总是返回到下一条指令陷阱有意的异常同步总是返回到下一条指令故障潜在可恢复的错误同步返回到当前指令终止不可恢复的错误同步不会返回在处理器执行到由于编程失误而导致的错误指令(例如被0除)的时候,或者是在执行期间出现特殊情况(例如缺页),必须靠内核来处理的时候,处理器就会产生一个异常。因为许多处理器体系结构处理异常与处理中断的方式类似,因此,内核对它们的处理也很类似。通过软中断实现系统调用,那就是陷人内核,然后引起一种特殊的异常—系统调用处理程序异常。你将会看到,中断的工作方式与之类似,其差异只在于中断是由硬件而不是软件引起的。1.4中断处理程序在响应一个特定中断的时候,内核会执行一个函数,该函数叫做中断处理程序(interrupthandler)或中断服务例程(interruptserviceroutine,ISR)。产生中断的每个设备都有一个相应的中断处理程序。在Linux中,中断处理程序看起来就是普普通通的C函数。只不过这些函数必须按照特定的类型声明,以便内核能够以标准的方式传递处理程序的信息。中断处理程序与其他内核函数的真正区别在于:中断处理程序是被内核调用来响应中断的,而它们运行于我们称之为中断上下文的特殊上下文中。中断可能随时发生,因此中断处理程序也就随时可能执行。所以必须保证中断处理程序能够快速执行,这样才能保证尽可能快地恢复中断代码的执行。因此,尽管对硬件而言,迅速对其中断进行服务非常重要,但对系统的其他部分而言,让中断处理程序在尽可能短的时间内完成运行也同样重要。即使是最精简版的中断服务程序,它也要与硬件进行交互,告诉该设备中断已被接收。我们可以考虑一下网络设备的中断处理程序面临的挑战。该处理程序除了要对硬件应答,还要把来自硬件的网络数据包拷贝到内存,对其进行处理后再交给合适的协议栈或应用程序。显而易见,这种工作量不会太小,尤其对于如今的千兆比特和万兆比特以太网卡而言。因此我们一般把中断处理切为两个部分或两半。中断处理程序是上半部(tophalf)—接收到一个中断,它就立即开始执行,但只做有严格时限的工作,例如对接收的中断进行应答或复位硬件,这些工作都是在所有中断被禁止的情况下完成的。能够被允许稍后完成的工作会推迟到下半部(bottomhalf)去。此后,在合适的时机,下半部会被开中断执行。以网卡作为实例,当网卡接收流入网络的数据包时,需要通知内核数据包到了。网卡需要立即完成这件事,从而优化网络的吞吐量和传输周期,以避免超时。因此,网卡立即发出中断:嘀,内核,我这里有最新数据包了。内核通过执行网卡已注册的中断处理程序来做出应答。中断开始执行,应答硬件,拷贝最新的网络数据包到内存,然后读取网卡更多的数据包。这些都是重要、紧迫而又与硬件相关的工作。处理和操作数据包的其他工作在随后的下半部中进行。深入剖析Linux中断机制之二--Linux中断的组织形式【摘要】本文详解了Linux内核的中断实现机制。首先介绍了中断的一些基本概念,然后分析了面向对象的Linux中断的组织形式、三种主要数据结构及其之间的关系。随后介绍了Linux处理异常和中断的基本流程,在此基础上分析了中断处理的详细流程,包括保存现场、中断处理、中断退出时的软中断执行及中断返回时的进程切换等问题。最后介绍了中断相关的API,包括中断注册和释放、中断关闭和使能、如何编写中断ISR、共享中断、中断上下文中断状态等。【关键字】中断,异常,hw_interrupt_type,irq_desc_t,irqaction,asm_do_IRQ,软中断,进程切换,中断注册释放request_irq,free_irq,共享中断,可重入,中断上下文1Linux中断的组织形式1.1IRQ描述符irq_desc对于每个IRQ中断线,Linux都用一个irq_desc_t数据结构来描述,我们把它叫做IRQ描述符,NR_IRQS个IRQ形成一个全局数组irq_desc[],其定义在/include/linux/irq.h中:structirq_desc–中断描述符148structirq_desc{149irq_flow_handler_thandle_irq;150structirq_chip*chip;151void*handler_data;152void*chip_data;153structirqaction*action;/*IRQactionlist*/154unsignedintstatus;/*IRQstatus*/155156unsignedintdepth;/*nestedirqdisables*/157unsignedintwake_depth;/*nestedwakeenables*/158unsignedintirq_count;/*FordetectingbrokenIRQs*/159unsignedintirqs_unhandled;160spinlock_tlock;161#ifdefCONFIG_SMP162cpumask_taffinity;163unsignedintcpu;164#endif171constchar*name;172}____cacheline_aligned;173174externstructirq_descirq_desc[NR_IRQS];handle_irq:上层的通用中断处理函数指针,如果未设置则默认为__do_IRQ()。通常针对电平触发或者边沿触发有不同的处理函数。每个中断线可分别设置;chip:底层中断的各种控制访问方法集合,各个CPU实现的都不同,这属于面向对象的中断处理方式中最底层的一部分;handler_data:附加参数,用于handle_irq;chip_data:平台相关的附加参数,用于chip;action:指向一个单向链表的指针,这个链表就是对中断服务例程进行描述的irqaction结构;status:中断当前的状态;depth:中断关闭打开的层数。如果启用这条IRQ中断线,depth则为0,如果禁用这条IRQ中断线不止一次,则为一个正数。如果depth等于0,每当调用一次disable_irq(),该函数就对这个域的值加1,同时该函数就禁用这条IRQ中断线。相反,每当调用enable_irq()函数时,该函数就对这个域的值减1;如果depth变为0,该函数就启用这条IRQ中断线。Lock:此中断描述符为全局共享暑假,对于SMP需要互斥访问Dir:/proc/irq/入口Name:/proc/interrupts中显示的中断名称“____cacheline_aligned”表示这个数据结构的存放按32字节(高速缓存行的大小)进行对齐,以便于将来存放在高速缓存并容易存取linux+v2.6.19/arch/arm/kernel/irq.c157void__initinit_IRQ(void)158{159intirq;160161for(irq=0;irqNR_IRQS;irq++)162irq_desc[irq].status|=IRQ_NOREQUEST|IRQ_DELAYED_DISABLE163IRQ_NOPROBE;164165#ifdefCONFIG_SMP166bad_irq_desc.affinity=CPU_MASK_ALL;167bad_irq_desc.cpu=smp_processor_id();168#endif169init_arch_irq();170}1.2中断控制器描述符irq_chip由于CPU不同,故每个处理器对于中断的处理方式不一样。Linux为了实现统一的中断处理,提供了底层的中断处理抽象接口,对于每个平台都需要实现底层的接口函数。这样对于上层的中断通用处理程序就无需任何改动。structirq_chip–片级的中断描述符94structirq_chip{95constchar*name;96unsignedint(*startup)(unsignedintirq);97void(*shutdown)(unsignedintirq);98void(*enable)(unsignedintirq);99void(*disable)(unsignedintirq);100101voi
本文标题:深入剖析Linux中断机制
链接地址:https://www.777doc.com/doc-6468879 .html