diff options
| author | Julian Elischer <julian@FreeBSD.org> | 1998-12-19 02:55:34 +0000 | 
|---|---|---|
| committer | Julian Elischer <julian@FreeBSD.org> | 1998-12-19 02:55:34 +0000 | 
| commit | 6626c6045c38a22c2dc57621a840ae612da0e2e3 (patch) | |
| tree | b5baf90edc2cac8af964657b46d2d820dce40d35 /sys/compat/linux/linux_misc.c | |
| parent | 02489dd7373f6eb94fc23050f36acaaa2b71167e (diff) | |
Notes
Diffstat (limited to 'sys/compat/linux/linux_misc.c')
| -rw-r--r-- | sys/compat/linux/linux_misc.c | 174 | 
1 files changed, 173 insertions, 1 deletions
diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index 68fee0f657d6..4b441fd81370 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -25,7 +25,7 @@   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   * - *  $Id: linux_misc.c,v 1.46 1998/12/04 22:54:50 archie Exp $ + *  $Id: linux_misc.c,v 1.47 1998/12/10 13:47:18 jkh Exp $   */  #include <sys/param.h> @@ -41,6 +41,9 @@  #include <sys/resourcevar.h>  #include <sys/stat.h>  #include <sys/sysctl.h> +#ifdef COMPAT_LINUX_THREADS +#include <sys/unistd.h> +#endif /* COMPAT_LINUX_THREADS */  #include <sys/vnode.h>  #include <sys/wait.h>  #include <sys/time.h> @@ -560,6 +563,84 @@ linux_fork(struct proc *p, struct linux_fork_args *args)      return 0;  } +#ifndef COMPAT_LINUX_THREADS +int +linux_clone(struct proc *p, struct linux_clone_args *args) +{ +    printf("linux_clone(%d): Not enabled\n", p->p_pid); +    return (EOPNOTSUPP); +} + +#else +#define CLONE_VM	0x100 +#define CLONE_FS	0x200 +#define CLONE_FILES	0x400 +#define CLONE_SIGHAND	0x800 +#define CLONE_PID	0x1000 + +int +linux_clone(struct proc *p, struct linux_clone_args *args) +{ +    int error, ff = RFPROC; +    struct proc *p2; +    int            growable; +    int            initstacksize; +    int            maxstacksize; +    int            exit_signal; +    vm_map_entry_t entry; +    vm_map_t       map; +    vm_offset_t    start; +    struct rfork_args rf_args; + +#ifdef SMP +    printf("linux_clone(%d): does not work with SMP yet\n", p->p_pid); +    return (EOPNOTSUPP); +#endif +#ifdef DEBUG +    if (args->flags & CLONE_PID) +	printf("linux_clone(%d): CLONE_PID not yet supported\n", p->p_pid); +    printf ("linux_clone(%d): invoked with flags %x and stack %x\n", p->p_pid, +	     (unsigned int)args->flags, (unsigned int)args->stack); +#endif + +    if (!args->stack) +        return (EINVAL); +    exit_signal = args->flags & 0x000000ff; +    if (exit_signal >= LINUX_NSIG) +	return EINVAL; +    exit_signal = linux_to_bsd_signal[exit_signal]; + +    /* RFTHREAD probably not necessary here, but it shouldn't hurt either */ +    ff |= RFTHREAD; + +    if (args->flags & CLONE_VM) +	ff |= RFMEM; +    if (args->flags & CLONE_SIGHAND) +	ff |= RFSIGSHARE; +    if (!(args->flags & CLONE_FILES)) +	ff |= RFFDG; + +    error = 0; +    start = 0; + +    rf_args.flags = ff; +    if (error = rfork(p, &rf_args)) +	return error; + +    p2 = pfind(p->p_retval[0]); +    if (p2 == 0) + 	return ESRCH; +     +    p2->p_sigparent = exit_signal; +    p2->p_md.md_regs->tf_esp = (unsigned int)args->stack; + +#ifdef DEBUG +    printf ("linux_clone(%d): successful rfork to %d\n", p->p_pid, p2->p_pid); +#endif +    return 0; +} + +#endif /* COMPAT_LINUX_THREADS */  /* XXX move */  struct linux_mmap_argv {  	linux_caddr_t addr; @@ -570,6 +651,11 @@ struct linux_mmap_argv {  	int pos;  }; +#ifdef COMPAT_LINUX_THREADS +#define STACK_SIZE  (2 * 1024 * 1024) +#define GUARD_SIZE  (4 * PAGE_SIZE) + +#endif /* COMPAT_LINUX_THREADS */  int  linux_mmap(struct proc *p, struct linux_mmap_args *args)  { @@ -602,8 +688,70 @@ linux_mmap(struct proc *p, struct linux_mmap_args *args)  	bsd_args.flags |= MAP_FIXED;      if (linux_args.flags & LINUX_MAP_ANON)  	bsd_args.flags |= MAP_ANON; +#ifndef COMPAT_LINUX_THREADS      bsd_args.addr = linux_args.addr;      bsd_args.len = linux_args.len; +#else + +#if !defined(USE_VM_STACK) && !defined(USE_VM_STACK_FOR_EXEC) +    /* Linux Threads will map into the proc stack space, unless +       we prevent it.  This causes problems if we're not using +       our VM_STACK options. +    */ +    if ((unsigned int)linux_args.addr + linux_args.len > (USRSTACK - MAXSSIZ)) +        return (EINVAL); +#endif + +    if (linux_args.flags & LINUX_MAP_GROWSDOWN) { + +#ifdef USE_VM_STACK +        /* USE_VM_STACK is defined (or not) in vm/vm_map.h */ +        bsd_args.flags |= MAP_STACK;       +#endif + +	/* The linux MAP_GROWSDOWN option does not limit auto +	   growth of the region.  Linux mmap with this option +	   takes as addr the inital BOS, and as len, the initial +	   region size.  It can then grow down from addr without +	   limit.  However, linux threads has an implicit internal +	   limit to stack size of STACK_SIZE.  Its just not +	   enforced explicitly in linux.  But, here we impose +	   a limit of (STACK_SIZE - GUARD_SIZE) on the stack +	   region, since we can do this with our mmap. + +	   Our mmap with MAP_STACK takes addr as the maximum +	   downsize limit on BOS, and as len the max size of +	   the region.  It them maps the top SGROWSIZ bytes, +	   and autgrows the region down, up to the limit +	   in addr. + +	   If we don't use the MAP_STACK option, the effect +	   of this code is to allocate a stack region of a +	   fixed size of (STACK_SIZE - GUARD_SIZE). +	*/ + +	/* This gives us TOS */ +        bsd_args.addr = linux_args.addr + linux_args.len; + +	/* This gives us our maximum stack size */ +	if (linux_args.len > STACK_SIZE - GUARD_SIZE) +	    bsd_args.len = linux_args.len; +	else +	    bsd_args.len  = STACK_SIZE - GUARD_SIZE; + +	/* This gives us a new BOS.  If we're using VM_STACK, then +	   mmap will just map the top SGROWSIZ bytes, and let +	   the stack grow down to the limit at BOS.  If we're +	   not using VM_STACK we map the full stack, since we +	   don't have a way to autogrow it. +	*/ +	bsd_args.addr -= bsd_args.len; + +    } else { +        bsd_args.addr = linux_args.addr; +	bsd_args.len  = linux_args.len; +    } +#endif /* COMPAT_LINUX_THREADS */      bsd_args.prot = linux_args.prot | PROT_READ;	/* always required */      bsd_args.fd = linux_args.fd;      bsd_args.pos = linux_args.pos; @@ -830,11 +978,25 @@ linux_waitpid(struct proc *p, struct linux_waitpid_args *args)  #endif      tmp.pid = args->pid;      tmp.status = args->status; +#ifndef COMPAT_LINUX_THREADS      tmp.options = args->options; +#else +    /* This filters out the linux option _WCLONE.  I don't +       think we need it, but I could be wrong.  If we need +       it, we need to fix wait4, since it will give us an +       error return of EINVAL if we pass in _WCLONE, and +       of course, it won't do anything with it. +    */ +    tmp.options = (args->options & (WNOHANG | WUNTRACED)); +#endif /* COMPAT_LINUX_THREADS */      tmp.rusage = NULL;      if (error = wait4(p, &tmp)) +#ifndef COMPAT_LINUX_THREADS  	return error; +#else +  	return error; +#endif /* COMPAT_LINUX_THREADS */      if (args->status) {  	if (error = copyin(args->status, &tmpstat, sizeof(int)))  	    return error; @@ -867,7 +1029,17 @@ linux_wait4(struct proc *p, struct linux_wait4_args *args)  #endif      tmp.pid = args->pid;      tmp.status = args->status; +#ifndef COMPAT_LINUX_THREADS      tmp.options = args->options; +#else +    /* This filters out the linux option _WCLONE.  I don't +       think we need it, but I could be wrong.  If we need +       it, we need to fix wait4, since it will give us an +       error return of EINVAL if we pass in _WCLONE, and +       of course, it won't do anything with it. +    */ +    tmp.options = (args->options & (WNOHANG | WUNTRACED)); +#endif /* COMPAT_LINUX_THREADS */      tmp.rusage = args->rusage;      if (error = wait4(p, &tmp))  | 
