armv8/armv9中断系列详解-中断示例展示

描述

 

一、中断示例展示(不含虚拟化部分)

 

环境配置:在linux/optee双系统环境下, linux系统的SCR.IRQ=0、SCR.FIQ=1, optee系统的SCR.IRQ=0、SCR.FIQ=0

说明:group1是非安全中断、secure group1是安全中断

1、当cpu处于REE,来了一个非安全中断

当cpu处于normal侧时,来了一个非安全中断,根据SCR.NS=1/中断在group1组,cpu interface将会给cpu一个IRQ,(由于SCR.IRQ=0,IRQ将被routing到EL1),cpu跳转至linux的irq中断异常向量表, 处理完毕后再返回到normal(linux)侧.

2、当cpu处于TEE,来了一个安全中断

当cpu处于secure侧时,来了一个安全中断,根据SCR.NS=0/中断在secure group1组,cpu interface将会给cpu一个IRQ,(由于SCR.IRQ=0,IRQ将被routing到EL1),cpu跳转至optee的irq中断异常向量表, 处理完毕后再返回到secure(optee)侧.

Linux

3、当cpu处于TEE,来了一个非安全中断

当cpu处于secure侧时,来了一个非安全中断,根据SCR.NS=0/中断在group1组,cpu interface将会给cpu一个FIQ,(由于SCR.FIQ=0,FIQ将被routing到EL1),跳转至optee的fiq中断异常向量表,再optee的fiq处理函数中,直接调用了smc跳转到ATF, ATF再切换至normal EL1(linux), 此时SCR.NS的状态发生变化,根据SCR.NS=1/中断在group1组,cpu interface会再给cpu发送一个IRQ异常,cpu跳转至linux的irq中断异常向量表,处理完毕后,再依次返回到ATF---返回到optee

Linux

4、当cpu处于REE,来了一个安全中断

当cpu处于normal侧时,来了一个安全中断,根据SCR.NS=0/中断在group1组,cpu interface将会给cpu一个FIQ,(由于SCR.FIQ=1,FIQ将被routing到EL3),在EL3(ATF)中,判断该中断是需要optee来处理的,会切换到optee。此时SCR.NS的状态发生变化,根据SCR.NS=0/中断在secure group1组,cpu interface会再给cpu发送一个IRQ异常,cpu跳转至optee的irq中断异常向量表, 处理完毕后再依次返回到ATF---返回到linux

Linux

5、当cpu处于ATF时,来了一个安全中断或非安全中断(G1NS、G1S)

当cpu处于EL3时,来得任何target到EL3的中断,都将被标记位FIQ

Linux

当cpu处于EL3时,配置SCR.XXX(XXX=EA或IRQ或FIQ)为0的中断不会被taken,配置SCR.XXX为1的中断将会直接target到EL3。

Linux

所以在 linux系统的SCR.IRQ=0、SCR.FIQ=1, optee系统的SCR.IRQ=0、SCR.FIQ=0的场景下,总结如下,当cpu运行在EL3时:

  • SCR_EL3为optee的cpu context时,来了一个G1S,中断将不会被taken

  • SCR_EL3为optee的cpu context时,来了一个G1NS,中断将不会被taken

  • SCR_EL3为linux的cpu context时,来了一个G1S,中断将会直接target到EL3

  • SCR_EL3为linux的cpu context时,来了一个G1NS,中断将不会被taken

6、当cpu处于EL3/EL2/EL1/EL0时,来了一个ATF(group0)中断(G0)

当cpu处于EL3/EL2/EL1/EL0时,来了一个G0中断,中断将被标记位FIQ

Linux

在 linux系统的SCR.IRQ=0、SCR.FIQ=1, optee系统的SCR.IRQ=0、SCR.FIQ=0的场景下,总结如下:

  • 当cpu正在Non-secure EL0/1/2运行时,来了G0中断,中断被标记为FIQ,直接target到EL3

  • 当cpu正在secure EL0/1/2运行时,来了G0中断,中断被标记为FIQ,中断target到了EL0/1/2,在该程序的fiq_offset会调用smc将cpu切回到EL3,到了EL3之后,中断不会被taken, 会继续返回到Non-secure EL0/1/2,然后cpu interface重新给core发送FIQ,接着又是直接target到EL3,EL3处理该中断。

  • 当cpu正在EL3时,来了一个G0中断,中断会被标记为FIQ,中断target到EL3。

7、思考-中断流程举例:在TEE侧时产生了FIQ,回到REE后为啥又产生了IRQ

在深入研读GICV3文档后,终于找到了答案。

首先我们了解下中断优先级,在CPU interfaces (ICC*ELn)寄存器的描述中:

• Provide general control and configuration to enable interrupt handling• Acknowledge an interrupt• Perform a priority drop and deactivation of interruptsSet an interrupt priority mask for the PE• Define the preemption policy for the PE• Determine the highest priority pending interrupt for the PE

也就是cpu interface掌管着中断优先级和将IRQ/FIQ发送给ARM Core.

