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:
parent
1c4fe3edc0
commit
97d0436486
3 changed files with 117 additions and 53 deletions
|
@ -81,11 +81,6 @@ void _NanoFatalErrorHandler(unsigned int reason, const NANO_ESF *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)
|
||||
{
|
||||
_SysFatalErrorHandler(_NANO_ERR_KERNEL_OOPS, ssf_ptr);
|
||||
|
|
|
@ -39,6 +39,13 @@ void _Fault(const NANO_ESF *esf)
|
|||
code = _ARC_V2_ECR_CODE(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",
|
||||
vector, code, parameter);
|
||||
printk("Address 0x%x\n", exc_addr);
|
||||
|
|
|
@ -33,6 +33,9 @@ GTEXT(__ev_extension)
|
|||
GTEXT(__ev_div_zero)
|
||||
GTEXT(__ev_dc_error)
|
||||
GTEXT(__ev_maligned)
|
||||
#ifdef CONFIG_IRQ_OFFLOAD
|
||||
GTEXT(_irq_do_offload);
|
||||
#endif
|
||||
|
||||
GDATA(exc_nest_count)
|
||||
|
||||
|
@ -40,10 +43,8 @@ GDATA(exc_nest_count)
|
|||
SECTION_VAR(BSS, saved_value)
|
||||
.word 0
|
||||
|
||||
#define EXCEPTION_STACK_SIZE 256
|
||||
|
||||
SECTION_VAR(NOINIT, _exception_stack)
|
||||
.space EXCEPTION_STACK_SIZE
|
||||
/* the necessary stack size for exception handling */
|
||||
#define EXCEPTION_STACK_SIZE 384
|
||||
|
||||
/*
|
||||
* @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_maligned)
|
||||
|
||||
_exc_entry:
|
||||
|
||||
#ifdef CONFIG_ARC_STACK_CHECKING
|
||||
st r0, [saved_value]
|
||||
|
@ -72,10 +74,24 @@ SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_maligned)
|
|||
ld r0, [saved_value]
|
||||
#endif
|
||||
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
|
||||
|
||||
/* 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
|
||||
|
||||
#ifdef CONFIG_ARC_HAS_SECURE
|
||||
|
@ -87,8 +103,8 @@ SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_maligned)
|
|||
lr r0,[_ARC_V2_ERET]
|
||||
st_s r0, [sp, ___isf_t_pc_OFFSET] /* eret into pc */
|
||||
|
||||
/* sp is parameter of _Fault */
|
||||
mov r0, sp
|
||||
|
||||
jl _Fault
|
||||
|
||||
_exc_return:
|
||||
|
@ -138,18 +154,13 @@ _exc_return_from_exc:
|
|||
rtie
|
||||
|
||||
|
||||
#ifdef CONFIG_IRQ_OFFLOAD
|
||||
GTEXT(_irq_do_offload);
|
||||
#endif
|
||||
|
||||
|
||||
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_trap)
|
||||
/* get the id of trap_s */
|
||||
lr ilink, [_ARC_V2_ECR]
|
||||
and ilink, ilink, 0x3f
|
||||
#ifdef CONFIG_USERSPACE
|
||||
cmp ilink, _TRAP_S_CALL_SYSTEM_CALL
|
||||
bne _do_other_trap
|
||||
bne _do_non_syscall_trap
|
||||
/* do sys_call */
|
||||
mov ilink, _SYSCALL_LIMIT
|
||||
cmp r6, ilink
|
||||
|
@ -177,27 +188,16 @@ valid_syscall_id:
|
|||
|
||||
rtie
|
||||
|
||||
/*
|
||||
* 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:
|
||||
_do_non_syscall_trap:
|
||||
#endif /* CONFIG_USERSPACE */
|
||||
#ifdef CONFIG_ARC_STACK_CHECKING
|
||||
st r0, [saved_value]
|
||||
/* disable stack checking */
|
||||
lr r0, [_ARC_V2_STATUS32]
|
||||
bclr r0, r0, _ARC_V2_STATUS32_SC_BIT
|
||||
kflag r0
|
||||
ld r0, [saved_value]
|
||||
#endif
|
||||
st sp, [saved_value]
|
||||
mov_s sp, _exception_stack
|
||||
add sp, sp, EXCEPTION_STACK_SIZE
|
||||
|
||||
#ifdef CONFIG_IRQ_OFFLOAD
|
||||
/*
|
||||
* IRQ_OFFLOAD is to simulate interrupt handling through exception,
|
||||
* so its entry is different with normal exception handling, it is
|
||||
* handled in isr stack
|
||||
*/
|
||||
cmp ilink, _TRAP_S_SCALL_IRQ_OFFLOAD
|
||||
bne _exc_entry
|
||||
/* save caller saved registers */
|
||||
_create_irq_stack_frame
|
||||
|
||||
|
@ -210,21 +210,83 @@ _do_other_trap:
|
|||
lr r0,[_ARC_V2_ERET]
|
||||
st_s r0, [sp, ___isf_t_pc_OFFSET] /* eret into pc */
|
||||
|
||||
mov r0, sp
|
||||
|
||||
mov blink, _exc_return
|
||||
|
||||
cmp ilink, _TRAP_S_CALL_RUNTIME_EXCEPT
|
||||
beq _oops
|
||||
|
||||
#ifdef CONFIG_IRQ_OFFLOAD
|
||||
cmp ilink, _TRAP_S_SCALL_IRQ_OFFLOAD
|
||||
bne _trap_fault
|
||||
j _irq_do_offload
|
||||
#ifdef CONFIG_ARC_STACK_CHECKING
|
||||
/* disable stack checking */
|
||||
lr r0, [_ARC_V2_STATUS32]
|
||||
bclr r0, r0, _ARC_V2_STATUS32_SC_BIT
|
||||
kflag r0
|
||||
#endif
|
||||
|
||||
_trap_fault:
|
||||
j _Fault
|
||||
ld r1, [exc_nest_count]
|
||||
add r0, r1, 1
|
||||
st r0, [exc_nest_count]
|
||||
cmp r1, 0
|
||||
|
||||
_oops:
|
||||
j _do_kernel_oops
|
||||
bgt.d exc_nest_handle
|
||||
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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue