1 /* ARM AArch32 GCC specific public inline assembler functions and macros */
2 
3 /*
4  * Copyright (c) 2015, Wind River Systems, Inc.
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 /* Either public functions or macros or invoked by public functions */
10 
11 #ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ASM_INLINE_GCC_H_
12 #define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ASM_INLINE_GCC_H_
13 
14 /*
15  * The file must not be included directly
16  * Include arch/cpu.h instead
17  */
18 
19 #ifndef _ASMLANGUAGE
20 
21 #include <zephyr/types.h>
22 #include <zephyr/arch/arm/exc.h>
23 
24 #if defined(CONFIG_CPU_AARCH32_CORTEX_R) || defined(CONFIG_CPU_AARCH32_CORTEX_A)
25 #include <zephyr/arch/arm/cortex_a_r/cpu.h>
26 #endif
27 
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31 
32 /* On ARMv7-M and ARMv8-M Mainline CPUs, this function prevents regular
33  * exceptions (i.e. with interrupt priority lower than or equal to
34  * _EXC_IRQ_DEFAULT_PRIO) from interrupting the CPU. NMI, Faults, SVC,
35  * and Zero Latency IRQs (if supported) may still interrupt the CPU.
36  *
37  * On ARMv6-M and ARMv8-M Baseline CPUs, this function reads the value of
38  * PRIMASK which shows if interrupts are enabled, then disables all interrupts
39  * except NMI.
40  */
41 
arch_irq_lock(void)42 static ALWAYS_INLINE unsigned int arch_irq_lock(void)
43 {
44 	unsigned int key;
45 
46 #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) && !defined(CONFIG_ARMV8_M_BASELINE)
47 #if CONFIG_MP_MAX_NUM_CPUS == 1
48 	__asm__ volatile("mrs %0, PRIMASK;"
49 		"cpsid i"
50 		: "=r" (key)
51 		:
52 		: "memory");
53 #else
54 #error "Cortex-M0 and Cortex-M0+ require SoC specific support for cross core synchronisation."
55 #endif
56 #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) || defined(CONFIG_ARMV8_M_BASELINE)
57 	unsigned int tmp;
58 
59 	__asm__ volatile(
60 		"mov %1, %2;"
61 		"mrs %0, BASEPRI;"
62 		"msr BASEPRI_MAX, %1;"
63 		"isb;"
64 		: "=r"(key),
65 #if defined(CONFIG_ARMV8_M_BASELINE)
66 		/* armv8-m.baseline's mov is limited to registers r0-r7.
67 		 * Let the compiler know we have this constraint on tmp.
68 		 */
69 		"=l"(tmp)
70 #else
71 		"=r"(tmp)
72 #endif
73 		: "i"(_EXC_IRQ_DEFAULT_PRIO)
74 		: "memory");
75 #elif defined(CONFIG_ARMV7_R) || defined(CONFIG_AARCH32_ARMV8_R) \
76 	|| defined(CONFIG_ARMV7_A)
77 	__asm__ volatile(
78 		"mrs %0, cpsr;"
79 		"and %0, #" TOSTR(I_BIT) ";"
80 		"cpsid i;"
81 		: "=r" (key)
82 		:
83 		: "memory", "cc");
84 #else
85 #error Unknown ARM architecture
86 #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */
87 
88 	return key;
89 }
90 
91 
92 /* On Cortex-M0/M0+, this enables all interrupts if they were not
93  * previously disabled.
94  */
95 
arch_irq_unlock(unsigned int key)96 static ALWAYS_INLINE void arch_irq_unlock(unsigned int key)
97 {
98 #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) && !defined(CONFIG_ARMV8_M_BASELINE)
99 	if (key != 0U) {
100 		return;
101 	}
102 	__asm__ volatile(
103 		"cpsie i;"
104 		"isb"
105 		: : : "memory");
106 #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) || defined(CONFIG_ARMV8_M_BASELINE)
107 	__asm__ volatile(
108 		"msr BASEPRI, %0;"
109 		"isb;"
110 		:  : "r"(key) : "memory");
111 #elif defined(CONFIG_ARMV7_R) || defined(CONFIG_AARCH32_ARMV8_R) \
112 	|| defined(CONFIG_ARMV7_A)
113 	if (key != 0U) {
114 		return;
115 	}
116 	__asm__ volatile(
117 		"cpsie i;"
118 		: : : "memory", "cc");
119 #else
120 #error Unknown ARM architecture
121 #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */
122 }
123 
arch_irq_unlocked(unsigned int key)124 static ALWAYS_INLINE bool arch_irq_unlocked(unsigned int key)
125 {
126 	/* This convention works for both PRIMASK and BASEPRI */
127 	return key == 0U;
128 }
129 
130 #ifdef __cplusplus
131 }
132 #endif
133 
134 #endif /* _ASMLANGUAGE */
135 
136 #endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ASM_INLINE_GCC_H_ */
137