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
/*	$NetBSD: emul.c,v 1.199 2023/04/22 13:53:44 riastradh Exp $	*/

/*
 * Copyright (c) 2007-2011 Antti Kantee.  All Rights Reserved.
 *
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: emul.c,v 1.199 2023/04/22 13:53:44 riastradh Exp $");

#include <sys/param.h>
#include <sys/cprng.h>
#include <sys/filedesc.h>
#include <sys/fstrans.h>
#include <sys/kauth.h>
#include <sys/module.h>
#include <sys/reboot.h>
#include <sys/syscall.h>
#include <sys/pserialize.h>
#ifdef LOCKDEBUG
#include <sys/sleepq.h>
#endif

#include <dev/cons.h>

#include <rump-sys/kern.h>

#include <rump/rumpuser.h>

void (*rump_vfs_fini)(void) = (void *)nullop;

/*
 * physmem is largely unused (except for nmbcluster calculations),
 * so pick a default value which suits ZFS.  if an application wants
 * a very small memory footprint, it can still adjust this before
 * calling rump_init()
 */
#define PHYSMEM 512*256
psize_t physmem = PHYSMEM;
size_t nkmempages = PHYSMEM/2; /* from le chapeau */
#undef PHYSMEM

struct vnode *rootvp;
dev_t rootdev = NODEV;

const int schedppq = 1;
int cold = 1;
int shutting_down;
int boothowto = AB_SILENT;
struct tty *constty;

const struct bdevsw *bdevsw0[255];
const struct bdevsw **bdevsw = bdevsw0;
const int sys_cdevsws = 255;
int max_cdevsws = 255;

const struct cdevsw *cdevsw0[255];
const struct cdevsw **cdevsw = cdevsw0;
const int sys_bdevsws = 255;
int max_bdevsws = 255;

int mem_no = 2;

device_t booted_device;
device_t booted_wedge;
int booted_partition;
const char *booted_method;

/* XXX: unused */
kmutex_t tty_lock;
krwlock_t exec_lock;

/* sparc doesn't sport constant page size, pretend we have 4k pages */
#ifdef __sparc__
int nbpg = 4096;
int pgofset = 4096-1;
int pgshift = 12;
#endif

/* on sun3 VM_MAX_ADDRESS is a const variable */
/* XXX: should be moved into rump.c and initialize for sun3 and sun3x? */
#ifdef sun3
const vaddr_t kernbase = KERNBASE3;
#endif

struct loadavg averunnable = {
	{ 0 * FSCALE,
	  1 * FSCALE,
	  11 * FSCALE, },
	FSCALE,
};

/*
 * Include the autogenerated list of auto-loadable syscalls
 */
#include <kern/syscalls_autoload.c>

struct emul emul_netbsd = {
	.e_name = "netbsd-rump",
	.e_sysent = rump_sysent,
	.e_nomodbits = rump_sysent_nomodbits,
#ifndef __HAVE_MINIMAL_EMUL
	.e_nsysent = SYS_NSYSENT,
#endif
	.e_vm_default_addr = uvm_default_mapaddr,
#ifdef __HAVE_SYSCALL_INTERN
	.e_syscall_intern = syscall_intern,
#endif
	.e_sc_autoload = netbsd_syscalls_autoload,
};

/* not used, but need the symbols for pointer comparisons */
syncobj_t mutex_syncobj, rw_syncobj;

int
kpause(const char *wmesg, bool intr, int timeo, kmutex_t *mtx)
{
	extern int hz;
	int rv __diagused;
	uint64_t sec, nsec;

	if (mtx)
		mutex_exit(mtx);

	sec = timeo / hz;
	nsec = (timeo % hz) * (1000000000 / hz);
	rv = rumpuser_clock_sleep(RUMPUSER_CLOCK_RELWALL, sec, nsec);
	KASSERT(rv == 0);

	if (mtx)
		mutex_enter(mtx);

	return 0;
}

vaddr_t
calc_cache_size(vsize_t vasz, int pct, int va_pct)
{
	paddr_t t;

	t = (paddr_t)physmem * pct / 100 * PAGE_SIZE;
	if ((vaddr_t)t != t) {
		panic("%s: needs tweak", __func__);
	}
	return t;
}

#define	RETURN_ADDRESS	(uintptr_t)__builtin_return_address(0)

void
assert_sleepable(void)
{
	const char *reason = NULL;

	/* always sleepable, although we should improve this */

	if (!pserialize_not_in_read_section()) {
		reason = "pserialize";
	}

	if (reason) {
		panic("%s: %s caller=%p", __func__, reason,
		    (void *)RETURN_ADDRESS);
	}
}

void
module_init_md(void)
{

	/*
	 * Nothing for now.  However, we should load the librump
	 * symbol table.
	 */
}

/*
 * Try to emulate all the MD definitions of DELAY() / delay().
 * Would be nice to fix the #defines in MD headers, but this quicker.
 *
 * XXX: we'd need a rumpuser_clock_sleep_nowrap() here.  Since we
 * don't have it in the current hypercall revision, busyloop.
 * Note that rather than calibrate a loop delay and work with that,
 * get call gettime (which does not block) in a loop to make sure
 * we didn't get virtual ghosttime.  That might be slightly inaccurate
 * for very small delays ...
 *
 * The other option would be to run a thread in the hypervisor which
 * sleeps for us and we can wait for it using rumpuser_cv_wait_nowrap()
 * Probably too fussy.  Better just wait for hypercall rev 18 ;)
 */
