从arm手册可以看出,异常向量表在EL1~EL3都有,本文只涉及Linux kernel中的实现,即只涉及EL1和EL0。
参考Wiki:
optee中的异常向量表解读–中断处理解读
参考Wiki:
armv8/armv9中断系列详解-学这篇就够了
kernel版本:v6.9-rc6
(arch/arm64/kernel/head.S)
SYM_FUNC_START_LOCAL(__secondary_switched)
...
/* 向量表起始地址放到EL1向量表基址寄存器中 */
adr_l x5, vectors
msr vbar_el1, x5
isb
...
SYM_FUNC_END(__secondary_switched)
向量表入口:
(arch/arm64/kernel/entry.S)
/*
* Exception vectors.
*/
.pushsection ".entry.text", "ax"
.align 11
SYM_CODE_START(vectors)
kernel_ventry 1, t, 64, sync // Synchronous EL1t
kernel_ventry 1, t, 64, irq // IRQ EL1t
kernel_ventry 1, t, 64, fiq // FIQ EL1t
kernel_ventry 1, t, 64, error // Error EL1t
kernel_ventry 1, h, 64, sync // Synchronous EL1h
kernel_ventry 1, h, 64, irq // IRQ EL1h
kernel_ventry 1, h, 64, fiq // FIQ EL1h
kernel_ventry 1, h, 64, error // Error EL1h
kernel_ventry 0, t, 64, sync // Synchronous 64-bit EL0
kernel_ventry 0, t, 64, irq // IRQ 64-bit EL0
kernel_ventry 0, t, 64, fiq // FIQ 64-bit EL0
kernel_ventry 0, t, 64, error // Error 64-bit EL0
kernel_ventry 0, t, 32, sync // Synchronous 32-bit EL0
kernel_ventry 0, t, 32, irq // IRQ 32-bit EL0
kernel_ventry 0, t, 32, fiq // FIQ 32-bit EL0
kernel_ventry 0, t, 32, error // Error 32-bit EL0
SYM_CODE_END(vectors)
遗留问题:向量表中的t/h代表啥意思呢?
查找资料,有如下解释:
处理器模式为t(指Task模式,即用户态模式)
处理器模式为h(指Handler模式,即内核态模式)
扩展:
向量表在kernel镜像中的链接位置
(include/asm-generic/vmlinux.lds.h)
#define ENTRY_TEXT \
ALIGN_FUNCTION(); \
__entry_text_start = .; \
*(.entry.text) \
__entry_text_end = .;
(arch/arm64/kernel/vmlinux.lds.S)
SECTIONS
{
...
.text : ALIGN(SEGMENT_ALIGN) { /* Real text segment */
_stext = .; /* Text and read-only data */
IRQENTRY_TEXT
SOFTIRQENTRY_TEXT
ENTRY_TEXT
TEXT_TEXT
SCHED_TEXT
LOCK_TEXT
KPROBES_TEXT
HYPERVISOR_TEXT
*(.gnu.warning)
}
. = ALIGN(SEGMENT_ALIGN);
_etext = .;
...
}
向量表分析
(arch/arm64/kernel/entry.S)
.macro kernel_ventry, el:req, ht:req, regsize:req, label:req
.align 7
...
b el\el\ht\()_\regsize\()_\label
...
.endm
(arch/arm64/kernel/entry.S)
.macro entry_handler el:req, ht:req, regsize:req, label:req
SYM_CODE_START_LOCAL(el\el\ht\()_\regsize\()_\label)
kernel_entry \el, \regsize
mov x0, sp
bl el\el\ht\()_\regsize\()_\label\()_handler
.if \el == 0
b ret_to_user
.else
b ret_to_kernel
.endif
SYM_CODE_END(el\el\ht\()_\regsize\()_\label)
.endm
上述汇编代码片段中,汇编宏 kernel_ventry的参数结合el\el\ht()\regsize()\label()_handler函数对应如下不同异常的入口:
(arch/arm64/include/asm/exception.h)
asmlinkage void el1t_64_sync_handler(struct pt_regs *regs);
asmlinkage void el1t_64_irq_handler(struct pt_regs *regs);
asmlinkage void el1t_64_fiq_handler(struct pt_regs *regs);
asmlinkage void el1t_64_error_handler(struct pt_regs *regs);
asmlinkage void el1h_64_sync_handler(struct pt_regs *regs);
asmlinkage void el1h_64_irq_handler(struct pt_regs *regs);
asmlinkage void el1h_64_fiq_handler(struct pt_regs *regs);
asmlinkage void el1h_64_error_handler(struct pt_regs *regs);
asmlinkage void el0t_64_sync_handler(struct pt_regs *regs