Linux中断处理流程

合集下载

Linux 内核软中断(softirq)执行分析

Linux 内核软中断(softirq)执行分析

Linux 内核软中断(softirq)执行分析Author: sinisterEmail: sinister@Homepage:Date: 2007-01-11本文对 Linux 内核软中断的执行流程进行了分析,并尽可能的结合当前运行环境详细地写出我的理解,但这并不表明我的理解一定正确。

这本是论坛里的一篇帖子,发出来是为了抛砖引玉,如果您在阅读本文时发现了我的错误,还望得到您的指正。

今天无意中看了眼 2.6 内核的软中断实现,发现和以前我看到的大不相同(以前也是走马观花,不大仔细),可以说改动很大。

连 softirq 的调用点都不一样了,以前是三个调用点,今天搜索了一下源代码,发现在多出了ksoftirqd 后,softirq 在系统中的调用点仅是在 ISR 返回时和使用了local_bh_enable() 函数后被调用了。

网卡部分的显示调用,我觉得应该不算是系统中的调用点。

ksoftirqd 返回去调用 do_softirq() 函数应该也只能算是其中的一个分支,因为其本身从源头上来讲也还是在 ISR 返回时irq_exit() 调用的。

这样一来就和前些日子写的那份笔记(Windows/Linux /Solaris 软中断机制)里介绍的 Linux 内核部分的软中断有出处了,看来以后讨论 Linux kernel 代码一定要以内核版本为前题,要不非乱了不可。

得买本 Linux 方面的书了,每次上来直接看相关代码也不是回事,时间也不允许。

//// do_IRQ 函数执行完硬件 ISR 后退出时调用此函数。

//void irq_exit(void){account_system_vtime(current);trace_hardirq_exit();sub_preempt_count(IRQ_EXIT_OFFSET);//// 判断当前是否有硬件中断嵌套,并且是否有软中断在// pending 状态,注意:这里只有两个条件同时满足// 时,才有可能调用 do_softirq() 进入软中断。

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链表中注册的处理函数。

啊嘛18.

啊嘛18.

●嵌入式系统是以应用为中心,以计算机技术为基础,软硬件可裁剪,适用于应用系统对功能、可靠性、成本、体积、功耗有严格要求的专用计算机系统●系统组成部分是嵌入式系统硬件平台、嵌入式操作系统和嵌入式系统应用。

硬件平台为各种嵌入式器件、设备(ARM、PowerPC、Xscale、MIPS);操作系统指在嵌入式硬件平台上运行的操作系统,主流的有嵌入式Linux、μCLinux、WinCE、μC/OS-Ⅱ、VxWorks。

RTOS有QNX,pSOS,vxworks,RT-Linux。

●用户进程:进程控制块、系统堆栈、用户堆栈、程序代码及数据段组成;Linux可管理512个进程,进程调度的police域有:SCHED_OTHER; SCHED_FIFO; SCHED_RR。

进程控制相关的系统调用函数有:fork,exit,vfork,wait,execve。

●五种状态进程状态:①就绪状态TASK_RUNNING 0;②可中断等待状态TASK_INTERRUPTIBLE 1;③不可中断等待状态TASK_UNINTERRUPTIBLE 2;④停止状态、僵尸状态TASK_ZOMBIE 4;⑤中止状态TASK_STOPPED 8。

●从Linux的调度来看,支持非实时(普通)和实时两种进程。

●Linux 虚拟文件系统维护描述整个虚拟文件系统以及实际已挂装的文件系统的数据结构。

常见文件系统:yaffs, jsffs, cramfs。

文件系统安装必须调用mount命令,把其他子系统安装到已经存在于文件系统的空闲节点上。

类型的注册函数为register filesystem,超级用户卸载文件系统使用umount命令。

●交换机制:将不用或暂不用的页框中的页移出,装上新的页面;linux三级分页结构●进程的通信与同步机制有管道、信号、消息队列、共享内存和信号量集等el 中。

Linux 管道有:匿名管道和命名管道;从信号的可靠性方面,信号分为:可靠信号和不可靠信号●linux设备驱动注册基本参数有设备名称,设备驱动的数据结构、设备号和次设备号。

Linux中断-简单中断,以GPIO中断为例

Linux中断-简单中断,以GPIO中断为例

Linux中断-简单中断,以GPIO中断为例Linux中断基础概念中断上下⽂Linux内核的中断回调可以有两部分,即上下⽂。

当中断⽐较简单时,可以只有上⽂。

⼀般中断上⽂是指由中断产⽣的回调函数直接执⾏的部分;中断下⽂在上⽂中启⽤调度,再由内核调度。

中断上⽂:处理尽可能少的任务,特点是响应速度快中断下⽂:处理耗时任务,可以被新的中断打断中断嵌套Linux中断现在不能嵌套,之前可以中断相关的函数及命令获取中断号如果是有设备树的内核,⼀般通过节点的interrupt-parent和interrupt属性来描述中断对GPIO来说,GPIO的节点可以作为中断控制器,⼀般由BSP⼚家编写<linux/of_irq.h>//从设备树的设备节点中获取中断号unsigned int irq_of_parse_and_map(struct device_node *dev, int index);//参数:dev设备节点,index索引(节点中interrupts属性可能包含多条中断信息,通过index确认)//返回值:中断号//如果是GPIO的话,可以不从设备树中获取int gpio_to_irq(unsigned int gpio);//参数:gpio的编号//返回值:gpio对应的中断号申请中断申请中断的函数int request_irq(unsigned int irq,irq_handler_t handler,unsigned long flags,const char *name,void *dev);//参数://irq:要申请中断的中断号//handler:中断处理函数//flags:中断标志//name:中断名字,可在/proc/interrupts⽂件中看到对应的名字//dev:flags为IRQF_SHARED时,dev⽤来区分不同的中断。

