Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
/*	$NetBSD: cpu.h,v 1.126 2019/02/08 20:14:50 palle Exp $ */

/*
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This software was developed by the Computer Systems Engineering group
 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
 * contributed to Berkeley.
 *
 * All advertising materials mentioning features or use of this software
 * must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Lawrence Berkeley Laboratory.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)cpu.h	8.4 (Berkeley) 1/5/94
 */

#ifndef _CPU_H_
#define _CPU_H_

/*
 * CTL_MACHDEP definitions.
 */
#define	CPU_BOOTED_KERNEL	1	/* string: booted kernel name */
#define	CPU_BOOTED_DEVICE	2	/* string: device booted from */
#define	CPU_BOOT_ARGS		3	/* string: args booted with */
#define	CPU_ARCH		4	/* integer: cpu architecture version */
#define CPU_VIS			5	/* 0 - no VIS, 1 - VIS 1.0, etc. */

/*
 * This is exported via sysctl for cpuctl(8).
 */
struct cacheinfo {
	int 	c_itotalsize;
	int 	c_ilinesize;
	int 	c_dtotalsize;
	int 	c_dlinesize;
	int 	c_etotalsize;
	int 	c_elinesize;
};

#if defined(_KERNEL) || defined(_KMEMUSER)
/*
 * Exported definitions unique to SPARC cpu support.
 */

#if defined(_KERNEL_OPT)
#include "opt_multiprocessor.h"
#include "opt_lockdebug.h"
#endif

#include <machine/psl.h>
#include <machine/reg.h>
#include <machine/pte.h>
#include <machine/intr.h>
#if defined(_KERNEL)
#include <machine/bus_defs.h>
#include <machine/cpuset.h>
#include <sparc64/sparc64/intreg.h>
#endif
#ifdef SUN4V
#include <machine/hypervisor.h>
#endif

#include <sys/cpu_data.h>
#include <sys/evcnt.h>

/*
 * The cpu_info structure is part of a 64KB structure mapped both the kernel
 * pmap and a single locked TTE a CPUINFO_VA for that particular processor.
 * Each processor's cpu_info is accessible at CPUINFO_VA only for that
 * processor.  Other processors can access that through an additional mapping
 * in the kernel pmap.
 *
 * The 64KB page contains:
 *
 * cpu_info
 * interrupt stack (all remaining space)
 * idle PCB
 * idle stack (STACKSPACE - sizeof(PCB))
 * 32KB TSB
 */

struct cpu_info {
	struct cpu_data		ci_data;	/* MI per-cpu data */


	/*
	 * SPARC cpu_info structures live at two VAs: one global
	 * VA (so each CPU can access any other CPU's cpu_info)
	 * and an alias VA CPUINFO_VA which is the same on each
	 * CPU and maps to that CPU's cpu_info.  Since the alias
	 * CPUINFO_VA is how we locate our cpu_info, we have to
	 * self-reference the global VA so that we can return it
	 * in the curcpu() macro.
	 */
	struct cpu_info * volatile ci_self;

	/* Most important fields first */
	struct lwp		*ci_curlwp;
	struct pcb		*ci_cpcb;
	struct cpu_info		*ci_next;

	struct lwp		*ci_fplwp;

	void			*ci_eintstack;

	int			ci_mtx_count;
	int			ci_mtx_oldspl;

	/* Spinning up the CPU */
	void			(*ci_spinup)(void);
	paddr_t			ci_paddr;

	int			ci_cpuid;

	uint64_t		ci_ver;

	/* CPU PROM information. */
	u_int			ci_node;
	const char		*ci_name;

	/* This is for sysctl. */
	struct cacheinfo	ci_cacheinfo;

	/* %tick and cpu frequency information */
	u_long			ci_tick_increment;
	uint64_t		ci_cpu_clockrate[2];	/* %tick */
	uint64_t		ci_system_clockrate[2];	/* %stick */

	/* Interrupts */
	struct intrhand		*ci_intrpending[16];
	struct intrhand		*ci_tick_ih;

	/* Event counters */
	struct evcnt		ci_tick_evcnt;

	/* This could be under MULTIPROCESSOR, but there's no good reason */
	struct evcnt		ci_ipi_evcnt[IPI_EVCNT_NUM];

	int			ci_flags;
	int			ci_want_ast;
	int			ci_want_resched;
	int			ci_idepth;

/*
 * A context is simply a small number that differentiates multiple mappings
 * of the same address.  Contexts on the spitfire are 13 bits, but could
 * be as large as 17 bits.
 *
 * Each context is either free or attached to a pmap.
 *
 * The context table is an array of pointers to psegs.  Just dereference
 * the right pointer and you get to the pmap segment tables.  These are
 * physical addresses, of course.
 *
 * ci_ctx_lock protects this CPUs context allocation/free.
 * These are all allocated almost with in the same cacheline.
 */
	kmutex_t		ci_ctx_lock;
	int			ci_pmap_next_ctx;
	int			ci_numctx;
	paddr_t 		*ci_ctxbusy;
	LIST_HEAD(, pmap) 	ci_pmap_ctxlist;

	/*
	 * The TSBs are per cpu too (since MMU context differs between
	 * cpus). These are just caches for the TLBs.
	 */
	pte_t			*ci_tsb_dmmu;
	pte_t			*ci_tsb_immu;

	/* TSB description (sun4v). */
	struct tsb_desc         *ci_tsb_desc;
	
	/* MMU Fault Status Area (sun4v).
	 * Will be initialized to the physical address of the bottom of
	 * the interrupt stack.
	 */
	paddr_t			ci_mmufsa;

	/*
	 * sun4v mondo control fields
	 */
	paddr_t			ci_cpumq;  /* cpu mondo queue address */
	paddr_t			ci_devmq;  /* device mondo queue address */
	paddr_t			ci_cpuset; /* mondo recipient address */ 
	paddr_t			ci_mondo;  /* mondo message address */
	
	/* probe fault in PCI config space reads */
	bool			ci_pci_probe;
	bool			ci_pci_fault;

	volatile void		*ci_ddb_regs;	/* DDB regs */
};

#endif /* _KERNEL || _KMEMUSER */

#ifdef _KERNEL

#define CPUF_PRIMARY	1

/*
 * CPU boot arguments. Used by secondary CPUs at the bootstrap time.
 */
struct cpu_bootargs {
	u_int	cb_node;	/* PROM CPU node */
	volatile int cb_flags;

	vaddr_t cb_ktext;
	paddr_t cb_ktextp;
	vaddr_t cb_ektext;

	vaddr_t cb_kdata;
	paddr_t cb_kdatap;
	vaddr_t cb_ekdata;

	paddr_t	cb_cpuinfo;
	int cb_cputyp;
};

extern struct cpu_bootargs *cpu_args;

#if defined(MULTIPROCESSOR)
extern int sparc_ncpus;
#else
#define sparc_ncpus 1
#endif

extern struct cpu_info *cpus;
extern struct pool_cache *fpstate_cache;

#define	curcpu()	(((struct cpu_info *)CPUINFO_VA)->ci_self)
#define	cpu_number()	(curcpu()->ci_index)
#define	CPU_IS_PRIMARY(ci)	((ci)->ci_flags & CPUF_PRIMARY)

#define CPU_INFO_ITERATOR		int __unused
#define CPU_INFO_FOREACH(cii, ci)	ci = cpus; ci != NULL; ci = ci->ci_next

#define curlwp		curcpu()->ci_curlwp
#define fplwp		curcpu()->ci_fplwp
#define curpcb		curcpu()->ci_cpcb

#define want_ast	curcpu()->ci_want_ast
#define want_resched	curcpu()->ci_want_resched

/*
 * definitions of cpu-dependent requirements
 * referenced in generic code
 */
#define	cpu_wait(p)	/* nothing */
void cpu_proc_fork(struct proc *, struct proc *);

/* run on the cpu itself */
void	cpu_pmap_init(struct cpu_info *);
/* run upfront to prepare the cpu_info */
void	cpu_pmap_prepare(struct cpu_info *, bool);

/* Helper functions to retrieve cache info */
int	cpu_ecache_associativity(int node);
int	cpu_ecache_size(int node);

#if defined(MULTIPROCESSOR)
extern vaddr_t cpu_spinup_trampoline;

extern  char   *mp_tramp_code;
extern  u_long  mp_tramp_code_len;
extern  u_long  mp_tramp_dtlb_slots, mp_tramp_itlb_slots;
extern  u_long  mp_tramp_func;
extern  u_long  mp_tramp_ci;

void	cpu_hatch(void);
void	cpu_boot_secondary_processors(void);

/*
 * Call a function on other cpus:
 *	multicast - send to everyone in the sparc64_cpuset_t
 *	broadcast - send to to all cpus but ourselves
 *	send - send to just this cpu
 * The called function do not follow the C ABI, so need to be coded in
 * assembler.
 */
typedef void (* ipifunc_t)(void *, void *);

void	sparc64_multicast_ipi(sparc64_cpuset_t, ipifunc_t, uint64_t, uint64_t);
void	sparc64_broadcast_ipi(ipifunc_t, uint64_t, uint64_t);
extern void (*sparc64_send_ipi)(int, ipifunc_t, uint64_t, uint64_t);

/*
 * Call an arbitrary C function on another cpu (or all others but ourself)
 */
typedef void (*ipi_c_call_func_t)(void*);
void	sparc64_generic_xcall(struct cpu_info*, ipi_c_call_func_t, void*);

#endif

/* Provide %pc of a lwp */
#define	LWP_PC(l)	((l)->l_md.md_tf->tf_pc)

/*
 * Arguments to hardclock, softclock and gatherstats encapsulate the
 * previous machine state in an opaque clockframe.  The ipl is here
 * as well for strayintr (see locore.s:interrupt and intr.c:strayintr).
 * Note that CLKF_INTR is valid only if CLKF_USERMODE is false.
 */
struct clockframe {
	struct trapframe64 t;
};

#define	CLKF_USERMODE(framep)	(((framep)->t.tf_tstate & TSTATE_PRIV) == 0)
#define	CLKF_PC(framep)		((framep)->t.tf_pc)
/* Since some files in sys/kern do not know BIAS, I'm using 0x7ff here */
#define	CLKF_INTR(framep)						\
	((!CLKF_USERMODE(framep))&&					\
		(((framep)->t.tf_out[6] & 1 ) ?				\
			(((vaddr_t)(framep)->t.tf_out[6] <		\
				(vaddr_t)EINTSTACK-0x7ff) &&		\
			((vaddr_t)(framep)->t.tf_out[6] >		\
				(vaddr_t)INTSTACK-0x7ff)) :		\
			(((vaddr_t)(framep)->t.tf_out[6] <		\
				(vaddr_t)EINTSTACK) &&			\
			((vaddr_t)(framep)->t.tf_out[6] >		\
				(vaddr_t)INTSTACK))))

/*
 * Give a profiling tick to the current process when the user profiling
 * buffer pages are invalid.  On the sparc, request an ast to send us
 * through trap(), marking the proc as needing a profiling tick.
 */
#define	cpu_need_proftick(l)	((l)->l_pflag |= LP_OWEUPC, want_ast = 1)

/*
 * Notify an LWP that it has a signal pending, process as soon as possible.
 */
void cpu_signotify(struct lwp *);


/*
 * Interrupt handler chains.  Interrupt handlers should return 0 for
 * ``not me'' or 1 (``I took care of it'').  intr_establish() inserts a
 * handler into the list.  The handler is called with its (single)
 * argument, or with a pointer to a clockframe if ih_arg is NULL.
 */
