IRQ0中断处理全过程

合集下载

简述中断控制器的工作过程

简述中断控制器的工作过程

简述中断控制器的工作过程
简述中断控制器的工作过程指的是对中断控制器如何工作的简要描述。

中断控制器是计算机中负责管理中断信号的硬件设备。

中断控制器的工作过程主要包括以下几个步骤:
1.接收中断信号:中断控制器时刻监听来自各个设备的中断信号。

一旦某个
设备产生中断信号,中断控制器会接收并处理这个信号。

2.判断优先级:中断控制器会根据预设的优先级规则判断接收到的中断信号
的优先级。

优先级高的中断会被优先处理。

3.保存上下文:中断控制器在处理中断之前,需要保存当前CPU的执行上下
文(如寄存器状态等),以便在处理完中断后能恢复到原来的执行状态。

4.处理中断:中断控制器将控制权交给相应的中断处理程序,由其执行中断
处理操作。

中断处理程序可以包括对发生中断的设备进行服务、数据处理等操作。

5.恢复上下文:中断处理程序执行完毕后,中断控制器会恢复CPU的执行上
下文,继续执行原来的任务。

6.发送中断结束信号:中断控制器在完成中断处理后,会向CPU发送一个中
断结束信号,通知CPU可以继续执行后续的任务。

以上是简述中断控制器工作过程的一般步骤,实际的中断处理过程可能因计算机架构和操作系统而有所不同。

BIOS中断大全(2)详解BIOS指令参数

BIOS中断大全(2)详解BIOS指令参数

BIOS中断大全(2)13)、功能0CH 功能描述:查觅入口参数:AH=0CH CH=柱点的低8位CL(7-6位)=柱面的高2位DH=磁头DL=80H~0FFH:硬盘出口参数:CF=0——操作成功,AH=00H, 中国彩吧3d ,否则,AH=状态代码,参见功能号01H中的说明(14)、功能0DH 功能描述:硬盘系统(13)、功能0CH功能描述:查觅入口参数:AH=0CHCH=柱点的低8位CL(7-6位)=柱面的高2位DH=磁头DL=80H~0FFH:硬盘出口参数:CF=0——操作成功,AH=00H,中国彩吧3d,否则,AH=状态代码,参见功能号01H中的说明(14)、功能0DH功能描述:硬盘系统复位入口参数:AH=0DHDL=80H~0FFH:硬盘出口参数:CF=0——操作成功,AH=00H,否则,AH=状态代码,参见功能号01H 中的说明(15)、功能0EH功能描述:读扇区缓冲区入口参数:AH=0EHES:BX=缓冲区的地址出口参数:CF=0——操作成功,否则,AH=状态代码,参睹功能号01H中的解释(16)、功能0FH功能描述:写扇区慢冲区入口参数:AH=0FHES:BX=徐冲区的地址出口参数:CF=0——操作成功,否则,AH=状态代码,参见功能号01H中的说明(17)、功能10H功能描述:读取驱动器状态入口参数:AH=10HDL=80H~0FFH:硬盘出口参数:CF=0——操作成功,AH=00H,否则,AH=状态代码,参见功能号01H 中的说亮(18)、功能11H功能描述:校准驱动器入口参数:AH=11HDL=80H~0FFH:硬盘出口参数:CF=0——操作成功,AH=00H,否则,AH=状态代码,参见功能号01H 中的说明(19)、功能12H功能描述:节制器RAM诊断入口参数:AH=12H出口参数:CF=0——操作成功,否则,AH=状态代码,参见功能号01H中的说明(20)、功能13H功能描述:把持器驱动诊断出口参数:CF=0——操作成功,否则,AH=状态代码,参见功能号01H中的说明(21)、功能14H功能描述:掌握器内部诊断入口参数:AH=14H出口参数:CF=0——操作成功,否则,AH=状态代码,参见功能号01H中的说明(22)、功能15H功能描述:读取磁盘类型入口参数:AH=15HDL=驱动器,00H~7FH:软盘;80H~0FFH:硬盘出口参数:CF=1——操作失败,AH=状态代码,参见功能号01H中的说明,否则,AH=00H —未安装驱动器=01H —无改变线支撑的软盘驱动器=02H —带有改变线支持的软盘驱动器=03H —硬盘,CX:DX=512字节的扇区数(23)、功能16H功能描述:读取磁盘变更状态入口参数:AH=16HDL=00H~7FH:软盘出口参数:CF=0——磁盘未改变,AH=00H,否则,AH=06H,参见功能号01H中的说明(24)、功能17H功能描述:设置磁盘种型DL=00H~7FH:软盘AL=00H —未用=01H — 360K在360K驱动器中=02H — 360K在1.2M驱动器中=03H — 1.2M在1.2M驱动器中=04H — 720K在720K驱动器中出口参数:CF=0——操作成功,AH=00H,否则,AH=状态编码,参见功能号01H 中的说明(25)、功能18H功能描述:设置格式化媒体类型入口参数:AH=18HCH=柱面数CL=每磁讲的扇区数DL=00H~7FH:软盘出口参数:CF=0——操作成功,AH=00H,ES:DI=介量类型参数表地址,否则,AH =状态编码,参见功能号01H中的说明(26)、功能19H功能描述:磁头保护,仅在PS/2中有效,在此从略(27)、功能1AH功能描述:格式化ESDI驱动器,仅在PS/2中有效,在此从略3、串行口服务(Serial Port Service——INT 14H)00H —初始化通信口03H —读取通信口状态01H —向通信口输出字符04H —裁减初始化通信口02H —从通信口读入字符(1)、功能00H功能描述:初始化通信口入口参数:AH=00HDX=初始化通信口号(0=COM1,1=COM2,……)AL=初始化参数,参数的说明如下:波特率奇偶位结束位字的位数76543210000 = 110X0 = None0 = 1 bit10 = 7 bits001 = 15001 = Odd1 = 2 bits11 = 8 bits010 = 30011 = Even011 = 600100 = 1200101 = 2400110 = 4800111 = 9600对PS/2,可用INT 14H之功效04H跟05H去始初化其通讯快率大于9600。

Linux中断处理流程

Linux中断处理流程

Linux中断处理流程1. 中断处理流程 当中断发⽣时,Linux系统会跳转到asm_do_IRQ()函数(所有中断程序的总⼊⼝函数),并且把中断号irq传进来。

根据中断号,找到中断号对应的irq_desc结构(irq_desc结构为内核中中断的描述结构,内核中有⼀个irq_desc结构的数组irq_desc_ptrs[NR_IRQS]),然后调⽤irq_desc中的handle_irq函数,即中断⼊⼝函数。

我们编写中断的驱动,即填充并注册irq_desc结构。

2. 中断处理数据结构:irq_desc Linux内核将所有的中断统⼀编号,使⽤⼀个irq_desc[NR_IRQS]的结构体数组来描述这些中断:每个数组项对应着⼀个中断源(也可能是⼀组中断源),记录中断⼊⼝函数、中断标记,并提供了中断的底层硬件访问函数(中断清除、屏蔽、使能)。

另外通过这个结构体数组项中的action,能够找到⽤户注册的中断处理函数。