⼀般将dev设置为设备结构体,传递给irq_handler_t的第⼆个参数//返回值:0申请成功,其他负值申请失败;如果返回-EBUSY标识已经被申请中断标志(申请中断函数的flags参数)定义在 include/linux/interrupt.h中常见的中断标志:标志功能IRQF_SHARED多个设备共享⼀个中断线,申请中断函数的dev参数是区分它们的唯⼀标志IRQF_ONESHOT单次中断,中断执⾏⼀次就结束IRQF_TRIGGER_NONE⽆触发IRQF_TRIGGER_RISING上升沿触发IRQF_TRIGGER_FALLING下降沿触发IRQF_TRIGGER_HIGH⾼电平触发IRQF_TRIGGER_LOW低电平触发中断处理函数使⽤request_irq申请中断的时候需要中断处理函数irq_handler_t来做参数,这⾥的irq_handler_t函数可以理解为中断上⽂的回调函数,发⽣中断时内核会调⽤处理函数。

10-5 Linux操作系统 - 中断、异常及系统调用

10-5 Linux操作系统 - 中断、异常及系统调用

10.5.4 中断上半部分的处理 一、 中断控制器 •每个硬件设备控制器都能通过中断请求线 发出中断请求(简称IRQ) •所有设备的中断请求线又连到中断控制器 的输入端。 •在x86单CPU的机器上采用两个8259A芯片作 为中断控制器,一主一从。
•当8259A有中断信号输入同时中断信号不被 屏蔽时,主8259A向CPU发出 INT信号,请求 中断。这时如果CPU是处于允许中断状况, CPU就会发信号给8259A进入中断响应周期。 •在对8259A芯片的初始化过程中,第n号中 断在IDT表中的向量号为 n+32
•IDT中向量号的使用情况如下: 0-31 异常与非屏蔽中断使用。 32-47 可屏蔽中断使用32至47 128(0x80)实现系统调用。 其余 未使用 •保存现场 发生异常时在核心栈的程序计数器eip的 值取决于具体情况。一般情况下eip保存的 下一条指令的地址,但对于页面异常,保存 的产生异常的这条指令的地址而不是下一条 指令的地址
中断向量表IDT •IDT是中断/异常处理在内核的入口。IDT表 项还记录了一些其它信息用以安全检查。 •IDT在系统初始化时创建。 •每个中断/异常都有一个向量号,该号的值 在0-255之间,该值是中断/异常在IDT中的 索引。 •每个中断/异常均有其相应的处理函数,中 断/异常在使用前必须在IDT中注册信息以保 证发生中断/异常时能找到相应的处理函数。
struct hw_interrupt_type { const char * typename; 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 (*end)(unsigned int irq); void (*set_affinity)(unsigned int irq, unsigned long mask); };

linux中断处理流程

linux中断处理流程

linux中断处理流程Linux中断处理流程Linux中断处理是操作系统中的一个重要组成部分,用于响应硬件设备的事件。

在Linux中,中断可以是外部中断,如硬件设备发送的中断信号,也可以是内部中断,如软件产生的异常或系统调用。

中断处理的目的是及时响应硬件设备的事件,并采取相应的措施来处理这些事件。

一、中断的触发中断是由硬件设备发送的一个信号,用于通知操作系统某个事件的发生。

这个信号可以是一个电平的变化,一个特定的数据包,或者一个指定的硬件寄存器的变化。

当硬件设备检测到某个事件发生时,它会向处理器发送一个中断信号,处理器会立即停止当前正在执行的任务,保存当前的上下文,并跳转到中断处理程序的入口点。

二、中断处理程序的执行中断处理程序是一个特殊的函数,负责处理中断事件。

当中断发生时,处理器会跳转到中断处理程序的入口点,并执行相应的代码。

中断处理程序的执行过程可以分为以下几个步骤:1. 保存上下文:在执行中断处理程序之前,处理器需要保存当前任务的上下文,包括程序计数器、寄存器和堆栈指针等。

这样可以确保在中断处理程序执行完成后,能够正确地返回到原来的任务。

2. 中断处理程序的执行:一旦保存了上下文,处理器就会执行中断处理程序的代码。

中断处理程序根据中断的类型,执行相应的操作。

例如,对于外部中断,中断处理程序可能需要读取硬件设备的状态,处理数据包或执行特定的操作。

对于内部中断,中断处理程序可能需要处理异常或系统调用。

3. 中断处理程序的结束:当中断处理程序执行完成后,处理器会恢复之前保存的上下文,并将控制权返回给原来的任务。

这样原来的任务就可以继续执行,而不会受到中断的影响。

三、中断处理的优先级在Linux中,中断处理有不同的优先级。

这是为了确保对于紧急事件的及时处理。

中断的优先级由硬件设备决定,通常是通过一个优先级编码器来实现的。

当多个中断同时发生时,处理器会按照优先级的顺序来处理中断。

高优先级的中断会立即被处理,而低优先级的中断则会被推迟到稍后处理。

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()来防止软中断嵌套,和抢占硬中断环境。

中断处理流程

中断处理流程

