您的位置:首页 > 其它

arm64 异常处理

2016-10-21 18:37 225 查看

<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: rgb(255, 255, 255);">armv8中有四个Exception Level,分别是下面四个:</span>

EL0 : 普通用户应用
EL1 : 操作系统OS层
EL2 : Hypervisor
EL3 : Low-level firmware, including the Secure Monitor



我们主要讨论EL0、EL1,不讨论EL2和EL3,有兴趣的可以研究下ARMv8设置这两个。

二、异常处理分类

Interrupts : 中断包括FIQ和IRQ;

Aborts : Aborts包括  Instruction aborts 和 Data aborts,当访问数据和指令的时候MMU会检测指令或数据是否正确,如果错误MMU会返回一个错误。

Reset : Reset是一个特殊的vector,在最高的Exception level,这个vector使用一个IMPLEMENTATION DEFINED的地址。

Exception generating instructions :我的理解是当你执行一条指令时,如果这条指令属于EL0层时,你去访问EL1层的内容,就会触发这个异常。Supervisor Call ( SVC )在  EL1 、 Hypervisor Call ( HVC )在EL2、Secure monitor Call (
SMC )在EL3,后面我们会简单介绍下ELn的含义。

三、异常处理寄存器

如果发生异常,系统自动将PSTATE的信息保存到Saved Program Status Register(SPSR_ELn)中,注意不存在SR_EL0,因为异常不会执行在EL0.





当发生异常时,SPSR_ELn寄存器被更新,存放PSTATE信息,然后将执行:



四、同步异常和异步异常

同步异常主要包含一下几点:

Aborts from the MMU. For example, permission failures or memory areas marked as Access flag fault.

SP and PC alignment checking.

Unallocated instructions.

Service Calls (SVCs, SMCs and HVCs).

异常向量表



五、分析下arm64中entry.S中的异常处理代码

</pre><pre name="code" class="objc">/*
* Exception vectors.
*/

.align	11
ENTRY(vectors)
ventry	el1_sync_invalid		// Synchronous EL1t
ventry	el1_irq_invalid			// IRQ EL1t
ventry	el1_fiq_invalid			// FIQ EL1t
ventry	el1_error_invalid		// Error EL1t

ventry	el1_sync			// Synchronous EL1h
ventry	el1_irq				// IRQ EL1h
ventry	el1_fiq_invalid			// FIQ EL1h
ventry	el1_error_invalid		// Error EL1h

ventry	el0_sync			// Synchronous 64-bit EL0
ventry	el0_irq				// IRQ 64-bit EL0
ventry	el0_fiq_invalid			// FIQ 64-bit EL0
ventry	el0_error_invalid		// Error 64-bit EL0

#ifdef CONFIG_COMPAT
ventry	el0_sync_compat			// Synchronous 32-bit EL0
ventry	el0_irq_compat			// IRQ 32-bit EL0
ventry	el0_fiq_invalid_compat		// FIQ 32-bit EL0
ventry	el0_error_invalid_compat	// Error 32-bit EL0
#else
ventry	el0_sync_invalid		// Synchronous 32-bit EL0
ventry	el0_irq_invalid			// IRQ 32-bit EL0
ventry	el0_fiq_invalid			// FIQ 32-bit EL0
ventry	el0_error_invalid		// Error 32-bit EL0
#endif
END(vectors)

/*
* Invalid mode handlers
*/
.macro	inv_entry, el, reason, regsize = 64
kernel_entry el, \regsize
mov	x0, sp
mov	x1, #\reason
mrs	x2, esr_el1
b	bad_mode
.endm

el0_sync_invalid:
inv_entry 0, BAD_SYNC
ENDPROC(el0_sync_invalid)

el0_irq_invalid:
inv_entry 0, BAD_IRQ
ENDPROC(el0_irq_invalid)

//inv_entry是一个宏定义,主要工作就是将寄存器压栈后跳到bad_mode函数运
//后面紧跟的1代表异常级是el1,即内核态
//BAD_IRQ定义在前面,值为1,代表发生异常的原因
el0_fiq_invalid:
inv_entry 0, BAD_FIQ
ENDPROC(el0_fiq_invalid)

el0_error_invalid:
inv_entry 0, BAD_ERROR
ENDPROC(el0_error_invalid)

#ifdef CONFIG_COMPAT
el0_fiq_invalid_compat:
inv_entry 0, BAD_FIQ, 32
ENDPROC(el0_fiq_invalid_compat)

el0_error_invalid_compat:
inv_entry 0, BAD_ERROR, 32
ENDPROC(el0_error_invalid_compat)
#endif

el1_sync_invalid:
inv_entry 1, BAD_SYNC
ENDPROC(el1_sync_invalid)

el1_irq_invalid:
inv_entry 1, BAD_IRQ
ENDPROC(el1_irq_invalid)

