linux_emul.c revision 293600
155714Skris/*- 255714Skris * Copyright (c) 2006 Roman Divacky 355714Skris * Copyright (c) 2013 Dmitry Chagin 455714Skris * All rights reserved. 555714Skris * 655714Skris * Redistribution and use in source and binary forms, with or without 755714Skris * modification, are permitted provided that the following conditions 855714Skris * are met: 9238405Sjkim * 1. Redistributions of source code must retain the above copyright 1055714Skris * notice, this list of conditions and the following disclaimer 1155714Skris * in this position and unchanged. 1259191Skris * 2. Redistributions in binary form must reproduce the above copyright 1355714Skris * notice, this list of conditions and the following disclaimer in the 14238405Sjkim * documentation and/or other materials provided with the distribution. 15160814Ssimon * 3. The name of the author may not be used to endorse or promote products 16238405Sjkim * derived from this software without specific prior written permission 17160814Ssimon * 18160814Ssimon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19238405Sjkim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20160814Ssimon * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21238405Sjkim * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22160814Ssimon * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23238405Sjkim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24194206Ssimon * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25238405Sjkim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26238405Sjkim * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27238405Sjkim * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28238405Sjkim */ 29238405Sjkim 30238405Sjkim#include <sys/cdefs.h> 31238405Sjkim__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_emul.c 293600 2016-01-09 18:07:48Z dchagin $"); 32238405Sjkim 33238405Sjkim#include <sys/param.h> 34238405Sjkim#include <sys/systm.h> 35238405Sjkim#include <sys/imgact.h> 36238405Sjkim#include <sys/kernel.h> 37238405Sjkim#include <sys/ktr.h> 38238405Sjkim#include <sys/lock.h> 39238405Sjkim#include <sys/malloc.h> 40238405Sjkim#include <sys/mutex.h> 41238405Sjkim#include <sys/sx.h> 42238405Sjkim#include <sys/proc.h> 43238405Sjkim#include <sys/syscallsubr.h> 44238405Sjkim#include <sys/sysent.h> 45238405Sjkim 46238405Sjkim#include <compat/linux/linux_emul.h> 47238405Sjkim#include <compat/linux/linux_misc.h> 48238405Sjkim#include <compat/linux/linux_util.h> 49194206Ssimon 50194206Ssimon 51142425Snectar/* 5255714Skris * This returns reference to the thread emuldata entry (if found) 53238405Sjkim * 54238405Sjkim * Hold PROC_LOCK when referencing emuldata from other threads. 55238405Sjkim */ 56238405Sjkimstruct linux_emuldata * 57238405Sjkimem_find(struct thread *td) 58238405Sjkim{ 5955714Skris struct linux_emuldata *em; 6055714Skris 6155714Skris em = td->td_emuldata; 62238405Sjkim 63238405Sjkim return (em); 64142425Snectar} 6555714Skris 6655714Skris/* 6755714Skris * This returns reference to the proc pemuldata entry (if found) 6855714Skris * 6955714Skris * Hold PROC_LOCK when referencing proc pemuldata from other threads. 70160814Ssimon * Hold LINUX_PEM_LOCK wher referencing pemuldata members. 71160814Ssimon */ 72109998Smarkmstruct linux_pemuldata * 7355714Skrispem_find(struct proc *p) 7455714Skris{ 7555714Skris struct linux_pemuldata *pem; 7655714Skris 7755714Skris pem = p->p_emuldata; 7855714Skris 7955714Skris return (pem); 80109998Smarkm} 81160814Ssimon 82194206Ssimonvoid 83160814Ssimonlinux_proc_init(struct thread *td, struct thread *newtd, int flags) 84160814Ssimon{ 8555714Skris struct linux_emuldata *em; 86238405Sjkim struct linux_pemuldata *pem; 8755714Skris struct epoll_emuldata *emd; 8855714Skris struct proc *p; 8955714Skris 90160814Ssimon if (newtd != NULL) { 9155714Skris p = newtd->td_proc; 9255714Skris 9355714Skris /* non-exec call */ 9455714Skris em = malloc(sizeof(*em), M_TEMP, M_WAITOK | M_ZERO); 9555714Skris if (flags & LINUX_CLONE_THREAD) { 9655714Skris LINUX_CTR1(proc_init, "thread newtd(%d)", 9755714Skris newtd->td_tid); 9855714Skris 9955714Skris em->em_tid = newtd->td_tid; 10055714Skris } else { 10155714Skris LINUX_CTR1(proc_init, "fork newtd(%d)", p->p_pid); 10268651Skris 10368651Skris em->em_tid = p->p_pid; 104109998Smarkm 105194206Ssimon pem = malloc(sizeof(*pem), M_LINUX, M_WAITOK | M_ZERO); 10655714Skris sx_init(&pem->pem_sx, "lpemlk"); 10755714Skris p->p_emuldata = pem; 10855714Skris } 10955714Skris newtd->td_emuldata = em; 110109998Smarkm } else { 111238405Sjkim p = td->td_proc; 112109998Smarkm 113160814Ssimon /* exec */ 114160814Ssimon LINUX_CTR1(proc_init, "exec newtd(%d)", p->p_pid); 115111147Snectar 116111147Snectar /* lookup the old one */ 11755714Skris em = em_find(td); 118160814Ssimon KASSERT(em != NULL, ("proc_init: emuldata not found in exec case.\n")); 119194206Ssimon 12059191Skris em->em_tid = p->p_pid; 12155714Skris em->flags = 0; 12255714Skris em->pdeath_signal = 0; 12355714Skris em->robust_futexes = NULL; 12455714Skris em->child_clear_tid = NULL; 12568651Skris em->child_set_tid = NULL; 12655714Skris 12755714Skris /* epoll should be destroyed in a case of exec. */ 12855714Skris pem = pem_find(p); 12955714Skris KASSERT(pem != NULL, ("proc_exit: proc emuldata not found.\n")); 13055714Skris 13155714Skris if (pem->epoll != NULL) { 13255714Skris emd = pem->epoll; 13355714Skris pem->epoll = NULL; 13455714Skris free(emd, M_EPOLL); 13555714Skris } 13655714Skris } 13755714Skris 13855714Skris} 139109998Smarkm 14055714Skrisvoid 14155714Skrislinux_proc_exit(void *arg __unused, struct proc *p) 14255714Skris{ 14355714Skris struct linux_pemuldata *pem; 144160814Ssimon struct epoll_emuldata *emd; 145160814Ssimon struct thread *td = curthread; 14655714Skris 14755714Skris if (__predict_false(SV_CURPROC_ABI() != SV_ABI_LINUX)) 14855714Skris return; 14955714Skris 15055714Skris LINUX_CTR3(proc_exit, "thread(%d) proc(%d) p %p", 151109998Smarkm td->td_tid, p->p_pid, p); 15255714Skris 15355714Skris pem = pem_find(p); 15455714Skris if (pem == NULL) 15555714Skris return; 15655714Skris (p->p_sysent->sv_thread_detach)(td); 15755714Skris 158160814Ssimon p->p_emuldata = NULL; 159160814Ssimon 16055714Skris if (pem->epoll != NULL) { 16155714Skris emd = pem->epoll; 16255714Skris pem->epoll = NULL; 16355714Skris free(emd, M_EPOLL); 16455714Skris } 16555714Skris 16655714Skris sx_destroy(&pem->pem_sx); 16755714Skris free(pem, M_LINUX); 16855714Skris} 16955714Skris 170160814Ssimonint 17155714Skrislinux_common_execve(struct thread *td, struct image_args *eargs) 17255714Skris{ 17355714Skris struct linux_pemuldata *pem; 174238405Sjkim struct epoll_emuldata *emd; 175238405Sjkim struct vmspace *oldvmspace; 176238405Sjkim struct linux_emuldata *em; 177238405Sjkim struct proc *p; 178238405Sjkim int error; 179238405Sjkim 180160814Ssimon p = td->td_proc; 18155714Skris 182160814Ssimon error = pre_execve(td, &oldvmspace); 183160814Ssimon if (error != 0) 18455714Skris return (error); 18555714Skris 18655714Skris error = kern_execve(td, eargs, NULL); 18755714Skris post_execve(td, error, oldvmspace); 18855714Skris if (error != 0) 18955714Skris return (error); 19055714Skris 19155714Skris /* 19255714Skris * In a case of transition from Linux binary execing to 19355714Skris * FreeBSD binary we destroy linux emuldata thread & proc entries. 19455714Skris */ 19555714Skris if (SV_CURPROC_ABI() != SV_ABI_LINUX) { 19655714Skris PROC_LOCK(p); 19755714Skris em = em_find(td); 19855714Skris KASSERT(em != NULL, ("proc_exec: thread emuldata not found.\n")); 19955714Skris td->td_emuldata = NULL; 20055714Skris 20155714Skris pem = pem_find(p); 20255714Skris KASSERT(pem != NULL, ("proc_exec: proc pemuldata not found.\n")); 20355714Skris p->p_emuldata = NULL; 20455714Skris PROC_UNLOCK(p); 20555714Skris 20655714Skris if (pem->epoll != NULL) { 20755714Skris emd = pem->epoll; 20855714Skris pem->epoll = NULL; 20955714Skris free(emd, M_EPOLL); 21055714Skris } 21155714Skris 21255714Skris free(em, M_TEMP); 21355714Skris free(pem, M_LINUX); 21455714Skris } 21555714Skris return (0); 216109998Smarkm} 217109998Smarkm 218109998Smarkmvoid 219109998Smarkmlinux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp) 220109998Smarkm{ 221160814Ssimon struct thread *td = curthread; 222194206Ssimon 223160814Ssimon /* 224160814Ssimon * In a case of execing to linux binary we create linux 225194206Ssimon * emuldata thread entry. 226160814Ssimon */ 227160814Ssimon if (__predict_false((imgp->sysent->sv_flags & SV_ABI_MASK) == 22855714Skris SV_ABI_LINUX)) { 22955714Skris 23055714Skris if (SV_PROC_ABI(p) == SV_ABI_LINUX) 23155714Skris linux_proc_init(td, NULL, 0); 23255714Skris else 23355714Skris linux_proc_init(td, td, 0); 23455714Skris } 23555714Skris} 236238405Sjkim 237238405Sjkimvoid 23855714Skrislinux_thread_dtor(void *arg __unused, struct thread *td) 23955714Skris{ 24055714Skris struct linux_emuldata *em; 24155714Skris 24255714Skris em = em_find(td); 24355714Skris if (em == NULL) 244160814Ssimon return; 245160814Ssimon td->td_emuldata = NULL; 246109998Smarkm 247109998Smarkm LINUX_CTR1(thread_dtor, "thread(%d)", em->em_tid); 248162911Ssimon 249194206Ssimon free(em, M_TEMP); 250109998Smarkm} 251109998Smarkm 252109998Smarkmvoid 253109998Smarkmlinux_schedtail(struct thread *td) 254109998Smarkm{ 255109998Smarkm struct linux_emuldata *em; 256109998Smarkm struct proc *p; 257109998Smarkm int error = 0; 258111147Snectar int *child_set_tid; 259109998Smarkm 260160814Ssimon p = td->td_proc; 261109998Smarkm 262109998Smarkm em = em_find(td); 263109998Smarkm KASSERT(em != NULL, ("linux_schedtail: thread emuldata not found.\n")); 264109998Smarkm child_set_tid = em->child_set_tid; 265109998Smarkm 266238405Sjkim if (child_set_tid != NULL) { 267109998Smarkm error = copyout(&em->em_tid, child_set_tid, 268109998Smarkm sizeof(em->em_tid)); 269109998Smarkm LINUX_CTR4(schedtail, "thread(%d) %p stored %d error %d", 270194206Ssimon td->td_tid, child_set_tid, em->em_tid, error); 271238405Sjkim } else 272194206Ssimon LINUX_CTR1(schedtail, "thread(%d)", em->em_tid); 273109998Smarkm} 274109998Smarkm