中断处理流程linux中断处理浅析最近在研究异步消息处理, 突然想起linux内核的中断处理, ⾥⾯由始⾄终都贯穿着"重要的事马上做, 不重要的事推后做"的异步处理思想. 于是整理⼀下~第⼀阶段--获取中断号每个CPU都有响应中断的能⼒, 每个CPU响应中断时都⾛相同的流程. 这个流程就是内核提供的中断服务程序.在进⼊中断服务程序时, CPU已经⾃动禁⽌了本CPU上的中断响应, 因为CPU不能假定中断服务程序是可重⼊的.中断处理程序的第⼀步要做两件事情:1. 将中断号压⼊栈中; (不同中断号的中断对应不同的中断服务程序⼊⼝)2. 将当前寄存器信息压⼊栈中; (以便中断退出时恢复)显然, 这两步都是不可重⼊的(如果在保存寄存器值时被中断了, 那么另外的操作很可能就把寄存器给改写了, 现场将⽆法恢复), 所以前⾯说到的CPU进⼊中断服务程序时要⾃动禁⽌中断.栈上的信息被作为函数参数, 调⽤do_IRQ函数.第⼆阶段--中断串⾏化进⼊do_IRQ函数, 第⼀步进⾏中断的串⾏化处理, 将多个CPU同时产⽣的某⼀中断进⾏串⾏化.其⽅法是如果当前中断处于"执⾏"状态(表明另⼀个CPU正在处理相同的中断), 则重新设置它的"触发"标记, 然后⽴即返回. 正在处理同⼀中断的那个CPU完成⼀次处理后, 会再次检查"触发"标记, 如果设置, 则再次触发处理过程.于是, 中断的处理是⼀个循环过程, 每次循环调⽤handle_IRQ_event来处理中断.第三阶段--关中断条件下的中断处理进⼊handle_IRQ_event函数, 调⽤对应的内核或内核模块通过request_irq函数注册的中断处理函数.注册的中断处理函数有个中断开关属性, ⼀般情况下, 中断处理函数总是在关中断的情况下进⾏的. ⽽调⽤request_irq注册中断处理函数时也可以设置该中断处理函数在开中断的情况下进⾏,这种情况⽐较少见, 因为这要求中断处理代码必须是可重⼊的. (另外, 这⾥如果开中断, 正在处理的这个中断⼀般也是会被阻塞的. 因为正在处理某个中断的时候, 硬件中断控制器上的这个中断并未被ack, 硬件不会发起下⼀次相同的中断.)中断处理函数的过程可能会很长, 如果整个过程都在关中断的情况下进⾏, 那么后续的中断将被阻塞很长的时间.于是, 有了soft_irq. 把不可重⼊的⼀部分在中断处理程序中(关中断)去完成, 然后调⽤raise_softirq 设置⼀个软中断, 中断处理程序结束. 后⾯的⼯作将放在soft_irq⾥⾯去做.第四阶段--开中断条件下的软中断上⼀阶段循环调⽤完当前所有被触发的中断处理函数后, do_softirq函数被调⽤, 开始处理软件中断.在软中断机制中, 为每个CPU维护了⼀个若⼲位的掩码集, 每位掩码代表⼀个中断号. 在上⼀阶段的中断处理函数中, 调⽤raise_softirq设置了对应的软中断, 到了这⾥, 软中断对应的处理函数就会被调⽤(处理函数由open_softirq函数来注册).可以看出, 软中断与中断的模型很类似, 每个CPU有⼀组中断号, 中断有其对应的优先级, 每个CPU处理属于⾃⼰的中断. 最⼤的不同是开中断与关中断.于是, ⼀个中断处理过程被分成了两部分, 第⼀部分在中断处理函数⾥⾯关中断的进⾏, 第⼆部分在软中断处理函数⾥⾯开中断的进⾏.由于这⼀步是在开中断条件下进⾏的,这⾥还可能发⽣新的中断(中断嵌套),然后新中断对应的中断处理⼜将开始⼀个新的第⼀阶段~第三阶段。

linux 软中断原理

linux 软中断原理

linux 软中断原理Linux软中断是操作系统中一种用于处理紧急任务的机制。

它采用的是一种特殊的中断方式,可以在用户态和内核态之间切换,以提供高效的中断处理能力。

在Linux内核中,软中断是一种特殊的中断处理机制。

相比硬中断,软中断的处理过程更加高效,可以在短时间内完成中断处理,并且不会占用过多的系统资源。

软中断的原理是通过将中断处理函数放入一个队列中,然后由内核线程负责依次执行队列中的中断处理函数。

在Linux内核中,每个软中断都有一个唯一的标识符,并且有一个对应的中断处理函数。

当某个软中断被触发时,中断处理函数会被调用。

这样,操作系统就可以根据不同的软中断来执行相应的中断处理操作。

软中断的使用可以提高系统的响应速度和处理能力。

在Linux内核中,有一些常用的软中断,如定时器中断、网络中断等。

这些软中断可以及时地处理系统中的紧急任务,并且不会对系统的正常运行产生太大的影响。

软中断的原理是基于内核线程的机制实现的。

在Linux内核中,有一个特殊的内核线程,称为软中断处理线程。

这个线程会不断地检查软中断队列,如果队列中有待处理的中断,就会调用相应的中断处理函数。

软中断的实现需要考虑到多核处理器的情况。

在多核处理器中,每个CPU核心都有自己的软中断处理队列和软中断处理线程。

这样,每个CPU核心都可以独立地处理软中断,提高系统的并发处理能力。

软中断的使用可以提高系统的可靠性和稳定性。

在Linux内核中,软中断可以用于处理系统中的紧急任务,如定时器中断、网络中断等。

这些紧急任务需要及时地处理,以保证系统的正常运行。

Linux软中断是一种高效的中断处理机制,可以提高系统的响应速度和处理能力。

它通过将中断处理函数放入一个队列中,然后由专门的内核线程负责执行,可以及时地处理系统中的紧急任务,并且不会对系统的正常运行产生太大的影响。

通过软中断的使用,可以提高系统的可靠性和稳定性,保证系统的正常运行。

linux终止指令运行的方法

linux终止指令运行的方法

linux终止指令运行的方法在Linux中,可以通过多种方式来终止正在运行的指令。

这些方法可以帮助您中断无响应的指令、停止不需要的进程或关闭正在进行的任务。

下面将介绍几种常见的终止指令运行的方法。

1. 使用Ctrl+C终止指令:最常用的方法是使用Ctrl+C组合键来终止运行中的指令。

在终端窗口中,按下Ctrl键和字母C键,将强制停止当前正在运行的指令。

这在大多数情况下都会正常工作,但对于一些指令可能无法生效。

2. 使用Ctrl+Z暂停指令:仅适用于实时交互式指令。

在运行指令时,按下Ctrl键和字母Z键,将暂停正在运行的指令并返回到终端提示符。

可以使用`fg`命令恢复被暂停的指令,或使用`bg`命令将其转换为后台运行。

3. 使用kill命令终止进程:使用kill命令可以终止运行于后台的进程。

可以使用以下命令格式:`kill <进程ID>`,其中"<进程ID>"是待终止进程的ID。

要查看所有正在运行的进程及其ID,可以使用`ps aux`命令。

还可以使用`killall <进程名>`来终止指定名称的所有进程。

4. 使用pkill命令终止进程:类似于kill命令,pkill命令也用于终止正在运行中的进程。

