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