当前位置: 首页 > news >正文

arm linux下的中断处理过程。

本文基于ast2600 soc来阐述,内核版本为5.10

1.中断gic初始化

start_kernel() -> init_IRQ() -> irqchip_init()

of_irq_init()主要是构建of_intc_desc.

489-514: 从__irqchip_of_table中找到dts node中匹配的of_table(匹配matches->compatible),

        然后申请desc, 保存匹配的of_table数据到desc,最后将desc插入intc_desc_lis中

521-541:调用desc->irq_init_cb.

我们先来看看这个of_table(__irqchip_of_table)有哪些数据。

这个__irqchip_of_table在arch/arm/kernel/vmlinux.lds申明了是在.init.data section中。

那么这个位置放置了些什么数据?

__irqchip_of_table中的数据由IRQCHIP_DECLARE()来声明和定义。

在我的板子上(arm cortex a7)的__irqchip_of_table数据如下:

所以,desc->irq_init_cb就是gic_of_init().

start_kernel() -> init_IRQ() -> irqchip_init() -> of_irq_init() -> gic_of_init()

gic_of_init()调用__gic_init_bases()去设置各种处理函数。比如设置handle_arch_irq为gic_handle_irq().

gic_init_chip()会设置irq_mask等函数,定义如下:

2. exception vector table.

Arm手册上说了,vector的地址有两个,一个是0,另一个是0xFFFF0000.

Arm linux实现时,vector设置的地址为0xFFFF0000.

start_kernel() -> setup_arch() -> paging_init() -> devicemaps_init()

devicemaps_init()调用early_trap_init()将异常向量表vector数据拷贝到vectors,然后将vectors映射到异常向量表地址0xffff0000。

我们继续看看异常向量表的定义__vectors_start.

__vectors_start放在.vectors section中。

.vectors段中定义的数据如下:

这个就是arm手册上定义的异常向量表的顺序:

对于普通中断,就是vector_irq.

vector_irq先保存现场数据:

1014-1016:保存r0, lr到栈sp,保存spsr到sp

1021-1023:设置ABORT模式。

1032-1033: lr为spsr的低4位,即表示中断前是什么mode(irq,fiq,svc等),然后加载异常

处理函数(pc + (mode << 2))指令,pc为当前指令地址+8(armv7为3级流水线)。

如果,中断前是user模式,mode(如下表)为0b10000,则对应的处理函数为

pc + (0b10000 & 0xf) << 2 = pc+0, 即为__irq_usr;

如果,中断前是svc模式,则这里对应的处理函数为

pc + (0b10011 & 0xf) << 2 = pc + 0b11<<2=pc + 12,即__irq_svc.

__irq_usr和__irq_svc都调用irq_handler处理中断。

irq_handler是一个宏。

irq_handler这个宏就是调用handle_arch_irq, 这个处理函数就是前面初始化介绍过在start_kernel() -> init_IRQ() -> irqchip_init() -> of_irq_init() -> gic_of_init() ->__gic_init_bases() -> set_handle_irq()的注册的函数gic_handle_irq().

gic_handle_irq()先读取interrupt ACKnowledge register(GIC_CPU_INTACK),这个读取操作就是ACK interrupt, 之后(362行), 写GIC_CPU_EOI告知GIC,本次中断处理完成,可以再次接受这个irq的中断。

然后调用handlr_domain_irq() -> __handle_domain_irq() -> generic_handle_irq() -> generic_handle_irq_desc() -> desc->handle_irq()

对于ast2600 MAC来说,这个desc->handle_irq()就是ftgmac100_interrupt().

ftgmac100_interrupt()在最后调用napi_schedule_irqoff()去raise一个NET_RX_SOFTIRQ中断。这个软中断会调用ftgmac100的napi函数ftgmac100_poll()去读取网卡上的数据,并递交给协议栈。

那么,相同irq号的中断可以嵌套吗?高优先级的irq可以抢占低优先级已经ack但未EOI的中断吗?

Arm手册的描述如下:

按arm手册描述,当某个irq中断发生时,GIC distributor将该interrup设置为pending状态,并按优先级将该中断发送到 GIC cpu interface. GIC cpu interface再选最高优先级的Interrupt,然后向cpu发起中断,并将Interrupt设置为active状态。

当cpu正在处理一个interrupt(已经ack, 但为EIO)时,如果来了一个高优先级中断,那么这个GIC cpu interrupt还是可以向cpu发送中断信号,以抢占中断处理。如果是相同优先级的中断,则不能抢占。

从gic_handle_irq()的实现来看,中断处理的上半部(驱动注册的中断处理函数),可以被高优先级中断抢占,当同优先级的中断则不能抢占。

所以:

相同优先级的不同中断,不能抢占正在处理的中断;

高优先级的中断,可以抢占当前正在处理的中断;

当前正在处理的中断再次发生中断,也不能抢占中断,当前中断状态会进入"active and pending"状态。

// update information

在armv7中,gic初始化的时候,将中断号32开始的所有中断的优先级设置为相同的,为0xa0, 中断号0-31预留给CPU使用,

所以,在armv7中,所有外设的中断都是相同优先级,外设中断不会有中断抢占。

在armv7的DTS中,描述interrupt有三个数字,第一个标识interrupt type, 第二个标识interrupt number, 第三个标识flags,如下图。DTS中不存在配置中断优先级操作。

上面说的这些都是在中断发生时,cpu不屏蔽中断的前提下,实际上,在armv7的实现时,在vector_irq中,cpsr.I位并没有清零,保持为1,这表示arm禁了中断,所以,无论怎么样,当irq_handler处理完后,无论是__irq_svc还是__irq_usr,在返回中断前时,spsr的值才会去更新cpsr,也就是enable irq.(svc模式下的内核抢占发生时,会主动设置cpsr的I位,即enable IRQ).

可见,arm 中断整个过程,IRQ都是被cpsr关闭的。直到处理完才enable.(svc内核抢占和softirq处理时会主动打开IRQ)


http://www.mrgr.cn/news/90425.html

相关文章:

  • 前端到AI,LangChain.Js(二)
  • JavaEE架构
  • 学习总结三十
  • 未来替代手机的产品,而非手机的本身
  • 【KOA】01-专栏介绍及学习计划(后续项目实战结合Vue3)
  • Qt:QWidget核心属性
  • 音视频协议
  • C++基础知识学习记录—构造函数
  • PyQt学习记录01——加法计算器
  • vue知识点3
  • MySQL两阶段提交策略
  • Ai无限免费生成高质量ppt教程(deepseek+kimi)
  • (1/100)每日小游戏平台系列
  • SAP-ABAP:ROLLBACK WORK使用详解
  • 19.3 连接数据库
  • Linux网络编程--Udp套接字+实战 (万字详解,超详细!!)
  • SAP-ABAP:在LOOP循环中 ASSIGNING FIELD-SYMBOL的使用代码详解
  • 独家|被高层看重,美团AI“大跃进”
  • html css网页制作成品——HTML+CSS茶百道的茶网页设计(6页)附源码
  • react项目引入tailwindcss不生效解决方案
  • React 高级教程
  • 【CS61A 2024秋】Python入门课,全过程记录P7(Week13 Macros至完结)【完结撒花!】
  • [笔记.AI]Deepseek-R1 各参数版本的蒸馏模型对比
  • Spring Boot 配置 Mybatis 读写分离
  • jenkins备份还原配置文件
  • 基于STM32的智能鱼缸水质净化系统设计