它可以通过进程名来终止进程,而不需要指定进程ID。

例如,使用`pkill firefox`可以终止所有名为firefox的进程。

5. 使用xkill命令关闭图形界面应用程序:对于图形界面应用程序,可以使用xkill命令来终止运行中的应用程序。

在终端中运行xkill命令后,光标将变成一个“X”符号。

然后,将光标移动到要终止的应用程序窗口上并单击鼠标左键,即可立即终止该应用程序。

6. 使用systemctl命令关闭服务:对于Linux系统中的服务,可以使用systemctl命令来停止运行中的服务。

例如,使用`sudo systemctl stop <服务名称>`可以停止指定名称的服务。

中断处理的主要步骤

中断处理的主要步骤

中断处理的主要步骤
《中断处理的主要步骤中断处理的主要步骤》
嘿,朋友!今天咱们来聊聊中断处理的那些主要步骤,这可有趣啦!
你知道吗,当中断发生的时候,就好像是系统突然被喊了一声“停!有急事!”这时候,第一步就是要赶紧“察觉”到这个中断。

就好比你正在专心做一件事,突然有人拍你肩膀,你得先反应过来有人找你。

然后呢,系统就得保存当前的“状态”。

这就像是你在出门前,得把家里正在做的事的情况都记下来,不然回来就乱套啦。

把那些重要的数据啊、程序的位置啊啥的都存好,这样等处理完中断的事儿,还能回来接着干。

搞清楚原因后,就得按照相应的规则去处理这个中断啦。

这就像是人家找你帮忙,你得知道怎么帮,用啥办法。

而且处理的时候还得认认真真,不能马虎。

处理完之后,可别忘了把之前保存的“状态”给恢复回来。

就像你忙完别人的事儿,得回到自己家,把之前记下来的情况还原,继续做自己的事。

呢,还得告诉系统“搞定啦,继续前进!”让系统能正常地运行下去。

你看,这中断处理就像是系统里的一场小冒险,每个步骤都很关键,一个不小心就可能出乱子。

不过只要咱们把这些步骤都做好,系
统就能稳稳当当,顺顺利利地工作啦!怎么样,是不是觉得还挺有意思的?
好啦,今天关于中断处理的主要步骤就聊到这儿,希望你能明白哟!。

ARM Linux对中断的处理

ARM Linux对中断的处理
int (*set_wake)(unsigned int irq, unsigned int on);
void (*bus_lock)(unsigned int irq);
void (*bus_sync_unlock)(unsigned int irq);
/* Currently used only by UML, might disappear one day.*/
kstat_irqs: irq stats per cpu
irq_2_iommu: iommu with this irq
handle_irq:高层的irq时间处理程序(如果为NULL,则默认调用__do_IRQ())
chip:底层的中断硬件访问,指向PIC对象(irq_chip结构),它服务于IRQ线,Linux中断管理系统使用该成员来进行中断控制器的访问。
struct proc_dir_entry *dir;
#endif
const char *name;
}____cacheline_internodealigned_in_smp;
irq_desc结构体(中断描述符)中各个字段说明:
irq:中断描述符的中断号
timer_rand_state: pointer to timer rand state struct
#endif
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 */

【原创】Linux中断子系统(四)-Workqueue

【原创】Linux中断子系统(四)-Workqueue

【原创】Linux中断子系统(四)-Workqueue背景•Read the fucking source code! --By 鲁迅•A picture is worth a thousand words. --By 高尔基说明:1.Kernel版本:4.142.ARM64处理器,Contex-A53,双核3.使用工具:Source Insight 3.5, Visio1. 概述•Workqueue工作队列是利用内核线程来异步执行工作任务的通用机制;•Workqueue工作队列可以用作中断处理的Bottom-half机制,利用进程上下文来执行中断处理中耗时的任务,因此它允许睡眠,而Softirq和Tasklet在处理任务时不能睡眠;来一张概述图:•在中断处理过程中,或者其他子系统中,调用workqueue的调度或入队接口后,通过建立好的链接关系图逐级找到合适的worker,最终完成工作任务的执行;2. 数据结构2.1 总览此处应有图:•先看看关键的数据结构:1.<>e>work_struct:工作队列调度的最小单位,work item;2.workqueue_struct:工作队列,work item都挂入到工作队列中;3.worker:work item的处理者,每个worker对应一个内核线程;4.worker_pool:worker池(内核线程池),是一个共享资源池,提供不同的worker来对work item进行处理;5.pool_workqueue:充当桥梁纽带的作用,用于连接workqueue和worker_pool,建立链接关系;下边看看细节吧:2.2 workstruct work_struct用来描述work,初始化一个work并添加到工作队列后,将会将其传递到合适的内核线程来进行处理,它是用于调度的最小单位。