struct irq_desc {unsigned int irq;irq_flow_handler_t handle_irq;struct irq_chip *chip;struct msi_desc *msi_desc;void *handler_data;void *chip_data;struct irqaction *action; /* IRQ action list */unsigned int status; /* IRQ status */unsigned int depth; /* nested irq disables */unsigned int wake_depth; /* nested wake enables */unsigned int irq_count; /* For detecting broken IRQs */unsigned long last_unhandled; /* Aging timer for unhandled count */unsigned int irqs_unhandled;spinlock_t lock;const char *name;} ____cacheline_internodealigned_in_smp;(1)handle_irq:中断的⼊⼝函数(2)chip:包含这个中断的清除、屏蔽、使能等底层函数struct irq_chip {const char *name;unsigned int (*startup)(unsigned int irq);void (*shutdown)(unsigned int irq);void (*enable)(unsigned int irq);void (*disable)(unsigned int irq);void (*ack)(unsigned int irq);void (*mask)(unsigned int irq);void (*mask_ack)(unsigned int irq);void (*unmask)(unsigned int irq);void (*eoi)(unsigned int irq);void (*end)(unsigned int irq);void (*set_affinity)(unsigned int irq,const struct cpumask *dest);int (*retrigger)(unsigned int irq);int (*set_type)(unsigned int irq, unsigned int flow_type);int (*set_wake)(unsigned int irq, unsigned int on);/* Currently used only by UML, might disappear one day.*/#ifdef CONFIG_IRQ_RELEASE_METHODvoid (*release)(unsigned int irq, void *dev_id);#endif/** For compatibility, ->typename is copied into ->name.* Will disappear.*/const char *typename;};(3)action:记录⽤户注册的中断处理函数、中断标志等内容struct irqaction {irq_handler_t handler;unsigned long flags;cpumask_t mask;const char *name;void *dev_id;struct irqaction *next;int irq;struct proc_dir_entry *dir;};3. 中断处理流程总结(1)发⽣中断后,CPU执⾏异常向量vector_irq的代码;(2)在vector_irq⾥⾯,最终会调⽤中断处理C程序总⼊⼝函数asm_do_IRQ();(3)asm_do_IRQ()根据中断号调⽤irq_des[NR_IRQS]数组中的对应数组项中的handle_irq();(4)handle_irq()会使⽤chip的成员函数来设置硬件,例如清除中断,禁⽌中断,重新开启中断等;(5)handle_irq逐个调⽤⽤户在action链表中注册的处理函数。

硬件中断

硬件中断

硬件中断硬件中断概述中断可以用下面的流程来表示:中断产生源 --> 中断向量表 (idt) --> 中断入口 ( 一般简单处理后调用相应的函数) --->do_IRQ--> 后续处理(软中断等工作)如图:具体地说,处理过程如下:1.中断信号由外部设备发送到中断芯片(模块)的引脚2.中断芯片将引脚的信号转换成数字信号传给CPU,例如8259主芯片引脚0发送的是0x203.CPU接收中断后,到中断向量表IDT中找中断向量4.根据存在中断向量中的数值找到向量入口5.由向量入口跳转到一个统一的处理函数do_IRQ6.在do_IRQ中可能会标注一些软中断,在执行完do_IRQ后执行这些软中断。

下面一一介绍。

8259芯片本文主要参考周明德《微型计算机系统原理及应用》和billpan的相关帖子1.中断产生过程(1)如果IR引脚上有信号,会使中断请求寄存器(Interrupt Request Register,IRR)相应的位置位,比如图中, IR3, IR4, IR5上有信号,那么IRR的3,4,5为1(2)如果这些IRR中有一个是允许的,也就是没有被屏蔽,那么就会通过INT 向CPU发出中断请求信号。

屏蔽是由中断屏蔽寄存器(Interrupt Mask Register,IMR)来控制的,比如图中位3被置1,也就是IRR位3的信号被屏蔽了。

在图中,还有4,5的信号没有被屏蔽,所以,会向CPU发出请求信号。

(3)如果CPU处于开中断状态,那么在执行指令的最后一个周期,在INTA上做出回应,并且关中断.(4)8259A收到回应后,将中断服务寄存器(In-Service Register)置位,而将相应的IRR复位:8259芯片会比较IRR中的中断的优先级,如上图中,由于IMR中位3处于屏蔽状态,所以实际上只是比较IR4,I5,缺省情况下,IR0最高,依次往下,IR7最低(这种优先级可以被设置),所以上图中,ISR被设置为4.(5)在CPU发出下一个INTA信号时,8259将中断号送到数据线上,从而能被CPU接收到,这里有个问题:比如在上图中,8259获得的是数4,但是CPU需要的是中断号(并不为4),从而可以到idt找相应的向量。

IRQ设置

IRQ设置
“Advanced”一栏最底下的“PCI Configuration”。
3、在“PCI Configuration”设置页面的上半部分有一项“Slot 3
IRQ”,它就是第三根PCI插槽所分配的IRQ位置。系统默认为“Auto”(自动)。
4、将光标移到“Slot 3
4设置为“IRQ11”等。
6、此外,如果你使用的主板集成有老一代的ISA插槽的话,还要在“PCI IRQ Resource
Exclusion”选项中,对个别的ISA总线硬件所需的IRQ进行更改设置。
7、完成设置后选择保存设置并重新启动电脑,就可以向烦人的IRQ冲突说BYEBYE啦。
二、什么是IRQ冲突
IRQ的数目有限,一部电脑虽然一共有16个IRQ(从IRQ0至IRQ15),但是其中很多IRQ已经预先分配给特定的硬件,具体如下:
IRQ0:系统计时器
IRQ1:键盘
IRQ2:可设置中断控制卡
IRQ3:COM2(串行接口2)
IRQ4:COM1(串行接口1)
IRQ设置
---------------------------------------------------------------
一、什么是IRQ
IRQ的全称是“Interupt
ReQuest”,即“中断要求”。当电脑内的周边硬件需要处理器去执行某些工作时,该硬件就会发出一个硬件信号,通知处理器工作,而这个信号就是IRQ。那为什么叫做“中断”呢?“中断”的意思是即使处理器正在执行其他工作,当它收到周边设备传来的中断信号时,处理器也会停下来,优先处理这个信号代表的工作,完成后再继续处理之前未完成的工作。
IRQ15:Secondary(从)IDE控制器

中断和中断处理流程

中断和中断处理流程

中断和中断处理流程转⾃:1. 中断概念中断是指由于接收到来⾃外围硬件(相对于中央处理器和内存)的异步信号或来⾃软件的同步信号,⽽进⾏相应的硬件/软件处理。

发出这样的信号称为进⾏中断请求(interrupt request,IRQ)。

硬件中断导致处理器通过⼀个上下⽂切换(context switch)来保存执⾏状态(以程序计数器和程序状态字等寄存器信息为主);软件中断则通常作为CPU指令集中的⼀个指令,以可编程的⽅式直接指⽰这种上下⽂切换,并将处理导向⼀段中断处理代码。

中断在计算机多任务处理,尤其是实时系统中尤为有⽤。

这样的系统,包括运⾏于其上的操作系统,也被称为“中断驱动的”(interrupt-driven)。

中断是⼀种使CPU中⽌正在执⾏的程序⽽转去处理特殊事件的操作,这些引起中断的事件称为中断源,它们可能是来⾃外设的输⼊输出请求,也可能是计算机的⼀些异常事故或其它内部原因。

中断:在运⾏⼀个程序的过程中,断续地以“插⼊”⽅式执⾏⼀些完成特定处理功能的程序段,这种处理⽅式称为中断。

2. 中断的作⽤并⾏操作硬件故障报警与处理⽀持多道程序并发运⾏,提⾼计算机系统的运⾏效率⽀持实时处理功能3. 术语按中断源进⾏分类:发出中断请求的设备称为中断源。

按中断源的不同,中断可分为1. 内中断:即程序运⾏错误引起的中断2. 外中断:即由外部设备、接⼝卡引起的中断3. 软件中断:由写在程序中的语句引起的中断程序的执⾏,称为软件中断允许/禁⽌(开/关)中断: CPU通过指令限制某些设备发出中断请求,称为屏蔽中断。

从CPU要不要接收中断即能不能限制某些中断发⽣的⾓度,中断可分为1. 可屏蔽中断:可被CPU通过指令限制某些设备发出中断请求的中断,那是不是意味着进中断时disable整个中断,其实disable的都是可屏蔽中断?2. 不可屏蔽中断:不允许屏蔽的中断如电源掉电中断允许触发器:在CPU内部设置⼀个中断允许触发器,只有该触发器置“1”,才允许中断;置“0”,不允许中断。

IRQ中断处理流程

IRQ中断处理流程

IRQ中断处理流程基于Linux2.6.30.4分析IRQ中断的处理流程。

1.中断⼊⼝/* arch/arm/kenel/entry-armv.S*/b vector_irq + stubs_offset2.vector_irqvector_stub 宏展开即为vector_irq, 参考。

/** Interrupt dispatcher*/vector_stub irq, IRQ_MODE, 4.long __irq_usr @ 0 (USR_26 / USR_32).long __irq_invalid @ 1 (FIQ_26 / FIQ_32).long __irq_invalid @ 2 (IRQ_26 / IRQ_32).long __irq_svc @ 3 (SVC_26 / SVC_32)3.__irq_user__irq_usr:usr_entry /*3.1*/kuser_cmpxchg_check#ifdef CONFIG_TRACE_IRQFLAGSbl trace_hardirqs_off#endifget_thread_info tsk /*3.2*/#ifdef CONFIG_PREEMPT/**r8<--old preempt_count*r7<--preempt_count+1*preempt_count<--r7*/ldr r8, [tsk, #TI_PREEMPT] @ get preempt countadd r7, r8, #1 @ increment itstr r7, [tsk, #TI_PREEMPT]#endifirq_handler /*3.3*/#ifdef CONFIG_PREEMPT/**r0<--new preempt_count*preempt<--old preempt_count*/ldr r0, [tsk, #TI_PREEMPT]str r8, [tsk, #TI_PREEMPT]teq r0, r7strne r0, [r0, -r0]#endif#ifdef CONFIG_TRACE_IRQFLAGSbl trace_hardirqs_on#endifmov why, #0b ret_to_user /*3.4*/UNWIND(.fnend )ENDPROC(__irq_usr)3.1__user_entry.macro usr_entryUNWIND(.fnstart )UNWIND(.cantunwind ) @ don't unwind the user space/* DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs));*/sub sp, sp, #S_FRAME_SIZE /**/stmib sp, {r1 - r12}ldmia r0, {r1 - r3}add r0, sp, #S_PC @ here for interlock avoidancemov r4, #-1 @ """"""""str r1, [sp] @ save the "real" r0 copied@ from the exception stack@@ We are now ready to fill in the remaining blanks on the stack: @@ r2 - lr_<exception>, already fixed up for correct return/restart@ r3 - spsr_<exception>@ r4 - orig_r0 (see pt_regs definition in ptrace.h)@@ Also, separately save sp_usr and lr_usr@stmia r0, {r2 - r4}/*“^”符号表⽰访问user mode的寄存器*/stmdb r0, {sp, lr}^@@ Enable the alignment trap while in kernel mode@alignment_trap r0@@ Clear FP to mark the first stack frame@zero_fp.endm这⾥⾯⽤到pt_regs结构保存栈上的数据,8字节对齐/** This struct defines the way the registers are stored on the* stack during a system call. Note that sizeof(struct pt_regs)* has to be a multiple of 8.*/struct pt_regs {long uregs[18];};与之相关的宏定义如下DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs));DEFINE(S_R0, offsetof(struct pt_regs, ARM_r0)); DEFINE(S_R1, offsetof(struct pt_regs, ARM_r1)); DEFINE(S_R2, offsetof(struct pt_regs, ARM_r2)); DEFINE(S_R3, offsetof(struct pt_regs, ARM_r3)); DEFINE(S_R4, offsetof(struct pt_regs, ARM_r4)); DEFINE(S_R5, offsetof(struct pt_regs, ARM_r5)); DEFINE(S_R6, offsetof(struct pt_regs, ARM_r6)); DEFINE(S_R7, offsetof(struct pt_regs, ARM_r7)); DEFINE(S_R8, offsetof(struct pt_regs, ARM_r8)); DEFINE(S_R9, offsetof(struct pt_regs, ARM_r9)); DEFINE(S_R10, offsetof(struct pt_regs, ARM_r10)); DEFINE(S_FP, offsetof(struct pt_regs, ARM_fp)); DEFINE(S_IP, offsetof(struct pt_regs, ARM_ip)); DEFINE(S_SP, offsetof(struct pt_regs, ARM_sp)); DEFINE(S_LR, offsetof(struct pt_regs, ARM_lr)); DEFINE(S_PC, offsetof(struct pt_regs, ARM_pc)); DEFINE(S_PSR, offsetof(struct pt_regs, ARM_cpsr)); DEFINE(S_OLD_R0, offsetof(struct pt_regs, ARM_ORIG_r0)); #define ARM_cpsr uregs[16]#define ARM_pc uregs[15]#define ARM_lr uregs[14]#define ARM_sp uregs[13]#define ARM_ip uregs[12]#define ARM_fp uregs[11]#define ARM_r10 uregs[10]#define ARM_r9 uregs[9]#define ARM_r8 uregs[8]#define ARM_r7 uregs[7]#define ARM_r6 uregs[6]#define ARM_r5 uregs[5]#define ARM_r4 uregs[4]#define ARM_r3 uregs[3]#define ARM_r2 uregs[2]#define ARM_r1 uregs[1]#define ARM_r0 uregs[0]#define ARM_ORIG_r0 uregs[17]macos3.2 get_thread_info tsktsk即r9寄存器的别名,内核中为寄存器声明的别名如下/** These are the registers used in the syscall handler, and allow us to* have in theory up to 7 arguments to a function - r0 to r6.** r7 is reserved for the system call number for thumb mode.** Note that tbl == why is intentional.** We must set at least "tsk" and "why" when calling ret_with_reschedule.*/scno .req r7 @ syscall numbertbl .req r8 @ syscall table pointerwhy .req r8 @ Linux syscall (!= 0)tsk .req r9 @ current thread_infoget_thread_info tsk的作⽤是获取sp地址保存在tsk(r9)中,即r9中保存当前任务的thread_info结构的地址。

linux中断处理之IRQ中断

linux中断处理之IRQ中断

linux中断处理之IRQ中断本文系本站原创,欢迎转载!转载请注明出处:/------------------------------------------一:前言在前一个专题里曾分析过所有IRQ中断处理流程,经过SAVE_ALL保存硬件环境后,都会进入do_IRQ()进行处理,今天接着分析do_IRQ()处理的相关东西.分为两部中断处理程序与软中断两个大的部份进行介绍.二:中断处理程序在驱动程序中,通常使用request_irq()来注册中断处理程序.我们先从注册中断处理程序的实现说起./*irq:可断号handler:中断处理程序irqflags:中断处理标志.SA_SHIRQ:共享中断线SA_INTERRUPT:快速处理中断必须在关中断的情况下运行.SA_SAMPLE_RANDOM:该中断可能用于产生一个随机数devname dev_id:设备名称与ID*/int request_irq(unsigned int irq,irqreturn_t (*handler)(int, void *, struct pt_regs *),unsigned long irqflags,const char * devname,void *dev_id){int retval;struct irqaction * action;#if 1if (irqflags & SA_SHIRQ) {if (!dev_id)printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n", devname, (&irq)[-1]);}#endif//参数有效性判断if (irq >= NR_IRQS)return -EINVAL;if (!handler)return -EINVAL;// 分配一个irqactionaction = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_ATOMIC);if (!action)return -ENOMEM;action->handler = handler;action->flags = irqflags;cpus_clear(action->mask);action->name = devname;action->next = NULL;action->dev_id = dev_id;//将创建并初始化完在的action加入irq_desc[NR_IRQS]retval = setup_irq(irq, action);if (retval)kfree(action);return retval;}上面涉及到的irqaction结构与irq_desc[]的关系我们在上一节我们已经详细分析过了,这里不再赘述. 转进setup_irq():int setup_irq(unsigned int irq, struct irqaction * new){int shared = 0;unsigned long flags;struct irqaction *old, **p;irq_desc_t *desc = irq_desc + irq;//如果hander == no_irq_type:说明中断控制器不支持该IRQ线if (desc->handler == &no_irq_type)return -ENOSYS;sif (new->flags & SA_SAMPLE_RANDOM) {rand_initialize_irq(irq);}/** The following block of code has to be executed atomically*/spin_lock_irqsave(&desc->lock,flags);p = &desc->action;if ((old = *p) != NULL) {//判断这条中断线上的中断处理程序是否允许SHARE/* Can't share interrupts unless both agree to */if (!(old->flags & new->flags & SA_SHIRQ)) {spin_unlock_irqrestore(&desc->lock,flags);return -EBUSY;}/* add new interrupt at end of irq queue */do {p = &old->next;old = *p;} while (old);shared = 1;}//将其添加到中断处理函数链的末尾*p = new;//如果这一条线还没有被占用,初始化这条中断线//包含清标志,在8259A上启用这条中断线if (!shared) {desc->depth = 0;desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);desc->handler->startup(irq);}spin_unlock_irqrestore(&desc->lock,flags);//在proc下建立相关的文件register_irq_proc(irq);return 0;}现在知道怎么打一个中断处理程序挂到irq_desc[NR_IRQS]数组上了,继续分析中断处理中如何调用中断处理函数.从我们开篇时说到的do_IRQ()说起.asmlinkage unsigned int do_IRQ(struct pt_regs regs){//屏蔽高位,取得中断号int irq = regs.orig_eax & 0xff; /* high bits used in ret_from_ code *///取得中断号对应的desc结构irq_desc_t *desc = irq_desc + irq;struct irqaction * action;unsigned int status;irq_enter();// 调试用,忽略#ifdef CONFIG_DEBUG_STACKOVERFLOW/* Debugging check for stack overflow: is there less than 1KB free? */{long esp;__asm__ __volatile__("andl %%esp,%0" :"=r" (esp) : "0" (THREAD_SIZE - 1));if (unlikely(esp < (sizeof(struct thread_info) + STACK_WARN))) {printk("do_IRQ: stack overflow: %ld\n",esp - sizeof(struct thread_info));dump_stack();}}#endif//更新统计计数kstat_this_cpu.irqs[irq]++;spin_lock(&desc->lock);//给8259 回一个ack.回ack之后,通常中断控制会屏蔽掉此条IRQ线desc->handler->ack(irq);//清除IRQ_REPLAY IRQ_WAITING标志status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);//设置IRQ_PENDING:表示中断被应答,但没有真正被处理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;//中断被屏蔽或者正在处理//IRQ_DIASBLED:中断被禁用//IRQ_INPROGRESS:这个类型的中断已经在被另一个CPU处理了if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) { action = desc->action;status &= ~IRQ_PENDING; /* we commit to handling *///置位,表示正在处理中...status |= c; /* we are handling it */}desc->status = status;//没有挂上相应的中断处理例程或者不满足条件if (unlikely(!action))goto out;for (;;) {irqreturn_t action_ret;u32 *isp;union irq_ctx * curctx;union irq_ctx * irqctx;curctx = (union irq_ctx *) current_thread_info();irqctx = hardirq_ctx[smp_processor_id()];spin_unlock(&desc->lock);//通常curctx == irqctx.除非中断程序使用独立的4K堆栈.if (curctx == irqctx)action_ret = handle_IRQ_event(irq, &regs, action);else {/* build the stack frame on the IRQ stack */isp = (u32*) ((char*)irqctx + sizeof(*irqctx));irqctx->tinfo.task = curctx->tinfo.task;irqctx->tinfo.real_stack = curctx->tinfo.real_stack;irqctx->tinfo.virtual_stack = curctx->tinfo.virtual_stack;irqctx->tinfo.previous_esp = current_stack_pointer();*--isp = (u32) action;*--isp = (u32) &regs;*--isp = (u32) irq;asm volatile(" xchgl %%ebx,%%esp \n"" call handle_IRQ_event \n"" xchgl %%ebx,%%esp \n": "=a"(action_ret): "b"(isp): "memory", "cc", "edx", "ecx");}spin_lock(&desc->lock);//调试用,忽略if (!noirqdebug)note_interrupt(irq, desc, action_ret, &regs);if (curctx != irqctx)irqctx->tinfo.task = NULL;//如果没有要处理的中断了,退出if (likely(!(desc->status & IRQ_c)))break;//又有中断到来了,继续处理desc->status &= ~c;}//处理完了,清除IRQ_INPROGRESS标志desc->status &= ~IRQ_INPROGRESS;out:/** The ->end() handler has to deal with interrupts which got* disabled while the handler was running.*///处理完了,调用中断控制器的end.通常此函数会使中断控制器恢复IRQ线中断desc->handler->end(irq);spin_unlock(&desc->lock);//irq_exit():理论上中断处理完了,可以处理它的下半部了irq_exit();return 1;}这段代码比较简单,但里面几个标志让人觉的很迷糊,列举如下:IRQ_DISABLED:相应的IRQ被禁用.既然中断线被禁用了,也就不会产生中断,进入do_IRQ()了?因为电子器件的各种原因可能会产生“伪中断”上报给CPU.IRQ_PENDING:CPU收到这个中断信号了,已经给出了应答,但并末对其进行处理.回顾上面的代码,进入do_IRQ后,发送ack,再设置此标志.IRQ_ INPROGRESS:表示这条IRQ线的中断正在被处理.为了不弄脏CPU的高速缓存.把相同IRQ线的中断放在一起处理可以提高效率,且使中断处理程序不必重入举例说明:如果CPU A接收到一个中断信号.回一个ACK,设置c,假设此时末有这个中断线的中断处理程序在处理,继而会将标志位设为IRQ_ INPROGRESS.转去中断处理函数执行.如果此时,CPU B检测到了这条IRQ线的中断信号.它会回一个ACK.设置IRQ_PENDING.但时此时这条IRQ线的标志为IRQ_ INPROGRESS.所以,它会进经过goto out退出.如果cpu A执行完了中断处理程序,判断它的标志线是否为IRQ_PENDING.因为CPU B已将其设为了IRQ_PENDING.所以继续循环一次.直到循环完后,清除IRQ_INPROGRESS标志注意上述读写标志都是加锁的.linux采用的这个方法,不能不赞一个*^_^*继续看代码:asmlinkage int handle_IRQ_event(unsigned int irq,struct pt_regs *regs, struct irqaction *action){int status = 1; /* Force the "do bottom halves" bit */int ret, retval = 0;//如果没有设置SA_INTERRUPT.将CPU 中断打开//应该尽量的避免CPU关中断的情况,因为CPU屏弊本地中断,会使//中断丢失if (!(action->flags & SA_INTERRUPT))local_irq_enable();//遍历运行中断处理程序do {ret = action->handler(irq, action->dev_id, regs);if (ret == IRQ_HANDLED)status |= action->flags;retval |= ret;action = action->next;} while (action);if (status & SA_SAMPLE_RANDOM)add_interrupt_randomness(irq);//关中断local_irq_disable();return retval;}可能会有这样的疑问.如果在一根中断线上挂上了很多个中断处理程序,会不会使这一段程序的效率变得很低下呢?事实上,我们在写驱动程序的过程中,都会首先在中断处理程序里判断设备名字与设备ID,只有条件符合的设备中断才会变处理.三:软中断为了提高中断的响应速度,很多操作系统都把中断分成了两个部份,上半部份与下半部份.上半部份通常是响应中断,并把中断所得到的数据保存进下半部.耗时的操作一般都会留到下半部去处理.接下来,我们看一下软中断的处理模型:Start_kernel() à softirq_init();在softirq_init()中会注册两个常用类型的软中断,看具体代码:void __init softirq_init(void){open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL);open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL);}//参数含义:nr:软中断类型action:软中断处理函数data:软中断处理函数参数void open_softirq(int nr, void (*action)(struct softirq_action*), void *data){softirq_vec[nr].data = data;softirq_vec[nr].action = action;}static struct softirq_action softirq_vec[32] __cacheline_aligned_in_smp;struct softirq_action{void (*action)(struct softirq_action *);void *data;};在上面的代码中,我们可以看到:open_softirq()中.其实就是对softirq_vec数组的nr项赋值.softirq_vec是一个32元素的数组,实际上linux内核只使用了六项. 如下示:enum{HI_SOFTIRQ=0,TIMER_SOFTIRQ,NET_TX_SOFTIRQ,NET_RX_SOFTIRQ,SCSI_SOFTIRQ,TASKLET_SOFTIRQ}另外.如果使软中断能被CPU调度,还得要让它激活才可以.激活所使用的函数为__raise_softirq_irqoff()代码如下:#define __raise_softirq_irqoff(nr) do { local_softirq_pending() |= 1UL << (nr); } while (0)这个宏使local_softirq_pending的nr位置1好了,经过open_softirq()à local_softirq_pending()后,我们来看下软中断怎么被CPU调度.继续上面中断处理的代码.在处理完硬件中断后,会调用irq_exit().这就是软中断的入口点了,我们来看下#define irq_exit() \do { \preempt_count() -= IRQ_EXIT_OFFSET; \//注意了,软中断不可以在硬件中断上下文或者是在软中断环境中使用哦^_^//softirq_pending()的判断,注意我们上面分析过的_raise_softirqoff().它判断当前cpu有没有激活软中断if (!in_interrupt() && softirq_pending(smp_processor_id())) \do_softirq(); \preempt_enable_no_resched(); \} while (0)跟踪进do_softirq()asmlinkage void do_softirq(void){__u32 pending;unsigned long flags;//在硬件中断环境中,退出if (in_interrupt())return;//禁止本地中断,不要让其受中断的影响local_irq_save(flags);pending = local_softirq_pending();//是否有软中断要处理?if (pending)__do_softirq();//恢复CPU中断local_irq_restore(flags);}转入__do_softirq()asmlinkage void __do_softirq(void){struct softirq_action *h;__u32 pending;int max_restart = MAX_SOFTIRQ_RESTART;int cpu;pending = local_softirq_pending();//禁止软中断,不允许软中断嵌套local_bh_disable();cpu = smp_processor_id();restart:/* Reset the pending bitmask before enabling irqs *///把挂上去的软中断清除掉,因为我们在这里会全部处理完local_softirq_pending() = 0;//开CPU中断local_irq_enable();//softirq_vec:32元素数组h = softirq_vec;//依次处理挂上去的软中断do {if (pending & 1) {//调用软中断函数h->action(h);rcu_bh_qsctr_inc(cpu);}h++;pending >>= 1;} while (pending);//关CPU 中断local_irq_disable();pending = local_softirq_pending();//在规定次数内,如果有新的软中断了,可以继续在这里处理完if (pending && --max_restart)goto restart;//依然有没有处理完的软中断,为了提高系统响应效率,唤醒softirqd进行处理if (pending)wakeup_softirqd();//恢复软中断__local_bh_enable();}从上面的处理流程可以看到,软中断处理就是调用open_ softirq()的action参数.这个函数对应的参数是软中断本身(h->action(h)),采用这样的形式,可以在改变softirq_action结构的时候,不会重写软中断处理函数在进入了软中断的时候,使用了in_interrupt()来防止软中断嵌套,和抢占硬中断环境。

不同CPU中断技术对比专题研究

不同CPU中断技术对比专题研究

不同CPU中断技术对比专题研究一.X86中断系统(1)中断源中断申请方式:按照产生中断的方法来分:1.外部中断(来自CPU外部,由外设的请求引起,通过外部硬件产生,也称为硬件中断)外部中断又分为非屏蔽中断NMI和可屏蔽中断INTR。

2.内部中断(来自CPU内部,由执行指令引起的)内部中断又分为微处理器内部中断和软件中断。

(2)中断优先级管理方式:优先级由高到低一次为:1.内部中断(除单步中断)2.NMI3.INTR (IRQ0, ... , IRQ7)4.单步中断(3)中断的处理过程:8086中断控制是由CPU与中断控制器共同完成的,其中断过程包括:1. 中断申请:当外设需要中断服务时,由硬件产生一个中断请求信号INTR发送给CPU;CPU 在当前指令结束时检测INTR引脚,判断是否有中断请求。

2. 中断响应:当检测到有中断请求且IF=1时,总线周期信号M/IO D/C W/R为000,通过总线控制逻辑发中断响应信号;INTA给中断请求设备表示应答;中断请求设备将中断号送上数据总线;系统自动进入中断响应周期,由硬件完成关中断、保存断点、取中断服务的入口地址(N*4)等一系列操作,而后转向中断服务程序执行中断处理。

3、中断处理:执行中断服务程序中规定的操作。

4、中断返回:将压栈的断点从堆栈中弹出,开中断,CPU转向被中断的主程序继续执行。

(4)中断向量:8086在内存的最低端开辟了1KB 的存贮区作为中断向量表。

该表以四字节为一组构造而成,共分为256组,按中断向量码的序号排列:I/O ADDRINT TYPE FUNCTION00 ~ 03 0 除法溢出中断04 ~ 07 1 单步(用于DEBUG)08 ~ 0B 2 非屏蔽中断(NMI)0C ~ 0F 3 断点中断(用于DEBUG)10 ~ 13 4 溢出中断14 ~ 17 5 打印屏幕18 ~ 1F 6,7 保留二.8051单片机中断系统51单片机的中断系统共有5个中断源,2个中断优先级,可以实现两级中断服务嵌套。

单片机实验IRQ0IRQ1IRQ2中断

单片机实验IRQ0IRQ1IRQ2中断
*P_IOA_Attrib =0x000f;
*P_IOA_Data = 0x0000;
*P_IOB_Dir = 0x000f;
*P_IOB_Attrib = 0x000f;
*P_IOB_Data = 0x0000;
//设置定时器A、B的属性
*P_TimerA_Ctrl = C_TMA1_4KHz | C_TMA2_1;
asm("INT IRQ");//开IRQ中断
while (1){
*P_Watchdog_Clear = C_WDTCLR;
}
return 0;
}
//isr.c
#include "SPCE061A.h"
void BREAK(void) __attribute__ ((ISR));
void FIQ(void) __attribute__ ((ISR));
后,翻转IOB口低四位输出电平以控制接在IOB低四位端口的发光二极管。程序运行时,可以
观察到接在IOA低四位端口的发光二极管亮灭的周期为4s,而接在IOB低四位端口的为2s【实验原理】
【实验原理】
IRQ0_fosc/1024、IRQ1_TMA、IRQ2_TMB中断源,通过写P_INT_Ctrl来允许中断,通过IRQ ON、
1、实验中遇到的问题及解决办法
答:1、问题:对不同中断信号频率的设置需要符合程序运行的方式,LED灯的闪烁频率太快时就无法看见其在闪烁,交替闪烁的快慢也会随之变化,在程序的编写上要严格按照规则编写,否则就会出错,因此在实验中一定要弄清楚其缘由。
2、解决方法:通过实际的计算测量。老师的引导,同学之间的相互交流沟通学习,一步步的完成了此实验,并在老师的详细讲解下熟悉了个窗口的功能及硬件的了解和正确的连接,做出与实验目的相符合的结果。

c51单片机定时器中断的执行过程

c51单片机定时器中断的执行过程

c51单片机定时器中断的执行过程
C51单片机定时器中断的执行过程可以分为以下几个步骤:
1. 初始化定时器:首先需要对定时器进行初始化,设置定时器的计数模式、计数值、溢出方式等参数。

这些参数可以通过编程实现,也可以通过硬件电路进行调整。

2. 启动定时器:初始化完成后,需要启动定时器。

启动定时器后,定时器开始按照预设的参数进行计数。

当计数值达到预设的溢出值时,定时器会产生一个溢出信号。

3. 设置中断服务程序:为了在定时器溢出时执行特定的操作,需要设置一个中断服务程序 ISR)。

