Line data Source code
1 1 : /*
2 : * Copyright (c) 2016 Cadence Design Systems, Inc.
3 : * SPDX-License-Identifier: Apache-2.0
4 : */
5 :
6 : /**
7 : * @file
8 : * @brief Xtensa specific kernel interface header
9 : *
10 : * This header contains the Xtensa specific kernel interface. It is
11 : * included by the kernel interface architecture-abstraction header
12 : * (include/zephyr/arch/cpu.h).
13 : */
14 :
15 : #ifndef ZEPHYR_INCLUDE_ARCH_XTENSA_ARCH_H_
16 : #define ZEPHYR_INCLUDE_ARCH_XTENSA_ARCH_H_
17 :
18 : #include <zephyr/irq.h>
19 :
20 : #include <zephyr/devicetree.h>
21 : #if !defined(_ASMLANGUAGE) && !defined(__ASSEMBLER__)
22 : #include <zephyr/types.h>
23 : #include <zephyr/toolchain.h>
24 : #include <zephyr/arch/common/sys_bitops.h>
25 : #include <zephyr/arch/common/sys_io.h>
26 : #include <zephyr/arch/common/ffs.h>
27 : #include <zephyr/sw_isr_table.h>
28 : #include <zephyr/arch/xtensa/syscall.h>
29 : #include <zephyr/arch/xtensa/thread.h>
30 : #include <zephyr/arch/xtensa/irq.h>
31 : #include <xtensa/config/core.h>
32 : #include <zephyr/arch/common/addr_types.h>
33 : #include <zephyr/arch/xtensa/gdbstub.h>
34 : #include <zephyr/debug/sparse.h>
35 : #include <zephyr/arch/xtensa/thread_stack.h>
36 : #include <zephyr/sys/slist.h>
37 :
38 : #include <zephyr/drivers/timer/system_timer.h>
39 :
40 : #ifdef CONFIG_XTENSA_MMU
41 : #include <zephyr/arch/xtensa/xtensa_mmu.h>
42 : #endif
43 :
44 : #ifdef CONFIG_XTENSA_MPU
45 : #include <zephyr/arch/xtensa/mpu.h>
46 : #endif
47 :
48 : /**
49 : * @defgroup xtensa_apis Xtensa APIs
50 : * @ingroup arch-interface
51 : * @{
52 : * @}
53 : *
54 : * @defgroup xtensa_internal_apis Xtensa Internal APIs
55 : * @ingroup xtensa_apis
56 : * @{
57 : * @}
58 : */
59 :
60 : #include <zephyr/arch/exception.h>
61 :
62 : #ifdef __cplusplus
63 : extern "C" {
64 : #endif
65 :
66 : struct arch_mem_domain {
67 : #ifdef CONFIG_XTENSA_MMU
68 : uint32_t *ptables;
69 : uint8_t asid;
70 : bool dirty;
71 :
72 : /* Following are used to program registers when changing page tables. */
73 : uint32_t reg_asid;
74 : uint32_t reg_ptevaddr;
75 : uint32_t reg_ptepin_as;
76 : uint32_t reg_ptepin_at;
77 : uint32_t reg_vecpin_as;
78 : uint32_t reg_vecpin_at;
79 : #endif
80 : #ifdef CONFIG_XTENSA_MPU
81 : struct xtensa_mpu_map mpu_map;
82 : #endif
83 : sys_snode_t node;
84 : };
85 :
86 0 : typedef struct arch_mem_domain arch_mem_domain_t;
87 :
88 : /**
89 : * @brief Generate hardware exception.
90 : *
91 : * This generates hardware exception which is used by ARCH_EXCEPT().
92 : *
93 : * @param reason_p Reason for exception.
94 : */
95 1 : void xtensa_arch_except(int reason_p);
96 :
97 : /**
98 : * @brief Generate kernel oops.
99 : *
100 : * This generates kernel oops which is used by arch_syscall_oops().
101 : *
102 : * @param reason_p Reason for exception.
103 : * @param ssf Stack pointer.
104 : */
105 1 : void xtensa_arch_kernel_oops(int reason_p, void *ssf);
106 :
107 : #ifdef CONFIG_USERSPACE
108 :
109 0 : #define ARCH_EXCEPT(reason_p) do { \
110 : if (k_is_user_context()) { \
111 : arch_syscall_invoke1(reason_p, \
112 : K_SYSCALL_XTENSA_USER_FAULT); \
113 : } else { \
114 : xtensa_arch_except(reason_p); \
115 : } \
116 : CODE_UNREACHABLE; \
117 : } while (false)
118 :
119 : #else
120 :
121 : #define ARCH_EXCEPT(reason_p) do { \
122 : xtensa_arch_except(reason_p); \
123 : CODE_UNREACHABLE; \
124 : } while (false)
125 :
126 : #endif
127 :
128 0 : __syscall void xtensa_user_fault(unsigned int reason);
129 :
130 : #include <zephyr/syscalls/arch.h>
131 :
132 : /* internal routine documented in C file, needed by IRQ_CONNECT() macro */
133 : void z_irq_priority_set(uint32_t irq, uint32_t prio, uint32_t flags);
134 :
135 0 : #define ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \
136 : { \
137 : Z_ISR_DECLARE(irq_p, flags_p, isr_p, isr_param_p); \
138 : }
139 :
140 : /** Implementation of @ref arch_k_cycle_get_32. */
141 1 : static inline uint32_t arch_k_cycle_get_32(void)
142 : {
143 : return sys_clock_cycle_get_32();
144 : }
145 :
146 : /** Implementation of @ref arch_k_cycle_get_64. */
147 1 : static inline uint64_t arch_k_cycle_get_64(void)
148 : {
149 : return sys_clock_cycle_get_64();
150 : }
151 :
152 : /** Implementation of @ref arch_nop. */
153 1 : static ALWAYS_INLINE void arch_nop(void)
154 : {
155 : __asm__ volatile("nop");
156 : }
157 :
158 : /**
159 : * @brief Lock VECBASE if supported by hardware.
160 : *
161 : * The bit 0 of VECBASE acts as a lock bit on hardware supporting
162 : * this feature. When this bit is set, VECBASE cannot be changed
163 : * until it is cleared by hardware reset. When the hardware does not
164 : * support this bit, it is hardwired to 0.
165 : */
166 1 : static ALWAYS_INLINE void xtensa_vecbase_lock(void)
167 : {
168 : int vecbase;
169 :
170 : __asm__ volatile("rsr.vecbase %0" : "=r" (vecbase));
171 : __asm__ volatile("wsr.vecbase %0; rsync" : : "r" (vecbase | 1));
172 : }
173 :
174 : #if defined(CONFIG_XTENSA_RPO_CACHE) || defined(__DOXYGEN__)
175 : #if defined(CONFIG_ARCH_HAS_COHERENCE) || defined(__DOXYGEN__)
176 : /** Implementation of @ref arch_mem_coherent. */
177 1 : static inline bool arch_mem_coherent(void *ptr)
178 : {
179 : size_t addr = (size_t) ptr;
180 :
181 : return (addr >> 29) == CONFIG_XTENSA_UNCACHED_REGION;
182 : }
183 : #endif
184 :
185 :
186 : /* Utility to generate an unrolled and optimal[1] code sequence to set
187 : * the RPO TLB registers (contra the HAL cacheattr macros, which
188 : * generate larger code and can't be called from C), based on the
189 : * KERNEL_COHERENCE configuration in use. Selects RPO attribute "2"
190 : * for regions (including MMIO registers in region zero) which want to
191 : * bypass L1, "4" for the cached region which wants writeback, and
192 : * "15" (invalid) elsewhere.
193 : *
194 : * Note that on cores that have the "translation" option set, we need
195 : * to put an identity mapping in the high bits. Also per spec
196 : * changing the current code region (by definition cached) requires
197 : * that WITLB be followed by an ISYNC and that both instructions live
198 : * in the same cache line (two 3-byte instructions fit in an 8-byte
199 : * aligned region, so that's guaranteed not to cross a cache line
200 : * boundary).
201 : *
202 : * [1] With the sole exception of gcc's infuriating insistence on
203 : * emitting a precomputed literal for addr + addrincr instead of
204 : * computing it with a single ADD instruction from values it already
205 : * has in registers. Explicitly assigning the variables to registers
206 : * via an attribute works, but then emits needless MOV instructions
207 : * instead. I tell myself it's just 32 bytes of .text, but... Sigh.
208 : */
209 : #define _REGION_ATTR(r) \
210 : ((r) == 0 ? 2 : \
211 : ((r) == CONFIG_XTENSA_CACHED_REGION ? 4 : \
212 : ((r) == CONFIG_XTENSA_UNCACHED_REGION ? 2 : 15)))
213 :
214 : #define _SET_ONE_TLB(region) do { \
215 : uint32_t attr = _REGION_ATTR(region); \
216 : if (XCHAL_HAVE_XLT_CACHEATTR) { \
217 : attr |= addr; /* RPO with translation */ \
218 : } \
219 : if (region != CONFIG_XTENSA_CACHED_REGION) { \
220 : __asm__ volatile("wdtlb %0, %1; witlb %0, %1" \
221 : :: "r"(attr), "r"(addr)); \
222 : } else { \
223 : __asm__ volatile("wdtlb %0, %1" \
224 : :: "r"(attr), "r"(addr)); \
225 : __asm__ volatile("j 1f; .align 8; 1:"); \
226 : __asm__ volatile("witlb %0, %1; isync" \
227 : :: "r"(attr), "r"(addr)); \
228 : } \
229 : addr += addrincr; \
230 : } while (0)
231 :
232 : /**
233 : * @brief Setup RPO TLB registers.
234 : */
235 1 : #define ARCH_XTENSA_SET_RPO_TLB() \
236 : do { \
237 : register uint32_t addr = 0, addrincr = 0x20000000; \
238 : FOR_EACH(_SET_ONE_TLB, (;), 0, 1, 2, 3, 4, 5, 6, 7); \
239 : } while (0)
240 : #endif /* CONFIG_XTENSA_RPO_CACHE */
241 :
242 : #if defined(CONFIG_XTENSA_MMU) || defined(__DOXYGEN__)
243 : /**
244 : * @brief Perform additional steps after MMU initialization.
245 : *
246 : * This performs additional steps related to memory management
247 : * after the main MMU initialization code. This needs to defined
248 : * in the SoC layer. Default is do no nothing.
249 : *
250 : * @param is_core0 True if this is called while executing on
251 : * CPU core #0.
252 : */
253 1 : void arch_xtensa_mmu_post_init(bool is_core0);
254 : #endif
255 :
256 : #ifdef __cplusplus
257 : }
258 : #endif
259 :
260 : #endif /* !defined(_ASMLANGUAGE) && !defined(__ASSEMBLER__) */
261 :
262 : #endif /* ZEPHYR_INCLUDE_ARCH_XTENSA_ARCH_H_ */
|