linux_machdep.c revision 67238
164921Smarcel/*- 264921Smarcel * Copyright (c) 2000 Marcel Moolenaar 364921Smarcel * All rights reserved. 464921Smarcel * 564921Smarcel * Redistribution and use in source and binary forms, with or without 664921Smarcel * modification, are permitted provided that the following conditions 764921Smarcel * are met: 864921Smarcel * 1. Redistributions of source code must retain the above copyright 964921Smarcel * notice, this list of conditions and the following disclaimer 1064921Smarcel * in this position and unchanged. 1164921Smarcel * 2. Redistributions in binary form must reproduce the above copyright 1264921Smarcel * notice, this list of conditions and the following disclaimer in the 1364921Smarcel * documentation and/or other materials provided with the distribution. 1464921Smarcel * 3. The name of the author may not be used to endorse or promote products 1565067Smarcel * derived from this software without specific prior written permission. 1664921Smarcel * 1764921Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1864921Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1964921Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2064921Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2164921Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2264921Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2364921Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2464921Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2564921Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2664921Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2764921Smarcel * 2864921Smarcel * $FreeBSD: head/sys/i386/linux/linux_machdep.c 67238 2000-10-17 00:25:43Z gallatin $ 2964921Smarcel */ 3064921Smarcel 3164921Smarcel#include <sys/param.h> 3264921Smarcel#include <sys/mman.h> 3364921Smarcel#include <sys/proc.h> 3464921Smarcel#include <sys/sysproto.h> 3564921Smarcel#include <sys/systm.h> 3664921Smarcel#include <sys/unistd.h> 3767238Sgallatin#include <sys/resource.h> 3867238Sgallatin#include <sys/resourcevar.h> 3964921Smarcel 4064921Smarcel#include <machine/frame.h> 4164921Smarcel#include <machine/psl.h> 4264921Smarcel#include <machine/segments.h> 4364921Smarcel#include <machine/sysarch.h> 4464921Smarcel 4567238Sgallatin#include <vm/vm.h> 4667238Sgallatin#include <sys/lock.h> 4767238Sgallatin#include <vm/pmap.h> 4867238Sgallatin#include <vm/vm_map.h> 4967238Sgallatin 5067238Sgallatin 5164921Smarcel#include <i386/linux/linux.h> 5264921Smarcel#include <i386/linux/linux_proto.h> 5364921Smarcel#include <compat/linux/linux_ipc.h> 5464921Smarcel#include <compat/linux/linux_signal.h> 5564921Smarcel#include <compat/linux/linux_util.h> 5664921Smarcel 5764921Smarcelstruct linux_descriptor { 5864921Smarcel unsigned int entry_number; 5964921Smarcel unsigned long base_addr; 6064921Smarcel unsigned int limit; 6164921Smarcel unsigned int seg_32bit:1; 6264921Smarcel unsigned int contents:2; 6364921Smarcel unsigned int read_exec_only:1; 6464921Smarcel unsigned int limit_in_pages:1; 6564921Smarcel unsigned int seg_not_present:1; 6664921Smarcel unsigned int useable:1; 6764921Smarcel}; 6864921Smarcel 6964921Smarcelstruct linux_select_argv { 7064921Smarcel int nfds; 7164921Smarcel fd_set *readfds; 7264921Smarcel fd_set *writefds; 7364921Smarcel fd_set *exceptfds; 7464921Smarcel struct timeval *timeout; 7564921Smarcel}; 7664921Smarcel 7764921Smarcelint 7867051Sgallatinlinux_to_bsd_sigaltstack(int lsa) 7967051Sgallatin{ 8067051Sgallatin int bsa = 0; 8167051Sgallatin 8267051Sgallatin if (lsa & LINUX_SS_DISABLE) 8367051Sgallatin bsa |= SS_DISABLE; 8467051Sgallatin if (lsa & LINUX_SS_ONSTACK) 8567051Sgallatin bsa |= SS_ONSTACK; 8667051Sgallatin if (lsa == LINUX_SS_ONSTACK_BC) 8767051Sgallatin bsa = SS_ONSTACK; 8867051Sgallatin return (bsa); 8967051Sgallatin} 9067051Sgallatin 9167051Sgallatinint 9267051Sgallatinbsd_to_linux_sigaltstack(int bsa) 9367051Sgallatin{ 9467051Sgallatin int lsa = 0; 9567051Sgallatin 9667051Sgallatin if (bsa & SS_DISABLE) 9767051Sgallatin lsa |= LINUX_SS_DISABLE; 9867051Sgallatin if (bsa & SS_ONSTACK) 9967051Sgallatin lsa |= LINUX_SS_ONSTACK; 10067051Sgallatin return (lsa); 10167051Sgallatin} 10267051Sgallatin 10367051Sgallatinint 10464921Smarcellinux_execve(struct proc *p, struct linux_execve_args *args) 10564921Smarcel{ 10664921Smarcel struct execve_args bsd; 10764921Smarcel caddr_t sg; 10864921Smarcel 10964921Smarcel sg = stackgap_init(); 11064921Smarcel CHECKALTEXIST(p, &sg, args->path); 11164921Smarcel 11264921Smarcel#ifdef DEBUG 11364921Smarcel printf("Linux-emul(%d): execve(%s)\n", 11464921Smarcel p->p_pid, args->path); 11564921Smarcel#endif 11664921Smarcel 11764921Smarcel bsd.fname = args->path; 11864921Smarcel bsd.argv = args->argp; 11964921Smarcel bsd.envv = args->envp; 12064921Smarcel return (execve(p, &bsd)); 12164921Smarcel} 12264921Smarcel 12364921Smarcelint 12464921Smarcellinux_ipc(struct proc *p, struct linux_ipc_args *args) 12564921Smarcel{ 12664921Smarcel switch (args->what) { 12764921Smarcel case LINUX_SEMOP: 12864921Smarcel return (linux_semop(p, args)); 12964921Smarcel case LINUX_SEMGET: 13064921Smarcel return (linux_semget(p, args)); 13164921Smarcel case LINUX_SEMCTL: 13264921Smarcel return (linux_semctl(p, args)); 13364921Smarcel case LINUX_MSGSND: 13464921Smarcel return (linux_msgsnd(p, args)); 13564921Smarcel case LINUX_MSGRCV: 13664921Smarcel return (linux_msgrcv(p, args)); 13764921Smarcel case LINUX_MSGGET: 13864921Smarcel return (linux_msgget(p, args)); 13964921Smarcel case LINUX_MSGCTL: 14064921Smarcel return (linux_msgctl(p, args)); 14164921Smarcel case LINUX_SHMAT: 14264921Smarcel return (linux_shmat(p, args)); 14364921Smarcel case LINUX_SHMDT: 14464921Smarcel return (linux_shmdt(p, args)); 14564921Smarcel case LINUX_SHMGET: 14664921Smarcel return (linux_shmget(p, args)); 14764921Smarcel case LINUX_SHMCTL: 14864921Smarcel return (linux_shmctl(p, args)); 14964921Smarcel } 15064921Smarcel 15164921Smarcel uprintf("LINUX: 'ipc' typ=%d not implemented\n", args->what); 15264921Smarcel return (ENOSYS); 15364921Smarcel} 15464921Smarcel 15564921Smarcelint 15664921Smarcellinux_select(struct proc *p, struct linux_select_args *args) 15764921Smarcel{ 15864921Smarcel struct linux_select_argv linux_args; 15964921Smarcel struct linux_newselect_args newsel; 16064921Smarcel int error; 16164921Smarcel 16264921Smarcel#ifdef SELECT_DEBUG 16364921Smarcel printf("Linux-emul(%ld): select(%x)\n", (long)p->p_pid, args->ptr); 16464921Smarcel#endif 16564921Smarcel 16664921Smarcel error = copyin(args->ptr, &linux_args, sizeof(linux_args)); 16764921Smarcel if (error) 16864921Smarcel return (error); 16964921Smarcel 17064921Smarcel newsel.nfds = linux_args.nfds; 17164921Smarcel newsel.readfds = linux_args.readfds; 17264921Smarcel newsel.writefds = linux_args.writefds; 17364921Smarcel newsel.exceptfds = linux_args.exceptfds; 17464921Smarcel newsel.timeout = linux_args.timeout; 17564921Smarcel return (linux_newselect(p, &newsel)); 17664921Smarcel} 17764921Smarcel 17864921Smarcelint 17964921Smarcellinux_fork(struct proc *p, struct linux_fork_args *args) 18064921Smarcel{ 18164921Smarcel int error; 18264921Smarcel 18364921Smarcel#ifdef DEBUG 18464921Smarcel printf("Linux-emul(%ld): fork()\n", (long)p->p_pid); 18564921Smarcel#endif 18664921Smarcel 18764921Smarcel if ((error = fork(p, (struct fork_args *)args)) != 0) 18864921Smarcel return (error); 18964921Smarcel 19064921Smarcel if (p->p_retval[1] == 1) 19164921Smarcel p->p_retval[0] = 0; 19264921Smarcel return (0); 19364921Smarcel} 19464921Smarcel 19564921Smarcelint 19664921Smarcellinux_vfork(struct proc *p, struct linux_vfork_args *args) 19764921Smarcel{ 19864921Smarcel int error; 19964921Smarcel 20064921Smarcel#ifdef DEBUG 20164921Smarcel printf("Linux-emul(%ld): vfork()\n", (long)p->p_pid); 20264921Smarcel#endif 20364921Smarcel 20464921Smarcel if ((error = vfork(p, (struct vfork_args *)args)) != 0) 20564921Smarcel return (error); 20664921Smarcel /* Are we the child? */ 20764921Smarcel if (p->p_retval[1] == 1) 20864921Smarcel p->p_retval[0] = 0; 20964921Smarcel return (0); 21064921Smarcel} 21164921Smarcel 21264921Smarcel#define CLONE_VM 0x100 21364921Smarcel#define CLONE_FS 0x200 21464921Smarcel#define CLONE_FILES 0x400 21564921Smarcel#define CLONE_SIGHAND 0x800 21664921Smarcel#define CLONE_PID 0x1000 21764921Smarcel 21864921Smarcelint 21964921Smarcellinux_clone(struct proc *p, struct linux_clone_args *args) 22064921Smarcel{ 22164921Smarcel int error, ff = RFPROC; 22264921Smarcel struct proc *p2; 22364921Smarcel int exit_signal; 22464921Smarcel vm_offset_t start; 22564921Smarcel struct rfork_args rf_args; 22664921Smarcel 22764921Smarcel#ifdef DEBUG 22864921Smarcel if (args->flags & CLONE_PID) 22964921Smarcel printf("linux_clone(%ld): CLONE_PID not yet supported\n", 23064921Smarcel (long)p->p_pid); 23164921Smarcel printf("linux_clone(%ld): invoked with flags %x and stack %x\n", 23264921Smarcel (long)p->p_pid, (unsigned int)args->flags, 23364921Smarcel (unsigned int)args->stack); 23464921Smarcel#endif 23564921Smarcel 23664921Smarcel if (!args->stack) 23764921Smarcel return (EINVAL); 23864921Smarcel 23964921Smarcel exit_signal = args->flags & 0x000000ff; 24064921Smarcel if (exit_signal >= LINUX_NSIG) 24164921Smarcel return (EINVAL); 24264921Smarcel 24364921Smarcel if (exit_signal <= LINUX_SIGTBLSZ) 24464921Smarcel exit_signal = linux_to_bsd_signal[_SIG_IDX(exit_signal)]; 24564921Smarcel 24664921Smarcel /* RFTHREAD probably not necessary here, but it shouldn't hurt */ 24764921Smarcel ff |= RFTHREAD; 24864921Smarcel 24964921Smarcel if (args->flags & CLONE_VM) 25064921Smarcel ff |= RFMEM; 25164921Smarcel if (args->flags & CLONE_SIGHAND) 25264921Smarcel ff |= RFSIGSHARE; 25364921Smarcel if (!(args->flags & CLONE_FILES)) 25464921Smarcel ff |= RFFDG; 25564921Smarcel 25664921Smarcel error = 0; 25764921Smarcel start = 0; 25864921Smarcel 25964921Smarcel rf_args.flags = ff; 26064921Smarcel if ((error = rfork(p, &rf_args)) != 0) 26164921Smarcel return (error); 26264921Smarcel 26364921Smarcel p2 = pfind(p->p_retval[0]); 26464921Smarcel if (p2 == 0) 26564921Smarcel return (ESRCH); 26664921Smarcel 26764921Smarcel p2->p_sigparent = exit_signal; 26864921Smarcel p2->p_md.md_regs->tf_esp = (unsigned int)args->stack; 26964921Smarcel 27064921Smarcel#ifdef DEBUG 27164921Smarcel printf ("linux_clone(%ld): successful rfork to %ld\n", (long)p->p_pid, 27264921Smarcel (long)p2->p_pid); 27364921Smarcel#endif 27464921Smarcel 27564921Smarcel return (0); 27664921Smarcel} 27764921Smarcel 27864921Smarcel/* XXX move */ 27964921Smarcelstruct linux_mmap_argv { 28064921Smarcel linux_caddr_t addr; 28164921Smarcel int len; 28264921Smarcel int prot; 28364921Smarcel int flags; 28464921Smarcel int fd; 28564921Smarcel int pos; 28664921Smarcel}; 28764921Smarcel 28864921Smarcel#define STACK_SIZE (2 * 1024 * 1024) 28964921Smarcel#define GUARD_SIZE (4 * PAGE_SIZE) 29064921Smarcel 29164921Smarcelint 29264921Smarcellinux_mmap(struct proc *p, struct linux_mmap_args *args) 29364921Smarcel{ 29464921Smarcel struct mmap_args /* { 29564921Smarcel caddr_t addr; 29664921Smarcel size_t len; 29764921Smarcel int prot; 29864921Smarcel int flags; 29964921Smarcel int fd; 30064921Smarcel long pad; 30164921Smarcel off_t pos; 30264921Smarcel } */ bsd_args; 30364921Smarcel int error; 30464921Smarcel struct linux_mmap_argv linux_args; 30564921Smarcel 30664921Smarcel error = copyin(args->ptr, &linux_args, sizeof(linux_args)); 30764921Smarcel if (error) 30864921Smarcel return (error); 30964921Smarcel 31064921Smarcel#ifdef DEBUG 31164921Smarcel printf("Linux-emul(%ld): mmap(%p, %d, %d, 0x%08x, %d, %d)", 31264921Smarcel (long)p->p_pid, (void *)linux_args.addr, linux_args.len, 31364921Smarcel linux_args.prot, linux_args.flags, linux_args.fd, linux_args.pos); 31464921Smarcel#endif 31564921Smarcel 31664921Smarcel bsd_args.flags = 0; 31764921Smarcel if (linux_args.flags & LINUX_MAP_SHARED) 31864921Smarcel bsd_args.flags |= MAP_SHARED; 31964921Smarcel if (linux_args.flags & LINUX_MAP_PRIVATE) 32064921Smarcel bsd_args.flags |= MAP_PRIVATE; 32164921Smarcel if (linux_args.flags & LINUX_MAP_FIXED) 32264921Smarcel bsd_args.flags |= MAP_FIXED; 32364921Smarcel if (linux_args.flags & LINUX_MAP_ANON) 32464921Smarcel bsd_args.flags |= MAP_ANON; 32564921Smarcel if (linux_args.flags & LINUX_MAP_GROWSDOWN) { 32664921Smarcel bsd_args.flags |= MAP_STACK; 32764921Smarcel 32864921Smarcel /* The linux MAP_GROWSDOWN option does not limit auto 32964921Smarcel * growth of the region. Linux mmap with this option 33064921Smarcel * takes as addr the inital BOS, and as len, the initial 33164921Smarcel * region size. It can then grow down from addr without 33264921Smarcel * limit. However, linux threads has an implicit internal 33364921Smarcel * limit to stack size of STACK_SIZE. Its just not 33464921Smarcel * enforced explicitly in linux. But, here we impose 33564921Smarcel * a limit of (STACK_SIZE - GUARD_SIZE) on the stack 33664921Smarcel * region, since we can do this with our mmap. 33764921Smarcel * 33864921Smarcel * Our mmap with MAP_STACK takes addr as the maximum 33964921Smarcel * downsize limit on BOS, and as len the max size of 34064921Smarcel * the region. It them maps the top SGROWSIZ bytes, 34164921Smarcel * and autgrows the region down, up to the limit 34264921Smarcel * in addr. 34364921Smarcel * 34464921Smarcel * If we don't use the MAP_STACK option, the effect 34564921Smarcel * of this code is to allocate a stack region of a 34664921Smarcel * fixed size of (STACK_SIZE - GUARD_SIZE). 34764921Smarcel */ 34864921Smarcel 34964921Smarcel /* This gives us TOS */ 35064921Smarcel bsd_args.addr = linux_args.addr + linux_args.len; 35164921Smarcel 35267238Sgallatin if (bsd_args.addr > p->p_vmspace->vm_maxsaddr) { 35367238Sgallatin /* Some linux apps will attempt to mmap 35467238Sgallatin * thread stacks near the top of their 35567238Sgallatin * address space. If their TOS is greater 35667238Sgallatin * than vm_maxsaddr, vm_map_growstack() 35767238Sgallatin * will confuse the thread stack with the 35867238Sgallatin * process stack and deliver a SEGV if they 35967238Sgallatin * attempt to grow the thread stack past their 36067238Sgallatin * current stacksize rlimit. To avoid this, 36167238Sgallatin * adjust vm_maxsaddr upwards to reflect 36267238Sgallatin * the current stacksize rlimit rather 36367238Sgallatin * than the maximum possible stacksize. 36467238Sgallatin * It would be better to adjust the 36567238Sgallatin * mmap'ed region, but some apps do not check 36667238Sgallatin * mmap's return value. 36767238Sgallatin */ 36867238Sgallatin p->p_vmspace->vm_maxsaddr = (char *)USRSTACK - 36967238Sgallatin p->p_rlimit[RLIMIT_STACK].rlim_cur; 37067238Sgallatin } 37167238Sgallatin 37264921Smarcel /* This gives us our maximum stack size */ 37364921Smarcel if (linux_args.len > STACK_SIZE - GUARD_SIZE) 37464921Smarcel bsd_args.len = linux_args.len; 37564921Smarcel else 37664921Smarcel bsd_args.len = STACK_SIZE - GUARD_SIZE; 37764921Smarcel 37864921Smarcel /* This gives us a new BOS. If we're using VM_STACK, then 37964921Smarcel * mmap will just map the top SGROWSIZ bytes, and let 38064921Smarcel * the stack grow down to the limit at BOS. If we're 38164921Smarcel * not using VM_STACK we map the full stack, since we 38264921Smarcel * don't have a way to autogrow it. 38364921Smarcel */ 38464921Smarcel bsd_args.addr -= bsd_args.len; 38564921Smarcel } else { 38664921Smarcel bsd_args.addr = linux_args.addr; 38764921Smarcel bsd_args.len = linux_args.len; 38864921Smarcel } 38964921Smarcel 39064921Smarcel bsd_args.prot = linux_args.prot | PROT_READ; /* always required */ 39164921Smarcel if (linux_args.flags & LINUX_MAP_ANON) 39264921Smarcel bsd_args.fd = -1; 39364921Smarcel else 39464921Smarcel bsd_args.fd = linux_args.fd; 39564921Smarcel bsd_args.pos = linux_args.pos; 39664921Smarcel bsd_args.pad = 0; 39764921Smarcel 39864921Smarcel#ifdef DEBUG 39964921Smarcel printf("-> (%p, %d, %d, 0x%08x, %d, %d)\n", (void *)bsd_args.addr, 40064921Smarcel bsd_args.len, bsd_args.prot, bsd_args.flags, bsd_args.fd, 40164921Smarcel (int)bsd_args.pos); 40264921Smarcel#endif 40364921Smarcel 40464921Smarcel return (mmap(p, &bsd_args)); 40564921Smarcel} 40664921Smarcel 40764921Smarcelint 40864921Smarcellinux_pipe(struct proc *p, struct linux_pipe_args *args) 40964921Smarcel{ 41064921Smarcel int error; 41164921Smarcel int reg_edx; 41264921Smarcel 41364921Smarcel#ifdef DEBUG 41464921Smarcel printf("Linux-emul(%ld): pipe(*)\n", (long)p->p_pid); 41564921Smarcel#endif 41664921Smarcel 41764921Smarcel reg_edx = p->p_retval[1]; 41864921Smarcel error = pipe(p, 0); 41964921Smarcel if (error) { 42064921Smarcel p->p_retval[1] = reg_edx; 42164921Smarcel return (error); 42264921Smarcel } 42364921Smarcel 42464921Smarcel error = copyout(p->p_retval, args->pipefds, 2*sizeof(int)); 42564921Smarcel if (error) { 42664921Smarcel p->p_retval[1] = reg_edx; 42764921Smarcel return (error); 42864921Smarcel } 42964921Smarcel 43064921Smarcel p->p_retval[1] = reg_edx; 43164921Smarcel p->p_retval[0] = 0; 43264921Smarcel return (0); 43364921Smarcel} 43464921Smarcel 43564921Smarcelint 43664921Smarcellinux_ioperm(struct proc *p, struct linux_ioperm_args *args) 43764921Smarcel{ 43864921Smarcel struct sysarch_args sa; 43964921Smarcel struct i386_ioperm_args *iia; 44064921Smarcel caddr_t sg; 44164921Smarcel 44264921Smarcel sg = stackgap_init(); 44364921Smarcel iia = stackgap_alloc(&sg, sizeof(struct i386_ioperm_args)); 44464921Smarcel iia->start = args->start; 44564921Smarcel iia->length = args->length; 44664921Smarcel iia->enable = args->enable; 44764921Smarcel sa.op = I386_SET_IOPERM; 44864921Smarcel sa.parms = (char *)iia; 44964921Smarcel return (sysarch(p, &sa)); 45064921Smarcel} 45164921Smarcel 45264921Smarcelint 45364921Smarcellinux_iopl(struct proc *p, struct linux_iopl_args *args) 45464921Smarcel{ 45564921Smarcel int error; 45664921Smarcel 45764921Smarcel if (args->level < 0 || args->level > 3) 45864921Smarcel return (EINVAL); 45964921Smarcel if ((error = suser(p)) != 0) 46064921Smarcel return (error); 46164921Smarcel if (securelevel > 0) 46264921Smarcel return (EPERM); 46364921Smarcel p->p_md.md_regs->tf_eflags = (p->p_md.md_regs->tf_eflags & ~PSL_IOPL) | 46464921Smarcel (args->level * (PSL_IOPL / 3)); 46564921Smarcel return (0); 46664921Smarcel} 46764921Smarcel 46864921Smarcelint 46964921Smarcellinux_modify_ldt(p, uap) 47064921Smarcel struct proc *p; 47164921Smarcel struct linux_modify_ldt_args *uap; 47264921Smarcel{ 47364921Smarcel int error; 47464921Smarcel caddr_t sg; 47564921Smarcel struct sysarch_args args; 47664921Smarcel struct i386_ldt_args *ldt; 47764921Smarcel struct linux_descriptor ld; 47864921Smarcel union descriptor *desc; 47964921Smarcel 48064921Smarcel sg = stackgap_init(); 48164921Smarcel 48264921Smarcel if (uap->ptr == NULL) 48364921Smarcel return (EINVAL); 48464921Smarcel 48564921Smarcel switch (uap->func) { 48664921Smarcel case 0x00: /* read_ldt */ 48764921Smarcel ldt = stackgap_alloc(&sg, sizeof(*ldt)); 48864921Smarcel ldt->start = 0; 48964921Smarcel ldt->descs = uap->ptr; 49064921Smarcel ldt->num = uap->bytecount / sizeof(union descriptor); 49164921Smarcel args.op = I386_GET_LDT; 49264921Smarcel args.parms = (char*)ldt; 49364921Smarcel error = sysarch(p, &args); 49464921Smarcel p->p_retval[0] *= sizeof(union descriptor); 49564921Smarcel break; 49664921Smarcel case 0x01: /* write_ldt */ 49764921Smarcel case 0x11: /* write_ldt */ 49864921Smarcel if (uap->bytecount != sizeof(ld)) 49964921Smarcel return (EINVAL); 50064921Smarcel 50164921Smarcel error = copyin(uap->ptr, &ld, sizeof(ld)); 50264921Smarcel if (error) 50364921Smarcel return (error); 50464921Smarcel 50564921Smarcel ldt = stackgap_alloc(&sg, sizeof(*ldt)); 50664921Smarcel desc = stackgap_alloc(&sg, sizeof(*desc)); 50764921Smarcel ldt->start = ld.entry_number; 50864921Smarcel ldt->descs = desc; 50964921Smarcel ldt->num = 1; 51064921Smarcel desc->sd.sd_lolimit = (ld.limit & 0x0000ffff); 51164921Smarcel desc->sd.sd_hilimit = (ld.limit & 0x000f0000) >> 16; 51264921Smarcel desc->sd.sd_lobase = (ld.base_addr & 0x00ffffff); 51364921Smarcel desc->sd.sd_hibase = (ld.base_addr & 0xff000000) >> 24; 51464921Smarcel desc->sd.sd_type = SDT_MEMRO | ((ld.read_exec_only ^ 1) << 1) | 51564921Smarcel (ld.contents << 2); 51664921Smarcel desc->sd.sd_dpl = 3; 51764921Smarcel desc->sd.sd_p = (ld.seg_not_present ^ 1); 51864921Smarcel desc->sd.sd_xx = 0; 51964921Smarcel desc->sd.sd_def32 = ld.seg_32bit; 52064921Smarcel desc->sd.sd_gran = ld.limit_in_pages; 52164921Smarcel args.op = I386_SET_LDT; 52264921Smarcel args.parms = (char*)ldt; 52364921Smarcel error = sysarch(p, &args); 52464921Smarcel break; 52564921Smarcel default: 52664921Smarcel error = EINVAL; 52764921Smarcel break; 52864921Smarcel } 52964921Smarcel 53064921Smarcel if (error == EOPNOTSUPP) { 53164921Smarcel printf("linux: modify_ldt needs kernel option USER_LDT\n"); 53264921Smarcel error = ENOSYS; 53364921Smarcel } 53464921Smarcel 53564921Smarcel return (error); 53664921Smarcel} 53764921Smarcel 53864921Smarcelint 53964921Smarcellinux_sigaction(struct proc *p, struct linux_sigaction_args *args) 54064921Smarcel{ 54164921Smarcel linux_osigaction_t osa; 54264921Smarcel linux_sigaction_t act, oact; 54364921Smarcel int error; 54464921Smarcel 54564921Smarcel#ifdef DEBUG 54664921Smarcel printf("Linux-emul(%ld): sigaction(%d, %p, %p)\n", (long)p->p_pid, 54764921Smarcel args->sig, (void *)args->nsa, (void *)args->osa); 54864921Smarcel#endif 54964921Smarcel 55064921Smarcel if (args->nsa != NULL) { 55164921Smarcel error = copyin(args->nsa, &osa, sizeof(linux_osigaction_t)); 55264921Smarcel if (error) 55364921Smarcel return (error); 55464921Smarcel act.lsa_handler = osa.lsa_handler; 55564921Smarcel act.lsa_flags = osa.lsa_flags; 55664921Smarcel act.lsa_restorer = osa.lsa_restorer; 55764921Smarcel LINUX_SIGEMPTYSET(act.lsa_mask); 55864921Smarcel act.lsa_mask.__bits[0] = osa.lsa_mask; 55964921Smarcel } 56064921Smarcel 56164921Smarcel error = linux_do_sigaction(p, args->sig, args->nsa ? &act : NULL, 56264921Smarcel args->osa ? &oact : NULL); 56364921Smarcel 56464921Smarcel if (args->osa != NULL && !error) { 56564921Smarcel osa.lsa_handler = oact.lsa_handler; 56664921Smarcel osa.lsa_flags = oact.lsa_flags; 56764921Smarcel osa.lsa_restorer = oact.lsa_restorer; 56864921Smarcel osa.lsa_mask = oact.lsa_mask.__bits[0]; 56964921Smarcel error = copyout(&osa, args->osa, sizeof(linux_osigaction_t)); 57064921Smarcel } 57164921Smarcel 57264921Smarcel return (error); 57364921Smarcel} 57464921Smarcel 57564921Smarcel/* 57664921Smarcel * Linux has two extra args, restart and oldmask. We dont use these, 57764921Smarcel * but it seems that "restart" is actually a context pointer that 57864921Smarcel * enables the signal to happen with a different register set. 57964921Smarcel */ 58064921Smarcelint 58164921Smarcellinux_sigsuspend(struct proc *p, struct linux_sigsuspend_args *args) 58264921Smarcel{ 58364921Smarcel struct sigsuspend_args bsd; 58464921Smarcel sigset_t *sigmask; 58564921Smarcel linux_sigset_t mask; 58664921Smarcel caddr_t sg = stackgap_init(); 58764921Smarcel 58864921Smarcel#ifdef DEBUG 58964921Smarcel printf("Linux-emul(%ld): sigsuspend(%08lx)\n", 59064921Smarcel (long)p->p_pid, (unsigned long)args->mask); 59164921Smarcel#endif 59264921Smarcel 59364921Smarcel sigmask = stackgap_alloc(&sg, sizeof(sigset_t)); 59464921Smarcel LINUX_SIGEMPTYSET(mask); 59564921Smarcel mask.__bits[0] = args->mask; 59664921Smarcel linux_to_bsd_sigset(&mask, sigmask); 59764921Smarcel bsd.sigmask = sigmask; 59864921Smarcel return (sigsuspend(p, &bsd)); 59964921Smarcel} 60064921Smarcel 60164921Smarcelint 60264921Smarcellinux_rt_sigsuspend(p, uap) 60364921Smarcel struct proc *p; 60464921Smarcel struct linux_rt_sigsuspend_args *uap; 60564921Smarcel{ 60664921Smarcel linux_sigset_t lmask; 60764921Smarcel sigset_t *bmask; 60864921Smarcel struct sigsuspend_args bsd; 60964921Smarcel caddr_t sg = stackgap_init(); 61064921Smarcel int error; 61164921Smarcel 61264921Smarcel#ifdef DEBUG 61364921Smarcel printf("Linux-emul(%ld): rt_sigsuspend(%p, %d)\n", (long)p->p_pid, 61464921Smarcel (void *)uap->newset, uap->sigsetsize); 61564921Smarcel#endif 61664921Smarcel 61764921Smarcel if (uap->sigsetsize != sizeof(linux_sigset_t)) 61864921Smarcel return (EINVAL); 61964921Smarcel 62064921Smarcel error = copyin(uap->newset, &lmask, sizeof(linux_sigset_t)); 62164921Smarcel if (error) 62264921Smarcel return (error); 62364921Smarcel 62464921Smarcel bmask = stackgap_alloc(&sg, sizeof(sigset_t)); 62564921Smarcel linux_to_bsd_sigset(&lmask, bmask); 62664921Smarcel bsd.sigmask = bmask; 62764921Smarcel return (sigsuspend(p, &bsd)); 62864921Smarcel} 62964921Smarcel 63064921Smarcelint 63164921Smarcellinux_pause(struct proc *p, struct linux_pause_args *args) 63264921Smarcel{ 63364921Smarcel struct sigsuspend_args bsd; 63464921Smarcel sigset_t *sigmask; 63564921Smarcel caddr_t sg = stackgap_init(); 63664921Smarcel 63764921Smarcel#ifdef DEBUG 63864921Smarcel printf("Linux-emul(%d): pause()\n", p->p_pid); 63964921Smarcel#endif 64064921Smarcel 64164921Smarcel sigmask = stackgap_alloc(&sg, sizeof(sigset_t)); 64264921Smarcel *sigmask = p->p_sigmask; 64364921Smarcel bsd.sigmask = sigmask; 64464921Smarcel return (sigsuspend(p, &bsd)); 64564921Smarcel} 64664921Smarcel 64764921Smarcelint 64864921Smarcellinux_sigaltstack(p, uap) 64964921Smarcel struct proc *p; 65064921Smarcel struct linux_sigaltstack_args *uap; 65164921Smarcel{ 65264921Smarcel struct sigaltstack_args bsd; 65364921Smarcel stack_t *ss, *oss; 65464921Smarcel linux_stack_t lss; 65564921Smarcel int error; 65664921Smarcel caddr_t sg = stackgap_init(); 65764921Smarcel 65864921Smarcel#ifdef DEBUG 65964921Smarcel printf("Linux-emul(%ld): sigaltstack(%p, %p)\n", 66064921Smarcel (long)p->p_pid, uap->uss, uap->uoss); 66164921Smarcel#endif 66264921Smarcel 66367051Sgallatin if (uap->uss == NULL) { 66467051Sgallatin ss = NULL; 66567051Sgallatin } else { 66667051Sgallatin error = copyin(uap->uss, &lss, sizeof(linux_stack_t)); 66767051Sgallatin if (error) 66867051Sgallatin return (error); 66964921Smarcel 67067051Sgallatin ss = stackgap_alloc(&sg, sizeof(stack_t)); 67167051Sgallatin ss->ss_sp = lss.ss_sp; 67267051Sgallatin ss->ss_size = (lss.ss_size >= LINUX_MINSIGSTKSZ && 67367051Sgallatin lss.ss_size < MINSIGSTKSZ) ? MINSIGSTKSZ : lss.ss_size; 67467051Sgallatin ss->ss_flags = linux_to_bsd_sigaltstack(lss.ss_flags); 67567051Sgallatin } 67664921Smarcel oss = (uap->uoss != NULL) 67764921Smarcel ? stackgap_alloc(&sg, sizeof(stack_t)) 67864921Smarcel : NULL; 67964921Smarcel 68064921Smarcel bsd.ss = ss; 68164921Smarcel bsd.oss = oss; 68264921Smarcel error = sigaltstack(p, &bsd); 68364921Smarcel 68464921Smarcel if (!error && oss != NULL) { 68564921Smarcel lss.ss_sp = oss->ss_sp; 68664921Smarcel lss.ss_size = oss->ss_size; 68767051Sgallatin lss.ss_flags = bsd_to_linux_sigaltstack(oss->ss_flags); 68864921Smarcel error = copyout(&lss, uap->uoss, sizeof(linux_stack_t)); 68964921Smarcel } 69064921Smarcel 69164921Smarcel return (error); 69264921Smarcel} 693