中断服务程序是一段特殊的代码,它会在定时器溢出时被自动调用。

4. 开启中断:在中断服务程序设置完成后,需要开启相应的中断。

开启中断后,当定时器溢出时,CPU会自动跳转到中断服务程序执行。

5. 执行中断服务程序:当定时器溢出时,CPU会暂停当前任务,跳转到中断服务程序执行。

在中断服务程序中,可以执行一些特定的操作,如更新显示、读取传感器数据等。

6. 返回主程序:中断服务程序执行完成后,CPU会自动返回到主程序继续执行。

这样,通过定时器中断,可以实现对单片机的周期性控制和数据采集等功能。

中断建立全过程的演示

中断建立全过程的演示

中断建立全过程的演示下面给出一个简单的例子,以演示如何建立一个外部中断。

1. 当系统启动后,先设置优先级组寄存器。

缺省情况下使用组0(7位抢占优先级,1位亚优先级)。

2. 如果需要重定位向量表,先把硬fault和NMI服务例程的入口地址写到新表项所在的地址中。

3. 配置向量表偏移量寄存器,使之指向新的向量表(如果有重定位的话)4. 为该中断建立中断向量。

因为向量表可能已经重定位了,保险起见需要先读取向量表偏移量寄存器的值,再根据该中断在表中的位置,计算出服务例程入口地址应写入的表项,再填写之。

