xref: /freebsd/sys/amd64/linux32/linux32_machdep.c (revision 61cc4830a7b16400efade3d884a59fda6d80d651)
1ea0fabbcSTim J. Robbins /*-
2c49761ddSPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
3c49761ddSPedro F. Giffuni  *
4ea0fabbcSTim J. Robbins  * Copyright (c) 2004 Tim J. Robbins
5ea0fabbcSTim J. Robbins  * Copyright (c) 2002 Doug Rabson
6ea0fabbcSTim J. Robbins  * Copyright (c) 2000 Marcel Moolenaar
7ea0fabbcSTim J. Robbins  * All rights reserved.
8ea0fabbcSTim J. Robbins  *
9ea0fabbcSTim J. Robbins  * Redistribution and use in source and binary forms, with or without
10ea0fabbcSTim J. Robbins  * modification, are permitted provided that the following conditions
11ea0fabbcSTim J. Robbins  * are met:
12ea0fabbcSTim J. Robbins  * 1. Redistributions of source code must retain the above copyright
13ea0fabbcSTim J. Robbins  *    notice, this list of conditions and the following disclaimer
14ea0fabbcSTim J. Robbins  *    in this position and unchanged.
15ea0fabbcSTim J. Robbins  * 2. Redistributions in binary form must reproduce the above copyright
16ea0fabbcSTim J. Robbins  *    notice, this list of conditions and the following disclaimer in the
17ea0fabbcSTim J. Robbins  *    documentation and/or other materials provided with the distribution.
18ea0fabbcSTim J. Robbins  * 3. The name of the author may not be used to endorse or promote products
19ea0fabbcSTim J. Robbins  *    derived from this software without specific prior written permission.
20ea0fabbcSTim J. Robbins  *
21ea0fabbcSTim J. Robbins  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22ea0fabbcSTim J. Robbins  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23ea0fabbcSTim J. Robbins  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24ea0fabbcSTim J. Robbins  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25ea0fabbcSTim J. Robbins  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26ea0fabbcSTim J. Robbins  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27ea0fabbcSTim J. Robbins  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28ea0fabbcSTim J. Robbins  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29ea0fabbcSTim J. Robbins  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30ea0fabbcSTim J. Robbins  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31ea0fabbcSTim J. Robbins  */
32ea0fabbcSTim J. Robbins 
33ea0fabbcSTim J. Robbins #include <sys/param.h>
34ea0fabbcSTim J. Robbins #include <sys/lock.h>
35ea0fabbcSTim J. Robbins #include <sys/mutex.h>
361e5ed8c1SJung-uk Kim #include <sys/priv.h>
37ea0fabbcSTim J. Robbins #include <sys/proc.h>
38b7924341SAndrew Turner #include <sys/reg.h>
39ea0fabbcSTim J. Robbins #include <sys/syscallsubr.h>
40ea0fabbcSTim J. Robbins 
41cb0eecdfSKonstantin Belousov #include <machine/md_var.h>
429c5b213eSJung-uk Kim #include <machine/specialreg.h>
43cb0eecdfSKonstantin Belousov #include <x86/ifunc.h>
44ea0fabbcSTim J. Robbins 
450b53d156SKonstantin Belousov #include <compat/freebsd32/freebsd32_util.h>
46ea0fabbcSTim J. Robbins #include <amd64/linux32/linux.h>
47ea0fabbcSTim J. Robbins #include <amd64/linux32/linux32_proto.h>
48c0aa0e2cSEd Maste #include <compat/linux/linux_emul.h>
490a4b664aSDmitry Chagin #include <compat/linux/linux_fork.h>
50ea0fabbcSTim J. Robbins #include <compat/linux/linux_ipc.h>
5197d06da6SDmitry Chagin #include <compat/linux/linux_mmap.h>
52ea0fabbcSTim J. Robbins #include <compat/linux/linux_signal.h>
53ea0fabbcSTim J. Robbins #include <compat/linux/linux_util.h>
54ea0fabbcSTim J. Robbins 
55001398c4SDmitry Chagin static void	bsd_to_linux_rusage(struct rusage *ru, struct l_rusage *lru);
56001398c4SDmitry Chagin 
57ea0fabbcSTim J. Robbins struct l_old_select_argv {
58ea0fabbcSTim J. Robbins 	l_int		nfds;
59ea0fabbcSTim J. Robbins 	l_uintptr_t	readfds;
60ea0fabbcSTim J. Robbins 	l_uintptr_t	writefds;
61ea0fabbcSTim J. Robbins 	l_uintptr_t	exceptfds;
62ea0fabbcSTim J. Robbins 	l_uintptr_t	timeout;
63ea0fabbcSTim J. Robbins } __packed;
64ea0fabbcSTim J. Robbins 
65572fb2e3SDmitry Chagin static void
bsd_to_linux_rusage(struct rusage * ru,struct l_rusage * lru)66572fb2e3SDmitry Chagin bsd_to_linux_rusage(struct rusage *ru, struct l_rusage *lru)
6753c74fc6SDmitry Chagin {
68572fb2e3SDmitry Chagin 
6953c74fc6SDmitry Chagin 	lru->ru_utime.tv_sec = ru->ru_utime.tv_sec;
7053c74fc6SDmitry Chagin 	lru->ru_utime.tv_usec = ru->ru_utime.tv_usec;
7153c74fc6SDmitry Chagin 	lru->ru_stime.tv_sec = ru->ru_stime.tv_sec;
7253c74fc6SDmitry Chagin 	lru->ru_stime.tv_usec = ru->ru_stime.tv_usec;
7353c74fc6SDmitry Chagin 	lru->ru_maxrss = ru->ru_maxrss;
7453c74fc6SDmitry Chagin 	lru->ru_ixrss = ru->ru_ixrss;
7553c74fc6SDmitry Chagin 	lru->ru_idrss = ru->ru_idrss;
7653c74fc6SDmitry Chagin 	lru->ru_isrss = ru->ru_isrss;
7753c74fc6SDmitry Chagin 	lru->ru_minflt = ru->ru_minflt;
7853c74fc6SDmitry Chagin 	lru->ru_majflt = ru->ru_majflt;
7953c74fc6SDmitry Chagin 	lru->ru_nswap = ru->ru_nswap;
8053c74fc6SDmitry Chagin 	lru->ru_inblock = ru->ru_inblock;
8153c74fc6SDmitry Chagin 	lru->ru_oublock = ru->ru_oublock;
8253c74fc6SDmitry Chagin 	lru->ru_msgsnd = ru->ru_msgsnd;
8353c74fc6SDmitry Chagin 	lru->ru_msgrcv = ru->ru_msgrcv;
8453c74fc6SDmitry Chagin 	lru->ru_nsignals = ru->ru_nsignals;
8553c74fc6SDmitry Chagin 	lru->ru_nvcsw = ru->ru_nvcsw;
8653c74fc6SDmitry Chagin 	lru->ru_nivcsw = ru->ru_nivcsw;
8753c74fc6SDmitry Chagin }
8853c74fc6SDmitry Chagin 
89ea0fabbcSTim J. Robbins int
linux_copyout_rusage(struct rusage * ru,void * uaddr)90001398c4SDmitry Chagin linux_copyout_rusage(struct rusage *ru, void *uaddr)
91001398c4SDmitry Chagin {
92001398c4SDmitry Chagin 	struct l_rusage lru;
93001398c4SDmitry Chagin 
94001398c4SDmitry Chagin 	bsd_to_linux_rusage(ru, &lru);
95001398c4SDmitry Chagin 
96001398c4SDmitry Chagin 	return (copyout(&lru, uaddr, sizeof(struct l_rusage)));
97001398c4SDmitry Chagin }
98001398c4SDmitry Chagin 
9941f53a36SKonstantin Belousov int
linux_readv(struct thread * td,struct linux_readv_args * uap)100ea0fabbcSTim J. Robbins linux_readv(struct thread *td, struct linux_readv_args *uap)
101ea0fabbcSTim J. Robbins {
1023dde27daSJohn Baldwin 	struct uio *auio;
1033dde27daSJohn Baldwin 	int error;
104ea0fabbcSTim J. Robbins 
105c987ff4dSDmitry Chagin 	error = freebsd32_copyinuio(uap->iovp, uap->iovcnt, &auio);
1063dde27daSJohn Baldwin 	if (error)
1073dde27daSJohn Baldwin 		return (error);
1083dde27daSJohn Baldwin 	error = kern_readv(td, uap->fd, auio);
109*61cc4830SAlfredo Mazzinghi 	freeuio(auio);
110ea0fabbcSTim J. Robbins 	return (error);
111ea0fabbcSTim J. Robbins }
112ea0fabbcSTim J. Robbins 
113ea0fabbcSTim J. Robbins struct l_ipc_kludge {
114ea0fabbcSTim J. Robbins 	l_uintptr_t msgp;
115ea0fabbcSTim J. Robbins 	l_long msgtyp;
116ea0fabbcSTim J. Robbins } __packed;
117ea0fabbcSTim J. Robbins 
118ea0fabbcSTim J. Robbins int
linux_ipc(struct thread * td,struct linux_ipc_args * args)119ea0fabbcSTim J. Robbins linux_ipc(struct thread *td, struct linux_ipc_args *args)
120ea0fabbcSTim J. Robbins {
121ea0fabbcSTim J. Robbins 
122ea0fabbcSTim J. Robbins 	switch (args->what & 0xFFFF) {
123ea0fabbcSTim J. Robbins 	case LINUX_SEMOP: {
124ea0fabbcSTim J. Robbins 
125f48a6887SDmitry Chagin 		return (kern_semop(td, args->arg1, PTRIN(args->ptr),
126f48a6887SDmitry Chagin 		    args->arg2, NULL));
127ea0fabbcSTim J. Robbins 	}
128ea0fabbcSTim J. Robbins 	case LINUX_SEMGET: {
129ea0fabbcSTim J. Robbins 		struct linux_semget_args a;
130ea0fabbcSTim J. Robbins 
131ea0fabbcSTim J. Robbins 		a.key = args->arg1;
132ea0fabbcSTim J. Robbins 		a.nsems = args->arg2;
133ea0fabbcSTim J. Robbins 		a.semflg = args->arg3;
134ea0fabbcSTim J. Robbins 		return (linux_semget(td, &a));
135ea0fabbcSTim J. Robbins 	}
136ea0fabbcSTim J. Robbins 	case LINUX_SEMCTL: {
137ea0fabbcSTim J. Robbins 		struct linux_semctl_args a;
138ea0fabbcSTim J. Robbins 		int error;
139ea0fabbcSTim J. Robbins 
140ea0fabbcSTim J. Robbins 		a.semid = args->arg1;
141ea0fabbcSTim J. Robbins 		a.semnum = args->arg2;
142ea0fabbcSTim J. Robbins 		a.cmd = args->arg3;
1437dabf89bSDmitry Chagin 		error = copyin(PTRIN(args->ptr), &a.arg, sizeof(a.arg));
144ea0fabbcSTim J. Robbins 		if (error)
145ea0fabbcSTim J. Robbins 			return (error);
146ea0fabbcSTim J. Robbins 		return (linux_semctl(td, &a));
147ea0fabbcSTim J. Robbins 	}
1483245a2ecSDmitry Chagin 	case LINUX_SEMTIMEDOP: {
1493245a2ecSDmitry Chagin 		struct linux_semtimedop_args a;
1503245a2ecSDmitry Chagin 
1513245a2ecSDmitry Chagin 		a.semid = args->arg1;
1523245a2ecSDmitry Chagin 		a.tsops = PTRIN(args->ptr);
1533245a2ecSDmitry Chagin 		a.nsops = args->arg2;
1543245a2ecSDmitry Chagin 		a.timeout = PTRIN(args->arg5);
1553245a2ecSDmitry Chagin 		return (linux_semtimedop(td, &a));
1563245a2ecSDmitry Chagin 	}
157ea0fabbcSTim J. Robbins 	case LINUX_MSGSND: {
158ea0fabbcSTim J. Robbins 		struct linux_msgsnd_args a;
159ea0fabbcSTim J. Robbins 
160ea0fabbcSTim J. Robbins 		a.msqid = args->arg1;
1617dabf89bSDmitry Chagin 		a.msgp = PTRIN(args->ptr);
162ea0fabbcSTim J. Robbins 		a.msgsz = args->arg2;
163ea0fabbcSTim J. Robbins 		a.msgflg = args->arg3;
164ea0fabbcSTim J. Robbins 		return (linux_msgsnd(td, &a));
165ea0fabbcSTim J. Robbins 	}
166ea0fabbcSTim J. Robbins 	case LINUX_MSGRCV: {
167ea0fabbcSTim J. Robbins 		struct linux_msgrcv_args a;
168ea0fabbcSTim J. Robbins 
169ea0fabbcSTim J. Robbins 		a.msqid = args->arg1;
170ea0fabbcSTim J. Robbins 		a.msgsz = args->arg2;
171ea0fabbcSTim J. Robbins 		a.msgflg = args->arg3;
172ea0fabbcSTim J. Robbins 		if ((args->what >> 16) == 0) {
173ea0fabbcSTim J. Robbins 			struct l_ipc_kludge tmp;
174ea0fabbcSTim J. Robbins 			int error;
175ea0fabbcSTim J. Robbins 
176ea0fabbcSTim J. Robbins 			if (args->ptr == 0)
177ea0fabbcSTim J. Robbins 				return (EINVAL);
1787dabf89bSDmitry Chagin 			error = copyin(PTRIN(args->ptr), &tmp, sizeof(tmp));
179ea0fabbcSTim J. Robbins 			if (error)
180ea0fabbcSTim J. Robbins 				return (error);
181ea0fabbcSTim J. Robbins 			a.msgp = PTRIN(tmp.msgp);
182ea0fabbcSTim J. Robbins 			a.msgtyp = tmp.msgtyp;
183ea0fabbcSTim J. Robbins 		} else {
1847dabf89bSDmitry Chagin 			a.msgp = PTRIN(args->ptr);
185ea0fabbcSTim J. Robbins 			a.msgtyp = args->arg5;
186ea0fabbcSTim J. Robbins 		}
187ea0fabbcSTim J. Robbins 		return (linux_msgrcv(td, &a));
188ea0fabbcSTim J. Robbins 	}
189ea0fabbcSTim J. Robbins 	case LINUX_MSGGET: {
190ea0fabbcSTim J. Robbins 		struct linux_msgget_args a;
191ea0fabbcSTim J. Robbins 
192ea0fabbcSTim J. Robbins 		a.key = args->arg1;
193ea0fabbcSTim J. Robbins 		a.msgflg = args->arg2;
194ea0fabbcSTim J. Robbins 		return (linux_msgget(td, &a));
195ea0fabbcSTim J. Robbins 	}
196ea0fabbcSTim J. Robbins 	case LINUX_MSGCTL: {
197ea0fabbcSTim J. Robbins 		struct linux_msgctl_args a;
198ea0fabbcSTim J. Robbins 
199ea0fabbcSTim J. Robbins 		a.msqid = args->arg1;
200ea0fabbcSTim J. Robbins 		a.cmd = args->arg2;
2017dabf89bSDmitry Chagin 		a.buf = PTRIN(args->ptr);
202ea0fabbcSTim J. Robbins 		return (linux_msgctl(td, &a));
203ea0fabbcSTim J. Robbins 	}
204ea0fabbcSTim J. Robbins 	case LINUX_SHMAT: {
205ea0fabbcSTim J. Robbins 		struct linux_shmat_args a;
2067dabf89bSDmitry Chagin 		l_uintptr_t addr;
2077dabf89bSDmitry Chagin 		int error;
208ea0fabbcSTim J. Robbins 
209ea0fabbcSTim J. Robbins 		a.shmid = args->arg1;
2107dabf89bSDmitry Chagin 		a.shmaddr = PTRIN(args->ptr);
211ea0fabbcSTim J. Robbins 		a.shmflg = args->arg2;
2127dabf89bSDmitry Chagin 		error = linux_shmat(td, &a);
2137dabf89bSDmitry Chagin 		if (error != 0)
2147dabf89bSDmitry Chagin 			return (error);
2157dabf89bSDmitry Chagin 		addr = td->td_retval[0];
2167dabf89bSDmitry Chagin 		error = copyout(&addr, PTRIN(args->arg3), sizeof(addr));
2177dabf89bSDmitry Chagin 		td->td_retval[0] = 0;
2187dabf89bSDmitry Chagin 		return (error);
219ea0fabbcSTim J. Robbins 	}
220ea0fabbcSTim J. Robbins 	case LINUX_SHMDT: {
221ea0fabbcSTim J. Robbins 		struct linux_shmdt_args a;
222ea0fabbcSTim J. Robbins 
2237dabf89bSDmitry Chagin 		a.shmaddr = PTRIN(args->ptr);
224ea0fabbcSTim J. Robbins 		return (linux_shmdt(td, &a));
225ea0fabbcSTim J. Robbins 	}
226ea0fabbcSTim J. Robbins 	case LINUX_SHMGET: {
227ea0fabbcSTim J. Robbins 		struct linux_shmget_args a;
228ea0fabbcSTim J. Robbins 
229ea0fabbcSTim J. Robbins 		a.key = args->arg1;
230ea0fabbcSTim J. Robbins 		a.size = args->arg2;
231ea0fabbcSTim J. Robbins 		a.shmflg = args->arg3;
232ea0fabbcSTim J. Robbins 		return (linux_shmget(td, &a));
233ea0fabbcSTim J. Robbins 	}
234ea0fabbcSTim J. Robbins 	case LINUX_SHMCTL: {
235ea0fabbcSTim J. Robbins 		struct linux_shmctl_args a;
236ea0fabbcSTim J. Robbins 
237ea0fabbcSTim J. Robbins 		a.shmid = args->arg1;
238ea0fabbcSTim J. Robbins 		a.cmd = args->arg2;
2397dabf89bSDmitry Chagin 		a.buf = PTRIN(args->ptr);
240ea0fabbcSTim J. Robbins 		return (linux_shmctl(td, &a));
241ea0fabbcSTim J. Robbins 	}
242ea0fabbcSTim J. Robbins 	default:
243ea0fabbcSTim J. Robbins 		break;
244ea0fabbcSTim J. Robbins 	}
245ea0fabbcSTim J. Robbins 
246ea0fabbcSTim J. Robbins 	return (EINVAL);
247ea0fabbcSTim J. Robbins }
248ea0fabbcSTim J. Robbins 
249ea0fabbcSTim J. Robbins int
linux_old_select(struct thread * td,struct linux_old_select_args * args)250ea0fabbcSTim J. Robbins linux_old_select(struct thread *td, struct linux_old_select_args *args)
251ea0fabbcSTim J. Robbins {
252ea0fabbcSTim J. Robbins 	struct l_old_select_argv linux_args;
253ea0fabbcSTim J. Robbins 	struct linux_select_args newsel;
254ea0fabbcSTim J. Robbins 	int error;
255ea0fabbcSTim J. Robbins 
256ea0fabbcSTim J. Robbins 	error = copyin(args->ptr, &linux_args, sizeof(linux_args));
257ea0fabbcSTim J. Robbins 	if (error)
258ea0fabbcSTim J. Robbins 		return (error);
259ea0fabbcSTim J. Robbins 
260ea0fabbcSTim J. Robbins 	newsel.nfds = linux_args.nfds;
261ea0fabbcSTim J. Robbins 	newsel.readfds = PTRIN(linux_args.readfds);
262ea0fabbcSTim J. Robbins 	newsel.writefds = PTRIN(linux_args.writefds);
263ea0fabbcSTim J. Robbins 	newsel.exceptfds = PTRIN(linux_args.exceptfds);
264ea0fabbcSTim J. Robbins 	newsel.timeout = PTRIN(linux_args.timeout);
265ea0fabbcSTim J. Robbins 	return (linux_select(td, &newsel));
266ea0fabbcSTim J. Robbins }
267ea0fabbcSTim J. Robbins 
268ea0fabbcSTim J. Robbins int
linux_set_cloned_tls(struct thread * td,void * desc)2692c7660baSDmitry Chagin linux_set_cloned_tls(struct thread *td, void *desc)
2702c7660baSDmitry Chagin {
2712c7660baSDmitry Chagin 	struct l_user_desc info;
2722c7660baSDmitry Chagin 	struct pcb *pcb;
2732c7660baSDmitry Chagin 	int error;
2742c7660baSDmitry Chagin 
2752c7660baSDmitry Chagin 	error = copyin(desc, &info, sizeof(struct l_user_desc));
2762c7660baSDmitry Chagin 	if (error) {
277c5156c77SDmitry Chagin 		linux_msg(td, "set_cloned_tls copyin info failed!");
2782c7660baSDmitry Chagin 	} else {
2792c7660baSDmitry Chagin 		/* We might copy out the entry_number as GUGS32_SEL. */
2802c7660baSDmitry Chagin 		info.entry_number = GUGS32_SEL;
2812c7660baSDmitry Chagin 		error = copyout(&info, desc, sizeof(struct l_user_desc));
2822c7660baSDmitry Chagin 		if (error)
283c5156c77SDmitry Chagin 			linux_msg(td, "set_cloned_tls copyout info failed!");
2842c7660baSDmitry Chagin 
2852c7660baSDmitry Chagin 		pcb = td->td_pcb;
286704547ceSJohn Baldwin 		update_pcb_bases(pcb);
2872c7660baSDmitry Chagin 		pcb->pcb_gsbase = (register_t)info.base_addr;
2882c7660baSDmitry Chagin 		td->td_frame->tf_gs = GSEL(GUGS32_SEL, SEL_UPL);
2892c7660baSDmitry Chagin 	}
2902c7660baSDmitry Chagin 
2912c7660baSDmitry Chagin 	return (error);
2922c7660baSDmitry Chagin }
2932c7660baSDmitry Chagin 
294ea0fabbcSTim J. Robbins int
linux_set_upcall(struct thread * td,register_t stack)2953b57ddb0SJohn Baldwin linux_set_upcall(struct thread *td, register_t stack)
296c8d6845eSDmitry Chagin {
297c8d6845eSDmitry Chagin 
29881338031SDmitry Chagin 	if (stack)
299c8d6845eSDmitry Chagin 		td->td_frame->tf_rsp = stack;
300c8d6845eSDmitry Chagin 
30181338031SDmitry Chagin 	/*
30281338031SDmitry Chagin 	 * The newly created Linux thread returns
30381338031SDmitry Chagin 	 * to the user space by the same path that a parent do.
30481338031SDmitry Chagin 	 */
30581338031SDmitry Chagin 	td->td_frame->tf_rax = 0;
306c8d6845eSDmitry Chagin 	return (0);
307c8d6845eSDmitry Chagin }
308c8d6845eSDmitry Chagin 
309ea0fabbcSTim J. Robbins int
linux_mmap(struct thread * td,struct linux_mmap_args * args)310ea0fabbcSTim J. Robbins linux_mmap(struct thread *td, struct linux_mmap_args *args)
311ea0fabbcSTim J. Robbins {
312ea0fabbcSTim J. Robbins 	int error;
313ea0fabbcSTim J. Robbins 	struct l_mmap_argv linux_args;
314ea0fabbcSTim J. Robbins 
315ea0fabbcSTim J. Robbins 	error = copyin(args->ptr, &linux_args, sizeof(linux_args));
316ea0fabbcSTim J. Robbins 	if (error)
317ea0fabbcSTim J. Robbins 		return (error);
318ea0fabbcSTim J. Robbins 
319f12c0348SJohn Baldwin 	return (linux_mmap_common(td, linux_args.addr, linux_args.len,
320f12c0348SJohn Baldwin 	    linux_args.prot, linux_args.flags, linux_args.fd,
321f12c0348SJohn Baldwin 	    (uint32_t)linux_args.pgoff));
322ea0fabbcSTim J. Robbins }
323ea0fabbcSTim J. Robbins 
324ea0fabbcSTim J. Robbins int
linux_iopl(struct thread * td,struct linux_iopl_args * args)3251e5ed8c1SJung-uk Kim linux_iopl(struct thread *td, struct linux_iopl_args *args)
3261e5ed8c1SJung-uk Kim {
3271e5ed8c1SJung-uk Kim 	int error;
3281e5ed8c1SJung-uk Kim 
3291e5ed8c1SJung-uk Kim 	if (args->level < 0 || args->level > 3)
3301e5ed8c1SJung-uk Kim 		return (EINVAL);
3311e5ed8c1SJung-uk Kim 	if ((error = priv_check(td, PRIV_IO)) != 0)
3321e5ed8c1SJung-uk Kim 		return (error);
3331e5ed8c1SJung-uk Kim 	if ((error = securelevel_gt(td->td_ucred, 0)) != 0)
3341e5ed8c1SJung-uk Kim 		return (error);
3351e5ed8c1SJung-uk Kim 	td->td_frame->tf_rflags = (td->td_frame->tf_rflags & ~PSL_IOPL) |
3361e5ed8c1SJung-uk Kim 	    (args->level * (PSL_IOPL / 3));
3371e5ed8c1SJung-uk Kim 
3381e5ed8c1SJung-uk Kim 	return (0);
3391e5ed8c1SJung-uk Kim }
3401e5ed8c1SJung-uk Kim 
3411e5ed8c1SJung-uk Kim int
linux_sigaction(struct thread * td,struct linux_sigaction_args * args)342ea0fabbcSTim J. Robbins linux_sigaction(struct thread *td, struct linux_sigaction_args *args)
343ea0fabbcSTim J. Robbins {
344ea0fabbcSTim J. Robbins 	l_osigaction_t osa;
345ea0fabbcSTim J. Robbins 	l_sigaction_t act, oact;
346ea0fabbcSTim J. Robbins 	int error;
347ea0fabbcSTim J. Robbins 
348ea0fabbcSTim J. Robbins 	if (args->nsa != NULL) {
349ea0fabbcSTim J. Robbins 		error = copyin(args->nsa, &osa, sizeof(l_osigaction_t));
350ea0fabbcSTim J. Robbins 		if (error)
351ea0fabbcSTim J. Robbins 			return (error);
352ea0fabbcSTim J. Robbins 		act.lsa_handler = osa.lsa_handler;
353ea0fabbcSTim J. Robbins 		act.lsa_flags = osa.lsa_flags;
354ea0fabbcSTim J. Robbins 		act.lsa_restorer = osa.lsa_restorer;
355ea0fabbcSTim J. Robbins 		LINUX_SIGEMPTYSET(act.lsa_mask);
3564ab7403bSDmitry Chagin 		act.lsa_mask.__mask = osa.lsa_mask;
357ea0fabbcSTim J. Robbins 	}
358ea0fabbcSTim J. Robbins 
359ea0fabbcSTim J. Robbins 	error = linux_do_sigaction(td, args->sig, args->nsa ? &act : NULL,
360ea0fabbcSTim J. Robbins 	    args->osa ? &oact : NULL);
361ea0fabbcSTim J. Robbins 
362ea0fabbcSTim J. Robbins 	if (args->osa != NULL && !error) {
363ea0fabbcSTim J. Robbins 		osa.lsa_handler = oact.lsa_handler;
364ea0fabbcSTim J. Robbins 		osa.lsa_flags = oact.lsa_flags;
365ea0fabbcSTim J. Robbins 		osa.lsa_restorer = oact.lsa_restorer;
3664ab7403bSDmitry Chagin 		osa.lsa_mask = oact.lsa_mask.__mask;
367ea0fabbcSTim J. Robbins 		error = copyout(&osa, args->osa, sizeof(l_osigaction_t));
368ea0fabbcSTim J. Robbins 	}
369ea0fabbcSTim J. Robbins 
370ea0fabbcSTim J. Robbins 	return (error);
371ea0fabbcSTim J. Robbins }
372ea0fabbcSTim J. Robbins 
373ea0fabbcSTim J. Robbins /*
374b5def2b6SJung-uk Kim  * Linux has two extra args, restart and oldmask.  We don't use these,
375ea0fabbcSTim J. Robbins  * but it seems that "restart" is actually a context pointer that
376ea0fabbcSTim J. Robbins  * enables the signal to happen with a different register set.
377ea0fabbcSTim J. Robbins  */
378ea0fabbcSTim J. Robbins int
linux_sigsuspend(struct thread * td,struct linux_sigsuspend_args * args)379ea0fabbcSTim J. Robbins linux_sigsuspend(struct thread *td, struct linux_sigsuspend_args *args)
380ea0fabbcSTim J. Robbins {
381ea0fabbcSTim J. Robbins 	sigset_t sigmask;
382ea0fabbcSTim J. Robbins 	l_sigset_t mask;
383ea0fabbcSTim J. Robbins 
384ea0fabbcSTim J. Robbins 	LINUX_SIGEMPTYSET(mask);
3854ab7403bSDmitry Chagin 	mask.__mask = args->mask;
386ea0fabbcSTim J. Robbins 	linux_to_bsd_sigset(&mask, &sigmask);
387ea0fabbcSTim J. Robbins 	return (kern_sigsuspend(td, sigmask));
388ea0fabbcSTim J. Robbins }
389ea0fabbcSTim J. Robbins 
390ea0fabbcSTim J. Robbins int
linux_pause(struct thread * td,struct linux_pause_args * args)391ea0fabbcSTim J. Robbins linux_pause(struct thread *td, struct linux_pause_args *args)
392ea0fabbcSTim J. Robbins {
393ea0fabbcSTim J. Robbins 	struct proc *p = td->td_proc;
394ea0fabbcSTim J. Robbins 	sigset_t sigmask;
395ea0fabbcSTim J. Robbins 
396ea0fabbcSTim J. Robbins 	PROC_LOCK(p);
397ea0fabbcSTim J. Robbins 	sigmask = td->td_sigmask;
398ea0fabbcSTim J. Robbins 	PROC_UNLOCK(p);
399ea0fabbcSTim J. Robbins 	return (kern_sigsuspend(td, sigmask));
400ea0fabbcSTim J. Robbins }
401ea0fabbcSTim J. Robbins 
402ea0fabbcSTim J. Robbins int
linux_gettimeofday(struct thread * td,struct linux_gettimeofday_args * uap)403ea0fabbcSTim J. Robbins linux_gettimeofday(struct thread *td, struct linux_gettimeofday_args *uap)
404ea0fabbcSTim J. Robbins {
405ea0fabbcSTim J. Robbins 	struct timeval atv;
406ea0fabbcSTim J. Robbins 	l_timeval atv32;
407ea0fabbcSTim J. Robbins 	struct timezone rtz;
408ea0fabbcSTim J. Robbins 	int error = 0;
409ea0fabbcSTim J. Robbins 
410ea0fabbcSTim J. Robbins 	if (uap->tp) {
411ea0fabbcSTim J. Robbins 		microtime(&atv);
412ea0fabbcSTim J. Robbins 		atv32.tv_sec = atv.tv_sec;
413ea0fabbcSTim J. Robbins 		atv32.tv_usec = atv.tv_usec;
414ea0fabbcSTim J. Robbins 		error = copyout(&atv32, uap->tp, sizeof(atv32));
415ea0fabbcSTim J. Robbins 	}
416ea0fabbcSTim J. Robbins 	if (error == 0 && uap->tzp != NULL) {
417329f0aa9SWarner Losh 		rtz.tz_minuteswest = 0;
418329f0aa9SWarner Losh 		rtz.tz_dsttime = 0;
419ea0fabbcSTim J. Robbins 		error = copyout(&rtz, uap->tzp, sizeof(rtz));
420ea0fabbcSTim J. Robbins 	}
421ea0fabbcSTim J. Robbins 	return (error);
422ea0fabbcSTim J. Robbins }
423ea0fabbcSTim J. Robbins 
424ea0fabbcSTim J. Robbins int
linux_settimeofday(struct thread * td,struct linux_settimeofday_args * uap)42586a0e5dbSJung-uk Kim linux_settimeofday(struct thread *td, struct linux_settimeofday_args *uap)
42686a0e5dbSJung-uk Kim {
42786a0e5dbSJung-uk Kim 	l_timeval atv32;
42886a0e5dbSJung-uk Kim 	struct timeval atv, *tvp;
42986a0e5dbSJung-uk Kim 	struct timezone atz, *tzp;
43086a0e5dbSJung-uk Kim 	int error;
43186a0e5dbSJung-uk Kim 
43286a0e5dbSJung-uk Kim 	if (uap->tp) {
43386a0e5dbSJung-uk Kim 		error = copyin(uap->tp, &atv32, sizeof(atv32));
43486a0e5dbSJung-uk Kim 		if (error)
43586a0e5dbSJung-uk Kim 			return (error);
43686a0e5dbSJung-uk Kim 		atv.tv_sec = atv32.tv_sec;
43786a0e5dbSJung-uk Kim 		atv.tv_usec = atv32.tv_usec;
43886a0e5dbSJung-uk Kim 		tvp = &atv;
43986a0e5dbSJung-uk Kim 	} else
44086a0e5dbSJung-uk Kim 		tvp = NULL;
44186a0e5dbSJung-uk Kim 	if (uap->tzp) {
44286a0e5dbSJung-uk Kim 		error = copyin(uap->tzp, &atz, sizeof(atz));
44386a0e5dbSJung-uk Kim 		if (error)
44486a0e5dbSJung-uk Kim 			return (error);
44586a0e5dbSJung-uk Kim 		tzp = &atz;
44686a0e5dbSJung-uk Kim 	} else
44786a0e5dbSJung-uk Kim 		tzp = NULL;
44886a0e5dbSJung-uk Kim 	return (kern_settimeofday(td, tvp, tzp));
44986a0e5dbSJung-uk Kim }
45086a0e5dbSJung-uk Kim 
45186a0e5dbSJung-uk Kim int
linux_getrusage(struct thread * td,struct linux_getrusage_args * uap)452ea0fabbcSTim J. Robbins linux_getrusage(struct thread *td, struct linux_getrusage_args *uap)
453ea0fabbcSTim J. Robbins {
45478c85e8dSJohn Baldwin 	struct rusage s;
455ea0fabbcSTim J. Robbins 	int error;
456ea0fabbcSTim J. Robbins 
45778c85e8dSJohn Baldwin 	error = kern_getrusage(td, uap->who, &s);
458ea0fabbcSTim J. Robbins 	if (error != 0)
459ea0fabbcSTim J. Robbins 		return (error);
460001398c4SDmitry Chagin 	if (uap->rusage != NULL)
461001398c4SDmitry Chagin 		error = linux_copyout_rusage(&s, uap->rusage);
462ea0fabbcSTim J. Robbins 	return (error);
463ea0fabbcSTim J. Robbins }
464ea0fabbcSTim J. Robbins 
465ea0fabbcSTim J. Robbins int
linux_set_thread_area(struct thread * td,struct linux_set_thread_area_args * args)4669c5b213eSJung-uk Kim linux_set_thread_area(struct thread *td,
4679c5b213eSJung-uk Kim     struct linux_set_thread_area_args *args)
468ea0fabbcSTim J. Robbins {
4699c5b213eSJung-uk Kim 	struct l_user_desc info;
470e6c006d9SJung-uk Kim 	struct pcb *pcb;
4719c5b213eSJung-uk Kim 	int error;
472ea0fabbcSTim J. Robbins 
4739c5b213eSJung-uk Kim 	error = copyin(args->desc, &info, sizeof(struct l_user_desc));
4749c5b213eSJung-uk Kim 	if (error)
4759c5b213eSJung-uk Kim 		return (error);
4769c5b213eSJung-uk Kim 
4779c5b213eSJung-uk Kim 	/*
4789c5b213eSJung-uk Kim 	 * Semantics of Linux version: every thread in the system has array
4799c5b213eSJung-uk Kim 	 * of three TLS descriptors. 1st is GLIBC TLS, 2nd is WINE, 3rd unknown.
48029eab3e4SGordon Bergling 	 * This syscall loads one of the selected TLS descriptors with a value
4819c5b213eSJung-uk Kim 	 * and also loads GDT descriptors 6, 7 and 8 with the content of
4829c5b213eSJung-uk Kim 	 * the per-thread descriptors.
4839c5b213eSJung-uk Kim 	 *
4849c5b213eSJung-uk Kim 	 * Semantics of FreeBSD version: I think we can ignore that Linux has
4859c5b213eSJung-uk Kim 	 * three per-thread descriptors and use just the first one.
4869c5b213eSJung-uk Kim 	 * The tls_array[] is used only in [gs]et_thread_area() syscalls and
4879c5b213eSJung-uk Kim 	 * for loading the GDT descriptors. We use just one GDT descriptor
4889c5b213eSJung-uk Kim 	 * for TLS, so we will load just one.
489f1753e05SJung-uk Kim 	 *
490f1753e05SJung-uk Kim 	 * XXX: This doesn't work when a user space process tries to use more
4919c5b213eSJung-uk Kim 	 * than one TLS segment. Comment in the Linux source says wine might
492f1753e05SJung-uk Kim 	 * do this.
4939c5b213eSJung-uk Kim 	 */
4949c5b213eSJung-uk Kim 
4959c5b213eSJung-uk Kim 	/*
4969c5b213eSJung-uk Kim 	 * GLIBC reads current %gs and call set_thread_area() with it.
4979c5b213eSJung-uk Kim 	 * We should let GUDATA_SEL and GUGS32_SEL proceed as well because
4989c5b213eSJung-uk Kim 	 * we use these segments.
4999c5b213eSJung-uk Kim 	 */
5009c5b213eSJung-uk Kim 	switch (info.entry_number) {
5019c5b213eSJung-uk Kim 	case GUGS32_SEL:
5029c5b213eSJung-uk Kim 	case GUDATA_SEL:
5039c5b213eSJung-uk Kim 	case 6:
5049c5b213eSJung-uk Kim 	case -1:
5059c5b213eSJung-uk Kim 		info.entry_number = GUGS32_SEL;
5069c5b213eSJung-uk Kim 		break;
5079c5b213eSJung-uk Kim 	default:
5089c5b213eSJung-uk Kim 		return (EINVAL);
5099c5b213eSJung-uk Kim 	}
5109c5b213eSJung-uk Kim 
5119c5b213eSJung-uk Kim 	/*
5129c5b213eSJung-uk Kim 	 * We have to copy out the GDT entry we use.
513f1753e05SJung-uk Kim 	 *
514f1753e05SJung-uk Kim 	 * XXX: What if a user space program does not check the return value
515f1753e05SJung-uk Kim 	 * and tries to use 6, 7 or 8?
5169c5b213eSJung-uk Kim 	 */
5179c5b213eSJung-uk Kim 	error = copyout(&info, args->desc, sizeof(struct l_user_desc));
5189c5b213eSJung-uk Kim 	if (error)
5199c5b213eSJung-uk Kim 		return (error);
5209c5b213eSJung-uk Kim 
521e6c006d9SJung-uk Kim 	pcb = td->td_pcb;
522704547ceSJohn Baldwin 	update_pcb_bases(pcb);
523e6c006d9SJung-uk Kim 	pcb->pcb_gsbase = (register_t)info.base_addr;
5242c66cccaSKonstantin Belousov 	update_gdt_gsbase(td, info.base_addr);
5259c5b213eSJung-uk Kim 
5269c5b213eSJung-uk Kim 	return (0);
527ea0fabbcSTim J. Robbins }
528cb0eecdfSKonstantin Belousov 
52995c19e1dSEdward Tomasz Napierala void
bsd_to_linux_regset32(const struct reg32 * b_reg,struct linux_pt_regset32 * l_regset)5303417c298SEdward Tomasz Napierala bsd_to_linux_regset32(const struct reg32 *b_reg,
5313417c298SEdward Tomasz Napierala     struct linux_pt_regset32 *l_regset)
53295c19e1dSEdward Tomasz Napierala {
53395c19e1dSEdward Tomasz Napierala 
53495c19e1dSEdward Tomasz Napierala 	l_regset->ebx = b_reg->r_ebx;
53595c19e1dSEdward Tomasz Napierala 	l_regset->ecx = b_reg->r_ecx;
53695c19e1dSEdward Tomasz Napierala 	l_regset->edx = b_reg->r_edx;
53795c19e1dSEdward Tomasz Napierala 	l_regset->esi = b_reg->r_esi;
53895c19e1dSEdward Tomasz Napierala 	l_regset->edi = b_reg->r_edi;
53995c19e1dSEdward Tomasz Napierala 	l_regset->ebp = b_reg->r_ebp;
54095c19e1dSEdward Tomasz Napierala 	l_regset->eax = b_reg->r_eax;
54195c19e1dSEdward Tomasz Napierala 	l_regset->ds = b_reg->r_ds;
54295c19e1dSEdward Tomasz Napierala 	l_regset->es = b_reg->r_es;
54395c19e1dSEdward Tomasz Napierala 	l_regset->fs = b_reg->r_fs;
54495c19e1dSEdward Tomasz Napierala 	l_regset->gs = b_reg->r_gs;
54595c19e1dSEdward Tomasz Napierala 	l_regset->orig_eax = b_reg->r_eax;
54695c19e1dSEdward Tomasz Napierala 	l_regset->eip = b_reg->r_eip;
54795c19e1dSEdward Tomasz Napierala 	l_regset->cs = b_reg->r_cs;
54895c19e1dSEdward Tomasz Napierala 	l_regset->eflags = b_reg->r_eflags;
54995c19e1dSEdward Tomasz Napierala 	l_regset->esp = b_reg->r_esp;
55095c19e1dSEdward Tomasz Napierala 	l_regset->ss = b_reg->r_ss;
55195c19e1dSEdward Tomasz Napierala }
55295c19e1dSEdward Tomasz Napierala 
553cb0eecdfSKonstantin Belousov int futex_xchgl_nosmap(int oparg, uint32_t *uaddr, int *oldval);
554cb0eecdfSKonstantin Belousov int futex_xchgl_smap(int oparg, uint32_t *uaddr, int *oldval);
5557c5a46a1SKonstantin Belousov DEFINE_IFUNC(, int, futex_xchgl, (int, uint32_t *, int *))
556cb0eecdfSKonstantin Belousov {
557cb0eecdfSKonstantin Belousov 
558cb0eecdfSKonstantin Belousov 	return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
559cb0eecdfSKonstantin Belousov 	    futex_xchgl_smap : futex_xchgl_nosmap);
560cb0eecdfSKonstantin Belousov }
561cb0eecdfSKonstantin Belousov 
562cb0eecdfSKonstantin Belousov int futex_addl_nosmap(int oparg, uint32_t *uaddr, int *oldval);
563cb0eecdfSKonstantin Belousov int futex_addl_smap(int oparg, uint32_t *uaddr, int *oldval);
5647c5a46a1SKonstantin Belousov DEFINE_IFUNC(, int, futex_addl, (int, uint32_t *, int *))
565cb0eecdfSKonstantin Belousov {
566cb0eecdfSKonstantin Belousov 
567cb0eecdfSKonstantin Belousov 	return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
568cb0eecdfSKonstantin Belousov 	    futex_addl_smap : futex_addl_nosmap);
569cb0eecdfSKonstantin Belousov }
570cb0eecdfSKonstantin Belousov 
571cb0eecdfSKonstantin Belousov int futex_orl_nosmap(int oparg, uint32_t *uaddr, int *oldval);
572cb0eecdfSKonstantin Belousov int futex_orl_smap(int oparg, uint32_t *uaddr, int *oldval);
5737c5a46a1SKonstantin Belousov DEFINE_IFUNC(, int, futex_orl, (int, uint32_t *, int *))
574cb0eecdfSKonstantin Belousov {
575cb0eecdfSKonstantin Belousov 
576cb0eecdfSKonstantin Belousov 	return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
577cb0eecdfSKonstantin Belousov 	    futex_orl_smap : futex_orl_nosmap);
578cb0eecdfSKonstantin Belousov }
579cb0eecdfSKonstantin Belousov 
580cb0eecdfSKonstantin Belousov int futex_andl_nosmap(int oparg, uint32_t *uaddr, int *oldval);
581cb0eecdfSKonstantin Belousov int futex_andl_smap(int oparg, uint32_t *uaddr, int *oldval);
5827c5a46a1SKonstantin Belousov DEFINE_IFUNC(, int, futex_andl, (int, uint32_t *, int *))
583cb0eecdfSKonstantin Belousov {
584cb0eecdfSKonstantin Belousov 
585cb0eecdfSKonstantin Belousov 	return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
586cb0eecdfSKonstantin Belousov 	    futex_andl_smap : futex_andl_nosmap);
587cb0eecdfSKonstantin Belousov }
588cb0eecdfSKonstantin Belousov 
589cb0eecdfSKonstantin Belousov int futex_xorl_nosmap(int oparg, uint32_t *uaddr, int *oldval);
590cb0eecdfSKonstantin Belousov int futex_xorl_smap(int oparg, uint32_t *uaddr, int *oldval);
5917c5a46a1SKonstantin Belousov DEFINE_IFUNC(, int, futex_xorl, (int, uint32_t *, int *))
592cb0eecdfSKonstantin Belousov {
593cb0eecdfSKonstantin Belousov 
594cb0eecdfSKonstantin Belousov 	return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
595cb0eecdfSKonstantin Belousov 	    futex_xorl_smap : futex_xorl_nosmap);
596cb0eecdfSKonstantin Belousov }
597dd2a6cd7SDmitry Chagin 
598dd2a6cd7SDmitry Chagin int
linux_ptrace_peekuser(struct thread * td,pid_t pid,void * addr,void * data)599dd2a6cd7SDmitry Chagin linux_ptrace_peekuser(struct thread *td, pid_t pid, void *addr, void *data)
600dd2a6cd7SDmitry Chagin {
601dd2a6cd7SDmitry Chagin 
602dd2a6cd7SDmitry Chagin 	LINUX_RATELIMIT_MSG_OPT1("PTRACE_PEEKUSER offset %ld not implemented; "
603dd2a6cd7SDmitry Chagin 	    "returning EINVAL", (uintptr_t)addr);
604dd2a6cd7SDmitry Chagin 	return (EINVAL);
605dd2a6cd7SDmitry Chagin }
6063d0addcdSDmitry Chagin 
6073d0addcdSDmitry Chagin int
linux_ptrace_pokeuser(struct thread * td,pid_t pid,void * addr,void * data)6083d0addcdSDmitry Chagin linux_ptrace_pokeuser(struct thread *td, pid_t pid, void *addr, void *data)
6093d0addcdSDmitry Chagin {
6103d0addcdSDmitry Chagin 
6113d0addcdSDmitry Chagin 	LINUX_RATELIMIT_MSG_OPT1("PTRACE_POKEUSER offset %ld "
6123d0addcdSDmitry Chagin 	    "not implemented; returning EINVAL", (uintptr_t)addr);
6133d0addcdSDmitry Chagin 	return (EINVAL);
6143d0addcdSDmitry Chagin }
615