linux_emul.c revision 293494
11638Srgrimes/*- 21638Srgrimes * Copyright (c) 2006 Roman Divacky 31638Srgrimes * Copyright (c) 2013 Dmitry Chagin 41638Srgrimes * All rights reserved. 51638Srgrimes * 61638Srgrimes * Redistribution and use in source and binary forms, with or without 71638Srgrimes * modification, are permitted provided that the following conditions 81638Srgrimes * are met: 91638Srgrimes * 1. Redistributions of source code must retain the above copyright 101638Srgrimes * notice, this list of conditions and the following disclaimer 111638Srgrimes * in this position and unchanged. 121638Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 131638Srgrimes * notice, this list of conditions and the following disclaimer in the 141638Srgrimes * documentation and/or other materials provided with the distribution. 151638Srgrimes * 3. The name of the author may not be used to endorse or promote products 161638Srgrimes * derived from this software without specific prior written permission 171638Srgrimes * 181638Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 191638Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 201638Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 211638Srgrimes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 221638Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 231638Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 241638Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 251638Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 261638Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 271638Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 281638Srgrimes */ 291638Srgrimes 301638Srgrimes#include <sys/cdefs.h> 311638Srgrimes__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_emul.c 293494 2016-01-09 15:17:34Z dchagin $"); 321638Srgrimes 331638Srgrimes#include "opt_compat.h" 341638Srgrimes#include "opt_kdtrace.h" 351638Srgrimes 361638Srgrimes#include <sys/param.h> 371638Srgrimes#include <sys/systm.h> 381638Srgrimes#include <sys/imgact.h> 391638Srgrimes#include <sys/kernel.h> 401638Srgrimes#include <sys/ktr.h> 411638Srgrimes#include <sys/lock.h> 421638Srgrimes#include <sys/malloc.h> 431638Srgrimes#include <sys/mutex.h> 441638Srgrimes#include <sys/sdt.h> 451638Srgrimes#include <sys/sx.h> 461638Srgrimes#include <sys/proc.h> 471638Srgrimes#include <sys/syscallsubr.h> 481638Srgrimes#include <sys/sysent.h> 491638Srgrimes#include <sys/sysproto.h> 501638Srgrimes#include <sys/unistd.h> 511638Srgrimes 521638Srgrimes#ifdef COMPAT_LINUX32 531638Srgrimes#include <machine/../linux32/linux.h> 541638Srgrimes#include <machine/../linux32/linux32_proto.h> 551638Srgrimes#else 561638Srgrimes#include <machine/../linux/linux.h> 571638Srgrimes#include <machine/../linux/linux_proto.h> 581638Srgrimes#endif 591638Srgrimes 601638Srgrimes#include <compat/linux/linux_dtrace.h> 611638Srgrimes#include <compat/linux/linux_emul.h> 621638Srgrimes#include <compat/linux/linux_futex.h> 631638Srgrimes#include <compat/linux/linux_misc.h> 641638Srgrimes#include <compat/linux/linux_util.h> 651638Srgrimes 661638Srgrimes/** 671638Srgrimes * Special DTrace provider for the linuxulator. 681638Srgrimes * 691638Srgrimes * In this file we define the provider for the entire linuxulator. All 701638Srgrimes * modules (= files of the linuxulator) use it. 711638Srgrimes * 721638Srgrimes * We define a different name depending on the emulated bitsize, see 731638Srgrimes * ../../<ARCH>/linux{,32}/linux.h, e.g.: 741638Srgrimes * native bitsize = linuxulator 751638Srgrimes * amd64, 32bit emulation = linuxulator32 761638Srgrimes */ 771638SrgrimesLIN_SDT_PROVIDER_DEFINE(LINUX_DTRACE); 781638Srgrimes 791638Srgrimes/** 801638Srgrimes * DTrace probes in this module. 811638Srgrimes */ 821638SrgrimesLIN_SDT_PROBE_DEFINE1(emul, em_find, entry, "struct thread *"); 831638SrgrimesLIN_SDT_PROBE_DEFINE0(emul, em_find, return); 841638SrgrimesLIN_SDT_PROBE_DEFINE3(emul, proc_init, entry, "struct thread *", 851638Srgrimes "struct thread *", "int"); 861638SrgrimesLIN_SDT_PROBE_DEFINE0(emul, proc_init, create_thread); 871638SrgrimesLIN_SDT_PROBE_DEFINE0(emul, proc_init, fork); 881638SrgrimesLIN_SDT_PROBE_DEFINE0(emul, proc_init, exec); 891638SrgrimesLIN_SDT_PROBE_DEFINE0(emul, proc_init, return); 901638SrgrimesLIN_SDT_PROBE_DEFINE1(emul, proc_exit, entry, "struct proc *"); 911638SrgrimesLIN_SDT_PROBE_DEFINE1(emul, linux_thread_detach, entry, "struct thread *"); 921638SrgrimesLIN_SDT_PROBE_DEFINE0(emul, linux_thread_detach, futex_failed); 931638SrgrimesLIN_SDT_PROBE_DEFINE1(emul, linux_thread_detach, child_clear_tid_error, "int"); 941638SrgrimesLIN_SDT_PROBE_DEFINE0(emul, linux_thread_detach, return); 95LIN_SDT_PROBE_DEFINE2(emul, proc_exec, entry, "struct proc *", 96 "struct image_params *"); 97LIN_SDT_PROBE_DEFINE0(emul, proc_exec, return); 98LIN_SDT_PROBE_DEFINE0(emul, linux_schedtail, entry); 99LIN_SDT_PROBE_DEFINE1(emul, linux_schedtail, copyout_error, "int"); 100LIN_SDT_PROBE_DEFINE0(emul, linux_schedtail, return); 101LIN_SDT_PROBE_DEFINE1(emul, linux_set_tid_address, entry, "int *"); 102LIN_SDT_PROBE_DEFINE0(emul, linux_set_tid_address, return); 103 104/* 105 * This returns reference to the emuldata entry (if found) 106 * 107 * Hold PROC_LOCK when referencing emuldata from other threads. 108 */ 109struct linux_emuldata * 110em_find(struct thread *td) 111{ 112 struct linux_emuldata *em; 113 114 LIN_SDT_PROBE1(emul, em_find, entry, td); 115 116 em = td->td_emuldata; 117 118 LIN_SDT_PROBE1(emul, em_find, return, em); 119 120 return (em); 121} 122 123void 124linux_proc_init(struct thread *td, struct thread *newtd, int flags) 125{ 126 struct linux_emuldata *em; 127 128 LIN_SDT_PROBE3(emul, proc_init, entry, td, newtd, flags); 129 130 if (newtd != NULL) { 131 /* non-exec call */ 132 em = malloc(sizeof(*em), M_TEMP, M_WAITOK | M_ZERO); 133 em->pdeath_signal = 0; 134 em->flags = 0; 135 em->robust_futexes = NULL; 136 if (flags & LINUX_CLONE_THREAD) { 137 LIN_SDT_PROBE0(emul, proc_init, create_thread); 138 139 em->em_tid = newtd->td_tid; 140 } else { 141 LIN_SDT_PROBE0(emul, proc_init, fork); 142 143 em->em_tid = newtd->td_proc->p_pid; 144 } 145 newtd->td_emuldata = em; 146 } else { 147 /* exec */ 148 LIN_SDT_PROBE0(emul, proc_init, exec); 149 150 /* lookup the old one */ 151 em = em_find(td); 152 KASSERT(em != NULL, ("proc_init: emuldata not found in exec case.\n")); 153 154 em->em_tid = td->td_proc->p_pid; 155 } 156 157 em->child_clear_tid = NULL; 158 em->child_set_tid = NULL; 159 160 LIN_SDT_PROBE0(emul, proc_init, return); 161} 162 163void 164linux_proc_exit(void *arg __unused, struct proc *p) 165{ 166 struct thread *td = curthread; 167 168 if (__predict_false(SV_CURPROC_ABI() != SV_ABI_LINUX)) { 169 LIN_SDT_PROBE1(emul, proc_exit, entry, p); 170 (p->p_sysent->sv_thread_detach)(td); 171 } 172} 173 174int 175linux_common_execve(struct thread *td, struct image_args *eargs) 176{ 177 struct linux_emuldata *em; 178 struct proc *p; 179 int error; 180 181 p = td->td_proc; 182 183 /* 184 * Unlike FreeBSD abort all other threads before 185 * proceeding exec. 186 */ 187 PROC_LOCK(p); 188 /* See exit1() comments. */ 189 thread_suspend_check(0); 190 while (p->p_flag & P_HADTHREADS) { 191 if (!thread_single(p, SINGLE_EXIT)) 192 break; 193 thread_suspend_check(0); 194 } 195 PROC_UNLOCK(p); 196 197 error = kern_execve(td, eargs, NULL); 198 if (error != 0) 199 return (error); 200 201 /* 202 * In a case of transition from Linux binary execing to 203 * FreeBSD binary we destroy linux emuldata thread entry. 204 */ 205 if (SV_CURPROC_ABI() != SV_ABI_LINUX) { 206 PROC_LOCK(p); 207 em = em_find(td); 208 KASSERT(em != NULL, ("proc_exec: emuldata not found.\n")); 209 td->td_emuldata = NULL; 210 PROC_UNLOCK(p); 211 212 free(em, M_TEMP); 213 } 214 return (0); 215} 216 217void 218linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp) 219{ 220 struct thread *td = curthread; 221 222 /* 223 * In a case of execing to linux binary we create linux 224 * emuldata thread entry. 225 */ 226 if (__predict_false((imgp->sysent->sv_flags & SV_ABI_MASK) == 227 SV_ABI_LINUX)) { 228 LIN_SDT_PROBE2(emul, proc_exec, entry, p, imgp); 229 if (SV_PROC_ABI(p) == SV_ABI_LINUX) 230 linux_proc_init(td, NULL, 0); 231 else 232 linux_proc_init(td, td, 0); 233 234 LIN_SDT_PROBE0(emul, proc_exec, return); 235 } 236} 237 238void 239linux_thread_detach(struct thread *td) 240{ 241 struct linux_sys_futex_args cup; 242 struct linux_emuldata *em; 243 int *child_clear_tid; 244 int null = 0; 245 int error; 246 247 LIN_SDT_PROBE1(emul, linux_thread_detach, entry, td); 248 249 em = em_find(td); 250 KASSERT(em != NULL, ("thread_detach: emuldata not found.\n")); 251 252 LINUX_CTR1(exit, "thread detach(%d)", em->em_tid); 253 254 release_futexes(td, em); 255 256 child_clear_tid = em->child_clear_tid; 257 258 if (child_clear_tid != NULL) { 259 260 LINUX_CTR2(exit, "thread detach(%d) %p", 261 em->em_tid, child_clear_tid); 262 263 error = copyout(&null, child_clear_tid, sizeof(null)); 264 if (error) { 265 LIN_SDT_PROBE1(emul, linux_thread_detach, 266 child_clear_tid_error, error); 267 268 LIN_SDT_PROBE0(emul, linux_thread_detach, return); 269 return; 270 } 271 272 cup.uaddr = child_clear_tid; 273 cup.op = LINUX_FUTEX_WAKE; 274 cup.val = 1; /* wake one */ 275 cup.timeout = NULL; 276 cup.uaddr2 = NULL; 277 cup.val3 = 0; 278 error = linux_sys_futex(td, &cup); 279 /* 280 * this cannot happen at the moment and if this happens it 281 * probably means there is a user space bug 282 */ 283 if (error) { 284 LIN_SDT_PROBE0(emul, linux_thread_detach, futex_failed); 285 printf(LMSG("futex stuff in thread_detach failed.\n")); 286 } 287 } 288 289 LIN_SDT_PROBE0(emul, linux_thread_detach, return); 290} 291 292void 293linux_thread_dtor(void *arg __unused, struct thread *td) 294{ 295 struct linux_emuldata *em; 296 297 em = em_find(td); 298 if (em == NULL) 299 return; 300 td->td_emuldata = NULL; 301 302 LINUX_CTR1(exit, "thread dtor(%d)", em->em_tid); 303 304 free(em, M_TEMP); 305} 306 307void 308linux_schedtail(struct thread *td) 309{ 310 struct linux_emuldata *em; 311 struct proc *p; 312 int error = 0; 313 int *child_set_tid; 314 315 LIN_SDT_PROBE1(emul, linux_schedtail, entry, td); 316 317 p = td->td_proc; 318 319 em = em_find(td); 320 KASSERT(em != NULL, ("linux_schedtail: emuldata not found.\n")); 321 child_set_tid = em->child_set_tid; 322 323 if (child_set_tid != NULL) { 324 error = copyout(&em->em_tid, (int *)child_set_tid, 325 sizeof(em->em_tid)); 326 LINUX_CTR4(clone, "schedtail(%d) %p stored %d error %d", 327 td->td_tid, child_set_tid, em->em_tid, error); 328 329 if (error != 0) { 330 LIN_SDT_PROBE1(emul, linux_schedtail, copyout_error, 331 error); 332 } 333 } else 334 LINUX_CTR1(clone, "schedtail(%d)", em->em_tid); 335 336 LIN_SDT_PROBE0(emul, linux_schedtail, return); 337} 338 339int 340linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args) 341{ 342 struct linux_emuldata *em; 343 344 LIN_SDT_PROBE1(emul, linux_set_tid_address, entry, args->tidptr); 345 346 em = em_find(td); 347 KASSERT(em != NULL, ("set_tid_address: emuldata not found.\n")); 348 349 em->child_clear_tid = args->tidptr; 350 351 td->td_retval[0] = em->em_tid; 352 353 LINUX_CTR3(set_tid_address, "tidptr(%d) %p, returns %d", 354 em->em_tid, args->tidptr, td->td_retval[0]); 355 356 LIN_SDT_PROBE0(emul, linux_set_tid_address, return); 357 return (0); 358} 359