xref: /freebsd/sys/compat/linux/linux_emul.c (revision bc273677607433dc32f6586c964a469f19867818)
1ad2056f2SAlexander Leidinger /*-
2ad2056f2SAlexander Leidinger  * Copyright (c) 2006 Roman Divacky
381338031SDmitry Chagin  * Copyright (c) 2013 Dmitry Chagin
4ad2056f2SAlexander Leidinger  * All rights reserved.
5ad2056f2SAlexander Leidinger  *
6ad2056f2SAlexander Leidinger  * Redistribution and use in source and binary forms, with or without
7ad2056f2SAlexander Leidinger  * modification, are permitted provided that the following conditions
8ad2056f2SAlexander Leidinger  * are met:
9ad2056f2SAlexander Leidinger  * 1. Redistributions of source code must retain the above copyright
10ad2056f2SAlexander Leidinger  *    notice, this list of conditions and the following disclaimer
11ad2056f2SAlexander Leidinger  *    in this position and unchanged.
12ad2056f2SAlexander Leidinger  * 2. Redistributions in binary form must reproduce the above copyright
13ad2056f2SAlexander Leidinger  *    notice, this list of conditions and the following disclaimer in the
14ad2056f2SAlexander Leidinger  *    documentation and/or other materials provided with the distribution.
15ad2056f2SAlexander Leidinger  * 3. The name of the author may not be used to endorse or promote products
16ad2056f2SAlexander Leidinger  *    derived from this software without specific prior written permission
17ad2056f2SAlexander Leidinger  *
18ad2056f2SAlexander Leidinger  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19ad2056f2SAlexander Leidinger  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20ad2056f2SAlexander Leidinger  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21ad2056f2SAlexander Leidinger  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22ad2056f2SAlexander Leidinger  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23ad2056f2SAlexander Leidinger  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24ad2056f2SAlexander Leidinger  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25ad2056f2SAlexander Leidinger  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26ad2056f2SAlexander Leidinger  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27ad2056f2SAlexander Leidinger  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28ad2056f2SAlexander Leidinger  */
29ad2056f2SAlexander Leidinger 
30ad2056f2SAlexander Leidinger #include <sys/cdefs.h>
31ad2056f2SAlexander Leidinger __FBSDID("$FreeBSD$");
32ad2056f2SAlexander Leidinger 
33ad2056f2SAlexander Leidinger #include <sys/param.h>
34ad2056f2SAlexander Leidinger #include <sys/systm.h>
35ad2056f2SAlexander Leidinger #include <sys/imgact.h>
36b4bb5154SKonstantin Belousov #include <sys/kernel.h>
3781338031SDmitry Chagin #include <sys/ktr.h>
38ad2056f2SAlexander Leidinger #include <sys/lock.h>
39ad2056f2SAlexander Leidinger #include <sys/malloc.h>
40ad2056f2SAlexander Leidinger #include <sys/mutex.h>
41ad2056f2SAlexander Leidinger #include <sys/sx.h>
42ad2056f2SAlexander Leidinger #include <sys/proc.h>
43ad2056f2SAlexander Leidinger #include <sys/syscallsubr.h>
4495353459SDimitry Andric #include <sys/sysent.h>
45ad2056f2SAlexander Leidinger #include <sys/sysproto.h>
46ad2056f2SAlexander Leidinger #include <sys/unistd.h>
47ad2056f2SAlexander Leidinger 
484732e446SRoman Divacky #include <compat/linux/linux_emul.h>
49d825ce0aSJohn Baldwin #include <compat/linux/linux_misc.h>
5081338031SDmitry Chagin #include <compat/linux/linux_util.h>
514732e446SRoman Divacky 
5219e252baSAlexander Leidinger 
5381338031SDmitry Chagin /*
54*bc273677SDmitry Chagin  * This returns reference to the thread emuldata entry (if found)
5581338031SDmitry Chagin  *
5681338031SDmitry Chagin  * Hold PROC_LOCK when referencing emuldata from other threads.
5781338031SDmitry Chagin  */
58ad2056f2SAlexander Leidinger struct linux_emuldata *
5981338031SDmitry Chagin em_find(struct thread *td)
60ad2056f2SAlexander Leidinger {
61ad2056f2SAlexander Leidinger 	struct linux_emuldata *em;
62ad2056f2SAlexander Leidinger 
6381338031SDmitry Chagin 	em = td->td_emuldata;
64ad2056f2SAlexander Leidinger 
65ad2056f2SAlexander Leidinger 	return (em);
66ad2056f2SAlexander Leidinger }
67ad2056f2SAlexander Leidinger 
68*bc273677SDmitry Chagin /*
69*bc273677SDmitry Chagin  * This returns reference to the proc pemuldata entry (if found)
70*bc273677SDmitry Chagin  *
71*bc273677SDmitry Chagin  * Hold PROC_LOCK when referencing proc pemuldata from other threads.
72*bc273677SDmitry Chagin  * Hold LINUX_PEM_LOCK wher referencing pemuldata members.
73*bc273677SDmitry Chagin  */
74*bc273677SDmitry Chagin struct linux_pemuldata *
75*bc273677SDmitry Chagin pem_find(struct proc *p)
76*bc273677SDmitry Chagin {
77*bc273677SDmitry Chagin 	struct linux_pemuldata *pem;
78*bc273677SDmitry Chagin 
79*bc273677SDmitry Chagin 	pem = p->p_emuldata;
80*bc273677SDmitry Chagin 
81*bc273677SDmitry Chagin 	return (pem);
82*bc273677SDmitry Chagin }
83*bc273677SDmitry Chagin 
8481338031SDmitry Chagin void
8581338031SDmitry Chagin linux_proc_init(struct thread *td, struct thread *newtd, int flags)
86ad2056f2SAlexander Leidinger {
8781338031SDmitry Chagin 	struct linux_emuldata *em;
88*bc273677SDmitry Chagin 	struct linux_pemuldata *pem;
8919e252baSAlexander Leidinger 
9081338031SDmitry Chagin 	if (newtd != NULL) {
9181338031SDmitry Chagin 		/* non-exec call */
9281338031SDmitry Chagin 		em = malloc(sizeof(*em), M_TEMP, M_WAITOK | M_ZERO);
93955d762aSAlexander Leidinger 		em->pdeath_signal = 0;
944732e446SRoman Divacky 		em->robust_futexes = NULL;
95a4e3bad7SJung-uk Kim 		if (flags & LINUX_CLONE_THREAD) {
9681338031SDmitry Chagin 			em->em_tid = newtd->td_tid;
9781338031SDmitry Chagin 		} else {
9819e252baSAlexander Leidinger 
9981338031SDmitry Chagin 			em->em_tid = newtd->td_proc->p_pid;
100*bc273677SDmitry Chagin 
101*bc273677SDmitry Chagin 			pem = malloc(sizeof(*pem), M_TEMP, M_WAITOK | M_ZERO);
102*bc273677SDmitry Chagin 			sx_init(&pem->pem_sx, "lpemlk");
103*bc273677SDmitry Chagin 			newtd->td_proc->p_emuldata = pem;
104ad2056f2SAlexander Leidinger 		}
10581338031SDmitry Chagin 		newtd->td_emuldata = em;
106ad2056f2SAlexander Leidinger 	} else {
10719e252baSAlexander Leidinger 		/* exec */
10819e252baSAlexander Leidinger 
109ad2056f2SAlexander Leidinger 		/* lookup the old one */
11081338031SDmitry Chagin 		em = em_find(td);
111ad2056f2SAlexander Leidinger 		KASSERT(em != NULL, ("proc_init: emuldata not found in exec case.\n"));
11281338031SDmitry Chagin 
11381338031SDmitry Chagin 		em->em_tid = td->td_proc->p_pid;
114ad2056f2SAlexander Leidinger 	}
115ad2056f2SAlexander Leidinger 
116ad2056f2SAlexander Leidinger 	em->child_clear_tid = NULL;
117ad2056f2SAlexander Leidinger 	em->child_set_tid = NULL;
118ad2056f2SAlexander Leidinger }
119ad2056f2SAlexander Leidinger 
120ad2056f2SAlexander Leidinger void
121ad2056f2SAlexander Leidinger linux_proc_exit(void *arg __unused, struct proc *p)
122ad2056f2SAlexander Leidinger {
123*bc273677SDmitry Chagin 	struct linux_pemuldata *pem;
12481338031SDmitry Chagin 	struct thread *td = curthread;
125ad2056f2SAlexander Leidinger 
126*bc273677SDmitry Chagin 	if (__predict_false(SV_CURPROC_ABI() != SV_ABI_LINUX))
127*bc273677SDmitry Chagin 		return;
128*bc273677SDmitry Chagin 
129*bc273677SDmitry Chagin 	pem = pem_find(p);
130*bc273677SDmitry Chagin 	if (pem == NULL)
131*bc273677SDmitry Chagin 		return;
13281338031SDmitry Chagin 	(p->p_sysent->sv_thread_detach)(td);
133*bc273677SDmitry Chagin 
134*bc273677SDmitry Chagin 	p->p_emuldata = NULL;
135*bc273677SDmitry Chagin 
136*bc273677SDmitry Chagin 	sx_destroy(&pem->pem_sx);
137*bc273677SDmitry Chagin 	free(pem, M_TEMP);
138e8b8b834SAlexander Leidinger }
139ad2056f2SAlexander Leidinger 
14081338031SDmitry Chagin int
14181338031SDmitry Chagin linux_common_execve(struct thread *td, struct image_args *eargs)
14281338031SDmitry Chagin {
143*bc273677SDmitry Chagin 	struct linux_pemuldata *pem;
14481338031SDmitry Chagin 	struct linux_emuldata *em;
14581338031SDmitry Chagin 	struct proc *p;
14681338031SDmitry Chagin 	int error;
147ad2056f2SAlexander Leidinger 
14881338031SDmitry Chagin 	p = td->td_proc;
149ad2056f2SAlexander Leidinger 
15081338031SDmitry Chagin 	/*
15181338031SDmitry Chagin 	 * Unlike FreeBSD abort all other threads before
15281338031SDmitry Chagin 	 * proceeding exec.
15381338031SDmitry Chagin 	 */
15481338031SDmitry Chagin 	PROC_LOCK(p);
15581338031SDmitry Chagin 	/* See exit1() comments. */
15681338031SDmitry Chagin 	thread_suspend_check(0);
15781338031SDmitry Chagin 	while (p->p_flag & P_HADTHREADS) {
15881338031SDmitry Chagin 		if (!thread_single(p, SINGLE_EXIT))
15981338031SDmitry Chagin 			break;
16081338031SDmitry Chagin 		thread_suspend_check(0);
16181338031SDmitry Chagin 	}
16281338031SDmitry Chagin 	PROC_UNLOCK(p);
16381338031SDmitry Chagin 
16481338031SDmitry Chagin 	error = kern_execve(td, eargs, NULL);
16581338031SDmitry Chagin 	if (error != 0)
16681338031SDmitry Chagin 		return (error);
16781338031SDmitry Chagin 
16881338031SDmitry Chagin 	/*
16981338031SDmitry Chagin 	 * In a case of transition from Linux binary execing to
170*bc273677SDmitry Chagin 	 * FreeBSD binary we destroy linux emuldata thread & proc entries.
17181338031SDmitry Chagin 	 */
17281338031SDmitry Chagin 	if (SV_CURPROC_ABI() != SV_ABI_LINUX) {
17381338031SDmitry Chagin 		PROC_LOCK(p);
17481338031SDmitry Chagin 		em = em_find(td);
175*bc273677SDmitry Chagin 		KASSERT(em != NULL, ("proc_exec: thread emuldata not found.\n"));
17681338031SDmitry Chagin 		td->td_emuldata = NULL;
177*bc273677SDmitry Chagin 
178*bc273677SDmitry Chagin 		pem = pem_find(p);
179*bc273677SDmitry Chagin 		KASSERT(pem != NULL, ("proc_exec: proc pemuldata not found.\n"));
180*bc273677SDmitry Chagin 		p->p_emuldata = NULL;
18181338031SDmitry Chagin 		PROC_UNLOCK(p);
18281338031SDmitry Chagin 
18381338031SDmitry Chagin 		free(em, M_TEMP);
184*bc273677SDmitry Chagin 		free(pem, M_TEMP);
18581338031SDmitry Chagin 	}
18681338031SDmitry Chagin 	return (0);
18781338031SDmitry Chagin }
18881338031SDmitry Chagin 
18981338031SDmitry Chagin void
19081338031SDmitry Chagin linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp)
19181338031SDmitry Chagin {
19281338031SDmitry Chagin 	struct thread *td = curthread;
19381338031SDmitry Chagin 
19481338031SDmitry Chagin 	/*
19581338031SDmitry Chagin 	 * In a case of execing to linux binary we create linux
19681338031SDmitry Chagin 	 * emuldata thread entry.
19781338031SDmitry Chagin 	 */
19881338031SDmitry Chagin 	if (__predict_false((imgp->sysent->sv_flags & SV_ABI_MASK) ==
19981338031SDmitry Chagin 	    SV_ABI_LINUX)) {
20081338031SDmitry Chagin 		if (SV_PROC_ABI(p) == SV_ABI_LINUX)
20181338031SDmitry Chagin 			linux_proc_init(td, NULL, 0);
20281338031SDmitry Chagin 		else
20381338031SDmitry Chagin 			linux_proc_init(td, td, 0);
20481338031SDmitry Chagin 	}
20581338031SDmitry Chagin }
20681338031SDmitry Chagin 
20781338031SDmitry Chagin void
20881338031SDmitry Chagin linux_thread_dtor(void *arg __unused, struct thread *td)
209ad2056f2SAlexander Leidinger {
210ad2056f2SAlexander Leidinger 	struct linux_emuldata *em;
211ad2056f2SAlexander Leidinger 
21281338031SDmitry Chagin 	em = em_find(td);
21381338031SDmitry Chagin 	if (em == NULL)
21481338031SDmitry Chagin 		return;
21581338031SDmitry Chagin 	td->td_emuldata = NULL;
216ad2056f2SAlexander Leidinger 
21781338031SDmitry Chagin 	LINUX_CTR1(exit, "thread dtor(%d)", em->em_tid);
218ad2056f2SAlexander Leidinger 
21981338031SDmitry Chagin 	free(em, M_TEMP);
220ad2056f2SAlexander Leidinger }
221ad2056f2SAlexander Leidinger 
222ad2056f2SAlexander Leidinger void
223e5d81ef1SDmitry Chagin linux_schedtail(struct thread *td)
224ad2056f2SAlexander Leidinger {
225ad2056f2SAlexander Leidinger 	struct linux_emuldata *em;
226e5d81ef1SDmitry Chagin 	struct proc *p;
227ad2056f2SAlexander Leidinger 	int error = 0;
228ad2056f2SAlexander Leidinger 	int *child_set_tid;
229ad2056f2SAlexander Leidinger 
230e5d81ef1SDmitry Chagin 	p = td->td_proc;
231e5d81ef1SDmitry Chagin 
23281338031SDmitry Chagin 	em = em_find(td);
233*bc273677SDmitry Chagin 	KASSERT(em != NULL, ("linux_schedtail: thread emuldata not found.\n"));
234ad2056f2SAlexander Leidinger 	child_set_tid = em->child_set_tid;
235ad2056f2SAlexander Leidinger 
23619e252baSAlexander Leidinger 	if (child_set_tid != NULL) {
23781338031SDmitry Chagin 		error = copyout(&em->em_tid, (int *)child_set_tid,
23881338031SDmitry Chagin 		    sizeof(em->em_tid));
23981338031SDmitry Chagin 		LINUX_CTR4(clone, "schedtail(%d) %p stored %d error %d",
24081338031SDmitry Chagin 		    td->td_tid, child_set_tid, em->em_tid, error);
24181338031SDmitry Chagin 	} else
24281338031SDmitry Chagin 		LINUX_CTR1(clone, "schedtail(%d)", em->em_tid);
243bb63fddeSAlexander Leidinger }
244