嵌入式系统 中断.ppt_第1页
嵌入式系统 中断.ppt_第2页
嵌入式系统 中断.ppt_第3页
嵌入式系统 中断.ppt_第4页
嵌入式系统 中断.ppt_第5页
已阅读5页,还剩46页未读 继续免费阅读

下载本文档

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

文档简介

1、,中断与异常,主要内容,中断的基本知识 中断描述符表的初始化 中断处理 中断的下半部处理机制 中断的应用时钟中断,中断的基本概念,硬中断的概念 硬中断即和硬件相关的中断也就是通常意义上的“中断处理程序”,它是直接处理由硬件发过来的中断信号的。 中断执行的过程 当某个设备发出中断请求时,CPU停止正在执行的指令, 转而跳到包括中断处理代码或者包括指 向中断处理代码的转移指令所在的内存区域。这些代码一般在CP U的中断方式下运 行。就回去自己驱动的设备上去看看设备的状态寄存器以了 解发生了什么事情,并进行相应的操作。当中断处理完毕以后,CPU将恢复到以前的状态,继续执行中断处理前正在执行的指令。,

2、中断的流程如图 i8259.c负责对外部中断的支持。8259芯片负责接收外部设备如定时器、键盘、声卡等的中断,两块8259共支持16个中断,Linux 中断处理特色,分 为上半部和下半部执行 上 半部屏蔽所有中断 下 半部允许中断,执行几乎所有中断,中断控 制的主要优点: CPU只 有在I/O需要服务时才响应 外部中断: 外部 设备所发出的I/O请求 内部 中断: 也称之为“异常”,是为解决机器运行时所出现的某些随机事件及编程方便而出现的,中断常识,中断向量 : 中 断源的编号 外设可屏蔽中断: 屏蔽外 部I/O请求 异常及非 屏蔽中断 : CPU内部中断或计算机内部硬件出错引起的异 常 中断

3、描述符表 : 描述 中断的相关信息 中断的 相 关汇 编指令 :,中断 向量: 每个中 断源都被分配一个8位无符号整数作为类型码,即中断向量 中断的种类: 中断: 外部 可屏蔽中断 外部非 屏蔽中断 异常:不 使用中断控制器,不能被屏蔽 故 障 陷 阱,中断向量中断源的类型,Intel x86通过两片中断控制器8259A来响应15个外中断源,每个8259A可管理8个中断源。 外部设备拥有相应权限时 ,可以向特定的中断线发送中断请求信号 外部I/O请求的屏蔽: 从CPU的角度, 清除eflag的中断标志位 从中断控制器的角度,将中断屏蔽寄存器的相应位置位,外设可屏蔽中断,异常就是CPU内部出现的

4、中断,即在CPU执行特定指令时出现的非法情况。 非屏蔽 中断就是 计算机内部硬件出错时引起的异常情况 Intel把非屏蔽中断作为一种异常来处理 在CPU执行一个 异常处理程序时,就不再为其他异 常或可屏蔽中断请求服务,异常及非屏蔽中断,中断的相关数据结构,从数据结 构入手,应该说 是分析操作系统源码最常用的和最主要的方法。因为操 作系统的几 大功能部件,如进程管理、 设备管 理、内存 管理等, 都可以通过对其相应的数据结 构的分析来弄懂 其实现机制。 很好的掌握这种方法, 对分析Linux内核大有帮助。 中断向量在保护模式下的实现机制是中断描述符表 (Interrupt Descriptor

5、Table, IDT),中断描述符表的结构如图3.4所示。中断描述符 表即中断向量表相当于一个数组,包含256个中断描述符,每个中断描述符8位,对应硬件提供的256个中断服务 例程的入口,即256个中断向量。IDT的位置由idtr确定,idtr是个48位的寄存器,高32位是IDT的基址,低16位为IDT的界限(通常为2k=256*8)。,中断的相关数据结构,图 3.4 Linux 的中断处理数据结构,中断的相关数据结构,在 i386 系统中,Linux 启动时要设置系统的中断描述符表IDT。IDT 中包含各个中断(以及异常,诸如浮点运算溢出)的服务程序地址,中断服务程序地址由 Linux 提供

6、。每个设备驱动程序可以在图 3.4 所示的结构(irq_action)中注册自己的中断及中断处理程序地址。Linux 的中断服务程序根据 irq_action 中的注册信息调用相应的设备驱动程序的中断处理程序。和硬件相关的中断处理代码隐藏在中断服务程序中,这样,设备驱动程序的中断处理程序可在不同平台之间 方便移植。一般来说,CPU 在处理中断时,首先要在堆栈中保存与 CPU 指令执行相关的寄存器(例如指令计数 寄存器),然后调用中断服务程序,中断服务程序结束时 再恢复这些寄存器。,中断的相关数据结构,irq_action 实际是一个数组,其中包含指向 irqaction 的指针,每个数组元素分