关键字段描述如下:struct work_struct {atomic_long_t data; //低比特存放状态位,高比特存放worker_pool的ID或者pool_workqueue的指针struct list_head entry; //用于添加到其他队列上work_func_t func; //工作任务的处理函数,在内核线程中回调#ifdef CONFIG_LOCKDEPstruct lockdep_map lockdep_map;#endif};图片说明下data字段:2.3 workqueue•内核中工作队列分为两种:1.bound:绑定处理器的工作队列,每个worker创建的内核线程绑定到特定的CPU上运行;2.unbound:不绑定处理器的工作队列,创建的时候需要指定WQ_UNBOUND标志,内核线程可以在处理器间迁移;•内核默认创建了一些工作队列(用户也可以创建):1.system_mq:如果work item执行时间较短,使用本队列,调用schedule[_delayed]_work[_on]()接口就是添加到本队列中;2.system_highpri_mq:高优先级工作队列,以nice值-20来运行;3.system_long_wq:如果work item执行时间较长,使用本队列;4.system_unbound_wq:该工作队列的内核线程不绑定到特定的处理器上;5.system_freezable_wq:该工作队列用于在Suspend时可冻结的work item;6.system_power_efficient_wq:该工作队列用于节能目的而选择牺牲性能的work item;7.system_freezable_power_efficient_wq:该工作队列用于节能或Suspend时可冻结目的的work item;struct workqueue_struct关键字段介绍如下:struct workqueue_struct {struct list_head pwqs; /* WR: all pwqs of this wq */ //所有的pool_workqueue都添加到本链表中struct list_head list; /* PR: list of all workqueues */ //用于将工作队列添加到全局链表workqueues中struct list_head maydays; /* MD: pwqs requesting rescue */ //rescue状态下的pool_workqueue添加到本链表中struct worker *rescuer; /* I: rescue worker */ //rescuer内核线程,用于处理内存紧张时创建工作线程失败的情况struct pool_workqueue *dfl_pwq; /* PW: only for unbound wqs */char name[WQ_NAME_LEN]; /* I:workqueue name *//* hot fields used during command issue, aligned to cacheline */unsigned int flags ____cacheline_aligned; /* WQ: WQ_* flags */struct pool_workqueue __percpu *cpu_pwqs; /* I: per-cpu pwqs */ //Per-CPU都创建pool_workqueuestruct pool_workqueue __rcu *numa_pwq_tbl[]; /* PWR: unbound pwqs indexed by node */ //Per-Node创建pool_workqueue...};2.4 worker•每个worker对应一个内核线程,用于对work item的处理;•worker根据工作状态,可以添加到worker_pool的空闲链表或忙碌列表中;•worker处于空闲状态时并接收到工作处理请求,将唤醒内核线程来处理;•内核线程是在每个worker_pool中由一个初始的空闲工作线程创建的,并根据需要动态创建和销毁;关键字段描述如下:struct worker {/* on idle list while idle, on busy hash table while busy */union {struct list_head entry; /* L: while idle */ //用于添加到worker_pool的空闲链表中struct hlist_node hentry; /* L: while busy */ //用于添加到worker_pool的忙碌列表中};struct work_struct *current_work; /* L: work being processed */ //当前正在处理的workwork_func_t current_func; /* L: current_work's fn */ //当前正在执行的work回调函数struct pool_workqueue *current_pwq; /* L: current_work's pwq */ //指向当前work所属的pool_workqueuestruct list_head scheduled; /* L: scheduled works */ //所有被调度执行的work都将添加到该链表中/* 64 bytes boundary on 64bit, 32 on 32bit */struct task_struct *task; /* I: worker task */ //指向内核线程struct worker_pool *pool; /* I: the associated pool */ //该worker所属的worker_pool/* L: for rescuers */struct list_head node; /* A: anchored at pool->workers */ //添加到worker_pool->workers链表中/* A: runs through worker->node */...};2.5 worker_pool•worker_pool是一个资源池,管理多个worker,也就是管理多个内核线程;•针对绑定类型的工作队列,worker_pool是Per-CPU创建,每个CPU都有两个worker_pool,对应不同的优先级,nice值分别为0和-20;•针对非绑定类型的工作队列,worker_pool创建后会添加到unbound_pool_hash哈希表中;•worker_pool管理一个空闲链表和一个忙碌列表,其中忙碌列表由哈希管理;关键字段描述如下:struct worker_pool {spinlock_t lock; /* the pool lock */int cpu; /* I: the associated cpu */ //绑定到CPU的workqueue,代表CPU IDint node; /* I: the associated node ID */ //非绑定类型的workqueue,代表内存Node IDint id; /* I: pool ID */unsigned int flags; /* X: flags */unsigned long watchdog_ts; /* L: watchdog timestamp */struct list_head worklist; /* L: list of pending works */ //pending状态的work添加到本链表int nr_workers; /* L: total number of workers */ //worker的数量/* nr_idle includes the ones off idle_list for rebinding */int nr_idle; /* L: currently idle ones */struct list_head idle_list; /* X: list of idle workers */ //处于IDLE状态的worker添加到本链表struct timer_list idle_timer; /* L: worker idle timeout */struct timer_list mayday_timer; /* L: SOS timer for workers *//* a workers is either on busy_hash or idle_list, or the manager */DECLARE_HASHTABLE(busy_hash,BUSY_WORKER_HASH_ORDER); //工作状态的worker添加到本哈希表中/* L: hash of busy workers *//* see manage_workers() for details on the two manager mutexes */struct worker *manager; /* L: purely informational */struct mutex attach_mutex; /* attach/detach exclusion */struct list_head workers; /* A: attached workers */ //worker_pool管理的worker添加到本链表中struct completion *detach_completion; /* all workers detached */struct ida worker_ida; /* worker IDs for task name */struct workqueue_attrs *attrs; /* I: worker attributes */struct hlist_node hash_node; /* PL: unbound_pool_hash node */ //用于添加到unbound_pool_hash中...} ____cacheline_aligned_in_smp;2.6 pool_workqueue•pool_workqueue充当纽带的作用,用于将workqueue和worker_pool关联起来;关键字段描述如下:struct pool_workqueue {struct worker_pool *pool; /* I: the associated pool */ //指向worker_poolstruct workqueue_struct *wq; /* I: the owning workqueue */ //指向所属的workqueueint nr_active; /* L: nr of active works */ //活跃的work数量int max_active; /* L: max active works */ //活跃的最大work数量struct list_head delayed_works; /* L: delayed works */ //延迟执行的work挂入本链表struct list_head pwqs_node; /* WR: node on wq->pwqs */ //用于添加到workqueue链表中struct list_head mayday_node; /* MD: node on wq->maydays */ //用于添加到workqueue链表中...} __aligned(1 << WORK_STRUCT_FLAG_BITS);2.7 小结再来张图,首尾呼应一下:3. 流程分析3.1 workqueue子系统初始化•workqueue子系统的初始化分成两步来完成的:workqueue_init_early和workqueue_init。

Exynos4412中断处理流程详解

Exynos4412中断处理流程详解

Exynos4412中断处理流程详解 Linux 中,当外设触发中断后,⼤体处理流程如下: a -- 具体CPU architecture相关的模块会进⾏现场保护,然后调⽤machine driver对应的中断处理handler; b -- machine driver对应的中断处理handler中会根据硬件的信息获取HW interrupt ID,并且通过irq domain模块翻译成IRQ number; c -- 调⽤该IRQ number 对应的high level irq event handler,在这个high level的handler中,会通过和interupt controller交互,进⾏中断处理的flow control(处理中断的嵌套、抢占等),当然最终会遍历该中断描述符的IRQ action list,调⽤外设的specific handler来处理该中断; d -- 具体CPU architecture相关的模块会进⾏现场恢复; 总结下来,整个过程可以分为三部分:1、硬件处理部分;2、汇编处理部分;3、C 处理部分; 下⾯我们来追踪⼀下代码,了解当中断发⽣时,Linux 是如何处理的,前⾯的⼀些中断初始化部分就不再这⾥详述了,下⾯开始具体分析: ⼀、硬件处理部分 当⼀切准备好之后,⼀旦打开处理器的全局中断就可以处理来⾃外设的各种中断事件了。

当外设(SOC内部或者外部都可以)检测到了中断事件,就会通过interrupt requestion line上的电平或者边沿(上升沿或者下降沿或者both)通知到该外设连接到的那个中断控制器,⽽中断控制器就会在多个处理器中选择⼀个,并把该中断通过IRQ(或者FIQ,本⽂不讨论FIQ的情况)分发给该processor。

ARM处理器感知到了中断事件后,会进⾏下⾯⼀系列的动作(硬件处理部分): 1、切换处理器模式 修改 CPSR 寄存器中的 M[4:0],切换处理器模式位 IRQ Mode(这⾥M[4:0] 所添值为 10010); 2、保护现场 保存发⽣中断时,CPSR值与PC值(为恢复现场做准备);这⾥要注意,此时中断可能发⽣在 usr mode (⽤户空间),也可能发⽣在 SVC mode(内核空间); 3、mask IRQ exception 关闭IRQ中断,也就是设定CPSR.I = 1; 4、设定PC值为IRQ exception vector 实现向异常向量表的跳转,ARM处理器会跳转到IRQ的exception vector地址,到这硬件所做的⼯作就结束了,下⾯就是软件⾏为了。

MIPS Linux异常中断处理

MIPS Linux异常中断处理

MIPS Linux异常中断代码分析CurrentVersion: 0.16Date: 2007-04-12Author: Dajie Tan <jiankemeng@>版本历史版本状态作 者参与者起止日期备注0.10Dajie Tan07-04-12完成草稿0.12Dajie Tan07-04-19完善A 0.14Dajie Tan07-08-17完善B.1 0.15Dajie Tan07-08-19完善B.2 0.16Dajie Tan07-09-10完善B.3本文拟以龙芯2E (兼容MIPS III)为例,对内核的异常、中断系统作一个框架式的描述,将结合2.6.18的代码来说明。

A. 概述龙芯2E在高优先级异常出现时,在设置了某些寄存器后,会根据异常类型跳转到相应的固定地址处(高优先级异常服务入口),操作系统会将相应的异常处理程序,置于这些地址处。

龙芯2E的高优先级异常有:冷启动、热重启、非屏蔽中断,TLB重填(32位模式),xTLB重填(64位模式),cache错误,其他异常。

龙芯2E之高优先级异常入口地址有以下五个:Table A.1 优先级异常入口当龙芯正常运行时,STATUS 寄存器之BEV位为0 ,0xFFFFFFFF 80000000地址处不经TLB映射、但缓存;当龙芯启动时,STATUS 寄存器之BEV位为1,0xFFFF FFFF BFC0 0200 地址处龙芯不缓存、不经TLB映射。

MIPS 下TLB、Cache都要OS参与管理,在其启动时OS尚未接管系统,这个时候不采用TLB、Cache机制是很重要的。

注意,冷启动、热重启、非屏蔽中断的入口地址始终位于0xFFFF FFFF BFC0 0000由此可见龙芯2E启动时(冷启动异常或者热重启异常),执行的第一条指令是位于地址0xFFFF FFFF BFC0 0000 处的,实际上龙芯电脑上所用之BOOTLOADER(PMON)的第一条指令就映射在地址空间的0xFFFF FFFF BFC0 0000处。

中断处理的一般流程

中断处理的一般流程

中断处理的一般流程
中断处理是计算机系统中非常重要的一部分,它允许计算机在
执行程序的过程中响应外部事件。

中断处理的一般流程通常包括以
下几个步骤:
1. 中断请求,外部设备向处理器发送中断请求,通知处理器发
生了某种事件,比如输入/输出操作完成、时钟中断等。

2. 中断响应,处理器接收到中断请求后,立即停止当前正在执
行的程序,保存当前程序的状态,并跳转到中断处理程序的入口点。

3. 中断处理程序执行,处理器开始执行中断处理程序,这是一
个预先定义好的程序,用于处理特定的中断事件。

中断处理程序可
能包括保存当前程序的状态、执行特定的中断服务例程、处理中断
事件等。

4. 中断服务例程执行,中断服务例程是中断处理程序的一部分,用于执行特定的中断处理任务,比如处理输入/输出操作、更新系统
时钟等。

5. 恢复现场,中断服务例程执行完成后,处理器会恢复之前被
中断的程序的状态,包括恢复程序计数器、寄存器状态等,然后继
续执行被中断的程序。

6. 中断处理结束,处理器完成中断处理后,会回到之前被中断
的程序继续执行,直到下一个中断事件发生。

中断处理的一般流程保证了计算机系统能够及时响应外部事件,并在处理完中断事件后继续执行之前的程序,从而提高了系统的效
率和可靠性。

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(处理器遇到⼀个未定义的指令的时候进⼊的异常模式)的时候也是采⽤了相同的策略。

linux以太网中断处理流程

linux以太网中断处理流程

linux以太网中断处理流程English Answer:1. Interrupt Generation.The network interface controller (NIC) detects a packet arrival on the wire.The NIC issues an interrupt to the CPU.2. Interrupt Handling in the Kernel.The kernel interrupt handler is invoked.The handler identifies the source of the interrupt and handles it accordingly.For Ethernet interrupts, the kernel invokes the Ethernet driver.3. Ethernet Driver Processing.The Ethernet driver reads the packet from the NIC's receive buffer.The driver checks the packet's integrity using the checksum.If the checksum fails, the packet is dropped.4. Network Stack Processing.The driver passes the valid packet to the network stack.The network stack processes the packet based on its destination IP address.The stack routes the packet to the appropriate upper-layer protocol (e.g., TCP, UDP).5. Upper-Layer Protocol Processing.The upper-layer protocol processes the packet and generates a response if necessary.The response is passed back to the network stack.6. Packet Transmission.The network stack sends the response packet to the Ethernet driver.The driver writes the packet to the NIC's transmit buffer.The NIC sends the packet out on the wire.7. Interrupt Exit.The kernel interrupt handler returns control to the interrupted process.Chinese Answer:1. 中断生成。

linux的irq中断子系统分析

linux的irq中断子系统分析

本文以Linux中断子系统架构为视角,旨在提供一个对Linux中断系统的全局认识,不涉及具体实现细节。

一、Linux中断子系统架构在Linux中断子系统(generic irq)出现之前,内核使用__do_IRQ处理所有的中断,这意味着__do_IRQ中要处理各种类型的中断,这会导致软件的复杂性增加,层次不分明,而且代码的可重用性也不好。

通用中断子系统的原型最初出现于ARM体系中,一开始内核的开发者们把3种中断类型区分出来(电平中断、边缘中断、简易中断),后来又针对某些需要回应eoi(end of interrupt)的中断控制器,加入了fast eoi type,针对smp加入了per cpu type。

把这些不同的中断类型抽象出来后,成为了中断子系统的流控层。

要使所有的体系架构都可以重用这部分的代码,中断控制器也被进一步地封装起来,形成了中断子系统中的芯片级硬件封装层。

二、芯片级硬件封装层中断系统与CPU硬件关系密切,linux系统为了兼容各种型号的CPU,提供了对于各种CPU的特性及其中断控制器的底层封装,这样就可以把底层的硬件实现尽可能地隐藏起来,使得驱动程序的开发人员不用关注底层的实现。

该部分主要工作是:●实现不同CPU的中断入口,初始化中断向量表,该部分通常由汇编实现。

●对中断控制器实现软件抽象(struct irq_chip),源码路径如:”arch/arm/plat-s3c24xx/irq.c”该部分初始化过程中,系统根据设备使用的中断控制器的类型,实现irq_chip结构中的接口,并把该irq_chip实例注册到irq_desc.irq_data.chip字段中,这样各个irq和中断控制器就进行了关联,只要知道irq编号,即可得到对应到irq_desc结构,进而可以通过chip指针访问中断控制器。

其初始化流程如下图所示:三、中断流控层由linux内核提供,所谓中断流控是指合理并正确地处理连续发生的中断,比如一个中断在处理中,同一个中断再次到达时如何处理,何时应该屏蔽中断,何时打开中断,何时回应中断控制器等一系列的操作。

中断服务程序基本框架

中断服务程序基本框架

中断服务程序基本框架
中断服务程序是操作系统中非常重要的部分,它允许计算机在执行程序的过程中,响应来自外部设备的事件。

中断服务程序通常由操作系统内核编写,其基本框架包括以下步骤:
1. 确定中断类型:中断可以分为硬件中断和软件中断,操作系统需要根据中断类型来确定下一步的操作。

2. 保存寄存器状态:在进入中断服务程序之前,操作系统需要将当前处理器状态保存,在处理完中断后再恢复。

3. 执行中断服务程序:根据中断类型,执行相应的中断服务程序代码,完成对外部事件的响应。

4. 恢复寄存器状态:在中断服务程序执行完毕后,需要将先前保存的处理器状态恢复,以便程序可以继续执行。

5. 返回中断源:在完成中断处理后,操作系统需要返回到中断源,继续执行原来的程序。

在实际编写中断服务程序时,需要考虑多种情况和异常情况,例如优先级处理、中断嵌套、中断重入等。

因此,中断服务程序的编写需要考虑周全,并进行充分的测试和验证,以确保系统的可靠性和稳定性。

- 1 -。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Linux中断处理流程先从函数注册引出问题吧。

一、中断注册方法在linux内核中用于申请中断的函数是request_irq(),函数原型在Kernel/irq/manage.c中定义:int request_irq(unsigned int irq, irq_handler_t handler,unsigned long irqflags, const char *devname, void *dev_id)irq是要申请的硬件中断号。

handler是向系统注册的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数,dev_id参数将被传递给它。

irqflags是中断处理的属性,若设置了IRQF_DISABLED(老版本中的SA_INTERRUPT,本版zhon已经不支持了),则表示中断处理程序是快速处理程序,快速处理程序被调用时屏蔽所有中断,慢速处理程序不屏蔽;若设置了IRQF_SHARED(老版本中的SA_SHIRQ),则表示多个设备共享中断,若设置了IRQF_SAMPLE_RANDOM(老版本中的SA_SAMPLE_RANDOM),表示对系统熵有贡献,对系统获取随机数有好处。

(这几个flag是可以通过或的方式同时使用的)dev_id在中断共享时会用到,一般设置为这个设备的设备结构体或者NULL。

devname设置中断名称,在cat /proc/interrupts中可以看到此名称。

request_irq()返回0表示成功,返回-INVAL表示中断号无效或处理函数指针为NULL,返回-EBUSY表示中断已经被占用且不能共享。

关于中断注册的例子,大家可在内核中搜索下request_irq。

在编写驱动的过程中,比较容易产生疑惑的地方是:1、中断向量表在什么位置?是如何建立的?2、从中断开始,系统是怎样执行到我自己注册的函数的?3、中断号是如何确定的?对于硬件上有子中断的中断号如何确定?4、中断共享是怎么回事,dev_id的作用是?本文以2.6.26内核和S3C2410处理器为例,为大家讲解这几个问题。

二、异常向量表的建立在ARM V4及V4T以后的大部分处理器中,中断向量表的位置可以有两个位置:一个是0,另一个是0xffff0000。

可以通过CP15协处理器c1寄存器中V位(bit[13])控制。

V和中断向量表的对应关系如下:V=0 ~ 0x00000000~0x0000001CV=1 ~ 0xffff0000~0xffff001Carch/arm/mm/proc-arm920.S中.section ".text.init", #alloc, #execinstr__arm920_setup:...... orr r0, r0, #0x2100 @ ..1. ...1 ..11 (1)//bit13=1 中断向量表基址为0xFFFF0000。

R0的值将被付给CP15的C1.在linux中,向量表建立的函数为:init/main.c->start_kernel()->trap_init()void __init trap_init(void){unsigned long vectors = CONFIG_VECTORS_BASE;……memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);....}在2.6.26内核中CONFIG_VECTORS_BASE最初是在各个平台的配置文件中设定的,如:arch/arm/configs/s3c2410_defconfig中CONFIG_VECTORS_BASE=0xffff0000__vectors_end 至 __vectors_start之间为异常向量表。

