1 /*
2  * Copyright (c) 2014 Wind River Systems, Inc.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief ARC specific kernel interface header
10  *
11  * This header contains the ARC specific kernel interface.  It is
12  * included by the kernel interface architecture-abstraction header
13  * include/arch/cpu.h)
14  */
15 
16 #ifndef ZEPHYR_INCLUDE_ARCH_ARC_ARCH_H_
17 #define ZEPHYR_INCLUDE_ARCH_ARC_ARCH_H_
18 
19 #include <zephyr/devicetree.h>
20 #include <zephyr/sw_isr_table.h>
21 #include <zephyr/arch/common/ffs.h>
22 #include <zephyr/arch/arc/thread.h>
23 #include <zephyr/arch/common/sys_bitops.h>
24 #include "sys-io-common.h"
25 
26 #include <zephyr/arch/arc/v2/exc.h>
27 #include <zephyr/arch/arc/v2/irq.h>
28 #include <zephyr/arch/arc/v2/misc.h>
29 #include <zephyr/arch/arc/v2/aux_regs.h>
30 #include <zephyr/arch/arc/v2/arcv2_irq_unit.h>
31 #include <zephyr/arch/arc/v2/asm_inline.h>
32 #include <zephyr/arch/arc/arc_addr_types.h>
33 #include <zephyr/arch/arc/v2/error.h>
34 
35 #ifdef CONFIG_ARC_CONNECT
36 #include <zephyr/arch/arc/v2/arc_connect.h>
37 #endif
38 
39 #ifdef CONFIG_ISA_ARCV2
40 #include "v2/sys_io.h"
41 #ifdef CONFIG_ARC_HAS_SECURE
42 #include <zephyr/arch/arc/v2/secureshield/arc_secure.h>
43 #endif
44 #endif
45 
46 #if defined(CONFIG_ARC_FIRQ) && defined(CONFIG_ISA_ARCV3)
47 #error "Unsupported configuration: ARC_FIRQ and ISA_ARCV3"
48 #endif
49 
50 /*
51  * We don't allow the configuration with FIRQ enabled and only one interrupt priority level
52  * (so all interrupts are FIRQ). Such configuration isn't supported in software and it is not
53  * beneficial from the performance point of view.
54  */
55 #if defined(CONFIG_ARC_FIRQ) && CONFIG_NUM_IRQ_PRIO_LEVELS < 2
56 #error "Unsupported configuration: ARC_FIRQ and (NUM_IRQ_PRIO_LEVELS < 2)"
57 #endif
58 
59 #if CONFIG_RGF_NUM_BANKS > 1 && !defined(CONFIG_ARC_FIRQ)
60 #error "Unsupported configuration: (RGF_NUM_BANKS > 1) and !ARC_FIRQ"
61 #endif
62 
63 /*
64  * It's required to have more than one interrupt priority level to use second register bank
65  * - otherwise all interrupts will use same register bank. Such configuration isn't supported in
66  * software and it is not beneficial from the performance point of view.
67  */
68 #if CONFIG_RGF_NUM_BANKS > 1 && CONFIG_NUM_IRQ_PRIO_LEVELS < 2
69 #error "Unsupported configuration: (RGF_NUM_BANKS > 1) and (NUM_IRQ_PRIO_LEVELS < 2)"
70 #endif
71 
72 #if defined(CONFIG_ARC_FIRQ_STACK) && !defined(CONFIG_ARC_FIRQ)
73 #error "Unsupported configuration: ARC_FIRQ_STACK and !ARC_FIRQ"
74 #endif
75 
76 #if defined(CONFIG_ARC_FIRQ_STACK) && CONFIG_RGF_NUM_BANKS < 2
77 #error "Unsupported configuration: ARC_FIRQ_STACK and (RGF_NUM_BANKS < 2)"
78 #endif
79 
80 /* In case of ARC 2+2 secure mode enabled the firq are not supported by HW */
81 #if defined(CONFIG_ARC_FIRQ) && defined(CONFIG_ARC_HAS_SECURE)
82 #error "Unsupported configuration: ARC_FIRQ and ARC_HAS_SECURE"
83 #endif
84 
85 #if defined(CONFIG_SMP) && !defined(CONFIG_MULTITHREADING)
86 #error "Non-multithreading mode isn't supported on SMP targets"
87 #endif
88 
89 #ifndef _ASMLANGUAGE
90 
91 #ifdef __cplusplus
92 extern "C" {
93 #endif
94 
95 #ifdef CONFIG_64BIT
96 #define ARCH_STACK_PTR_ALIGN	8
97 #else
98 #define ARCH_STACK_PTR_ALIGN	4
99 #endif /* CONFIG_64BIT */
100 
101 BUILD_ASSERT(CONFIG_ISR_STACK_SIZE % ARCH_STACK_PTR_ALIGN == 0,
102 	"CONFIG_ISR_STACK_SIZE must be a multiple of ARCH_STACK_PTR_ALIGN");
103 
104 BUILD_ASSERT(CONFIG_ARC_EXCEPTION_STACK_SIZE % ARCH_STACK_PTR_ALIGN == 0,
105 	"CONFIG_ARC_EXCEPTION_STACK_SIZE must be a multiple of ARCH_STACK_PTR_ALIGN");
106 
107 /* Indicate, for a minimally sized MPU region, how large it must be and what
108  * its base address must be aligned to.
109  *
110  * For regions that are NOT the minimum size, this define has no semantics
111  * on ARC MPUv2 as its regions must be power of two size and aligned to their
112  * own size. On ARC MPUv4, region sizes are arbitrary and this just indicates
113  * the required size granularity.
114  */
115 #ifdef CONFIG_ARC_CORE_MPU
116 #if CONFIG_ARC_MPU_VER == 2
117 #define Z_ARC_MPU_ALIGN	2048
118 #elif (CONFIG_ARC_MPU_VER == 3) || (CONFIG_ARC_MPU_VER == 4) || \
119 	(CONFIG_ARC_MPU_VER == 6) || (CONFIG_ARC_MPU_VER == 8)
120 #define Z_ARC_MPU_ALIGN	32
121 #else
122 #error "Unsupported MPU version"
123 #endif
124 #endif
125 
126 #ifdef CONFIG_MPU_STACK_GUARD
127 #define Z_ARC_STACK_GUARD_SIZE	Z_ARC_MPU_ALIGN
128 #else
129 #define Z_ARC_STACK_GUARD_SIZE	0
130 #endif
131 
132 /* Kernel-only stacks have the following layout if a stack guard is enabled:
133  *
134  * +------------+ <- thread.stack_obj
135  * | Guard      | } Z_ARC_STACK_GUARD_SIZE
136  * +------------+ <- thread.stack_info.start
137  * | Kernel     |
138  * | stack      |
139  * |            |
140  * +............|
141  * | TLS        | } thread.stack_info.delta
142  * +------------+ <- thread.stack_info.start + thread.stack_info.size
143  */
144 #ifdef CONFIG_MPU_STACK_GUARD
145 #define ARCH_KERNEL_STACK_RESERVED	Z_ARC_STACK_GUARD_SIZE
146 #define ARCH_KERNEL_STACK_OBJ_ALIGN	Z_ARC_MPU_ALIGN
147 #endif
148 
149 #ifdef CONFIG_USERSPACE
150 /* Any thread running In user mode will have full access to the region denoted
151  * by thread.stack_info.
152  *
153  * Thread-local storage is at the very highest memory locations of this area.
154  * Memory for TLS and any initial random stack pointer offset is captured
155  * in thread.stack_info.delta.
156  */
157 #ifdef CONFIG_MPU_STACK_GUARD
158 /* MPU guards are only supported with V3 MPU and later. In this configuration
159  * the stack object will contain the MPU guard, the privilege stack, and then
160  * the stack buffer in that order:
161  *
162  * +------------+ <- thread.stack_obj
163  * | Guard      | } Z_ARC_STACK_GUARD_SIZE
164  * +------------+ <- thread.arch.priv_stack_start
165  * | Priv Stack | } CONFIG_PRIVILEGED_STACK_SIZE
166  * +------------+ <- thread.stack_info.start
167  * | Thread     |
168  * | stack      |
169  * |            |
170  * +............|
171  * | TLS        | } thread.stack_info.delta
172  * +------------+ <- thread.stack_info.start + thread.stack_info.size
173  */
174 #define ARCH_THREAD_STACK_RESERVED	(Z_ARC_STACK_GUARD_SIZE + \
175 					 CONFIG_PRIVILEGED_STACK_SIZE)
176 #define ARCH_THREAD_STACK_OBJ_ALIGN(size)	Z_ARC_MPU_ALIGN
177 /* We need to be able to exactly cover the stack buffer with an MPU region,
178  * so round its size up to the required granularity of the MPU
179  */
180 #define ARCH_THREAD_STACK_SIZE_ADJUST(size) \
181 		(ROUND_UP((size), Z_ARC_MPU_ALIGN))
182 BUILD_ASSERT(CONFIG_PRIVILEGED_STACK_SIZE % Z_ARC_MPU_ALIGN == 0,
183 	     "improper privilege stack size");
184 #else /* !CONFIG_MPU_STACK_GUARD */
185 /* Userspace enabled, but supervisor stack guards are not in use */
186 #ifdef CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT
187 /* Use defaults for everything. The privilege elevation stack is located
188  * in another area of memory generated at build time by gen_kobject_list.py
189  *
190  * +------------+ <- thread.arch.priv_stack_start
191  * | Priv Stack | } Z_KERNEL_STACK_LEN(CONFIG_PRIVILEGED_STACK_SIZE)
192  * +------------+
193  *
194  * +------------+ <- thread.stack_obj = thread.stack_info.start
195  * | Thread     |
196  * | stack      |
197  * |            |
198  * +............|
199  * | TLS        | } thread.stack_info.delta
200  * +------------+ <- thread.stack_info.start + thread.stack_info.size
201  */
202 #define ARCH_THREAD_STACK_SIZE_ADJUST(size) \
203 		Z_POW2_CEIL(ROUND_UP((size), Z_ARC_MPU_ALIGN))
204 #define ARCH_THREAD_STACK_OBJ_ALIGN(size) \
205 		ARCH_THREAD_STACK_SIZE_ADJUST(size)
206 #define ARCH_THREAD_STACK_RESERVED		0
207 #else /* !CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT */
208 /* Reserved area of the thread object just contains the privilege stack:
209  *
210  * +------------+ <- thread.stack_obj = thread.arch.priv_stack_start
211  * | Priv Stack | } CONFIG_PRIVILEGED_STACK_SIZE
212  * +------------+ <- thread.stack_info.start
213  * | Thread     |
214  * | stack      |
215  * |            |
216  * +............|
217  * | TLS        | } thread.stack_info.delta
218  * +------------+ <- thread.stack_info.start + thread.stack_info.size
219  */
220 #define ARCH_THREAD_STACK_RESERVED		CONFIG_PRIVILEGED_STACK_SIZE
221 #define ARCH_THREAD_STACK_SIZE_ADJUST(size) \
222 		(ROUND_UP((size), Z_ARC_MPU_ALIGN))
223 #define ARCH_THREAD_STACK_OBJ_ALIGN(size)	Z_ARC_MPU_ALIGN
224 
225 BUILD_ASSERT(CONFIG_PRIVILEGED_STACK_SIZE % Z_ARC_MPU_ALIGN == 0,
226 	     "improper privilege stack size");
227 #endif /* CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT */
228 #endif /* CONFIG_MPU_STACK_GUARD */
229 
230 #else /* !CONFIG_USERSPACE */
231 
232 #ifdef CONFIG_MPU_STACK_GUARD
233 /* Only supported on ARC MPU V3 and higher. Reserve some memory for the stack
234  * guard. This is just a minimally-sized region at the beginning of the stack
235  * object, which is programmed to produce an exception if written to.
236  *
237  * +------------+ <- thread.stack_obj
238  * | Guard      | } Z_ARC_STACK_GUARD_SIZE
239  * +------------+ <- thread.stack_info.start
240  * | Thread     |
241  * | stack      |
242  * |            |
243  * +............|
244  * | TLS        | } thread.stack_info.delta
245  * +------------+ <- thread.stack_info.start + thread.stack_info.size
246  */
247 #define ARCH_THREAD_STACK_RESERVED		Z_ARC_STACK_GUARD_SIZE
248 #define ARCH_THREAD_STACK_OBJ_ALIGN(size)	Z_ARC_MPU_ALIGN
249 /* Default for ARCH_THREAD_STACK_SIZE_ADJUST */
250 #else /* !CONFIG_MPU_STACK_GUARD */
251 /* No stack guard, no userspace, Use defaults for everything. */
252 #endif /* CONFIG_MPU_STACK_GUARD */
253 #endif /* CONFIG_USERSPACE */
254 
255 #ifdef CONFIG_ARC_MPU
256 
257 /* Legacy case: retain containing extern "C" with C++ */
258 #include <zephyr/arch/arc/v2/mpu/arc_mpu.h>
259 
260 #define K_MEM_PARTITION_P_NA_U_NA	AUX_MPU_ATTR_N
261 #define K_MEM_PARTITION_P_RW_U_RW	(AUX_MPU_ATTR_UW | AUX_MPU_ATTR_UR | \
262 					 AUX_MPU_ATTR_KW | AUX_MPU_ATTR_KR)
263 #define K_MEM_PARTITION_P_RW_U_RO	(AUX_MPU_ATTR_UR | \
264 					 AUX_MPU_ATTR_KW | AUX_MPU_ATTR_KR)
265 #define K_MEM_PARTITION_P_RW_U_NA	(AUX_MPU_ATTR_KW | AUX_MPU_ATTR_KR)
266 #define K_MEM_PARTITION_P_RO_U_RO	(AUX_MPU_ATTR_UR | AUX_MPU_ATTR_KR)
267 #define K_MEM_PARTITION_P_RO_U_NA	(AUX_MPU_ATTR_KR)
268 
269 /* Execution-allowed attributes */
270 #define K_MEM_PARTITION_P_RWX_U_RWX	(AUX_MPU_ATTR_UW | AUX_MPU_ATTR_UR | \
271 					 AUX_MPU_ATTR_KW | AUX_MPU_ATTR_KR | \
272 					 AUX_MPU_ATTR_KE | AUX_MPU_ATTR_UE)
273 #define K_MEM_PARTITION_P_RWX_U_RX	(AUX_MPU_ATTR_UR | \
274 					 AUX_MPU_ATTR_KW | AUX_MPU_ATTR_KR | \
275 					 AUX_MPU_ATTR_KE | AUX_MPU_ATTR_UE)
276 #define K_MEM_PARTITION_P_RX_U_RX	(AUX_MPU_ATTR_UR | \
277 					 AUX_MPU_ATTR_KR | \
278 					 AUX_MPU_ATTR_KE | AUX_MPU_ATTR_UE)
279 
280 #define K_MEM_PARTITION_IS_WRITABLE(attr) \
281 	({ \
282 		int __is_writable__; \
283 		switch (attr & (AUX_MPU_ATTR_UW | AUX_MPU_ATTR_KW)) { \
284 		case (AUX_MPU_ATTR_UW | AUX_MPU_ATTR_KW): \
285 		case AUX_MPU_ATTR_UW: \
286 		case AUX_MPU_ATTR_KW: \
287 			__is_writable__ = 1; \
288 			break; \
289 		default: \
290 			__is_writable__ = 0; \
291 			break; \
292 		} \
293 		__is_writable__; \
294 	})
295 #define K_MEM_PARTITION_IS_EXECUTABLE(attr) \
296 	((attr) & (AUX_MPU_ATTR_KE | AUX_MPU_ATTR_UE))
297 
298 /*
299  * BUILD_ASSERT in case of MWDT is a bit more picky in performing compile-time check.
300  * For example it can't evaluate variable address at build time like GCC toolchain can do.
301  * That's why we provide custom _ARCH_MEM_PARTITION_ALIGN_CHECK implementation for MWDT toolchain
302  * with additional check for arguments availability in compile time.
303  */
304 #ifdef __CCAC__
305 #define IS_BUILTIN_MWDT(val) __builtin_constant_p((uintptr_t)(val))
306 #if CONFIG_ARC_MPU_VER == 2 || CONFIG_ARC_MPU_VER == 3 || CONFIG_ARC_MPU_VER == 6
307 #define _ARCH_MEM_PARTITION_ALIGN_CHECK(start, size)						\
308 	BUILD_ASSERT(IS_BUILTIN_MWDT(size) ? !((size) & ((size) - 1)) : 1,			\
309 		"partition size must be power of 2");						\
310 	BUILD_ASSERT(IS_BUILTIN_MWDT(size) ? (size) >= Z_ARC_MPU_ALIGN : 1,			\
311 		"partition size must be >= mpu address alignment.");				\
312 	BUILD_ASSERT(IS_BUILTIN_MWDT(size) ? IS_BUILTIN_MWDT(start) ?				\
313 		!((uintptr_t)(start) & ((size) - 1)) : 1 : 1,					\
314 		"partition start address must align with size.")
315 #elif CONFIG_ARC_MPU_VER == 4 || CONFIG_ARC_MPU_VER == 8
316 #define _ARCH_MEM_PARTITION_ALIGN_CHECK(start, size)						\
317 	BUILD_ASSERT(IS_BUILTIN_MWDT(size) ? (size) % Z_ARC_MPU_ALIGN == 0 : 1,			\
318 		"partition size must align with " STRINGIFY(Z_ARC_MPU_ALIGN));			\
319 	BUILD_ASSERT(IS_BUILTIN_MWDT(size) ? (size) >= Z_ARC_MPU_ALIGN : 1,			\
320 		"partition size must be >= " STRINGIFY(Z_ARC_MPU_ALIGN));			\
321 	BUILD_ASSERT(IS_BUILTIN_MWDT(start) ? (uintptr_t)(start) % Z_ARC_MPU_ALIGN == 0 : 1,	\
322 		"partition start address must align with " STRINGIFY(Z_ARC_MPU_ALIGN))
323 #endif
324 #else /* __CCAC__ */
325 #if CONFIG_ARC_MPU_VER == 2 || CONFIG_ARC_MPU_VER == 3 || CONFIG_ARC_MPU_VER == 6
326 #define _ARCH_MEM_PARTITION_ALIGN_CHECK(start, size)						\
327 	BUILD_ASSERT(!((size) & ((size) - 1)),							\
328 		"partition size must be power of 2");						\
329 	BUILD_ASSERT((size) >= Z_ARC_MPU_ALIGN,							\
330 		"partition size must be >= mpu address alignment.");				\
331 	BUILD_ASSERT(!((uintptr_t)(start) & ((size) - 1)),					\
332 		"partition start address must align with size.")
333 #elif CONFIG_ARC_MPU_VER == 4 || CONFIG_ARC_MPU_VER == 8
334 #define _ARCH_MEM_PARTITION_ALIGN_CHECK(start, size)						\
335 	BUILD_ASSERT((size) % Z_ARC_MPU_ALIGN == 0,						\
336 		"partition size must align with " STRINGIFY(Z_ARC_MPU_ALIGN));			\
337 	BUILD_ASSERT((size) >= Z_ARC_MPU_ALIGN,							\
338 		"partition size must be >= " STRINGIFY(Z_ARC_MPU_ALIGN));			\
339 	BUILD_ASSERT((uintptr_t)(start) % Z_ARC_MPU_ALIGN == 0,					\
340 		"partition start address must align with " STRINGIFY(Z_ARC_MPU_ALIGN))
341 #endif
342 #endif /* __CCAC__ */
343 #endif /* CONFIG_ARC_MPU*/
344 
345 /* Typedef for the k_mem_partition attribute*/
346 typedef uint32_t k_mem_partition_attr_t;
347 
arch_nop(void)348 static ALWAYS_INLINE void arch_nop(void)
349 {
350 	__builtin_arc_nop();
351 }
352 
353 #ifndef CONFIG_XIP
354 extern char __arc_rw_sram_size[];
355 #endif /* CONFIG_XIP */
356 
357 #endif /* _ASMLANGUAGE */
358 
359 #ifdef __cplusplus
360 }
361 #endif
362 #endif /* ZEPHYR_INCLUDE_ARCH_ARC_ARCH_H_ */
363