如果一直使用ROM中的向量表,则无需此步骤。

5. 为该中断设置优先级。

6. 使能该中断示例汇编代码如下:LDR R0, =0xE000ED0C ; 应用程序中断及复位控制寄存器LDR R1, =0x05FA0500 ; 使用优先级组5 (2/6)STR R1, [R0] ; 设置优先级组...MOV R4, #8 ; ROM 中的向量表LDR R5, =(NEW_VECT_TABLE+8)LDMIA R4!, {R0-R1} ; 读取NMI 和硬fault 的向量STMIA R5!, {R0-R1} ; 拷贝它们的向量到新表中...LDR R0, =0xE000ED08 ; 向量表偏移量寄存器的地址LDR R1, =NEW_VECT_TABLESTR R1, [R0] ; 把向量表重定位...LDR R0, =IRQ7_Handler ; 取得IRQ #7 服务例程的入口地址LDR R1, =0xE000ED08 ; 向量表偏移量寄存器的地址LDR R1, [R1]ADD R1, R1,#(4*(7+16)); 计算IRQ #7 服务例程的入口地址STR R0, [R1] ; 在向量表中写入IRQ #7 服务例程的入口地址...LDR R0, =0xE000E400 ; 外部中断优先级寄存器阵列的基地址MOV R1, #0xC0STRB R1, [R0,#7] ; 把IRQ #7 的优先级设置为0xC0 ...LDR R0, =0xE000E100 ; SETEN 寄存器的地址MOV R1, #(1<<7) ; 置位IRQ #7 的使能位STR R1, [R0] ; 使能IRQ #7。

