2.2 ARM64异常处理

Interrupt Pipeline系列文章大纲-CSDN博客

1 异常级别转换

        异常发生时,如何处理呢?

        异常级别分为4级,其中EL0不处理异常。当EL0发生异常时,会进入更高的异常级别进行处理。

        ARM64包含4个异常级别:

  • EL0:非特权模式,常用来跑应用程序;
  • EL1:特权模式,常用来跑内核;
  • EL2:虚拟化监控程序,例如hypervisor;
  • EL3:安全模式,例如secure monitor;

        同步异常一般在当前或更高的异常级别中进行处理。异步异常(如果需要)可以路由到更高级别的异常级别处理。SCR_EL3寄存器指明了什么异常应该路由到EL3,同理,HCR_EL2寄存器指明了什么异常路由到EL2。这两个寄存器都有特定的bit去控制IRQ,FIQ和SError。异常级别EL0不处理任何异常,必须在更高的异常级别中处理。

2 异常向量表

        Linux的运行只涉及EL0和EL1,即Linux内核运行在异常级别EL1,应用程序运行在异常级别EL0. 在EL0或EL1中发生的异常,都会跳转到EL1的异常向量表,根据异常的类别,找到对应的表项。

        VBAR是异常向量表的基地址寄存器。异常向量表存放的基地址可以通过VBAR (Vector Base Address Register)来设置。不同的异常级别有各自独立的VBAR,例如VBAR_EL1,VBAR_EL2,VBAR_EL3等。Linux内核启动时,在head.S中会设置VBAR_EL1指向在

        arch/arm64/kernel/head.S: __primary_switched

       adr_l    x8, vectors                   // load VBAR_EL1 with virtual

       msr     vbar_el1, x8                 // vector table address

        这里提一下,I-pipe没有对head.S做修改。

        如果当前处于EL0且发生了异常,异常级别会从EL0变为EL1,此时EL1只能使用SP_EL1。

        如果当前处于EL1且发生了异常,异常级别会停留在EL1。EL1选择使用SP_EL0,那么对应的异常向量表中的表项为EL1t;EL1选择使用SP_EL1,那么对应的异常向量表中的表项为EL1h。

        Linux在EL1中选择使用自己专属的寄存器SP_EL1,所以只需关注EL1h即可。另外,Linux内核并不使用FIQ,只使用IRQ。

        ARM64的异常向量表一共占用2048个字节,每个表项占128字节,可容纳32条指令。在Linux中实现的异常向量表,精简之后如下。其中.align       11代表与2^11(2028)对齐。

/*

 * Exception vectors.

 */

       .pushsection ".entry.text", "ax"

       .align      11

ENTRY(vectors)

       ……

       kernel_ventry 1, sync           // Sync EL1h:EL1下触发了同步异常,且使用SP_EL1

       kernel_ventry 1, irq              // IRQ EL1h:EL1下触发了IRQ,且使用SP_EL1

       kernel_ventry 1, fiq_invalid   // FIQ EL1h

       kernel_ventry 1, error          // Error EL1h

       kernel_ventry 0, sync           // Sync 64-bit EL0:EL0下触发了同步异常

       kernel_ventry 0, irq              // IRQ 64-bit EL0:EL0下触发了IRQ

       kernel_ventry 0, fiq_invalid   // FIQ 64-bit EL0

       kernel_ventry 0, error          // Error 64-bit EL0

       ……

END(vectors)

        其中,kernel_ventry中最主要的部分摘出来:

.macro kernel_ventry, el, label, regsize = 64

       .align 7                                             (1)

       sub  sp, sp, #S_FRAME_SIZE        (2)

       b     el\()\el\()_\label                         (3)

.endm

(1).align 7表示与2^7即128字节对齐

(2)把sp指针减掉S_FRAME_SIZE大小,用于保存进程用户空间现场。此时使用的sp指针为EL1_SP,此处表示压栈。S_FRAME_SIZE定义在arch/arm64/kernel/asm-offsets.c:

DEFINE(S_FRAME_SIZE,       sizeof(struct pt_regs));

(3)b     el\()\el\()_\label,其中\()代表结束符,\el代表引用入参el,\label代表引用入参label。以kernel_ventry 0,irq为例,展开为el0_irq,定义在entry.S中。

        根据上面的分析,需要关注的异常向量表表项如下。

异常向量表表项

最终跳转到

1

kernel_ventry 0,sync

el0_sync

2

kernel_ventry 0,irq

el0_irq

4

kernel_ventry 1,sync

el1_sync

5

kernel_ventry 1,irq

el1_irq

        接下来对上述表项进行深入分析。

点击查看系列文章 =》 Interrupt Pipeline系列文章大纲-CSDN博客

原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!

  • 18
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值