1/* 2 * Copyright (c) 2014 Wind River Systems, Inc. 3 * Copyright (c) 2018 Synopsys. 4 * 5 * SPDX-License-Identifier: Apache-2.0 6 */ 7 8/** 9 * @file 10 * @brief Fault handlers for ARCv2 11 * 12 * Fault handlers for ARCv2 processors. 13 */ 14 15#include <zephyr/toolchain.h> 16#include <zephyr/linker/sections.h> 17#include <zephyr/arch/cpu.h> 18#include <swap_macros.h> 19#include <zephyr/syscall.h> 20#include <zephyr/arch/arc/asm-compat/assembler.h> 21 22GTEXT(_Fault) 23GTEXT(__reset) 24GTEXT(__memory_error) 25GTEXT(__instruction_error) 26GTEXT(__ev_machine_check) 27GTEXT(__ev_tlb_miss_i) 28GTEXT(__ev_tlb_miss_d) 29GTEXT(__ev_prot_v) 30GTEXT(__ev_privilege_v) 31GTEXT(__ev_swi) 32GTEXT(__ev_trap) 33GTEXT(__ev_extension) 34GTEXT(__ev_div_zero) 35GTEXT(__ev_dc_error) 36GTEXT(__ev_maligned) 37 38.macro _save_exc_regs_into_stack 39#ifdef CONFIG_ARC_HAS_SECURE 40 /* ERSEC_STAT is IOW/RAZ in normal mode */ 41 lr r0,[_ARC_V2_ERSEC_STAT] 42 st_s r0, [sp, ___isf_t_sec_stat_OFFSET] 43#endif 44 LRR r0, [_ARC_V2_ERET] 45 STR r0, sp, ___isf_t_pc_OFFSET 46 LRR r0, [_ARC_V2_ERSTATUS] 47 STR r0, sp, ___isf_t_status32_OFFSET 48.endm 49 50/* 51 * The exception handling will use top part of interrupt stack to 52 * get smaller memory footprint, because exception is not frequent. 53 * To reduce the impact on interrupt handling, especially nested interrupt 54 * the top part of interrupt stack cannot be too large, so add a check 55 * here 56 */ 57#if CONFIG_ARC_EXCEPTION_STACK_SIZE > (CONFIG_ISR_STACK_SIZE >> 1) 58#error "interrupt stack size is too small" 59#endif 60 61/* 62 * @brief Fault handler installed in the fault and reserved vectors 63 */ 64 65SECTION_SUBSEC_FUNC(TEXT,__fault,__memory_error) 66SECTION_SUBSEC_FUNC(TEXT,__fault,__instruction_error) 67SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_machine_check) 68SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_tlb_miss_i) 69SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_tlb_miss_d) 70SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_prot_v) 71SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_privilege_v) 72SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_swi) 73SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_extension) 74SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_div_zero) 75SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_dc_error) 76SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_maligned) 77 78_exc_entry: 79 /* 80 * re-use the top part of interrupt stack as exception 81 * stack. If this top part is used by interrupt handling, 82 * and exception is raised, then here it's guaranteed that 83 * exception handling has necessary stack to use 84 */ 85 MOVR ilink, sp 86 _get_curr_cpu_irq_stack sp 87 SUBR sp, sp, (CONFIG_ISR_STACK_SIZE - CONFIG_ARC_EXCEPTION_STACK_SIZE) 88 89 /* 90 * save caller saved registers 91 * this stack frame is set up in exception stack, 92 * not in the original sp (thread stack or interrupt stack). 93 * Because the exception may be raised by stack checking or 94 * mpu protect violation related to stack. If this stack frame 95 * is setup in original sp, double exception may be raised during 96 * _create_irq_stack_frame, which is unrecoverable. 97 */ 98 _create_irq_stack_frame 99 100 _save_exc_regs_into_stack 101 102 /* sp is parameter of _Fault */ 103 MOVR r0, sp 104 /* ilink is the thread's original sp */ 105 MOVR r1, ilink 106 jl _Fault 107 108_exc_return: 109/* the exception cause must be fixed in exception handler when exception returns 110 * directly, or exception will be repeated. 111 * 112 * If thread switch is raised in exception handler, the context of old thread will 113 * not be saved, i.e., it cannot be recovered, because we don't know where the 114 * exception comes out, thread context?irq_context?nest irq context? 115 */ 116 117 _get_next_switch_handle 118 119 BREQR r0, 0, _exc_return_from_exc 120 121 /* Save old thread into switch handle which is required by z_sched_switch_spin which 122 * will be called during old thread abort. 123 */ 124 STR r2, r2, ___thread_t_switch_handle_OFFSET 125 126 MOVR r2, r0 127 128#ifdef CONFIG_ARC_SECURE_FIRMWARE 129 /* 130 * sync up the ERSEC_STAT.ERM and SEC_STAT.IRM. 131 * use a fake interrupt return to simulate an exception turn. 132 * ERM and IRM record which mode the cpu should return, 1: secure 133 * 0: normal 134 */ 135 lr r3,[_ARC_V2_ERSEC_STAT] 136 btst r3, 31 137 bset.nz r3, r3, _ARC_V2_SEC_STAT_IRM_BIT 138 bclr.z r3, r3, _ARC_V2_SEC_STAT_IRM_BIT 139 sflag r3 140#endif 141 /* clear AE bit to forget this was an exception, and go to 142 * register bank0 (if exception is raised in firq with 2 reg 143 * banks, then we may be bank1) 144 */ 145#if defined(CONFIG_ARC_FIRQ) && CONFIG_RGF_NUM_BANKS != 1 146 /* save r2 in ilink because of the possible following reg 147 * bank switch 148 */ 149 mov ilink, r2 150#endif 151 LRR r3, [_ARC_V2_STATUS32] 152 ANDR r3, r3, (~(_ARC_V2_STATUS32_AE | _ARC_V2_STATUS32_RB(7))) 153 kflag r3 154 /* pretend lowest priority interrupt happened to use common handler 155 * if exception is raised in irq, i.e., _ARC_V2_AUX_IRQ_ACT !=0, 156 * ignore irq handling, we cannot return to irq handling which may 157 * raise exception again. The ignored interrupts will be re-triggered 158 * if not cleared, or re-triggered by interrupt sources, or just missed 159 */ 160 161#ifdef CONFIG_ARC_SECURE_FIRMWARE 162 mov_s r3, (1 << (ARC_N_IRQ_START_LEVEL - 1)) 163#else 164 MOVR r3, (1 << (CONFIG_NUM_IRQ_PRIO_LEVELS - 1)) 165#endif 166 167#ifdef CONFIG_ARC_NORMAL_FIRMWARE 168 push_s r2 169 mov_s r0, _ARC_V2_AUX_IRQ_ACT 170 mov_s r1, r3 171 mov_s r6, ARC_S_CALL_AUX_WRITE 172 sjli SJLI_CALL_ARC_SECURE 173 pop_s r2 174#else 175 SRR r3, [_ARC_V2_AUX_IRQ_ACT] 176#endif 177 178#if defined(CONFIG_ARC_FIRQ) && CONFIG_RGF_NUM_BANKS != 1 179 mov r2, ilink 180#endif 181 182 /* Assumption: r2 has next thread */ 183 b _rirq_newthread_switch 184 185_exc_return_from_exc: 186 /* exception handler may change return address. 187 * reload it 188 */ 189 LDR r0, sp, ___isf_t_pc_OFFSET 190 SRR r0, [_ARC_V2_ERET] 191 192 _pop_irq_stack_frame 193 MOVR sp, ilink 194 rtie 195 196/* separated entry for trap which may be used by irq_offload, USERPSACE */ 197SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_trap) 198 /* get the id of trap_s */ 199 LRR ilink, [_ARC_V2_ECR] 200 ANDR ilink, ilink, 0x3f 201#ifdef CONFIG_USERSPACE 202 cmp ilink, _TRAP_S_CALL_SYSTEM_CALL 203 bne _do_non_syscall_trap 204 /* do sys_call */ 205 mov ilink, K_SYSCALL_LIMIT 206 cmp r6, ilink 207 blo valid_syscall_id 208 209 mov_s r0, r6 210 mov_s r6, K_SYSCALL_BAD 211 212valid_syscall_id: 213 /* create a sys call frame 214 * caller regs (r0 - 12) are saved in _create_irq_stack_frame 215 * ok to use them later 216 */ 217 _create_irq_stack_frame 218 219 _save_exc_regs_into_stack 220 221 /* exc return and do sys call in kernel mode, 222 * so need to clear U bit, r0 is already loaded 223 * with ERSTATUS in _save_exc_regs_into_stack 224 */ 225 226 bclr r0, r0, _ARC_V2_STATUS32_U_BIT 227 sr r0, [_ARC_V2_ERSTATUS] 228 229 mov_s r0, _arc_do_syscall 230 sr r0, [_ARC_V2_ERET] 231 232 rtie 233 234_do_non_syscall_trap: 235#endif /* CONFIG_USERSPACE */ 236 b _exc_entry 237