中断方式及接口

中断方式及接口
请求触发器 完成 屏蔽 CP 请求 屏蔽 请求触发器
完成
CP
(2)如何传送中断请求?
1)使用单独请求线
请求
2)使用公共请求线
公共请求 CPU
I/O I/O
CPU
请求
I/O
I/O
2.中断判优 (1)优先顺序 故障、DMA、外中断(输入、输出) (2)CPU现行程序与外设请求的判优
1)CPU设置允许中断标志 =1,开中断 (模型机采用) =0,关中断 2)CPU设置程序状态字的优先级字段 为现行程序赋予优先级 <外设请求优先级,响应 ≥外设请求优先级,不响应
(3)各外设请求的判优
1)软件判优 由程序查询顺序确定优先级。可灵活修改优先级。 2)硬件判优 例.中断控制器判优 中断控制器(如8259)集中解决请求信号的接收、屏蔽、判 优、编码等问题。
D7~D0
INT INTA 7 0 IRR: 00010100 IMR: 00000100 ISR: 00001000 不发INT 7 0 00010100 00000000 00001000 发INT
模型机的外中断源安排: 8259 通过IRQ2进行扩展。 (1)接口组成 两个扩展中断源共用一个接口。
5 4 3 2 1
IRQ0 系统时钟 IRQ1 实时时钟 IRQ2 通信 IRQ7 打印机
0
命令字格式: 启动1 停止1 选通1 启动2 停止2 选通2
状态字格式: 忙1 完成1 出错1 忙2 完成2 出错2
第二节 中断方式及接口 7.2.1 中断基本概念 1.定义 CPU暂时中止现行程序的执行,转去执行为某个随 机事态服务的中断处理程序。处理完毕后自动恢 复原程序的执行。 2.实质与特点 (1)实质 方法:保存断点,保护现场; 程序切换 恢复现场,返回断点。 时间:一条指令结束时切换。 保证程序的完整性。

