赞
踩
当 PE 将异常处理到使用 AArch64 的异常级别时,将强制执行到作为异常的异常向量的地址。 异常向量存在于异常被处理到的异常级别的向量表中。
从向量基地址开始,向量表在内存中占用多个连续的字对齐地址。
每个异常级别都有一个关联的向量基地址寄存器 (VBAR),它定义了该异常级别的表的异常基地址。
对于 AArch64 状态的异常,向量表提供以下信息:
1.异常是否为以下之一:
2.有关异常来自的异常级别的信息,结合有关正在使用的堆栈指针的信息,以及寄存器的状态。
Vector offsets from vector table base address
Exception level的Vector Base Address Register (VBAR)寄存器,该寄存器保存了各个exception level的异常向量表的基地址。该寄存器有三个,分别是VBAR_EL1,VBAR_EL2,VBAR_EL3。
linux初始化的时候会配置每一个PE的vbar_el1设置为linux的中断向量表。
SYM_FUNC_START_LOCAL(__primary_switched)
adr_l x8, vectors // load VBAR_EL1 with virtual
msr vbar_el1, x8 // vector table address
isb
SYM_FUNC_START_LOCAL(__secondary_switched)
adr_l x5, vectors
msr vbar_el1, x5
isb
涉及文件
linux/arch/arm64/kernel/head.S
495 /* 496 * Exception vectors. 497 */ 498 .pushsection ".entry.text", "ax" //表明编译到.entry.text 段 ax的意思是a (可分配)、 w(可写)、r (可读)、x (可执行), 499 500 .align 11 //2K地址对齐 501 SYM_CODE_START(vectors) //中断向量表,主要通过宏kernel_ventry来实现。 502 kernel_ventry 1, sync_invalid // Synchronous EL1t EL1t的中断向量为invalid 503 kernel_ventry 1, irq_invalid // IRQ EL1t 504 kernel_ventry 1, fiq_invalid // FIQ EL1t 505 kernel_ventry 1, error_invalid // Error EL1t 506 507 kernel_ventry 1, sync // Synchronous EL1h EL1h的同步异常 508 kernel_ventry 1, irq // IRQ EL1h EL1h的irq 509 kernel_ventry 1, fiq_invalid // FIQ EL1h EL1h的fiq为invalid 510 kernel_ventry 1, error // Error EL1h EL1h的error 511 512 kernel_ventry 0, sync // Synchronous 64-bit EL0 EL0的同步异常 513 kernel_ventry 0, irq // IRQ 64-bit EL0 EL0的irq 514 kernel_ventry 0, fiq_invalid // FIQ 64-bit EL0 EL0的fiq为invalid 515 kernel_ventry 0, error // Error 64-bit EL0 EL0的error 516 517 #ifdef CONFIG_COMPAT //El0运行在aarch32状态的中断的支持 518 519 kernel_ventry 0, irq_compat, 32 // IRQ 32-bit EL0 520 kernel_ventry 0, fiq_invalid_compat, 32 // FIQ 32-bit EL0 521 kernel_ventry 0, error_compat, 32 // Error 32-bit EL0 522 #else 523 kernel_ventry 0, sync_invalid, 32 // Synchronous 32-bit EL0 524 kernel_ventry 0, irq_invalid, 32 // IRQ 32-bit EL0 525 kernel_ventry 0, fiq_invalid, 32 // FIQ 32-bit EL0 526 kernel_ventry 0, error_invalid, 32 // Error 32-bit EL0 527 #endif 528 SYM_CODE_END(vectors)
关于该向量表的解释参考armv8手册
D1.10.2章节
其中EL1t和ELL1h的差别描述如下:
kernel_ventry是个宏实现如下,主要做了:
.macro kernel_ventry, el, label, regsize = 64 //el代表异常等级。lable中断触发的方式irq fiq error sync还有invalid。 regsize默认是64位。 .align 7 //对齐 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0 //KPTI方案的补丁,这里略过 .if \el == 0 alternative_if ARM64_UNMAP_KERNEL_AT_EL0 .if \regsize == 64 mrs x30, tpidrro_el0 msr tpidrro_el0, xzr .else mov x30, xzr .endif alternative_else_nop_endif .endif #endif sub sp, sp, #S_FRAME_SIZE //sp减去S_FRAME_SIZE用 保存当前pt_regs 用来恢复callstack #ifdef CONFIG_VMAP_STACK //虚拟映射栈,这里略过。 /* * Test whether the SP has overflowed, without corrupting a GPR. * Task and IRQ stacks are aligned so that SP & (1 << THREAD_SHIFT) * should always be zero. */ add sp, sp, x0 // sp' = sp + x0 sub x0, sp, x0 // x0' = sp' - x0 = (sp + x0) - x0 = sp tbnz x0, #THREAD_SHIFT, 0f sub x0, sp, x0 // x0'' = sp' - x0' = (sp + x0) - sp = x0 sub sp, sp, x0 // sp'' = sp' - x0 = (sp + x0) - x0 = sp b el()\el()_\label 0: /* * Either we've just detected an overflow, or we've taken an exception * while on the overflow stack. Either way, we won't return to * userspace, and can clobber EL0 registers to free up GPRs. */ /* Stash the original SP (minus S_FRAME_SIZE) in tpidr_el0. */ msr tpidr_el0, x0 /* Recover the original x0 value and stash it in tpidrro_el0 */ sub x0, sp, x0 msr tpidrro_el0, x0 /* Switch to the overflow stack */ adr_this_cpu sp, overflow_stack + OVERFLOW_STACK_SIZE, x0 /* * Check whether we were already on the overflow stack. This may happen * after panic() re-enables interrupts. */ mrs x0, tpidr_el0 // sp of interrupted context sub x0, sp, x0 // delta with top of overflow stack tst x0, #~(OVERFLOW_STACK_SIZE - 1) // within range? b.ne __bad_stack // no? -> bad stack pointer /* We were already on the overflow stack. Restore sp/x0 and carry on. */ sub sp, sp, x0 mrs x0, tpidrro_el0 #endif b el()\el()_\label //跳转到 eln_lable 例如el1_irq,第一个el()是字符串,\el()是传递的参数,\label也是参数。 .endm
可知,根据kernel的中断向量表根据中断来源的不同,实现了以下异常类型
涉及文件
linux/arch/arm64/kernel/entry.S
参考 armv8手册 :DDI0487D_a_armv8_arm-20181102S
D1.10 Exception entry
D1.10.2 Exception vectors
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。