NetBSD/sys/rump/librump/rumpkern/rump.c

847 lines
18 KiB
C
Raw Normal View History

/* $NetBSD: rump.c,v 1.177 2010/06/09 14:08:17 pooka Exp $ */
/*
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
*
* Development of this software was supported by Google Summer of Code.
*
* 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.
*/
2008-12-18 03:24:12 +03:00
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: rump.c,v 1.177 2010/06/09 14:08:17 pooka Exp $");
#include <sys/systm.h>
#define ELFSIZE ARCH_ELFSIZE
2008-12-18 03:24:12 +03:00
#include <sys/param.h>
#include <sys/atomic.h>
#include <sys/buf.h>
#include <sys/callout.h>
2008-12-29 20:45:55 +03:00
#include <sys/conf.h>
#include <sys/cpu.h>
#include <sys/device.h>
2009-03-29 22:22:08 +04:00
#include <sys/evcnt.h>
#include <sys/event.h>
#include <sys/exec_elf.h>
#include <sys/filedesc.h>
#include <sys/iostat.h>
#include <sys/kauth.h>
#include <sys/kernel.h>
#include <sys/kmem.h>
#include <sys/kprintf.h>
#include <sys/kthread.h>
2009-01-08 00:11:19 +03:00
#include <sys/ksyms.h>
#include <sys/msgbuf.h>
#include <sys/module.h>
#include <sys/once.h>
2008-10-11 00:24:10 +04:00
#include <sys/percpu.h>
2009-11-26 20:36:22 +03:00
#include <sys/pipe.h>
2010-04-21 20:16:31 +04:00
#include <sys/pool.h>
#include <sys/queue.h>
2009-10-09 18:41:36 +04:00
#include <sys/reboot.h>
#include <sys/resourcevar.h>
#include <sys/select.h>
2008-08-01 23:34:51 +04:00
#include <sys/sysctl.h>
2009-02-20 21:08:12 +03:00
#include <sys/syscall.h>
#include <sys/syscallvar.h>
#include <sys/timetc.h>
#include <sys/tty.h>
#include <sys/uidinfo.h>
#include <sys/vmem.h>
#include <sys/xcall.h>
#include <rump/rumpuser.h>
First part of secmodel cleanup and other misc. changes: - Separate the suser part of the bsd44 secmodel into its own secmodel and directory, pending even more cleanups. For revision history purposes, the original location of the files was src/sys/secmodel/bsd44/secmodel_bsd44_suser.c src/sys/secmodel/bsd44/suser.h - Add a man-page for secmodel_suser(9) and update the one for secmodel_bsd44(9). - Add a "secmodel" module class and use it. Userland program and documentation updated. - Manage secmodel count (nsecmodels) through the module framework. This eliminates the need for secmodel_{,de}register() calls in secmodel code. - Prepare for secmodel modularization by adding relevant module bits. The secmodels don't allow auto unload. The bsd44 secmodel depends on the suser and securelevel secmodels. The overlay secmodel depends on the bsd44 secmodel. As the module class is only cosmetic, and to prevent ambiguity, the bsd44 and overlay secmodels are prefixed with "secmodel_". - Adapt the overlay secmodel to recent changes (mainly vnode scope). - Stop using link-sets for the sysctl node(s) creation. - Keep sysctl variables under nodes of their relevant secmodels. In other words, don't create duplicates for the suser/securelevel secmodels under the bsd44 secmodel, as the latter is merely used for "grouping". - For the suser and securelevel secmodels, "advertise presence" in relevant sysctl nodes (sysctl.security.models.{suser,securelevel}). - Get rid of the LKM preprocessor stuff. - As secmodels are now modules, there's no need for an explicit call to secmodel_start(); it's handled by the module framework. That said, the module framework was adjusted to properly load secmodels early during system startup. - Adapt rump to changes: Instead of using empty stubs for securelevel, simply use the suser secmodel. Also replace secmodel_start() with a call to secmodel_suser_start(). - 5.99.20. Testing was done on i386 ("release" build). Spearated module_init() changes were tested on sparc and sparc64 as well by martin@ (thanks!). Mailing list reference: http://mail-index.netbsd.org/tech-kern/2009/09/25/msg006135.html
2009-10-02 22:50:12 +04:00
#include <secmodel/suser/suser.h>
2009-09-13 23:09:13 +04:00
#include <prop/proplib.h>
#include <uvm/uvm_extern.h>
2009-11-10 20:02:36 +03:00
#include <uvm/uvm_readahead.h>
#include "rump_private.h"
#include "rump_net_private.h"
#include "rump_vfs_private.h"
2009-09-07 00:54:19 +04:00
#include "rump_dev_private.h"
struct proc proc0;
struct session rump_session = {
.s_count = 1,
.s_flags = 0,
.s_leader = &proc0,
.s_login = "rumphobo",
.s_sid = 0,
};
struct pgrp rump_pgrp = {
.pg_members = LIST_HEAD_INITIALIZER(pg_members),
.pg_session = &rump_session,
.pg_jobc = 1,
};
struct pstats rump_stats;
struct plimit rump_limits;
struct filedesc rump_filedesc0;
struct proclist allproc;
char machine[] = MACHINE;
2008-09-30 23:25:56 +04:00
static kauth_cred_t rump_susercred;
/* pretend the master rump proc is init */
struct proc *initproc = &proc0;
struct rumpuser_mtx *rump_giantlock;
2007-11-07 19:24:22 +03:00
struct device rump_rootdev = {
.dv_class = DV_VIRTUAL
};
#ifdef RUMP_WITHOUT_THREADS
int rump_threads = 0;
#else
int rump_threads = 1;
#endif
static char rump_msgbuf[16*1024]; /* 16k should be enough for std rump needs */
static void
rump_aiodone_worker(struct work *wk, void *dummy)
{
struct buf *bp = (struct buf *)wk;
KASSERT(&bp->b_work == wk);
bp->b_iodone(bp);
}
2008-08-01 23:34:51 +04:00
static int rump_inited;
2010-04-21 20:16:31 +04:00
/*
* Make sure pnbuf_cache is available even without vfs
*/
struct pool_cache *pnbuf_cache;
int rump_initpnbufpool(void);
int rump_initpnbufpool(void)
{
pnbuf_cache = pool_cache_init(MAXPATHLEN, 0, 0, 0, "pnbufpl",
NULL, IPL_NONE, NULL, NULL, NULL);
return EOPNOTSUPP;
}
int rump__unavailable(void);
int rump__unavailable() {return EOPNOTSUPP;}
__weak_alias(rump_net_init,rump__unavailable);
2010-04-21 20:16:31 +04:00
__weak_alias(rump_vfs_init,rump_initpnbufpool);
2009-09-07 00:54:19 +04:00
__weak_alias(rump_dev_init,rump__unavailable);
2009-10-09 18:41:36 +04:00
__weak_alias(rump_vfs_fini,rump__unavailable);
__weak_alias(biodone,rump__unavailable);
__weak_alias(sopoll,rump__unavailable);
void rump__unavailable_vfs_panic(void);
void rump__unavailable_vfs_panic() {panic("vfs component not available");}
__weak_alias(usermount_common_policy,rump__unavailable_vfs_panic);
2009-12-09 03:11:21 +03:00
rump_proc_vfs_init_fn rump_proc_vfs_init;
rump_proc_vfs_release_fn rump_proc_vfs_release;
static void add_linkedin_modules(const struct modinfo *const *, size_t);
static void __noinline
messthestack(void)
{
volatile uint32_t mess[64];
uint64_t d1, d2;
int i, error;
for (i = 0; i < 64; i++) {
rumpuser_gettime(&d1, &d2, &error);
mess[i] = d2;
}
}
/*
* Create kern.hostname. why only this you ask. well, init_sysctl
* is a kitchen sink in need of some gardening. but i want to use
* kern.hostname today.
*/
static void
mksysctls(void)
{
sysctl_createv(NULL, 0, NULL, NULL,
CTLFLAG_PERMANENT, CTLTYPE_NODE, "kern", NULL,
NULL, 0, NULL, 0, CTL_KERN, CTL_EOL);
/* XXX: setting hostnamelen is missing */
sysctl_createv(NULL, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_STRING, "hostname",
SYSCTL_DESCR("System hostname"), NULL, 0,
&hostname, MAXHOSTNAMELEN, CTL_KERN, KERN_HOSTNAME, CTL_EOL);
}
int
2009-01-08 00:12:30 +03:00
rump__init(int rump_version)
{
char buf[256];
struct timespec ts;
2010-03-31 16:16:15 +04:00
uint64_t sec, nsec;
struct proc *p;
struct lwp *l;
int i, numcpu;
int error;
2009-10-09 18:41:36 +04:00
/* not reentrant */
if (rump_inited)
return 0;
2009-10-09 18:41:36 +04:00
else if (rump_inited == -1)
panic("rump_init: host process restart required");
else
rump_inited = 1;
if (rumpuser_getversion() != RUMPUSER_VERSION) {
/* let's hope the ABI of rumpuser_dprintf is the same ;) */
rumpuser_dprintf("rumpuser version mismatch: %d vs. %d\n",
rumpuser_getversion(), RUMPUSER_VERSION);
return EPROGMISMATCH;
}
if (rumpuser_getenv("RUMP_VERBOSE", buf, sizeof(buf), &error) == 0) {
if (*buf != '0')
boothowto = AB_VERBOSE;
}
if (rumpuser_getenv("RUMP_NCPU", buf, sizeof(buf), &error) == 0)
error = 0;
/* non-x86 is missing CPU_INFO_FOREACH() support */
#if defined(__i386__) || defined(__x86_64__)
if (error == 0) {
numcpu = strtoll(buf, NULL, 10);
if (numcpu < 1)
numcpu = 1;
} else {
numcpu = rumpuser_getnhostcpu();
}
#else
if (error == 0)
printf("NCPU limited to 1 on this host\n");
numcpu = 1;
#endif
rump_cpus_bootstrap(numcpu);
2010-03-31 16:16:15 +04:00
rumpuser_gettime(&sec, &nsec, &error);
boottime.tv_sec = sec;
boottime.tv_nsec = nsec;
initmsgbuf(rump_msgbuf, sizeof(rump_msgbuf));
aprint_verbose("%s%s", copyright, version);
/*
* Seed arc4random() with a "reasonable" amount of randomness.
* Yes, this is a quick kludge which depends on the arc4random
* implementation.
*/
messthestack();
arc4random();
if (rump_version != RUMP_VERSION) {
printf("rump version mismatch, %d vs. %d\n",
rump_version, RUMP_VERSION);
return EPROGMISMATCH;
}
if (rumpuser_getenv("RUMP_THREADS", buf, sizeof(buf), &error) == 0) {
rump_threads = *buf != '0';
}
rumpuser_thrinit(rump_user_schedule, rump_user_unschedule,
rump_threads);
rump_intr_init();
rump_tsleep_init();
/* init minimal lwp/cpu context */
l = &lwp0;
l->l_lid = 1;
l->l_cpu = l->l_target_cpu = rump_cpu;
rumpuser_set_curlwp(l);
mutex_init(&tty_lock, MUTEX_DEFAULT, IPL_NONE);
rumpuser_mutex_recursive_init(&rump_giantlock);
2009-01-08 00:11:19 +03:00
ksyms_init();
uvm_init();
2009-03-29 22:22:08 +04:00
evcnt_init();
once_init();
2009-09-13 23:09:13 +04:00
prop_kern_init();
pool_subsystem_init();
kmem_init();
2009-11-10 20:02:36 +03:00
uvm_ra_init();
mutex_obj_init();
callout_startup();
kprintf_init();
loginit();
2008-09-30 23:25:56 +04:00
kauth_init();
rump_susercred = rump_cred_create(0, 0, 0, NULL);
2008-09-30 23:25:56 +04:00
/* init proc0 and rest of lwp0 now that we can allocate memory */
p = &proc0;
p->p_stats = &rump_stats;
p->p_limit = &rump_limits;
p->p_pgrp = &rump_pgrp;
p->p_pid = 0;
p->p_fd = &rump_filedesc0;
p->p_vmspace = &rump_vmspace;
p->p_emul = &emul_netbsd;
p->p_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE);
l->l_cred = rump_cred_suserget();
l->l_proc = p;
LIST_INIT(&allproc);
2009-04-29 19:49:28 +04:00
LIST_INSERT_HEAD(&allproc, &proc0, p_list);
2009-01-26 17:41:28 +03:00
proc_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE);
2010-06-09 17:51:02 +04:00
2010-04-13 02:17:23 +04:00
lwpinit_specificdata();
2010-06-09 17:51:02 +04:00
lwp_initspecific(&lwp0);
2010-04-21 20:16:31 +04:00
mutex_init(&rump_limits.pl_lock, MUTEX_DEFAULT, IPL_NONE);
rump_limits.pl_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
rump_limits.pl_rlimit[RLIMIT_NOFILE].rlim_cur = RLIM_INFINITY;
2008-10-13 23:41:13 +04:00
rump_limits.pl_rlimit[RLIMIT_SBSIZE].rlim_cur = RLIM_INFINITY;
2010-04-21 20:16:31 +04:00
rump_limits.pl_corename = defcorename;
rump_scheduler_init();
/* revert temporary context and schedule a real context */
l->l_cpu = NULL;
rumpuser_set_curlwp(NULL);
rump_schedule();
percpu_init();
inittimecounter();
ntp_init();
rumpuser_gettime(&sec, &nsec, &error);
ts.tv_sec = sec;
ts.tv_nsec = nsec;
tc_setclock(&ts);
/* we are mostly go. do per-cpu subsystem init */
for (i = 0; i < ncpu; i++) {
struct cpu_info *ci = cpu_lookup(i);
callout_init_cpu(ci);
softint_init(ci);
xc_init_cpu(ci);
pool_cache_cpu_init(ci);
selsysinit(ci);
percpu_init_cpu(ci);
}
2008-04-28 23:31:45 +04:00
sysctl_init();
kqueue_init();
iostat_init();
uid_init();
2008-04-28 23:31:45 +04:00
fd_sys_init();
module_init();
2008-12-29 20:45:55 +03:00
devsw_init();
2009-11-26 20:36:22 +03:00
pipe_init();
2010-04-21 20:16:31 +04:00
resource_init();
/* start page baroness */
if (rump_threads) {
if (kthread_create(PRI_PGDAEMON, KTHREAD_MPSAFE, NULL,
uvm_pageout, NULL, &uvm.pagedaemon_lwp, "pdaemon") != 0)
panic("pagedaemon create failed");
} else
uvm.pagedaemon_lwp = NULL; /* doesn't match curlwp */
/* process dso's */
rumpuser_dl_bootstrap(add_linkedin_modules, rump_kernelfsym_load);
/* these do nothing if not present */
rump_vfs_init();
rump_net_init();
2009-09-07 00:54:19 +04:00
rump_dev_init();
cold = 0;
/* aieeeedondest */
if (rump_threads) {
if (workqueue_create(&uvm.aiodone_queue, "aiodoned",
rump_aiodone_worker, NULL, 0, 0, WQ_MPSAFE))
panic("aiodoned");
}
mksysctls();
sysctl_finalize();
module_init_class(MODULE_CLASS_ANY);
rumpuser_gethostname(hostname, MAXHOSTNAMELEN, &error);
hostnamelen = strlen(hostname);
2007-12-31 02:29:06 +03:00
sigemptyset(&sigcantmask);
lwp0.l_fd = proc0.p_fd = fd_init(&rump_filedesc0);
if (rump_threads)
vmem_rehash_start();
rump_unschedule();
return 0;
}
2009-10-09 18:41:36 +04:00
/* maybe support sys_reboot some day for remote shutdown */
void
rump_reboot(int howto)
2009-10-09 18:41:36 +04:00
{
/* dump means we really take the dive here */
if ((howto & RB_DUMP) || panicstr) {
rumpuser_exit(RUMPUSER_PANIC);
/*NOTREACHED*/
}
/* try to sync */
if (!((howto & RB_NOSYNC) || panicstr)) {
rump_vfs_fini();
}
/* your wish is my command */
if (howto & RB_HALT) {
for (;;) {
uint64_t sec = 5, nsec = 0;
int error;
rumpuser_nanosleep(&sec, &nsec, &error);
}
}
rump_inited = -1;
}
struct uio *
rump_uio_setup(void *buf, size_t bufsize, off_t offset, enum rump_uiorw rw)
{
struct uio *uio;
enum uio_rw uiorw;
switch (rw) {
case RUMPUIO_READ:
uiorw = UIO_READ;
break;
case RUMPUIO_WRITE:
uiorw = UIO_WRITE;
break;
default:
panic("%s: invalid rw %d", __func__, rw);
}
uio = kmem_alloc(sizeof(struct uio), KM_SLEEP);
uio->uio_iov = kmem_alloc(sizeof(struct iovec), KM_SLEEP);
uio->uio_iov->iov_base = buf;
uio->uio_iov->iov_len = bufsize;
uio->uio_iovcnt = 1;
uio->uio_offset = offset;
uio->uio_resid = bufsize;
uio->uio_rw = uiorw;
uio->uio_vmspace = UIO_VMSPACE_SYS;
return uio;
}
size_t
rump_uio_getresid(struct uio *uio)
{
return uio->uio_resid;
}
off_t
rump_uio_getoff(struct uio *uio)
{
return uio->uio_offset;
}
size_t
rump_uio_free(struct uio *uio)
{
size_t resid;
resid = uio->uio_resid;
kmem_free(uio->uio_iov, sizeof(*uio->uio_iov));
kmem_free(uio, sizeof(*uio));
return resid;
}
static pid_t nextpid = 1;
struct lwp *
rump_newproc_switch()
{
struct lwp *l;
pid_t mypid;
mypid = atomic_inc_uint_nv(&nextpid);
if (__predict_false(mypid == 0))
mypid = atomic_inc_uint_nv(&nextpid);
l = rump_lwp_alloc(mypid, 0);
rump_lwp_switch(l);
return l;
}
struct lwp *
rump_lwp_alloc_and_switch(pid_t pid, lwpid_t lid)
{
struct lwp *l;
l = rump_lwp_alloc(pid, lid);
rump_lwp_switch(l);
return l;
}
struct lwp *
rump_lwp_alloc(pid_t pid, lwpid_t lid)
{
struct lwp *l;
struct proc *p;
l = kmem_zalloc(sizeof(*l), KM_SLEEP);
if (pid != 0) {
p = kmem_zalloc(sizeof(*p), KM_SLEEP);
2009-12-09 03:11:21 +03:00
if (rump_proc_vfs_init)
rump_proc_vfs_init(p);
p->p_stats = &rump_stats;
2010-04-21 20:16:31 +04:00
p->p_limit = lim_copy(&rump_limits);
p->p_pid = pid;
p->p_vmspace = &rump_vmspace;
p->p_emul = &emul_netbsd;
p->p_fd = fd_init(NULL);
2009-09-04 16:27:09 +04:00
p->p_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE);
p->p_pgrp = &rump_pgrp;
2009-11-06 18:22:33 +03:00
l->l_cred = rump_cred_suserget();
} else {
p = &proc0;
2009-11-06 18:22:33 +03:00
l->l_cred = rump_susercred;
}
l->l_proc = p;
l->l_lid = lid;
l->l_fd = p->p_fd;
l->l_cpu = NULL;
l->l_target_cpu = rump_cpu;
2010-04-13 02:17:23 +04:00
lwp_initspecific(l);
LIST_INSERT_HEAD(&alllwp, l, l_list);
return l;
}
void
rump_lwp_switch(struct lwp *newlwp)
{
struct lwp *l = curlwp;
rumpuser_set_curlwp(NULL);
newlwp->l_cpu = newlwp->l_target_cpu = l->l_cpu;
newlwp->l_mutex = l->l_mutex;
l->l_mutex = NULL;
l->l_cpu = NULL;
rumpuser_set_curlwp(newlwp);
if (l->l_flag & LW_WEXIT)
rump_lwp_free(l);
}
/* XXX: this has effect only on non-pid0 lwps */
void
rump_lwp_release(struct lwp *l)
{
struct proc *p;
p = l->l_proc;
if (p->p_pid != 0) {
2009-09-04 16:27:09 +04:00
mutex_obj_free(p->p_lock);
fd_free();
2009-12-09 03:11:21 +03:00
if (rump_proc_vfs_release)
rump_proc_vfs_release(p);
rump_cred_put(l->l_cred);
2010-04-21 20:16:31 +04:00
limfree(p->p_limit);
kmem_free(p, sizeof(*p));
}
KASSERT((l->l_flag & LW_WEXIT) == 0);
l->l_flag |= LW_WEXIT;
}
void
rump_lwp_free(struct lwp *l)
{
KASSERT(l->l_flag & LW_WEXIT);
KASSERT(l->l_mutex == NULL);
2010-02-09 19:53:13 +03:00
if (l->l_name)
kmem_free(l->l_name, MAXCOMLEN);
2010-04-13 02:17:23 +04:00
lwp_finispecific(l);
LIST_REMOVE(l, l_list);
kmem_free(l, sizeof(*l));
}
struct lwp *
rump_lwp_curlwp(void)
{
struct lwp *l = curlwp;
if (l->l_flag & LW_WEXIT)
return NULL;
return l;
}
/* rump private. NEEDS WORK! */
void
rump_set_vmspace(struct vmspace *vm)
{
struct proc *p = curproc;
p->p_vmspace = vm;
}
2008-09-30 23:25:56 +04:00
kauth_cred_t
rump_cred_create(uid_t uid, gid_t gid, size_t ngroups, gid_t *groups)
2008-09-30 23:25:56 +04:00
{
kauth_cred_t cred;
int rv;
cred = kauth_cred_alloc();
kauth_cred_setuid(cred, uid);
kauth_cred_seteuid(cred, uid);
kauth_cred_setsvuid(cred, uid);
kauth_cred_setgid(cred, gid);
kauth_cred_setgid(cred, gid);
kauth_cred_setegid(cred, gid);
kauth_cred_setsvgid(cred, gid);
rv = kauth_cred_setgroups(cred, groups, ngroups, 0, UIO_SYSSPACE);
/* oh this is silly. and by "this" I mean kauth_cred_setgroups() */
assert(rv == 0);
return cred;
}
void
rump_cred_put(kauth_cred_t cred)
2008-09-30 23:25:56 +04:00
{
kauth_cred_free(cred);
}
kauth_cred_t
rump_cred_suserget(void)
2008-09-30 23:25:56 +04:00
{
kauth_cred_hold(rump_susercred);
return rump_susercred;
}
/*
* Return the next system lwpid
*/
lwpid_t
rump_nextlid(void)
{
lwpid_t retid;
mutex_enter(proc0.p_lock);
/*
* Take next one, don't return 0
* XXX: most likely we'll have collisions in case this
* wraps around.
*/
if (++proc0.p_nlwpid == 0)
++proc0.p_nlwpid;
retid = proc0.p_nlwpid;
mutex_exit(proc0.p_lock);
return retid;
}
static int compcounter[RUMP_COMPONENT_MAX];
static void
rump_component_init_cb(struct rump_component *rc, int type)
{
KASSERT(type < RUMP_COMPONENT_MAX);
if (rc->rc_type == type) {
rc->rc_init();
compcounter[type]++;
}
}
int
rump_component_count(enum rump_component_type type)
{
KASSERT(type <= RUMP_COMPONENT_MAX);
return compcounter[type];
}
void
rump_component_init(enum rump_component_type type)
{
rumpuser_dl_component_init(type, rump_component_init_cb);
}
/*
* Initialize a module which has already been loaded and linked
* with dlopen(). This is fundamentally the same as a builtin module.
*/
int
rump_module_init(const struct modinfo * const *mip, size_t nmodinfo)
{
return module_builtin_add(mip, nmodinfo, true);
}
/*
* Finish module (flawless victory, fatality!).
*/
int
rump_module_fini(const struct modinfo *mi)
{
return module_builtin_remove(mi, true);
}
/*
* Add loaded and linked module to the builtin list. It will
* later be initialized with module_init_class().
*/
static void
add_linkedin_modules(const struct modinfo * const *mip, size_t nmodinfo)
{
module_builtin_add(mip, nmodinfo, false);
}
int
rump_kernelfsym_load(void *symtab, uint64_t symsize,
char *strtab, uint64_t strsize)
{
static int inited = 0;
Elf64_Ehdr ehdr;
if (inited)
return EBUSY;
inited = 1;
/*
* Use 64bit header since it's bigger. Shouldn't make a
* difference, since we're passing in all zeroes anyway.
*/
memset(&ehdr, 0, sizeof(ehdr));
ksyms_addsyms_explicit(&ehdr, symtab, symsize, strtab, strsize);
return 0;
}
static int
rump_sysproxy_local(int num, void *arg, uint8_t *data, size_t dlen,
register_t *retval)
{
struct lwp *l;
struct sysent *callp;
int rv;
if (__predict_false(num >= SYS_NSYSENT))
return ENOSYS;
callp = rump_sysent + num;
rump_schedule();
l = curlwp;
rv = sy_call(callp, l, (void *)data, retval);
rump_unschedule();
return rv;
}
int
rump_boot_gethowto()
{
return boothowto;
}
void
rump_boot_sethowto(int howto)
{
boothowto = howto;
}
rump_sysproxy_t rump_sysproxy = rump_sysproxy_local;
void *rump_sysproxy_arg;
/*
* This whole syscall-via-rpc is still taking form. For example, it
* may be necessary to set syscalls individually instead of lobbing
* them all to the same place. So don't think this interface is
* set in stone.
*/
int
rump_sysproxy_set(rump_sysproxy_t proxy, void *arg)
{
if (rump_sysproxy_arg)
return EBUSY;
rump_sysproxy_arg = arg;
rump_sysproxy = proxy;
return 0;
}
int
rump_getversion(void)
{
return __NetBSD_Version__;
}
/*
* Note: may be called unscheduled. Not fully safe since no locking
* of allevents (currently that's not even available).
*/
void
rump_printevcnts()
{
struct evcnt *ev;
TAILQ_FOREACH(ev, &allevents, ev_list)
rumpuser_dprintf("%s / %s: %" PRIu64 "\n",
ev->ev_group, ev->ev_name, ev->ev_count);
}