arch: arc: use top of isr stack as exception stack and bug fixes

* re-use top of isr stack as exception stack
* bug fixes in irq offload's implementation
* improve kernel oops implementation

Signed-off-by: Wayne Ren <wei.ren@synopsys.com>
This commit is contained in:
Wayne Ren 2018-06-09 22:08:04 +08:00 committed by Maureen Helm
commit 97d0436486
3 changed files with 117 additions and 53 deletions

View file

@ -81,11 +81,6 @@ void _NanoFatalErrorHandler(unsigned int reason, const NANO_ESF *pEsf)
_SysFatalErrorHandler(reason, pEsf); _SysFatalErrorHandler(reason, pEsf);
} }
void _do_kernel_oops(const NANO_ESF *esf)
{
_NanoFatalErrorHandler(esf->r0, esf);
}
FUNC_NORETURN void _arch_syscall_oops(void *ssf_ptr) FUNC_NORETURN void _arch_syscall_oops(void *ssf_ptr)
{ {
_SysFatalErrorHandler(_NANO_ERR_KERNEL_OOPS, ssf_ptr); _SysFatalErrorHandler(_NANO_ERR_KERNEL_OOPS, ssf_ptr);

View file

@ -39,6 +39,13 @@ void _Fault(const NANO_ESF *esf)
code = _ARC_V2_ECR_CODE(ecr); code = _ARC_V2_ECR_CODE(ecr);
parameter = _ARC_V2_ECR_PARAMETER(ecr); parameter = _ARC_V2_ECR_PARAMETER(ecr);
/* exception raised by kernel */
if (vector == 0x9 && parameter == _TRAP_S_CALL_RUNTIME_EXCEPT) {
_NanoFatalErrorHandler(esf->r0, esf);
return;
}
printk("Exception vector: 0x%x, cause code: 0x%x, parameter 0x%x\n", printk("Exception vector: 0x%x, cause code: 0x%x, parameter 0x%x\n",
vector, code, parameter); vector, code, parameter);
printk("Address 0x%x\n", exc_addr); printk("Address 0x%x\n", exc_addr);

View file

@ -33,6 +33,9 @@ GTEXT(__ev_extension)
GTEXT(__ev_div_zero) GTEXT(__ev_div_zero)
GTEXT(__ev_dc_error) GTEXT(__ev_dc_error)
GTEXT(__ev_maligned) GTEXT(__ev_maligned)
#ifdef CONFIG_IRQ_OFFLOAD
GTEXT(_irq_do_offload);
#endif
GDATA(exc_nest_count) GDATA(exc_nest_count)
@ -40,10 +43,8 @@ GDATA(exc_nest_count)
SECTION_VAR(BSS, saved_value) SECTION_VAR(BSS, saved_value)
.word 0 .word 0
#define EXCEPTION_STACK_SIZE 256 /* the necessary stack size for exception handling */
#define EXCEPTION_STACK_SIZE 384
SECTION_VAR(NOINIT, _exception_stack)
.space EXCEPTION_STACK_SIZE
/* /*
* @brief Fault handler installed in the fault and reserved vectors * @brief Fault handler installed in the fault and reserved vectors
@ -62,6 +63,7 @@ SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_div_zero)
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_dc_error) SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_dc_error)
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_maligned) SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_maligned)
_exc_entry:
#ifdef CONFIG_ARC_STACK_CHECKING #ifdef CONFIG_ARC_STACK_CHECKING
st r0, [saved_value] st r0, [saved_value]
@ -72,10 +74,24 @@ SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_maligned)
ld r0, [saved_value] ld r0, [saved_value]
#endif #endif
st sp, [saved_value] st sp, [saved_value]
mov_s sp, _exception_stack /*
* re-use the top part of interrupt stack as exception
* stack. If this top part is used by interrupt handling,
* and exception is raised, then here it's guaranteed that
* exception handling has necessary stack to use
*/
mov_s sp, _interrupt_stack
add sp, sp, EXCEPTION_STACK_SIZE add sp, sp, EXCEPTION_STACK_SIZE
/* save caller saved registers */ /*
* save caller saved registers
* this stack frame is set up in exception stack,
* not in the original sp (thread stack or interrupt stack).
* Because the exception may be raised by stack checking or
* mpu protect violation related to stack. If this stack frame
* is setup in original sp, double exception may be raised during
* _create_irq_stack_frame, which is unrecoverable.
*/
_create_irq_stack_frame _create_irq_stack_frame
#ifdef CONFIG_ARC_HAS_SECURE #ifdef CONFIG_ARC_HAS_SECURE
@ -87,8 +103,8 @@ SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_maligned)
lr r0,[_ARC_V2_ERET] lr r0,[_ARC_V2_ERET]
st_s r0, [sp, ___isf_t_pc_OFFSET] /* eret into pc */ st_s r0, [sp, ___isf_t_pc_OFFSET] /* eret into pc */
/* sp is parameter of _Fault */
mov r0, sp mov r0, sp
jl _Fault jl _Fault
_exc_return: _exc_return:
@ -138,18 +154,13 @@ _exc_return_from_exc:
rtie rtie
#ifdef CONFIG_IRQ_OFFLOAD
GTEXT(_irq_do_offload);
#endif
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_trap) SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_trap)
/* get the id of trap_s */ /* get the id of trap_s */
lr ilink, [_ARC_V2_ECR] lr ilink, [_ARC_V2_ECR]
and ilink, ilink, 0x3f and ilink, ilink, 0x3f
#ifdef CONFIG_USERSPACE #ifdef CONFIG_USERSPACE
cmp ilink, _TRAP_S_CALL_SYSTEM_CALL cmp ilink, _TRAP_S_CALL_SYSTEM_CALL
bne _do_other_trap bne _do_non_syscall_trap
/* do sys_call */ /* do sys_call */
mov ilink, _SYSCALL_LIMIT mov ilink, _SYSCALL_LIMIT
cmp r6, ilink cmp r6, ilink
@ -177,27 +188,16 @@ valid_syscall_id:
rtie rtie
/* _do_non_syscall_trap:
* Before invoking exception handler, the kernel switches to an exception
* stack to save the faulting thread's registers.
* The exception is fatal and all the kernel can do is just print
* a diagnostic message and halt.
*/
_do_other_trap:
#endif /* CONFIG_USERSPACE */ #endif /* CONFIG_USERSPACE */
#ifdef CONFIG_ARC_STACK_CHECKING #ifdef CONFIG_IRQ_OFFLOAD
st r0, [saved_value] /*
/* disable stack checking */ * IRQ_OFFLOAD is to simulate interrupt handling through exception,
lr r0, [_ARC_V2_STATUS32] * so its entry is different with normal exception handling, it is
bclr r0, r0, _ARC_V2_STATUS32_SC_BIT * handled in isr stack
kflag r0 */
ld r0, [saved_value] cmp ilink, _TRAP_S_SCALL_IRQ_OFFLOAD
#endif bne _exc_entry
st sp, [saved_value]
mov_s sp, _exception_stack
add sp, sp, EXCEPTION_STACK_SIZE
/* save caller saved registers */ /* save caller saved registers */
_create_irq_stack_frame _create_irq_stack_frame
@ -210,21 +210,83 @@ _do_other_trap:
lr r0,[_ARC_V2_ERET] lr r0,[_ARC_V2_ERET]
st_s r0, [sp, ___isf_t_pc_OFFSET] /* eret into pc */ st_s r0, [sp, ___isf_t_pc_OFFSET] /* eret into pc */
mov r0, sp #ifdef CONFIG_ARC_STACK_CHECKING
/* disable stack checking */
mov blink, _exc_return lr r0, [_ARC_V2_STATUS32]
bclr r0, r0, _ARC_V2_STATUS32_SC_BIT
cmp ilink, _TRAP_S_CALL_RUNTIME_EXCEPT kflag r0
beq _oops
#ifdef CONFIG_IRQ_OFFLOAD
cmp ilink, _TRAP_S_SCALL_IRQ_OFFLOAD
bne _trap_fault
j _irq_do_offload
#endif #endif
_trap_fault: ld r1, [exc_nest_count]
j _Fault add r0, r1, 1
st r0, [exc_nest_count]
cmp r1, 0
_oops: bgt.d exc_nest_handle
j _do_kernel_oops mov r0, sp
mov r1, _kernel
ld sp, [r1, _kernel_offset_to_irq_stack]
exc_nest_handle:
push_s r0
jl _irq_do_offload
pop sp
mov r1, exc_nest_count
ld r0, [r1]
sub r0, r0, 1
cmp r0, 0
bne.d _exc_return_from_exc
st r0, [r1]
#ifdef CONFIG_PREEMPT_ENABLED
mov_s r1, _kernel
ld_s r2, [r1, _kernel_offset_to_current]
/* check if the current thread needs to be rescheduled */
ld_s r0, [r1, _kernel_offset_to_ready_q_cache]
breq r0, r2, _exc_return_from_irqoffload_trap
_save_callee_saved_regs
st _CAUSE_RIRQ, [r2, _thread_offset_to_relinquish_cause]
/* note: Ok to use _CAUSE_RIRQ since everything is saved */
ld_s r2, [r1, _kernel_offset_to_ready_q_cache]
st_s r2, [r1, _kernel_offset_to_current]
#ifdef CONFIG_ARC_HAS_SECURE
/*
* sync up the ERSEC_STAT.ERM and SEC_STAT.IRM.
* use a fake interrupt return to simulate an exception turn.
* ERM and IRM record which mode the cpu should return, 1: secure
* 0: normal
*/
lr r3,[_ARC_V2_ERSEC_STAT]
btst r3, 31
bset.nz r3, r3, 3
bclr.z r3, r3, 3
/* sflag r3 */
/* sflag instruction is not supported in current ARC GNU */
.long 0x00ff302f
#endif
/* clear AE bit to forget this was an exception */
lr r3, [_ARC_V2_STATUS32]
and r3,r3,(~_ARC_V2_STATUS32_AE)
kflag r3
/* pretend lowest priority interrupt happened to use common handler */
lr r3, [_ARC_V2_AUX_IRQ_ACT]
or r3,r3,(1<<(CONFIG_NUM_IRQ_PRIO_LEVELS-1)) /* use lowest */
sr r3, [_ARC_V2_AUX_IRQ_ACT]
/* Assumption: r2 has current thread */
b _rirq_common_interrupt_swap
#endif
_exc_return_from_irqoffload_trap:
_pop_irq_stack_frame
rtie
#endif /* CONFIG_IRQ_OFFLOAD */
b _exc_entry