struct intrhand {
	int			(*ih_fun)(void *);
	void			*ih_arg;
	/* if we have to take the biglock, we interpose a wrapper
	 * and need to save the original function and arg */
	int			(*ih_realfun)(void *);
	void			*ih_realarg;
	short			ih_number;	/* interrupt number */
						/* the H/W provides */
	char			ih_pil;		/* interrupt priority */
	struct intrhand		*ih_next;	/* global list */
	struct intrhand		*ih_pending;	/* interrupt queued */
	volatile uint64_t	*ih_map;	/* Interrupt map reg */
	volatile uint64_t	*ih_clr;	/* clear interrupt reg */
	void			(*ih_ack)(struct intrhand *); /* ack interrupt function */
	bus_space_tag_t		ih_bus;		/* parent bus */
	struct evcnt		ih_cnt;		/* counter for vmstat */
	uint32_t		ih_ivec;
	char			ih_name[32];	/* name for the above */
};
extern struct intrhand *intrhand[];
extern struct intrhand *intrlev[MAXINTNUM];

void	intr_establish(int level, bool mpsafe, struct intrhand *);
void	*sparc_softintr_establish(int, int (*)(void *), void *);
void	sparc_softintr_schedule(void *);
void	sparc_softintr_disestablish(void *);
struct intrhand *intrhand_alloc(void);

/* cpu.c */
int	cpu_myid(void);

/* disksubr.c */
struct dkbad;
int isbad(struct dkbad *bt, int, int, int);
/* machdep.c */
void *	reserve_dumppages(void *);
/* clock.c */
struct timeval;
int	tickintr(void *);	/* level 10/14 (tick) interrupt code */
int	stickintr(void *);	/* system tick interrupt code */
int	stick2eintr(void *);	/* system tick interrupt code */
int	clockintr(void *);	/* level 10 (clock) interrupt code */
int	statintr(void *);	/* level 14 (statclock) interrupt code */
int	schedintr(void *);	/* level 10 (schedclock) interrupt code */
void	tickintr_establish(int, int (*)(void *));
void	stickintr_establish(int, int (*)(void *));
void	stick2eintr_establish(int, int (*)(void *));

/* locore.s */
struct fpstate64;
void	savefpstate(struct fpstate64 *);
void	loadfpstate(struct fpstate64 *);
void	clearfpstate(void);
uint64_t	probeget(paddr_t, int, int);
int	probeset(paddr_t, int, int, uint64_t);
void	setcputyp(int);

#define	 write_all_windows() __asm volatile("flushw" : : )
#define	 write_user_windows() __asm volatile("flushw" : : )

struct pcb;
void	snapshot(struct pcb *);
struct frame *getfp(void);
void	switchtoctx_us(int);
void	switchtoctx_usiii(int);
void	next_tick(long);
void	next_stick(long);
void	next_stick_init(void);
/* trap.c */
void	cpu_vmspace_exec(struct lwp *, vaddr_t, vaddr_t);
int	rwindow_save(struct lwp *);
/* cons.c */
int	cnrom(void);
/* zs.c */
void zsconsole(struct tty *, int, int, void (**)(struct tty *, int));
/* fb.c */
void	fb_unblank(void);
/* kgdb_stub.c */
#ifdef KGDB
void kgdb_attach(int (*)(void *), void (*)(void *, int), void *);
void kgdb_connect(int);
void kgdb_panic(void);
#endif
/* emul.c */
int	fixalign(struct lwp *, struct trapframe64 *);
int	emulinstr(vaddr_t, struct trapframe64 *);

#else /* _KERNEL */

/*
 * XXX: provide some definitions for crash(8), probably can share
 */
#if defined(_KMEMUSER)
#define	curcpu()	(((struct cpu_info *)CPUINFO_VA)->ci_self)
#define curlwp		curcpu()->ci_curlwp
#endif

#endif /* _KERNEL */
#endif /* _CPU_H_ */