7、别定义一个 IRQ。Linux 内核提供相应的操作函数,设备驱动程序可调用这些操作函数设置相应的中断处理函数。一般在系统启动时,由各个设备驱动程序通过如下途径获取相关的设备 IRQ 并设置对应的 irq_action 数组元素所指向的 irqaction 结构。 由于0-31号中断向量已被Intel保留,就剩下32-255共224个中断向量可用。在Linux中,这224个中断向量除了0 x80 (SYSCALL_VECTOR)用作系统调用总入口之外,其它都用在外部硬件中断源(包括可编程中断控制器8259A的15个irq)上。实际上,当没有定义CONFIG_X86_IO_APIC时,其它223(

8、除0 x80外)个中断向量,只利用了从32号开始的15个,其它208个空着未用。这些中断服务程序入口的设置将在下面详细说明。 与硬中断相关数据结构主要有三个, 三者关系如图3.5所示。,3.2.2 中断的相关数据结构,图3.5 与硬中断相关的几个数据结构的关系,中断的相关数据结构,(1) 定义在/arch/i386/Kernel/irq.h中的struct hw_interrupt_type数据结构,它是一个抽象的中 断控制器。这包含一系列的指向函数的指针,这些函数处理控制器 特有的操作: typename:控制器的名字。 startup:允许从给定 的控制器的IRQ所产生的事件。 shutd

9、own:禁止从给 定的控制器的IRQ所产生的事件。 handle:根据提供 给该函数的IRQ,处理唯一的中断。 enable和disable:这两个函数基本上和startup和shutdown相同; struct hw_interrupt_type const char * typename; void (*startup)(unsigned int irq); void (*shutdown)(unsigned int irq); void (*handle)(unsigned int irq, struct pt_regs * regs); void (*enable)(unsigned

10、int irq); void (*disable)(unsigned int irq); ;,中断的相关数据结构,(2) 定义在/arch/i386/Kernel/irq.h中的另外一个数据结构是irq_desc_t,它具有如下成员: status:一个整数。代表IRQ的状态:IRQ是否被禁止了,有关IRQ的设备当前是否正被自动检测,等等。 handler:指向hw_interrupt_type的指针。 action:指向irqaction结构组成的队列的头。正常情况下每个IRQ只有一个操作,因此链接列表的正常长度是1(或者0)。但是,如果IRQ被两个或者多个设备所共享,那么这个队列中就有多个

11、操作。 depth:irq_desc_t的当前用户的个数。主要是用来保证在中断处理过程中IRQ不会被禁止。,中断的相关数据结构,irq_desc是irq_desc_t 类型 的数组。对于每一个IRQ都有一个数组入口,即数组把每一个IRQ映射 到和它相关的处理程序和irq_desc_t中的其它信息。 typedef struct unsigned int status; / IRQ status - IRQ_INPROGRESS, IRQ_DISABLED struct hw_interrupt_type *handler; / handle/enable/disable functions s

12、truct irqaction *action; / IRQ action list unsigned int depth; / Disable depth for nested irq disables irq_desc_t;,中断的相关数据结构,(3) 定义在include/linux/ interrupt.h中的struct irqaction数据结构包含了内核接收到特定IRQ之后应采取的操作,其成员如下: handler:是一指向某个函数的指针。该函数就是所在结构对相应中断的处理函数。 flags:取值只有SA_INTERRUPT(中断可嵌套),SA_SAMPLE_RANDOM(这个中

13、断是源于物理随机性的),和SA_SHIRQ(这个IRQ和其它struct irqaction共享)。 mask:在x86或者体系结构无关的代码中不会使用(除非将其设置为0);只有在SPARC64的移植版本中要跟踪有关软盘的信息时才会使用它。 name:产生中断的硬件设备的名字。因为不止一个硬件可以共享一个IRQ。 dev_id:标识硬件类型的一个唯一的ID。Linux支持的所有硬件设备的每一种类型,都有一个由制造厂商定义的在此成员中记录的设备ID。 next:如果IRQ是共享的,那么这就是指向队列中下一个struct irqaction结构的指针。通常情况下,IRQ不是共享的,因此这个成员就为

14、空。,中断的相关数据结构,struct irqaction void (*handler)(int, void *, struct pt_regs *); unsigned long flags; unsigned long mask; const char *name; void *dev_id; struct irqaction *next; ;,中断和异常的 硬件处理 : 从硬件的角 度看CPU如何处理中断和异常 中断请求队列 的建立: 方便外设共 享中断线 中断处理程序的执行 从中断返回: 调用恢复中断现场的宏RESTORE_ALL,彻底从中断返回,中断处理,当CPU执行了当前指令之后

15、,CS和EIP这对寄存器中所包含的内容就是下一条将要执行指令的虚地址。 在对下一条指令执行前,CPU先要判断在执行当前指令的过程中是否发生了中断或异常。 如果发生了一个中断或异常,那么CPU将做以下事情 :,中断和异常的硬件处理,确定所发生中断或异常的向量i(在0255之间) 通过IDTR寄存器找到IDT表,读取IDT表第i项(或叫第i个门) 分“段”级、“门”级两步进行有效性检查 检查是否发生了特权级的变化,中断和异常处理中CPU的工作,SS ESP EFLAGS CS EIP ERROR CODE,EFLAGS CS EIP ERROR CODE,堆栈增长方向,中断发生前夕的SS:ESP,

