1 /* $NetBSD: sysproxy.c,v 1.10 2023/07/16 23:05:53 riastradh Exp $ */ 2 3 /* 4 * Copyright (c) 2010, 2011 Antti Kantee. All Rights Reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __KERNEL_RCSID(0, "$NetBSD: sysproxy.c,v 1.10 2023/07/16 23:05:53 riastradh Exp $"); 30 31 #include <sys/param.h> 32 #include <sys/filedesc.h> 33 #include <sys/kmem.h> 34 #include <sys/syscall.h> 35 #include <sys/syscallvar.h> 36 #include <sys/systm.h> 37 #include <sys/xcall.h> 38 #include <sys/lockdebug.h> 39 #include <sys/psref.h> 40 41 #if defined(__i386__) || defined(__x86_64__) 42 /* 43 * This file abuses the pmap abstraction to create its own statically 44 * allocated struct pmap object, even though it can't do anything 45 * useful with such a thing from userland. On x86 the struct pmap 46 * definition is private, so we have to go to extra effort to abuse it 47 * there. This should be fixed -- all of the struct pmap definitions 48 * should be private, and then rump can furnish its own fake struct 49 * pmap without clashing with anything. 50 */ 51 #include <machine/pmap_private.h> 52 #endif 53 54 #define _RUMP_SYSPROXY 55 #include <rump/rumpuser.h> 56 57 #include <rump-sys/kern.h> 58 59 int 60 rump_init_server(const char *url) 61 { 62 63 return rumpuser_sp_init(url, ostype, osrelease, MACHINE); 64 } 65 66 static pid_t 67 hyp_getpid(void) 68 { 69 70 return curproc->p_pid; 71 } 72 73 static int 74 hyp_syscall(int num, void *arg, long *retval) 75 { 76 register_t regrv[2] = {0, 0}; 77 struct lwp *l; 78 struct sysent *callp; 79 int rv; 80 81 if (__predict_false(num >= SYS_NSYSENT)) 82 return ENOSYS; 83 84 /* XXX: always uses native syscall vector */ 85 callp = rump_sysent + num; 86 l = curlwp; 87 rv = sy_invoke(callp, l, (void *)arg, regrv, num); 88 retval[0] = regrv[0]; 89 retval[1] = regrv[1]; 90 91 /* Sanity checks (from mi_userret) */ 92 LOCKDEBUG_BARRIER(NULL, 0); 93 KASSERT(l->l_nopreempt == 0); 94 PSREF_DEBUG_BARRIER(); 95 KASSERT(l->l_psrefs == 0); 96 97 return rv; 98 } 99 100 static struct pmap remotepmap; 101 102 static int 103 hyp_rfork(void *priv, int flags, const char *comm) 104 { 105 struct rump_spctl *spctl; 106 struct vmspace *vm; 107 struct proc *p; 108 struct lwp *l; 109 int error; 110 bool initfds; 111 112 /* 113 * If we are forking off of pid 1, initialize file descriptors. 114 */ 115 l = curlwp; 116 if (l->l_proc->p_pid == 1) { 117 KASSERT(flags == RUMP_RFFD_CLEAR); 118 initfds = true; 119 } else { 120 initfds = false; 121 } 122 123 /* 124 * Since it's a proxy proc, we create a vmspace for it. 125 */ 126 spctl = kmem_zalloc(sizeof(*spctl), KM_SLEEP); 127 vm = &spctl->spctl_vm; 128 uvmspace_init(vm, &remotepmap, 0, 0, false); 129 spctl->spctl = priv; 130 131 if ((error = rump_lwproc_rfork_vmspace(vm, flags)) != 0) { 132 kmem_free(vm, sizeof(*vm)); 133 return error; 134 } 135 136 /* 137 * We forked in this routine, so cannot use curlwp (const) 138 */ 139 l = rump_lwproc_curlwp(); 140 p = l->l_proc; 141 142 if (comm) 143 strlcpy(p->p_comm, comm, sizeof(p->p_comm)); 144 if (initfds) 145 rump_consdev_init(); 146 147 return 0; 148 } 149 150 /* 151 * Order all lwps in a process to exit. does *not* wait for them to drain. 152 */ 153 static void 154 hyp_lwpexit(void) 155 { 156 struct proc *p = curproc; 157 struct lwp *l; 158 159 mutex_enter(p->p_lock); 160 /* 161 * First pass: mark all lwps in the process with LW_RUMP_QEXIT 162 * so that they know they should exit. 163 */ 164 LIST_FOREACH(l, &p->p_lwps, l_sibling) { 165 if (l == curlwp) 166 continue; 167 l->l_flag |= LW_RUMP_QEXIT; 168 } 169 mutex_exit(p->p_lock); 170 171 /* 172 * Next, make sure everyone on all CPUs sees our status 173 * update. This keeps threads inside cv_wait() and makes 174 * sure we don't access a stale cv pointer later when 175 * we wake up the threads. 176 */ 177 178 xc_barrier(0); 179 180 /* 181 * Ok, all lwps are either: 182 * 1) not in the cv code 183 * 2) sleeping on l->l_sched.info 184 * 3) sleeping on p->p_waitcv 185 * 186 * Either way, l_sched.info is stable until we set 187 * PS_RUMP_LWPEXIT in p->p_sflag. 188 */ 189 190 mutex_enter(p->p_lock); 191 LIST_FOREACH(l, &p->p_lwps, l_sibling) { 192 if (l->l_sched.info) 193 cv_broadcast(l->l_sched.info); 194 } 195 p->p_sflag |= PS_RUMP_LWPEXIT; 196 cv_broadcast(&p->p_waitcv); 197 mutex_exit(p->p_lock); 198 } 199 200 /* 201 * Notify process that all threads have been drained and exec is complete. 202 */ 203 static void 204 hyp_execnotify(const char *comm) 205 { 206 struct proc *p = curproc; 207 208 fd_closeexec(); 209 mutex_enter(p->p_lock); 210 KASSERT(p->p_nlwps == 1 && p->p_sflag & PS_RUMP_LWPEXIT); 211 p->p_sflag &= ~PS_RUMP_LWPEXIT; 212 mutex_exit(p->p_lock); 213 strlcpy(p->p_comm, comm, sizeof(p->p_comm)); 214 } 215 216 /* 217 * Initialize interface pointers since component is present. 218 */ 219 RUMP_COMPONENT(RUMP_COMPONENT_KERN) 220 { 221 222 rump_sysproxy_ops.rspo_copyin = rumpuser_sp_copyin; 223 rump_sysproxy_ops.rspo_copyinstr = rumpuser_sp_copyinstr; 224 rump_sysproxy_ops.rspo_copyout = rumpuser_sp_copyout; 225 rump_sysproxy_ops.rspo_copyoutstr = rumpuser_sp_copyoutstr; 226 rump_sysproxy_ops.rspo_anonmmap = rumpuser_sp_anonmmap; 227 rump_sysproxy_ops.rspo_raise = rumpuser_sp_raise; 228 rump_sysproxy_ops.rspo_fini = rumpuser_sp_fini; 229 230 rump_sysproxy_ops.rspo_hyp_getpid = hyp_getpid; 231 rump_sysproxy_ops.rspo_hyp_syscall = hyp_syscall; 232 rump_sysproxy_ops.rspo_hyp_rfork = hyp_rfork; 233 rump_sysproxy_ops.rspo_hyp_lwpexit = hyp_lwpexit; 234 rump_sysproxy_ops.rspo_hyp_execnotify = hyp_execnotify; 235 } 236