linux 内核 --- 中断子系统
ARM芯片有硬件中断号,比如0~15是SGI中断
linux内核规定了软件中断号及软件中断号的功能;不直接使用ARM芯片的硬件中断号是因为linux内核是适配多架构操作系统,比如有些芯片硬件中断号20是GPIO中断,有些芯片是25;linux统一规定了某个中断号对应GPIO中断。这样就存在硬件中断号和软件中断号的映射(IRQ domain)
下面除非特别说明,否则出现的中断号都是软件中断号
相关API
request_irq() // 注册中断,第一个参数就是软件中断号 freee_irq() // 注销中断
代码分析
总体流程
触发中断,硬件会根据触发的中断类型自动做一些事情
下图是IRQ中断,跳转到中断代码之前,CPU自动完成的操作
把进中断前的 CPSR 保存到 SPSR_irq,返回地址保存到 LR_irq;
设置CPSR.M = '10010',进入IRQ模式(类似于CM3 的 Thread 模式和 Handler 模式)
设置CPSR.I = '1',关闭 IRQ 中断
跳转到 IRQ 中断函数
跳转到 vector_irq,vector_irq 是用宏实现的,接着执行 __irq_usr
__irq_usr() ---> irq_handler() ---> handle_arch_irq() == gic_handle_irq() ---> handle_domain_irq() ---> handle_irq_desc() ---> generic_handle_irq_desc()
gic 初始化(gic_irq_domain_map())的时候,会设置 desc 的 handle_irq,对于 IRQ 中断,就是 handle_fasteoi_irq()。最后在 __handle_irq_event_percpu() 执行 request_irq() 设置的中断服务函数 action->handler()
request_irq()
每个中断号都对应一个 struct irq_desc 实例,request_irq() 的目的就是填写对应中断号的 struct irq_desc,比如填写中断服务函数。
当触发中断时,就可以根据中断号取出对应的中断服务函数执行。