Home | History | Annotate | Line # | Download | only in rumpkern
rump.c revision 1.81
      1 /*	$NetBSD: rump.c,v 1.81 2009/01/02 02:54:13 pooka Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2007 Antti Kantee.  All Rights Reserved.
      5  *
      6  * Development of this software was supported by Google Summer of Code.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     18  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     20  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27  * SUCH DAMAGE.
     28  */
     29 
     30 #include <sys/cdefs.h>
     31 __KERNEL_RCSID(0, "$NetBSD: rump.c,v 1.81 2009/01/02 02:54:13 pooka Exp $");
     32 
     33 #include <sys/param.h>
     34 #include <sys/atomic.h>
     35 #include <sys/buf.h>
     36 #include <sys/callout.h>
     37 #include <sys/conf.h>
     38 #include <sys/cpu.h>
     39 #include <sys/filedesc.h>
     40 #include <sys/iostat.h>
     41 #include <sys/kauth.h>
     42 #include <sys/kernel.h>
     43 #include <sys/kmem.h>
     44 #include <sys/kprintf.h>
     45 #include <sys/msgbuf.h>
     46 #include <sys/module.h>
     47 #include <sys/once.h>
     48 #include <sys/percpu.h>
     49 #include <sys/queue.h>
     50 #include <sys/resourcevar.h>
     51 #include <sys/select.h>
     52 #include <sys/uidinfo.h>
     53 #include <sys/sysctl.h>
     54 
     55 #include <rump/rumpuser.h>
     56 
     57 #include "rump_private.h"
     58 #include "rump_net_private.h"
     59 #include "rump_vfs_private.h"
     60 
     61 struct proc proc0;
     62 struct session rump_session = {
     63 	.s_count = 1,
     64 	.s_flags = 0,
     65 	.s_leader = &proc0,
     66 	.s_login = "rumphobo",
     67 	.s_sid = 0,
     68 };
     69 struct pgrp rump_pgrp = {
     70 	.pg_members = LIST_HEAD_INITIALIZER(pg_members),
     71 	.pg_session = &rump_session,
     72 	.pg_jobc = 1,
     73 };
     74 struct pstats rump_stats;
     75 struct plimit rump_limits;
     76 struct cpu_info rump_cpu;
     77 struct filedesc rump_filedesc0;
     78 struct proclist allproc;
     79 char machine[] = "rump";
     80 static kauth_cred_t rump_susercred;
     81 
     82 struct rumpuser_mtx *rump_giantlock;
     83 
     84 sigset_t sigcantmask;
     85 
     86 #ifdef RUMP_WITHOUT_THREADS
     87 int rump_threads = 0;
     88 #else
     89 int rump_threads = 1;
     90 #endif
     91 
     92 static void
     93 rump_aiodone_worker(struct work *wk, void *dummy)
     94 {
     95 	struct buf *bp = (struct buf *)wk;
     96 
     97 	KASSERT(&bp->b_work == wk);
     98 	bp->b_iodone(bp);
     99 }
    100 
    101 static int rump_inited;
    102 static struct emul emul_rump;
    103 
    104 void __rump_unavailable(void);
    105 void __rump_unavailable() {}
    106 __weak_alias(rump_net_init,__rump_unavailable);
    107 __weak_alias(rump_vfs_init,__rump_unavailable);
    108 
    109 static void
    110 pvfsinit_nop(struct proc *p)
    111 {
    112 
    113 	return;
    114 }
    115 
    116 static void
    117 pvfsrele_nop(struct proc *p)
    118 {
    119 
    120 	return;
    121 }
    122 
    123 rump_proc_vfs_init_fn rump_proc_vfs_init = pvfsinit_nop;
    124 rump_proc_vfs_release_fn rump_proc_vfs_release = pvfsrele_nop;
    125 
    126 int
    127 _rump_init(int rump_version)
    128 {
    129 	char buf[256];
    130 	struct proc *p;
    131 	struct lwp *l;
    132 	int error;
    133 
    134 	/* XXX */
    135 	if (rump_inited)
    136 		return 0;
    137 	rump_inited = 1;
    138 
    139 	if (rump_version != RUMP_VERSION) {
    140 		printf("rump version mismatch, %d vs. %d\n",
    141 		    rump_version, RUMP_VERSION);
    142 		return EPROGMISMATCH;
    143 	}
    144 
    145 	if (rumpuser_getenv("RUMP_NVNODES", buf, sizeof(buf), &error) == 0) {
    146 		desiredvnodes = strtoul(buf, NULL, 10);
    147 	} else {
    148 		desiredvnodes = 1<<16;
    149 	}
    150 	if (rumpuser_getenv("RUMP_THREADS", buf, sizeof(buf), &error) == 0) {
    151 		rump_threads = *buf != '0';
    152 	}
    153 
    154 	rumpuser_mutex_recursive_init(&rump_giantlock);
    155 
    156 	rumpvm_init();
    157 	rump_sleepers_init();
    158 #ifdef RUMP_USE_REAL_KMEM
    159 	kmem_init();
    160 #endif
    161 	kprintf_init();
    162 	loginit();
    163 
    164 	kauth_init();
    165 	rump_susercred = rump_cred_create(0, 0, 0, NULL);
    166 
    167 	l = &lwp0;
    168 	p = &proc0;
    169 	p->p_stats = &rump_stats;
    170 	p->p_limit = &rump_limits;
    171 	p->p_pgrp = &rump_pgrp;
    172 	p->p_pid = 0;
    173 	p->p_fd = &rump_filedesc0;
    174 	p->p_vmspace = &rump_vmspace;
    175 	p->p_emul = &emul_rump;
    176 	l->l_cred = rump_cred_suserget();
    177 	l->l_proc = p;
    178 	l->l_lid = 1;
    179 	LIST_INSERT_HEAD(&allproc, p, p_list);
    180 
    181 	rump_limits.pl_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
    182 	rump_limits.pl_rlimit[RLIMIT_NOFILE].rlim_cur = RLIM_INFINITY;
    183 	rump_limits.pl_rlimit[RLIMIT_SBSIZE].rlim_cur = RLIM_INFINITY;
    184 
    185 	rumpuser_thrinit();
    186 	callout_startup();
    187 	callout_init_cpu(&rump_cpu);
    188 
    189 	once_init();
    190 	iostat_init();
    191 	uid_init();
    192 	percpu_init();
    193 	fd_sys_init();
    194 	module_init();
    195 	sysctl_init();
    196 	softint_init(&rump_cpu);
    197 	cold = 0;
    198 	devsw_init();
    199 
    200 	/* these do nothing if not present */
    201 	rump_vfs_init();
    202 	rump_net_init();
    203 
    204 	/* aieeeedondest */
    205 	if (rump_threads) {
    206 		if (workqueue_create(&uvm.aiodone_queue, "aiodoned",
    207 		    rump_aiodone_worker, NULL, 0, 0, 0))
    208 			panic("aiodoned");
    209 	}
    210 
    211 	rumpuser_gethostname(hostname, MAXHOSTNAMELEN, &error);
    212 	hostnamelen = strlen(hostname);
    213 
    214 	sigemptyset(&sigcantmask);
    215 
    216 	lwp0.l_fd = proc0.p_fd = fd_init(&rump_filedesc0);
    217 
    218 	return 0;
    219 }
    220 
    221 struct uio *
    222 rump_uio_setup(void *buf, size_t bufsize, off_t offset, enum rump_uiorw rw)
    223 {
    224 	struct uio *uio;
    225 	enum uio_rw uiorw;
    226 
    227 	switch (rw) {
    228 	case RUMPUIO_READ:
    229 		uiorw = UIO_READ;
    230 		break;
    231 	case RUMPUIO_WRITE:
    232 		uiorw = UIO_WRITE;
    233 		break;
    234 	default:
    235 		panic("%s: invalid rw %d", __func__, rw);
    236 	}
    237 
    238 	uio = kmem_alloc(sizeof(struct uio), KM_SLEEP);
    239 	uio->uio_iov = kmem_alloc(sizeof(struct iovec), KM_SLEEP);
    240 
    241 	uio->uio_iov->iov_base = buf;
    242 	uio->uio_iov->iov_len = bufsize;
    243 
    244 	uio->uio_iovcnt = 1;
    245 	uio->uio_offset = offset;
    246 	uio->uio_resid = bufsize;
    247 	uio->uio_rw = uiorw;
    248 	uio->uio_vmspace = UIO_VMSPACE_SYS;
    249 
    250 	return uio;
    251 }
    252 
    253 size_t
    254 rump_uio_getresid(struct uio *uio)
    255 {
    256 
    257 	return uio->uio_resid;
    258 }
    259 
    260 off_t
    261 rump_uio_getoff(struct uio *uio)
    262 {
    263 
    264 	return uio->uio_offset;
    265 }
    266 
    267 size_t
    268 rump_uio_free(struct uio *uio)
    269 {
    270 	size_t resid;
    271 
    272 	resid = uio->uio_resid;
    273 	kmem_free(uio->uio_iov, sizeof(*uio->uio_iov));
    274 	kmem_free(uio, sizeof(*uio));
    275 
    276 	return resid;
    277 }
    278 
    279 struct lwp *
    280 rump_setup_curlwp(pid_t pid, lwpid_t lid, int set)
    281 {
    282 	struct lwp *l;
    283 	struct proc *p;
    284 
    285 	l = kmem_zalloc(sizeof(struct lwp), KM_SLEEP);
    286 	if (pid != 0) {
    287 		p = kmem_zalloc(sizeof(struct proc), KM_SLEEP);
    288 		rump_proc_vfs_init(p);
    289 		p->p_stats = &rump_stats;
    290 		p->p_limit = &rump_limits;
    291 		p->p_pid = pid;
    292 		p->p_vmspace = &rump_vmspace;
    293 		p->p_fd = fd_init(NULL);
    294 	} else {
    295 		p = &proc0;
    296 	}
    297 
    298 	l->l_cred = rump_cred_suserget();
    299 	l->l_proc = p;
    300 	l->l_lid = lid;
    301 	l->l_fd = p->p_fd;
    302 	l->l_mutex = RUMP_LMUTEX_MAGIC;
    303 	l->l_cpu = &rump_cpu;
    304 
    305 	if (set)
    306 		rumpuser_set_curlwp(l);
    307 
    308 	return l;
    309 }
    310 
    311 void
    312 rump_clear_curlwp()
    313 {
    314 	struct lwp *l;
    315 
    316 	l = rumpuser_get_curlwp();
    317 	if (l->l_proc->p_pid != 0) {
    318 		fd_free();
    319 		rump_proc_vfs_release(l->l_proc);
    320 		rump_cred_destroy(l->l_cred);
    321 		kmem_free(l->l_proc, sizeof(*l->l_proc));
    322 	}
    323 	kmem_free(l, sizeof(*l));
    324 	rumpuser_set_curlwp(NULL);
    325 }
    326 
    327 struct lwp *
    328 rump_get_curlwp()
    329 {
    330 	struct lwp *l;
    331 
    332 	l = rumpuser_get_curlwp();
    333 	if (l == NULL)
    334 		l = &lwp0;
    335 
    336 	return l;
    337 }
    338 
    339 int
    340 rump_splfoo()
    341 {
    342 
    343 	if (rumpuser_whatis_ipl() != RUMPUSER_IPL_INTR) {
    344 		rumpuser_rw_enter(&rumpspl, 0);
    345 		rumpuser_set_ipl(RUMPUSER_IPL_SPLFOO);
    346 	}
    347 
    348 	return 0;
    349 }
    350 
    351 void
    352 rump_intr_enter(void)
    353 {
    354 
    355 	rumpuser_set_ipl(RUMPUSER_IPL_INTR);
    356 	rumpuser_rw_enter(&rumpspl, 1);
    357 }
    358 
    359 void
    360 rump_intr_exit(void)
    361 {
    362 
    363 	rumpuser_rw_exit(&rumpspl);
    364 	rumpuser_clear_ipl(RUMPUSER_IPL_INTR);
    365 }
    366 
    367 void
    368 rump_splx(int dummy)
    369 {
    370 
    371 	if (rumpuser_whatis_ipl() != RUMPUSER_IPL_INTR) {
    372 		rumpuser_clear_ipl(RUMPUSER_IPL_SPLFOO);
    373 		rumpuser_rw_exit(&rumpspl);
    374 	}
    375 }
    376 
    377 kauth_cred_t
    378 rump_cred_create(uid_t uid, gid_t gid, size_t ngroups, gid_t *groups)
    379 {
    380 	kauth_cred_t cred;
    381 	int rv;
    382 
    383 	cred = kauth_cred_alloc();
    384 	kauth_cred_setuid(cred, uid);
    385 	kauth_cred_seteuid(cred, uid);
    386 	kauth_cred_setsvuid(cred, uid);
    387 	kauth_cred_setgid(cred, gid);
    388 	kauth_cred_setgid(cred, gid);
    389 	kauth_cred_setegid(cred, gid);
    390 	kauth_cred_setsvgid(cred, gid);
    391 	rv = kauth_cred_setgroups(cred, groups, ngroups, 0, UIO_SYSSPACE);
    392 	/* oh this is silly.  and by "this" I mean kauth_cred_setgroups() */
    393 	assert(rv == 0);
    394 
    395 	return cred;
    396 }
    397 
    398 void
    399 rump_cred_destroy(kauth_cred_t cred)
    400 {
    401 
    402 	kauth_cred_free(cred);
    403 }
    404 
    405 kauth_cred_t
    406 rump_cred_suserget()
    407 {
    408 
    409 	kauth_cred_hold(rump_susercred);
    410 	return rump_susercred;
    411 }
    412 
    413 /* XXX: if they overflow, we're screwed */
    414 lwpid_t
    415 rump_nextlid()
    416 {
    417 	static unsigned lwpid = 2;
    418 
    419 	do {
    420 		lwpid = atomic_inc_uint_nv(&lwpid);
    421 	} while (lwpid == 0);
    422 
    423 	return (lwpid_t)lwpid;
    424 }
    425 
    426 int
    427 rump_module_load(struct modinfo **mi)
    428 {
    429 
    430 	if (!module_compatible((*mi)->mi_version, __NetBSD_Version__))
    431 		return EPROGMISMATCH;
    432 
    433 	return (*mi)->mi_modcmd(MODULE_CMD_INIT, NULL);
    434 }
    435 
    436 int _syspuffs_stub(int, int *);
    437 int
    438 _syspuffs_stub(int fd, int *newfd)
    439 {
    440 
    441 	return ENODEV;
    442 }
    443 __weak_alias(syspuffs_glueinit,_syspuffs_stub);
    444