1 /*
2  * Copyright (c) 2013-2014 Wind River Systems, Inc.
3  * Copyright 2023, 2025 Arm Limited and/or its affiliates <open-source-office@arm.com>
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/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 		IF_ENABLED(CONFIG_ARM_BTI, ("bti\n")) \
43 		:: [_reason] "r" (reason_p), [id] "i" (_SVC_CALL_RUNTIME_EXCEPT) \
44 		: "r0", "memory"); \
45 } while (false)
46 #elif defined(CONFIG_ARMV7_R) || defined(CONFIG_AARCH32_ARMV8_R) \
47 	|| defined(CONFIG_ARMV7_A)
48 /*
49  * In order to support using svc for an exception while running in an
50  * isr, stack $lr_svc before calling svc.  While exiting the isr,
51  * z_check_stack_sentinel is called.  $lr_svc contains the return address.
52  * If the sentinel is wrong, it calls svc to cause an oops.  This svc
53  * call will overwrite $lr_svc, losing the return address from the
54  * z_check_stack_sentinel call if it is not stacked before the svc.
55  */
56 #define ARCH_EXCEPT(reason_p) \
57 do { \
58 	register uint32_t r0 __asm__("r0") = reason_p; \
59 	__asm__ volatile ( \
60 		"push {lr}\n\t" \
61 		"cpsie i\n\t" \
62 		"svc %[id]\n\t" \
63 		IF_ENABLED(CONFIG_ARM_BTI, ("bti\n\t")) \
64 		"pop {lr}\n\t" \
65 		: \
66 		: "r" (r0), [id] "i" (_SVC_CALL_RUNTIME_EXCEPT) \
67 		: "memory"); \
68 } while (false)
69 #else
70 #error Unknown ARM architecture
71 #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */
72 
73 #ifdef __cplusplus
74 }
75 #endif
76 
77 #endif /* ZEPHYR_INCLUDE_ARCH_ARM_ERROR_H_ */
78