1 /*
2  * Copyright (c) 2013-2014 Wind River Systems, Inc.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief ARM AArch32 public error handling
10  *
11  * ARM AArch32-specific kernel error handling interface. Included by
12  * arm/arch.h.
13  */
14 
15 #ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ERROR_H_
16 #define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ERROR_H_
17 
18 #include <zephyr/arch/arm/syscall.h>
19 #include <zephyr/arch/arm/exc.h>
20 #include <stdbool.h>
21 
22 #ifdef __cplusplus
23 extern "C" {
24 #endif
25 
26 #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
27 /* ARMv6 will hard-fault if SVC is called with interrupts locked. Just
28  * force them unlocked, the thread is in an undefined state anyway
29  *
30  * On ARMv7m we won't get a HardFault, but if interrupts were locked the
31  * thread will continue executing after the exception and forbid PendSV to
32  * schedule a new thread until they are unlocked which is not what we want.
33  * Force them unlocked as well.
34  */
35 #define ARCH_EXCEPT(reason_p) \
36 register uint32_t r0 __asm__("r0") = reason_p; \
37 do { \
38 	__asm__ volatile ( \
39 		"cpsie i\n\t" \
40 		"svc %[id]\n\t" \
41 		: \
42 		: "r" (r0), [id] "i" (_SVC_CALL_RUNTIME_EXCEPT) \
43 		: "memory"); \
44 } while (false)
45 #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
46 #define ARCH_EXCEPT(reason_p) do { \
47 	__asm__ volatile ( \
48 		"eors.n r0, r0\n\t" \
49 		"msr BASEPRI, r0\n\t" \
50 		"mov r0, %[reason]\n\t" \
51 		"svc %[id]\n\t" \
52 		: \
53 		: [reason] "i" (reason_p), [id] "i" (_SVC_CALL_RUNTIME_EXCEPT) \
54 		: "memory"); \
55 } while (false)
56 #elif defined(CONFIG_ARMV7_R) || defined(CONFIG_AARCH32_ARMV8_R) \
57 	|| defined(CONFIG_ARMV7_A)
58 /*
59  * In order to support using svc for an exception while running in an
60  * isr, stack $lr_svc before calling svc.  While exiting the isr,
61  * z_check_stack_sentinel is called.  $lr_svc contains the return address.
62  * If the sentinel is wrong, it calls svc to cause an oops.  This svc
63  * call will overwrite $lr_svc, losing the return address from the
64  * z_check_stack_sentinel call if it is not stacked before the svc.
65  */
66 #define ARCH_EXCEPT(reason_p) \
67 register uint32_t r0 __asm__("r0") = reason_p; \
68 do { \
69 	__asm__ volatile ( \
70 		"push {lr}\n\t" \
71 		"cpsie i\n\t" \
72 		"svc %[id]\n\t" \
73 		"pop {lr}\n\t" \
74 		: \
75 		: "r" (r0), [id] "i" (_SVC_CALL_RUNTIME_EXCEPT) \
76 		: "memory"); \
77 } while (false)
78 #else
79 #error Unknown ARM architecture
80 #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */
81 
82 #ifdef __cplusplus
83 }
84 #endif
85 
86 #endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ERROR_H_ */
87