You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
我们看一下CPU保护中断现场的工作,kernel保护中断现场放在1.4.1 top half来说。CPU发生异常的时候会自动把SP/PC/PSTATE这些数据备份到寄存器里面,但是这里有个问题,如果我们对这个数据不加以备份,当异常嵌套异常的时候,寄存器的值就会被冲走,我们只能恢复一级的异常,因此还要备份异常到相应的栈里面,当多级嵌套的异常从根节点一路路返回的时候,从栈中拿出寄存器的数据进行返回。这个好比QQ幻想里面的飞空艇仙子,龙城->长乐村->桃源村->天都,我们手里的信息只能回溯到上一站,等我们返回桃源村的时候,打开飞空艇仙子的对话框,就不知道去哪里了。因此我们每飞一个地方之后,需要在各个城市的飞空艇仙子的复印一个副本,告诉他我来自哪里,到天都之后我就知道回到桃源村,到桃源村的时候我就知道来自长乐村,最后我就能返回龙城。这就相当于中断现场的保护,在每一次中断过来之后,备份SP/PC/PSTATE到栈空间。
11_ARMv8_异常处理(二)- Legacy 中断处理
异常处理还没有完成,在异常处理(一)里面算是把ARMV8a上面的一些比较基本的异常相关的知识罗列出来了,但是还没有具体的分析。在ARM的世界,中断是异常的一种。这一节的目标是利用Linux内核研究:
ARMv8的中断有两种模式可以配置,一种是传统的中断处理Legacy模式,一种是使用GIC中断管理器模式。我们这次目标是Legacy模式,下一节异常处理(三)会学习GIC中断管理。
1 Overview interrupt
外部设备assert一个中断线,中断控制器会产生一个IRQ使CPU进入到异常处理流程,保存一些PC->ELR(子函数返回地址),保存PSTATE状态信息,还会切入EL1异常等级(栈指针),接着就是CPU和Kernel共同完成的中断向量表,根据中断向量表的地址进入到内核的异常handler,执行内核中断上下文。
1.1 Interrupt controller
1.1.1 RTL design
我并非研究ARM的RTL设计的人员,但是从RTL里面能给我们提供一些本质的信息。我们这里用ZYNQ设计的双核Cortex-A9为例1,看看整个中断控制器如何工作的。
中断控制器的RTL设计如图所示,我在图片上标注了中断控制器的输入输出,输入一共是两个,分别是图中的source 1和source 2,一个是外部的通过外设引脚输入进来的中断源,一个是内部的CPU产生的中断源,通过或的关系合并成FIQ和IRQ两个中断输出,中断的输出被接入到CPU0和CPU1的接口。我们在CPU上能观测到的就是异常的产生。
我们可以在PSTATE寄存器中控制IRQ和FIQ的开关。
1.1.2 Legacy interrupt controller
参考一些做CortexA72的二级产商的技术手册,NXP的imx82和德州仪器TDA4VM3,并没有设计相应的legacy中断,我以树莓派的Cortex A72(x4)为例4,了解一下legacy interrupt怎么设计的,我们在异常处理(三)中研究一下不同厂商如何将GIC集成到自己的ARM处理器上的。
树莓派是这样做的,将中断线分为几类,ARM coreN(arm核心组中断),ARM_LOCAL(只有CPU能访问的中断), ARMC(CPU和GPU共享的中断),videocore(GPU的中断)和ETH_PCIe(网络PCIE中断)。
中断比较多,传统的中断寄存器就是使用串联的方法,待定寄存器三个FIQn/IRQn_PENDING1 + FIQn/IRQn_PENDING0,还有一个PENDING2,串联起来,相当于把ARMC和外设类的中断打包,共用一个位,最后组装成ARM_LOCAL FIQ/IRQ_SOURCEn寄存器。所以我们使用这些寄存器来控制和读取中断状态。
在树莓派的手册里面举了个例子,一个UART4的FIQ中断发送到ARM core3上的处理时序:
这部分应该是中断上半段处理的内容。
1.2 CPU work
中断也是一种异常和异常处理(一)的处理方式一样,摘录于异常处理(一):
当中断发生的时候有两个现场需要保护:
这两个中断现场有个比较明显的分界线,就是是否跳转异常向量表。CPU的中断现场在跳转异常向量表之前,此时还没有进入到EL1,但是备份到EL1;Kernel的保护中断现场上半段,此时已经在CPU的EL1,栈已经切到了EL1的栈空间上面,保护程序逻辑的现场。
我们看一下CPU保护中断现场的工作,kernel保护中断现场放在1.4.1 top half来说。CPU发生异常的时候会自动把SP/PC/PSTATE这些数据备份到寄存器里面,但是这里有个问题,如果我们对这个数据不加以备份,当异常嵌套异常的时候,寄存器的值就会被冲走,我们只能恢复一级的异常,因此还要备份异常到相应的栈里面,当多级嵌套的异常从根节点一路路返回的时候,从栈中拿出寄存器的数据进行返回。这个好比QQ幻想里面的飞空艇仙子,龙城->长乐村->桃源村->天都,我们手里的信息只能回溯到上一站,等我们返回桃源村的时候,打开飞空艇仙子的对话框,就不知道去哪里了。因此我们每飞一个地方之后,需要在各个城市的飞空艇仙子的复印一个副本,告诉他我来自哪里,到天都之后我就知道回到桃源村,到桃源村的时候我就知道来自长乐村,最后我就能返回龙城。这就相当于中断现场的保护,在每一次中断过来之后,备份SP/PC/PSTATE到栈空间。
在entry.S中kernel_entry就是CPU保护中断现场的工作,当然处理保护中断现场,还有很多关于内存的指令,这里面先不做过多的关注。
1.4 kernel:exception handler
这部分我们在Linux Kernel专题里面来讨论,在ARM64处理器这块就暂时不讨论了。
2 Example
对于Legacy中断模式,我们启动系统的定时器,在Cortex-A72处理器的树莓派4b上面实现一个定时器,需要自己完成寄存器的配置,异常向量表的跳转,寄存器的备份工作。
2.1 Timer Pre-knowledge
2.1.2 regs
Cortex-A72一共是有4个定时器5:
相关寄存器也在这里6:
4个通用定时器总中断设置是在ARM_LOCAL的中断组的寄存器中配置。到此,其实我读到这里就有个疑问了,根据手册,CPU的4个通用定时器是在ARM_Core的中断组的,ARM_LOCAL里面只有一个local timer并不是这4个ARM的通用定时器,为什么要在ARM_LOCAL中断组寄存器里面配置。后面看了legacy中断的路由信息可以注意到:
虽然几个定时器被分配到了ARMCore组,但是实际上是在ARM_LOCAL里面的寄存器处理的,这个设计真的是有点令人很迷惑。
2.1.2 config
定时器需要配置,根据常识都需要:
ARM: CNTP_CTRL_EL0
我们选定的是CNT定时器,也就是EL1里面的PS定时器。在手册里面,CNTP_CTL_EL0来配置,这里还有个奇怪的事情,就是PS定时器是EL1里面的,但是配置寄存器是在CNTP_CTL_EL0内配置的(我搜了一下手册,是没有CNTP_CTL_EL1的,可能配置都是EL0寄存器里面完成的)
CNTP_CTL_EL0, counter_timer physical timer control register.
ARM: CNTP_TVAL_EL0
Timervalue的初始值,这个值会递减到0的时候会触发中断,还需要在handler里面重新赋值。
CortexA72: TIMER_CNTRLx
树莓派一共三个这样的寄存器,这个寄存器用于软件决定从ARM core接收一个FIQ的中断请求。我们关注的应该是BIT0,是cortex-A72处理器内核的PS定时器。
ARM: PSTATE
配置PSTATE上面的DAIF使能总的中断开关。
2.1.3 process
3 Reference
Footnotes
FPGA Technical Tutorials - Zynq System-on-Chip Design Overview Interrupts ↩
i.MX 8QuadMax Applications Processor Reference Manual - 3.1.2 Interrupt Interface ↩
DRA829/TDA4VM Technical Reference Manual (Rev. C) - 9.1 Interrupt Architecture ↩
BCM2711 ARM Peripherals ↩
ARM Cortex-A72 MPCore Processor Technical Reference Manual r0p3 - Generic Timer functional description ↩
ARM Cortex-A72 MPCore Processor Technical Reference Manual r0p3 - AArch64 Generic Timer register summary ↩
The text was updated successfully, but these errors were encountered: