Blog icon indicating copy to clipboard operation
Blog copied to clipboard

aarch64体系结构与编程7--ARM64的中断处理

Open jason--liu opened this issue 4 years ago • 0 comments

ARM64异常处理之中断处理

  • ARM核心两个和中断相关的 管脚:nIRQ 和 nFIQ
  • 每个CPU核心有一对这样的 中断相关的管脚

image

  • PSTATE状态中有两个比特位和中断相关
    • I:用来屏蔽IRQ中断
    • F:用来屏蔽FIQ中断

ARM64中的GIC控制器

  • ARM提供了标准的GIC控制器,例如树莓派4b上支持GIC-400
  • 树莓派3b上支持 传统的中断方式(legacy interrupt)

image

中断处理过程

image

树莓派4b上的中断控制器

  • 树莓派4b上提供两种中断控制器
    • GIC-400 (默认)
    • 传统的中断控制器(legacy interrupt controller)
  • 树莓派4b支持多种中断源
    • ARM Core N:ARM Core本身的中断源,例如Core里面的generic timer
    • ARMC:可以被VPU和CPU访问的中断源,例如mailbox等
    • ARM_LOCAL:只能被CPU访问的中断源,例如本地timer等

image 这里的IRQ routing可以是legacy,也可以是gic. 下图是legace的方式routing image

legacy routing处理流程

image 中断状态寄存器 路由过程:

  1. 先读SOURCEn中断状态寄存器
  2. SOURCEn寄存器 bit 8 是否置位,若置位,读取PENDING2寄存器
  3. 若PENDING2的bit24置位,则读PENDING0寄存器
  4. 若PENDING2的bit25置位,则读PENDING1寄存器

举例:以ARM Core的generic timer为例

Cortex-A72支持4个ARM Core的generic timer

  • CNT_PS_IRQ:Secure EL1 Physical Timer Event interrupt
  • CNT_PNS_IRQ:Nonsecure EL 1 Physical Timer Event interrupt
  • CNT_HP_IRQ: Hypervisor Physical Timer Event interrupt, EL2
  • CNT_V_IRQ:Virtual Timer Event interrupt EL3

image ARM_LOCAL寄存器中有:

  • 4个IRQ_SOURCE寄存器,每个CPU一个,表示中断源的状态
  • 4个FIQ_SOURCE寄存器,每个CPU一个
  • 4个TIMER_CNTRL寄存器,每个CPU一个,用来enable对应的中断源

以 Nonsecure EL 1 Physical Timer为例,相关初始化的寄存器是在ARM Core中,见armv8.6手册。 CNTP_CTL_EL0, Counter-timer Physical Timer Control register. (第D13.8.16章) image CNTP_TVAL_EL0, Counter-timer Physical Timer TimerValue register(第D13.8.18章) image Timer支持两种触发方式:见第D11.2.4章

  1. 64位的 comparevalue的方式
  2. timervalue的方式,就是初始化一个值,当递减到0的时候,timer中断就触发

EL1的 Nonsecure generic timer的中断处理流程

  1. 初始化timer,设置cntp_ctl_el0寄存器的enable域为1
  2. 给timer的TimeValue一个初值,设置cntp_tval_el0寄存器
  3. 打开树莓派中断控制器中和timer相关的中断,设置TIMER_CNTRL0寄存器中的CNT_PNS_IRQ为1.
  4. 打开PSTATE寄存器中的IRQ中断总开关
  5. Timer中断发生
  6. 跳转到el1_irq汇编函数
  7. 保存中断上下文(使用kernel_entry宏)
  8. 跳转到中断处理函数
  9. 读取ARM_LOCAL中中断状态寄存器IRQ_SOURCE0
  10. 判断是否CNT_PNS_IRQ中断发生,如果是,重新设置TimeValue
  11. 返回到el1_irq汇编函数
  12. 恢复中断上下文
  13. 返回中断现场

### 中断现场(中断上下文) 中断发生瞬间,CPU的状态,包括:

  • PSTATE寄存器
  • PC值
  • SP值
  • X0~x30寄存器

使用一个栈框数据结构来描述需要保存的中断现场(struct pt_regs) image

保存中断现场

中断发生时,中断上下文保存到当前进程的内核栈里,使用栈框保存 image

恢复中断现场

中断返回时,从内核栈恢复中断现场 image

GIC中断控制器介绍

早期的中断控制器

传统的中断控制器,例如树莓派4b上的legacy interrupt controller

  • 中断enable寄存器
  • 中断disable寄存器
  • 中断状态寄存器

传统的使用简单状态寄存器的方式来管理中断,变得越来越难管理

  • 中断源变得原来越多
  • 不同类型的中断,比如多核间的中断,中断优先级,软件定义的中断等

GIC中断控制器发展历史

在Cortex-A时期就开发了GIC中断控制器 GICV1: ✓ 支持8核 ✓ 支持多大1020个中断源 ✓ 8bit优先级 ✓ 支持软件触发中断 ✓ TrustZone支持 IP: GIC-390 应用场景: Cortex-A9 MPCore

GICV2: ✓ 虚拟化支持 ✓ 支持secure software IP: GIC-400 应用场景: Cortex-A7 MPCore 树莓派4b

GICV3: ✓ 支持CPU核心数量大于8 ✓ 支持基于消息的中断 ✓ 支持更多的中断ID IP: GIC-500 GIC-600

