1 /* cpufunc.h,v 1.40.22.4 2007/11/08 10:59:33 matt Exp */
2
3 /*
4 * Copyright (c) 1997 Mark Brinicombe.
5 * Copyright (c) 1997 Causality Limited
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Causality Limited.
19 * 4. The name of Causality Limited may not be used to endorse or promote
20 * products derived from this software without specific prior written
21 * permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY CAUSALITY LIMITED ``AS IS'' AND ANY EXPRESS
24 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL CAUSALITY LIMITED BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * RiscBSD kernel project
36 *
37 * cpufunc.h
38 *
39 * Prototypes for cpu, mmu and tlb related functions.
40 */
41
42 #ifndef _ARM_CPUFUNC_H_
43 #define _ARM_CPUFUNC_H_
44
45 #ifdef _ARM_ARCH_7
46 /*
47 * Options for DMB and DSB:
48 * oshld Outer Shareable, load
49 * oshst Outer Shareable, store
50 * osh Outer Shareable, all
51 * nshld Non-shareable, load
52 * nshst Non-shareable, store
53 * nsh Non-shareable, all
54 * ishld Inner Shareable, load
55 * ishst Inner Shareable, store
56 * ish Inner Shareable, all
57 * ld Full system, load
58 * st Full system, store
59 * sy Full system, all
60 */
61 #define dsb(opt) __asm __volatile("dsb " __STRING(opt) : : : "memory")
62 #define dmb(opt) __asm __volatile("dmb " __STRING(opt) : : : "memory")
63 #define isb() __asm __volatile("isb" : : : "memory")
64 #define sev() __asm __volatile("sev" : : : "memory")
65
66 #else
67
68 #define dsb(opt) \
69 __asm __volatile("mcr p15, 0, %0, c7, c10, 4" :: "r" (0) : "memory")
70 #define dmb(opt) \
71 __asm __volatile("mcr p15, 0, %0, c7, c10, 5" :: "r" (0) : "memory")
72 #define isb() \
73 __asm __volatile("mcr p15, 0, %0, c7, c5, 4" :: "r" (0) : "memory")
74 #define sev() __nothing
75
76 #endif
77
78 #ifdef __arm__
79
80 #ifdef _KERNEL
81
82 #include <sys/types.h>
83
84 #include <arm/armreg.h>
85 #include <arm/cpuconf.h>
86 #include <arm/cpufunc_proto.h>
87
88 struct cpu_functions {
89
90 /* CPU functions */
91
92 u_int (*cf_id) (void);
93 void (*cf_cpwait) (void);
94
95 /* MMU functions */
96
97 u_int (*cf_control) (u_int, u_int);
98 void (*cf_domains) (u_int);
99 #if defined(ARM_MMU_EXTENDED)
100 void (*cf_setttb) (u_int, tlb_asid_t);
101 #else
102 void (*cf_setttb) (u_int, bool);
103 #endif
104 u_int (*cf_faultstatus) (void);
105 u_int (*cf_faultaddress) (void);
106
107 /* TLB functions */
108
109 void (*cf_tlb_flushID) (void);
110 void (*cf_tlb_flushID_SE) (vaddr_t);
111 void (*cf_tlb_flushI) (void);
112 void (*cf_tlb_flushI_SE) (vaddr_t);
113 void (*cf_tlb_flushD) (void);
114 void (*cf_tlb_flushD_SE) (vaddr_t);
115
116 /*
117 * Cache operations:
118 *
119 * We define the following primitives:
120 *
121 * icache_sync_all Synchronize I-cache
122 * icache_sync_range Synchronize I-cache range
123 *
124 * dcache_wbinv_all Write-back and Invalidate D-cache
125 * dcache_wbinv_range Write-back and Invalidate D-cache range
126 * dcache_inv_range Invalidate D-cache range
127 * dcache_wb_range Write-back D-cache range
128 *
129 * idcache_wbinv_all Write-back and Invalidate D-cache,
130 * Invalidate I-cache
131 * idcache_wbinv_range Write-back and Invalidate D-cache,
132 * Invalidate I-cache range
133 *
134 * Note that the ARM term for "write-back" is "clean". We use
135 * the term "write-back" since it's a more common way to describe
136 * the operation.
137 *
138 * There are some rules that must be followed:
139 *
140 * I-cache Synch (all or range):
141 * The goal is to synchronize the instruction stream,
142 * so you may beed to write-back dirty D-cache blocks
143 * first. If a range is requested, and you can't
144 * synchronize just a range, you have to hit the whole
145 * thing.
146 *
147 * D-cache Write-Back and Invalidate range:
148 * If you can't WB-Inv a range, you must WB-Inv the
149 * entire D-cache.
150 *
151 * D-cache Invalidate:
152 * If you can't Inv the D-cache, you must Write-Back
153 * and Invalidate. Code that uses this operation
154 * MUST NOT assume that the D-cache will not be written
155 * back to memory.
156 *
157 * D-cache Write-Back:
158 * If you can't Write-back without doing an Inv,
159 * that's fine. Then treat this as a WB-Inv.
160 * Skipping the invalidate is merely an optimization.
161 *
162 * All operations:
163 * Valid virtual addresses must be passed to each
164 * cache operation.
165 */
166 void (*cf_icache_sync_all) (void);
167 void (*cf_icache_sync_range) (vaddr_t, vsize_t);
168
169 void (*cf_dcache_wbinv_all) (void);
170 void (*cf_dcache_wbinv_range)(vaddr_t, vsize_t);
171 void (*cf_dcache_inv_range) (vaddr_t, vsize_t);
172 void (*cf_dcache_wb_range) (vaddr_t, vsize_t);
173
174 void (*cf_sdcache_wbinv_range)(vaddr_t, paddr_t, psize_t);
175 void (*cf_sdcache_inv_range) (vaddr_t, paddr_t, psize_t);
176 void (*cf_sdcache_wb_range) (vaddr_t, paddr_t, psize_t);
177
178 void (*cf_idcache_wbinv_all) (void);
179 void (*cf_idcache_wbinv_range)(vaddr_t, vsize_t);
180
181 /* Other functions */
182
183 void (*cf_flush_prefetchbuf) (void);
184 void (*cf_drain_writebuf) (void);
185 void (*cf_flush_brnchtgt_C) (void);
186 void (*cf_flush_brnchtgt_E) (u_int);
187
188 void (*cf_sleep) (int mode);
189
190 /* Soft functions */
191
192 int (*cf_dataabt_fixup) (void *);
193 int (*cf_prefetchabt_fixup) (void *);
194
195 #if defined(ARM_MMU_EXTENDED)
196 void (*cf_context_switch) (u_int, tlb_asid_t);
197 #else
198 void (*cf_context_switch) (u_int);
199 #endif
200
201 void (*cf_setup) (char *);
202 };
203
204 extern struct cpu_functions cpufuncs;
205 extern u_int cputype;
206
207 #define cpu_idnum() cpufuncs.cf_id()
208
209 #define cpu_control(c, e) cpufuncs.cf_control(c, e)
210 #define cpu_domains(d) cpufuncs.cf_domains(d)
211 #define cpu_setttb(t, f) cpufuncs.cf_setttb(t, f)
212 #define cpu_faultstatus() cpufuncs.cf_faultstatus()
213 #define cpu_faultaddress() cpufuncs.cf_faultaddress()
214
215 #define cpu_tlb_flushID() cpufuncs.cf_tlb_flushID()
216 #define cpu_tlb_flushID_SE(e) cpufuncs.cf_tlb_flushID_SE(e)
217 #define cpu_tlb_flushI() cpufuncs.cf_tlb_flushI()
218 #define cpu_tlb_flushI_SE(e) cpufuncs.cf_tlb_flushI_SE(e)
219 #define cpu_tlb_flushD() cpufuncs.cf_tlb_flushD()
220 #define cpu_tlb_flushD_SE(e) cpufuncs.cf_tlb_flushD_SE(e)
221
222 #define cpu_icache_sync_all() cpufuncs.cf_icache_sync_all()
223 #define cpu_icache_sync_range(a, s) cpufuncs.cf_icache_sync_range((a), (s))
224
225 #define cpu_dcache_wbinv_all() cpufuncs.cf_dcache_wbinv_all()
226 #define cpu_dcache_wbinv_range(a, s) cpufuncs.cf_dcache_wbinv_range((a), (s))
227 #define cpu_dcache_inv_range(a, s) cpufuncs.cf_dcache_inv_range((a), (s))
228 #define cpu_dcache_wb_range(a, s) cpufuncs.cf_dcache_wb_range((a), (s))
229
230 #define cpu_sdcache_wbinv_range(a, b, s) cpufuncs.cf_sdcache_wbinv_range((a), (b), (s))
231 #define cpu_sdcache_inv_range(a, b, s) cpufuncs.cf_sdcache_inv_range((a), (b), (s))
232 #define cpu_sdcache_wb_range(a, b, s) cpufuncs.cf_sdcache_wb_range((a), (b), (s))
233
234 #define cpu_idcache_wbinv_all() cpufuncs.cf_idcache_wbinv_all()
235 #define cpu_idcache_wbinv_range(a, s) cpufuncs.cf_idcache_wbinv_range((a), (s))
236
237 #define cpu_flush_prefetchbuf() cpufuncs.cf_flush_prefetchbuf()
238 #define cpu_drain_writebuf() cpufuncs.cf_drain_writebuf()
239 #define cpu_flush_brnchtgt_C() cpufuncs.cf_flush_brnchtgt_C()
240 #define cpu_flush_brnchtgt_E(e) cpufuncs.cf_flush_brnchtgt_E(e)
241
242 #define cpu_sleep(m) cpufuncs.cf_sleep(m)
243
244 #define cpu_dataabt_fixup(a) cpufuncs.cf_dataabt_fixup(a)
245 #define cpu_prefetchabt_fixup(a) cpufuncs.cf_prefetchabt_fixup(a)
246 #define ABORT_FIXUP_OK 0 /* fixup succeeded */
247 #define ABORT_FIXUP_FAILED 1 /* fixup failed */
248 #define ABORT_FIXUP_RETURN 2 /* abort handler should return */
249
250 #define cpu_context_switch(a) cpufuncs.cf_context_switch(a)
251 #define cpu_setup(a) cpufuncs.cf_setup(a)
252
253 int set_cpufuncs (void);
254 int set_cpufuncs_id (u_int);
255 #define ARCHITECTURE_NOT_PRESENT 1 /* known but not configured */
256 #define ARCHITECTURE_NOT_SUPPORTED 2 /* not known */
257
258 void cpufunc_nullop (void);
259 int cpufunc_null_fixup (void *);
260 int early_abort_fixup (void *);
261 int late_abort_fixup (void *);
262 u_int cpufunc_id (void);
263 u_int cpufunc_control (u_int, u_int);
264 void cpufunc_domains (u_int);
265 u_int cpufunc_faultstatus (void);
266 u_int cpufunc_faultaddress (void);
267
268 #if defined(CPU_XSCALE)
269 #define cpu_cpwait() cpufuncs.cf_cpwait()
270 #endif
271
272 #ifndef cpu_cpwait
273 #define cpu_cpwait()
274 #endif
275
276 /*
277 * Macros for manipulating CPU interrupts
278 */
279 static __inline uint32_t __set_cpsr_c(uint32_t bic, uint32_t eor) __attribute__((__unused__));
280 static __inline uint32_t disable_interrupts(uint32_t mask) __attribute__((__unused__));
281 static __inline uint32_t enable_interrupts(uint32_t mask) __attribute__((__unused__));
282
283 static __inline uint32_t
__set_cpsr_c(uint32_t bic,uint32_t eor)284 __set_cpsr_c(uint32_t bic, uint32_t eor)
285 {
286 uint32_t tmp, ret;
287
288 __asm volatile(
289 "mrs %0, cpsr\n" /* Get the CPSR */
290 "bic %1, %0, %2\n" /* Clear bits */
291 "eor %1, %1, %3\n" /* XOR bits */
292 "msr cpsr_c, %1\n" /* Set the control field of CPSR */
293 : "=&r" (ret), "=&r" (tmp)
294 : "r" (bic), "r" (eor) : "memory");
295
296 return ret;
297 }
298
299 static __inline uint32_t
disable_interrupts(uint32_t mask)300 disable_interrupts(uint32_t mask)
301 {
302 uint32_t tmp, ret;
303 mask &= (I32_bit | F32_bit);
304
305 __asm volatile(
306 "mrs %0, cpsr\n" /* Get the CPSR */
307 "orr %1, %0, %2\n" /* set bits */
308 "msr cpsr_c, %1\n" /* Set the control field of CPSR */
309 : "=&r" (ret), "=&r" (tmp)
310 : "r" (mask)
311 : "memory");
312
313 return ret;
314 }
315
316 static __inline uint32_t
enable_interrupts(uint32_t mask)317 enable_interrupts(uint32_t mask)
318 {
319 uint32_t ret;
320 mask &= (I32_bit | F32_bit);
321
322 /* Get the CPSR */
323 __asm __volatile("mrs\t%0, cpsr\n" : "=r"(ret));
324 #ifdef _ARM_ARCH_6
325 if (__builtin_constant_p(mask)) {
326 switch (mask) {
327 case I32_bit | F32_bit:
328 __asm __volatile("cpsie\tif");
329 break;
330 case I32_bit:
331 __asm __volatile("cpsie\ti");
332 break;
333 case F32_bit:
334 __asm __volatile("cpsie\tf");
335 break;
336 default:
337 break;
338 }
339 return ret;
340 }
341 #endif /* _ARM_ARCH_6 */
342
343 /* Set the control field of CPSR */
344 __asm volatile("msr\tcpsr_c, %0" :: "r"(ret & ~mask));
345
346 return ret;
347 }
348
349 #define restore_interrupts(old_cpsr) \
350 (__set_cpsr_c((I32_bit | F32_bit), (old_cpsr) & (I32_bit | F32_bit)))
351
352 #define ENABLE_INTERRUPT() cpsie(I32_bit)
353 #define DISABLE_INTERRUPT() cpsid(I32_bit)
354 #define DISABLE_INTERRUPT_SAVE() cpsid(I32_bit)
355
356 static inline void cpsie(register_t psw) __attribute__((__unused__));
357 static inline register_t cpsid(register_t psw) __attribute__((__unused__));
358
359 static inline void
cpsie(register_t psw)360 cpsie(register_t psw)
361 {
362 #ifdef _ARM_ARCH_6
363 if (!__builtin_constant_p(psw)) {
364 enable_interrupts(psw);
365 return;
366 }
367 switch (psw & (I32_bit|F32_bit)) {
368 case I32_bit: __asm("cpsie\ti"); break;
369 case F32_bit: __asm("cpsie\tf"); break;
370 case I32_bit|F32_bit: __asm("cpsie\tif"); break;
371 }
372 #else
373 enable_interrupts(psw);
374 #endif
375 }
376
377 static inline register_t
cpsid(register_t psw)378 cpsid(register_t psw)
379 {
380 #ifdef _ARM_ARCH_6
381 register_t oldpsw;
382 if (!__builtin_constant_p(psw))
383 return disable_interrupts(psw);
384
385 __asm("mrs %0, cpsr" : "=r"(oldpsw));
386 switch (psw & (I32_bit|F32_bit)) {
387 case I32_bit: __asm("cpsid\ti"); break;
388 case F32_bit: __asm("cpsid\tf"); break;
389 case I32_bit|F32_bit: __asm("cpsid\tif"); break;
390 }
391 return oldpsw;
392 #else
393 return disable_interrupts(psw);
394 #endif
395 }
396
397
398 /* Functions to manipulate the CPSR. */
399 u_int SetCPSR(u_int, u_int);
400 u_int GetCPSR(void);
401
402
403 /*
404 * CPU functions from locore.S
405 */
406
407 void cpu_reset (void) __dead;
408
409 #if (ARM_MMU_V6 + ARM_MMU_V7) != 0
410 extern u_int arm_cache_prefer_mask;
411 #endif
412 extern u_int arm_dcache_align;
413 extern u_int arm_dcache_align_mask;
414
415 extern struct arm_cache_info arm_pcache;
416 extern struct arm_cache_info arm_scache;
417
418 extern uint32_t cpu_ttb;
419
420 #endif /* _KERNEL */
421
422 #if defined(_KERNEL) || defined(_KMEMUSER)
423 /*
424 * Miscellany
425 */
426
427 int get_pc_str_offset (void);
428
429 bool cpu_gtmr_exists_p(void);
430 u_int cpu_clusterid(void);
431 bool cpu_earlydevice_va_p(void);
432
433 /*
434 * Functions to manipulate cpu r13
435 * (in arm/arm32/setstack.S)
436 */
437
438 void set_stackptr (u_int, u_int);
439 u_int get_stackptr (u_int);
440
441 #endif /* _KERNEL || _KMEMUSER */
442
443 #elif defined(__aarch64__)
444
445 #include <aarch64/cpufunc.h>
446
447 #endif /* __arm__/__aarch64__ */
448
449 #endif /* _ARM_CPUFUNC_H_ */
450
451 /* End of cpufunc.h */
452