1 /* cpu.h,v 1.45.4.7 2008/01/28 18:20:39 matt Exp */ 2 3 /* 4 * Copyright (c) 1994-1996 Mark Brinicombe. 5 * Copyright (c) 1994 Brini. 6 * All rights reserved. 7 * 8 * This code is derived from software written for Brini by Mark Brinicombe 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by Brini. 21 * 4. The name of the company nor the name of the author may be used to 22 * endorse or promote products derived from this software without specific 23 * prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED 26 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28 * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * RiscBSD kernel project 38 * 39 * cpu.h 40 * 41 * CPU specific symbols 42 * 43 * Created : 18/09/94 44 * 45 * Based on kate/katelib/arm6.h 46 */ 47 48 #ifndef _ARM_CPU_H_ 49 #define _ARM_CPU_H_ 50 51 /* 52 * User-visible definitions 53 */ 54 55 /* CTL_MACHDEP definitions. */ 56 #define CPU_DEBUG 1 /* int: misc kernel debug control */ 57 #define CPU_BOOTED_DEVICE 2 /* string: device we booted from */ 58 #define CPU_BOOTED_KERNEL 3 /* string: kernel we booted */ 59 #define CPU_CONSDEV 4 /* struct: dev_t of our console */ 60 #define CPU_POWERSAVE 5 /* int: use CPU powersave mode */ 61 #define CPU_MAXID 6 /* number of valid machdep ids */ 62 63 #if defined(_KERNEL) || defined(_KMEMUSER) 64 65 /* 66 * Kernel-only definitions 67 */ 68 69 #if !defined(_LKM) && defined(_KERNEL_OPT) 70 #include "opt_multiprocessor.h" 71 #include "opt_cpuoptions.h" 72 #include "opt_lockdebug.h" 73 #include "opt_cputypes.h" 74 #endif /* !_LKM && _KERNEL_OPT */ 75 76 #include <arm/cpuconf.h> 77 78 #ifndef _LOCORE 79 #include <machine/frame.h> 80 #endif /* !_LOCORE */ 81 82 #include <arm/armreg.h> 83 84 85 #ifndef _LOCORE 86 /* 1 == use cpu_sleep(), 0 == don't */ 87 extern int cpu_do_powersave; 88 extern int cpu_fpu_present; 89 #endif 90 91 #ifdef _LOCORE 92 93 #if defined(_ARM_ARCH_6) 94 #define IRQdisable cpsid i 95 #define IRQenable cpsie i 96 #elif defined(__PROG32) 97 #define IRQdisable \ 98 stmfd sp!, {r0} ; \ 99 mrs r0, cpsr ; \ 100 orr r0, r0, #(I32_bit) ; \ 101 msr cpsr_c, r0 ; \ 102 ldmfd sp!, {r0} 103 104 #define IRQenable \ 105 stmfd sp!, {r0} ; \ 106 mrs r0, cpsr ; \ 107 bic r0, r0, #(I32_bit) ; \ 108 msr cpsr_c, r0 ; \ 109 ldmfd sp!, {r0} 110 #else 111 /* Not yet used in 26-bit code */ 112 #endif 113 114 #if defined (TPIDRPRW_IS_CURCPU) 115 #define GET_CURCPU(rX) mrc p15, 0, rX, c13, c0, 4 116 #define GET_CURLWP(rX) GET_CURCPU(rX); ldr rX, [rX, #CI_CURLWP] 117 #elif defined (TPIDRPRW_IS_CURLWP) 118 #define GET_CURLWP(rX) mrc p15, 0, rX, c13, c0, 4 119 #define GET_CURCPU(rX) GET_CURLWP(rX); ldr rX, [rX, #L_CPU] 120 #elif !defined(MULTIPROCESSOR) 121 #define GET_CURCPU(rX) ldr rX, =_C_LABEL(cpu_info_store) 122 #define GET_CURLWP(rX) GET_CURCPU(rX); ldr rX, [rX, #CI_CURLWP] 123 #endif 124 #define GET_CURPCB(rX) GET_CURLWP(rX); ldr rX, [rX, #L_PCB] 125 126 #else /* !_LOCORE */ 127 128 #ifdef __PROG32 129 #define IRQdisable __set_cpsr_c(I32_bit, I32_bit); 130 #define IRQenable __set_cpsr_c(I32_bit, 0); 131 #else 132 #define IRQdisable set_r15(R15_IRQ_DISABLE, R15_IRQ_DISABLE); 133 #define IRQenable set_r15(R15_IRQ_DISABLE, 0); 134 #endif 135 136 #endif /* !_LOCORE */ 137 138 #ifndef _LOCORE 139 140 /* All the CLKF_* macros take a struct clockframe * as an argument. */ 141 142 /* 143 * CLKF_USERMODE: Return TRUE/FALSE (1/0) depending on whether the 144 * frame came from USR mode or not. 145 */ 146 #ifdef __PROG32 147 #define CLKF_USERMODE(frame) ((frame->cf_tf.tf_spsr & PSR_MODE) == PSR_USR32_MODE) 148 #else 149 #define CLKF_USERMODE(frame) ((frame->cf_if.if_r15 & R15_MODE) == R15_MODE_USR) 150 #endif 151 152 /* 153 * CLKF_INTR: True if we took the interrupt from inside another 154 * interrupt handler. 155 */ 156 #ifdef __PROG32 157 /* Hack to treat FPE time as interrupt time so we can measure it */ 158 #define CLKF_INTR(frame) \ 159 ((curcpu()->ci_intr_depth > 1) || \ 160 (frame->cf_tf.tf_spsr & PSR_MODE) == PSR_UND32_MODE) 161 #else 162 #define CLKF_INTR(frame) (curcpu()->ci_intr_depth > 1) 163 #endif 164 165 /* 166 * CLKF_PC: Extract the program counter from a clockframe 167 */ 168 #ifdef __PROG32 169 #define CLKF_PC(frame) (frame->cf_tf.tf_pc) 170 #else 171 #define CLKF_PC(frame) (frame->cf_if.if_r15 & R15_PC) 172 #endif 173 174 /* 175 * LWP_PC: Find out the program counter for the given lwp. 176 */ 177 #ifdef __PROG32 178 #define LWP_PC(l) (lwp_trapframe(l)->tf_pc) 179 #else 180 #define LWP_PC(l) (lwp_trapframe(l)->tf_r15 & R15_PC) 181 #endif 182 183 /* 184 * Validate a PC or PSR for a user process. Used by various system calls 185 * that take a context passed by the user and restore it. 186 */ 187 188 #ifdef __PROG32 189 #define VALID_R15_PSR(r15,psr) \ 190 (((psr) & PSR_MODE) == PSR_USR32_MODE && \ 191 ((psr) & (I32_bit | F32_bit)) == 0) 192 #else 193 #define VALID_R15_PSR(r15,psr) \ 194 (((r15) & R15_MODE) == R15_MODE_USR && \ 195 ((r15) & (R15_IRQ_DISABLE | R15_FIQ_DISABLE)) == 0) 196 #endif 197 198 199 200 /* The address of the vector page. */ 201 extern vaddr_t vector_page; 202 #ifdef __PROG32 203 void arm32_vector_init(vaddr_t, int); 204 205 #define ARM_VEC_RESET (1 << 0) 206 #define ARM_VEC_UNDEFINED (1 << 1) 207 #define ARM_VEC_SWI (1 << 2) 208 #define ARM_VEC_PREFETCH_ABORT (1 << 3) 209 #define ARM_VEC_DATA_ABORT (1 << 4) 210 #define ARM_VEC_ADDRESS_EXCEPTION (1 << 5) 211 #define ARM_VEC_IRQ (1 << 6) 212 #define ARM_VEC_FIQ (1 << 7) 213 214 #define ARM_NVEC 8 215 #define ARM_VEC_ALL 0xffffffff 216 #endif 217 218 /* 219 * Per-CPU information. For now we assume one CPU. 220 */ 221 static inline int curcpl(void); 222 static inline void set_curcpl(int); 223 static inline void cpu_dosoftints(void); 224 225 #include <sys/device_if.h> 226 #include <sys/evcnt.h> 227 #include <sys/cpu_data.h> 228 229 struct cpu_info { 230 struct cpu_data ci_data; /* MI per-cpu data */ 231 device_t ci_dev; /* Device corresponding to this CPU */ 232 cpuid_t ci_cpuid; 233 uint32_t ci_arm_cpuid; /* aggregate CPU id */ 234 uint32_t ci_arm_cputype; /* CPU type */ 235 uint32_t ci_arm_cpurev; /* CPU revision */ 236 uint32_t ci_ctrl; /* The CPU control register */ 237 int ci_cpl; /* current processor level (spl) */ 238 int ci_astpending; /* */ 239 int ci_want_resched; /* resched() was called */ 240 int ci_intr_depth; /* */ 241 struct cpu_softc *ci_softc; /* platform softc */ 242 #ifdef __HAVE_FAST_SOFTINTS 243 lwp_t *ci_softlwps[SOFTINT_COUNT]; 244 volatile uint32_t ci_softints; 245 #endif 246 lwp_t *ci_curlwp; /* current lwp */ 247 struct evcnt ci_arm700bugcount; 248 int32_t ci_mtx_count; 249 int ci_mtx_oldspl; 250 register_t ci_undefsave[3]; 251 uint32_t ci_vfp_id; 252 #if defined(_ARM_ARCH_7) 253 uint64_t ci_lastintr; 254 #endif 255 struct evcnt ci_abt_evs[FAULT_TYPE_MASK+1]; 256 #if defined(MP_CPU_INFO_MEMBERS) 257 MP_CPU_INFO_MEMBERS 258 #endif 259 }; 260 261 extern struct cpu_info cpu_info_store; 262 #if defined(TPIDRPRW_IS_CURLWP) 263 static inline struct lwp * 264 _curlwp(void) 265 { 266 return (struct lwp *) armreg_tpidrprw_read(); 267 } 268 269 static inline void 270 _curlwp_set(struct lwp *l) 271 { 272 armreg_tpidrprw_write((uintptr_t)l); 273 } 274 275 #define curlwp (_curlwp()) 276 static inline struct cpu_info * 277 curcpu(void) 278 { 279 return curlwp->l_cpu; 280 } 281 #elif defined(TPIDRPRW_IS_CURCPU) 282 static inline struct cpu_info * 283 curcpu(void) 284 { 285 return (struct cpu_info *) armreg_tpidrprw_read(); 286 } 287 #elif !defined(MULTIPROCESSOR) 288 #define curcpu() (&cpu_info_store) 289 #else 290 #error MULTIPROCESSOR requires TPIDRPRW_IS_CURLWP or TPIDRPRW_IS_CURCPU 291 #endif /* !TPIDRPRW_IS_CURCPU && !TPIDRPRW_IS_CURLWP */ 292 293 #ifndef curlwp 294 #define curlwp (curcpu()->ci_curlwp) 295 #endif 296 297 #define CPU_INFO_ITERATOR int 298 #if defined(MULTIPROCESSOR) 299 extern struct cpu_info *cpu_info[]; 300 #define cpu_number() (curcpu()->ci_cpuid) 301 void cpu_boot_secondary_processors(void); 302 #define CPU_IS_PRIMARY(ci) ((ci)->ci_cpuid == 0) 303 #define CPU_INFO_FOREACH(cii, ci) \ 304 cii = 0, ci = cpu_info[0]; cii < ncpu && (ci = cpu_info[cii]) != NULL; cii++ 305 #else 306 #define cpu_number() 0 307 308 #define CPU_IS_PRIMARY(ci) true 309 #define CPU_INFO_FOREACH(cii, ci) \ 310 cii = 0, ci = curcpu(); ci != NULL; ci = NULL 311 #endif 312 313 #define LWP0_CPU_INFO (&cpu_info_store) 314 315 static inline int 316 curcpl(void) 317 { 318 return curcpu()->ci_cpl; 319 } 320 321 static inline void 322 set_curcpl(int pri) 323 { 324 curcpu()->ci_cpl = pri; 325 } 326 327 static inline void 328 cpu_dosoftints(void) 329 { 330 #ifdef __HAVE_FAST_SOFTINTS 331 void dosoftints(void); 332 #ifndef __HAVE_PIC_FAST_SOFTINTS 333 struct cpu_info * const ci = curcpu(); 334 if (ci->ci_intr_depth == 0 && (ci->ci_softints >> ci->ci_cpl) > 0) 335 dosoftints(); 336 #endif 337 #endif 338 } 339 340 #ifdef __PROG32 341 void cpu_proc_fork(struct proc *, struct proc *); 342 #else 343 #define cpu_proc_fork(p1, p2) 344 #endif 345 346 /* 347 * Scheduling glue 348 */ 349 350 #define setsoftast() (curcpu()->ci_astpending = 1) 351 352 /* 353 * Notify the current process (p) that it has a signal pending, 354 * process as soon as possible. 355 */ 356 357 #define cpu_signotify(l) setsoftast() 358 359 /* 360 * Give a profiling tick to the current process when the user profiling 361 * buffer pages are invalid. On the i386, request an ast to send us 362 * through trap(), marking the proc as needing a profiling tick. 363 */ 364 #define cpu_need_proftick(l) ((l)->l_pflag |= LP_OWEUPC, setsoftast()) 365 366 /* 367 * We've already preallocated the stack for the idlelwps for additional CPUs. 368 * This hook allows to return them. 369 */ 370 vaddr_t cpu_uarea_alloc_idlelwp(struct cpu_info *); 371 372 #ifndef acorn26 373 /* 374 * cpu device glue (belongs in cpuvar.h) 375 */ 376 void cpu_attach(device_t, cpuid_t); 377 #endif 378 379 /* 380 * Random cruft 381 */ 382 383 struct lwp; 384 385 /* locore.S */ 386 void atomic_set_bit(u_int *, u_int); 387 void atomic_clear_bit(u_int *, u_int); 388 389 /* cpuswitch.S */ 390 struct pcb; 391 void savectx(struct pcb *); 392 393 /* ast.c */ 394 void userret(register struct lwp *); 395 396 /* *_machdep.c */ 397 void bootsync(void); 398 399 /* fault.c */ 400 int badaddr_read(void *, size_t, void *); 401 402 /* syscall.c */ 403 void swi_handler(trapframe_t *); 404 405 /* arm_machdep.c */ 406 void ucas_ras_check(trapframe_t *); 407 408 /* vfp_init.c */ 409 void vfp_attach(void); 410 void vfp_discardcontext(void); 411 void vfp_savecontext(void); 412 void vfp_kernel_acquire(void); 413 void vfp_kernel_release(void); 414 extern const pcu_ops_t arm_vfp_ops; 415 416 #endif /* !_LOCORE */ 417 418 #endif /* _KERNEL */ 419 420 #endif /* !_ARM_CPU_H_ */ 421