位于arch/arm/kernel/entry-armv.S.globl __vectors_start__vectors_start:swi SYS_ERROR0:b vector_und + stubs_offset //复位异常:ldr pc, .LCvswi + stubs_offset //未定义指令异常:b vector_pabt + stubs_offset //软件中断异常:b vector_dabt + stubs_offset //数据异常:b vector_addrexcptn + stubs_offset //保留:b vector_irq + stubs_offset //普通中断异常:b vector_fiq + stubs_offset //快速中断异常:.globl __vectors_end:__vectors_end:__stubs_end 至__stubs_start之间是异常处理的位置。

也位于文件arch/arm/kernel/entry-armv.S中。

vector_und、vector_pabt、vector_irq、vector_fiq都在它们中间。

stubs_offset值如下:.equ stubs_offset, __vectors_start + 0x200 - __stubs_startstubs_offset是如何确定的呢?(引用网络上的一段比较详细的解释)当汇编器看到B指令后会把要跳转的标签转化为相对于当前PC的偏移量(±32M)写入指令码。

从上面的代码可以看到中断向量表和stubs都发生了代码搬移,所以如果中断向量表中仍然写成bvector_irq,那么实际执行的时候就无法跳转到搬移后的vector_irq处,因为指令码里写的是原来的偏移量,所以需要把指令码中的偏移量写成搬移后的。

