1/* $OpenBSD: cpu.h,v 1.25 2026/04/06 08:10:54 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
77struct 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
144register struct cpu_info *__curcpu asm ("tp");
145
146#define curcpu() (__curcpu)
147
148extern uint32_t boot_hart; /* The hart we booted on. */
149extern struct cpu_info cpu_info_primary;
150extern struct cpu_info *cpu_info_list;
151
152#ifndef MULTIPROCESSOR
153
154#define cpu_number() 0
155#define CPU_IS_PRIMARY(ci) 1
156#define CPU_IS_RUNNING(ci) 1
157#define CPU_INFO_ITERATOR int
158#define CPU_INFO_FOREACH(cii, ci) \
159 for (cii = 0, ci = curcpu(); ci != NULL; ci = NULL)
160#define CPU_INFO_UNIT(ci) 0
161#define MAXCPUS 1
162#define cpu_unidle(ci)
163
164#else
165
166#define cpu_number() (curcpu()->ci_cpuid)
167#define CPU_IS_PRIMARY(ci) ((ci) == &cpu_info_primary)
168#define CPU_IS_RUNNING(ci) ((ci)->ci_flags & CPUF_RUNNING)
169#define CPU_INFO_ITERATOR int
170#define CPU_INFO_FOREACH(cii, ci) for (cii = 0, ci = cpu_info_list; \
171 ci != NULL; ci = ci->ci_next)
172#define CPU_INFO_UNIT(ci) ((ci)->ci_dev ? (ci)->ci_dev->dv_unit : 0)
173#define MAXCPUS 32
174
175extern struct cpu_info *cpu_info[MAXCPUS];
176
177void cpu_boot_secondary_processors(void);
178
179#endif /* !MULTIPROCESSOR */
180
181/* Zihintpause ratified extension */
182#define CPU_BUSY_CYCLE() __asm volatile(".long 0x0100000f" ::: "memory")
183
184#define curpcb curcpu()->ci_curpcb
185
186static inline unsigned int
187cpu_rnd_messybits(void)
188{
189 // Should do bit reversal ^ with csr_read(time);
190 return csr_read(time);
191}
192
193/*
194 * Scheduling glue
195 */
196#define aston(p) ((p)->p_md.md_astpending = 1)
197#define setsoftast() aston(curcpu()->ci_curproc)
198
199/*
200 * Notify the current process (p) that it has a signal pending,
201 * process as soon as possible.
202 */
203
204#ifdef MULTIPROCESSOR
205void cpu_unidle(struct cpu_info *ci);
206#define signotify(p) (aston(p), cpu_unidle((p)->p_cpu))
207void cpu_kick(struct cpu_info *);
208#else
209#define cpu_kick(ci)
210#define cpu_unidle(ci)
211#define signotify(p) setsoftast()
212#endif
213
214/*
215 * Preempt the current process if in interrupt from user mode,
216 * or after the current trap/syscall if in system mode.
217 */
218void need_resched(struct cpu_info *);
219#define clear_resched(ci) ((ci)->ci_want_resched = 0)
220
221/*
222 * Give a profiling tick to the current process when the user profiling
223 * buffer pages are invalid. On the i386, request an ast to send us
224 * through trap(), marking the proc as needing a profiling tick.
225 */
226#define need_proftick(p) aston(p)
227
228// asm code to start new kernel contexts.
229void proc_trampoline(void);
230
231/*
232 * Random cruft
233 */
234void dumpconf(void);
235
236static inline void
237intr_enable(void)
238{
239 __asm volatile("csrsi sstatus, %0" :: "i" (SSTATUS_SIE));
240}
241
242static inline u_long
243intr_disable(void)
244{
245 uint64_t ret;
246
247 __asm volatile(
248 "csrrci %0, sstatus, %1"
249 : "=&r" (ret) : "i" (SSTATUS_SIE)
250 );
251
252 return (ret & (SSTATUS_SIE));
253}
254
255static inline void
256intr_restore(u_long s)
257{
258 __asm volatile("csrs sstatus, %0" :: "r" (s));
259}
260
261void delay (unsigned);
262#define DELAY(x) delay(x)
263
264extern void (*cpu_startclock_fcn)(void);
265
266void fpu_save(struct proc *, struct trapframe *);
267void fpu_load(struct proc *);
268
269extern int cpu_errata_sifive_cip_1200;
270
271#define cpu_idle_enter() do { /* nothing */ } while (0)
272#define cpu_idle_leave() do { /* nothing */ } while (0)
273
274#endif /* _KERNEL */
275
276#ifdef MULTIPROCESSOR
277#include <sys/mplock.h>
278#endif /* MULTIPROCESSOR */
279
280#endif /* !_MACHINE_CPU_H_ */