static void
rump_delay(unsigned int us)
{
	struct timespec target, tmp;
	uint64_t sec, sec_ini, sec_now;
	long nsec, nsec_ini, nsec_now;
	int loops;

	rumpuser_clock_gettime(RUMPUSER_CLOCK_ABSMONO, &sec_ini, &nsec_ini);

#ifdef __mac68k__
	sec = us / 1000;
	nsec = (us % 1000) * 1000000;
#else
	sec = us / 1000000;
	nsec = (us % 1000000) * 1000;
#endif

	target.tv_sec = sec_ini;
	tmp.tv_sec = sec;
	target.tv_nsec = nsec_ini;
	tmp.tv_nsec = nsec;
	timespecadd(&target, &tmp, &target);

	if (__predict_false(sec != 0))
		printf("WARNING: over 1s delay\n");

	for (loops = 0; loops < 1000*1000*100; loops++) {
		struct timespec cur;

		rumpuser_clock_gettime(RUMPUSER_CLOCK_ABSMONO,
		    &sec_now, &nsec_now);
		cur.tv_sec = sec_now;
		cur.tv_nsec = nsec_now;
		if (timespeccmp(&cur, &target, >=)) {
			return;
		}
	}
	printf("WARNING: DELAY ESCAPED\n");
}
void (*delay_func)(unsigned int) = rump_delay;
__strong_alias(delay,rump_delay);
__strong_alias(_delay,rump_delay);

/* Weak alias for getcwd_common to be used unless librumpvfs is present. */

int rump_getcwd_common(struct vnode *, struct vnode *, char **, char *,
    int, int, struct lwp *);
int
rump_getcwd_common(struct vnode *lvp, struct vnode *rvp, char **bpp, char *bufp,
    int limit, int flags, struct lwp *l)
{

	return ENOENT;
}
__weak_alias(getcwd_common,rump_getcwd_common);

/* Weak alias for vnode_to_path to be used unless librumpvfs is present. */

int rump_vnode_to_path(char *, size_t, struct vnode *, struct lwp *,
    struct proc *);
int
rump_vnode_to_path(char *path, size_t len, struct vnode *vp, struct lwp *curl,
    struct proc *p)
{

	return ENOENT; /* pretend getcwd_common() failed. */
}
__weak_alias(vnode_to_path,rump_vnode_to_path);


/* Weak aliases for fstrans to be used unless librumpvfs is present. */

void rump_fstrans_start(struct mount *);
void
rump_fstrans_start(struct mount *mp)
{

}
__weak_alias(fstrans_start,rump_fstrans_start);

int rump_fstrans_start_nowait(struct mount *);
int
rump_fstrans_start_nowait(struct mount *mp)
{

	return 0;
}
__weak_alias(fstrans_start_nowait,rump_fstrans_start_nowait);

void rump_fstrans_start_lazy(struct mount *);
void
rump_fstrans_start_lazy(struct mount *mp)
{

}
__weak_alias(fstrans_start_lazy,rump_fstrans_start_lazy);


void rump_fstrans_done(struct mount *);
void
rump_fstrans_done(struct mount *mp)
{

}
__weak_alias(fstrans_done,rump_fstrans_done);


void rump_fstrans_lwp_dtor(struct lwp *);
void
rump_fstrans_lwp_dtor(struct lwp *l)
{

}
__weak_alias(fstrans_lwp_dtor,rump_fstrans_lwp_dtor);

static int
rump_filt_fsattach(struct knote *kn)
{

	return EOPNOTSUPP;
}

struct filterops rump_fs_filtops = {
	.f_attach = rump_filt_fsattach,
};
__weak_alias(fs_filtops,rump_fs_filtops);

struct pool_cache *rump_pnbuf_cache;
__weak_alias(pnbuf_cache,rump_pnbuf_cache);

/*
 * Provide weak aliases for tty routines used by printf.
 * They will be used unless the rumpkern_tty component is present.
 */

int rump_ttycheckoutq(struct tty *, int);
int
rump_ttycheckoutq(struct tty *tp, int wait)
{

	return 1;
}
__weak_alias(ttycheckoutq,rump_ttycheckoutq);

int rump_tputchar(int, int, struct tty *);
int
rump_tputchar(int c, int flags, struct tty *tp)
{

	cnputc(c);
	return 0;
}
__weak_alias(tputchar,rump_tputchar);

void
cnputc(int c)
{

	rumpuser_putchar(c);
}

void
cnflush(void)
{

	/* done */
}

void
resettodr(void)
{

	/* setting clocks is not in the jurisdiction of rump kernels */
}

#ifdef __HAVE_SYSCALL_INTERN
void
syscall_intern(struct proc *p)
{

	p->p_emuldata = NULL;
}
#endif

#ifdef LOCKDEBUG
void
turnstile_print(volatile void *obj, void (*pr)(const char *, ...))
{

	/* nada */
}
#endif

void
cpu_reboot(int howto, char *bootstr)
{
	int ruhow = 0;
	void *finiarg;

	printf("rump kernel halting...\n");

	if (!RUMP_LOCALPROC_P(curproc))
		finiarg = RUMP_SPVM2CTL(curproc->p_vmspace);
	else
		finiarg = NULL;

	/* dump means we really take the dive here */
	if ((howto & RB_DUMP) || panicstr) {
		ruhow = RUMPUSER_PANIC;
		goto out;
	}

	/* try to sync */
	if (!((howto & RB_NOSYNC) || panicstr)) {
		rump_vfs_fini();
	}

	doshutdownhooks();

	/* your wish is my command */
	if (howto & RB_HALT) {
		printf("rump kernel halted (with RB_HALT, not exiting)\n");
		rump_sysproxy_fini(finiarg);
		for (;;) {
			rumpuser_clock_sleep(RUMPUSER_CLOCK_RELWALL, 10, 0);
		}
	}

	/* this function is __dead, we must exit */
 out:
	rump_sysproxy_fini(finiarg);
	rumpuser_exit(ruhow);
}