1/* $OpenBSD: cpu.h,v 1.55 2026/04/03 14:20:23 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
64extern uint64_t cpu_id_aa64isar0;
65extern uint64_t cpu_id_aa64isar1;
66extern uint64_t cpu_id_aa64isar2;
67extern uint64_t cpu_id_aa64mmfr0;
68extern uint64_t cpu_id_aa64mmfr1;
69extern uint64_t cpu_id_aa64mmfr2;
70extern uint64_t cpu_id_aa64pfr0;
71extern uint64_t cpu_id_aa64pfr1;
72extern uint64_t cpu_id_aa64zfr0;
73
74void cpu_identify_cleanup(void);
75
76#include <machine/intr.h>
77#include <machine/frame.h>
78#include <machine/armreg.h>
79
80/* All the CLKF_* macros take a struct clockframe * as an argument. */
81
82#define clockframe trapframe
83/*
84 * CLKF_USERMODE: Return TRUE/FALSE (1/0) depending on whether the
85 * frame came from USR mode or not.
86 */
87#define CLKF_USERMODE(frame) ((frame->tf_elr & (1ul << 63)) == 0)
88
89/*
90 * CLKF_INTR: True if we took the interrupt from inside another
91 * interrupt handler.
92 */
93#define CLKF_INTR(frame) (curcpu()->ci_idepth > 1)
94
95/*
96 * CLKF_PC: Extract the program counter from a clockframe
97 */
98#define CLKF_PC(frame) (frame->tf_elr)
99
100/*
101 * PROC_PC: Find out the program counter for the given process.
102 */
103#define PROC_PC(p) ((p)->p_addr->u_pcb.pcb_tf->tf_elr)
104#define PROC_STACK(p) ((p)->p_addr->u_pcb.pcb_tf->tf_sp)
105
106/*
107 * Per-CPU information. For now we assume one CPU.
108 */
109
110#include <sys/clockintr.h>
111#include <sys/device.h>
112#include <sys/sched.h>
113#include <sys/srp.h>
114#include <uvm/uvm_percpu.h>
115#include <sys/xcall.h>
116
117struct cpu_info {
118 struct device *ci_dev; /* Device corresponding to this CPU */
119 struct cpu_info *ci_next;
120 struct schedstate_percpu ci_schedstate; /* scheduler state */
121
122 u_int32_t ci_cpuid;
123 uint64_t ci_mpidr;
124 uint64_t ci_midr;
125 u_int ci_acpi_proc_id;
126 int ci_node;
127 struct cpu_info *ci_self;
128
129#define __HAVE_CPU_TOPOLOGY
130 u_int32_t ci_cputype;
131 u_int32_t ci_smt_id;
132 u_int32_t ci_core_id;
133 u_int32_t ci_pkg_id;
134
135 struct proc *ci_curproc;
136 struct pcb *ci_curpcb;
137 struct pmap *ci_curpm;
138 u_int32_t ci_randseed;
139
140 u_int32_t ci_ctrl; /* The CPU control register */
141
142 u_int64_t ci_trampoline_vectors;
143
144 uint32_t ci_cpl;
145 uint32_t ci_ipending;
146 uint32_t ci_idepth;
147#ifdef DIAGNOSTIC
148 int ci_mutex_level;
149#endif
150 int ci_want_resched;
151
152 void (*ci_flush_bp)(void);
153 void (*ci_serror)(void);
154
155 uint64_t ci_ttbr1;
156 vaddr_t ci_el1_stkend;
157
158 uint32_t ci_psci_idle_latency;
159 uint32_t ci_psci_idle_param;
160 uint32_t ci_psci_suspend_param;
161
162 struct opp_table *ci_opp_table;
163 volatile int ci_opp_idx;
164 volatile int ci_opp_max;
165 uint32_t ci_cpu_supply;
166
167 uint64_t ci_capacity;
168
169 u_long ci_prev_sleep;
170 u_long ci_last_itime;
171
172#ifdef MULTIPROCESSOR
173 struct srp_hazard ci_srp_hazards[SRP_HAZARD_NUM];
174 struct xcall_cpu ci_xcall;
175#define __HAVE_UVM_PERCPU
176 struct uvm_pmr_cache ci_uvm;
177 volatile int ci_flags;
178
179 volatile int ci_ddb_paused;
180#define CI_DDB_RUNNING 0
181#define CI_DDB_SHOULDSTOP 1
182#define CI_DDB_STOPPED 2
183#define CI_DDB_ENTERDDB 3
184#define CI_DDB_INDDB 4
185
186#endif
187
188#ifdef GPROF
189 struct gmonparam *ci_gmon;
190 struct clockintr ci_gmonclock;
191#endif
192 struct clockqueue ci_queue;
193 char ci_panicbuf[512];
194};
195
196#define CPUF_PRIMARY (1<<0)
197#define CPUF_AP (1<<1)
198#define CPUF_IDENTIFY (1<<2)
199#define CPUF_IDENTIFIED (1<<3)
200#define CPUF_PRESENT (1<<4)
201#define CPUF_GO (1<<5)
202#define CPUF_RUNNING (1<<6)
203
204static inline struct cpu_info *
205curcpu(void)
206{
207 struct cpu_info *__ci = NULL;
208 __asm volatile("mrs %0, tpidr_el1" : "=r" (__ci));
209 return (__ci);
210}
211
212extern struct cpu_info cpu_info_primary;
213extern struct cpu_info *cpu_info_list;
214
215#ifndef MULTIPROCESSOR
216#define cpu_number() 0
217#define CPU_IS_PRIMARY(ci) 1
218#define CPU_IS_RUNNING(ci) 1
219#define CPU_INFO_ITERATOR int
220#define CPU_INFO_FOREACH(cii, ci) \
221 for (cii = 0, ci = curcpu(); ci != NULL; ci = NULL)
222#define CPU_INFO_UNIT(ci) 0
223#define MAXCPUS 1
224#define cpu_unidle(ci)
225#else
226#define cpu_number() (curcpu()->ci_cpuid)
227#define CPU_IS_PRIMARY(ci) ((ci) == &cpu_info_primary)
228#define CPU_IS_RUNNING(ci) ((ci)->ci_flags & CPUF_RUNNING)
229#define CPU_INFO_ITERATOR int
230#define CPU_INFO_FOREACH(cii, ci) for (cii = 0, ci = cpu_info_list; \
231 ci != NULL; ci = ci->ci_next)
232#define CPU_INFO_UNIT(ci) ((ci)->ci_dev ? (ci)->ci_dev->dv_unit : 0)
233#define MAXCPUS 256
234
235extern struct cpu_info *cpu_info[MAXCPUS];
236
237void cpu_boot_secondary_processors(void);
238#endif /* !MULTIPROCESSOR */
239
240#define CPU_BUSY_CYCLE() __asm volatile("yield" : : : "memory")
241
242#define curpcb curcpu()->ci_curpcb
243
244static inline unsigned int
245cpu_rnd_messybits(void)
246{
247 uint64_t val, rval;
248
249 __asm volatile("mrs %0, CNTVCT_EL0; rbit %1, %0;"
250 : "=r" (val), "=r" (rval));
251
252 return (val ^ rval);
253}
254
255/*
256 * Scheduling glue
257 */
258#define aston(p) ((p)->p_md.md_astpending = 1)
259#define setsoftast() aston(curcpu()->ci_curproc)
260
261/*
262 * Notify the current process (p) that it has a signal pending,
263 * process as soon as possible.
264 */
265
266#ifdef MULTIPROCESSOR
267void cpu_unidle(struct cpu_info *ci);
268#define signotify(p) (aston(p), cpu_unidle((p)->p_cpu))
269void cpu_kick(struct cpu_info *);
270#else
271#define cpu_kick(ci)
272#define cpu_unidle(ci)
273#define signotify(p) setsoftast()
274#endif
275
276/*
277 * Preempt the current process if in interrupt from user mode,
278 * or after the current trap/syscall if in system mode.
279 */
280void need_resched(struct cpu_info *);
281#define clear_resched(ci) ((ci)->ci_want_resched = 0)
282
283/*
284 * Give a profiling tick to the current process when the user profiling
285 * buffer pages are invalid. On the i386, request an ast to send us
286 * through trap(), marking the proc as needing a profiling tick.
287 */
288#define need_proftick(p) aston(p)
289
290// asm code to start new kernel contexts.
291void proc_trampoline(void);
292
293/*
294 * Random cruft
295 */
296void dumpconf(void);
297
298// syscall.c
299void svc_handler (trapframe_t *);
300
301// functions to manipulate interrupt state
302static __inline void
303restore_daif(uint32_t daif)
304{
305 __asm volatile ("msr daif, %x0":: "r"(daif));
306}
307
308static __inline void
309enable_irq_daif(void)
310{
311 __asm volatile ("msr daifclr, #3");
312}
313
314static __inline void
315disable_irq_daif(void)
316{
317 __asm volatile ("msr daifset, #3");
318}
319
320static __inline uint32_t
321disable_irq_daif_ret(void)
322{
323 uint32_t daif;
324 __asm volatile ("mrs %x0, daif": "=r"(daif));
325 __asm volatile ("msr daifset, #3");
326 return daif;
327}
328
329static inline void
330intr_enable(void)
331{
332 enable_irq_daif();
333}
334
335static inline u_long
336intr_disable(void)
337{
338 return disable_irq_daif_ret();
339}
340
341static inline void
342intr_restore(u_long daif)
343{
344 restore_daif(daif);
345}
346
347void cpu_classify(void);
348void cpu_halt(void);
349int cpu_suspend_primary(void);
350void cpu_resume_secondary(struct cpu_info *);
351
352extern void (*cpu_idle_cycle_fcn)(void);
353extern void (*cpu_suspend_cycle_fcn)(void);
354
355void cpu_wfi(void);
356
357void delay (unsigned);
358#define DELAY(x) delay(x)
359
360#endif /* _KERNEL */
361
362#ifdef MULTIPROCESSOR
363#include <sys/mplock.h>
364#endif /* MULTIPROCESSOR */
365
366#endif /* !_MACHINE_CPU_H_ */