linux32_machdep.c revision 134269
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 134269 2004-08-24 20:52:52Z jhb $"); 33133819Stjr 34133819Stjr#include <sys/param.h> 35133819Stjr#include <sys/kernel.h> 36133819Stjr#include <sys/systm.h> 37133819Stjr#include <sys/lock.h> 38133819Stjr#include <sys/malloc.h> 39133819Stjr#include <sys/mman.h> 40133819Stjr#include <sys/mutex.h> 41133819Stjr#include <sys/proc.h> 42133819Stjr#include <sys/resource.h> 43133819Stjr#include <sys/resourcevar.h> 44133819Stjr#include <sys/syscallsubr.h> 45133819Stjr#include <sys/sysproto.h> 46133819Stjr#include <sys/unistd.h> 47133819Stjr 48133819Stjr#include <machine/frame.h> 49133819Stjr 50133819Stjr#include <vm/vm.h> 51133819Stjr#include <vm/pmap.h> 52133819Stjr#include <vm/vm_map.h> 53133819Stjr 54133819Stjr#include <amd64/linux32/linux.h> 55133819Stjr#include <amd64/linux32/linux32_proto.h> 56133819Stjr#include <compat/linux/linux_ipc.h> 57133819Stjr#include <compat/linux/linux_signal.h> 58133819Stjr#include <compat/linux/linux_util.h> 59133819Stjr 60133819Stjrstruct l_old_select_argv { 61133819Stjr l_int nfds; 62133819Stjr l_uintptr_t readfds; 63133819Stjr l_uintptr_t writefds; 64133819Stjr l_uintptr_t exceptfds; 65133819Stjr l_uintptr_t timeout; 66133819Stjr} __packed; 67133819Stjr 68133819Stjrint 69133819Stjrlinux_to_bsd_sigaltstack(int lsa) 70133819Stjr{ 71133819Stjr int bsa = 0; 72133819Stjr 73133819Stjr if (lsa & LINUX_SS_DISABLE) 74133819Stjr bsa |= SS_DISABLE; 75133819Stjr if (lsa & LINUX_SS_ONSTACK) 76133819Stjr bsa |= SS_ONSTACK; 77133819Stjr return (bsa); 78133819Stjr} 79133819Stjr 80133819Stjrint 81133819Stjrbsd_to_linux_sigaltstack(int bsa) 82133819Stjr{ 83133819Stjr int lsa = 0; 84133819Stjr 85133819Stjr if (bsa & SS_DISABLE) 86133819Stjr lsa |= LINUX_SS_DISABLE; 87133819Stjr if (bsa & SS_ONSTACK) 88133819Stjr lsa |= LINUX_SS_ONSTACK; 89133819Stjr return (lsa); 90133819Stjr} 91133819Stjr 92133819Stjrint 93133819Stjrlinux_execve(struct thread *td, struct linux_execve_args *args) 94133819Stjr{ 95133819Stjr struct execve_args ap; 96133819Stjr caddr_t sg; 97133819Stjr int error; 98133819Stjr u_int32_t *p32, arg; 99133819Stjr char **p, *p64; 100133819Stjr int count; 101133819Stjr 102133819Stjr sg = stackgap_init(); 103133819Stjr CHECKALTEXIST(td, &sg, args->path); 104133819Stjr 105133819Stjr#ifdef DEBUG 106133819Stjr if (ldebug(execve)) 107133819Stjr printf(ARGS(execve, "%s"), args->path); 108133819Stjr#endif 109133819Stjr 110133819Stjr ap.fname = args->path; 111133819Stjr 112133819Stjr if (args->argp != NULL) { 113133819Stjr count = 0; 114133819Stjr p32 = (u_int32_t *)args->argp; 115133819Stjr do { 116133819Stjr error = copyin(p32++, &arg, sizeof(arg)); 117133819Stjr if (error) 118133819Stjr return error; 119133819Stjr count++; 120133819Stjr } while (arg != 0); 121133819Stjr p = stackgap_alloc(&sg, count * sizeof(char *)); 122133819Stjr ap.argv = p; 123133819Stjr p32 = (u_int32_t *)args->argp; 124133819Stjr do { 125133819Stjr error = copyin(p32++, &arg, sizeof(arg)); 126133819Stjr if (error) 127133819Stjr return error; 128133819Stjr p64 = PTRIN(arg); 129133819Stjr error = copyout(&p64, p++, sizeof(p64)); 130133819Stjr if (error) 131133819Stjr return error; 132133819Stjr } while (arg != 0); 133133819Stjr } 134133819Stjr if (args->envp != NULL) { 135133819Stjr count = 0; 136133819Stjr p32 = (u_int32_t *)args->envp; 137133819Stjr do { 138133819Stjr error = copyin(p32++, &arg, sizeof(arg)); 139133819Stjr if (error) 140133819Stjr return error; 141133819Stjr count++; 142133819Stjr } while (arg != 0); 143133819Stjr p = stackgap_alloc(&sg, count * sizeof(char *)); 144133819Stjr ap.envv = p; 145133819Stjr p32 = (u_int32_t *)args->envp; 146133819Stjr do { 147133819Stjr error = copyin(p32++, &arg, sizeof(arg)); 148133819Stjr if (error) 149133819Stjr return error; 150133819Stjr p64 = PTRIN(arg); 151133819Stjr error = copyout(&p64, p++, sizeof(p64)); 152133819Stjr if (error) 153133819Stjr return error; 154133819Stjr } while (arg != 0); 155133819Stjr } 156133819Stjr 157133819Stjr return (execve(td, &ap)); 158133819Stjr} 159133819Stjr 160133819Stjrstruct iovec32 { 161133819Stjr u_int32_t iov_base; 162133819Stjr int iov_len; 163133819Stjr}; 164133819Stjr#define STACKGAPLEN 400 165133819Stjr 166133819StjrCTASSERT(sizeof(struct iovec32) == 8); 167133819Stjr 168133819Stjrint 169133819Stjrlinux_readv(struct thread *td, struct linux_readv_args *uap) 170133819Stjr{ 171133819Stjr int error, osize, nsize, i; 172133819Stjr caddr_t sg; 173133819Stjr struct readv_args /* { 174133819Stjr syscallarg(int) fd; 175133819Stjr syscallarg(struct iovec *) iovp; 176133819Stjr syscallarg(u_int) iovcnt; 177133819Stjr } */ a; 178133819Stjr struct iovec32 *oio; 179133819Stjr struct iovec *nio; 180133819Stjr 181133819Stjr sg = stackgap_init(); 182133819Stjr 183133819Stjr if (uap->iovcnt > (STACKGAPLEN / sizeof (struct iovec))) 184133819Stjr return (EINVAL); 185133819Stjr 186133819Stjr osize = uap->iovcnt * sizeof (struct iovec32); 187133819Stjr nsize = uap->iovcnt * sizeof (struct iovec); 188133819Stjr 189133819Stjr oio = malloc(osize, M_TEMP, M_WAITOK); 190133819Stjr nio = malloc(nsize, M_TEMP, M_WAITOK); 191133819Stjr 192133819Stjr error = 0; 193133819Stjr if ((error = copyin(uap->iovp, oio, osize))) 194133819Stjr goto punt; 195133819Stjr for (i = 0; i < uap->iovcnt; i++) { 196133819Stjr nio[i].iov_base = PTRIN(oio[i].iov_base); 197133819Stjr nio[i].iov_len = oio[i].iov_len; 198133819Stjr } 199133819Stjr 200133819Stjr a.fd = uap->fd; 201133819Stjr a.iovp = stackgap_alloc(&sg, nsize); 202133819Stjr a.iovcnt = uap->iovcnt; 203133819Stjr 204133819Stjr if ((error = copyout(nio, (caddr_t)a.iovp, nsize))) 205133819Stjr goto punt; 206133819Stjr error = readv(td, &a); 207133819Stjr 208133819Stjrpunt: 209133819Stjr free(oio, M_TEMP); 210133819Stjr free(nio, M_TEMP); 211133819Stjr return (error); 212133819Stjr} 213133819Stjr 214133819Stjrint 215133819Stjrlinux_writev(struct thread *td, struct linux_writev_args *uap) 216133819Stjr{ 217133819Stjr int error, i, nsize, osize; 218133819Stjr caddr_t sg; 219133819Stjr struct writev_args /* { 220133819Stjr syscallarg(int) fd; 221133819Stjr syscallarg(struct iovec *) iovp; 222133819Stjr syscallarg(u_int) iovcnt; 223133819Stjr } */ a; 224133819Stjr struct iovec32 *oio; 225133819Stjr struct iovec *nio; 226133819Stjr 227133819Stjr sg = stackgap_init(); 228133819Stjr 229133819Stjr if (uap->iovcnt > (STACKGAPLEN / sizeof (struct iovec))) 230133819Stjr return (EINVAL); 231133819Stjr 232133819Stjr osize = uap->iovcnt * sizeof (struct iovec32); 233133819Stjr nsize = uap->iovcnt * sizeof (struct iovec); 234133819Stjr 235133819Stjr oio = malloc(osize, M_TEMP, M_WAITOK); 236133819Stjr nio = malloc(nsize, M_TEMP, M_WAITOK); 237133819Stjr 238133819Stjr error = 0; 239133819Stjr if ((error = copyin(uap->iovp, oio, osize))) 240133819Stjr goto punt; 241133819Stjr for (i = 0; i < uap->iovcnt; i++) { 242133819Stjr nio[i].iov_base = PTRIN(oio[i].iov_base); 243133819Stjr nio[i].iov_len = oio[i].iov_len; 244133819Stjr } 245133819Stjr 246133819Stjr a.fd = uap->fd; 247133819Stjr a.iovp = stackgap_alloc(&sg, nsize); 248133819Stjr a.iovcnt = uap->iovcnt; 249133819Stjr 250133819Stjr if ((error = copyout(nio, (caddr_t)a.iovp, nsize))) 251133819Stjr goto punt; 252133819Stjr error = writev(td, &a); 253133819Stjr 254133819Stjrpunt: 255133819Stjr free(oio, M_TEMP); 256133819Stjr free(nio, M_TEMP); 257133819Stjr return (error); 258133819Stjr} 259133819Stjr 260133819Stjrstruct l_ipc_kludge { 261133819Stjr l_uintptr_t msgp; 262133819Stjr l_long msgtyp; 263133819Stjr} __packed; 264133819Stjr 265133819Stjrint 266133819Stjrlinux_ipc(struct thread *td, struct linux_ipc_args *args) 267133819Stjr{ 268133819Stjr 269133819Stjr switch (args->what & 0xFFFF) { 270133819Stjr case LINUX_SEMOP: { 271133819Stjr struct linux_semop_args a; 272133819Stjr 273133819Stjr a.semid = args->arg1; 274133819Stjr a.tsops = args->ptr; 275133819Stjr a.nsops = args->arg2; 276133819Stjr return (linux_semop(td, &a)); 277133819Stjr } 278133819Stjr case LINUX_SEMGET: { 279133819Stjr struct linux_semget_args a; 280133819Stjr 281133819Stjr a.key = args->arg1; 282133819Stjr a.nsems = args->arg2; 283133819Stjr a.semflg = args->arg3; 284133819Stjr return (linux_semget(td, &a)); 285133819Stjr } 286133819Stjr case LINUX_SEMCTL: { 287133819Stjr struct linux_semctl_args a; 288133819Stjr int error; 289133819Stjr 290133819Stjr a.semid = args->arg1; 291133819Stjr a.semnum = args->arg2; 292133819Stjr a.cmd = args->arg3; 293133819Stjr error = copyin(args->ptr, &a.arg, sizeof(a.arg)); 294133819Stjr if (error) 295133819Stjr return (error); 296133819Stjr return (linux_semctl(td, &a)); 297133819Stjr } 298133819Stjr case LINUX_MSGSND: { 299133819Stjr struct linux_msgsnd_args a; 300133819Stjr 301133819Stjr a.msqid = args->arg1; 302133819Stjr a.msgp = args->ptr; 303133819Stjr a.msgsz = args->arg2; 304133819Stjr a.msgflg = args->arg3; 305133819Stjr return (linux_msgsnd(td, &a)); 306133819Stjr } 307133819Stjr case LINUX_MSGRCV: { 308133819Stjr struct linux_msgrcv_args a; 309133819Stjr 310133819Stjr a.msqid = args->arg1; 311133819Stjr a.msgsz = args->arg2; 312133819Stjr a.msgflg = args->arg3; 313133819Stjr if ((args->what >> 16) == 0) { 314133819Stjr struct l_ipc_kludge tmp; 315133819Stjr int error; 316133819Stjr 317133819Stjr if (args->ptr == 0) 318133819Stjr return (EINVAL); 319133819Stjr error = copyin(args->ptr, &tmp, sizeof(tmp)); 320133819Stjr if (error) 321133819Stjr return (error); 322133819Stjr a.msgp = PTRIN(tmp.msgp); 323133819Stjr a.msgtyp = tmp.msgtyp; 324133819Stjr } else { 325133819Stjr a.msgp = args->ptr; 326133819Stjr a.msgtyp = args->arg5; 327133819Stjr } 328133819Stjr return (linux_msgrcv(td, &a)); 329133819Stjr } 330133819Stjr case LINUX_MSGGET: { 331133819Stjr struct linux_msgget_args a; 332133819Stjr 333133819Stjr a.key = args->arg1; 334133819Stjr a.msgflg = args->arg2; 335133819Stjr return (linux_msgget(td, &a)); 336133819Stjr } 337133819Stjr case LINUX_MSGCTL: { 338133819Stjr struct linux_msgctl_args a; 339133819Stjr 340133819Stjr a.msqid = args->arg1; 341133819Stjr a.cmd = args->arg2; 342133819Stjr a.buf = args->ptr; 343133819Stjr return (linux_msgctl(td, &a)); 344133819Stjr } 345133819Stjr case LINUX_SHMAT: { 346133819Stjr struct linux_shmat_args a; 347133819Stjr 348133819Stjr a.shmid = args->arg1; 349133819Stjr a.shmaddr = args->ptr; 350133819Stjr a.shmflg = args->arg2; 351133819Stjr a.raddr = PTRIN(args->arg3); 352133819Stjr return (linux_shmat(td, &a)); 353133819Stjr } 354133819Stjr case LINUX_SHMDT: { 355133819Stjr struct linux_shmdt_args a; 356133819Stjr 357133819Stjr a.shmaddr = args->ptr; 358133819Stjr return (linux_shmdt(td, &a)); 359133819Stjr } 360133819Stjr case LINUX_SHMGET: { 361133819Stjr struct linux_shmget_args a; 362133819Stjr 363133819Stjr a.key = args->arg1; 364133819Stjr a.size = args->arg2; 365133819Stjr a.shmflg = args->arg3; 366133819Stjr return (linux_shmget(td, &a)); 367133819Stjr } 368133819Stjr case LINUX_SHMCTL: { 369133819Stjr struct linux_shmctl_args a; 370133819Stjr 371133819Stjr a.shmid = args->arg1; 372133819Stjr a.cmd = args->arg2; 373133819Stjr a.buf = args->ptr; 374133819Stjr return (linux_shmctl(td, &a)); 375133819Stjr } 376133819Stjr default: 377133819Stjr break; 378133819Stjr } 379133819Stjr 380133819Stjr return (EINVAL); 381133819Stjr} 382133819Stjr 383133819Stjrint 384133819Stjrlinux_old_select(struct thread *td, struct linux_old_select_args *args) 385133819Stjr{ 386133819Stjr struct l_old_select_argv linux_args; 387133819Stjr struct linux_select_args newsel; 388133819Stjr int error; 389133819Stjr 390133819Stjr#ifdef DEBUG 391133819Stjr if (ldebug(old_select)) 392133819Stjr printf(ARGS(old_select, "%p"), args->ptr); 393133819Stjr#endif 394133819Stjr 395133819Stjr error = copyin(args->ptr, &linux_args, sizeof(linux_args)); 396133819Stjr if (error) 397133819Stjr return (error); 398133819Stjr 399133819Stjr newsel.nfds = linux_args.nfds; 400133819Stjr newsel.readfds = PTRIN(linux_args.readfds); 401133819Stjr newsel.writefds = PTRIN(linux_args.writefds); 402133819Stjr newsel.exceptfds = PTRIN(linux_args.exceptfds); 403133819Stjr newsel.timeout = PTRIN(linux_args.timeout); 404133819Stjr return (linux_select(td, &newsel)); 405133819Stjr} 406133819Stjr 407133819Stjrint 408133819Stjrlinux_fork(struct thread *td, struct linux_fork_args *args) 409133819Stjr{ 410133819Stjr int error; 411133819Stjr 412133819Stjr#ifdef DEBUG 413133819Stjr if (ldebug(fork)) 414133819Stjr printf(ARGS(fork, "")); 415133819Stjr#endif 416133819Stjr 417133819Stjr if ((error = fork(td, (struct fork_args *)args)) != 0) 418133819Stjr return (error); 419133819Stjr 420133819Stjr if (td->td_retval[1] == 1) 421133819Stjr td->td_retval[0] = 0; 422133819Stjr return (0); 423133819Stjr} 424133819Stjr 425133819Stjrint 426133819Stjrlinux_vfork(struct thread *td, struct linux_vfork_args *args) 427133819Stjr{ 428133819Stjr int error; 429133819Stjr 430133819Stjr#ifdef DEBUG 431133819Stjr if (ldebug(vfork)) 432133819Stjr printf(ARGS(vfork, "")); 433133819Stjr#endif 434133819Stjr 435133819Stjr if ((error = vfork(td, (struct vfork_args *)args)) != 0) 436133819Stjr return (error); 437133819Stjr /* Are we the child? */ 438133819Stjr if (td->td_retval[1] == 1) 439133819Stjr td->td_retval[0] = 0; 440133819Stjr return (0); 441133819Stjr} 442133819Stjr 443133819Stjr#define CLONE_VM 0x100 444133819Stjr#define CLONE_FS 0x200 445133819Stjr#define CLONE_FILES 0x400 446133819Stjr#define CLONE_SIGHAND 0x800 447133819Stjr#define CLONE_PID 0x1000 448133819Stjr 449133819Stjrint 450133819Stjrlinux_clone(struct thread *td, struct linux_clone_args *args) 451133819Stjr{ 452133819Stjr int error, ff = RFPROC | RFSTOPPED; 453133819Stjr struct proc *p2; 454133819Stjr struct thread *td2; 455133819Stjr int exit_signal; 456133819Stjr 457133819Stjr#ifdef DEBUG 458133819Stjr if (ldebug(clone)) { 459133819Stjr printf(ARGS(clone, "flags %x, stack %x"), 460133843Sobrien (unsigned int)(uintptr_t)args->flags, 461133843Sobrien (unsigned int)(uintptr_t)args->stack); 462133819Stjr if (args->flags & CLONE_PID) 463133819Stjr printf(LMSG("CLONE_PID not yet supported")); 464133819Stjr } 465133819Stjr#endif 466133819Stjr 467133819Stjr if (!args->stack) 468133819Stjr return (EINVAL); 469133819Stjr 470133819Stjr exit_signal = args->flags & 0x000000ff; 471133819Stjr if (exit_signal >= LINUX_NSIG) 472133819Stjr return (EINVAL); 473133819Stjr 474133819Stjr if (exit_signal <= LINUX_SIGTBLSZ) 475133819Stjr exit_signal = linux_to_bsd_signal[_SIG_IDX(exit_signal)]; 476133819Stjr 477133819Stjr if (args->flags & CLONE_VM) 478133819Stjr ff |= RFMEM; 479133819Stjr if (args->flags & CLONE_SIGHAND) 480133819Stjr ff |= RFSIGSHARE; 481133819Stjr if (!(args->flags & CLONE_FILES)) 482133819Stjr ff |= RFFDG; 483133819Stjr 484133819Stjr error = fork1(td, ff, 0, &p2); 485133819Stjr if (error) 486133819Stjr return (error); 487133819Stjr 488133819Stjr 489133819Stjr PROC_LOCK(p2); 490133819Stjr p2->p_sigparent = exit_signal; 491133819Stjr PROC_UNLOCK(p2); 492133819Stjr td2 = FIRST_THREAD_IN_PROC(p2); 493133819Stjr td2->td_frame->tf_rsp = PTROUT(args->stack); 494133819Stjr 495133819Stjr#ifdef DEBUG 496133819Stjr if (ldebug(clone)) 497133819Stjr printf(LMSG("clone: successful rfork to %ld, stack %p sig = %d"), 498133819Stjr (long)p2->p_pid, args->stack, exit_signal); 499133819Stjr#endif 500133819Stjr 501133819Stjr /* 502133819Stjr * Make this runnable after we are finished with it. 503133819Stjr */ 504133819Stjr mtx_lock_spin(&sched_lock); 505133819Stjr TD_SET_CAN_RUN(td2); 506133819Stjr setrunqueue(td2); 507133819Stjr mtx_unlock_spin(&sched_lock); 508133819Stjr 509133819Stjr td->td_retval[0] = p2->p_pid; 510133819Stjr td->td_retval[1] = 0; 511133819Stjr return (0); 512133819Stjr} 513133819Stjr 514133819Stjr/* XXX move */ 515133819Stjrstruct l_mmap_argv { 516133819Stjr l_ulong addr; 517133819Stjr l_int len; 518133819Stjr l_int prot; 519133819Stjr l_int flags; 520133819Stjr l_int fd; 521133819Stjr l_int pos; 522133819Stjr}; 523133819Stjr 524133819Stjr#define STACK_SIZE (2 * 1024 * 1024) 525133819Stjr#define GUARD_SIZE (4 * PAGE_SIZE) 526133819Stjr 527133819Stjrstatic int linux_mmap_common(struct thread *, struct l_mmap_argv *); 528133819Stjr 529133819Stjrint 530133819Stjrlinux_mmap2(struct thread *td, struct linux_mmap2_args *args) 531133819Stjr{ 532133819Stjr struct l_mmap_argv linux_args; 533133819Stjr 534133819Stjr#ifdef DEBUG 535133819Stjr if (ldebug(mmap2)) 536133819Stjr printf(ARGS(mmap2, "%p, %d, %d, 0x%08x, %d, %d"), 537133843Sobrien (void *)(intptr_t)args->addr, args->len, args->prot, 538133819Stjr args->flags, args->fd, args->pgoff); 539133819Stjr#endif 540133819Stjr 541133819Stjr linux_args.addr = PTROUT(args->addr); 542133819Stjr linux_args.len = args->len; 543133819Stjr linux_args.prot = args->prot; 544133819Stjr linux_args.flags = args->flags; 545133819Stjr linux_args.fd = args->fd; 546133819Stjr linux_args.pos = args->pgoff * PAGE_SIZE; 547133819Stjr 548133819Stjr return (linux_mmap_common(td, &linux_args)); 549133819Stjr} 550133819Stjr 551133819Stjrint 552133819Stjrlinux_mmap(struct thread *td, struct linux_mmap_args *args) 553133819Stjr{ 554133819Stjr int error; 555133819Stjr struct l_mmap_argv linux_args; 556133819Stjr 557133819Stjr error = copyin(args->ptr, &linux_args, sizeof(linux_args)); 558133819Stjr if (error) 559133819Stjr return (error); 560133819Stjr 561133819Stjr#ifdef DEBUG 562133819Stjr if (ldebug(mmap)) 563133819Stjr printf(ARGS(mmap, "%p, %d, %d, 0x%08x, %d, %d"), 564133843Sobrien (void *)(intptr_t)linux_args.addr, linux_args.len, 565133843Sobrien linux_args.prot, linux_args.flags, linux_args.fd, 566133843Sobrien linux_args.pos); 567133819Stjr#endif 568133819Stjr 569133819Stjr return (linux_mmap_common(td, &linux_args)); 570133819Stjr} 571133819Stjr 572133819Stjrstatic int 573133819Stjrlinux_mmap_common(struct thread *td, struct l_mmap_argv *linux_args) 574133819Stjr{ 575133819Stjr struct proc *p = td->td_proc; 576133819Stjr struct mmap_args /* { 577133819Stjr caddr_t addr; 578133819Stjr size_t len; 579133819Stjr int prot; 580133819Stjr int flags; 581133819Stjr int fd; 582133819Stjr long pad; 583133819Stjr off_t pos; 584133819Stjr } */ bsd_args; 585133819Stjr int error; 586133819Stjr 587133819Stjr error = 0; 588133819Stjr bsd_args.flags = 0; 589133819Stjr if (linux_args->flags & LINUX_MAP_SHARED) 590133819Stjr bsd_args.flags |= MAP_SHARED; 591133819Stjr if (linux_args->flags & LINUX_MAP_PRIVATE) 592133819Stjr bsd_args.flags |= MAP_PRIVATE; 593133819Stjr if (linux_args->flags & LINUX_MAP_FIXED) 594133819Stjr bsd_args.flags |= MAP_FIXED; 595133819Stjr if (linux_args->flags & LINUX_MAP_ANON) 596133819Stjr bsd_args.flags |= MAP_ANON; 597133819Stjr else 598133819Stjr bsd_args.flags |= MAP_NOSYNC; 599133819Stjr if (linux_args->flags & LINUX_MAP_GROWSDOWN) { 600133819Stjr bsd_args.flags |= MAP_STACK; 601133819Stjr 602133819Stjr /* The linux MAP_GROWSDOWN option does not limit auto 603133819Stjr * growth of the region. Linux mmap with this option 604133819Stjr * takes as addr the inital BOS, and as len, the initial 605133819Stjr * region size. It can then grow down from addr without 606133819Stjr * limit. However, linux threads has an implicit internal 607133819Stjr * limit to stack size of STACK_SIZE. Its just not 608133819Stjr * enforced explicitly in linux. But, here we impose 609133819Stjr * a limit of (STACK_SIZE - GUARD_SIZE) on the stack 610133819Stjr * region, since we can do this with our mmap. 611133819Stjr * 612133819Stjr * Our mmap with MAP_STACK takes addr as the maximum 613133819Stjr * downsize limit on BOS, and as len the max size of 614133819Stjr * the region. It them maps the top SGROWSIZ bytes, 615133819Stjr * and autgrows the region down, up to the limit 616133819Stjr * in addr. 617133819Stjr * 618133819Stjr * If we don't use the MAP_STACK option, the effect 619133819Stjr * of this code is to allocate a stack region of a 620133819Stjr * fixed size of (STACK_SIZE - GUARD_SIZE). 621133819Stjr */ 622133819Stjr 623133819Stjr /* This gives us TOS */ 624133819Stjr bsd_args.addr = (caddr_t)PTRIN(linux_args->addr) + 625133819Stjr linux_args->len; 626133819Stjr 627133819Stjr if ((caddr_t)PTRIN(bsd_args.addr) > 628133819Stjr p->p_vmspace->vm_maxsaddr) { 629133819Stjr /* Some linux apps will attempt to mmap 630133819Stjr * thread stacks near the top of their 631133819Stjr * address space. If their TOS is greater 632133819Stjr * than vm_maxsaddr, vm_map_growstack() 633133819Stjr * will confuse the thread stack with the 634133819Stjr * process stack and deliver a SEGV if they 635133819Stjr * attempt to grow the thread stack past their 636133819Stjr * current stacksize rlimit. To avoid this, 637133819Stjr * adjust vm_maxsaddr upwards to reflect 638133819Stjr * the current stacksize rlimit rather 639133819Stjr * than the maximum possible stacksize. 640133819Stjr * It would be better to adjust the 641133819Stjr * mmap'ed region, but some apps do not check 642133819Stjr * mmap's return value. 643133819Stjr */ 644133819Stjr PROC_LOCK(p); 645133819Stjr p->p_vmspace->vm_maxsaddr = 646133819Stjr (char *)LINUX32_USRSTACK - 647133819Stjr lim_cur(p, RLIMIT_STACK); 648133819Stjr PROC_UNLOCK(p); 649133819Stjr } 650133819Stjr 651133819Stjr /* This gives us our maximum stack size */ 652133819Stjr if (linux_args->len > STACK_SIZE - GUARD_SIZE) 653133819Stjr bsd_args.len = linux_args->len; 654133819Stjr else 655133819Stjr bsd_args.len = STACK_SIZE - GUARD_SIZE; 656133819Stjr 657133819Stjr /* This gives us a new BOS. If we're using VM_STACK, then 658133819Stjr * mmap will just map the top SGROWSIZ bytes, and let 659133819Stjr * the stack grow down to the limit at BOS. If we're 660133819Stjr * not using VM_STACK we map the full stack, since we 661133819Stjr * don't have a way to autogrow it. 662133819Stjr */ 663133819Stjr bsd_args.addr -= bsd_args.len; 664133819Stjr } else { 665133819Stjr bsd_args.addr = (caddr_t)PTRIN(linux_args->addr); 666133819Stjr bsd_args.len = linux_args->len; 667133819Stjr } 668133819Stjr /* 669133819Stjr * XXX i386 Linux always emulator forces PROT_READ on (why?) 670133819Stjr * so we do the same. We add PROT_EXEC to work around buggy 671133819Stjr * applications (e.g. Java) that take advantage of the fact 672133819Stjr * that execute permissions are not enforced by x86 CPUs. 673133819Stjr */ 674133819Stjr bsd_args.prot = linux_args->prot | PROT_EXEC | PROT_READ; 675133819Stjr if (linux_args->flags & LINUX_MAP_ANON) 676133819Stjr bsd_args.fd = -1; 677133819Stjr else 678133819Stjr bsd_args.fd = linux_args->fd; 679133819Stjr bsd_args.pos = linux_args->pos; 680133819Stjr bsd_args.pad = 0; 681133819Stjr 682133819Stjr#ifdef DEBUG 683133819Stjr if (ldebug(mmap)) 684133819Stjr printf("-> %s(%p, %d, %d, 0x%08x, %d, 0x%x)\n", 685133819Stjr __func__, 686133843Sobrien (void *)bsd_args.addr, (int)bsd_args.len, bsd_args.prot, 687133819Stjr bsd_args.flags, bsd_args.fd, (int)bsd_args.pos); 688133819Stjr#endif 689133819Stjr error = mmap(td, &bsd_args); 690133819Stjr#ifdef DEBUG 691133819Stjr if (ldebug(mmap)) 692133819Stjr printf("-> %s() return: 0x%x (0x%08x)\n", 693133819Stjr __func__, error, (u_int)td->td_retval[0]); 694133819Stjr#endif 695133819Stjr return (error); 696133819Stjr} 697133819Stjr 698133819Stjrint 699133819Stjrlinux_pipe(struct thread *td, struct linux_pipe_args *args) 700133819Stjr{ 701133819Stjr int pip[2]; 702133819Stjr int error; 703133819Stjr register_t reg_rdx; 704133819Stjr 705133819Stjr#ifdef DEBUG 706133819Stjr if (ldebug(pipe)) 707133819Stjr printf(ARGS(pipe, "*")); 708133819Stjr#endif 709133819Stjr 710133819Stjr reg_rdx = td->td_retval[1]; 711133819Stjr error = pipe(td, 0); 712133819Stjr if (error) { 713133819Stjr td->td_retval[1] = reg_rdx; 714133819Stjr return (error); 715133819Stjr } 716133819Stjr 717133819Stjr pip[0] = td->td_retval[0]; 718133819Stjr pip[1] = td->td_retval[1]; 719133819Stjr error = copyout(pip, args->pipefds, 2 * sizeof(int)); 720133819Stjr if (error) { 721133819Stjr td->td_retval[1] = reg_rdx; 722133819Stjr return (error); 723133819Stjr } 724133819Stjr 725133819Stjr td->td_retval[1] = reg_rdx; 726133819Stjr td->td_retval[0] = 0; 727133819Stjr return (0); 728133819Stjr} 729133819Stjr 730133819Stjrint 731133819Stjrlinux_sigaction(struct thread *td, struct linux_sigaction_args *args) 732133819Stjr{ 733133819Stjr l_osigaction_t osa; 734133819Stjr l_sigaction_t act, oact; 735133819Stjr int error; 736133819Stjr 737133819Stjr#ifdef DEBUG 738133819Stjr if (ldebug(sigaction)) 739133819Stjr printf(ARGS(sigaction, "%d, %p, %p"), 740133819Stjr args->sig, (void *)args->nsa, (void *)args->osa); 741133819Stjr#endif 742133819Stjr 743133819Stjr if (args->nsa != NULL) { 744133819Stjr error = copyin(args->nsa, &osa, sizeof(l_osigaction_t)); 745133819Stjr if (error) 746133819Stjr return (error); 747133819Stjr act.lsa_handler = osa.lsa_handler; 748133819Stjr act.lsa_flags = osa.lsa_flags; 749133819Stjr act.lsa_restorer = osa.lsa_restorer; 750133819Stjr LINUX_SIGEMPTYSET(act.lsa_mask); 751133819Stjr act.lsa_mask.__bits[0] = osa.lsa_mask; 752133819Stjr } 753133819Stjr 754133819Stjr error = linux_do_sigaction(td, args->sig, args->nsa ? &act : NULL, 755133819Stjr args->osa ? &oact : NULL); 756133819Stjr 757133819Stjr if (args->osa != NULL && !error) { 758133819Stjr osa.lsa_handler = oact.lsa_handler; 759133819Stjr osa.lsa_flags = oact.lsa_flags; 760133819Stjr osa.lsa_restorer = oact.lsa_restorer; 761133819Stjr osa.lsa_mask = oact.lsa_mask.__bits[0]; 762133819Stjr error = copyout(&osa, args->osa, sizeof(l_osigaction_t)); 763133819Stjr } 764133819Stjr 765133819Stjr return (error); 766133819Stjr} 767133819Stjr 768133819Stjr/* 769133819Stjr * Linux has two extra args, restart and oldmask. We dont use these, 770133819Stjr * but it seems that "restart" is actually a context pointer that 771133819Stjr * enables the signal to happen with a different register set. 772133819Stjr */ 773133819Stjrint 774133819Stjrlinux_sigsuspend(struct thread *td, struct linux_sigsuspend_args *args) 775133819Stjr{ 776133819Stjr sigset_t sigmask; 777133819Stjr l_sigset_t mask; 778133819Stjr 779133819Stjr#ifdef DEBUG 780133819Stjr if (ldebug(sigsuspend)) 781133819Stjr printf(ARGS(sigsuspend, "%08lx"), (unsigned long)args->mask); 782133819Stjr#endif 783133819Stjr 784133819Stjr LINUX_SIGEMPTYSET(mask); 785133819Stjr mask.__bits[0] = args->mask; 786133819Stjr linux_to_bsd_sigset(&mask, &sigmask); 787133819Stjr return (kern_sigsuspend(td, sigmask)); 788133819Stjr} 789133819Stjr 790133819Stjrint 791133819Stjrlinux_rt_sigsuspend(struct thread *td, struct linux_rt_sigsuspend_args *uap) 792133819Stjr{ 793133819Stjr l_sigset_t lmask; 794133819Stjr sigset_t sigmask; 795133819Stjr int error; 796133819Stjr 797133819Stjr#ifdef DEBUG 798133819Stjr if (ldebug(rt_sigsuspend)) 799133819Stjr printf(ARGS(rt_sigsuspend, "%p, %d"), 800133819Stjr (void *)uap->newset, uap->sigsetsize); 801133819Stjr#endif 802133819Stjr 803133819Stjr if (uap->sigsetsize != sizeof(l_sigset_t)) 804133819Stjr return (EINVAL); 805133819Stjr 806133819Stjr error = copyin(uap->newset, &lmask, sizeof(l_sigset_t)); 807133819Stjr if (error) 808133819Stjr return (error); 809133819Stjr 810133819Stjr linux_to_bsd_sigset(&lmask, &sigmask); 811133819Stjr return (kern_sigsuspend(td, sigmask)); 812133819Stjr} 813133819Stjr 814133819Stjrint 815133819Stjrlinux_pause(struct thread *td, struct linux_pause_args *args) 816133819Stjr{ 817133819Stjr struct proc *p = td->td_proc; 818133819Stjr sigset_t sigmask; 819133819Stjr 820133819Stjr#ifdef DEBUG 821133819Stjr if (ldebug(pause)) 822133819Stjr printf(ARGS(pause, "")); 823133819Stjr#endif 824133819Stjr 825133819Stjr PROC_LOCK(p); 826133819Stjr sigmask = td->td_sigmask; 827133819Stjr PROC_UNLOCK(p); 828133819Stjr return (kern_sigsuspend(td, sigmask)); 829133819Stjr} 830133819Stjr 831133819Stjrint 832133819Stjrlinux_sigaltstack(struct thread *td, struct linux_sigaltstack_args *uap) 833133819Stjr{ 834133819Stjr stack_t ss, oss; 835133819Stjr l_stack_t lss; 836133819Stjr int error; 837133819Stjr 838133819Stjr#ifdef DEBUG 839133819Stjr if (ldebug(sigaltstack)) 840133819Stjr printf(ARGS(sigaltstack, "%p, %p"), uap->uss, uap->uoss); 841133819Stjr#endif 842133819Stjr 843133819Stjr if (uap->uss != NULL) { 844133819Stjr error = copyin(uap->uss, &lss, sizeof(l_stack_t)); 845133819Stjr if (error) 846133819Stjr return (error); 847133819Stjr 848133819Stjr ss.ss_sp = PTRIN(lss.ss_sp); 849133819Stjr ss.ss_size = lss.ss_size; 850133819Stjr ss.ss_flags = linux_to_bsd_sigaltstack(lss.ss_flags); 851133819Stjr } 852134269Sjhb error = kern_sigaltstack(td, (uap->uss != NULL) ? &ss : NULL, 853134269Sjhb (uap->uoss != NULL) ? &oss : NULL); 854133819Stjr if (!error && uap->uoss != NULL) { 855133819Stjr lss.ss_sp = PTROUT(oss.ss_sp); 856133819Stjr lss.ss_size = oss.ss_size; 857133819Stjr lss.ss_flags = bsd_to_linux_sigaltstack(oss.ss_flags); 858133819Stjr error = copyout(&lss, uap->uoss, sizeof(l_stack_t)); 859133819Stjr } 860133819Stjr 861133819Stjr return (error); 862133819Stjr} 863133819Stjr 864133819Stjrint 865133819Stjrlinux_ftruncate64(struct thread *td, struct linux_ftruncate64_args *args) 866133819Stjr{ 867133819Stjr struct ftruncate_args sa; 868133819Stjr 869133819Stjr#ifdef DEBUG 870133819Stjr if (ldebug(ftruncate64)) 871133819Stjr printf(ARGS(ftruncate64, "%u, %jd"), args->fd, 872133819Stjr (intmax_t)args->length); 873133819Stjr#endif 874133819Stjr 875133819Stjr sa.fd = args->fd; 876133819Stjr sa.pad = 0; 877133819Stjr sa.length = args->length; 878133819Stjr return ftruncate(td, &sa); 879133819Stjr} 880133819Stjr 881133819Stjrint 882133819Stjrlinux_gettimeofday(struct thread *td, struct linux_gettimeofday_args *uap) 883133819Stjr{ 884133819Stjr struct timeval atv; 885133819Stjr l_timeval atv32; 886133819Stjr struct timezone rtz; 887133819Stjr int error = 0; 888133819Stjr 889133819Stjr if (uap->tp) { 890133819Stjr microtime(&atv); 891133819Stjr atv32.tv_sec = atv.tv_sec; 892133819Stjr atv32.tv_usec = atv.tv_usec; 893133819Stjr error = copyout(&atv32, uap->tp, sizeof (atv32)); 894133819Stjr } 895133819Stjr if (error == 0 && uap->tzp != NULL) { 896133819Stjr rtz.tz_minuteswest = tz_minuteswest; 897133819Stjr rtz.tz_dsttime = tz_dsttime; 898133819Stjr error = copyout(&rtz, uap->tzp, sizeof (rtz)); 899133819Stjr } 900133819Stjr return (error); 901133819Stjr} 902133819Stjr 903133819Stjrint 904133819Stjrlinux_nanosleep(struct thread *td, struct linux_nanosleep_args *uap) 905133819Stjr{ 906133819Stjr struct timespec ats; 907133819Stjr struct l_timespec ats32; 908133819Stjr struct nanosleep_args bsd_args; 909133819Stjr int error; 910133819Stjr caddr_t sg; 911133819Stjr caddr_t sarqts, sarmts; 912133819Stjr 913133819Stjr sg = stackgap_init(); 914133819Stjr error = copyin(uap->rqtp, &ats32, sizeof(ats32)); 915133819Stjr if (error != 0) 916133819Stjr return (error); 917133819Stjr ats.tv_sec = ats32.tv_sec; 918133819Stjr ats.tv_nsec = ats32.tv_nsec; 919133819Stjr sarqts = stackgap_alloc(&sg, sizeof(ats)); 920133819Stjr error = copyout(&ats, sarqts, sizeof(ats)); 921133819Stjr if (error != 0) 922133819Stjr return (error); 923133819Stjr sarmts = stackgap_alloc(&sg, sizeof(ats)); 924133819Stjr bsd_args.rqtp = (void *)sarqts; 925133819Stjr bsd_args.rmtp = (void *)sarmts; 926133819Stjr error = nanosleep(td, &bsd_args); 927133819Stjr if (uap->rmtp != NULL) { 928133819Stjr error = copyin(sarmts, &ats, sizeof(ats)); 929133819Stjr if (error != 0) 930133819Stjr return (error); 931133819Stjr ats32.tv_sec = ats.tv_sec; 932133819Stjr ats32.tv_nsec = ats.tv_nsec; 933133819Stjr error = copyout(&ats32, uap->rmtp, sizeof(ats32)); 934133819Stjr if (error != 0) 935133819Stjr return (error); 936133819Stjr } 937133819Stjr return (error); 938133819Stjr} 939133819Stjr 940133819Stjrint 941133819Stjrlinux_getrusage(struct thread *td, struct linux_getrusage_args *uap) 942133819Stjr{ 943133819Stjr int error; 944133819Stjr caddr_t sg; 945133819Stjr struct l_rusage *p32, s32; 946133819Stjr struct rusage *p = NULL, s; 947133819Stjr 948133819Stjr p32 = uap->rusage; 949133819Stjr if (p32 != NULL) { 950133819Stjr sg = stackgap_init(); 951133819Stjr p = stackgap_alloc(&sg, sizeof(struct rusage)); 952133819Stjr uap->rusage = (struct l_rusage *)p; 953133819Stjr } 954133819Stjr error = getrusage(td, (struct getrusage_args *) uap); 955133819Stjr if (error != 0) 956133819Stjr return (error); 957133819Stjr if (p32 != NULL) { 958133819Stjr error = copyin(p, &s, sizeof(s)); 959133819Stjr if (error != 0) 960133819Stjr return (error); 961133819Stjr s32.ru_utime.tv_sec = s.ru_utime.tv_sec; 962133819Stjr s32.ru_utime.tv_usec = s.ru_utime.tv_usec; 963133819Stjr s32.ru_stime.tv_sec = s.ru_stime.tv_sec; 964133819Stjr s32.ru_stime.tv_usec = s.ru_stime.tv_usec; 965133819Stjr s32.ru_maxrss = s.ru_maxrss; 966133819Stjr s32.ru_ixrss = s.ru_ixrss; 967133819Stjr s32.ru_idrss = s.ru_idrss; 968133819Stjr s32.ru_isrss = s.ru_isrss; 969133819Stjr s32.ru_minflt = s.ru_minflt; 970133819Stjr s32.ru_majflt = s.ru_majflt; 971133819Stjr s32.ru_nswap = s.ru_nswap; 972133819Stjr s32.ru_inblock = s.ru_inblock; 973133819Stjr s32.ru_oublock = s.ru_oublock; 974133819Stjr s32.ru_msgsnd = s.ru_msgsnd; 975133819Stjr s32.ru_msgrcv = s.ru_msgrcv; 976133819Stjr s32.ru_nsignals = s.ru_nsignals; 977133819Stjr s32.ru_nvcsw = s.ru_nvcsw; 978133819Stjr s32.ru_nivcsw = s.ru_nivcsw; 979133819Stjr error = copyout(&s32, p32, sizeof(s32)); 980133819Stjr } 981133819Stjr return (error); 982133819Stjr} 983133819Stjr 984133819Stjrint 985133819Stjrlinux_sched_rr_get_interval(struct thread *td, 986133819Stjr struct linux_sched_rr_get_interval_args *uap) 987133819Stjr{ 988133819Stjr struct sched_rr_get_interval_args bsd_args; 989133819Stjr caddr_t sg, psgts; 990133819Stjr struct timespec ts; 991133819Stjr struct l_timespec ts32; 992133819Stjr int error; 993133819Stjr 994133819Stjr sg = stackgap_init(); 995133819Stjr psgts = stackgap_alloc(&sg, sizeof(struct timespec)); 996133819Stjr bsd_args.pid = uap->pid; 997133819Stjr bsd_args.interval = (void *)psgts; 998133819Stjr error = sched_rr_get_interval(td, &bsd_args); 999133819Stjr if (error != 0) 1000133819Stjr return (error); 1001133819Stjr error = copyin(psgts, &ts, sizeof(ts)); 1002133819Stjr if (error != 0) 1003133819Stjr return (error); 1004133819Stjr ts32.tv_sec = ts.tv_sec; 1005133819Stjr ts32.tv_nsec = ts.tv_nsec; 1006133819Stjr return (copyout(&ts32, uap->interval, sizeof(ts32))); 1007133819Stjr} 1008133819Stjr 1009133819Stjrint 1010133819Stjrlinux_mprotect(struct thread *td, struct linux_mprotect_args *uap) 1011133819Stjr{ 1012133819Stjr struct mprotect_args bsd_args; 1013133819Stjr 1014133819Stjr bsd_args.addr = uap->addr; 1015133819Stjr bsd_args.len = uap->len; 1016133819Stjr bsd_args.prot = uap->prot; 1017133819Stjr /* XXX PROT_READ implies PROT_EXEC; see linux_mmap_common(). */ 1018133819Stjr if ((bsd_args.prot & PROT_READ) != 0) 1019133819Stjr bsd_args.prot |= PROT_EXEC; 1020133819Stjr return (mprotect(td, &bsd_args)); 1021133819Stjr} 1022