IRQ0中断处理全过程

IRQ0中断处理全过程
}
就是简单的设置bh_base和bh_mask.
看看这些的定义:
atomic_t bh_mask_count[32];
unsigned long bh_active = 0;
unsigned long bh_mask = 0;
void (*bh_base[32])(void);
bh_base[]
31 bh_active 0
}
mark_bh()函数把bh_active相应的位置1.
这里看到了没有,其实时钟中断有两个下半部分。
一个TIMER_BH,一个TQUEUE_BH。
4现在来看看系统执行下半底过程。do_bottom_half
①do_bottom_half(\kernel\softirq.c)做一些处理后,就调用run_bottom_halves();
来看看init_bh是怎么处理的。
去掉一些加琐解琐的东西,就变成以下了。
void init_bh(int nr, void (*routine)(void))
{
bh_base[nr] = routine;
atomic_set(&bh_mask_count[nr], 0);
bh_mask |= 1 << nr;
s),
对于IRQ0来说,它会间接的调用timer_interrupt(),上面已经讲过。
④timer_interrupt(\arch\i386\kernel\Time.c)是内核接收到IRQ0之后使用的函数,从
CPU时间截记数器中读取一些属性值。如果有值,就调用do_timer_interrup
t(同一个文件中)。
③do_IRQ在\arch\i386\kernel\irq.c

微机原理与接口技术:中断处理的基本过程

微机原理与接口技术:中断处理的基本过程
15
5. 中断返回
返回到原程序的断点处,恢复硬件现场,继续执行原程序。中断返回 操作是中断响应操作的逆过程。
16
12ห้องสมุดไป่ตู้
中断控制器判优 中断控制器,如Intel8259A,可以以多种方式设置中断源的中断优先级。 中断控制器中有一个中断优先级判别器,它自动判别出目前提出中断请求 的优先级最高的中断源,并将它的中断向量码送到数据总线,CPU接收中 断向量码并据此找到它的中断服务程序。
13
3. 中断响应
经过中断判优,中断处理就进入中断响应阶段。中断响应时,CPU向中断 源发出中断响应信号,同时: ① 保护硬件现场; ② 关中断; ③ 保护断点; ④ 获得中断服务程序的入口地址。
14
4. 中断服务
中断服务程序的一般结构为: (1)保护现场。在中断服务程序的起始部分安排若干条入栈指令,将各 寄存器的内容压入堆栈保存。 (2)开中断。在中断服务程序执行期间允许级别更高的中断请求中断现 行的中断服务程序,实现中断嵌套。 (3)中断服务。完成中断源的具体要求。 (4)恢复现场。中断服务程序结束前,必须恢复主程序的中断现场。通 常是将保存在堆栈中的现场信息弹出到原来的寄存器中。 (5)中断返回。返回到原程序的断点处,继续执行原程序。
菊花链判优电路 CPU收到中断请求,如果允许中断,CPU发出中断响应信号。中断响应信 号首先到达菊花链的前端,如果中断源1提出了中断请求,它就会截获中 断响应信号,封锁它,使它不能向下一个中断源传送。不论下面的中断源 有没有提出中断请求,都不可能接收到中断响应信号,因此它们的中断请 求也不能被响应。
. A2
. A3
. . A4
。 A5
A6
&
I5

