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