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