1 Exception vectors
1.1 Vector table offsets from vector table base address
1.2 linux Exception vectors
.pushsection ".entry.text", "ax"
.align 11
ENTRY(vectors)
kernel_ventry 1, sync_invalid
kernel_ventry 1, irq_invalid
kernel_ventry 1, fiq_invalid
kernel_ventry 1, error_invalid
kernel_ventry 1, sync
kernel_ventry 1, irq
kernel_ventry 1, fiq_invalid
kernel_ventry 1, error
kernel_ventry 0, sync
kernel_ventry 0, irq
kernel_ventry 0, fiq_invalid
kernel_ventry 0, error
#ifdef CONFIG_COMPAT
kernel_ventry 0, sync_compat, 32
kernel_ventry 0, irq_compat, 32
kernel_ventry 0, fiq_invalid_compat, 32
kernel_ventry 0, error_compat, 32
#else
kernel_ventry 0, sync_invalid, 32
kernel_ventry 0, irq_invalid, 32
kernel_ventry 0, fiq_invalid, 32
kernel_ventry 0, error_invalid, 32
#endif
END(vectors)
1.2.1 当前异常等级使用SP_EL0
kernel_ventry 1, sync_invalid
kernel_ventry 1, irq_invalid
kernel_ventry 1, fiq_invalid
kernel_ventry 1, error_invalid
1.2.2 当前异常等级使用SP_ELx
kernel_ventry 1, sync
kernel_ventry 1, irq
kernel_ventry 1, fiq_invalid
kernel_ventry 1, error
1.2.3 在Aarch64的低等级发生异常
kernel_ventry 0, sync
kernel_ventry 0, irq
kernel_ventry 0, fiq_invalid
kernel_ventry 0, error
1.2.4 在Aarch32的低等级发生异常
#ifdef CONFIG_COMPAT
kernel_ventry 0, sync_compat, 32
kernel_ventry 0, irq_compat, 32
kernel_ventry 0, fiq_invalid_compat, 32
kernel_ventry 0, error_compat, 32
#else
kernel_ventry 0, sync_invalid, 32
kernel_ventry 0, irq_invalid, 32
kernel_ventry 0, fiq_invalid, 32
kernel_ventry 0, error_invalid, 32
#endif
1.3 kernel_ventry
.macro kernel_ventry, el, label, regsize = 64
.align 7
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
alternative_if ARM64_UNMAP_KERNEL_AT_EL0
.if \el == 0
.if \regsize == 64
mrs x30, tpidrro_el0
msr tpidrro_el0, xzr
.else
mov x30, xzr
.endif
.endif
alternative_else_nop_endif
#endif
sub sp, sp, #S_FRAME_SIZE
#ifdef CONFIG_VMAP_STACK
add sp, sp, x0
sub x0, sp, x0
tbnz x0, #THREAD_SHIFT, 0f
sub x0, sp, x0
sub sp, sp, x0
b el\()\el\()_\label
0:
msr tpidr_el0, x0
sub x0, sp, x0
msr tpidrro_el0, x0
adr_this_cpu sp, overflow_stack + OVERFLOW_STACK_SIZE, x0
mrs x0, tpidr_el0
sub x0, sp, x0
tst x0, #~(OVERFLOW_STACK_SIZE - 1)
b.ne __bad_stack
sub sp, sp, x0
mrs x0, tpidrro_el0
#endif
b el\()\el\()_\label
.endm
1.3.1 预留struct pt_regs大小的栈框
sub sp, sp, #S_FRAME_SIZE
1.3.2 跳转到特定的异常处理接口
b el\()\el\()_\label
1.4 el1_irq
.align 6
el1_irq:
kernel_entry 1
enable_da_f
#ifdef CONFIG_TRACE_IRQFLAGS
bl trace_hardirqs_off
#endif
irq_handler
#ifdef CONFIG_PREEMPT
ldr x24, [tsk, #TSK_TI_PREEMPT]
cbnz x24, 1f
bl el1_preempt
1:
#endif
#ifdef CONFIG_TRACE_IRQFLAGS
bl trace_hardirqs_on
#endif
kernel_exit 1
ENDPROC(el1_irq)
1.5 struct pt_regs
kernel_entry 和kernel_exit 这两个函数均是对pt_regs结构体的处理,通过对pt_regs的处理来切换上下文。
struct pt_regs {
union {
struct user_pt_regs user_regs;
struct {
u64 regs[31];
u64 sp;
u64 pc;
u64 pstate;
};
};
u64 orig_x0;
#ifdef __AARCH64EB__
u32 unused2;
s32 syscallno;
#else
s32 syscallno;
u32 unused2;
#endif
u64 orig_addr_limit;
u64 unused;
u64 stackframe[2];
};
和pt_regs对应的宏定义是编译之后生成的include/generated/asm-offsets.h 文件所定义的下面的宏,
1.6 kernel_entry
kernel_entry 的处理和linux内核所定义的struct pt_regs 所对应
.macro kernel_entry, el, regsize = 64
.if \regsize == 32
mov w0, w0
.endif
stp x0, x1, [sp, #16 * 0]
stp x2, x3, [sp, #16 * 1]
stp x4, x5, [sp, #16 * 2]
stp x6, x7, [sp, #16 * 3]
stp x8, x9, [sp, #16 * 4]
stp x10, x11, [sp, #16 * 5]
stp x12, x13, [sp, #16 * 6]
stp x14, x15, [sp, #16 * 7]
stp x16, x17, [sp, #16 * 8]
stp x18, x19, [sp, #16 * 9]
stp x20, x21, [sp, #16 * 10]
stp x22, x23, [sp, #16 * 11]
stp x24, x25, [sp, #16 * 12]
stp x26, x27, [sp, #16 * 13]
stp x28, x29, [sp, #16 * 14]
.if \el == 0
clear_gp_regs
mrs x21, sp_el0
ldr_this_cpu tsk, __entry_task, x20
ldr x19, [tsk, #TSK_TI_FLAGS]
disable_step_tsk x19, x20
apply_ssbd 1, x22, x23
.else
add x21, sp, #S_FRAME_SIZE
get_thread_info tsk
ldr x20, [tsk, #TSK_TI_ADDR_LIMIT]
str x20, [sp, #S_ORIG_ADDR_LIMIT]
mov x20, #USER_DS
str x20, [tsk, #TSK_TI_ADDR_LIMIT]
.endif
mrs x22, elr_el1
mrs x23, spsr_el1
stp lr, x21, [sp, #S_LR]
.if \el == 0
stp xzr, xzr, [sp, #S_STACKFRAME]
.else
stp x29, x22, [sp, #S_STACKFRAME]
.endif
add x29, sp, #S_STACKFRAME
#ifdef CONFIG_ARM64_SW_TTBR0_PAN
alternative_if ARM64_HAS_PAN
b 1f
alternative_else_nop_endif
.if \el != 0
mrs x21, ttbr0_el1
tst x21, #TTBR_ASID_MASK
orr x23, x23, #PSR_PAN_BIT
b.eq 1f
and x23, x23, #~PSR_PAN_BIT
.endif
__uaccess_ttbr0_disable x21
1:
#endif
stp x22, x23, [sp, #S_PC]
.if \el == 0
mov w21, #NO_SYSCALL
str w21, [sp, #S_SYSCALLNO]
.endif
.if \el == 0
msr sp_el0, tsk
.endif
.endm
1.6.1 struct user_pt_regs user_regs对应的汇编代码
union {
struct user_pt_regs user_regs;
struct {
u64 regs[31];
u64 sp;
u64 pc;
u64 pstate;
};
};
stp x0, x1, [sp, #16 * 0]
stp x2, x3, [sp, #16 * 1]
stp x4, x5, [sp, #16 * 2]
stp x6, x7, [sp, #16 * 3]
stp x8, x9, [sp, #16 * 4]
stp x10, x11, [sp, #16 * 5]
stp x12, x13, [sp, #16 * 6]
stp x14, x15, [sp, #16 * 7]
stp x16, x17, [sp, #16 * 8]
stp x18, x19, [sp, #16 * 9]
stp x20, x21, [sp, #16 * 10]
stp x22, x23, [sp, #16 * 11]
stp x24, x25, [sp, #16 * 12]
stp x26, x27, [sp, #16 * 13]
stp x28, x29, [sp, #16 * 14]
.if \el == 0
clear_gp_regs
mrs x21, sp_el0
ldr_this_cpu tsk, __entry_task, x20
ldr x19, [tsk, #TSK_TI_FLAGS]
disable_step_tsk x19, x20
apply_ssbd 1, x22, x23
.else
add x21, sp, #S_FRAME_SIZE
get_thread_info tsk
ldr x20, [tsk, #TSK_TI_ADDR_LIMIT]
str x20, [sp, #S_ORIG_ADDR_LIMIT]
mov x20, #USER_DS
str x20, [tsk, #TSK_TI_ADDR_LIMIT]
.endif
mrs x22, elr_el1
mrs x23, spsr_el1
stp lr, x21, [sp, #S_LR]
.if \el == 0
stp xzr, xzr, [sp, #S_STACKFRAME]
.else
stp x29, x22, [sp, #S_STACKFRAME]
1.7 kernel_exit
.macro kernel_exit, el
.if \el != 0
disable_daif
ldr x20, [sp, #S_ORIG_ADDR_LIMIT]
str x20, [tsk, #TSK_TI_ADDR_LIMIT]
.endif
ldp x21, x22, [sp, #S_PC]
.if \el == 0
ct_user_enter
.endif
#ifdef CONFIG_ARM64_SW_TTBR0_PAN
alternative_if ARM64_HAS_PAN
b 2f
alternative_else_nop_endif
.if \el != 0
tbnz x22, #22, 1f
.endif
__uaccess_ttbr0_enable x0, x1
.if \el == 0
bl post_ttbr_update_workaround
.endif
1:
.if \el != 0
and x22, x22, #~PSR_PAN_BIT
.endif
2:
#endif
.if \el == 0
ldr x23, [sp, #S_SP]
msr sp_el0, x23
tst x22, #PSR_MODE32_BIT
b.eq 3f
#ifdef CONFIG_ARM64_ERRATUM_845719
alternative_if ARM64_WORKAROUND_845719
#ifdef CONFIG_PID_IN_CONTEXTIDR
mrs x29, contextidr_el1
msr contextidr_el1, x29
#else
msr contextidr_el1, xzr
#endif
alternative_else_nop_endif
#endif
3:
apply_ssbd 0, x0, x1
.endif
msr elr_el1, x21
msr spsr_el1, x22
ldp x0, x1, [sp, #16 * 0]
ldp x2, x3, [sp, #16 * 1]
ldp x4, x5, [sp, #16 * 2]
ldp x6, x7, [sp, #16 * 3]
ldp x8, x9, [sp, #16 * 4]
ldp x10, x11, [sp, #16 * 5]
ldp x12, x13, [sp, #16 * 6]
ldp x14, x15, [sp, #16 * 7]
ldp x16, x17, [sp, #16 * 8]
ldp x18, x19, [sp, #16 * 9]
ldp x20, x21, [sp, #16 * 10]
ldp x22, x23, [sp, #16 * 11]
ldp x24, x25, [sp, #16 * 12]
ldp x26, x27, [sp, #16 * 13]
ldp x28, x29, [sp, #16 * 14]
ldr lr, [sp, #S_LR]
add sp, sp, #S_FRAME_SIZE
.if \el == 0
alternative_insn eret, nop, ARM64_UNMAP_KERNEL_AT_EL0
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
bne 4f
msr far_el1, x30
tramp_alias x30, tramp_exit_native
br x30
4:
tramp_alias x30, tramp_exit_compat
br x30
#endif
.else
eret
.endif
sb
.endm
|