linux32_machdep.c revision 161474
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 161474 2006-08-20 13:50:27Z netchild $"); 33133819Stjr 34133819Stjr#include <sys/param.h> 35133819Stjr#include <sys/kernel.h> 36133819Stjr#include <sys/systm.h> 37142057Sjhb#include <sys/imgact.h> 38161310Snetchild#include <sys/limits.h> 39133819Stjr#include <sys/lock.h> 40133819Stjr#include <sys/malloc.h> 41133819Stjr#include <sys/mman.h> 42133819Stjr#include <sys/mutex.h> 43133819Stjr#include <sys/proc.h> 44133819Stjr#include <sys/resource.h> 45133819Stjr#include <sys/resourcevar.h> 46133819Stjr#include <sys/syscallsubr.h> 47133819Stjr#include <sys/sysproto.h> 48133819Stjr#include <sys/unistd.h> 49133819Stjr 50133819Stjr#include <machine/frame.h> 51133819Stjr 52133819Stjr#include <vm/vm.h> 53133819Stjr#include <vm/pmap.h> 54142057Sjhb#include <vm/vm_extern.h> 55142057Sjhb#include <vm/vm_kern.h> 56133819Stjr#include <vm/vm_map.h> 57133819Stjr 58133819Stjr#include <amd64/linux32/linux.h> 59133819Stjr#include <amd64/linux32/linux32_proto.h> 60133819Stjr#include <compat/linux/linux_ipc.h> 61133819Stjr#include <compat/linux/linux_signal.h> 62133819Stjr#include <compat/linux/linux_util.h> 63161474Snetchild#include <compat/linux/linux_emul.h> 64133819Stjr 65133819Stjrstruct l_old_select_argv { 66133819Stjr l_int nfds; 67133819Stjr l_uintptr_t readfds; 68133819Stjr l_uintptr_t writefds; 69133819Stjr l_uintptr_t exceptfds; 70133819Stjr l_uintptr_t timeout; 71133819Stjr} __packed; 72133819Stjr 73133819Stjrint 74133819Stjrlinux_to_bsd_sigaltstack(int lsa) 75133819Stjr{ 76133819Stjr int bsa = 0; 77133819Stjr 78133819Stjr if (lsa & LINUX_SS_DISABLE) 79133819Stjr bsa |= SS_DISABLE; 80133819Stjr if (lsa & LINUX_SS_ONSTACK) 81133819Stjr bsa |= SS_ONSTACK; 82133819Stjr return (bsa); 83133819Stjr} 84133819Stjr 85133819Stjrint 86133819Stjrbsd_to_linux_sigaltstack(int bsa) 87133819Stjr{ 88133819Stjr int lsa = 0; 89133819Stjr 90133819Stjr if (bsa & SS_DISABLE) 91133819Stjr lsa |= LINUX_SS_DISABLE; 92133819Stjr if (bsa & SS_ONSTACK) 93133819Stjr lsa |= LINUX_SS_ONSTACK; 94133819Stjr return (lsa); 95133819Stjr} 96133819Stjr 97142057Sjhb/* 98142057Sjhb * Custom version of exec_copyin_args() so that we can translate 99142057Sjhb * the pointers. 100142057Sjhb */ 101142057Sjhbstatic int 102142057Sjhblinux_exec_copyin_args(struct image_args *args, char *fname, 103142057Sjhb enum uio_seg segflg, char **argv, char **envv) 104133819Stjr{ 105142057Sjhb char *argp, *envp; 106142057Sjhb u_int32_t *p32, arg; 107142057Sjhb size_t length; 108133819Stjr int error; 109133819Stjr 110142057Sjhb bzero(args, sizeof(*args)); 111142057Sjhb if (argv == NULL) 112142057Sjhb return (EFAULT); 113133819Stjr 114142057Sjhb /* 115142057Sjhb * Allocate temporary demand zeroed space for argument and 116142057Sjhb * environment strings 117142057Sjhb */ 118147588Sjhb args->buf = (char *) kmem_alloc_wait(exec_map, 119147588Sjhb PATH_MAX + ARG_MAX + MAXSHELLCMDLEN); 120142057Sjhb if (args->buf == NULL) 121142057Sjhb return (ENOMEM); 122142057Sjhb args->begin_argv = args->buf; 123142057Sjhb args->endp = args->begin_argv; 124142057Sjhb args->stringspace = ARG_MAX; 125133819Stjr 126142057Sjhb args->fname = args->buf + ARG_MAX; 127133819Stjr 128142057Sjhb /* 129142057Sjhb * Copy the file name. 130142057Sjhb */ 131142057Sjhb error = (segflg == UIO_SYSSPACE) ? 132142057Sjhb copystr(fname, args->fname, PATH_MAX, &length) : 133142057Sjhb copyinstr(fname, args->fname, PATH_MAX, &length); 134142057Sjhb if (error != 0) 135156440Sups goto err_exit; 136142057Sjhb 137142057Sjhb /* 138142057Sjhb * extract arguments first 139142057Sjhb */ 140142057Sjhb p32 = (u_int32_t *)argv; 141142057Sjhb for (;;) { 142142057Sjhb error = copyin(p32++, &arg, sizeof(arg)); 143142057Sjhb if (error) 144156440Sups goto err_exit; 145142057Sjhb if (arg == 0) 146142057Sjhb break; 147142057Sjhb argp = PTRIN(arg); 148142057Sjhb error = copyinstr(argp, args->endp, args->stringspace, &length); 149142057Sjhb if (error) { 150142057Sjhb if (error == ENAMETOOLONG) 151156440Sups error = E2BIG; 152156440Sups 153156440Sups goto err_exit; 154142057Sjhb } 155142057Sjhb args->stringspace -= length; 156142057Sjhb args->endp += length; 157142057Sjhb args->argc++; 158133819Stjr } 159142057Sjhb 160142057Sjhb args->begin_envv = args->endp; 161142057Sjhb 162142057Sjhb /* 163142057Sjhb * extract environment strings 164142057Sjhb */ 165142057Sjhb if (envv) { 166142057Sjhb p32 = (u_int32_t *)envv; 167142057Sjhb for (;;) { 168133819Stjr error = copyin(p32++, &arg, sizeof(arg)); 169133819Stjr if (error) 170156440Sups goto err_exit; 171142057Sjhb if (arg == 0) 172142057Sjhb break; 173142057Sjhb envp = PTRIN(arg); 174142057Sjhb error = copyinstr(envp, args->endp, args->stringspace, 175142057Sjhb &length); 176142057Sjhb if (error) { 177142057Sjhb if (error == ENAMETOOLONG) 178156440Sups error = E2BIG; 179156440Sups goto err_exit; 180142057Sjhb } 181142057Sjhb args->stringspace -= length; 182142057Sjhb args->endp += length; 183142057Sjhb args->envc++; 184142057Sjhb } 185133819Stjr } 186133819Stjr 187142057Sjhb return (0); 188156440Sups 189156440Supserr_exit: 190156440Sups kmem_free_wakeup(exec_map, (vm_offset_t)args->buf, 191156440Sups PATH_MAX + ARG_MAX + MAXSHELLCMDLEN); 192156440Sups args->buf = NULL; 193156440Sups return (error); 194133819Stjr} 195133819Stjr 196142057Sjhbint 197142057Sjhblinux_execve(struct thread *td, struct linux_execve_args *args) 198142057Sjhb{ 199142057Sjhb struct image_args eargs; 200142057Sjhb char *path; 201142057Sjhb int error; 202142057Sjhb 203142057Sjhb LCONVPATHEXIST(td, args->path, &path); 204142057Sjhb 205142057Sjhb#ifdef DEBUG 206142057Sjhb if (ldebug(execve)) 207142057Sjhb printf(ARGS(execve, "%s"), path); 208142057Sjhb#endif 209142057Sjhb 210142057Sjhb error = linux_exec_copyin_args(&eargs, path, UIO_SYSSPACE, args->argp, 211142057Sjhb args->envp); 212142057Sjhb free(path, M_TEMP); 213142057Sjhb if (error == 0) 214142057Sjhb error = kern_execve(td, &eargs, NULL); 215161474Snetchild if (error == 0) 216161474Snetchild /* linux process can exec fbsd one, dont attempt 217161474Snetchild * to create emuldata for such process using 218161474Snetchild * linux_proc_init, this leads to a panic on KASSERT 219161474Snetchild * because such process has p->p_emuldata == NULL 220161474Snetchild */ 221161474Snetchild if (td->td_proc->p_sysent == &elf_linux_sysvec) 222161474Snetchild error = linux_proc_init(td, 0, 0); 223142057Sjhb return (error); 224142057Sjhb} 225142057Sjhb 226133819Stjrstruct iovec32 { 227133819Stjr u_int32_t iov_base; 228133819Stjr int iov_len; 229133819Stjr}; 230133819Stjr 231133819StjrCTASSERT(sizeof(struct iovec32) == 8); 232133819Stjr 233144449Sjhbstatic int 234144449Sjhblinux32_copyinuio(struct iovec32 *iovp, u_int iovcnt, struct uio **uiop) 235133819Stjr{ 236144449Sjhb struct iovec32 iov32; 237144449Sjhb struct iovec *iov; 238144449Sjhb struct uio *uio; 239144449Sjhb u_int iovlen; 240144449Sjhb int error, i; 241133819Stjr 242144449Sjhb *uiop = NULL; 243144449Sjhb if (iovcnt > UIO_MAXIOV) 244133819Stjr return (EINVAL); 245144449Sjhb iovlen = iovcnt * sizeof(struct iovec); 246144449Sjhb uio = malloc(iovlen + sizeof *uio, M_IOV, M_WAITOK); 247144449Sjhb iov = (struct iovec *)(uio + 1); 248144449Sjhb for (i = 0; i < iovcnt; i++) { 249144449Sjhb error = copyin(&iovp[i], &iov32, sizeof(struct iovec32)); 250144449Sjhb if (error) { 251144449Sjhb free(uio, M_IOV); 252144449Sjhb return (error); 253144449Sjhb } 254144449Sjhb iov[i].iov_base = PTRIN(iov32.iov_base); 255144449Sjhb iov[i].iov_len = iov32.iov_len; 256133819Stjr } 257144449Sjhb uio->uio_iov = iov; 258144449Sjhb uio->uio_iovcnt = iovcnt; 259144449Sjhb uio->uio_segflg = UIO_USERSPACE; 260144449Sjhb uio->uio_offset = -1; 261144449Sjhb uio->uio_resid = 0; 262144449Sjhb for (i = 0; i < iovcnt; i++) { 263144449Sjhb if (iov->iov_len > INT_MAX - uio->uio_resid) { 264144449Sjhb free(uio, M_IOV); 265144449Sjhb return (EINVAL); 266144449Sjhb } 267144449Sjhb uio->uio_resid += iov->iov_len; 268144449Sjhb iov++; 269144449Sjhb } 270144449Sjhb *uiop = uio; 271144449Sjhb return (0); 272144449Sjhb} 273133819Stjr 274144449Sjhbint 275144449Sjhblinux_readv(struct thread *td, struct linux_readv_args *uap) 276144449Sjhb{ 277144449Sjhb struct uio *auio; 278144449Sjhb int error; 279133819Stjr 280144449Sjhb error = linux32_copyinuio(uap->iovp, uap->iovcnt, &auio); 281144449Sjhb if (error) 282144449Sjhb return (error); 283144449Sjhb error = kern_readv(td, uap->fd, auio); 284144449Sjhb free(auio, M_IOV); 285133819Stjr return (error); 286133819Stjr} 287133819Stjr 288133819Stjrint 289133819Stjrlinux_writev(struct thread *td, struct linux_writev_args *uap) 290133819Stjr{ 291144449Sjhb struct uio *auio; 292144449Sjhb int error; 293133819Stjr 294144449Sjhb error = linux32_copyinuio(uap->iovp, uap->iovcnt, &auio); 295144449Sjhb if (error) 296144449Sjhb return (error); 297144449Sjhb error = kern_writev(td, uap->fd, auio); 298144449Sjhb free(auio, M_IOV); 299133819Stjr return (error); 300133819Stjr} 301133819Stjr 302133819Stjrstruct l_ipc_kludge { 303133819Stjr l_uintptr_t msgp; 304133819Stjr l_long msgtyp; 305133819Stjr} __packed; 306133819Stjr 307133819Stjrint 308133819Stjrlinux_ipc(struct thread *td, struct linux_ipc_args *args) 309133819Stjr{ 310133819Stjr 311133819Stjr switch (args->what & 0xFFFF) { 312133819Stjr case LINUX_SEMOP: { 313133819Stjr struct linux_semop_args a; 314133819Stjr 315133819Stjr a.semid = args->arg1; 316133819Stjr a.tsops = args->ptr; 317133819Stjr a.nsops = args->arg2; 318133819Stjr return (linux_semop(td, &a)); 319133819Stjr } 320133819Stjr case LINUX_SEMGET: { 321133819Stjr struct linux_semget_args a; 322133819Stjr 323133819Stjr a.key = args->arg1; 324133819Stjr a.nsems = args->arg2; 325133819Stjr a.semflg = args->arg3; 326133819Stjr return (linux_semget(td, &a)); 327133819Stjr } 328133819Stjr case LINUX_SEMCTL: { 329133819Stjr struct linux_semctl_args a; 330133819Stjr int error; 331133819Stjr 332133819Stjr a.semid = args->arg1; 333133819Stjr a.semnum = args->arg2; 334133819Stjr a.cmd = args->arg3; 335133819Stjr error = copyin(args->ptr, &a.arg, sizeof(a.arg)); 336133819Stjr if (error) 337133819Stjr return (error); 338133819Stjr return (linux_semctl(td, &a)); 339133819Stjr } 340133819Stjr case LINUX_MSGSND: { 341133819Stjr struct linux_msgsnd_args a; 342133819Stjr 343133819Stjr a.msqid = args->arg1; 344133819Stjr a.msgp = args->ptr; 345133819Stjr a.msgsz = args->arg2; 346133819Stjr a.msgflg = args->arg3; 347133819Stjr return (linux_msgsnd(td, &a)); 348133819Stjr } 349133819Stjr case LINUX_MSGRCV: { 350133819Stjr struct linux_msgrcv_args a; 351133819Stjr 352133819Stjr a.msqid = args->arg1; 353133819Stjr a.msgsz = args->arg2; 354133819Stjr a.msgflg = args->arg3; 355133819Stjr if ((args->what >> 16) == 0) { 356133819Stjr struct l_ipc_kludge tmp; 357133819Stjr int error; 358133819Stjr 359133819Stjr if (args->ptr == 0) 360133819Stjr return (EINVAL); 361133819Stjr error = copyin(args->ptr, &tmp, sizeof(tmp)); 362133819Stjr if (error) 363133819Stjr return (error); 364133819Stjr a.msgp = PTRIN(tmp.msgp); 365133819Stjr a.msgtyp = tmp.msgtyp; 366133819Stjr } else { 367133819Stjr a.msgp = args->ptr; 368133819Stjr a.msgtyp = args->arg5; 369133819Stjr } 370133819Stjr return (linux_msgrcv(td, &a)); 371133819Stjr } 372133819Stjr case LINUX_MSGGET: { 373133819Stjr struct linux_msgget_args a; 374133819Stjr 375133819Stjr a.key = args->arg1; 376133819Stjr a.msgflg = args->arg2; 377133819Stjr return (linux_msgget(td, &a)); 378133819Stjr } 379133819Stjr case LINUX_MSGCTL: { 380133819Stjr struct linux_msgctl_args a; 381133819Stjr 382133819Stjr a.msqid = args->arg1; 383133819Stjr a.cmd = args->arg2; 384133819Stjr a.buf = args->ptr; 385133819Stjr return (linux_msgctl(td, &a)); 386133819Stjr } 387133819Stjr case LINUX_SHMAT: { 388133819Stjr struct linux_shmat_args a; 389133819Stjr 390133819Stjr a.shmid = args->arg1; 391133819Stjr a.shmaddr = args->ptr; 392133819Stjr a.shmflg = args->arg2; 393144441Sjhb a.raddr = PTRIN((l_uint)args->arg3); 394133819Stjr return (linux_shmat(td, &a)); 395133819Stjr } 396133819Stjr case LINUX_SHMDT: { 397133819Stjr struct linux_shmdt_args a; 398133819Stjr 399133819Stjr a.shmaddr = args->ptr; 400133819Stjr return (linux_shmdt(td, &a)); 401133819Stjr } 402133819Stjr case LINUX_SHMGET: { 403133819Stjr struct linux_shmget_args a; 404133819Stjr 405133819Stjr a.key = args->arg1; 406133819Stjr a.size = args->arg2; 407133819Stjr a.shmflg = args->arg3; 408133819Stjr return (linux_shmget(td, &a)); 409133819Stjr } 410133819Stjr case LINUX_SHMCTL: { 411133819Stjr struct linux_shmctl_args a; 412133819Stjr 413133819Stjr a.shmid = args->arg1; 414133819Stjr a.cmd = args->arg2; 415133819Stjr a.buf = args->ptr; 416133819Stjr return (linux_shmctl(td, &a)); 417133819Stjr } 418133819Stjr default: 419133819Stjr break; 420133819Stjr } 421133819Stjr 422133819Stjr return (EINVAL); 423133819Stjr} 424133819Stjr 425133819Stjrint 426133819Stjrlinux_old_select(struct thread *td, struct linux_old_select_args *args) 427133819Stjr{ 428133819Stjr struct l_old_select_argv linux_args; 429133819Stjr struct linux_select_args newsel; 430133819Stjr int error; 431133819Stjr 432133819Stjr#ifdef DEBUG 433133819Stjr if (ldebug(old_select)) 434133819Stjr printf(ARGS(old_select, "%p"), args->ptr); 435133819Stjr#endif 436133819Stjr 437133819Stjr error = copyin(args->ptr, &linux_args, sizeof(linux_args)); 438133819Stjr if (error) 439133819Stjr return (error); 440133819Stjr 441133819Stjr newsel.nfds = linux_args.nfds; 442133819Stjr newsel.readfds = PTRIN(linux_args.readfds); 443133819Stjr newsel.writefds = PTRIN(linux_args.writefds); 444133819Stjr newsel.exceptfds = PTRIN(linux_args.exceptfds); 445133819Stjr newsel.timeout = PTRIN(linux_args.timeout); 446133819Stjr return (linux_select(td, &newsel)); 447133819Stjr} 448133819Stjr 449133819Stjrint 450133819Stjrlinux_fork(struct thread *td, struct linux_fork_args *args) 451133819Stjr{ 452133819Stjr int error; 453133819Stjr 454133819Stjr#ifdef DEBUG 455133819Stjr if (ldebug(fork)) 456133819Stjr printf(ARGS(fork, "")); 457133819Stjr#endif 458133819Stjr 459133819Stjr if ((error = fork(td, (struct fork_args *)args)) != 0) 460133819Stjr return (error); 461133819Stjr 462133819Stjr if (td->td_retval[1] == 1) 463133819Stjr td->td_retval[0] = 0; 464161474Snetchild error = linux_proc_init(td, td->td_retval[0], 0); 465161474Snetchild if (error) 466161474Snetchild return (error); 467161474Snetchild 468133819Stjr return (0); 469133819Stjr} 470133819Stjr 471133819Stjrint 472133819Stjrlinux_vfork(struct thread *td, struct linux_vfork_args *args) 473133819Stjr{ 474133819Stjr int error; 475133819Stjr 476133819Stjr#ifdef DEBUG 477133819Stjr if (ldebug(vfork)) 478133819Stjr printf(ARGS(vfork, "")); 479133819Stjr#endif 480133819Stjr 481133819Stjr if ((error = vfork(td, (struct vfork_args *)args)) != 0) 482133819Stjr return (error); 483133819Stjr /* Are we the child? */ 484133819Stjr if (td->td_retval[1] == 1) 485133819Stjr td->td_retval[0] = 0; 486161474Snetchild error = linux_proc_init(td, td->td_retval[0], 0); 487161474Snetchild if (error) 488161474Snetchild return (error); 489133819Stjr return (0); 490133819Stjr} 491133819Stjr 492133819Stjrint 493133819Stjrlinux_clone(struct thread *td, struct linux_clone_args *args) 494133819Stjr{ 495133819Stjr int error, ff = RFPROC | RFSTOPPED; 496133819Stjr struct proc *p2; 497133819Stjr struct thread *td2; 498133819Stjr int exit_signal; 499161474Snetchild struct linux_emuldata *em; 500133819Stjr 501133819Stjr#ifdef DEBUG 502133819Stjr if (ldebug(clone)) { 503161474Snetchild printf(ARGS(clone, "flags %x, stack %x, parent tid: %x, child tid: %x"), 504161474Snetchild (unsigned int)args->flags, (unsigned int)(uintptr_t)args->stack, 505161474Snetchild (unsigned int)(uintptr_t)args->parent_tidptr, 506161474Snetchild (unsigned int)(uintptr_t)args->child_tidptr); 507133819Stjr } 508133819Stjr#endif 509133819Stjr 510133819Stjr exit_signal = args->flags & 0x000000ff; 511133819Stjr if (exit_signal >= LINUX_NSIG) 512133819Stjr return (EINVAL); 513133819Stjr 514133819Stjr if (exit_signal <= LINUX_SIGTBLSZ) 515133819Stjr exit_signal = linux_to_bsd_signal[_SIG_IDX(exit_signal)]; 516133819Stjr 517133819Stjr if (args->flags & CLONE_VM) 518133819Stjr ff |= RFMEM; 519133819Stjr if (args->flags & CLONE_SIGHAND) 520133819Stjr ff |= RFSIGSHARE; 521133819Stjr if (!(args->flags & CLONE_FILES)) 522133819Stjr ff |= RFFDG; 523133819Stjr 524161474Snetchild /* 525161474Snetchild * Attempt to detect when linux_clone(2) is used for creating 526161474Snetchild * kernel threads. Unfortunately despite the existence of the 527161474Snetchild * CLONE_THREAD flag, version of linuxthreads package used in 528161474Snetchild * most popular distros as of beginning of 2005 doesn't make 529161474Snetchild * any use of it. Therefore, this detection relay fully on 530161474Snetchild * empirical observation that linuxthreads sets certain 531161474Snetchild * combination of flags, so that we can make more or less 532161474Snetchild * precise detection and notify the FreeBSD kernel that several 533161474Snetchild * processes are in fact part of the same threading group, so 534161474Snetchild * that special treatment is necessary for signal delivery 535161474Snetchild * between those processes and fd locking. 536161474Snetchild */ 537161474Snetchild if ((args->flags & 0xffffff00) == THREADING_FLAGS) 538161474Snetchild ff |= RFTHREAD; 539161474Snetchild 540133819Stjr error = fork1(td, ff, 0, &p2); 541133819Stjr if (error) 542133819Stjr return (error); 543133819Stjr 544161474Snetchild /* create the emuldata */ 545161474Snetchild error = linux_proc_init(td, p2->p_pid, args->flags); 546161474Snetchild /* reference it - no need to check this */ 547161474Snetchild em = em_find(p2, EMUL_UNLOCKED); 548161474Snetchild KASSERT(em != NULL, ("clone: emuldata not found.\n")); 549161474Snetchild /* and adjust it */ 550161474Snetchild if (args->flags & CLONE_PARENT_SETTID) { 551161474Snetchild if (args->parent_tidptr == NULL) { 552161474Snetchild EMUL_UNLOCK(&emul_lock); 553161474Snetchild return (EINVAL); 554161474Snetchild } 555161474Snetchild error = copyout(&p2->p_pid, args->parent_tidptr, sizeof(p2->p_pid)); 556161474Snetchild if (error) { 557161474Snetchild EMUL_UNLOCK(&emul_lock); 558161474Snetchild return (error); 559161474Snetchild } 560161474Snetchild } 561133819Stjr 562161474Snetchild if (args->flags & CLONE_PARENT) { 563161474Snetchild#ifdef DEBUG 564161474Snetchild printf("linux_clone: CLONE_PARENT\n"); 565161474Snetchild#endif 566161474Snetchild } 567161474Snetchild 568161474Snetchild if (args->flags & CLONE_THREAD) { 569161474Snetchild /* XXX: linux mangles pgrp and pptr somehow 570161474Snetchild * I think it might be this but I am not sure. 571161474Snetchild */ 572161474Snetchild#ifdef notyet 573161474Snetchild p2->p_pgrp = td->td_proc->p_pgrp; 574161474Snetchild p2->p_pptr = td->td_proc->p_pptr; 575161474Snetchild#endif 576161474Snetchild exit_signal = 0; 577161474Snetchild#ifdef DEBUG 578161474Snetchild printf("linux_clone: CLONE_THREADS\n"); 579161474Snetchild#endif 580161474Snetchild } 581161474Snetchild 582161474Snetchild if (args->flags & CLONE_CHILD_SETTID) 583161474Snetchild em->child_set_tid = args->child_tidptr; 584161474Snetchild else 585161474Snetchild em->child_set_tid = NULL; 586161474Snetchild 587161474Snetchild if (args->flags & CLONE_CHILD_CLEARTID) 588161474Snetchild em->child_clear_tid = args->child_tidptr; 589161474Snetchild else 590161474Snetchild em->child_clear_tid = NULL; 591161474Snetchild EMUL_UNLOCK(&emul_lock); 592161474Snetchild 593133819Stjr PROC_LOCK(p2); 594133819Stjr p2->p_sigparent = exit_signal; 595133819Stjr PROC_UNLOCK(p2); 596133819Stjr td2 = FIRST_THREAD_IN_PROC(p2); 597161365Snetchild /* 598161365Snetchild * in a case of stack = NULL we are supposed to COW calling process stack 599161310Snetchild * this is what normal fork() does so we just keep the tf_rsp arg intact 600161310Snetchild */ 601161310Snetchild if (args->stack) 602161310Snetchild td2->td_frame->tf_rsp = PTROUT(args->stack); 603133819Stjr 604161474Snetchild if (args->flags & CLONE_SETTLS) { 605161474Snetchild /* XXX: todo */ 606161474Snetchild } 607161474Snetchild 608133819Stjr#ifdef DEBUG 609133819Stjr if (ldebug(clone)) 610133819Stjr printf(LMSG("clone: successful rfork to %ld, stack %p sig = %d"), 611133819Stjr (long)p2->p_pid, args->stack, exit_signal); 612133819Stjr#endif 613133819Stjr 614133819Stjr /* 615133819Stjr * Make this runnable after we are finished with it. 616133819Stjr */ 617133819Stjr mtx_lock_spin(&sched_lock); 618133819Stjr TD_SET_CAN_RUN(td2); 619134586Sjulian setrunqueue(td2, SRQ_BORING); 620133819Stjr mtx_unlock_spin(&sched_lock); 621133819Stjr 622133819Stjr td->td_retval[0] = p2->p_pid; 623133819Stjr td->td_retval[1] = 0; 624133819Stjr return (0); 625133819Stjr} 626133819Stjr 627133819Stjr/* XXX move */ 628133819Stjrstruct l_mmap_argv { 629133819Stjr l_ulong addr; 630144441Sjhb l_ulong len; 631144441Sjhb l_ulong prot; 632144441Sjhb l_ulong flags; 633144441Sjhb l_ulong fd; 634144441Sjhb l_ulong pgoff; 635133819Stjr}; 636133819Stjr 637133819Stjr#define STACK_SIZE (2 * 1024 * 1024) 638133819Stjr#define GUARD_SIZE (4 * PAGE_SIZE) 639133819Stjr 640133819Stjrstatic int linux_mmap_common(struct thread *, struct l_mmap_argv *); 641133819Stjr 642133819Stjrint 643133819Stjrlinux_mmap2(struct thread *td, struct linux_mmap2_args *args) 644133819Stjr{ 645133819Stjr struct l_mmap_argv linux_args; 646133819Stjr 647133819Stjr#ifdef DEBUG 648133819Stjr if (ldebug(mmap2)) 649133819Stjr printf(ARGS(mmap2, "%p, %d, %d, 0x%08x, %d, %d"), 650133843Sobrien (void *)(intptr_t)args->addr, args->len, args->prot, 651133819Stjr args->flags, args->fd, args->pgoff); 652133819Stjr#endif 653133819Stjr 654133819Stjr linux_args.addr = PTROUT(args->addr); 655133819Stjr linux_args.len = args->len; 656133819Stjr linux_args.prot = args->prot; 657133819Stjr linux_args.flags = args->flags; 658133819Stjr linux_args.fd = args->fd; 659144441Sjhb linux_args.pgoff = args->pgoff; 660133819Stjr 661133819Stjr return (linux_mmap_common(td, &linux_args)); 662133819Stjr} 663133819Stjr 664133819Stjrint 665133819Stjrlinux_mmap(struct thread *td, struct linux_mmap_args *args) 666133819Stjr{ 667133819Stjr int error; 668133819Stjr struct l_mmap_argv linux_args; 669133819Stjr 670133819Stjr error = copyin(args->ptr, &linux_args, sizeof(linux_args)); 671133819Stjr if (error) 672133819Stjr return (error); 673133819Stjr 674133819Stjr#ifdef DEBUG 675133819Stjr if (ldebug(mmap)) 676133819Stjr printf(ARGS(mmap, "%p, %d, %d, 0x%08x, %d, %d"), 677133843Sobrien (void *)(intptr_t)linux_args.addr, linux_args.len, 678133843Sobrien linux_args.prot, linux_args.flags, linux_args.fd, 679144670Sjhb linux_args.pgoff); 680133819Stjr#endif 681144441Sjhb if ((linux_args.pgoff % PAGE_SIZE) != 0) 682144441Sjhb return (EINVAL); 683144441Sjhb linux_args.pgoff /= PAGE_SIZE; 684133819Stjr 685133819Stjr return (linux_mmap_common(td, &linux_args)); 686133819Stjr} 687133819Stjr 688133819Stjrstatic int 689133819Stjrlinux_mmap_common(struct thread *td, struct l_mmap_argv *linux_args) 690133819Stjr{ 691133819Stjr struct proc *p = td->td_proc; 692133819Stjr struct mmap_args /* { 693133819Stjr caddr_t addr; 694133819Stjr size_t len; 695133819Stjr int prot; 696133819Stjr int flags; 697133819Stjr int fd; 698133819Stjr long pad; 699133819Stjr off_t pos; 700133819Stjr } */ bsd_args; 701133819Stjr int error; 702133819Stjr 703133819Stjr error = 0; 704133819Stjr bsd_args.flags = 0; 705133819Stjr if (linux_args->flags & LINUX_MAP_SHARED) 706133819Stjr bsd_args.flags |= MAP_SHARED; 707133819Stjr if (linux_args->flags & LINUX_MAP_PRIVATE) 708133819Stjr bsd_args.flags |= MAP_PRIVATE; 709133819Stjr if (linux_args->flags & LINUX_MAP_FIXED) 710133819Stjr bsd_args.flags |= MAP_FIXED; 711133819Stjr if (linux_args->flags & LINUX_MAP_ANON) 712133819Stjr bsd_args.flags |= MAP_ANON; 713133819Stjr else 714133819Stjr bsd_args.flags |= MAP_NOSYNC; 715133819Stjr if (linux_args->flags & LINUX_MAP_GROWSDOWN) { 716133819Stjr bsd_args.flags |= MAP_STACK; 717133819Stjr 718161365Snetchild /* 719161365Snetchild * The linux MAP_GROWSDOWN option does not limit auto 720133819Stjr * growth of the region. Linux mmap with this option 721133819Stjr * takes as addr the inital BOS, and as len, the initial 722133819Stjr * region size. It can then grow down from addr without 723133819Stjr * limit. However, linux threads has an implicit internal 724133819Stjr * limit to stack size of STACK_SIZE. Its just not 725133819Stjr * enforced explicitly in linux. But, here we impose 726133819Stjr * a limit of (STACK_SIZE - GUARD_SIZE) on the stack 727133819Stjr * region, since we can do this with our mmap. 728133819Stjr * 729133819Stjr * Our mmap with MAP_STACK takes addr as the maximum 730133819Stjr * downsize limit on BOS, and as len the max size of 731133819Stjr * the region. It them maps the top SGROWSIZ bytes, 732133819Stjr * and autgrows the region down, up to the limit 733133819Stjr * in addr. 734133819Stjr * 735133819Stjr * If we don't use the MAP_STACK option, the effect 736133819Stjr * of this code is to allocate a stack region of a 737133819Stjr * fixed size of (STACK_SIZE - GUARD_SIZE). 738133819Stjr */ 739133819Stjr 740133819Stjr /* This gives us TOS */ 741133819Stjr bsd_args.addr = (caddr_t)PTRIN(linux_args->addr) + 742133819Stjr linux_args->len; 743133819Stjr 744133819Stjr if ((caddr_t)PTRIN(bsd_args.addr) > 745133819Stjr p->p_vmspace->vm_maxsaddr) { 746161365Snetchild /* 747161365Snetchild * Some linux apps will attempt to mmap 748133819Stjr * thread stacks near the top of their 749133819Stjr * address space. If their TOS is greater 750133819Stjr * than vm_maxsaddr, vm_map_growstack() 751133819Stjr * will confuse the thread stack with the 752133819Stjr * process stack and deliver a SEGV if they 753133819Stjr * attempt to grow the thread stack past their 754133819Stjr * current stacksize rlimit. To avoid this, 755133819Stjr * adjust vm_maxsaddr upwards to reflect 756133819Stjr * the current stacksize rlimit rather 757133819Stjr * than the maximum possible stacksize. 758133819Stjr * It would be better to adjust the 759133819Stjr * mmap'ed region, but some apps do not check 760133819Stjr * mmap's return value. 761133819Stjr */ 762133819Stjr PROC_LOCK(p); 763133819Stjr p->p_vmspace->vm_maxsaddr = 764133819Stjr (char *)LINUX32_USRSTACK - 765133819Stjr lim_cur(p, RLIMIT_STACK); 766133819Stjr PROC_UNLOCK(p); 767133819Stjr } 768133819Stjr 769133819Stjr /* This gives us our maximum stack size */ 770133819Stjr if (linux_args->len > STACK_SIZE - GUARD_SIZE) 771133819Stjr bsd_args.len = linux_args->len; 772133819Stjr else 773133819Stjr bsd_args.len = STACK_SIZE - GUARD_SIZE; 774133819Stjr 775161365Snetchild /* 776161365Snetchild * This gives us a new BOS. If we're using VM_STACK, then 777133819Stjr * mmap will just map the top SGROWSIZ bytes, and let 778133819Stjr * the stack grow down to the limit at BOS. If we're 779133819Stjr * not using VM_STACK we map the full stack, since we 780133819Stjr * don't have a way to autogrow it. 781133819Stjr */ 782133819Stjr bsd_args.addr -= bsd_args.len; 783133819Stjr } else { 784133819Stjr bsd_args.addr = (caddr_t)PTRIN(linux_args->addr); 785133819Stjr bsd_args.len = linux_args->len; 786133819Stjr } 787133819Stjr /* 788133819Stjr * XXX i386 Linux always emulator forces PROT_READ on (why?) 789133819Stjr * so we do the same. We add PROT_EXEC to work around buggy 790133819Stjr * applications (e.g. Java) that take advantage of the fact 791133819Stjr * that execute permissions are not enforced by x86 CPUs. 792133819Stjr */ 793133819Stjr bsd_args.prot = linux_args->prot | PROT_EXEC | PROT_READ; 794133819Stjr if (linux_args->flags & LINUX_MAP_ANON) 795133819Stjr bsd_args.fd = -1; 796133819Stjr else 797133819Stjr bsd_args.fd = linux_args->fd; 798144441Sjhb bsd_args.pos = (off_t)linux_args->pgoff * PAGE_SIZE; 799133819Stjr bsd_args.pad = 0; 800133819Stjr 801133819Stjr#ifdef DEBUG 802133819Stjr if (ldebug(mmap)) 803133819Stjr printf("-> %s(%p, %d, %d, 0x%08x, %d, 0x%x)\n", 804133819Stjr __func__, 805133843Sobrien (void *)bsd_args.addr, (int)bsd_args.len, bsd_args.prot, 806133819Stjr bsd_args.flags, bsd_args.fd, (int)bsd_args.pos); 807133819Stjr#endif 808133819Stjr error = mmap(td, &bsd_args); 809133819Stjr#ifdef DEBUG 810133819Stjr if (ldebug(mmap)) 811133819Stjr printf("-> %s() return: 0x%x (0x%08x)\n", 812133819Stjr __func__, error, (u_int)td->td_retval[0]); 813133819Stjr#endif 814133819Stjr return (error); 815133819Stjr} 816133819Stjr 817133819Stjrint 818133819Stjrlinux_pipe(struct thread *td, struct linux_pipe_args *args) 819133819Stjr{ 820133819Stjr int pip[2]; 821133819Stjr int error; 822133819Stjr register_t reg_rdx; 823133819Stjr 824133819Stjr#ifdef DEBUG 825133819Stjr if (ldebug(pipe)) 826133819Stjr printf(ARGS(pipe, "*")); 827133819Stjr#endif 828133819Stjr 829133819Stjr reg_rdx = td->td_retval[1]; 830133819Stjr error = pipe(td, 0); 831133819Stjr if (error) { 832133819Stjr td->td_retval[1] = reg_rdx; 833133819Stjr return (error); 834133819Stjr } 835133819Stjr 836133819Stjr pip[0] = td->td_retval[0]; 837133819Stjr pip[1] = td->td_retval[1]; 838133819Stjr error = copyout(pip, args->pipefds, 2 * sizeof(int)); 839133819Stjr if (error) { 840133819Stjr td->td_retval[1] = reg_rdx; 841133819Stjr return (error); 842133819Stjr } 843133819Stjr 844133819Stjr td->td_retval[1] = reg_rdx; 845133819Stjr td->td_retval[0] = 0; 846133819Stjr return (0); 847133819Stjr} 848133819Stjr 849133819Stjrint 850133819Stjrlinux_sigaction(struct thread *td, struct linux_sigaction_args *args) 851133819Stjr{ 852133819Stjr l_osigaction_t osa; 853133819Stjr l_sigaction_t act, oact; 854133819Stjr int error; 855133819Stjr 856133819Stjr#ifdef DEBUG 857133819Stjr if (ldebug(sigaction)) 858133819Stjr printf(ARGS(sigaction, "%d, %p, %p"), 859133819Stjr args->sig, (void *)args->nsa, (void *)args->osa); 860133819Stjr#endif 861133819Stjr 862133819Stjr if (args->nsa != NULL) { 863133819Stjr error = copyin(args->nsa, &osa, sizeof(l_osigaction_t)); 864133819Stjr if (error) 865133819Stjr return (error); 866133819Stjr act.lsa_handler = osa.lsa_handler; 867133819Stjr act.lsa_flags = osa.lsa_flags; 868133819Stjr act.lsa_restorer = osa.lsa_restorer; 869133819Stjr LINUX_SIGEMPTYSET(act.lsa_mask); 870133819Stjr act.lsa_mask.__bits[0] = osa.lsa_mask; 871133819Stjr } 872133819Stjr 873133819Stjr error = linux_do_sigaction(td, args->sig, args->nsa ? &act : NULL, 874133819Stjr args->osa ? &oact : NULL); 875133819Stjr 876133819Stjr if (args->osa != NULL && !error) { 877133819Stjr osa.lsa_handler = oact.lsa_handler; 878133819Stjr osa.lsa_flags = oact.lsa_flags; 879133819Stjr osa.lsa_restorer = oact.lsa_restorer; 880133819Stjr osa.lsa_mask = oact.lsa_mask.__bits[0]; 881133819Stjr error = copyout(&osa, args->osa, sizeof(l_osigaction_t)); 882133819Stjr } 883133819Stjr 884133819Stjr return (error); 885133819Stjr} 886133819Stjr 887133819Stjr/* 888133819Stjr * Linux has two extra args, restart and oldmask. We dont use these, 889133819Stjr * but it seems that "restart" is actually a context pointer that 890133819Stjr * enables the signal to happen with a different register set. 891133819Stjr */ 892133819Stjrint 893133819Stjrlinux_sigsuspend(struct thread *td, struct linux_sigsuspend_args *args) 894133819Stjr{ 895133819Stjr sigset_t sigmask; 896133819Stjr l_sigset_t mask; 897133819Stjr 898133819Stjr#ifdef DEBUG 899133819Stjr if (ldebug(sigsuspend)) 900133819Stjr printf(ARGS(sigsuspend, "%08lx"), (unsigned long)args->mask); 901133819Stjr#endif 902133819Stjr 903133819Stjr LINUX_SIGEMPTYSET(mask); 904133819Stjr mask.__bits[0] = args->mask; 905133819Stjr linux_to_bsd_sigset(&mask, &sigmask); 906133819Stjr return (kern_sigsuspend(td, sigmask)); 907133819Stjr} 908133819Stjr 909133819Stjrint 910133819Stjrlinux_rt_sigsuspend(struct thread *td, struct linux_rt_sigsuspend_args *uap) 911133819Stjr{ 912133819Stjr l_sigset_t lmask; 913133819Stjr sigset_t sigmask; 914133819Stjr int error; 915133819Stjr 916133819Stjr#ifdef DEBUG 917133819Stjr if (ldebug(rt_sigsuspend)) 918133819Stjr printf(ARGS(rt_sigsuspend, "%p, %d"), 919133819Stjr (void *)uap->newset, uap->sigsetsize); 920133819Stjr#endif 921133819Stjr 922133819Stjr if (uap->sigsetsize != sizeof(l_sigset_t)) 923133819Stjr return (EINVAL); 924133819Stjr 925133819Stjr error = copyin(uap->newset, &lmask, sizeof(l_sigset_t)); 926133819Stjr if (error) 927133819Stjr return (error); 928133819Stjr 929133819Stjr linux_to_bsd_sigset(&lmask, &sigmask); 930133819Stjr return (kern_sigsuspend(td, sigmask)); 931133819Stjr} 932133819Stjr 933133819Stjrint 934133819Stjrlinux_pause(struct thread *td, struct linux_pause_args *args) 935133819Stjr{ 936133819Stjr struct proc *p = td->td_proc; 937133819Stjr sigset_t sigmask; 938133819Stjr 939133819Stjr#ifdef DEBUG 940133819Stjr if (ldebug(pause)) 941133819Stjr printf(ARGS(pause, "")); 942133819Stjr#endif 943133819Stjr 944133819Stjr PROC_LOCK(p); 945133819Stjr sigmask = td->td_sigmask; 946133819Stjr PROC_UNLOCK(p); 947133819Stjr return (kern_sigsuspend(td, sigmask)); 948133819Stjr} 949133819Stjr 950133819Stjrint 951133819Stjrlinux_sigaltstack(struct thread *td, struct linux_sigaltstack_args *uap) 952133819Stjr{ 953133819Stjr stack_t ss, oss; 954133819Stjr l_stack_t lss; 955133819Stjr int error; 956133819Stjr 957133819Stjr#ifdef DEBUG 958133819Stjr if (ldebug(sigaltstack)) 959133819Stjr printf(ARGS(sigaltstack, "%p, %p"), uap->uss, uap->uoss); 960133819Stjr#endif 961133819Stjr 962133819Stjr if (uap->uss != NULL) { 963133819Stjr error = copyin(uap->uss, &lss, sizeof(l_stack_t)); 964133819Stjr if (error) 965133819Stjr return (error); 966133819Stjr 967133819Stjr ss.ss_sp = PTRIN(lss.ss_sp); 968133819Stjr ss.ss_size = lss.ss_size; 969133819Stjr ss.ss_flags = linux_to_bsd_sigaltstack(lss.ss_flags); 970133819Stjr } 971134269Sjhb error = kern_sigaltstack(td, (uap->uss != NULL) ? &ss : NULL, 972134269Sjhb (uap->uoss != NULL) ? &oss : NULL); 973133819Stjr if (!error && uap->uoss != NULL) { 974133819Stjr lss.ss_sp = PTROUT(oss.ss_sp); 975133819Stjr lss.ss_size = oss.ss_size; 976133819Stjr lss.ss_flags = bsd_to_linux_sigaltstack(oss.ss_flags); 977133819Stjr error = copyout(&lss, uap->uoss, sizeof(l_stack_t)); 978133819Stjr } 979133819Stjr 980133819Stjr return (error); 981133819Stjr} 982133819Stjr 983133819Stjrint 984133819Stjrlinux_ftruncate64(struct thread *td, struct linux_ftruncate64_args *args) 985133819Stjr{ 986133819Stjr struct ftruncate_args sa; 987133819Stjr 988133819Stjr#ifdef DEBUG 989133819Stjr if (ldebug(ftruncate64)) 990133819Stjr printf(ARGS(ftruncate64, "%u, %jd"), args->fd, 991133819Stjr (intmax_t)args->length); 992133819Stjr#endif 993133819Stjr 994133819Stjr sa.fd = args->fd; 995133819Stjr sa.pad = 0; 996133819Stjr sa.length = args->length; 997133819Stjr return ftruncate(td, &sa); 998133819Stjr} 999133819Stjr 1000133819Stjrint 1001133819Stjrlinux_gettimeofday(struct thread *td, struct linux_gettimeofday_args *uap) 1002133819Stjr{ 1003133819Stjr struct timeval atv; 1004133819Stjr l_timeval atv32; 1005133819Stjr struct timezone rtz; 1006133819Stjr int error = 0; 1007133819Stjr 1008133819Stjr if (uap->tp) { 1009133819Stjr microtime(&atv); 1010133819Stjr atv32.tv_sec = atv.tv_sec; 1011133819Stjr atv32.tv_usec = atv.tv_usec; 1012133819Stjr error = copyout(&atv32, uap->tp, sizeof (atv32)); 1013133819Stjr } 1014133819Stjr if (error == 0 && uap->tzp != NULL) { 1015133819Stjr rtz.tz_minuteswest = tz_minuteswest; 1016133819Stjr rtz.tz_dsttime = tz_dsttime; 1017133819Stjr error = copyout(&rtz, uap->tzp, sizeof (rtz)); 1018133819Stjr } 1019133819Stjr return (error); 1020133819Stjr} 1021133819Stjr 1022133819Stjrint 1023133819Stjrlinux_nanosleep(struct thread *td, struct linux_nanosleep_args *uap) 1024133819Stjr{ 1025142057Sjhb struct timespec rqt, rmt; 1026133819Stjr struct l_timespec ats32; 1027133819Stjr int error; 1028133819Stjr 1029133819Stjr error = copyin(uap->rqtp, &ats32, sizeof(ats32)); 1030133819Stjr if (error != 0) 1031133819Stjr return (error); 1032142057Sjhb rqt.tv_sec = ats32.tv_sec; 1033142057Sjhb rqt.tv_nsec = ats32.tv_nsec; 1034142057Sjhb error = kern_nanosleep(td, &rqt, &rmt); 1035133819Stjr if (uap->rmtp != NULL) { 1036142057Sjhb ats32.tv_sec = rmt.tv_sec; 1037142057Sjhb ats32.tv_nsec = rmt.tv_nsec; 1038133819Stjr error = copyout(&ats32, uap->rmtp, sizeof(ats32)); 1039133819Stjr } 1040133819Stjr return (error); 1041133819Stjr} 1042133819Stjr 1043133819Stjrint 1044133819Stjrlinux_getrusage(struct thread *td, struct linux_getrusage_args *uap) 1045133819Stjr{ 1046136152Sjhb struct l_rusage s32; 1047136152Sjhb struct rusage s; 1048133819Stjr int error; 1049133819Stjr 1050136152Sjhb error = kern_getrusage(td, uap->who, &s); 1051133819Stjr if (error != 0) 1052133819Stjr return (error); 1053136152Sjhb if (uap->rusage != NULL) { 1054133819Stjr s32.ru_utime.tv_sec = s.ru_utime.tv_sec; 1055133819Stjr s32.ru_utime.tv_usec = s.ru_utime.tv_usec; 1056133819Stjr s32.ru_stime.tv_sec = s.ru_stime.tv_sec; 1057133819Stjr s32.ru_stime.tv_usec = s.ru_stime.tv_usec; 1058133819Stjr s32.ru_maxrss = s.ru_maxrss; 1059133819Stjr s32.ru_ixrss = s.ru_ixrss; 1060133819Stjr s32.ru_idrss = s.ru_idrss; 1061133819Stjr s32.ru_isrss = s.ru_isrss; 1062133819Stjr s32.ru_minflt = s.ru_minflt; 1063133819Stjr s32.ru_majflt = s.ru_majflt; 1064133819Stjr s32.ru_nswap = s.ru_nswap; 1065133819Stjr s32.ru_inblock = s.ru_inblock; 1066133819Stjr s32.ru_oublock = s.ru_oublock; 1067133819Stjr s32.ru_msgsnd = s.ru_msgsnd; 1068133819Stjr s32.ru_msgrcv = s.ru_msgrcv; 1069133819Stjr s32.ru_nsignals = s.ru_nsignals; 1070133819Stjr s32.ru_nvcsw = s.ru_nvcsw; 1071133819Stjr s32.ru_nivcsw = s.ru_nivcsw; 1072136152Sjhb error = copyout(&s32, uap->rusage, sizeof(s32)); 1073133819Stjr } 1074133819Stjr return (error); 1075133819Stjr} 1076133819Stjr 1077133819Stjrint 1078133819Stjrlinux_sched_rr_get_interval(struct thread *td, 1079133819Stjr struct linux_sched_rr_get_interval_args *uap) 1080133819Stjr{ 1081133819Stjr struct timespec ts; 1082133819Stjr struct l_timespec ts32; 1083133819Stjr int error; 1084133819Stjr 1085144449Sjhb error = kern_sched_rr_get_interval(td, uap->pid, &ts); 1086133819Stjr if (error != 0) 1087133819Stjr return (error); 1088133819Stjr ts32.tv_sec = ts.tv_sec; 1089133819Stjr ts32.tv_nsec = ts.tv_nsec; 1090133819Stjr return (copyout(&ts32, uap->interval, sizeof(ts32))); 1091133819Stjr} 1092133819Stjr 1093133819Stjrint 1094133819Stjrlinux_mprotect(struct thread *td, struct linux_mprotect_args *uap) 1095133819Stjr{ 1096133819Stjr struct mprotect_args bsd_args; 1097133819Stjr 1098133819Stjr bsd_args.addr = uap->addr; 1099133819Stjr bsd_args.len = uap->len; 1100133819Stjr bsd_args.prot = uap->prot; 1101133819Stjr /* XXX PROT_READ implies PROT_EXEC; see linux_mmap_common(). */ 1102133819Stjr if ((bsd_args.prot & PROT_READ) != 0) 1103133819Stjr bsd_args.prot |= PROT_EXEC; 1104133819Stjr return (mprotect(td, &bsd_args)); 1105133819Stjr} 1106