1 /* $OpenBSD: cpu.h,v 1.50 2024/07/24 21:24:18 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2016 Dale Rahn <drahn@dalerahn.com> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #ifndef _MACHINE_CPU_H_ 19 #define _MACHINE_CPU_H_ 20 21 /* 22 * User-visible definitions 23 */ 24 25 /* 26 * CTL_MACHDEP definitions. 27 */ 28 #define CPU_COMPATIBLE 1 /* compatible property */ 29 #define CPU_ID_AA64ISAR0 2 30 #define CPU_ID_AA64ISAR1 3 31 #define CPU_ID_AA64ISAR2 4 32 #define CPU_ID_AA64MMFR0 5 33 #define CPU_ID_AA64MMFR1 6 34 #define CPU_ID_AA64MMFR2 7 35 #define CPU_ID_AA64PFR0 8 36 #define CPU_ID_AA64PFR1 9 37 #define CPU_ID_AA64SMFR0 10 38 #define CPU_ID_AA64ZFR0 11 39 #define CPU_LIDACTION 12 40 #define CPU_MAXID 13 /* number of valid machdep ids */ 41 42 #define CTL_MACHDEP_NAMES { \ 43 { 0, 0 }, \ 44 { "compatible", CTLTYPE_STRING }, \ 45 { "id_aa64isar0", CTLTYPE_QUAD }, \ 46 { "id_aa64isar1", CTLTYPE_QUAD }, \ 47 { "id_aa64isar2", CTLTYPE_QUAD }, \ 48 { "id_aa64mmfr0", CTLTYPE_QUAD }, \ 49 { "id_aa64mmfr1", CTLTYPE_QUAD }, \ 50 { "id_aa64mmfr2", CTLTYPE_QUAD }, \ 51 { "id_aa64pfr0", CTLTYPE_QUAD }, \ 52 { "id_aa64pfr1", CTLTYPE_QUAD }, \ 53 { "id_aa64smfr0", CTLTYPE_QUAD }, \ 54 { "id_aa64zfr0", CTLTYPE_QUAD }, \ 55 { "lidaction", CTLTYPE_INT }, \ 56 } 57 58 #ifdef _KERNEL 59 60 /* 61 * Kernel-only definitions 62 */ 63 64 extern uint64_t cpu_id_aa64isar0; 65 extern uint64_t cpu_id_aa64isar1; 66 extern uint64_t cpu_id_aa64isar2; 67 extern uint64_t cpu_id_aa64mmfr0; 68 extern uint64_t cpu_id_aa64mmfr1; 69 extern uint64_t cpu_id_aa64mmfr2; 70 extern uint64_t cpu_id_aa64pfr0; 71 extern uint64_t cpu_id_aa64pfr1; 72 73 void cpu_identify_cleanup(void); 74 75 #include <machine/intr.h> 76 #include <machine/frame.h> 77 #include <machine/armreg.h> 78 79 /* All the CLKF_* macros take a struct clockframe * as an argument. */ 80 81 #define clockframe trapframe 82 /* 83 * CLKF_USERMODE: Return TRUE/FALSE (1/0) depending on whether the 84 * frame came from USR mode or not. 85 */ 86 #define CLKF_USERMODE(frame) ((frame->tf_elr & (1ul << 63)) == 0) 87 88 /* 89 * CLKF_INTR: True if we took the interrupt from inside another 90 * interrupt handler. 91 */ 92 #define CLKF_INTR(frame) (curcpu()->ci_idepth > 1) 93 94 /* 95 * CLKF_PC: Extract the program counter from a clockframe 96 */ 97 #define CLKF_PC(frame) (frame->tf_elr) 98 99 /* 100 * PROC_PC: Find out the program counter for the given process. 101 */ 102 #define PROC_PC(p) ((p)->p_addr->u_pcb.pcb_tf->tf_elr) 103 #define PROC_STACK(p) ((p)->p_addr->u_pcb.pcb_tf->tf_sp) 104 105 /* 106 * Per-CPU information. For now we assume one CPU. 107 */ 108 109 #include <sys/clockintr.h> 110 #include <sys/device.h> 111 #include <sys/sched.h> 112 #include <sys/srp.h> 113 #include <uvm/uvm_percpu.h> 114 115 struct cpu_info { 116 struct device *ci_dev; /* Device corresponding to this CPU */ 117 struct cpu_info *ci_next; 118 struct schedstate_percpu ci_schedstate; /* scheduler state */ 119 120 u_int32_t ci_cpuid; 121 uint64_t ci_mpidr; 122 uint64_t ci_midr; 123 u_int ci_acpi_proc_id; 124 int ci_node; 125 struct cpu_info *ci_self; 126 127 #define __HAVE_CPU_TOPOLOGY 128 u_int32_t ci_smt_id; 129 u_int32_t ci_core_id; 130 u_int32_t ci_pkg_id; 131 132 struct proc *ci_curproc; 133 struct pcb *ci_curpcb; 134 struct pmap *ci_curpm; 135 u_int32_t ci_randseed; 136 137 u_int32_t ci_ctrl; /* The CPU control register */ 138 139 u_int64_t ci_trampoline_vectors; 140 141 uint32_t ci_cpl; 142 uint32_t ci_ipending; 143 uint32_t ci_idepth; 144 #ifdef DIAGNOSTIC 145 int ci_mutex_level; 146 #endif 147 int ci_want_resched; 148 149 void (*ci_flush_bp)(void); 150 void (*ci_serror)(void); 151 152 uint64_t ci_ttbr1; 153 vaddr_t ci_el1_stkend; 154 155 uint32_t ci_psci_idle_latency; 156 uint32_t ci_psci_idle_param; 157 uint32_t ci_psci_suspend_param; 158 159 struct opp_table *ci_opp_table; 160 volatile int ci_opp_idx; 161 volatile int ci_opp_max; 162 uint32_t ci_cpu_supply; 163 164 u_long ci_prev_sleep; 165 u_long ci_last_itime; 166 167 #ifdef MULTIPROCESSOR 168 struct srp_hazard ci_srp_hazards[SRP_HAZARD_NUM]; 169 #define __HAVE_UVM_PERCPU 170 struct uvm_pmr_cache ci_uvm; 171 volatile int ci_flags; 172 173 volatile int ci_ddb_paused; 174 #define CI_DDB_RUNNING 0 175 #define CI_DDB_SHOULDSTOP 1 176 #define CI_DDB_STOPPED 2 177 #define CI_DDB_ENTERDDB 3 178 #define CI_DDB_INDDB 4 179 180 #endif 181 182 #ifdef GPROF 183 struct gmonparam *ci_gmon; 184 struct clockintr ci_gmonclock; 185 #endif 186 struct clockqueue ci_queue; 187 char ci_panicbuf[512]; 188 }; 189 190 #define CPUF_PRIMARY (1<<0) 191 #define CPUF_AP (1<<1) 192 #define CPUF_IDENTIFY (1<<2) 193 #define CPUF_IDENTIFIED (1<<3) 194 #define CPUF_PRESENT (1<<4) 195 #define CPUF_GO (1<<5) 196 #define CPUF_RUNNING (1<<6) 197 198 static inline struct cpu_info * 199 curcpu(void) 200 { 201 struct cpu_info *__ci = NULL; 202 __asm volatile("mrs %0, tpidr_el1" : "=r" (__ci)); 203 return (__ci); 204 } 205 206 extern struct cpu_info cpu_info_primary; 207 extern struct cpu_info *cpu_info_list; 208 209 #ifndef MULTIPROCESSOR 210 #define cpu_number() 0 211 #define CPU_IS_PRIMARY(ci) 1 212 #define CPU_IS_RUNNING(ci) 1 213 #define CPU_INFO_ITERATOR int 214 #define CPU_INFO_FOREACH(cii, ci) \ 215 for (cii = 0, ci = curcpu(); ci != NULL; ci = NULL) 216 #define CPU_INFO_UNIT(ci) 0 217 #define MAXCPUS 1 218 #define cpu_unidle(ci) 219 #else 220 #define cpu_number() (curcpu()->ci_cpuid) 221 #define CPU_IS_PRIMARY(ci) ((ci) == &cpu_info_primary) 222 #define CPU_IS_RUNNING(ci) ((ci)->ci_flags & CPUF_RUNNING) 223 #define CPU_INFO_ITERATOR int 224 #define CPU_INFO_FOREACH(cii, ci) for (cii = 0, ci = cpu_info_list; \ 225 ci != NULL; ci = ci->ci_next) 226 #define CPU_INFO_UNIT(ci) ((ci)->ci_dev ? (ci)->ci_dev->dv_unit : 0) 227 #define MAXCPUS 256 228 229 extern struct cpu_info *cpu_info[MAXCPUS]; 230 231 void cpu_boot_secondary_processors(void); 232 #endif /* !MULTIPROCESSOR */ 233 234 #define CPU_BUSY_CYCLE() __asm volatile("yield" : : : "memory") 235 236 #define curpcb curcpu()->ci_curpcb 237 238 static inline unsigned int 239 cpu_rnd_messybits(void) 240 { 241 uint64_t val, rval; 242 243 __asm volatile("mrs %0, CNTVCT_EL0; rbit %1, %0;" 244 : "=r" (val), "=r" (rval)); 245 246 return (val ^ rval); 247 } 248 249 /* 250 * Scheduling glue 251 */ 252 #define aston(p) ((p)->p_md.md_astpending = 1) 253 #define setsoftast() aston(curcpu()->ci_curproc) 254 255 /* 256 * Notify the current process (p) that it has a signal pending, 257 * process as soon as possible. 258 */ 259 260 #ifdef MULTIPROCESSOR 261 void cpu_unidle(struct cpu_info *ci); 262 #define signotify(p) (aston(p), cpu_unidle((p)->p_cpu)) 263 void cpu_kick(struct cpu_info *); 264 #else 265 #define cpu_kick(ci) 266 #define cpu_unidle(ci) 267 #define signotify(p) setsoftast() 268 #endif 269 270 /* 271 * Preempt the current process if in interrupt from user mode, 272 * or after the current trap/syscall if in system mode. 273 */ 274 void need_resched(struct cpu_info *); 275 #define clear_resched(ci) ((ci)->ci_want_resched = 0) 276 277 /* 278 * Give a profiling tick to the current process when the user profiling 279 * buffer pages are invalid. On the i386, request an ast to send us 280 * through trap(), marking the proc as needing a profiling tick. 281 */ 282 #define need_proftick(p) aston(p) 283 284 // asm code to start new kernel contexts. 285 void proc_trampoline(void); 286 287 /* 288 * Random cruft 289 */ 290 void dumpconf(void); 291 292 // syscall.c 293 void svc_handler (trapframe_t *); 294 295 // functions to manipulate interrupt state 296 static __inline void 297 restore_daif(uint32_t daif) 298 { 299 __asm volatile ("msr daif, %x0":: "r"(daif)); 300 } 301 302 static __inline void 303 enable_irq_daif(void) 304 { 305 __asm volatile ("msr daifclr, #3"); 306 } 307 308 static __inline void 309 disable_irq_daif(void) 310 { 311 __asm volatile ("msr daifset, #3"); 312 } 313 314 static __inline uint32_t 315 disable_irq_daif_ret(void) 316 { 317 uint32_t daif; 318 __asm volatile ("mrs %x0, daif": "=r"(daif)); 319 __asm volatile ("msr daifset, #3"); 320 return daif; 321 } 322 323 static inline void 324 intr_enable(void) 325 { 326 enable_irq_daif(); 327 } 328 329 static inline u_long 330 intr_disable(void) 331 { 332 return disable_irq_daif_ret(); 333 } 334 335 static inline void 336 intr_restore(u_long daif) 337 { 338 restore_daif(daif); 339 } 340 341 void cpu_halt(void); 342 int cpu_suspend_primary(void); 343 void cpu_resume_secondary(struct cpu_info *); 344 345 extern void (*cpu_idle_cycle_fcn)(void); 346 extern void (*cpu_suspend_cycle_fcn)(void); 347 348 void cpu_wfi(void); 349 350 void delay (unsigned); 351 #define DELAY(x) delay(x) 352 353 #endif /* _KERNEL */ 354 355 #ifdef MULTIPROCESSOR 356 #include <sys/mplock.h> 357 #endif /* MULTIPROCESSOR */ 358 359 #endif /* !_MACHINE_CPU_H_ */ 360