/* * Copyright (c) 2014 Wind River Systems, Inc. * Copyright (c) 2018 Synopsys. * * SPDX-License-Identifier: Apache-2.0 */ /** * @file * @brief Fault handlers for ARCv2 * * Fault handlers for ARCv2 processors. */ #include #include #include #include GTEXT(_Fault) GTEXT(_do_kernel_oops) GTEXT(__reset) GTEXT(__memory_error) GTEXT(__instruction_error) GTEXT(__ev_machine_check) GTEXT(__ev_tlb_miss_i) GTEXT(__ev_tlb_miss_d) GTEXT(__ev_prot_v) GTEXT(__ev_privilege_v) GTEXT(__ev_swi) GTEXT(__ev_trap) GTEXT(__ev_extension) GTEXT(__ev_div_zero) GTEXT(__ev_dc_error) GTEXT(__ev_maligned) GDATA(exc_nest_count) /* * @brief Fault handler installed in the fault and reserved vectors */ SECTION_SUBSEC_FUNC(TEXT,__fault,__memory_error) SECTION_SUBSEC_FUNC(TEXT,__fault,__instruction_error) SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_machine_check) SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_tlb_miss_i) SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_tlb_miss_d) SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_prot_v) SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_privilege_v) SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_swi) SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_extension) SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_div_zero) SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_dc_error) SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_maligned) /* * 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. */ #ifdef CONFIG_ARC_STACK_CHECKING push_s r2 /* disable stack checking */ lr r2, [_ARC_V2_STATUS32] bclr r2, r2, _ARC_V2_STATUS32_SC_BIT kflag r2 pop_s r2 #endif /* save caller saved registers */ _create_irq_stack_frame #ifdef CONFIG_ARC_HAS_SECURE lr r0,[_ARC_V2_ERSEC_STAT] st_s r0, [sp, ___isf_t_sec_stat_OFFSET] #endif lr r0,[_ARC_V2_ERSTATUS] st_s r0, [sp, ___isf_t_status32_OFFSET] lr r0,[_ARC_V2_ERET] st_s r0, [sp, ___isf_t_pc_OFFSET] /* eret into pc */ 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 r1, _kernel ld sp, [r1, _kernel_offset_to_irq_stack] exc_nest_handle: push_s r0 jl _Fault _exc_return: 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_exc _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_exc: _pop_irq_stack_frame 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 /* do sys_call */ mov ilink, _SYSCALL_LIMIT cmp r6, ilink blt valid_syscall_id mov r0, r6 mov r6, _SYSCALL_BAD valid_syscall_id: #ifdef CONFIG_ARC_HAS_SECURE lr ilink, [_ARC_V2_ERSEC_STAT] push ilink #endif lr ilink, [_ARC_V2_ERET] push ilink lr ilink, [_ARC_V2_ERSTATUS] push ilink bclr ilink, ilink, _ARC_V2_STATUS32_U_BIT sr ilink, [_ARC_V2_ERSTATUS] mov ilink, _arc_do_syscall sr ilink, [_ARC_V2_ERET] 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: #endif /* CONFIG_USERSPACE */ #ifdef CONFIG_ARC_STACK_CHECKING push_s r2 /* disable stack checking */ lr r2, [_ARC_V2_STATUS32] bclr r2, r2, _ARC_V2_STATUS32_SC_BIT kflag r2 pop_s r2 #endif /* save caller saved registers */ _create_irq_stack_frame #ifdef CONFIG_ARC_HAS_SECURE lr r0,[_ARC_V2_ERSEC_STAT] st_s r0, [sp, ___isf_t_sec_stat_OFFSET] #endif lr r0,[_ARC_V2_ERSTATUS] st_s r0, [sp, ___isf_t_status32_OFFSET] lr r0,[_ARC_V2_ERET] st_s r0, [sp, ___isf_t_pc_OFFSET] /* eret into pc */ ld r1, [exc_nest_count] add r0, r1, 1 st r0, [exc_nest_count] cmp r1, 0 bgt.d trap_nest_handle mov r0, sp mov r1, _kernel ld sp, [r1, _kernel_offset_to_irq_stack] trap_nest_handle: push_s r0 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 #endif _trap_fault: j _Fault _oops: j _do_kernel_oops