我们以Level sensitive interrupts的中断为例,先不考虑active and pending的情况:CPU interface发送给Core后,中断状态变为pending,当Core acknowledge中断后(PE跳转到中断向量表), 中断状态变为active,当中断退出后,Cpu interface会再次将优先级最高的中断发送给Core,Core处理下一个中断。

Linux

我们再看下中断的退出流程( End of interrupt), 中断的退出有两种方式:• Priority drop 将中断优先级降到中断产生之前的值• Deactivation 将中断从active变成inactive -- ( 多数情况下,使用这个场景)

重点来了,在中断退出的时候,软件中一般会有Priority drop和Deactivation,既要么将中断优先级降低,要么将中断变为inactive,那么中断退出之后,cpu interface感知到的优先级最高的中断,就可能不会是此中断了,一切运行正常,符合业务.....

那么我们再看下上述的中断流程举例,在TEE中,cpu interface发了一个FIQ给Core,跳转到optee的FIQ向量表,在FIQ的处理流程中,软件几乎什么都没干,没有Priority drop和Deactivation, 那么当SMC切换到了EL3之后,又退回REE后,Cpu interface感知到上一个中断处理完成,会再次发送下一个优先级最高的中断,由于之前的中断号的优先级没变,此时基本上依然是最高的优先级。此时CPU interface会再次发送该中断给Core,由于SCR.NS发生了变化,此时Cpu interface发送给Core的就变成了IRQ...

8、思考-G1NS G1S G0都有可能产生target到EL3的FIQ,如何区分?

其实在我们的linux系统的SCR.IRQ=0、SCR.FIQ=1, optee系统的SCR.IRQ=0、SCR.FIQ=0的场景下,不考虑aarch32的情况,有两种情况会产生target到EL3的FIQ:

  • (1)cpu在EL0/1/2运行时,来了一个G0中断,最终CPU将会进入到EL3的向量表中的第三组向量表。

     

Linux

 

  • (2)ccpu在EL3运行时,来了一个G0中断,最终CPU将会进入到EL3的向量表中的第二组向量表 不过很遗憾,ATF中的向量表中未实现第二组向量表。那么为什么不需要实现呢?在ATF/docs/firmware-design.md中找到了答案, 原来是在进入ATF之前,disable了所有的exception,ATF又没有修改PSTATE.DAIF,所有在ATF Runtime时 irq/fiq/serror/svnc都是disabled。所以异常向量表的第二行,也就用不着了。

     

Required CPU state when calling bl31_entrypoint() during cold boot
This function must only be called by the primary CPU.
On entry to this function the calling primary CPU must be executing in AArch64EL3, little-endian data access, and all interrupt sources masked:

  • PSTATE.EL = 3

  • PSTATE.RW = 1

  • PSTATE.DAIF = 0xf

  • SCTLR_EL3.EE = 0

 

  • (3)cpu在normal EL0/1/2/3运行时(Linux侧的SCR_EL3.FIQ=1的情况下),来了一个G1S中断,CPU将会target到EL3的向量表中的第三组向量表。

那么在ATF中第三组向量表中的fiqoffset中,是如何区分上述(1)(3)中的场景呢,即如何区分该中断是给EL3 handler处理的,还是给optee的handler处理的?此时1020-1023号中断发生了作用。

Linux

我们应该会用到1020,那么用在哪里的呢?请看上述汇编代码bl platicgetpendinginterrupttype的具体实现:


	
  1. uint32_t plat_ic_get_pending_interrupt_type(void)

  2. {

  3. unsignedint irqnr;

  4.  

  5. assert(IS_IN_EL3());

  6. irqnr = gicv3_get_pending_interrupt_type();

  7.  

  8. switch(irqnr) {

  9. case PENDING_G1S_INTID:

  10. return INTR_TYPE_S_EL1;

  11. case PENDING_G1NS_INTID:

  12. return INTR_TYPE_NS;

  13. case GIC_SPURIOUS_INTERRUPT:

  14. return INTR_TYPE_INVAL;

  15. default:

  16. return INTR_TYPE_EL3;

  17. }

  18. }

其实就是在读取pending的中断号,看看有没有1020或1021,从而获得此次的中断是从secure或non-secure过来的,还是在EL3产生的。然后走相应的逻辑。

二、中断示例展示(虚拟化部分)

影响中断routing的相关控制位主要是 HCR_EL2.IMO/FMO/AMO(本文只探讨irq/virq,所以我们只看 IMO比特位),除此之外还有 HCR_EL2.TGE比特位影响Application是做为Host还是Guest.

以下是这些比特位的路由规则的总结:

Linux

我们学习了其原理之后,我们再看4个示例:(1)、HCREL2.IMO=1 , HCREL2.TGE=1 --routing到EL2,Application做为Guest

Linux

(2)、HCREL2.IMO=1 , HCREL2.TGE=0 --routing到EL2,Application做为Host

Linux

(3)、HCREL2.IMO=0 , HCREL2.TGE=1 --routing到EL1,Application做为Guest

Linux

(4)、HCREL2.IMO=0 , HCREL2.TGE=0 --routing到EL1,Application做为host

Linux

审核编辑 :李倩


打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分