GIC支持的中断类型

  • SGI:软件产生的中断(Software Generated Interrupt),软中断即软件产生的中断,用于给其他CPU核心发送中断信号
  • PPI:私有外设中断(Private Peripheral Interrupt),私有的外设中断,该中断是某个指定的CPU独有的
  • SPI:共享外设中断(Shared Peripheral Interrupt),共享的外设中断,所有CPU都可以访问这个中断
  • LPI,本地特殊外设中断(Locality-specific Peripheral Interrupt),GICv3新增的中断类型。基于消息传递的中断类型

GICV2中断控制器中断号分配情况

中断类型 中断号范围
软件触发中断(SGI) 0~15
私有外设中断(PPI) 16~31
共享外设中断(SPI) 32~1019

注意:中断号1020~1023是保留的

中断状态

  • 不活跃状态(inactive):中断处于无效状态
  • 等待状态(pending):中断处于有效状态,但是等待CPU响应该中断
  • 活跃状态(active):CPU已经响应该中断
  • 活跃并等待状态(active and pending):CPU正在响应该中断,但是该中断源又发送中断过来

image

GICV2中断控制器

image

The Distributor registers (GICD_)包含了中断设置和配置 The CPU Interface registers (GICC_)包含CPU相关的特殊设置

image

中断路由

image GICD_ITARGETSRn 寄存器用来配置Distributor可以把中断路由到哪个CPU上。

  • 8bit来表示一个中断源,每个bit代表能路由的CPU
  • 某个bit设置了,说明该中断源可以路由到这个CPU上
  • 前32个中断源的路由配置是 硬件设置好的,RO
  • 第33~1019号中断,可以由软件来配置其路由, RW

image

GIC-400中断信号时序

image

  • T1 The Distributor detects the assertion of Group 0 interrupt M.
  • T2 The Distributor sets interrupt M to pending.
  • T17 The CPU interface asserts nFIQCPU[n].(The assertion of nFIQCPU[n] occurs some CLK cycles after interrupt M becomes pending. In Figure B-1, the latency at the physical interface is tph = 15 clock cycles.)
  • T42 The Distributor detects the assertion of a higher priority Group 0 interrupt, N.
  • T43 The Distributor replaces interrupt M with interrupt N as the highest priority pending interrupt and sets N to pending.
  • T58 tph clock cycles after interrupt N became pending, the CPU interface asserts nFIQCPU[n]. The state of nFIQCPU[n] is unchanged because nFIQCPU[n] was asserted at T17.
    The CPU interface updates the InterruptID field in the GICC_IAR, to contain the ID value for interrupt N.
  • T61 The processor reads the GICC_IAR, acknowledging the highest priority pending interrupt, N. The Distributor sets interrupt N to active and pending
  • T61-T131 The processor services interrupt N.
  • T64 3 clock cycles after interrupt N has been acknowledged, the CPU interface deasserts nFIQCPU[n]
  • T126 The peripheral deasserts interrupt N.
  • T128 The pending state is removed from N.
  • T131 The processor writes to the End of Interrupt Register, GICC_EOIR, with the ID of interrupt N and the Distributor deactivates interrupt N.
  • T146 tph clock cycles after GICC_EOIR was written to for N, the Distributor forwards the new highest priority pending interrupt, M, to the CPU interface, which asserts nFIQCPU[n].
  • T211 The processor reads the GICC_IAR, acknowledging the highest priority pending interrupt, M, and the Distributor sets interrupt M to active and pending.
  • T214 3 clock cycles after interrupt M has been acknowledged, the CPU interface deasserts nFIQCPU[n].

GICv2寄存器

GICv2寄存器分成两组:

  • D:表示Distributor的寄存器
  • C:表示CPU interface的寄存器

有些寄存器是按照 中断号 来描述的,比如使用某几个比特位来描述一个 中断号 的相关属性 同一个寄存器可以n个。 例如GICD_ISENABLERn寄存器,它是用来 使能某个中断号的。“n”表示它有n个这样的寄存器 image Table 4-1 Distributor register map,可以看到这个寄存器从0x100 到 0x17c,这些都是这个寄存器 image 上面寄存器里的每个比特位表示一个中断号的enable 寄存器n的计算 image

树莓派4b上的GIC-400中断号分配情况

image

访问GIC-400寄存器

树莓派4b上的GIC-400的基地址

image

GIC-400上distributor和CPU interface的offset

image

GIC-400初始化流程

1.设置distributor和CPU interface寄存器组的基地址 2.读取GICD_TYPER寄存器,计算当前GIC最大支持多少个中断源。 3.初始化distributor
a. Disable distributor b. 设置SPI中断的路由 c. 设置SPI中断的触发类型,例如level触发 d. Disactive和disable所有的中断源 e. Enable distributor 4.初始化CPU interface a. 设置GIC_CPU_PRIMASK,设置中断优先级mask level b. Enable CPU interface

注册中断

  1. 初始化外设
  2. 查找该外设的中断在GIC-400的中断号,例如PNS timer的中断号为30
  3. 设置GIC_DIST_ENABLE_SET寄存器来 enable这个中断号
  4. 打开设备相关的中断,例如树莓派上的generic timer,需要打开ARM_LOCAL寄存器组中的TIMER_CNTRL0寄存器中相关的enable位
  5. 打开CPU的PSTATE中I位(PSTATE.I)

中断响应

  1. 中断发生
  2. 异常向量表
  3. 跳转到GIC中断函数里,gic_handle_irq()
  4. 读取GICC_IAR寄存器,获取中断号
  5. 根据中断号来进行相应中断处理,例如读取的中断号为30,说明的是PNS的generic timer,然后跳转到generic timer的处理函数里

jason--liu avatar Dec 29 '20 11:12 jason--liu