el1_fiq_invalid:
inv_entry 1, BAD_FIQ
ENDPROC(el1_fiq_invalid)

el1_error_invalid:
inv_entry 1, BAD_ERROR
ENDPROC(el1_error_invalid)

/*
* EL1 mode handlers.
*/
.align	6
el1_sync:
kernel_entry 1
mov	x0, sp
and	x20, x0, #0xffffffffffffc000
ldr	w4, [x20, #TI_CPU_EXCP]
add	w4, w4, #0x1
str	w4, [x20, #TI_CPU_EXCP]
cmp	w4, #0x1
b.ne	el1_sync_nest
str	x0, [x20, #TI_REGS_ON_EXCP]
el1_sync_nest:
cmp	w4, #0x2
b.lt	el1_sync_nest_skip
bl	aee_stop_nested_panic
el1_sync_nest_skip:
mrs	x1, esr_el1			// read the syndrome register
lsr	x24, x1, #ESR_EL1_EC_SHIFT	// exception class
cmp	x24, #ESR_EL1_EC_DABT_EL1	// data abort in EL1
b.eq	el1_da
cmp	x24, #ESR_EL1_EC_SYS64		// configurable trap
b.eq	el1_undef
cmp	x24, #ESR_EL1_EC_SP_ALIGN	// stack alignment exception
b.eq	el1_sp_pc
cmp	x24, #ESR_EL1_EC_PC_ALIGN	// pc alignment exception
b.eq	el1_sp_pc
cmp	x24, #ESR_EL1_EC_UNKNOWN	// unknown exception in EL1
b.eq	el1_undef
cmp	x24, #ESR_EL1_EC_BREAKPT_EL1	// debug exception in EL1
b.ge	el1_dbg
b	el1_inv
el1_da:
/*
* Data abort handling
*/
mrs	x0, far_el1
enable_dbg
// re-enable interrupts if they were enabled in the aborted context
tbnz	x23, #7, 1f			// PSR_I_BIT
enable_irq
1:
mov	x2, sp				// struct pt_regs
bl	do_mem_abort
mov	x5, sp
and	x20, x5, #0xffffffffffffc000
ldr	w4, [x20, #TI_CPU_EXCP]
sub	w4, w4, #0x1
str	w4, [x20, #TI_CPU_EXCP]

// disable interrupts before pulling preserved data off the stack
disable_irq
kernel_exit 1
el1_sp_pc:
/*
* Stack or PC alignment exception handling
*/
mrs	x0, far_el1
enable_dbg
mov	x2, sp
b	do_sp_pc_abort
el1_undef:
/*
* Undefined instruction
*/
enable_dbg
mov	x0, sp
bl	do_undefinstr
kernel_exit 1
el1_dbg:
/*
* Debug exception handling
*/
cmp	x24, #ESR_EL1_EC_BRK64		// if BRK64
cinc	x24, x24, eq			// set bit '0'
tbz	x24, #0, el1_inv		// EL1 only
mrs	x0, far_el1
mov	x2, sp				// struct pt_regs
bl	do_debug_exception
mov	x5, sp
and	x20, x5, #0xffffffffffffc000
ldr	w4, [x20, #TI_CPU_EXCP]
sub	w4, w4, #0x1
str	w4, [x20, #TI_CPU_EXCP]

kernel_exit 1
el1_inv:
// TODO: add support for undefined instructions in kernel mode
enable_dbg
mov	x0, sp
mov	x1, #BAD_SYNC
mrs	x2, esr_el1
b	bad_mode
ENDPROC(el1_sync)

.align	6
el1_irq:
kernel_entry 1
enable_dbg
#ifdef CONFIG_TRACE_IRQFLAGS
bl	trace_hardirqs_off
#endif
#ifdef CONFIG_MTPROF
bl  MT_trace_hardirqs_off
#endif
irq_handler

#ifdef CONFIG_PREEMPT
get_thread_info tsk
ldr	w24, [tsk, #TI_PREEMPT]		// get preempt count
cbnz	w24, 1f				// preempt count != 0
ldr	x0, [tsk, #TI_FLAGS]		// get flags
tbz	x0, #TIF_NEED_RESCHED, 1f	// needs rescheduling?
bl	el1_preempt
1:
#endif
#ifdef CONFIG_MTPROF
bl  MT_trace_hardirqs_on
#endif
#ifdef CONFIG_TRACE_IRQFLAGS
bl	trace_hardirqs_on
#endif
kernel_exit 1
ENDPROC(el1_irq)

#ifdef CONFIG_PREEMPT
el1_preempt:
mov	x24, lr
1:	bl	preempt_schedule_irq		// irq en/disable is done inside
ldr	x0, [tsk, #TI_FLAGS]		// get new tasks TI_FLAGS
tbnz	x0, #TIF_NEED_RESCHED, 1b	// needs rescheduling?
ret	x24
#endif
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  arm64 armv8