您好、欢迎来到现金彩票网!
当前位置:2019跑狗图高清彩图 > 向量屏蔽 >

linux中断源码分析 - 概述(一)

发布时间:2019-07-07 16:44 来源:未知 编辑:admin

  一般在书中都会把中断和异常一起说明,因为它们具有相同的特点,同时也有不同的地方。在CPU里,中断和异常都会放入到一个中断描述符表中,都需要特定的处理程序进行处理,并且它们都是异步事件,内核完全不知道何时会有一个异常或者中断发生。当异常或者中断发生时,进程都会陷入内核,在内核中执行相应的处理。异常一般都是由CPU内部或者进程产生,而中断一般都是由外部设备产生。异常处理过程实际上和系统调用没什么区别(实际上系统调用是通过一个0x80异常陷入内核当中),而中断的处理过程和情况就相对来说比较复杂。一个中断处理分为硬中断和软中断两个部分,在中断处理的过程中系统是禁止调度和抢占的,而异常处理过程中是允许的。一个中断处理程序可以抢占其他的中断处理程序,也可以抢占异常处理程序,相反的,异常处理程序却不能够抢占中断处理程序。

  为了方便说明,这里我们将PIC和APIC统称为中断控制器。中断控制器是作为中断(IRQ)和CPU核之间的一个桥梁而存在的,每个CPU内部都有一个自己的中断控制器,中断线并不是直接与CPU核相连,而是与CPU内部或外部的中断控制器相连。而为什么叫做可编程中断控制器,是因为其本身有一定的寄存器,CPU可以通过操作设置中断控制器屏蔽某个中断引脚的信号,实现硬件上的中断屏蔽。中断控制器也可以级联提供更多的中断线,具体如下:

  如上图,CPU的INTR与中断控制器的INT相连,INTA与ACK相连,当一个外部中断发生时(比如键盘中断IRQ1),中断控制器与CPU交互操作如下:

  IRQ1发生中断,主中断控制器接收到中断信号,检查中断屏蔽寄存器IRQ1是否被屏蔽,如果屏蔽则忽略此中断信号。

  将中断控制器中的中断请求寄存器对应的IRQ1位置位,表示收到IRQ1中断。

  CPU每执行完一条指令时,都会检查INTR引脚是否被拉高,这里已被拉高。

  CPU检查EFLAGS寄存器的中断运行标志位IF是否为1,若为1,表明允许中断,通过INTA向中断控制器发出应答。

  中断控制器接收到应答信号,将IRQ1的中断向量号发到数据总线上,此时CPU会通过数据总线的中断向量号。

  最后,如果中断控制器需要EOI(End of Interrupt)信号,CPU则会发送,否则中断控制器自动将INT拉低,并清除IRQ1对应的中断请求寄存器位。

  在linux内核中,用struct irq_chip结构体描述一个可编程中断控制器,它的整个结构和调度器中的调度类类似,里面定义了中断控制器的一些操作,如下:

  在中断系统中有两个名字很相像的结构,就是中断描述符表和中断描述符数组。这里我们先说说中断描述符表。一个系统中的中断和异常加起来一共是256个,它们以向量的形式保存在中断描述符表中,每一个向量是8字节(整个表大小就是8 x 256=2048字节),其主要保存着权限位和向量对应的中断或异常处理程序的入口地址。而一般的,linux会将中断描述符表中的0~31用于非屏蔽中断和异常,其他的中断用于32~255之间。CPU把中断描述符表的向量类型分为三种类型:任务门、中断门、陷阱门。CPU为了防止恶意程序访问中断,限制了中断门的权限,而在某些时候,用户程序又必须使用中断,所以Linux把中断描述符的中断向量类型改为了5种:中断门,系统门,系统中断门,陷阱门,任务门。这个中断描述符表的基地址保存在idtr寄存器中。

  系统门用户程序可以访问的CPU陷阱门(权限字段为3)。我们的系统调用就是通过向量128系统门进入的。系统中断门能够被用户进程访问的CPU陷阱门(权限字段为3),作为一个特别的异常处理所用。

  陷阱门用户进程不能访问的CPU陷阱门(权限字段为0),大部分异常处理程序入口都为陷阱门。任务门用户进程不能访问的CPU任务门(权限字段为0),Double fault异常处理程序入口。

  当我们发生异常或中断时,系统首先会判断权限字段(安全处理),权限通过则进入指定的处理函数,而所有的中断门的中断处理函数都是同一个,它首先是一段汇编代码,汇编代码操作如下:

  每个能够产生中断的设备或者模块都会在内核中注册一个中断服务例程(ISR),当产生中断时,中断处理程序会被执行,在中断处理程序中,首先会保存中断向量号和上下文,之后执行中断线对应的中断服务例程。对于CPU来说,中断线是非常宝贵的资源,而由于计算机的发展,外部设备数量和种类越来越多,导致了中断线资源不足的情况,linux为了应对这种情况,实现了两种中断线分配方式,分别是:共享中断线,中断线动态分配。

  多个设备共用一条中断线,当此条中断线发生中断时,因为不可能预先知道哪个特定的设备产生了中断,因此,这条中断线上的每个中断服务例程都会被执行,以验证是哪个设备产生的中断(一般的,设备产生中断时,会标记自己的状态寄存器,中断服务例程通过检查每个设备的状态寄存器来查找产生中断的设备)。

  一条中断线在可能使用的时刻才与一个设备驱动程序关联起来,这样一来,即使几个硬件设备并不共享中断线,同一个中断向量也可以由这几个设备在不同时刻运行。

  共享中断线的分配方式是比较常见的,一次典型的基于共享中断线的中断处理流程如下:

  中断处理程序正在运行时,CPU会通知中断控制器屏蔽产生此中断的中断线。此中断线发出的信号被暂时忽略,当中断处理程序结束时恢复此中断线。

  在中断服务例程的设计中,原则上是立即处理紧急的操作,将非紧急的操作延后处理(交给软中断进行处理)。

  中断处理程序是运行在中断上下文,但是其是代表进程运行的,因此它所代表的进行必须处于TASK_RUNNING状态,否则可能出现僵死情况,因此在中断处理程序中不能执行任何阻塞过程。

  中断描述符用于描述IRQ线的属性与状态,每个IRQ都有它自己的中断描述符,这些中断描述符用一个数组保存, 这个数组就是中断描述符数组,整个中断描述符数组长度为NR_IRQS(通常为224)项。当产生一个中断或者异常时,首先会从中断描述符表中获取到一个中断向量号时(此中断向量号有可能表示中断,也可能表示的是一个异常),如果是一个中断导致的,会执行do_IRQ()函数,而在do_IRQ()函数中,会根据中断向量号,从中断描述符数组中获取对应的中断描述符,如下图:

  中断服务例程用于描述一个设备的中断处理(区别与中断处理函数),每个申请了中断的外部设备都会有一个中断服务例程,其作用就是执行对应设备的中断处理。当多个设备共享IRQ线时,内核会将此IRQ线上所有设备的中断服务例程组织成一个链表并保存在中断描述符中,当此IRQ线产生中断时,中断处理函数会依次执行此IRQ线上的中断服务例程。内核使用struct irqaction描述一个中断服务例程:

  此数组包含NR_CPUS个元素,系统中每个CPU对应数组中的一个元素。每个元素的类型为irq_cpustat_t,其包含几个计数器和内核记录CPU正在做什么的标志。

  到此,在中断处理中所涉及的几个重要的数据结构已经说明,其最主要的数据结构为:中断描述符(struct irq_desc),中断控制器描述符(struct irq_chip),中断服务例程(struct irqaction)。它们的组织形式如下:

http://bluecaleel.com/xiangliangpingbi/238.html
锟斤拷锟斤拷锟斤拷QQ微锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷微锟斤拷
关于我们|联系我们|版权声明|网站地图|
Copyright © 2002-2019 现金彩票 版权所有