linux32_machdep.c revision 162954
1133819Stjr/*- 2133819Stjr * Copyright (c) 2004 Tim J. Robbins 3133819Stjr * Copyright (c) 2002 Doug Rabson 4133819Stjr * Copyright (c) 2000 Marcel Moolenaar 5133819Stjr * All rights reserved. 6133819Stjr * 7133819Stjr * Redistribution and use in source and binary forms, with or without 8133819Stjr * modification, are permitted provided that the following conditions 9133819Stjr * are met: 10133819Stjr * 1. Redistributions of source code must retain the above copyright 11133819Stjr * notice, this list of conditions and the following disclaimer 12133819Stjr * in this position and unchanged. 13133819Stjr * 2. Redistributions in binary form must reproduce the above copyright 14133819Stjr * notice, this list of conditions and the following disclaimer in the 15133819Stjr * documentation and/or other materials provided with the distribution. 16133819Stjr * 3. The name of the author may not be used to endorse or promote products 17133819Stjr * derived from this software without specific prior written permission. 18133819Stjr * 19133819Stjr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20133819Stjr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21133819Stjr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22133819Stjr * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23133819Stjr * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24133819Stjr * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25133819Stjr * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26133819Stjr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27133819Stjr * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28133819Stjr * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29133819Stjr */ 30133819Stjr 31133819Stjr#include <sys/cdefs.h> 32133819Stjr__FBSDID("$FreeBSD: head/sys/amd64/linux32/linux32_machdep.c 162954 2006-10-02 12:59:59Z phk $"); 33133819Stjr 34133819Stjr#include <sys/param.h> 35133819Stjr#include <sys/kernel.h> 36133819Stjr#include <sys/systm.h> 37162954Sphk#include <sys/clock.h> 38142057Sjhb#include <sys/imgact.h> 39161310Snetchild#include <sys/limits.h> 40133819Stjr#include <sys/lock.h> 41133819Stjr#include <sys/malloc.h> 42133819Stjr#include <sys/mman.h> 43133819Stjr#include <sys/mutex.h> 44133819Stjr#include <sys/proc.h> 45133819Stjr#include <sys/resource.h> 46133819Stjr#include <sys/resourcevar.h> 47133819Stjr#include <sys/syscallsubr.h> 48133819Stjr#include <sys/sysproto.h> 49133819Stjr#include <sys/unistd.h> 50133819Stjr 51133819Stjr#include <machine/frame.h> 52133819Stjr 53133819Stjr#include <vm/vm.h> 54133819Stjr#include <vm/pmap.h> 55142057Sjhb#include <vm/vm_extern.h> 56142057Sjhb#include <vm/vm_kern.h> 57133819Stjr#include <vm/vm_map.h> 58133819Stjr 59133819Stjr#include <amd64/linux32/linux.h> 60133819Stjr#include <amd64/linux32/linux32_proto.h> 61133819Stjr#include <compat/linux/linux_ipc.h> 62133819Stjr#include <compat/linux/linux_signal.h> 63133819Stjr#include <compat/linux/linux_util.h> 64161474Snetchild#include <compat/linux/linux_emul.h> 65133819Stjr 66133819Stjrstruct l_old_select_argv { 67133819Stjr l_int nfds; 68133819Stjr l_uintptr_t readfds; 69133819Stjr l_uintptr_t writefds; 70133819Stjr l_uintptr_t exceptfds; 71133819Stjr l_uintptr_t timeout; 72133819Stjr} __packed; 73133819Stjr 74133819Stjrint 75133819Stjrlinux_to_bsd_sigaltstack(int lsa) 76133819Stjr{ 77133819Stjr int bsa = 0; 78133819Stjr 79133819Stjr if (lsa & LINUX_SS_DISABLE) 80133819Stjr bsa |= SS_DISABLE; 81133819Stjr if (lsa & LINUX_SS_ONSTACK) 82133819Stjr bsa |= SS_ONSTACK; 83133819Stjr return (bsa); 84133819Stjr} 85133819Stjr 86133819Stjrint 87133819Stjrbsd_to_linux_sigaltstack(int bsa) 88133819Stjr{ 89133819Stjr int lsa = 0; 90133819Stjr 91133819Stjr if (bsa & SS_DISABLE) 92133819Stjr lsa |= LINUX_SS_DISABLE; 93133819Stjr if (bsa & SS_ONSTACK) 94133819Stjr lsa |= LINUX_SS_ONSTACK; 95133819Stjr return (lsa); 96133819Stjr} 97133819Stjr 98142057Sjhb/* 99142057Sjhb * Custom version of exec_copyin_args() so that we can translate 100142057Sjhb * the pointers. 101142057Sjhb */ 102142057Sjhbstatic int 103142057Sjhblinux_exec_copyin_args(struct image_args *args, char *fname, 104142057Sjhb enum uio_seg segflg, char **argv, char **envv) 105133819Stjr{ 106142057Sjhb char *argp, *envp; 107142057Sjhb u_int32_t *p32, arg; 108142057Sjhb size_t length; 109133819Stjr int error; 110133819Stjr 111142057Sjhb bzero(args, sizeof(*args)); 112142057Sjhb if (argv == NULL) 113142057Sjhb return (EFAULT); 114133819Stjr 115142057Sjhb /* 116142057Sjhb * Allocate temporary demand zeroed space for argument and 117142057Sjhb * environment strings 118142057Sjhb */ 119147588Sjhb args->buf = (char *) kmem_alloc_wait(exec_map, 120147588Sjhb PATH_MAX + ARG_MAX + MAXSHELLCMDLEN); 121142057Sjhb if (args->buf == NULL) 122142057Sjhb return (ENOMEM); 123142057Sjhb args->begin_argv = args->buf; 124142057Sjhb args->endp = args->begin_argv; 125142057Sjhb args->stringspace = ARG_MAX; 126133819Stjr 127142057Sjhb args->fname = args->buf + ARG_MAX; 128133819Stjr 129142057Sjhb /* 130142057Sjhb * Copy the file name. 131142057Sjhb */ 132142057Sjhb error = (segflg == UIO_SYSSPACE) ? 133142057Sjhb copystr(fname, args->fname, PATH_MAX, &length) : 134142057Sjhb copyinstr(fname, args->fname, PATH_MAX, &length); 135142057Sjhb if (error != 0) 136156440Sups goto err_exit; 137142057Sjhb 138142057Sjhb /* 139142057Sjhb * extract arguments first 140142057Sjhb */ 141142057Sjhb p32 = (u_int32_t *)argv; 142142057Sjhb for (;;) { 143142057Sjhb error = copyin(p32++, &arg, sizeof(arg)); 144142057Sjhb if (error) 145156440Sups goto err_exit; 146142057Sjhb if (arg == 0) 147142057Sjhb break; 148142057Sjhb argp = PTRIN(arg); 149142057Sjhb error = copyinstr(argp, args->endp, args->stringspace, &length); 150142057Sjhb if (error) { 151142057Sjhb if (error == ENAMETOOLONG) 152156440Sups error = E2BIG; 153156440Sups 154156440Sups goto err_exit; 155142057Sjhb } 156142057Sjhb args->stringspace -= length; 157142057Sjhb args->endp += length; 158142057Sjhb args->argc++; 159133819Stjr } 160142057Sjhb 161142057Sjhb args->begin_envv = args->endp; 162142057Sjhb 163142057Sjhb /* 164142057Sjhb * extract environment strings 165142057Sjhb */ 166142057Sjhb if (envv) { 167142057Sjhb p32 = (u_int32_t *)envv; 168142057Sjhb for (;;) { 169133819Stjr error = copyin(p32++, &arg, sizeof(arg)); 170133819Stjr if (error) 171156440Sups goto err_exit; 172142057Sjhb if (arg == 0) 173142057Sjhb break; 174142057Sjhb envp = PTRIN(arg); 175142057Sjhb error = copyinstr(envp, args->endp, args->stringspace, 176142057Sjhb &length); 177142057Sjhb if (error) { 178142057Sjhb if (error == ENAMETOOLONG) 179156440Sups error = E2BIG; 180156440Sups goto err_exit; 181142057Sjhb } 182142057Sjhb args->stringspace -= length; 183142057Sjhb args->endp += length; 184142057Sjhb args->envc++; 185142057Sjhb } 186133819Stjr } 187133819Stjr 188142057Sjhb return (0); 189156440Sups 190156440Supserr_exit: 191156440Sups kmem_free_wakeup(exec_map, (vm_offset_t)args->buf, 192156440Sups PATH_MAX + ARG_MAX + MAXSHELLCMDLEN); 193156440Sups args->buf = NULL; 194156440Sups return (error); 195133819Stjr} 196133819Stjr 197142057Sjhbint 198142057Sjhblinux_execve(struct thread *td, struct linux_execve_args *args) 199142057Sjhb{ 200142057Sjhb struct image_args eargs; 201142057Sjhb char *path; 202142057Sjhb int error; 203142057Sjhb 204142057Sjhb LCONVPATHEXIST(td, args->path, &path); 205142057Sjhb 206142057Sjhb#ifdef DEBUG 207142057Sjhb if (ldebug(execve)) 208142057Sjhb printf(ARGS(execve, "%s"), path); 209142057Sjhb#endif 210142057Sjhb 211142057Sjhb error = linux_exec_copyin_args(&eargs, path, UIO_SYSSPACE, args->argp, 212142057Sjhb args->envp); 213142057Sjhb free(path, M_TEMP); 214142057Sjhb if (error == 0) 215142057Sjhb error = kern_execve(td, &eargs, NULL); 216161474Snetchild if (error == 0) 217161474Snetchild /* linux process can exec fbsd one, dont attempt 218161474Snetchild * to create emuldata for such process using 219161474Snetchild * linux_proc_init, this leads to a panic on KASSERT 220161474Snetchild * because such process has p->p_emuldata == NULL 221161474Snetchild */ 222161474Snetchild if (td->td_proc->p_sysent == &elf_linux_sysvec) 223161474Snetchild error = linux_proc_init(td, 0, 0); 224142057Sjhb return (error); 225142057Sjhb} 226142057Sjhb 227133819Stjrstruct iovec32 { 228133819Stjr u_int32_t iov_base; 229133819Stjr int iov_len; 230133819Stjr}; 231133819Stjr 232133819StjrCTASSERT(sizeof(struct iovec32) == 8); 233133819Stjr 234144449Sjhbstatic int 235144449Sjhblinux32_copyinuio(struct iovec32 *iovp, u_int iovcnt, struct uio **uiop) 236133819Stjr{ 237144449Sjhb struct iovec32 iov32; 238144449Sjhb struct iovec *iov; 239144449Sjhb struct uio *uio; 240144449Sjhb u_int iovlen; 241144449Sjhb int error, i; 242133819Stjr 243144449Sjhb *uiop = NULL; 244144449Sjhb if (iovcnt > UIO_MAXIOV) 245133819Stjr return (EINVAL); 246144449Sjhb iovlen = iovcnt * sizeof(struct iovec); 247144449Sjhb uio = malloc(iovlen + sizeof *uio, M_IOV, M_WAITOK); 248144449Sjhb iov = (struct iovec *)(uio + 1); 249144449Sjhb for (i = 0; i < iovcnt; i++) { 250144449Sjhb error = copyin(&iovp[i], &iov32, sizeof(struct iovec32)); 251144449Sjhb if (error) { 252144449Sjhb free(uio, M_IOV); 253144449Sjhb return (error); 254144449Sjhb } 255144449Sjhb iov[i].iov_base = PTRIN(iov32.iov_base); 256144449Sjhb iov[i].iov_len = iov32.iov_len; 257133819Stjr } 258144449Sjhb uio->uio_iov = iov; 259144449Sjhb uio->uio_iovcnt = iovcnt; 260144449Sjhb uio->uio_segflg = UIO_USERSPACE; 261144449Sjhb uio->uio_offset = -1; 262144449Sjhb uio->uio_resid = 0; 263144449Sjhb for (i = 0; i < iovcnt; i++) { 264144449Sjhb if (iov->iov_len > INT_MAX - uio->uio_resid) { 265144449Sjhb free(uio, M_IOV); 266144449Sjhb return (EINVAL); 267144449Sjhb } 268144449Sjhb uio->uio_resid += iov->iov_len; 269144449Sjhb iov++; 270144449Sjhb } 271144449Sjhb *uiop = uio; 272144449Sjhb return (0); 273144449Sjhb} 274133819Stjr 275144449Sjhbint 276144449Sjhblinux_readv(struct thread *td, struct linux_readv_args *uap) 277144449Sjhb{ 278144449Sjhb struct uio *auio; 279144449Sjhb int error; 280133819Stjr 281144449Sjhb error = linux32_copyinuio(uap->iovp, uap->iovcnt, &auio); 282144449Sjhb if (error) 283144449Sjhb return (error); 284144449Sjhb error = kern_readv(td, uap->fd, auio); 285144449Sjhb free(auio, M_IOV); 286133819Stjr return (error); 287133819Stjr} 288133819Stjr 289133819Stjrint 290133819Stjrlinux_writev(struct thread *td, struct linux_writev_args *uap) 291133819Stjr{ 292144449Sjhb struct uio *auio; 293144449Sjhb int error; 294133819Stjr 295144449Sjhb error = linux32_copyinuio(uap->iovp, uap->iovcnt, &auio); 296144449Sjhb if (error) 297144449Sjhb return (error); 298144449Sjhb error = kern_writev(td, uap->fd, auio); 299144449Sjhb free(auio, M_IOV); 300133819Stjr return (error); 301133819Stjr} 302133819Stjr 303133819Stjrstruct l_ipc_kludge { 304133819Stjr l_uintptr_t msgp; 305133819Stjr l_long msgtyp; 306133819Stjr} __packed; 307133819Stjr 308133819Stjrint 309133819Stjrlinux_ipc(struct thread *td, struct linux_ipc_args *args) 310133819Stjr{ 311133819Stjr 312133819Stjr switch (args->what & 0xFFFF) { 313133819Stjr case LINUX_SEMOP: { 314133819Stjr struct linux_semop_args a; 315133819Stjr 316133819Stjr a.semid = args->arg1; 317133819Stjr a.tsops = args->ptr; 318133819Stjr a.nsops = args->arg2; 319133819Stjr return (linux_semop(td, &a)); 320133819Stjr } 321133819Stjr case LINUX_SEMGET: { 322133819Stjr struct linux_semget_args a; 323133819Stjr 324133819Stjr a.key = args->arg1; 325133819Stjr a.nsems = args->arg2; 326133819Stjr a.semflg = args->arg3; 327133819Stjr return (linux_semget(td, &a)); 328133819Stjr } 329133819Stjr case LINUX_SEMCTL: { 330133819Stjr struct linux_semctl_args a; 331133819Stjr int error; 332133819Stjr 333133819Stjr a.semid = args->arg1; 334133819Stjr a.semnum = args->arg2; 335133819Stjr a.cmd = args->arg3; 336133819Stjr error = copyin(args->ptr, &a.arg, sizeof(a.arg)); 337133819Stjr if (error) 338133819Stjr return (error); 339133819Stjr return (linux_semctl(td, &a)); 340133819Stjr } 341133819Stjr case LINUX_MSGSND: { 342133819Stjr struct linux_msgsnd_args a; 343133819Stjr 344133819Stjr a.msqid = args->arg1; 345133819Stjr a.msgp = args->ptr; 346133819Stjr a.msgsz = args->arg2; 347133819Stjr a.msgflg = args->arg3; 348133819Stjr return (linux_msgsnd(td, &a)); 349133819Stjr } 350133819Stjr case LINUX_MSGRCV: { 351133819Stjr struct linux_msgrcv_args a; 352133819Stjr 353133819Stjr a.msqid = args->arg1; 354133819Stjr a.msgsz = args->arg2; 355133819Stjr a.msgflg = args->arg3; 356133819Stjr if ((args->what >> 16) == 0) { 357133819Stjr struct l_ipc_kludge tmp; 358133819Stjr int error; 359133819Stjr 360133819Stjr if (args->ptr == 0) 361133819Stjr return (EINVAL); 362133819Stjr error = copyin(args->ptr, &tmp, sizeof(tmp)); 363133819Stjr if (error) 364133819Stjr return (error); 365133819Stjr a.msgp = PTRIN(tmp.msgp); 366133819Stjr a.msgtyp = tmp.msgtyp; 367133819Stjr } else { 368133819Stjr a.msgp = args->ptr; 369133819Stjr a.msgtyp = args->arg5; 370133819Stjr } 371133819Stjr return (linux_msgrcv(td, &a)); 372133819Stjr } 373133819Stjr case LINUX_MSGGET: { 374133819Stjr struct linux_msgget_args a; 375133819Stjr 376133819Stjr a.key = args->arg1; 377133819Stjr a.msgflg = args->arg2; 378133819Stjr return (linux_msgget(td, &a)); 379133819Stjr } 380133819Stjr case LINUX_MSGCTL: { 381133819Stjr struct linux_msgctl_args a; 382133819Stjr 383133819Stjr a.msqid = args->arg1; 384133819Stjr a.cmd = args->arg2; 385133819Stjr a.buf = args->ptr; 386133819Stjr return (linux_msgctl(td, &a)); 387133819Stjr } 388133819Stjr case LINUX_SHMAT: { 389133819Stjr struct linux_shmat_args a; 390133819Stjr 391133819Stjr a.shmid = args->arg1; 392133819Stjr a.shmaddr = args->ptr; 393133819Stjr a.shmflg = args->arg2; 394144441Sjhb a.raddr = PTRIN((l_uint)args->arg3); 395133819Stjr return (linux_shmat(td, &a)); 396133819Stjr } 397133819Stjr case LINUX_SHMDT: { 398133819Stjr struct linux_shmdt_args a; 399133819Stjr 400133819Stjr a.shmaddr = args->ptr; 401133819Stjr return (linux_shmdt(td, &a)); 402133819Stjr } 403133819Stjr case LINUX_SHMGET: { 404133819Stjr struct linux_shmget_args a; 405133819Stjr 406133819Stjr a.key = args->arg1; 407133819Stjr a.size = args->arg2; 408133819Stjr a.shmflg = args->arg3; 409133819Stjr return (linux_shmget(td, &a)); 410133819Stjr } 411133819Stjr case LINUX_SHMCTL: { 412133819Stjr struct linux_shmctl_args a; 413133819Stjr 414133819Stjr a.shmid = args->arg1; 415133819Stjr a.cmd = args->arg2; 416133819Stjr a.buf = args->ptr; 417133819Stjr return (linux_shmctl(td, &a)); 418133819Stjr } 419133819Stjr default: 420133819Stjr break; 421133819Stjr } 422133819Stjr 423133819Stjr return (EINVAL); 424133819Stjr} 425133819Stjr 426133819Stjrint 427133819Stjrlinux_old_select(struct thread *td, struct linux_old_select_args *args) 428133819Stjr{ 429133819Stjr struct l_old_select_argv linux_args; 430133819Stjr struct linux_select_args newsel; 431133819Stjr int error; 432133819Stjr 433133819Stjr#ifdef DEBUG 434133819Stjr if (ldebug(old_select)) 435133819Stjr printf(ARGS(old_select, "%p"), args->ptr); 436133819Stjr#endif 437133819Stjr 438133819Stjr error = copyin(args->ptr, &linux_args, sizeof(linux_args)); 439133819Stjr if (error) 440133819Stjr return (error); 441133819Stjr 442133819Stjr newsel.nfds = linux_args.nfds; 443133819Stjr newsel.readfds = PTRIN(linux_args.readfds); 444133819Stjr newsel.writefds = PTRIN(linux_args.writefds); 445133819Stjr newsel.exceptfds = PTRIN(linux_args.exceptfds); 446133819Stjr newsel.timeout = PTRIN(linux_args.timeout); 447133819Stjr return (linux_select(td, &newsel)); 448133819Stjr} 449133819Stjr 450133819Stjrint 451133819Stjrlinux_fork(struct thread *td, struct linux_fork_args *args) 452133819Stjr{ 453133819Stjr int error; 454133819Stjr 455133819Stjr#ifdef DEBUG 456133819Stjr if (ldebug(fork)) 457133819Stjr printf(ARGS(fork, "")); 458133819Stjr#endif 459133819Stjr 460133819Stjr if ((error = fork(td, (struct fork_args *)args)) != 0) 461133819Stjr return (error); 462133819Stjr 463133819Stjr if (td->td_retval[1] == 1) 464133819Stjr td->td_retval[0] = 0; 465161474Snetchild error = linux_proc_init(td, td->td_retval[0], 0); 466161474Snetchild if (error) 467161474Snetchild return (error); 468161474Snetchild 469133819Stjr return (0); 470133819Stjr} 471133819Stjr 472133819Stjrint 473133819Stjrlinux_vfork(struct thread *td, struct linux_vfork_args *args) 474133819Stjr{ 475133819Stjr int error; 476161611Snetchild struct proc *p2; 477133819Stjr 478133819Stjr#ifdef DEBUG 479133819Stjr if (ldebug(vfork)) 480133819Stjr printf(ARGS(vfork, "")); 481133819Stjr#endif 482133819Stjr 483161611Snetchild /* exclude RFPPWAIT */ 484161611Snetchild if ((error = fork1(td, RFFDG | RFPROC | RFMEM, 0, &p2)) != 0) 485133819Stjr return (error); 486161611Snetchild if (error == 0) { 487161611Snetchild td->td_retval[0] = p2->p_pid; 488161611Snetchild td->td_retval[1] = 0; 489161611Snetchild } 490133819Stjr /* Are we the child? */ 491133819Stjr if (td->td_retval[1] == 1) 492133819Stjr td->td_retval[0] = 0; 493161474Snetchild error = linux_proc_init(td, td->td_retval[0], 0); 494161474Snetchild if (error) 495161474Snetchild return (error); 496161611Snetchild /* wait for the children to exit, ie. emulate vfork */ 497161611Snetchild PROC_LOCK(p2); 498161611Snetchild while (p2->p_flag & P_PPWAIT) 499161611Snetchild msleep(td->td_proc, &p2->p_mtx, PWAIT, "ppwait", 0); 500161611Snetchild PROC_UNLOCK(p2); 501133819Stjr return (0); 502133819Stjr} 503133819Stjr 504133819Stjrint 505133819Stjrlinux_clone(struct thread *td, struct linux_clone_args *args) 506133819Stjr{ 507133819Stjr int error, ff = RFPROC | RFSTOPPED; 508133819Stjr struct proc *p2; 509133819Stjr struct thread *td2; 510133819Stjr int exit_signal; 511161474Snetchild struct linux_emuldata *em; 512133819Stjr 513133819Stjr#ifdef DEBUG 514133819Stjr if (ldebug(clone)) { 515161474Snetchild printf(ARGS(clone, "flags %x, stack %x, parent tid: %x, child tid: %x"), 516161474Snetchild (unsigned int)args->flags, (unsigned int)(uintptr_t)args->stack, 517161474Snetchild (unsigned int)(uintptr_t)args->parent_tidptr, 518161474Snetchild (unsigned int)(uintptr_t)args->child_tidptr); 519133819Stjr } 520133819Stjr#endif 521133819Stjr 522133819Stjr exit_signal = args->flags & 0x000000ff; 523133819Stjr if (exit_signal >= LINUX_NSIG) 524133819Stjr return (EINVAL); 525133819Stjr 526133819Stjr if (exit_signal <= LINUX_SIGTBLSZ) 527133819Stjr exit_signal = linux_to_bsd_signal[_SIG_IDX(exit_signal)]; 528133819Stjr 529133819Stjr if (args->flags & CLONE_VM) 530133819Stjr ff |= RFMEM; 531133819Stjr if (args->flags & CLONE_SIGHAND) 532133819Stjr ff |= RFSIGSHARE; 533133819Stjr if (!(args->flags & CLONE_FILES)) 534133819Stjr ff |= RFFDG; 535133819Stjr 536161474Snetchild /* 537161474Snetchild * Attempt to detect when linux_clone(2) is used for creating 538161474Snetchild * kernel threads. Unfortunately despite the existence of the 539161474Snetchild * CLONE_THREAD flag, version of linuxthreads package used in 540161474Snetchild * most popular distros as of beginning of 2005 doesn't make 541161474Snetchild * any use of it. Therefore, this detection relay fully on 542161474Snetchild * empirical observation that linuxthreads sets certain 543161474Snetchild * combination of flags, so that we can make more or less 544161474Snetchild * precise detection and notify the FreeBSD kernel that several 545161474Snetchild * processes are in fact part of the same threading group, so 546161474Snetchild * that special treatment is necessary for signal delivery 547161474Snetchild * between those processes and fd locking. 548161474Snetchild */ 549161474Snetchild if ((args->flags & 0xffffff00) == THREADING_FLAGS) 550161474Snetchild ff |= RFTHREAD; 551161474Snetchild 552133819Stjr error = fork1(td, ff, 0, &p2); 553133819Stjr if (error) 554133819Stjr return (error); 555133819Stjr 556161474Snetchild /* create the emuldata */ 557161474Snetchild error = linux_proc_init(td, p2->p_pid, args->flags); 558161474Snetchild /* reference it - no need to check this */ 559161474Snetchild em = em_find(p2, EMUL_UNLOCKED); 560161474Snetchild KASSERT(em != NULL, ("clone: emuldata not found.\n")); 561161474Snetchild /* and adjust it */ 562161474Snetchild if (args->flags & CLONE_PARENT_SETTID) { 563161474Snetchild if (args->parent_tidptr == NULL) { 564161474Snetchild EMUL_UNLOCK(&emul_lock); 565161474Snetchild return (EINVAL); 566161474Snetchild } 567161474Snetchild error = copyout(&p2->p_pid, args->parent_tidptr, sizeof(p2->p_pid)); 568161474Snetchild if (error) { 569161474Snetchild EMUL_UNLOCK(&emul_lock); 570161474Snetchild return (error); 571161474Snetchild } 572161474Snetchild } 573133819Stjr 574161696Snetchild if (args->flags & (CLONE_PARENT|CLONE_THREAD)) { 575161696Snetchild sx_xlock(&proctree_lock); 576161696Snetchild PROC_LOCK(p2); 577161696Snetchild proc_reparent(p2, td->td_proc->p_pptr); 578161696Snetchild PROC_UNLOCK(p2); 579161696Snetchild sx_xunlock(&proctree_lock); 580161474Snetchild } 581161696Snetchild 582161474Snetchild if (args->flags & CLONE_THREAD) { 583161474Snetchild /* XXX: linux mangles pgrp and pptr somehow 584161474Snetchild * I think it might be this but I am not sure. 585161474Snetchild */ 586161474Snetchild#ifdef notyet 587161696Snetchild PROC_LOCK(p2); 588161474Snetchild p2->p_pgrp = td->td_proc->p_pgrp; 589161696Snetchild PROC_UNLOCK(p2); 590161474Snetchild#endif 591161474Snetchild exit_signal = 0; 592161474Snetchild } 593161474Snetchild 594161474Snetchild if (args->flags & CLONE_CHILD_SETTID) 595161474Snetchild em->child_set_tid = args->child_tidptr; 596161474Snetchild else 597161474Snetchild em->child_set_tid = NULL; 598161474Snetchild 599161474Snetchild if (args->flags & CLONE_CHILD_CLEARTID) 600161474Snetchild em->child_clear_tid = args->child_tidptr; 601161474Snetchild else 602161474Snetchild em->child_clear_tid = NULL; 603161696Snetchild 604161474Snetchild EMUL_UNLOCK(&emul_lock); 605161474Snetchild 606133819Stjr PROC_LOCK(p2); 607133819Stjr p2->p_sigparent = exit_signal; 608133819Stjr PROC_UNLOCK(p2); 609133819Stjr td2 = FIRST_THREAD_IN_PROC(p2); 610161365Snetchild /* 611161365Snetchild * in a case of stack = NULL we are supposed to COW calling process stack 612161310Snetchild * this is what normal fork() does so we just keep the tf_rsp arg intact 613161310Snetchild */ 614161310Snetchild if (args->stack) 615161310Snetchild td2->td_frame->tf_rsp = PTROUT(args->stack); 616133819Stjr 617161474Snetchild if (args->flags & CLONE_SETTLS) { 618161474Snetchild /* XXX: todo */ 619161474Snetchild } 620161474Snetchild 621133819Stjr#ifdef DEBUG 622133819Stjr if (ldebug(clone)) 623133819Stjr printf(LMSG("clone: successful rfork to %ld, stack %p sig = %d"), 624133819Stjr (long)p2->p_pid, args->stack, exit_signal); 625133819Stjr#endif 626133819Stjr 627133819Stjr /* 628133819Stjr * Make this runnable after we are finished with it. 629133819Stjr */ 630133819Stjr mtx_lock_spin(&sched_lock); 631133819Stjr TD_SET_CAN_RUN(td2); 632134586Sjulian setrunqueue(td2, SRQ_BORING); 633133819Stjr mtx_unlock_spin(&sched_lock); 634133819Stjr 635133819Stjr td->td_retval[0] = p2->p_pid; 636133819Stjr td->td_retval[1] = 0; 637133819Stjr return (0); 638133819Stjr} 639133819Stjr 640133819Stjr/* XXX move */ 641133819Stjrstruct l_mmap_argv { 642133819Stjr l_ulong addr; 643144441Sjhb l_ulong len; 644144441Sjhb l_ulong prot; 645144441Sjhb l_ulong flags; 646144441Sjhb l_ulong fd; 647144441Sjhb l_ulong pgoff; 648133819Stjr}; 649133819Stjr 650133819Stjr#define STACK_SIZE (2 * 1024 * 1024) 651133819Stjr#define GUARD_SIZE (4 * PAGE_SIZE) 652133819Stjr 653133819Stjrstatic int linux_mmap_common(struct thread *, struct l_mmap_argv *); 654133819Stjr 655133819Stjrint 656133819Stjrlinux_mmap2(struct thread *td, struct linux_mmap2_args *args) 657133819Stjr{ 658133819Stjr struct l_mmap_argv linux_args; 659133819Stjr 660133819Stjr#ifdef DEBUG 661133819Stjr if (ldebug(mmap2)) 662133819Stjr printf(ARGS(mmap2, "%p, %d, %d, 0x%08x, %d, %d"), 663133843Sobrien (void *)(intptr_t)args->addr, args->len, args->prot, 664133819Stjr args->flags, args->fd, args->pgoff); 665133819Stjr#endif 666133819Stjr 667133819Stjr linux_args.addr = PTROUT(args->addr); 668133819Stjr linux_args.len = args->len; 669133819Stjr linux_args.prot = args->prot; 670133819Stjr linux_args.flags = args->flags; 671133819Stjr linux_args.fd = args->fd; 672144441Sjhb linux_args.pgoff = args->pgoff; 673133819Stjr 674133819Stjr return (linux_mmap_common(td, &linux_args)); 675133819Stjr} 676133819Stjr 677133819Stjrint 678133819Stjrlinux_mmap(struct thread *td, struct linux_mmap_args *args) 679133819Stjr{ 680133819Stjr int error; 681133819Stjr struct l_mmap_argv linux_args; 682133819Stjr 683133819Stjr error = copyin(args->ptr, &linux_args, sizeof(linux_args)); 684133819Stjr if (error) 685133819Stjr return (error); 686133819Stjr 687133819Stjr#ifdef DEBUG 688133819Stjr if (ldebug(mmap)) 689133819Stjr printf(ARGS(mmap, "%p, %d, %d, 0x%08x, %d, %d"), 690133843Sobrien (void *)(intptr_t)linux_args.addr, linux_args.len, 691133843Sobrien linux_args.prot, linux_args.flags, linux_args.fd, 692144670Sjhb linux_args.pgoff); 693133819Stjr#endif 694144441Sjhb if ((linux_args.pgoff % PAGE_SIZE) != 0) 695144441Sjhb return (EINVAL); 696144441Sjhb linux_args.pgoff /= PAGE_SIZE; 697133819Stjr 698133819Stjr return (linux_mmap_common(td, &linux_args)); 699133819Stjr} 700133819Stjr 701133819Stjrstatic int 702133819Stjrlinux_mmap_common(struct thread *td, struct l_mmap_argv *linux_args) 703133819Stjr{ 704133819Stjr struct proc *p = td->td_proc; 705133819Stjr struct mmap_args /* { 706133819Stjr caddr_t addr; 707133819Stjr size_t len; 708133819Stjr int prot; 709133819Stjr int flags; 710133819Stjr int fd; 711133819Stjr long pad; 712133819Stjr off_t pos; 713133819Stjr } */ bsd_args; 714133819Stjr int error; 715133819Stjr 716133819Stjr error = 0; 717133819Stjr bsd_args.flags = 0; 718133819Stjr if (linux_args->flags & LINUX_MAP_SHARED) 719133819Stjr bsd_args.flags |= MAP_SHARED; 720133819Stjr if (linux_args->flags & LINUX_MAP_PRIVATE) 721133819Stjr bsd_args.flags |= MAP_PRIVATE; 722133819Stjr if (linux_args->flags & LINUX_MAP_FIXED) 723133819Stjr bsd_args.flags |= MAP_FIXED; 724133819Stjr if (linux_args->flags & LINUX_MAP_ANON) 725133819Stjr bsd_args.flags |= MAP_ANON; 726133819Stjr else 727133819Stjr bsd_args.flags |= MAP_NOSYNC; 728133819Stjr if (linux_args->flags & LINUX_MAP_GROWSDOWN) { 729133819Stjr bsd_args.flags |= MAP_STACK; 730133819Stjr 731161365Snetchild /* 732161365Snetchild * The linux MAP_GROWSDOWN option does not limit auto 733133819Stjr * growth of the region. Linux mmap with this option 734133819Stjr * takes as addr the inital BOS, and as len, the initial 735133819Stjr * region size. It can then grow down from addr without 736133819Stjr * limit. However, linux threads has an implicit internal 737133819Stjr * limit to stack size of STACK_SIZE. Its just not 738133819Stjr * enforced explicitly in linux. But, here we impose 739133819Stjr * a limit of (STACK_SIZE - GUARD_SIZE) on the stack 740133819Stjr * region, since we can do this with our mmap. 741133819Stjr * 742133819Stjr * Our mmap with MAP_STACK takes addr as the maximum 743133819Stjr * downsize limit on BOS, and as len the max size of 744133819Stjr * the region. It them maps the top SGROWSIZ bytes, 745133819Stjr * and autgrows the region down, up to the limit 746133819Stjr * in addr. 747133819Stjr * 748133819Stjr * If we don't use the MAP_STACK option, the effect 749133819Stjr * of this code is to allocate a stack region of a 750133819Stjr * fixed size of (STACK_SIZE - GUARD_SIZE). 751133819Stjr */ 752133819Stjr 753133819Stjr /* This gives us TOS */ 754133819Stjr bsd_args.addr = (caddr_t)PTRIN(linux_args->addr) + 755133819Stjr linux_args->len; 756133819Stjr 757133819Stjr if ((caddr_t)PTRIN(bsd_args.addr) > 758133819Stjr p->p_vmspace->vm_maxsaddr) { 759161365Snetchild /* 760161365Snetchild * Some linux apps will attempt to mmap 761133819Stjr * thread stacks near the top of their 762133819Stjr * address space. If their TOS is greater 763133819Stjr * than vm_maxsaddr, vm_map_growstack() 764133819Stjr * will confuse the thread stack with the 765133819Stjr * process stack and deliver a SEGV if they 766133819Stjr * attempt to grow the thread stack past their 767133819Stjr * current stacksize rlimit. To avoid this, 768133819Stjr * adjust vm_maxsaddr upwards to reflect 769133819Stjr * the current stacksize rlimit rather 770133819Stjr * than the maximum possible stacksize. 771133819Stjr * It would be better to adjust the 772133819Stjr * mmap'ed region, but some apps do not check 773133819Stjr * mmap's return value. 774133819Stjr */ 775133819Stjr PROC_LOCK(p); 776133819Stjr p->p_vmspace->vm_maxsaddr = 777133819Stjr (char *)LINUX32_USRSTACK - 778133819Stjr lim_cur(p, RLIMIT_STACK); 779133819Stjr PROC_UNLOCK(p); 780133819Stjr } 781133819Stjr 782133819Stjr /* This gives us our maximum stack size */ 783133819Stjr if (linux_args->len > STACK_SIZE - GUARD_SIZE) 784133819Stjr bsd_args.len = linux_args->len; 785133819Stjr else 786133819Stjr bsd_args.len = STACK_SIZE - GUARD_SIZE; 787133819Stjr 788161365Snetchild /* 789161365Snetchild * This gives us a new BOS. If we're using VM_STACK, then 790133819Stjr * mmap will just map the top SGROWSIZ bytes, and let 791133819Stjr * the stack grow down to the limit at BOS. If we're 792133819Stjr * not using VM_STACK we map the full stack, since we 793133819Stjr * don't have a way to autogrow it. 794133819Stjr */ 795133819Stjr bsd_args.addr -= bsd_args.len; 796133819Stjr } else { 797133819Stjr bsd_args.addr = (caddr_t)PTRIN(linux_args->addr); 798133819Stjr bsd_args.len = linux_args->len; 799133819Stjr } 800133819Stjr /* 801133819Stjr * XXX i386 Linux always emulator forces PROT_READ on (why?) 802133819Stjr * so we do the same. We add PROT_EXEC to work around buggy 803133819Stjr * applications (e.g. Java) that take advantage of the fact 804133819Stjr * that execute permissions are not enforced by x86 CPUs. 805133819Stjr */ 806133819Stjr bsd_args.prot = linux_args->prot | PROT_EXEC | PROT_READ; 807133819Stjr if (linux_args->flags & LINUX_MAP_ANON) 808133819Stjr bsd_args.fd = -1; 809133819Stjr else 810133819Stjr bsd_args.fd = linux_args->fd; 811144441Sjhb bsd_args.pos = (off_t)linux_args->pgoff * PAGE_SIZE; 812133819Stjr bsd_args.pad = 0; 813133819Stjr 814133819Stjr#ifdef DEBUG 815133819Stjr if (ldebug(mmap)) 816133819Stjr printf("-> %s(%p, %d, %d, 0x%08x, %d, 0x%x)\n", 817133819Stjr __func__, 818133843Sobrien (void *)bsd_args.addr, (int)bsd_args.len, bsd_args.prot, 819133819Stjr bsd_args.flags, bsd_args.fd, (int)bsd_args.pos); 820133819Stjr#endif 821133819Stjr error = mmap(td, &bsd_args); 822133819Stjr#ifdef DEBUG 823133819Stjr if (ldebug(mmap)) 824133819Stjr printf("-> %s() return: 0x%x (0x%08x)\n", 825133819Stjr __func__, error, (u_int)td->td_retval[0]); 826133819Stjr#endif 827133819Stjr return (error); 828133819Stjr} 829133819Stjr 830133819Stjrint 831133819Stjrlinux_pipe(struct thread *td, struct linux_pipe_args *args) 832133819Stjr{ 833133819Stjr int pip[2]; 834133819Stjr int error; 835133819Stjr register_t reg_rdx; 836133819Stjr 837133819Stjr#ifdef DEBUG 838133819Stjr if (ldebug(pipe)) 839133819Stjr printf(ARGS(pipe, "*")); 840133819Stjr#endif 841133819Stjr 842133819Stjr reg_rdx = td->td_retval[1]; 843133819Stjr error = pipe(td, 0); 844133819Stjr if (error) { 845133819Stjr td->td_retval[1] = reg_rdx; 846133819Stjr return (error); 847133819Stjr } 848133819Stjr 849133819Stjr pip[0] = td->td_retval[0]; 850133819Stjr pip[1] = td->td_retval[1]; 851133819Stjr error = copyout(pip, args->pipefds, 2 * sizeof(int)); 852133819Stjr if (error) { 853133819Stjr td->td_retval[1] = reg_rdx; 854133819Stjr return (error); 855133819Stjr } 856133819Stjr 857133819Stjr td->td_retval[1] = reg_rdx; 858133819Stjr td->td_retval[0] = 0; 859133819Stjr return (0); 860133819Stjr} 861133819Stjr 862133819Stjrint 863133819Stjrlinux_sigaction(struct thread *td, struct linux_sigaction_args *args) 864133819Stjr{ 865133819Stjr l_osigaction_t osa; 866133819Stjr l_sigaction_t act, oact; 867133819Stjr int error; 868133819Stjr 869133819Stjr#ifdef DEBUG 870133819Stjr if (ldebug(sigaction)) 871133819Stjr printf(ARGS(sigaction, "%d, %p, %p"), 872133819Stjr args->sig, (void *)args->nsa, (void *)args->osa); 873133819Stjr#endif 874133819Stjr 875133819Stjr if (args->nsa != NULL) { 876133819Stjr error = copyin(args->nsa, &osa, sizeof(l_osigaction_t)); 877133819Stjr if (error) 878133819Stjr return (error); 879133819Stjr act.lsa_handler = osa.lsa_handler; 880133819Stjr act.lsa_flags = osa.lsa_flags; 881133819Stjr act.lsa_restorer = osa.lsa_restorer; 882133819Stjr LINUX_SIGEMPTYSET(act.lsa_mask); 883133819Stjr act.lsa_mask.__bits[0] = osa.lsa_mask; 884133819Stjr } 885133819Stjr 886133819Stjr error = linux_do_sigaction(td, args->sig, args->nsa ? &act : NULL, 887133819Stjr args->osa ? &oact : NULL); 888133819Stjr 889133819Stjr if (args->osa != NULL && !error) { 890133819Stjr osa.lsa_handler = oact.lsa_handler; 891133819Stjr osa.lsa_flags = oact.lsa_flags; 892133819Stjr osa.lsa_restorer = oact.lsa_restorer; 893133819Stjr osa.lsa_mask = oact.lsa_mask.__bits[0]; 894133819Stjr error = copyout(&osa, args->osa, sizeof(l_osigaction_t)); 895133819Stjr } 896133819Stjr 897133819Stjr return (error); 898133819Stjr} 899133819Stjr 900133819Stjr/* 901133819Stjr * Linux has two extra args, restart and oldmask. We dont use these, 902133819Stjr * but it seems that "restart" is actually a context pointer that 903133819Stjr * enables the signal to happen with a different register set. 904133819Stjr */ 905133819Stjrint 906133819Stjrlinux_sigsuspend(struct thread *td, struct linux_sigsuspend_args *args) 907133819Stjr{ 908133819Stjr sigset_t sigmask; 909133819Stjr l_sigset_t mask; 910133819Stjr 911133819Stjr#ifdef DEBUG 912133819Stjr if (ldebug(sigsuspend)) 913133819Stjr printf(ARGS(sigsuspend, "%08lx"), (unsigned long)args->mask); 914133819Stjr#endif 915133819Stjr 916133819Stjr LINUX_SIGEMPTYSET(mask); 917133819Stjr mask.__bits[0] = args->mask; 918133819Stjr linux_to_bsd_sigset(&mask, &sigmask); 919133819Stjr return (kern_sigsuspend(td, sigmask)); 920133819Stjr} 921133819Stjr 922133819Stjrint 923133819Stjrlinux_rt_sigsuspend(struct thread *td, struct linux_rt_sigsuspend_args *uap) 924133819Stjr{ 925133819Stjr l_sigset_t lmask; 926133819Stjr sigset_t sigmask; 927133819Stjr int error; 928133819Stjr 929133819Stjr#ifdef DEBUG 930133819Stjr if (ldebug(rt_sigsuspend)) 931133819Stjr printf(ARGS(rt_sigsuspend, "%p, %d"), 932133819Stjr (void *)uap->newset, uap->sigsetsize); 933133819Stjr#endif 934133819Stjr 935133819Stjr if (uap->sigsetsize != sizeof(l_sigset_t)) 936133819Stjr return (EINVAL); 937133819Stjr 938133819Stjr error = copyin(uap->newset, &lmask, sizeof(l_sigset_t)); 939133819Stjr if (error) 940133819Stjr return (error); 941133819Stjr 942133819Stjr linux_to_bsd_sigset(&lmask, &sigmask); 943133819Stjr return (kern_sigsuspend(td, sigmask)); 944133819Stjr} 945133819Stjr 946133819Stjrint 947133819Stjrlinux_pause(struct thread *td, struct linux_pause_args *args) 948133819Stjr{ 949133819Stjr struct proc *p = td->td_proc; 950133819Stjr sigset_t sigmask; 951133819Stjr 952133819Stjr#ifdef DEBUG 953133819Stjr if (ldebug(pause)) 954133819Stjr printf(ARGS(pause, "")); 955133819Stjr#endif 956133819Stjr 957133819Stjr PROC_LOCK(p); 958133819Stjr sigmask = td->td_sigmask; 959133819Stjr PROC_UNLOCK(p); 960133819Stjr return (kern_sigsuspend(td, sigmask)); 961133819Stjr} 962133819Stjr 963133819Stjrint 964133819Stjrlinux_sigaltstack(struct thread *td, struct linux_sigaltstack_args *uap) 965133819Stjr{ 966133819Stjr stack_t ss, oss; 967133819Stjr l_stack_t lss; 968133819Stjr int error; 969133819Stjr 970133819Stjr#ifdef DEBUG 971133819Stjr if (ldebug(sigaltstack)) 972133819Stjr printf(ARGS(sigaltstack, "%p, %p"), uap->uss, uap->uoss); 973133819Stjr#endif 974133819Stjr 975133819Stjr if (uap->uss != NULL) { 976133819Stjr error = copyin(uap->uss, &lss, sizeof(l_stack_t)); 977133819Stjr if (error) 978133819Stjr return (error); 979133819Stjr 980133819Stjr ss.ss_sp = PTRIN(lss.ss_sp); 981133819Stjr ss.ss_size = lss.ss_size; 982133819Stjr ss.ss_flags = linux_to_bsd_sigaltstack(lss.ss_flags); 983133819Stjr } 984134269Sjhb error = kern_sigaltstack(td, (uap->uss != NULL) ? &ss : NULL, 985134269Sjhb (uap->uoss != NULL) ? &oss : NULL); 986133819Stjr if (!error && uap->uoss != NULL) { 987133819Stjr lss.ss_sp = PTROUT(oss.ss_sp); 988133819Stjr lss.ss_size = oss.ss_size; 989133819Stjr lss.ss_flags = bsd_to_linux_sigaltstack(oss.ss_flags); 990133819Stjr error = copyout(&lss, uap->uoss, sizeof(l_stack_t)); 991133819Stjr } 992133819Stjr 993133819Stjr return (error); 994133819Stjr} 995133819Stjr 996133819Stjrint 997133819Stjrlinux_ftruncate64(struct thread *td, struct linux_ftruncate64_args *args) 998133819Stjr{ 999133819Stjr struct ftruncate_args sa; 1000133819Stjr 1001133819Stjr#ifdef DEBUG 1002133819Stjr if (ldebug(ftruncate64)) 1003133819Stjr printf(ARGS(ftruncate64, "%u, %jd"), args->fd, 1004133819Stjr (intmax_t)args->length); 1005133819Stjr#endif 1006133819Stjr 1007133819Stjr sa.fd = args->fd; 1008133819Stjr sa.pad = 0; 1009133819Stjr sa.length = args->length; 1010133819Stjr return ftruncate(td, &sa); 1011133819Stjr} 1012133819Stjr 1013133819Stjrint 1014133819Stjrlinux_gettimeofday(struct thread *td, struct linux_gettimeofday_args *uap) 1015133819Stjr{ 1016133819Stjr struct timeval atv; 1017133819Stjr l_timeval atv32; 1018133819Stjr struct timezone rtz; 1019133819Stjr int error = 0; 1020133819Stjr 1021133819Stjr if (uap->tp) { 1022133819Stjr microtime(&atv); 1023133819Stjr atv32.tv_sec = atv.tv_sec; 1024133819Stjr atv32.tv_usec = atv.tv_usec; 1025133819Stjr error = copyout(&atv32, uap->tp, sizeof (atv32)); 1026133819Stjr } 1027133819Stjr if (error == 0 && uap->tzp != NULL) { 1028133819Stjr rtz.tz_minuteswest = tz_minuteswest; 1029133819Stjr rtz.tz_dsttime = tz_dsttime; 1030133819Stjr error = copyout(&rtz, uap->tzp, sizeof (rtz)); 1031133819Stjr } 1032133819Stjr return (error); 1033133819Stjr} 1034133819Stjr 1035133819Stjrint 1036133819Stjrlinux_nanosleep(struct thread *td, struct linux_nanosleep_args *uap) 1037133819Stjr{ 1038142057Sjhb struct timespec rqt, rmt; 1039133819Stjr struct l_timespec ats32; 1040133819Stjr int error; 1041133819Stjr 1042133819Stjr error = copyin(uap->rqtp, &ats32, sizeof(ats32)); 1043133819Stjr if (error != 0) 1044133819Stjr return (error); 1045142057Sjhb rqt.tv_sec = ats32.tv_sec; 1046142057Sjhb rqt.tv_nsec = ats32.tv_nsec; 1047142057Sjhb error = kern_nanosleep(td, &rqt, &rmt); 1048133819Stjr if (uap->rmtp != NULL) { 1049142057Sjhb ats32.tv_sec = rmt.tv_sec; 1050142057Sjhb ats32.tv_nsec = rmt.tv_nsec; 1051133819Stjr error = copyout(&ats32, uap->rmtp, sizeof(ats32)); 1052133819Stjr } 1053133819Stjr return (error); 1054133819Stjr} 1055133819Stjr 1056133819Stjrint 1057133819Stjrlinux_getrusage(struct thread *td, struct linux_getrusage_args *uap) 1058133819Stjr{ 1059136152Sjhb struct l_rusage s32; 1060136152Sjhb struct rusage s; 1061133819Stjr int error; 1062133819Stjr 1063136152Sjhb error = kern_getrusage(td, uap->who, &s); 1064133819Stjr if (error != 0) 1065133819Stjr return (error); 1066136152Sjhb if (uap->rusage != NULL) { 1067133819Stjr s32.ru_utime.tv_sec = s.ru_utime.tv_sec; 1068133819Stjr s32.ru_utime.tv_usec = s.ru_utime.tv_usec; 1069133819Stjr s32.ru_stime.tv_sec = s.ru_stime.tv_sec; 1070133819Stjr s32.ru_stime.tv_usec = s.ru_stime.tv_usec; 1071133819Stjr s32.ru_maxrss = s.ru_maxrss; 1072133819Stjr s32.ru_ixrss = s.ru_ixrss; 1073133819Stjr s32.ru_idrss = s.ru_idrss; 1074133819Stjr s32.ru_isrss = s.ru_isrss; 1075133819Stjr s32.ru_minflt = s.ru_minflt; 1076133819Stjr s32.ru_majflt = s.ru_majflt; 1077133819Stjr s32.ru_nswap = s.ru_nswap; 1078133819Stjr s32.ru_inblock = s.ru_inblock; 1079133819Stjr s32.ru_oublock = s.ru_oublock; 1080133819Stjr s32.ru_msgsnd = s.ru_msgsnd; 1081133819Stjr s32.ru_msgrcv = s.ru_msgrcv; 1082133819Stjr s32.ru_nsignals = s.ru_nsignals; 1083133819Stjr s32.ru_nvcsw = s.ru_nvcsw; 1084133819Stjr s32.ru_nivcsw = s.ru_nivcsw; 1085136152Sjhb error = copyout(&s32, uap->rusage, sizeof(s32)); 1086133819Stjr } 1087133819Stjr return (error); 1088133819Stjr} 1089133819Stjr 1090133819Stjrint 1091133819Stjrlinux_sched_rr_get_interval(struct thread *td, 1092133819Stjr struct linux_sched_rr_get_interval_args *uap) 1093133819Stjr{ 1094133819Stjr struct timespec ts; 1095133819Stjr struct l_timespec ts32; 1096133819Stjr int error; 1097133819Stjr 1098144449Sjhb error = kern_sched_rr_get_interval(td, uap->pid, &ts); 1099133819Stjr if (error != 0) 1100133819Stjr return (error); 1101133819Stjr ts32.tv_sec = ts.tv_sec; 1102133819Stjr ts32.tv_nsec = ts.tv_nsec; 1103133819Stjr return (copyout(&ts32, uap->interval, sizeof(ts32))); 1104133819Stjr} 1105133819Stjr 1106133819Stjrint 1107133819Stjrlinux_mprotect(struct thread *td, struct linux_mprotect_args *uap) 1108133819Stjr{ 1109133819Stjr struct mprotect_args bsd_args; 1110133819Stjr 1111133819Stjr bsd_args.addr = uap->addr; 1112133819Stjr bsd_args.len = uap->len; 1113133819Stjr bsd_args.prot = uap->prot; 1114133819Stjr /* XXX PROT_READ implies PROT_EXEC; see linux_mmap_common(). */ 1115133819Stjr if ((bsd_args.prot & PROT_READ) != 0) 1116133819Stjr bsd_args.prot |= PROT_EXEC; 1117133819Stjr return (mprotect(td, &bsd_args)); 1118133819Stjr} 1119