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