16、返回地址,错误码,中断处理程序堆栈,由于硬件 条件的限制,很多硬件设备共享一条中断线 为方便处理,Linux为每条中断线设置了一个 中断请求队列 中断服务例程 与中断处理程序 中断线共享的数据结构 注册中断服务例程,中断请求队列的建立,中断服务例程(Interrupt Service Routine ):每个中断请求都有自己单独的中断服务例程 中断处理程序:共享同一条中断线的所有中断请求有一个总的中断处理程序 在Linux中,15条中断线对应15个中断处理程序,中断服务例程与中断处理程序,struct irqaction void (*handler)(int, void *, struct

17、pt_regs *); unsigned long flags; unsigned long mask; const char *name; void *dev_id; struct irqaction *next; ;,Handler:指向一个具体I/O设备的中断服务例程 Flags:用一组标志描述中断线与I/O设备之间的关系。 SA_INTERRUPT:中断处理程序执行时必须禁止中断 SA_SHIRQ:允许其它设备共享这条中断线。,中断线共享的数据结构,struct irqaction void (*handler)(int, void *, struct pt_regs *); unsi

18、gned long flags; unsigned long mask; const char *name; void *dev_id; struct irqaction *next; ;,SA_SAMPLE_RANDOM:内核可以用它做随机数产生器。 SA_PROBE:内核正在使用这条中断线进行硬件设备探测。 Name:I/O设备名 dev_id:指定I/O设备的主设备号和次设备号(参见第9章)。 Next:指向irqaction描述符链表的下一个元素,中断线共享的数据结构,初始化IDT表之后,必须通过 request_irq() 函数将相应的中断服务例程挂入中断请求队列,即对其进行注册 在

19、关闭设备时,必须通过调用free_irq()函数释放所申请的中断请求号,注册中断服务例程,int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id),CPU从中断 控制器的一个端口取得中断向量I 根据I从中断 描述符表IDT中找到相应的中断门 从中断门获 得中断处理程序的入口地址 判断是否要 进行堆栈切换 调用do_IRQ ()对所接收的中断进行应答 ,并禁止这条中断线 调

20、用handle_IRQ_event()来运行对应的中断服务例程,中断处理程序的执行,当处理所有外设中断请求的函数do_IRQ()执行时,内核栈顶包含的就是do_IRQ()的返回地址,这个地址指向ret_from_intr 从中断返回时, CPU要调用恢复中断现场的宏 RESTORE_ALL,彻底从中断返回。,从中断返回,中断服务例程在中断请求关闭的条件下执行,避免嵌套使中断控制复杂化 系统不能长时间关中断运行,因此内核应尽可能快的处理完中断请求,尽其所能把更多的处理向后推迟 内核把中断处理分为两部分:上半部(top half)和下半部(bottom half),上半部内核立即执行,而下半部留着

21、稍后处理,中断的下半部处理机制,中断描述符表(IDT):即中断向量表,每个中断占据一个表项,中断描述符表,调用过程指令CALL : CALL 过程名 调用中断过程的指令INT INT 中断向量 中断返回指 令IRET IRET 加载中断描述符表的指令LIDT LIDT 48位的伪描述符,相关汇编指令,Linux内核在系统的初始化阶段要初始化可编程控制器8259A;将中断描述符表的起始地址装入IDTR寄存器,并初始化表中的每一项 当计算机运行在实模式时,中断描述符表被初始化, 并由BIOS使用 。 真正进入了Linux内核,中断描述符表就被移到内存的另一个区域, 并为进入保护模式进行预初始化,初

22、始化中断描述符表,IDT表项的设置通过_set_gaet()函数实现 调用该函数在IDT表中插入一个中断门:set_intr_gate(unsigned int n, void *addr) 调用该函数在IDT表中插入一个陷阱门:set_trap_gate(unsigned int n, void *addr) 调用该函数在IDT表中插入一个系统门:set_system_gate(unsigned int n, void *addr),IDT表项的设置,trap_init()函数用 于设置中断描述符表开头的19个陷阱 门和系统门 这些中断向量都 是CPU保留用于异常处理的 ,例: set_tr

23、ap_gate(0,初始化陷阱门和系统门,中断门的设置是由init_IRQ( )函数中的一段代码完成的 : 设置时必须跳过用于系统调用的向量0 x80 中断处理程序的入口地址是一个数组interrupt,数组中的每个元素是指向中断处理函数的指针。,中断门的设置,for (i = 0; i NR_IRQS; i+) int vector = FIRST_EXTERNAL_VECTOR + i; if (vector != SYSCALL_VECTOR) set_intr_gate(vector, interrupti); ,小任务是指待处理的下半部,其数据结构为tasklet_struct,每个结构代表一个独立的小任务 小任务既可以静态地创建,也可以动态

温馨提示

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

评论

0/150

提交评论