中断处理过程有哪些?中断处理过程的五个阶段

中断处理过程有哪些?中断处理过程的五个阶段

中断处理过程有哪些?中断处理过程的五个阶段中断处理全过程指的是从中断源发出中断请求开始,CPU响应这个请求,现行程序被中断,转至中断服务程序,直到中断服务程序执行完毕,CPU再返回原来的程序继续执行的整个过程。

那么具体的中断处理全过程是哪些呢,下面我就带着大家一起具体看看吧!中断处理过程的五个阶段中断处理的基本过程包括中断请求、中断判优、中断响应、中断服务和中断返回等五个阶段。

1.中断请求阶段1)发生在CPU内部的中断(内部中断),不需要中断请求,CPU 内部的中断控制逻辑直接接收处理。

2)外部中断请求由中断源提出。

外部中断源利用CPU的中断输入引脚输入中断请求信号。

一般CPU设有两个中断请求输入引脚:可屏蔽中断请求输入引脚和不可屏蔽中断请求输入引脚。

1.1中断请求触发器每个中断源发中断请求信号的时间是不确定的,而CPU在何时响应中断也是不确定的。

所以,每个中断源都有一个中断请求触发器,锁存自己的中断请求信号,并保持到CPU响应这个中断请求之后才将其清除。

1.2中断允许触发器在CPU内部有一个中断允许触发器,当其为"1'时,允许CPU响应中断,称为开中断。

若其为"0',不允许CPU响应中断,中断被屏蔽,称为关中断。

%%通常,当CPU复位时,中断允许触发器也复位为"0',即关中断。

当CPU中断响应时,CPU自动关闭中断,禁止接受另一个新的中断。

%%中断允许触发器的状态可以用开中断或关中断指令来设置。

2.中断判优阶段CPU一次只能接受一个中断源的请求,当多个中断源同时向CPU 提出中断请求时,CPU必须找出中断优先级最高的中断源,这一过程称为中断判优。

中断判优可以采用硬件方法,也可采用软件方法。

2.1软件判优CPU检测到中断请求后,首先读取中断请求寄存器的内容,逐位检测它们的状态,检测到某一位为1,就确定对应的中断源有中断请求,转去执行它的中断服务程序。

中断异常处理流程

中断异常处理流程

中断异常处理流程1.特殊中断响应与返回系统运行时,特殊可能会随时发生。

当一个特殊出现以后,ARM微处理器会执行下列几步操作:1) 将下一条指令的地址存入相应连接寄存器LR,以便程序在处理特殊返回时能从正确的位置重新开始执行。

2) 将CPSR复制到相应的SPSR中。

3) 根据特殊类型,强制设置CPSR的运行模式位。

4) 强制PC从有关的特殊向量地址取下一条指令执行,从而跳转到相应的特殊处理程序处。

这些工作是由ARM 内核完成的,不需要用户程序参与。

特殊处理完毕之后,ARM 微处理器会执行下列几步操作从特殊返回:1) 将连接寄存器LR的值减去相应的偏移量后送到PC中。

2) 将SPSR复制回CPSR中。

3) 若在进入特殊处理时设置了中断禁止位,要在此清除。

这些工作务必由用户在中断处理函数中实现。

为保证在ARM处理器发生特殊时不至于处于未知状态,在应用程序的设计中,首先要进行特殊处理。

使用的方式是在特殊向量表中的特定位置放置一条跳转指令,跳转到特殊处理程序。

当ARM处理器发生特殊时,程序计数器PC会被强制设置为对应的特殊向量,从而跳转到特殊处理程序。

当特殊处理完成以后,返回到主程序继续执行。

能够认为应用程序总是从复位特殊处理程序开始执行的,因此复位特殊处理程序不需要返回。

2.特殊处理程序设计2.1 特殊响应流程由于向量表的限制,只能有一条指令B完成32MB范围内的跳转,并不能保证所有的特殊处理函数都位于32MB范围内。

为了扩展跳转范围,需要二次跳转才能把特殊处理函数的地址传送给PC。

特殊处理调用关系如图1所示。

三星公司网站提供了test2410_r11软件包,其中2410init.s有如下代码:HandlerXXXsub sp,sp,#4 ;减少sp,储存跳转地址stmfd sp!,{r0} ;将工作寄存器压入堆栈ldr r0,=HandleXXX ;将HandleXXX地址放入r0ldr r0,[r0] ;将中断程序入口地址放入r0str r0,[sp,#4] ;将中断程序入口地址压入堆栈ldmfd sp!,{r0,pc} ;将工作寄存器与中断程序入口地址弹出到r0与PC图1特殊处理调用同时在RAM中定义了存有中断程序入口地址表_ISR_STARTADDRESS:AREA RamData, DA TA, READWRITE^ _ISR_STARTADDRESSHandleReset # 4HandleUndef # 4HandleSWI # 4HandlePabort # 4HandleDabort # 4HandleReserved # 4HandleIRQ # 4HandleFIQ # 4通常HandlerXXX位于程序入口地址32MB范围内,HandleXXX是以_ISR_STARTADDRESS为基地址的RAM中地址。

ARMlinux的中断处理过程(转)

ARMlinux的中断处理过程(转)

ARMlinux的中断处理过程(转)⼀、前⾔本⽂主要以ARM体系结构下的中断处理为例,讲述整个中断处理过程中的硬件⾏为和软件动作。

具体整个处理过程分成三个步骤来描述:1、第⼆章描述了中断处理的准备过程2、第三章描述了当发⽣中的时候,ARM硬件的⾏为3、第四章描述了ARM的中断进⼊过程4、第五章描述了ARM的中断退出过程本⽂涉及的代码来⾃3.14内核。

另外,本⽂注意描述ARM指令集的内容,有些source code为了简短⼀些,删除了THUMB相关的代码,除此之外,有些debug相关的内容也会删除。

⼆、中断处理的准备过程1、中断模式的stack准备ARM处理器有多种process mode,例如user mode(⽤户空间的AP所处于的模式)、supervisor mode(即SVC mode,⼤部分的内核态代码都处于这种mode)、IRQ mode(发⽣中断后,处理器会切⼊到该mode)等。

对于 kernel,其中断处理处理过程中,ARM 处理器⼤部分都是处于SVC mode。

但是,实际上产⽣中断的时候,ARM处理器实际上是进⼊IRQ mode,因此在进⼊真正的IRQ异常处理之前会有⼀⼩段IRQ mode的操作,之后会进⼊SVC mode进⾏真正的IRQ异常处理。

由于IRQ mode只是⼀个过度,因此IRQ mode的栈很⼩,只有12个字节,具体如下:struct stack {u32 irq[3];u32 abt[3];u32 und[3];} ____cacheline_aligned;static struct stack stacks[NR_CPUS];除了irq mode,linux kernel在处理abt mode(当发⽣data abort exception或者prefetch abort exception的时候进⼊的模式)和und mode(处理器遇到⼀个未定义的指令的时候进⼊的异常模式)的时候也是采⽤了相同的策略。

如何解决电脑中断请求IRQ冲突

如何解决电脑中断请求IRQ冲突

如何解决电脑中断请求IRQ冲突(2009-11-09 15:30:47)转载标签:如何解决irq冲突it如何解决IRQ冲突轻松分配板卡资源中断是计算机处理特殊问题的一个过程,当计算机执行程序的过程中出现某个特殊情况时,会暂时中止现行程序,转去执行这一事件的程序,处理完毕之后再回到原来程序的中断点继续执行的整个过程叫做中断。

