xref: /openbsd/sys/arch/riscv64/include/cpu.h (revision e1898f87)
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