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 *
curcpu(void)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
cpu_rnd_messybits(void)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
restore_daif(uint32_t daif)297 restore_daif(uint32_t daif)
298 {
299 __asm volatile ("msr daif, %x0":: "r"(daif));
300 }
301
302 static __inline void
enable_irq_daif(void)303 enable_irq_daif(void)
304 {
305 __asm volatile ("msr daifclr, #3");
306 }
307
308 static __inline void
disable_irq_daif(void)309 disable_irq_daif(void)
310 {
311 __asm volatile ("msr daifset, #3");
312 }
313
314 static __inline uint32_t
disable_irq_daif_ret(void)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
intr_enable(void)324 intr_enable(void)
325 {
326 enable_irq_daif();
327 }
328
329 static inline u_long
intr_disable(void)330 intr_disable(void)
331 {
332 return disable_irq_daif_ret();
333 }
334
335 static inline void
intr_restore(u_long daif)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