1 /* $OpenBSD: cpu.h,v 1.24 2024/06/11 16:02:35 jca 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/clockintr.h>
72 #include <sys/device.h>
73 #include <sys/sched.h>
74 #include <sys/srp.h>
75 #include <uvm/uvm_percpu.h>
76
77 struct cpu_info {
78 struct device *ci_dev; /* Device corresponding to this CPU */
79 struct cpu_info *ci_next;
80 struct schedstate_percpu ci_schedstate; /* scheduler state */
81
82 u_int32_t ci_cpuid;
83 uint64_t ci_hartid;
84 int ci_node;
85 struct cpu_info *ci_self;
86
87 struct proc *ci_curproc;
88 struct pmap *ci_curpm;
89 u_int32_t ci_randseed;
90
91 struct pcb *ci_curpcb;
92 struct pcb *ci_idle_pcb;
93
94 struct clockqueue ci_queue;
95 volatile int ci_timer_deferred;
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 struct opp_table *ci_opp_table;
106 volatile int ci_opp_idx;
107 volatile int ci_opp_max;
108 uint32_t ci_cpu_supply;
109
110 #ifdef MULTIPROCESSOR
111 struct srp_hazard ci_srp_hazards[SRP_HAZARD_NUM];
112 #define __HAVE_UVM_PERCPU
113 struct uvm_pmr_cache ci_uvm;
114 volatile int ci_flags;
115 uint64_t ci_satp;
116 vaddr_t ci_initstack_end;
117 int ci_ipi_reason;
118
119 volatile int ci_ddb_paused;
120 #define CI_DDB_RUNNING 0
121 #define CI_DDB_SHOULDSTOP 1
122 #define CI_DDB_STOPPED 2
123 #define CI_DDB_ENTERDDB 3
124 #define CI_DDB_INDDB 4
125
126 #endif
127
128 #ifdef GPROF
129 struct gmonparam *ci_gmon;
130 struct clockintr ci_gmonclock;
131 #endif
132
133 char ci_panicbuf[512];
134 };
135
136 #define CPUF_PRIMARY (1<<0)
137 #define CPUF_AP (1<<1)
138 #define CPUF_IDENTIFY (1<<2)
139 #define CPUF_IDENTIFIED (1<<3)
140 #define CPUF_PRESENT (1<<4)
141 #define CPUF_GO (1<<5)
142 #define CPUF_RUNNING (1<<6)
143
144 static inline struct cpu_info *
curcpu(void)145 curcpu(void)
146 {
147 struct cpu_info *__ci = NULL;
148 __asm volatile("mv %0, tp" : "=&r"(__ci));
149 return (__ci);
150 }
151
152 extern uint32_t boot_hart; /* The hart we booted on. */
153 extern struct cpu_info cpu_info_primary;
154 extern struct cpu_info *cpu_info_list;
155
156 #ifndef MULTIPROCESSOR
157
158 #define cpu_number() 0
159 #define CPU_IS_PRIMARY(ci) 1
160 #define CPU_IS_RUNNING(ci) 1
161 #define CPU_INFO_ITERATOR int
162 #define CPU_INFO_FOREACH(cii, ci) \
163 for (cii = 0, ci = curcpu(); ci != NULL; ci = NULL)
164 #define CPU_INFO_UNIT(ci) 0
165 #define MAXCPUS 1
166 #define cpu_unidle(ci)
167
168 #else
169
170 #define cpu_number() (curcpu()->ci_cpuid)
171 #define CPU_IS_PRIMARY(ci) ((ci) == &cpu_info_primary)
172 #define CPU_IS_RUNNING(ci) ((ci)->ci_flags & CPUF_RUNNING)
173 #define CPU_INFO_ITERATOR int
174 #define CPU_INFO_FOREACH(cii, ci) for (cii = 0, ci = cpu_info_list; \
175 ci != NULL; ci = ci->ci_next)
176 #define CPU_INFO_UNIT(ci) ((ci)->ci_dev ? (ci)->ci_dev->dv_unit : 0)
177 #define MAXCPUS 32
178
179 extern struct cpu_info *cpu_info[MAXCPUS];
180
181 void cpu_boot_secondary_processors(void);
182
183 #endif /* !MULTIPROCESSOR */
184
185 /* Zihintpause ratified extension */
186 #define CPU_BUSY_CYCLE() __asm volatile(".long 0x0100000f" ::: "memory")
187
188 #define curpcb curcpu()->ci_curpcb
189
190 static inline unsigned int
cpu_rnd_messybits(void)191 cpu_rnd_messybits(void)
192 {
193 // Should do bit reversal ^ with csr_read(time);
194 return csr_read(time);
195 }
196
197 /*
198 * Scheduling glue
199 */
200 #define aston(p) ((p)->p_md.md_astpending = 1)
201 #define setsoftast() aston(curcpu()->ci_curproc)
202
203 /*
204 * Notify the current process (p) that it has a signal pending,
205 * process as soon as possible.
206 */
207
208 #ifdef MULTIPROCESSOR
209 void cpu_unidle(struct cpu_info *ci);
210 #define signotify(p) (aston(p), cpu_unidle((p)->p_cpu))
211 void cpu_kick(struct cpu_info *);
212 #else
213 #define cpu_kick(ci)
214 #define cpu_unidle(ci)
215 #define signotify(p) setsoftast()
216 #endif
217
218 /*
219 * Preempt the current process if in interrupt from user mode,
220 * or after the current trap/syscall if in system mode.
221 */
222 void need_resched(struct cpu_info *);
223 #define clear_resched(ci) ((ci)->ci_want_resched = 0)
224
225 /*
226 * Give a profiling tick to the current process when the user profiling
227 * buffer pages are invalid. On the i386, request an ast to send us
228 * through trap(), marking the proc as needing a profiling tick.
229 */
230 #define need_proftick(p) aston(p)
231
232 // asm code to start new kernel contexts.
233 void proc_trampoline(void);
234
235 /*
236 * Random cruft
237 */
238 void dumpconf(void);
239
240 static inline void
intr_enable(void)241 intr_enable(void)
242 {
243 __asm volatile("csrsi sstatus, %0" :: "i" (SSTATUS_SIE));
244 }
245
246 static inline u_long
intr_disable(void)247 intr_disable(void)
248 {
249 uint64_t ret;
250
251 __asm volatile(
252 "csrrci %0, sstatus, %1"
253 : "=&r" (ret) : "i" (SSTATUS_SIE)
254 );
255
256 return (ret & (SSTATUS_SIE));
257 }
258
259 static inline void
intr_restore(u_long s)260 intr_restore(u_long s)
261 {
262 __asm volatile("csrs sstatus, %0" :: "r" (s));
263 }
264
265 void delay (unsigned);
266 #define DELAY(x) delay(x)
267
268 extern void (*cpu_startclock_fcn)(void);
269
270 void fpu_save(struct proc *, struct trapframe *);
271 void fpu_load(struct proc *);
272
273 extern int cpu_errata_sifive_cip_1200;
274
275 #define cpu_idle_enter() do { /* nothing */ } while (0)
276 #define cpu_idle_leave() do { /* nothing */ } while (0)
277
278 #endif /* _KERNEL */
279
280 #ifdef MULTIPROCESSOR
281 #include <sys/mplock.h>
282 #endif /* MULTIPROCESSOR */
283
284 #endif /* !_MACHINE_CPU_H_ */
285