可以参考内核文档IRQ-domain.txt 为什么引入IRQ-Domain 当早期的系统只存在一个interrupt-controller的时候,而且中断数目也不多的时候,一个很简单的做法就是一个中断号对应到...interrupt-contoller的一个号,可以说是简单的线性映射 而当一个系统中有多个interrupt-controller的时候,而且中断号也逐渐增加。...linux内核为了应对此问题,引入了IRQ-domain的概念 irq-domain的引入相当于一个中断控制器就是一个irq-domain。就是一个中断区域。...而Hwirq-num就是dts中配置的irq号 而第一列就是对应的softirq-num,也就是request_irq时传入的irq 中断控制器级联的情况图 hwirq到softirq的映射 当开机之后...函数进行hwirq到softirq的map 首先dts中配置的中断号都是hwirq 刚开机hwirq没有对应的softirq的,所以第一次开机需要进行hwirq和softirq之间建立map int irq_domain_alloc_descs
大家都知道,ARM有IRQ, FIQ, USR,SVC,ABORT等各种模式。当系统收到IRQ的时候,会进入ARM的IRQ模式。...那么,ARM Linux各种驱动的中断服务程序工作在ARM的IRQ模式吗? 答案是否定的。 我们加一段汇编来读CPSR: ? 然后我们随便找一个ARM Linux的中断服务程序去打印CPSR: ?...cpsr:40000193 低8位的二进制是10010011 那么对应ARM CPSR的查询,可以看出CPU处于ARM的SVC模式(低5位是10011),而且I bit被设置(第7位是1),所以是禁止IRQ...可见,ARM Linux最初进入IRQ模式后,比较快速地从IRQ模式切换到了SVC模式,但是这个时候,并没有使能CPSR的I bit,所以仍然是禁止其他中断嵌套进入的。
本节目标: 分析在linux中的中断是如何运行的,以及中断3大结构体:irq_desc、irq_chip、irqaction 在裸板程序中(参考stmdb和ldmia详解): 1.按键按下, 2....r5, lr get_irqnr_and_base r0, r6, r5, lr // get_irqnr_and_base:获取中断号,r0=中断号...; 3).清中断 asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs) //irq:中断号...*regs:发生中断前的各个寄存器基地址 { struct pt_regs *old_regs = set_irq_regs(regs); /*根据irq中断号,找到哪个中断, *desc =irq_desc...根据中断号和desc,调用函数指针,进入中断处理, irq_finish(irq); irq_exit(); set_irq_regs(old_regs); } 上面主要是执行desc_handle_irq
*dev_id) 参数说明: unsigned int irq:为要注册中断服务函数的中断号,比如外部中断0就是16,定义在mach/irqs.h irq_handler_t handler:为要注册的中断服务函数...,就是(irq_desc+ irq )->action->handler unsigned long irqflags: 触发中断的参数,比如边沿触发, 定义在linux/interrupt.h。 ...irq_desc *desc = irq_desc + irq; //根据中断号找到irq_ desc[irq] ... ......int irq, void *dev_id); 参数说明: unsigned int irq:要卸载的中断号 void *dev_id:这个是要卸载的中断action下的哪个服务函数, 2.1 free_irq...>= NR_IRQS) return; desc = irq_desc + irq; //根据中断号,找到数组 spin_lock_irqsave
中断描述符项定义 当中断发生,cpu获取到中断向量后,查找IDT中断描述符表得到相应的中断描述符,再根据中断描述符记录的信息来作权限判断,运行级别转换,最终调用相应的中断处理程序; 这里涉及到Linux...int)regs->bp); #endif /* CONFIG_IA32_EMULATION */ } syscall_return_slowpath(regs); } 通过中断向量号...硬件中断相关IDT的初始化也是在Linux启动时完成,在start_kernel中通过调用init_IRQ完成,我们来看一下: void __init init_IRQ(void) { int...pushq $(~vector+0x80) /* Note: always in signed byte range */ jmp common_interrupt 即先将中断号压栈...} exiting_irq(); set_irq_regs(old_regs); return 1; } 首先根据中断向量号获取到对应的中断描述符irq_desc,
中断处理 - 上半部(硬中断) 由于 APIC中断控制器 有点小复杂,所以本文主要通过 8259A中断控制器 来介绍Linux对中断的处理过程。...,handler 的第一个参数是中断号,第二个参数是设备对应的ID,第三个参数是中断发生时由内核保存的各个寄存器的值。...(irq); // 注册proc文件系统 return 0; } setup_irq() 函数比较简单,就是通过 irq 号来查找对应的 irq_desc_t 结构,并把新的 irqaction...regs) { int irq = regs.orig_eax & 0xff; /* 获取IRQ号 */ int cpu = smp_processor_id(); irq_desc_t...return 1; } do_IRQ() 函数首先通过IRQ号获取到其对应的 irq_desc_t 结构,注意的是同一个中断有可能发生多次,所以要判断当前IRQ是否正在被处理当中(判断 irq_desc_t
最近在研究异步消息处理, 突然想起linux内核的中断处理, 里面由始至终都贯穿着”重要的事马上做, 不重要的事推后做”的异步处理思想....将中断号压入栈中; (不同中断号的中断对应不同的中断服务程序入口) 2....栈上的信息被作为函数参数, 调用do_IRQ函数. 第二阶段 中断串行化 进入do_IRQ函数, 第一步进行中断的串行化处理, 将多个CPU同时产生的某一中断进行串行化....第三阶段 关中断条件下的中断处理 进入handle_IRQ_event函数, 调用对应的内核或内核模块通过request_irq函数注册的中断处理函数....在软中断机制中, 为每个CPU维护了一个若干位的掩码集, 每位掩码代表一个中断号.
最核心的结构体是irq_desc,之前为了易于理解,我们说在Linux内核中有一个中断数组,对于每一个硬件中断,都有一个数组项,这个数组就是irq_desc数组。...它就是个中转站,里面有irq_chip指针 irq_domain指针,都是指向别的结构体。 比较有意思的是irq、hwirq,irq是软件中断号,hwirq是硬件中断号。...比如上面我们举的例子,在GPIO中断B是软件中断号,可以找到irq_desc[B]这个数组项;GPIO里的第x号中断,这就是hwirq。 谁来建立irq、hwirq之间的联系呢?...比如GPIO控制器里有第1号中断,UART模块里也有第1号中断,这两个“第1号中断”是不一样的,它们属于不同的“域”──irq_domain。...但是我们在驱动中会使用request_irq(irq, handler)这样的函数来注册中断,irq是什么?它是软件中断号,它应该从“gpio1的第5号中断”转换得来。 谁把hwirq转换为irq?
我没有查到中断到底是何时引入的,但是从 Linux 问世以来就已经有了,而且 Linux 是基于 UNIX 开发的,可以认为 UNIX 就已经引入中断机制了,而且换个角度来说,UNIX 作为如此著名的操作系统...根据中断号去 IDT(中断向量表)中取得中断向量并执行中断处理程序,处理完成后,CPU 会返回当前的任务继续执行。...在中断向量表中,中断向量号顺序排列,每个中断向量号占用 4 字节,因此每个中断向量的内存位置就是 [0x0000:N 乘 4,0x0000:N+1 乘 4 - 1) 。...在 Linux 系统中,将 int32 - int47 对应于 8259A 中断控制芯片发出的硬件中断请求信号 IRQ0 - IRQ15,并把程序编程发出的系统调用中断设置为 int128 ,也就是 0x80...下面是 8259A 芯片中断请求发出的中断号列表: 中断请求号 中断号 用途 IRQ0 0x20(32) 8253 发出的 100HZ 时钟中断 IRQ1 0x21(33) 键盘中断 IRQ2 0x22
处理流程对比 在这里插入图片描述 参考资料: linux kernel的中断子系统之(七):GIC代码分析 Linux 4.9.88内核源码 Linux-4.9.88\drivers...它底下的4个中断触发时,都会导致GIC的33号中断被触发。 处理中断时,需要分辨:是谁触发了GIC 33号中断?这需要读取"chained intc"中的寄存器。...按下KEY时: 程序从GIC中读取寄存器知道发生了33号中断,通过GIC irq_domain可以知道virq为17 处理virq 17号中断:调用irq_desc[17].handle_irq...,确定是GPIO里2号引脚发生中断 通过GPIO irq_domain可以知道virq为102 处理virq 102号中断:调用irq_desc[102].handle_irq,即handleC...按下KEY时: 程序从GIC中读取寄存器知道发生了102号中断,通过GIC irq_domain可以知道virq为236 处理virq 236号中断:调用irq_desc[236].handle_irq
Linux内核提供了中断的注册接口: (1)注册中断 头文件 include\linux\interrupt.h 定义文件 include\linux\interrupt.h 函数原型 int...返回值 0 表示成功 -EINVAL (无效参数22)表示中断号无效。 -EBUSY (设备或者资源忙16)表示中断已经被占用。...(2)注销中断 void free_irq(unsigned int irq,void * dev_id) irq: 要注销的中断号 dev_id:其实就是注册时候使用的dev参数,在共享中断必不可少,...使能中断 void enable_irq(unsigned int irq); 参数:irq,要使能的中断对应的编号 (4)获取irq中断号 int gpio_to_irq(unsigned gpio...获取中断号*/ key_info[i].irq=gpio_to_irq(key_info[i].gpio); /*2.
= 0;//中断号 2.中断服务函数 中断服务函数的入口参数和返回值都是有规定的,后面会介绍。...(IRQ_HANDLED); } 3.注册函数和注销函数 GPIO中断注册与注销主要需要以下几个函数,第一个是gpio_to_irq,这是一个宏定义,作用是申请中断号,只有申请了中断号,才可以进行后面的操作...ret; } /* irq:中断号 type:中断类型 */ 可配置的中断类型有以下几种: #define IRQ_TYPE_NONE 0x00000000 /* Default, unspecified...request_threaded_irq(irq, handler, NULL, flags, name, dev); } /* irq:中断号 handler:中断服务程序 flags:中断类型..., desc); } /* irq:中断号 dev_id:如果中断设置为共享(IRQF_SHARED)的话,此参数用来区分具体的中断。
硬中断和虚拟中断号 在Linux 内核笔记之高层中断处理一文中,介绍了ARM gic中断控制器对于硬中断的处理过程。...对于软件工程师而言,我们不需要care是中断哪个中断控制器的第几个中断号, 因此linux kernel提供了一个虚拟中断号的概念。...irq_domain 接下来讨论硬件中断号是如何映射到虚拟中断号的linux kernel提供irq_domain的管理框架, 将hwirq映射到虚拟中断号上。...) +-> irq_create_mapping // 映射硬件中断号到虚拟中断号 +-> irq_domain_alloc_descs // 分配一个虚拟中断号 从allocated_irq...irq_data->hwirq中, 完成了硬中断到虚拟中断号的映射。
#endif 9997: .endm linux-4.19-rc3\kernel\irq\handle.c e. handle_arch_irq的处理过程: 请看视频和图片 读取寄存器获得中断信息...使用irq_desc[virq].irq_data.chip的函数清中断 对于0号中断,加上一个或控制器,形成一个共享中断,可以控制网卡中断irq_net和摄像头中断irq_camera, 在0号中断上有两个设备...从中断号开始依次查找,直到找到最后空闲项, 如果bit=0则虚拟中断号就是2 虚拟中断号保存在irq_domain结构体中 irq_domain linear_revmap[hwirq]...,…),中断号是通过宏方式进行定义的,所以直接使用中断号进行注册 如何使用新型中断号,注册irq 先在设备树中表明要使用那个中断,内核解析设备树时才会把这个中断号和某一个虚拟中断号挂钩,这些信息会转换成...-4.19-rc3.tar.gz 打上补丁: cd linux-4.19-rc3 patch -p1 linux-4.19-rc3_device_tree_for_irq_jz2440.
编程处理0号中断 1.1 效果演示 现在我们考虑改变一下0号中断处理程序的功能,即重新编写一个0号中断处理程序,它的功能是在屏幕中间显示“overflow!”然后返回到操作系统,如下图所示。...当CPU 执行div bh后,发生了除法溢出错误,产生0号中断信息,引发中断过程,CPU 执行我们编写的0号中断处理程序。在屏幕中间显示提示信息“overflow!”后,返回到操作系统中。...1.2 分析所要编写的中断处理程序 1.2.1 引发中断 当发生除法溢出的时候,产生0号中断信息,从而引发中断过程。...,即do0 的代码,就变成了0号中断的中断处理程序。...答:将它的地址放入CS、IP 中; 那么,我们如何让一段程序成为N号中断的中断处理程序? 答:将它的入口地址放入中断向量表的N号表项中。 2.
目录 Linux 中断的知识点梳理 中断的分类 中断号和中断向量 中断服务程序ISR 上半部分和下半部分 中断处理的注册和注销 API 实操:捕获键盘中断 示例代码 驱动程序传参 IO编址:IO端口和IO...中断号和中断向量 这张图只要记住中断号与中断向量的关系就可以了: 中断号与中断控制器(PIC/APIC)相关; 中断向量与 CPU 相关,用来查找中断处理函数的入口地址; 中断服务例程 ISR 中断服务程序...(unsigned int irq, void *dev_id); 参数说明: irq: 硬件中断号; dev_id: 中断程序的唯一标识; 实操:捕获键盘中断 示例代码 有了上面的知识铺垫,下面就来实操一下.../module.h> #include linux/interrupt.h> // 中断号 static int irq; // 驱动程序名称 static char * devname;...向驱动程序传参 示例代码中,在调用 request_irq 时,需要指定中断号和驱动程序的名称。 这两个参数是在加载驱动模块的时候,从命令行传入的。
GIC中断处理流程源码分析 参考资料: linux kernel的中断子系统之(七):GIC代码分析 Linux 4.9.88内核源码 Linux-4.9.88\drivers\irqchip...\irq-gic.c Linux-4.9.88/arch/arm/boot/dts/imx6ull.dtsi Linux 5.4内核源码 Linux-5.4\drivers\irqchip\irq-gic.c...假设要使用UART模块,它发出的中断连接到GIC的32号中断,分配的irq_desc序号为16 在GIC domain中会记录(32, 16) 那么注册中断时就是:request_irq(16, ......发生UART中断时 程序从GIC中读取寄存器知道发生了32号中断,通过GIC irq_domain可以知道virq为16 调用irq_desc[16]中的handleA函数,它的作用是调用action...按下KEY时: 程序从GIC中读取寄存器知道发生了33号中断,通过GIC irq_domain可以知道virq为16 调用irq_desc[16]中的handleB函数 handleB
一级中断控制器处理流程 2. 多级中断控制器处理流程 参考资料: linux kernel的中断子系统之(七):GIC代码分析 使用逐步演进的方法才能形象地理解。 1....假设要使用UART模块,它发出的中断连接到GIC的32号中断,分配的irq_desc序号为16 在GIC domain中会记录(32, 16) 那么注册中断时就是:request_irq(16, ......发生UART中断时 程序从GIC中读取寄存器知道发生了32号中断,通过GIC irq_domain可以知道virq为16 调用irq_desc[16]中的handleA函数,它的作用是调用action...按下KEY时: 程序从GIC中读取寄存器知道发生了33号中断,通过GIC irq_domain可以知道virq为16 调用irq_desc[16]中的handleB函数 handleB...读取GPIO寄存器,确定是GPIO里2号引脚发生中断 通过GPIO irq_domain可以知道virq为102 调用irq_desc[102]中的handleA函数,它的作用是调用action链表中用户注册的函数
9.调度引发缺页中断的进程,操作系统返回调用他的汇编例程 10.该例程恢复寄存器和其他状态信息,返回到用户空间继续执行,就好像缺页中断没有发生过。...linux内核对缺页异常的处理流程很复杂,但是基本思想和上述流程差不多。...下面看linux的基本处理流程: 内核处理缺页异常的主函数就是do_page_fault: /* * 缺页异常处理函数 * pt_regs 各个寄存器的值 * error_code,由硬件产生:...*/ if (regs->eflags & (X86_EFLAGS_IF|VM_MASK)) local_irq_enable(); mm = tsk->mm; //获取当前进程的内存描述符...), "=r" (x) : "m"(__m(addr)), "i"(errret), "0"(err)) //"m"(__m(addr)), "i"(4), "0"(4)) 经过以上分析,对linux
首先增加BRAM控制器和BRAM,然后增加中断,本文使用第11个中断,连接至IRQ_F2P 修改Linux设备树 /include/ "system-conf.dtsi" / { irq: irq...,上一级中断是intc,中断号需要查手册,第11个中断号(本文使用)是86,减去32(前面其他功能的中断),是54, 1表示的是中断触发形式,上升沿触发 中断程序 中断程序如下 #include linux...> #include linux/semaphore.h> #include linux/timer.h> #include linux/of_irq.h> #include linux/irq.h.../* 中断号 */ char name[10]; /* 名字 */ irqreturn_t (*handler)(int, void *); /* 中断服务函数 */ }; /*...* @param - irq : 中断号 * @param - dev_id : 设备结构。
领取专属 10元无门槛券
手把手带您无忧上云