xref: /netbsd-src/sys/rump/librump/rumpkern/emul.c (revision ac23d067c9b405eaca9444bc96d80159a491e22d)
1*ac23d067Sbad /*	$NetBSD: emul.c,v 1.202 2024/07/28 13:01:55 bad Exp $	*/
2daafee87Spooka 
3daafee87Spooka /*
423bbd0e0Spooka  * Copyright (c) 2007-2011 Antti Kantee.  All Rights Reserved.
5daafee87Spooka  *
6daafee87Spooka  * Redistribution and use in source and binary forms, with or without
7daafee87Spooka  * modification, are permitted provided that the following conditions
8daafee87Spooka  * are met:
9daafee87Spooka  * 1. Redistributions of source code must retain the above copyright
10daafee87Spooka  *    notice, this list of conditions and the following disclaimer.
11daafee87Spooka  * 2. Redistributions in binary form must reproduce the above copyright
12daafee87Spooka  *    notice, this list of conditions and the following disclaimer in the
13daafee87Spooka  *    documentation and/or other materials provided with the distribution.
14daafee87Spooka  *
15daafee87Spooka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16daafee87Spooka  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17daafee87Spooka  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18daafee87Spooka  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19daafee87Spooka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20daafee87Spooka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21daafee87Spooka  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22daafee87Spooka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23daafee87Spooka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24daafee87Spooka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25daafee87Spooka  * SUCH DAMAGE.
26daafee87Spooka  */
27daafee87Spooka 
28a768afd6Spooka #include <sys/cdefs.h>
29*ac23d067Sbad __KERNEL_RCSID(0, "$NetBSD: emul.c,v 1.202 2024/07/28 13:01:55 bad Exp $");
30cfd4dc8fSpooka 
31daafee87Spooka #include <sys/param.h>
3285df50f3Spooka #include <sys/cprng.h>
33934cd9a8Spooka #include <sys/filedesc.h>
348a83906aShannken #include <sys/fstrans.h>
3585df50f3Spooka #include <sys/kauth.h>
369a722ef7Spooka #include <sys/module.h>
37167269d4Spooka #include <sys/reboot.h>
38e1ef9449Spooka #include <sys/syscall.h>
399e8ba65aSozaki-r #include <sys/pserialize.h>
40eef1a9e4Sozaki-r #ifdef LOCKDEBUG
41eef1a9e4Sozaki-r #include <sys/sleepq.h>
42eef1a9e4Sozaki-r #endif
4306525b99Sriastradh #include <sys/syncobj.h>
44167269d4Spooka 
45167269d4Spooka #include <dev/cons.h>
46daafee87Spooka 
476bb51422Spooka #include <rump-sys/kern.h>
48bdf6e0b0Spooka 
496bb51422Spooka #include <rump/rumpuser.h>
50daafee87Spooka 
512cd42818Spooka void (*rump_vfs_fini)(void) = (void *)nullop;
522cd42818Spooka 
530ec2770cSpooka /*
540ec2770cSpooka  * physmem is largely unused (except for nmbcluster calculations),
550ec2770cSpooka  * so pick a default value which suits ZFS.  if an application wants
560ec2770cSpooka  * a very small memory footprint, it can still adjust this before
570ec2770cSpooka  * calling rump_init()
580ec2770cSpooka  */
590ec2770cSpooka #define PHYSMEM 512*256
603a405f03Scherry psize_t physmem = PHYSMEM;
61c1da2a84Sskrll size_t nkmempages = PHYSMEM/2; /* from le chapeau */
620ec2770cSpooka #undef PHYSMEM
630ec2770cSpooka 
64daafee87Spooka struct vnode *rootvp;
6559e540bbSpooka dev_t rootdev = NODEV;
660ec2770cSpooka 
67f48aa71aSpooka const int schedppq = 1;
689a722ef7Spooka int cold = 1;
69d6c967bbSthorpej int shutting_down;
70dfd2ba19Spooka int boothowto = AB_SILENT;
71167269d4Spooka struct tty *constty;
72daafee87Spooka 
7353d420f9Spooka const struct bdevsw *bdevsw0[255];
74614c3350Spooka const struct bdevsw **bdevsw = bdevsw0;
75*ac23d067Sbad const int sys_bdevsws = 255;
76*ac23d067Sbad int max_bdevsws = 255;
77614c3350Spooka 
7853d420f9Spooka const struct cdevsw *cdevsw0[255];
79614c3350Spooka const struct cdevsw **cdevsw = cdevsw0;
80*ac23d067Sbad const int sys_cdevsws = 255;
81*ac23d067Sbad int max_cdevsws = 255;
82614c3350Spooka 
8307334a46Spooka int mem_no = 2;
8407334a46Spooka 
85cbab9cadSchs device_t booted_device;
86cbab9cadSchs device_t booted_wedge;
8774e84221Smanu daddr_t booted_startblk;
8874e84221Smanu uint64_t booted_nblks;
89f42da039Spooka int booted_partition;
903284574bSchristos const char *booted_method;
91f42da039Spooka 
9288447903Spooka /* XXX: unused */
9307334a46Spooka kmutex_t tty_lock;
9488447903Spooka krwlock_t exec_lock;
95614c3350Spooka 
9683474ef4Spooka /* sparc doesn't sport constant page size, pretend we have 4k pages */
97d502da58Spooka #ifdef __sparc__
98d502da58Spooka int nbpg = 4096;
9983474ef4Spooka int pgofset = 4096-1;
10083474ef4Spooka int pgshift = 12;
101d502da58Spooka #endif
102d502da58Spooka 
1038e16588bStsutsui /* on sun3 VM_MAX_ADDRESS is a const variable */
1048e16588bStsutsui /* XXX: should be moved into rump.c and initialize for sun3 and sun3x? */
105a2b72aafSpooka #ifdef sun3
1068e16588bStsutsui const vaddr_t kernbase = KERNBASE3;
1077ed9d6c4Spooka #endif
1087ed9d6c4Spooka 
1098bb03ea9Spooka struct loadavg averunnable = {
1108bb03ea9Spooka 	{ 0 * FSCALE,
1118bb03ea9Spooka 	  1 * FSCALE,
1128bb03ea9Spooka 	  11 * FSCALE, },
1138bb03ea9Spooka 	FSCALE,
1148bb03ea9Spooka };
1158bb03ea9Spooka 
116e04dc482Spgoyette /*
117e04dc482Spgoyette  * Include the autogenerated list of auto-loadable syscalls
118e04dc482Spgoyette  */
119e04dc482Spgoyette #include <kern/syscalls_autoload.c>
120e04dc482Spgoyette 
1218b923892Spooka struct emul emul_netbsd = {
1228b923892Spooka 	.e_name = "netbsd-rump",
1238b923892Spooka 	.e_sysent = rump_sysent,
1243cd7406aSpgoyette 	.e_nomodbits = rump_sysent_nomodbits,
125e1ef9449Spooka #ifndef __HAVE_MINIMAL_EMUL
126e1ef9449Spooka 	.e_nsysent = SYS_NSYSENT,
127e1ef9449Spooka #endif
1289cf6a575Spooka 	.e_vm_default_addr = uvm_default_mapaddr,
129eacf4402Spooka #ifdef __HAVE_SYSCALL_INTERN
130eacf4402Spooka 	.e_syscall_intern = syscall_intern,
131eacf4402Spooka #endif
132e04dc482Spgoyette 	.e_sc_autoload = netbsd_syscalls_autoload,
1338b923892Spooka };
1348b923892Spooka 
1350d177642Spooka /* not used, but need the symbols for pointer comparisons */
1360d177642Spooka syncobj_t mutex_syncobj, rw_syncobj;
1370d177642Spooka 
1384f69d01dSpooka int
1394f69d01dSpooka kpause(const char *wmesg, bool intr, int timeo, kmutex_t *mtx)
1404f69d01dSpooka {
1414f69d01dSpooka 	extern int hz;
142129ca10eSjustin 	int rv __diagused;
1438c19023aSpooka 	uint64_t sec, nsec;
1444f69d01dSpooka 
1454f69d01dSpooka 	if (mtx)
1464f69d01dSpooka 		mutex_exit(mtx);
147441a8c67Spooka 
1488c19023aSpooka 	sec = timeo / hz;
1498c19023aSpooka 	nsec = (timeo % hz) * (1000000000 / hz);
150152588e3Spooka 	rv = rumpuser_clock_sleep(RUMPUSER_CLOCK_RELWALL, sec, nsec);
151a53a2a53Spooka 	KASSERT(rv == 0);
152441a8c67Spooka 
1534f69d01dSpooka 	if (mtx)
1544f69d01dSpooka 		mutex_enter(mtx);
1554f69d01dSpooka 
1564f69d01dSpooka 	return 0;
1574f69d01dSpooka }
158fb310736Spooka 
159c3c197baSyamt vaddr_t
16082aa1e7eSpara calc_cache_size(vsize_t vasz, int pct, int va_pct)
161c3c197baSyamt {
162c3c197baSyamt 	paddr_t t;
163c3c197baSyamt 
164c3c197baSyamt 	t = (paddr_t)physmem * pct / 100 * PAGE_SIZE;
165c3c197baSyamt 	if ((vaddr_t)t != t) {
166c3c197baSyamt 		panic("%s: needs tweak", __func__);
167c3c197baSyamt 	}
168c3c197baSyamt 	return t;
169c3c197baSyamt }
17099c43f07Smartin 
171683f5aa5Sozaki-r #define	RETURN_ADDRESS	(uintptr_t)__builtin_return_address(0)
172683f5aa5Sozaki-r 
173d496f014Spooka void
174d496f014Spooka assert_sleepable(void)
175d496f014Spooka {
176683f5aa5Sozaki-r 	const char *reason = NULL;
177d496f014Spooka 
178d496f014Spooka 	/* always sleepable, although we should improve this */
179683f5aa5Sozaki-r 
180683f5aa5Sozaki-r 	if (!pserialize_not_in_read_section()) {
181683f5aa5Sozaki-r 		reason = "pserialize";
182683f5aa5Sozaki-r 	}
183683f5aa5Sozaki-r 
184683f5aa5Sozaki-r 	if (reason) {
185683f5aa5Sozaki-r 		panic("%s: %s caller=%p", __func__, reason,
186683f5aa5Sozaki-r 		    (void *)RETURN_ADDRESS);
187683f5aa5Sozaki-r 	}
188d496f014Spooka }
1894a0d2098Spooka 
1909a722ef7Spooka void
191df7f595eScegger module_init_md(void)
1929a722ef7Spooka {
1939a722ef7Spooka 
1949a722ef7Spooka 	/*
1959a722ef7Spooka 	 * Nothing for now.  However, we should load the librump
1969a722ef7Spooka 	 * symbol table.
1979a722ef7Spooka 	 */
1989a722ef7Spooka }
199167269d4Spooka 
200ef964280Spooka /*
201ef964280Spooka  * Try to emulate all the MD definitions of DELAY() / delay().
202ef964280Spooka  * Would be nice to fix the #defines in MD headers, but this quicker.
203a0d2bb5eSpooka  *
204a0d2bb5eSpooka  * XXX: we'd need a rumpuser_clock_sleep_nowrap() here.  Since we
205a0d2bb5eSpooka  * don't have it in the current hypercall revision, busyloop.
206a0d2bb5eSpooka  * Note that rather than calibrate a loop delay and work with that,
207a0d2bb5eSpooka  * get call gettime (which does not block) in a loop to make sure
208a0d2bb5eSpooka  * we didn't get virtual ghosttime.  That might be slightly inaccurate
209a0d2bb5eSpooka  * for very small delays ...
210a0d2bb5eSpooka  *
211a0d2bb5eSpooka  * The other option would be to run a thread in the hypervisor which
212a0d2bb5eSpooka  * sleeps for us and we can wait for it using rumpuser_cv_wait_nowrap()
213a0d2bb5eSpooka  * Probably too fussy.  Better just wait for hypercall rev 18 ;)
214ef964280Spooka  */
215055c86bdSpooka static void
216055c86bdSpooka rump_delay(unsigned int us)
217167269d4Spooka {
218a0d2bb5eSpooka 	struct timespec target, tmp;
219a0d2bb5eSpooka 	uint64_t sec, sec_ini, sec_now;
220a0d2bb5eSpooka 	long nsec, nsec_ini, nsec_now;
221a0d2bb5eSpooka 	int loops;
222a0d2bb5eSpooka 
223a0d2bb5eSpooka 	rumpuser_clock_gettime(RUMPUSER_CLOCK_ABSMONO, &sec_ini, &nsec_ini);
224167269d4Spooka 
225ef964280Spooka #ifdef __mac68k__
226ef964280Spooka 	sec = us / 1000;
227ef964280Spooka 	nsec = (us % 1000) * 1000000;
228ef964280Spooka #else
2298c19023aSpooka 	sec = us / 1000000;
2308c19023aSpooka 	nsec = (us % 1000000) * 1000;
231ef964280Spooka #endif
232167269d4Spooka 
233a0d2bb5eSpooka 	target.tv_sec = sec_ini;
234a0d2bb5eSpooka 	tmp.tv_sec = sec;
235a0d2bb5eSpooka 	target.tv_nsec = nsec_ini;
236a0d2bb5eSpooka 	tmp.tv_nsec = nsec;
237a0d2bb5eSpooka 	timespecadd(&target, &tmp, &target);
238a0d2bb5eSpooka 
2398c19023aSpooka 	if (__predict_false(sec != 0))
240167269d4Spooka 		printf("WARNING: over 1s delay\n");
241167269d4Spooka 
242a0d2bb5eSpooka 	for (loops = 0; loops < 1000*1000*100; loops++) {
243a0d2bb5eSpooka 		struct timespec cur;
244a0d2bb5eSpooka 
245a0d2bb5eSpooka 		rumpuser_clock_gettime(RUMPUSER_CLOCK_ABSMONO,
246a0d2bb5eSpooka 		    &sec_now, &nsec_now);
247a0d2bb5eSpooka 		cur.tv_sec = sec_now;
248a0d2bb5eSpooka 		cur.tv_nsec = nsec_now;
249a0d2bb5eSpooka 		if (timespeccmp(&cur, &target, >=)) {
250a0d2bb5eSpooka 			return;
251a0d2bb5eSpooka 		}
252a0d2bb5eSpooka 	}
253a0d2bb5eSpooka 	printf("WARNING: DELAY ESCAPED\n");
254167269d4Spooka }
255055c86bdSpooka void (*delay_func)(unsigned int) = rump_delay;
256ef964280Spooka __strong_alias(delay,rump_delay);
257ef964280Spooka __strong_alias(_delay,rump_delay);
258167269d4Spooka 
25967d3f625Skre /* Weak alias for getcwd_common to be used unless librumpvfs is present. */
26067d3f625Skre 
26167d3f625Skre int rump_getcwd_common(struct vnode *, struct vnode *, char **, char *,
26267d3f625Skre     int, int, struct lwp *);
26367d3f625Skre int
26467d3f625Skre rump_getcwd_common(struct vnode *lvp, struct vnode *rvp, char **bpp, char *bufp,
26567d3f625Skre     int limit, int flags, struct lwp *l)
26667d3f625Skre {
26767d3f625Skre 
26867d3f625Skre 	return ENOENT;
26967d3f625Skre }
27067d3f625Skre __weak_alias(getcwd_common,rump_getcwd_common);
27167d3f625Skre 
272c3c178f6Sbad /* Weak alias for vnode_to_path to be used unless librumpvfs is present. */
273c3c178f6Sbad 
274c3c178f6Sbad int rump_vnode_to_path(char *, size_t, struct vnode *, struct lwp *,
275c3c178f6Sbad     struct proc *);
276c3c178f6Sbad int
277c3c178f6Sbad rump_vnode_to_path(char *path, size_t len, struct vnode *vp, struct lwp *curl,
278c3c178f6Sbad     struct proc *p)
279c3c178f6Sbad {
280c3c178f6Sbad 
281c3c178f6Sbad 	return ENOENT; /* pretend getcwd_common() failed. */
282c3c178f6Sbad }
283c3c178f6Sbad __weak_alias(vnode_to_path,rump_vnode_to_path);
284c3c178f6Sbad 
285c3c178f6Sbad 
2868a83906aShannken /* Weak aliases for fstrans to be used unless librumpvfs is present. */
2878a83906aShannken 
288287643b0Shannken void rump_fstrans_start(struct mount *);
289287643b0Shannken void
290287643b0Shannken rump_fstrans_start(struct mount *mp)
291287643b0Shannken {
292287643b0Shannken 
293287643b0Shannken }
294287643b0Shannken __weak_alias(fstrans_start,rump_fstrans_start);
295287643b0Shannken 
296287643b0Shannken int rump_fstrans_start_nowait(struct mount *);
2978a83906aShannken int
298287643b0Shannken rump_fstrans_start_nowait(struct mount *mp)
2998a83906aShannken {
3008a83906aShannken 
3018a83906aShannken 	return 0;
3028a83906aShannken }
303287643b0Shannken __weak_alias(fstrans_start_nowait,rump_fstrans_start_nowait);
3048a83906aShannken 
305fef73d22Shannken void rump_fstrans_start_lazy(struct mount *);
306fef73d22Shannken void
307fef73d22Shannken rump_fstrans_start_lazy(struct mount *mp)
308fef73d22Shannken {
309fef73d22Shannken 
310fef73d22Shannken }
311fef73d22Shannken __weak_alias(fstrans_start_lazy,rump_fstrans_start_lazy);
312fef73d22Shannken 
313fef73d22Shannken 
3148a83906aShannken void rump_fstrans_done(struct mount *);
3158a83906aShannken void
3168a83906aShannken rump_fstrans_done(struct mount *mp)
3178a83906aShannken {
3188a83906aShannken 
3198a83906aShannken }
3208a83906aShannken __weak_alias(fstrans_done,rump_fstrans_done);
3218a83906aShannken 
32201a7e2e4Shannken 
32301a7e2e4Shannken void rump_fstrans_lwp_dtor(struct lwp *);
32401a7e2e4Shannken void
32501a7e2e4Shannken rump_fstrans_lwp_dtor(struct lwp *l)
32601a7e2e4Shannken {
32701a7e2e4Shannken 
32801a7e2e4Shannken }
32901a7e2e4Shannken __weak_alias(fstrans_lwp_dtor,rump_fstrans_lwp_dtor);
33001a7e2e4Shannken 
33140ce89a2Sriastradh static int
33240ce89a2Sriastradh rump_filt_fsattach(struct knote *kn)
33340ce89a2Sriastradh {
33440ce89a2Sriastradh 
33540ce89a2Sriastradh 	return EOPNOTSUPP;
33640ce89a2Sriastradh }
33740ce89a2Sriastradh 
33840ce89a2Sriastradh struct filterops rump_fs_filtops = {
33940ce89a2Sriastradh 	.f_attach = rump_filt_fsattach,
34040ce89a2Sriastradh };
34140ce89a2Sriastradh __weak_alias(fs_filtops,rump_fs_filtops);
34240ce89a2Sriastradh 
34301ab3089Sriastradh struct pool_cache *rump_pnbuf_cache;
34401ab3089Sriastradh __weak_alias(pnbuf_cache,rump_pnbuf_cache);
34501ab3089Sriastradh 
34607333402Spooka /*
34707333402Spooka  * Provide weak aliases for tty routines used by printf.
34807333402Spooka  * They will be used unless the rumpkern_tty component is present.
34907333402Spooka  */
35007333402Spooka 
35107333402Spooka int rump_ttycheckoutq(struct tty *, int);
352a69d5558Spooka int
35307333402Spooka rump_ttycheckoutq(struct tty *tp, int wait)
354167269d4Spooka {
355167269d4Spooka 
356167269d4Spooka 	return 1;
357167269d4Spooka }
35807333402Spooka __weak_alias(ttycheckoutq,rump_ttycheckoutq);
359167269d4Spooka 
36007333402Spooka int rump_tputchar(int, int, struct tty *);
36107333402Spooka int
36207333402Spooka rump_tputchar(int c, int flags, struct tty *tp)
36307333402Spooka {
36407333402Spooka 
36507333402Spooka 	cnputc(c);
36607333402Spooka 	return 0;
36707333402Spooka }
36807333402Spooka __weak_alias(tputchar,rump_tputchar);
36907333402Spooka 
370167269d4Spooka void
371167269d4Spooka cnputc(int c)
372167269d4Spooka {
373167269d4Spooka 
37432a34307Spooka 	rumpuser_putchar(c);
375167269d4Spooka }
376167269d4Spooka 
377167269d4Spooka void
378df7f595eScegger cnflush(void)
379167269d4Spooka {
380167269d4Spooka 
381167269d4Spooka 	/* done */
382167269d4Spooka }
383167269d4Spooka 
384b7c666f3Spooka void
385b7c666f3Spooka resettodr(void)
386b7c666f3Spooka {
387b7c666f3Spooka 
388b7c666f3Spooka 	/* setting clocks is not in the jurisdiction of rump kernels */
389b7c666f3Spooka }
390b7c666f3Spooka 
391eacf4402Spooka #ifdef __HAVE_SYSCALL_INTERN
392eacf4402Spooka void
393eacf4402Spooka syscall_intern(struct proc *p)
394eacf4402Spooka {
395eacf4402Spooka 
396f5bd9f40Spooka 	p->p_emuldata = NULL;
397eacf4402Spooka }
398eacf4402Spooka #endif
399c15f18f4Spooka 
400cd73d116Spooka #ifdef LOCKDEBUG
401cd73d116Spooka void
402cd73d116Spooka turnstile_print(volatile void *obj, void (*pr)(const char *, ...))
403cd73d116Spooka {
404cd73d116Spooka 
405cd73d116Spooka 	/* nada */
406cd73d116Spooka }
407cd73d116Spooka #endif
4082cd42818Spooka 
4092cd42818Spooka void
4102cd42818Spooka cpu_reboot(int howto, char *bootstr)
4112cd42818Spooka {
4122cd42818Spooka 	int ruhow = 0;
4132cd42818Spooka 	void *finiarg;
4142cd42818Spooka 
4152cd42818Spooka 	printf("rump kernel halting...\n");
4162cd42818Spooka 
4172cd42818Spooka 	if (!RUMP_LOCALPROC_P(curproc))
4186195daadSpooka 		finiarg = RUMP_SPVM2CTL(curproc->p_vmspace);
4192cd42818Spooka 	else
4202cd42818Spooka 		finiarg = NULL;
4212cd42818Spooka 
4222cd42818Spooka 	/* dump means we really take the dive here */
4232cd42818Spooka 	if ((howto & RB_DUMP) || panicstr) {
4242cd42818Spooka 		ruhow = RUMPUSER_PANIC;
4252cd42818Spooka 		goto out;
4262cd42818Spooka 	}
4272cd42818Spooka 
4282cd42818Spooka 	/* try to sync */
4292cd42818Spooka 	if (!((howto & RB_NOSYNC) || panicstr)) {
4302cd42818Spooka 		rump_vfs_fini();
4312cd42818Spooka 	}
4322cd42818Spooka 
4332cd42818Spooka 	doshutdownhooks();
4342cd42818Spooka 
4352cd42818Spooka 	/* your wish is my command */
4362cd42818Spooka 	if (howto & RB_HALT) {
4375ede295bSpooka 		printf("rump kernel halted (with RB_HALT, not exiting)\n");
438787cba47Spooka 		rump_sysproxy_fini(finiarg);
4392cd42818Spooka 		for (;;) {
4402cd42818Spooka 			rumpuser_clock_sleep(RUMPUSER_CLOCK_RELWALL, 10, 0);
4412cd42818Spooka 		}
4422cd42818Spooka 	}
4432cd42818Spooka 
4442cd42818Spooka 	/* this function is __dead, we must exit */
4452cd42818Spooka  out:
446787cba47Spooka 	rump_sysproxy_fini(finiarg);
4472cd42818Spooka 	rumpuser_exit(ruhow);
4482cd42818Spooka }
449