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" 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博客
原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!