Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | /* * Copyright (c) 2020 Stephanos Ioannidis <root@stephanos.io> * * SPDX-License-Identifier: Apache-2.0 */ /** * @file * @brief Exception handlers for ARM Cortex-A and Cortex-R * * This file implements the exception handlers (undefined instruction, prefetch * abort and data abort) for ARM Cortex-A and Cortex-R processors. * * All exception handlers save the exception stack frame into the exception * mode stack rather than the system mode stack, in order to ensure predictable * exception behaviour (i.e. an arbitrary thread stack overflow cannot cause * exception handling and thereby subsequent total system failure). * * In case the exception is due to a fatal (unrecoverable) fault, the fault * handler is responsible for invoking the architecture fatal exception handler * (z_arm_fatal_error) which invokes the kernel fatal exception handler * (z_fatal_error) that either locks up the system or aborts the current thread * depending on the application exception handler implementation. */ #include <zephyr/toolchain.h> #include <zephyr/linker/sections.h> #include <offsets_short.h> #include <zephyr/arch/cpu.h> _ASM_FILE_PROLOGUE #if defined(CONFIG_FPU_SHARING) GTEXT(z_arm_fault_undef_instruction_fp) #endif GTEXT(z_arm_fault_undef_instruction) GTEXT(z_arm_fault_prefetch) GTEXT(z_arm_fault_data) GTEXT(z_arm_undef_instruction) GTEXT(z_arm_prefetch_abort) GTEXT(z_arm_data_abort) .macro exception_entry mode /* * Store r0-r3, r12, lr, lr_und and spsr_und into the stack to * construct an exception stack frame. */ srsdb sp!, #\mode stmfd sp, {r0-r3, r12, lr}^ sub sp, #24 #if defined(CONFIG_FPU_SHARING) sub sp, #___fpu_t_SIZEOF vmrs r1, fpexc mov r0, #FPEXC_EN vmsr fpexc, r0 vmrs r0, fpscr mov r2, sp vstmia r2!, {s0-s15} stm r2, {r0, r1} #endif #if defined(CONFIG_EXTRA_EXCEPTION_INFO) /* Pointer to extra esf info */ sub sp, #___extra_esf_info_t_SIZEOF mov r0, #0 str r0, [sp, #4] str r0, [sp, #8] sub r1, sp, #___callee_saved_t_SIZEOF str r1, [sp] cps #MODE_SYS stm r1, {r4-r11, sp} cps #\mode mov r0, sp mov sp, r1 #else mov r0, sp #endif /* Increment exception nesting count */ ldr r2, =_kernel ldr r1, [r2, #_kernel_offset_to_nested] add r1, r1, #1 str r1, [r2, #_kernel_offset_to_nested] .endm .macro exception_exit /* Exit exception */ #if defined(CONFIG_EXTRA_EXCEPTION_INFO) add sp, #___extra_esf_info_t_SIZEOF add sp, #___callee_saved_t_SIZEOF #endif .endm /** * @brief Undefined instruction exception handler * * An undefined instruction (UNDEF) exception is generated when an undefined * instruction, or a VFP instruction when the VFP is not enabled, is * encountered. */ SECTION_SUBSEC_FUNC(TEXT, __exc, z_arm_undef_instruction) /* * The undefined instruction address is offset by 2 if the previous * mode is Thumb; otherwise, it is offset by 4. */ push {r0} mrs r0, spsr tst r0, #T_BIT subeq lr, #4 /* ARM (!T_BIT) */ subne lr, #2 /* Thumb (T_BIT) */ pop {r0} /* * Store r0-r3, r12, lr, lr_und and spsr_und into the stack to * construct an exception stack frame. */ srsdb sp!, #MODE_UND stmfd sp, {r0-r3, r12, lr}^ sub sp, #24 /* Increment exception nesting count */ ldr r2, =_kernel ldr r1, [r2, #_kernel_offset_to_nested] add r1, r1, #1 str r1, [r2, #_kernel_offset_to_nested] #if defined(CONFIG_FPU_SHARING) sub sp, #___fpu_t_SIZEOF bl z_arm_fault_undef_instruction_fp cmp r0, #0 beq z_arm_exc_exit vmrs r1, fpexc mov r0, #FPEXC_EN vmsr fpexc, r0 vmrs r0, fpscr mov r2, sp vstmia r2!, {s0-s15} stm r2, {r0, r1} #endif #if defined(CONFIG_EXTRA_EXCEPTION_INFO) /* Pointer to extra esf info */ sub sp, #___extra_esf_info_t_SIZEOF mov r0, #0 str r0, [sp, #4] str r0, [sp, #8] sub r1, sp, #___callee_saved_t_SIZEOF str r1, [sp] cps #MODE_SYS stm r1, {r4-r11, sp} cps #MODE_UND mov r0, sp mov sp, r1 #else mov r0, sp #endif bl z_arm_fault_undef_instruction exception_exit b z_arm_exc_exit /** * @brief Prefetch abort exception handler * * A prefetch abort (PABT) exception is generated when the processor marks the * prefetched instruction as invalid and the instruction is executed. */ SECTION_SUBSEC_FUNC(TEXT, __exc, z_arm_prefetch_abort) /* * The faulting instruction address is always offset by 4 for the * prefetch abort exceptions. */ sub lr, #4 exception_entry MODE_ABT bl z_arm_fault_prefetch exception_exit b z_arm_exc_exit #if defined(CONFIG_FPU_SHARING) #define FPU_SF_SIZE ___fpu_t_SIZEOF #else #define FPU_SF_SIZE 0 #endif /** * @brief Data abort exception handler * * A data abort (DABT) exception is generated when an error occurs on a data * memory access. This exception can be either synchronous or asynchronous, * depending on the type of fault that caused it. */ SECTION_SUBSEC_FUNC(TEXT, __exc, z_arm_data_abort) /* * The faulting instruction address is always offset by 8 for the data * abort exceptions. */ sub lr, #8 exception_entry MODE_ABT bl z_arm_fault_data /* * If z_arm_fault_data returns false, then we recovered from * the error. It may have updated $pc, so copy $pc back to * the true esf from the one passed to z_arm_fault_data. */ cmp r0, #0 ldreq r1, [sp, #24 + FPU_SF_SIZE] exception_exit streq r1, [sp, #24 + FPU_SF_SIZE] b z_arm_exc_exit |