我们把搬移前的中断向量表中的irq入口地址记irq_PC,它在中断向量表的偏移量就是irq_PC-vectors_start,vector_irq在stubs中的偏移量是vector_irq-stubs_start,这两个偏移量在搬移前后是不变的。

搬移后vectors_start在0xffff0000处,而stubs_start在0xffff0200处,所以搬移后的vector_irq相对于中断向量中的中断入口地址的偏移量就是,200+vector_irq在stubs中的偏移量再减去中断入口在向量表中的偏移量,即200+vector_irq-stubs_start-irq_PC+vectors_start = (vector_irq-irq_PC) + vectors_start+200-stubs_start,对于括号内的值实际上就是中断向量表中写的vector_irq,减去irq_PC是由汇编器完成的,而后面的vectors_start+200-stubs_start就应该是stubs_offset,实际上在entry-armv.S中也是这样定义的三、中断处理过程这一节将以S3C2410为例,描述linux-2.6.26内核中,从中断开始,中断是如何一步一步执行到我们注册函数的。

3.1 中断向量表 arch\arm\kernel\entry-armv.S__vectors_start:swi SYS_ERROR0b vector_und + stubs_offsetldr pc, .LCvswi + stubs_offsetb vector_pabt + stubs_offsetb vector_dabt + stubs_offsetb vector_addrexcptn + stubs_offsetb vector_irq + stubs_offsetb vector_fiq + stubs_offset.globl __vectors_end__vectors_end:中断发生后,跳转到b vector_irq + stubs_offset的位置执行。

