1 /* $OpenBSD: cpu.h,v 1.10 2021/07/24 18:15:13 kettenis Exp $ */ 2 3 /* 4 * Copyright (c) 2019 Mike Larkin <mlarkin@openbsd.org> 5 * Copyright (c) 2016 Dale Rahn <drahn@dalerahn.com> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #ifndef _MACHINE_CPU_H_ 21 #define _MACHINE_CPU_H_ 22 23 /* 24 * User-visible definitions 25 */ 26 27 /* CTL_MACHDEP definitions. */ 28 #define CPU_COMPATIBLE 1 /* compatible property */ 29 #define CPU_MAXID 2 /* number of valid machdep ids */ 30 31 #define CTL_MACHDEP_NAMES { \ 32 { 0, 0 }, \ 33 { "compatible", CTLTYPE_STRING }, \ 34 } 35 36 #ifdef _KERNEL 37 38 /* 39 * Kernel-only definitions 40 */ 41 #include <machine/intr.h> 42 #include <machine/frame.h> 43 #include <machine/riscvreg.h> 44 45 /* All the CLKF_* macros take a struct clockframe * as an argument. */ 46 47 #define clockframe trapframe 48 /* 49 * CLKF_USERMODE: Return TRUE/FALSE (1/0) depending on whether the 50 * frame came from USR mode or not. 51 */ 52 #define CLKF_USERMODE(frame) ((frame->tf_sstatus & SSTATUS_SPP) == 0) 53 54 /* 55 * CLKF_INTR: True if we took the interrupt from inside another 56 * interrupt handler. 57 */ 58 #define CLKF_INTR(frame) (curcpu()->ci_idepth > 1) 59 60 /* 61 * CLKF_PC: Extract the program counter from a clockframe 62 */ 63 #define CLKF_PC(frame) (frame->tf_sepc) 64 65 /* 66 * PROC_PC: Find out the program counter for the given process. 67 */ 68 #define PROC_PC(p) ((p)->p_addr->u_pcb.pcb_tf->tf_sepc) 69 #define PROC_STACK(p) ((p)->p_addr->u_pcb.pcb_tf->tf_sp) 70 71 #include <sys/device.h> 72 #include <sys/sched.h> 73 #include <sys/srp.h> 74 75 struct cpu_info { 76 struct device *ci_dev; /* Device corresponding to this CPU */ 77 struct cpu_info *ci_next; 78 struct schedstate_percpu ci_schedstate; /* scheduler state */ 79 80 u_int32_t ci_cpuid; 81 uint64_t ci_hartid; 82 int ci_node; 83 struct cpu_info *ci_self; 84 85 struct proc *ci_curproc; 86 struct pmap *ci_curpm; 87 u_int32_t ci_randseed; 88 89 struct pcb *ci_curpcb; 90 struct pcb *ci_idle_pcb; 91 92 uint64_t ci_lasttb; 93 uint64_t ci_nexttimerevent; 94 uint64_t ci_nextstatevent; 95 int ci_statspending; 96 97 uint32_t ci_cpl; 98 uint32_t ci_ipending; 99 uint32_t ci_idepth; 100 #ifdef DIAGNOSTIC 101 int ci_mutex_level; 102 #endif 103 int ci_want_resched; 104 105 #ifdef MULTIPROCESSOR 106 struct srp_hazard ci_srp_hazards[SRP_HAZARD_NUM]; 107 volatile int ci_flags; 108 uint64_t ci_satp; 109 vaddr_t ci_initstack_end; 110 int ci_ipi_reason; 111 112 volatile int ci_ddb_paused; 113 #define CI_DDB_RUNNING 0 114 #define CI_DDB_SHOULDSTOP 1 115 #define CI_DDB_STOPPED 2 116 #define CI_DDB_ENTERDDB 3 117 #define CI_DDB_INDDB 4 118 119 #endif 120 121 #ifdef GPROF 122 struct gmonparam *ci_gmon; 123 #endif 124 125 char ci_panicbuf[512]; 126 }; 127 128 #define CPUF_PRIMARY (1<<0) 129 #define CPUF_AP (1<<1) 130 #define CPUF_IDENTIFY (1<<2) 131 #define CPUF_IDENTIFIED (1<<3) 132 #define CPUF_PRESENT (1<<4) 133 #define CPUF_GO (1<<5) 134 #define CPUF_RUNNING (1<<6) 135 136 static inline struct cpu_info * 137 curcpu(void) 138 { 139 struct cpu_info *__ci = NULL; 140 __asm __volatile("mv %0, tp" : "=&r"(__ci)); 141 return (__ci); 142 } 143 144 extern uint32_t boot_hart; /* The hart we booted on. */ 145 extern struct cpu_info cpu_info_primary; 146 extern struct cpu_info *cpu_info_list; 147 148 #ifndef MULTIPROCESSOR 149 150 #define cpu_number() 0 151 #define CPU_IS_PRIMARY(ci) 1 152 #define CPU_IS_RUNNING(ci) 1 153 #define CPU_INFO_ITERATOR int 154 #define CPU_INFO_FOREACH(cii, ci) \ 155 for (cii = 0, ci = curcpu(); ci != NULL; ci = NULL) 156 #define CPU_INFO_UNIT(ci) 0 157 #define MAXCPUS 1 158 #define cpu_unidle(ci) 159 160 #else 161 162 #define cpu_number() (curcpu()->ci_cpuid) 163 #define CPU_IS_PRIMARY(ci) ((ci) == &cpu_info_primary) 164 #define CPU_IS_RUNNING(ci) ((ci)->ci_flags & CPUF_RUNNING) 165 #define CPU_INFO_ITERATOR int 166 #define CPU_INFO_FOREACH(cii, ci) for (cii = 0, ci = cpu_info_list; \ 167 ci != NULL; ci = ci->ci_next) 168 #define CPU_INFO_UNIT(ci) ((ci)->ci_dev ? (ci)->ci_dev->dv_unit : 0) 169 #define MAXCPUS 32 170 171 extern struct cpu_info *cpu_info[MAXCPUS]; 172 173 void cpu_boot_secondary_processors(void); 174 void cpu_startclock(void); 175 176 #endif /* !MULTIPROCESSOR */ 177 178 #define CPU_BUSY_CYCLE() do {} while (0) 179 180 #define curpcb curcpu()->ci_curpcb 181 182 static inline unsigned int 183 cpu_rnd_messybits(void) 184 { 185 // Should do bit reversal ^ with csr_read(time); 186 return csr_read(time); 187 } 188 189 /* 190 * Scheduling glue 191 */ 192 #define aston(p) ((p)->p_md.md_astpending = 1) 193 #define setsoftast() aston(curcpu()->ci_curproc) 194 195 /* 196 * Notify the current process (p) that it has a signal pending, 197 * process as soon as possible. 198 */ 199 200 #ifdef MULTIPROCESSOR 201 void cpu_unidle(struct cpu_info *ci); 202 #define signotify(p) (aston(p), cpu_unidle((p)->p_cpu)) 203 void cpu_kick(struct cpu_info *); 204 #else 205 #define cpu_kick(ci) 206 #define cpu_unidle(ci) 207 #define signotify(p) setsoftast() 208 #endif 209 210 /* 211 * Preempt the current process if in interrupt from user mode, 212 * or after the current trap/syscall if in system mode. 213 */ 214 void need_resched(struct cpu_info *); 215 #define clear_resched(ci) ((ci)->ci_want_resched = 0) 216 217 /* 218 * Give a profiling tick to the current process when the user profiling 219 * buffer pages are invalid. On the i386, request an ast to send us 220 * through trap(), marking the proc as needing a profiling tick. 221 */ 222 #define need_proftick(p) aston(p) 223 224 // asm code to start new kernel contexts. 225 void proc_trampoline(void); 226 void child_trampoline(void); 227 228 /* 229 * Random cruft 230 */ 231 void dumpconf(void); 232 233 /* cpuswitch.S */ 234 struct pcb; 235 void savectx (struct pcb *pcb); 236 237 static inline void 238 intr_enable(void) 239 { 240 __asm __volatile("csrsi sstatus, %0" :: "i" (SSTATUS_SIE)); 241 } 242 243 static inline u_long 244 intr_disable(void) 245 { 246 uint64_t ret; 247 248 __asm __volatile( 249 "csrrci %0, sstatus, %1" 250 : "=&r" (ret) : "i" (SSTATUS_SIE) 251 ); 252 253 return (ret & (SSTATUS_SIE)); 254 } 255 256 static inline void 257 intr_restore(u_long s) 258 { 259 __asm __volatile("csrs sstatus, %0" :: "r" (s)); 260 } 261 262 void delay (unsigned); 263 #define DELAY(x) delay(x) 264 265 void fpu_save(struct proc *, struct trapframe *); 266 void fpu_load(struct proc *); 267 void fpu_discard(struct proc *p); 268 269 extern int cpu_errata_sifive_cip_1200; 270 271 #endif /* _KERNEL */ 272 273 #ifdef MULTIPROCESSOR 274 #include <sys/mplock.h> 275 #endif /* MULTIPROCESSOR */ 276 277 #endif /* !_MACHINE_CPU_H_ */ 278