Commit 97d04364 authored by Wayne Ren's avatar Wayne Ren Committed by Maureen Helm
Browse files

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: default avatarWayne Ren <wei.ren@synopsys.com>
parent 1c4fe3ed
Loading
Loading
Loading
Loading
+0 −5
Original line number Diff line number Diff line
@@ -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);
+7 −0
Original line number Diff line number Diff line
@@ -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);
+105 −43
Original line number Diff line number Diff line
@@ -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

_do_non_syscall_trap:
#endif /* CONFIG_USERSPACE */
#ifdef CONFIG_IRQ_OFFLOAD
	/*
	 * 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.
	 * IRQ_OFFLOAD is to simulate interrupt handling through exception,
	 * so its entry is different with normal exception handling, it is
	 * handled in isr stack
	 */

_do_other_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

	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 */

#ifdef CONFIG_ARC_STACK_CHECKING
	/* disable stack checking */
	lr r0, [_ARC_V2_STATUS32]
	bclr r0, r0, _ARC_V2_STATUS32_SC_BIT
	kflag r0
#endif

	ld r1, [exc_nest_count]
	add r0, r1, 1
	st r0, [exc_nest_count]
	cmp r1, 0

	bgt.d  exc_nest_handle
	mov r0, sp

	mov blink,  _exc_return
	mov r1, _kernel
	ld sp, [r1, _kernel_offset_to_irq_stack]
exc_nest_handle:
	push_s r0

	cmp ilink, _TRAP_S_CALL_RUNTIME_EXCEPT
	beq _oops
	jl _irq_do_offload

#ifdef CONFIG_IRQ_OFFLOAD
	cmp ilink, _TRAP_S_SCALL_IRQ_OFFLOAD
	bne _trap_fault
	j _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]

_trap_fault:
	j _Fault
	/* Assumption: r2 has current thread */
	b _rirq_common_interrupt_swap
#endif

_oops:
	j _do_kernel_oops
_exc_return_from_irqoffload_trap:
	_pop_irq_stack_frame
	rtie
#endif /* CONFIG_IRQ_OFFLOAD */
	b _exc_entry