注意现在的向量表的初始位置是0xffff0000。

3.2 中断跳转的入口位置 arch\arm\kernel\entry-armv.S.globl __stubs_start__stubs_start:/** Interrupt dispatcher*/vector_stub irq, IRQ_MODE, 4 @IRQ_MODE在include\asm\ptrace.h中定义:0x12.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).long __irq_invalid @ 4.long __irq_invalid @ 5.long __irq_invalid @ 6.long __irq_invalid @ 7.long __irq_invalid @ 8.long __irq_invalid @ 9.long __irq_invalid @ a.long __irq_invalid @ b.long __irq_invalid @ c.long __irq_invalid @ d.long __irq_invalid @ e.long __irq_invalid @ f上面代码中vector_stub宏的定义为:.macro vector_stub, name, mode, correction=0.align 5vector_\name:.if \correctionsub lr, lr, #\correction.endif@@ Save r0, lr_ (parent PC) and spsr_@ (parent CPSR)@stmia sp, {r0, lr} @ save r0, lrmrs lr, spsrstr lr, [sp, #8] @ save spsr@@ Prepare for SVC32 mode. IRQs remain disabled.@mrs r0, cpsreor r0, r0, #(\mode ^ SVC_MODE)msr spsr_cxsf, r0 @为后面进入svc模式做准备@@ the branch table must immediately follow this code@and lr, lr, #0x0f @进入中断前的mode的后4位@#define USR_MODE 0x00000010@#define FIQ_MODE 0x00000011@#define IRQ_MODE 0x00000012@#define SVC_MODE 0x00000013@#define ABT_MODE 0x00000017@#define UND_MODE 0x0000001b@#define SYSTEM_MODE 0x0000001fmov r0, spldr lr, [pc, lr, lsl #2] @如果进入中断前是usr,则取出PC+4*0的内容,即__irq_usr @如果进入中断前是svc,则取出PC+4*3的内容,即__irq_svcmovs pc, lr @ 当指令的目标寄存器是PC,且指令以S结束,则它会把@ spsr的值恢复给cpsr branch to handler in SVC mode.endm.globl __stubs_start__stubs_start:/** 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)用“irq, IRQ_MODE, 4”代替宏vector_stub中的“name, mode, correction”,找到了我们中断处理的入口位置为vector_irq(宏里面的vector_\name)。

相关文档
最新文档