什么是IRQ那么,什么是IRQ(中断请求)呢?中断请求是由某个设备发出并同时请求CPU产生中断的一个请求响应信号。

通常情况下,计算机是根据中断请求的优先级来决定究竟应当首先响应哪一个设备的中断请求的(中断请求IRQ0~1RQ15中,IRQ0的优先级别最高,IRQ15最低)。

原则上,计算机中每个设备自身只有惟一的一个中断请求通道,即IRQ值(又叫IRQ号)。

当两个硬件设备同时使用同一个中断通道(IRQ值)时,就会发生IRQ冲突,因为这个时候处理器已经无法准确判断收到的中断请求究竟来自于哪个设备了。

IRQ的分配与冲突产生的原因表1 各irq在bios中所对应的硬件设备irq编号设备名称用途irq0time电脑系统计时器irq1keyboard键盘redirect irq9与irq9相接,mpu-401 mdi使用该irqirq3com2串口设备irq4com1串口设备irq5lpt2建议声卡使用该irqirq6fdd软驱传输控制用irq7lpt1打印机传输控制用irq8cmos alert即时时钟irq9redirect irq2与irq2相接;可设定给其他硬件使用irq10reversed建议网卡使用该irqirq11reversed与irq10相同,都是保留给pci硬件使用,建议分配给显卡irq12ps/2mouse接ps/2鼠标,若无,也可设定给其他硬件使用fpu协处理器用,例如fpu(浮点运算器)irq14primary ide主硬盘传输控制器(1号)irq15secondary ide从硬盘传输控制器(2号)在我们使用的计算机中,大都是由一个中断控制器8259来控制系统中每个硬件的IRQ值。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
i8259A_irq_type定义如下:
static struct hw_interrupt_type i8259A_irq_type = {
"XT-PIC",
startup_8259A_irq,
shutdown_8259A_irq,
do_8259A_IRQ,
enable_8259A_irq,
disable_8259A_irq
};
do_8259A_IRQ()是个重要的函数,是个IRQ响应处理程序。
同一个文件下,去掉那些不相关的部分,如下:
static void do_8259A_IRQ(unsigned int irq, struct pt_regs * regs)
{ struct irqaction * action;
{
bh_base[nr] = routine;
atomic_set(&bh_mask_count[nr], 0);
bh_mask |= 1 << nr;
}
就是简单的设置bh_base和bh_mask.
看看这些的定义:
atomic_t bh_mask_count[32];
unsigned long bh_active = 0;
s),
对于IRQ0来说,它会间接的调用timer_interrupt(),上面已经讲过。
④timer_interrupt(\arch\i386\kernel\Time.c)是内核接收到IRQ0之后使用的函数,从
CPU时间截记数器中读取一些属性值。如果有值,就调用do_timer_interrup
t(同一个文件中)。
irq_desc[i].depth = 0;
if (i < 16) {
irq_desc[i].handler = &i8259A_irq_type;
} else {
irq_desc[i].handler = &no_irq_type;
}
}
}
把IRQ小于16的handler都置为了i8259A_irq_type。
比较重要的调用就是init_ISA_irqs();
③init_ISA_irqs()在同一个文件里
void init_ISA_irqs (void)
{ int i;
for (i = 0; i < NR_IRQS; i++) {
irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = 0;
irq_desc[irq].handler->handle(irq, &regs);
if (1) {
if (bh_active & bh_mask)
do_bottom_half();/*处理下半部分*/
}
}
其实这里irq_desc[irq].handler->handle(irq, &regs);就是do_8259A_IRQ(irq,&reg
⑥时钟中断的另外一个下半底tqueue_bh(\kernel\Sched.c)
run_old_timers();
run_timer_list();
}
④void run_old_timers(void)
{/*
*简单的遍历处理timer_table数组的列表项,
*如果定时器已经触发,就调用相关的函数。*/
struct timer_struct *tp;
unsigned long mask;
⑤在do_timer_interrupt中又调用do_timer(\kernel\sched.c)。其他东西现在不感兴趣

⑥void do_timer(struct pt_regs * regs)
{
/*全局变量jiffies加1*/
(*(unsigned long *)&jiffies)++;
lost_ticks++;/*丢失的定时器滴答的数目*/
IRQ0中断处理全过程
1:系统注册IRQ0(时钟中断)的下半部分的处理过程。
在\kernel\sched.c的sched_init函数中
init_bh(TIMER_BH, timer_bh);/*TIMER_BH==0*/
init_bh(TQUEUE_BH, tqueue_bh);/*TQUEUE_BH==2*/
对于IRQ0,其实就是timer_interrupt函数。
不,其实现在还不是,等time_init()完就基本差不多了。
⑤time_init()在\arch\i386\kernel\Time.c中
感兴趣的就是setup_x86_irq(0, &irq0);作用就是给IRQ0增加一个操作。即timer_inte
}
mark_bh()函数把bh_active相应的位置1.
这里看到了没有,其实时钟中断有两个下半部分。
一个TIMER_BH,一个TQUEUE_BH。
4现在来看看系统执行下半底过程。do_bottom_half
①do_bottom_half(\kernel\softirq.c)做一些处理后,就调用run_bottom_halves();
continue;
timer_active &= ~mask;
tp->fn();
sti();
}
}
老的系统定时器如下组织:
timer_table[32] timer_struct
Timer_struct
Timer_active
31 0
⑤run_timer_list()也差不多是这样组织的。
Timer_head timer_list timer_list
unsigned long bh_mask = 0;
void (*bh_base[32])(void);
bh_base[]
31 bh_active 0
Bottom half handler(timer_bh)
31 bh_mask 0
不好意思,画的这么难看:P
如果bh_mask的第N位被置为1,则表明bh_base[]中的第N个指针指向了一个Bottom half
rrupt().
static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer",
NULL, NULL};
现在关于IRQ0的初始化完成了。变成如下图示:
irq_desc_t irq_desc[]
struct hw_interrupt_type
{
int status;
int cpu = smp_processor_id();
irq_enter(cpu, irq);
status = 1; /* Force the "do bottom halves" bit */
do {
if (!(action->flags & SA_INTERRUPT))
②void run_bottom_halves(void)
{
unsigned long active;
void (**bh)(void);
active = get_active_bhs();/*取得激活的下半底*/
clear_active_bhs(active);/*清那些激活的下半底*/
bh = bh_base;
mark_bh(TIMER_BH);/*标记timer的下半部*/
if (!user_mode(regs))
lost_ticks_system++;/*如果在系统模式下
*在系统模式下丢失的滴答数加1
*/
if (tq_timer)/*判断定时器队列中有无任务*/
mark_bh(TQUEUE_BH);/*如果有,标记定时器队列的下半部分*/
do {
if (active & 1)
(*bh)();
bh++;
active >>= 1;
} while (active);
}
③对于IRQ0来说,(*bh)();就是timer_bh(\kernel\Sched.c);
void timer_bh(void)
{/*这是定时器真正的下半部分*/
update_times();/*更新统计数字*/
if (status & SA_SAMPLE_RANDOM)
add_interrupt_randomness(irq);
__cli();
irq_exit(cpu, irq);
return status;
}
只注意这里一个函数:
action->handler(irq, action->dev_id, regs);
例程。
如果bh_active的第N位被置为1,则表明一旦调度进程许可,立即调用第N个Bottom hal
f例程。
bh_mask_count[]跟踪为每个下半部分提出的enable/disable请求嵌套对的数组。
2.系统初始化时钟中断(IRQ0)
①先看看start_kernel(\init\main.c)吧
}
handle_IRQ_event(irq, regs, action);
}
④handle_IRQ_event()也在同一个文件里。
int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqacti
相关文档
最新文档