linux_machdep.c revision 73856
1139749Simp/*-
253855Simp * Copyright (c) 2000 Marcel Moolenaar
353855Simp * All rights reserved.
453855Simp *
553855Simp * Redistribution and use in source and binary forms, with or without
653855Simp * modification, are permitted provided that the following conditions
753855Simp * are met:
853855Simp * 1. Redistributions of source code must retain the above copyright
953855Simp *    notice, this list of conditions and the following disclaimer
1053855Simp *    in this position and unchanged.
1153855Simp * 2. Redistributions in binary form must reproduce the above copyright
1253855Simp *    notice, this list of conditions and the following disclaimer in the
1353855Simp *    documentation and/or other materials provided with the distribution.
1453855Simp * 3. The name of the author may not be used to endorse or promote products
1553855Simp *    derived from this software without specific prior written permission.
1653855Simp *
1753855Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1853855Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1953855Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2053855Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2153855Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2253855Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2353855Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2453855Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2553855Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2653855Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2753855Simp *
2853855Simp * $FreeBSD: head/sys/i386/linux/linux_machdep.c 73856 2001-03-06 02:59:46Z jhb $
2959272Simp */
30129798Simp
3197613Stakawata#include <sys/param.h>
3259272Simp#include <sys/mman.h>
3353855Simp#include <sys/proc.h>
3453855Simp#include <sys/sysproto.h>
3574636Simp#include <sys/systm.h>
3674636Simp#include <sys/unistd.h>
3774636Simp#include <sys/resource.h>
3853855Simp#include <sys/resourcevar.h>
3953855Simp
4053855Simp#include <machine/frame.h>
4153855Simp#include <machine/psl.h>
4253855Simp#include <machine/segments.h>
4353855Simp#include <machine/sysarch.h>
4453855Simp
4553855Simp#include <vm/vm.h>
4653855Simp#include <sys/lock.h>
4759193Simp#include <vm/pmap.h>
4853855Simp#include <vm/vm_map.h>
4953855Simp
5059193Simp#include <i386/linux/linux.h>
5158581Simp#include <i386/linux/linux_proto.h>
5259193Simp#include <compat/linux/linux_ipc.h>
5353855Simp#include <compat/linux/linux_signal.h>
5453855Simp#include <compat/linux/linux_util.h>
5559193Simp
5653855Simpstruct linux_descriptor {
5753855Simp	unsigned int  entry_number;
5859193Simp	unsigned long base_addr;
5953855Simp	unsigned int  limit;
6059193Simp	unsigned int  seg_32bit:1;
6153855Simp	unsigned int  contents:2;
6259193Simp	unsigned int  read_exec_only:1;
6361779Simp	unsigned int  limit_in_pages:1;
6461779Simp	unsigned int  seg_not_present:1;
6561779Simp	unsigned int  useable:1;
6661779Simp};
6759193Simp
6859193Simpstruct linux_select_argv {
6959193Simp	int nfds;
7082376Sjon	fd_set *readfds;
71140692Simp	fd_set *writefds;
72140692Simp	fd_set *exceptfds;
7359193Simp	struct timeval *timeout;
7459193Simp};
7564544Simp
7664544Simpint
7764544Simplinux_to_bsd_sigaltstack(int lsa)
7882376Sjon{
79140692Simp	int bsa = 0;
8064544Simp
8164544Simp	if (lsa & LINUX_SS_DISABLE)
8261779Simp		bsa |= SS_DISABLE;
8361779Simp	if (lsa & LINUX_SS_ONSTACK)
8461779Simp		bsa |= SS_ONSTACK;
8559193Simp	return (bsa);
8659193Simp}
8759193Simp
8859193Simpint
8961779Simpbsd_to_linux_sigaltstack(int bsa)
9061779Simp{
9161779Simp	int lsa = 0;
9259193Simp
9359193Simp	if (bsa & SS_DISABLE)
9459193Simp		lsa |= LINUX_SS_DISABLE;
9559193Simp	if (bsa & SS_ONSTACK)
9661779Simp		lsa |= LINUX_SS_ONSTACK;
9766058Simp	return (lsa);
9866058Simp}
9966058Simp
10066058Simpint
10166058Simplinux_execve(struct proc *p, struct linux_execve_args *args)
10266058Simp{
10366058Simp	struct execve_args bsd;
10466058Simp	caddr_t sg;
10566058Simp
10666058Simp	sg = stackgap_init();
10766058Simp	CHECKALTEXIST(p, &sg, args->path);
10866058Simp
10966058Simp#ifdef DEBUG
11066058Simp	if (ldebug(execve))
11166058Simp		printf(ARGS(execve, "%s"), args->path);
11266058Simp#endif
11366058Simp
11466058Simp	bsd.fname = args->path;
11566058Simp	bsd.argv = args->argp;
11666058Simp	bsd.envv = args->envp;
11766058Simp	return (execve(p, &bsd));
11866058Simp}
11974636Simp
12074636Simpint
12174636Simplinux_ipc(struct proc *p, struct linux_ipc_args *args)
12274636Simp{
12366058Simp	switch (args->what) {
12466058Simp	case LINUX_SEMOP:
12566058Simp		return (linux_semop(p, args));
12666058Simp	case LINUX_SEMGET:
12766058Simp		return (linux_semget(p, args));
12866058Simp	case LINUX_SEMCTL:
12966058Simp		return (linux_semctl(p, args));
13066058Simp	case LINUX_MSGSND:
13174636Simp		return (linux_msgsnd(p, args));
13274636Simp	case LINUX_MSGRCV:
13374636Simp		return (linux_msgrcv(p, args));
13474636Simp	case LINUX_MSGGET:
13574636Simp		return (linux_msgget(p, args));
13674636Simp	case LINUX_MSGCTL:
13774636Simp		return (linux_msgctl(p, args));
13874636Simp	case LINUX_SHMAT:
13974636Simp		return (linux_shmat(p, args));
14074636Simp	case LINUX_SHMDT:
14174636Simp		return (linux_shmdt(p, args));
14274636Simp	case LINUX_SHMGET:
14374636Simp		return (linux_shmget(p, args));
14474636Simp	case LINUX_SHMCTL:
14574636Simp		return (linux_shmctl(p, args));
146100218Simp	}
14774636Simp
14874636Simp	uprintf("LINUX: 'ipc' typ=%d not implemented\n", args->what);
14974636Simp	return (ENOSYS);
15074636Simp}
15174636Simp
15274636Simpint
153100218Simplinux_select(struct proc *p, struct linux_select_args *args)
154100218Simp{
155100218Simp	struct linux_select_argv linux_args;
15697613Stakawata	struct linux_newselect_args newsel;
15797613Stakawata	int error;
15897613Stakawata
15997613Stakawata#ifdef SELECT_DEBUG
16097613Stakawata	if (ldebug(select))
16197613Stakawata		printf(ARGS(select, "%x"), args->ptr);
16297613Stakawata#endif
163100218Simp
16466058Simp	error = copyin(args->ptr, &linux_args, sizeof(linux_args));
16566058Simp	if (error)
16666058Simp		return (error);
16766058Simp
16866058Simp	newsel.nfds = linux_args.nfds;
16966058Simp	newsel.readfds = linux_args.readfds;
17066058Simp	newsel.writefds = linux_args.writefds;
17166058Simp	newsel.exceptfds = linux_args.exceptfds;
172147711Simp	newsel.timeout = linux_args.timeout;
173147711Simp	return (linux_newselect(p, &newsel));
174147711Simp}
175147711Simp
176147711Simpint
177147711Simplinux_fork(struct proc *p, struct linux_fork_args *args)
178147711Simp{
179147711Simp	int error;
180147711Simp
181#ifdef DEBUG
182	if (ldebug(fork))
183		printf(ARGS(fork, ""));
184#endif
185
186	if ((error = fork(p, (struct fork_args *)args)) != 0)
187		return (error);
188
189	if (p->p_retval[1] == 1)
190		p->p_retval[0] = 0;
191	return (0);
192}
193
194int
195linux_vfork(struct proc *p, struct linux_vfork_args *args)
196{
197	int error;
198
199#ifdef DEBUG
200	if (ldebug(vfork))
201		printf(ARGS(vfork, ""));
202#endif
203
204	if ((error = vfork(p, (struct vfork_args *)args)) != 0)
205		return (error);
206	/* Are we the child? */
207	if (p->p_retval[1] == 1)
208		p->p_retval[0] = 0;
209	return (0);
210}
211
212#define CLONE_VM	0x100
213#define CLONE_FS	0x200
214#define CLONE_FILES	0x400
215#define CLONE_SIGHAND	0x800
216#define CLONE_PID	0x1000
217
218int
219linux_clone(struct proc *p, struct linux_clone_args *args)
220{
221	int error, ff = RFPROC | RFSTOPPED;
222	struct proc *p2;
223	int exit_signal;
224	vm_offset_t start;
225	struct rfork_args rf_args;
226
227#ifdef DEBUG
228	if (ldebug(clone)) {
229		printf(ARGS(clone, "flags %x, stack %x"),
230		    (unsigned int)args->flags, (unsigned int)args->stack);
231		if (args->flags & CLONE_PID)
232			printf(LMSG("CLONE_PID not yet supported"));
233	}
234#endif
235
236	if (!args->stack)
237		return (EINVAL);
238
239	exit_signal = args->flags & 0x000000ff;
240	if (exit_signal >= LINUX_NSIG)
241		return (EINVAL);
242
243	if (exit_signal <= LINUX_SIGTBLSZ)
244		exit_signal = linux_to_bsd_signal[_SIG_IDX(exit_signal)];
245
246	/* RFTHREAD probably not necessary here, but it shouldn't hurt */
247	ff |= RFTHREAD;
248
249	if (args->flags & CLONE_VM)
250		ff |= RFMEM;
251	if (args->flags & CLONE_SIGHAND)
252		ff |= RFSIGSHARE;
253	if (!(args->flags & CLONE_FILES))
254		ff |= RFFDG;
255
256	error = 0;
257	start = 0;
258
259	rf_args.flags = ff;
260	if ((error = rfork(p, &rf_args)) != 0)
261		return (error);
262
263	p2 = pfind(p->p_retval[0]);
264	if (p2 == NULL)
265		return (ESRCH);
266
267	PROC_LOCK(p2);
268	p2->p_sigparent = exit_signal;
269	PROC_UNLOCK(p2);
270	p2->p_md.md_regs->tf_esp = (unsigned int)args->stack;
271
272#ifdef DEBUG
273	if (ldebug(clone))
274		printf(LMSG("clone: successful rfork to %ld"),
275		    (long)p2->p_pid);
276#endif
277
278	/*
279	 * Make this runnable after we are finished with it.
280	 */
281	mtx_lock_spin(&sched_lock);
282	p2->p_stat = SRUN;
283	setrunqueue(p2);
284	mtx_unlock_spin(&sched_lock);
285
286	return (0);
287}
288
289/* XXX move */
290struct linux_mmap_argv {
291	linux_caddr_t addr;
292	int len;
293	int prot;
294	int flags;
295	int fd;
296	int pos;
297};
298
299#define STACK_SIZE  (2 * 1024 * 1024)
300#define GUARD_SIZE  (4 * PAGE_SIZE)
301
302int
303linux_mmap(struct proc *p, struct linux_mmap_args *args)
304{
305	struct mmap_args /* {
306		caddr_t addr;
307		size_t len;
308		int prot;
309		int flags;
310		int fd;
311		long pad;
312		off_t pos;
313	} */ bsd_args;
314	int error;
315	struct linux_mmap_argv linux_args;
316
317	error = copyin(args->ptr, &linux_args, sizeof(linux_args));
318	if (error)
319		return (error);
320
321#ifdef DEBUG
322	if (ldebug(mmap))
323		printf(ARGS(mmap, "%p, %d, %d, 0x%08x, %d, %d"),
324		    (void *)linux_args.addr, linux_args.len, linux_args.prot,
325		    linux_args.flags, linux_args.fd, linux_args.pos);
326#endif
327
328	bsd_args.flags = 0;
329	if (linux_args.flags & LINUX_MAP_SHARED)
330		bsd_args.flags |= MAP_SHARED;
331	if (linux_args.flags & LINUX_MAP_PRIVATE)
332		bsd_args.flags |= MAP_PRIVATE;
333	if (linux_args.flags & LINUX_MAP_FIXED)
334		bsd_args.flags |= MAP_FIXED;
335	if (linux_args.flags & LINUX_MAP_ANON)
336		bsd_args.flags |= MAP_ANON;
337	else
338		bsd_args.flags |= MAP_NOSYNC;
339	if (linux_args.flags & LINUX_MAP_GROWSDOWN) {
340		bsd_args.flags |= MAP_STACK;
341
342		/* The linux MAP_GROWSDOWN option does not limit auto
343		 * growth of the region.  Linux mmap with this option
344		 * takes as addr the inital BOS, and as len, the initial
345		 * region size.  It can then grow down from addr without
346		 * limit.  However, linux threads has an implicit internal
347		 * limit to stack size of STACK_SIZE.  Its just not
348		 * enforced explicitly in linux.  But, here we impose
349		 * a limit of (STACK_SIZE - GUARD_SIZE) on the stack
350		 * region, since we can do this with our mmap.
351		 *
352		 * Our mmap with MAP_STACK takes addr as the maximum
353		 * downsize limit on BOS, and as len the max size of
354		 * the region.  It them maps the top SGROWSIZ bytes,
355		 * and autgrows the region down, up to the limit
356		 * in addr.
357		 *
358		 * If we don't use the MAP_STACK option, the effect
359		 * of this code is to allocate a stack region of a
360		 * fixed size of (STACK_SIZE - GUARD_SIZE).
361		 */
362
363		/* This gives us TOS */
364		bsd_args.addr = linux_args.addr + linux_args.len;
365
366		if (bsd_args.addr > p->p_vmspace->vm_maxsaddr) {
367			/* Some linux apps will attempt to mmap
368			 * thread stacks near the top of their
369			 * address space.  If their TOS is greater
370			 * than vm_maxsaddr, vm_map_growstack()
371			 * will confuse the thread stack with the
372			 * process stack and deliver a SEGV if they
373			 * attempt to grow the thread stack past their
374			 * current stacksize rlimit.  To avoid this,
375			 * adjust vm_maxsaddr upwards to reflect
376			 * the current stacksize rlimit rather
377			 * than the maximum possible stacksize.
378			 * It would be better to adjust the
379			 * mmap'ed region, but some apps do not check
380			 * mmap's return value.
381			 */
382			mtx_assert(&Giant, MA_OWNED);
383			p->p_vmspace->vm_maxsaddr = (char *)USRSTACK -
384			    p->p_rlimit[RLIMIT_STACK].rlim_cur;
385		}
386
387		/* This gives us our maximum stack size */
388		if (linux_args.len > STACK_SIZE - GUARD_SIZE)
389			bsd_args.len = linux_args.len;
390		else
391			bsd_args.len  = STACK_SIZE - GUARD_SIZE;
392
393		/* This gives us a new BOS.  If we're using VM_STACK, then
394		 * mmap will just map the top SGROWSIZ bytes, and let
395		 * the stack grow down to the limit at BOS.  If we're
396		 * not using VM_STACK we map the full stack, since we
397		 * don't have a way to autogrow it.
398		 */
399		bsd_args.addr -= bsd_args.len;
400	} else {
401		bsd_args.addr = linux_args.addr;
402		bsd_args.len  = linux_args.len;
403	}
404
405	bsd_args.prot = linux_args.prot | PROT_READ;	/* always required */
406	if (linux_args.flags & LINUX_MAP_ANON)
407		bsd_args.fd = -1;
408	else
409		bsd_args.fd = linux_args.fd;
410	bsd_args.pos = linux_args.pos;
411	bsd_args.pad = 0;
412
413#ifdef DEBUG
414	if (ldebug(mmap))
415		printf("-> (%p, %d, %d, 0x%08x, %d, %d)\n",
416		    (void *)bsd_args.addr, bsd_args.len, bsd_args.prot,
417		    bsd_args.flags, bsd_args.fd, (int)bsd_args.pos);
418#endif
419
420	return (mmap(p, &bsd_args));
421}
422
423int
424linux_pipe(struct proc *p, struct linux_pipe_args *args)
425{
426	int error;
427	int reg_edx;
428
429#ifdef DEBUG
430	if (ldebug(pipe))
431		printf(ARGS(pipe, "*"));
432#endif
433
434	reg_edx = p->p_retval[1];
435	error = pipe(p, 0);
436	if (error) {
437		p->p_retval[1] = reg_edx;
438		return (error);
439	}
440
441	error = copyout(p->p_retval, args->pipefds, 2*sizeof(int));
442	if (error) {
443		p->p_retval[1] = reg_edx;
444		return (error);
445	}
446
447	p->p_retval[1] = reg_edx;
448	p->p_retval[0] = 0;
449	return (0);
450}
451
452int
453linux_ioperm(struct proc *p, struct linux_ioperm_args *args)
454{
455	struct sysarch_args sa;
456	struct i386_ioperm_args *iia;
457	caddr_t sg;
458
459	sg = stackgap_init();
460	iia = stackgap_alloc(&sg, sizeof(struct i386_ioperm_args));
461	iia->start = args->start;
462	iia->length = args->length;
463	iia->enable = args->enable;
464	sa.op = I386_SET_IOPERM;
465	sa.parms = (char *)iia;
466	return (sysarch(p, &sa));
467}
468
469int
470linux_iopl(struct proc *p, struct linux_iopl_args *args)
471{
472	int error;
473
474	if (args->level < 0 || args->level > 3)
475		return (EINVAL);
476	if ((error = suser(p)) != 0)
477		return (error);
478	if (securelevel > 0)
479		return (EPERM);
480	p->p_md.md_regs->tf_eflags = (p->p_md.md_regs->tf_eflags & ~PSL_IOPL) |
481	    (args->level * (PSL_IOPL / 3));
482	return (0);
483}
484
485int
486linux_modify_ldt(p, uap)
487	struct proc *p;
488	struct linux_modify_ldt_args *uap;
489{
490	int error;
491	caddr_t sg;
492	struct sysarch_args args;
493	struct i386_ldt_args *ldt;
494	struct linux_descriptor ld;
495	union descriptor *desc;
496
497	sg = stackgap_init();
498
499	if (uap->ptr == NULL)
500		return (EINVAL);
501
502	switch (uap->func) {
503	case 0x00: /* read_ldt */
504		ldt = stackgap_alloc(&sg, sizeof(*ldt));
505		ldt->start = 0;
506		ldt->descs = uap->ptr;
507		ldt->num = uap->bytecount / sizeof(union descriptor);
508		args.op = I386_GET_LDT;
509		args.parms = (char*)ldt;
510		error = sysarch(p, &args);
511		p->p_retval[0] *= sizeof(union descriptor);
512		break;
513	case 0x01: /* write_ldt */
514	case 0x11: /* write_ldt */
515		if (uap->bytecount != sizeof(ld))
516			return (EINVAL);
517
518		error = copyin(uap->ptr, &ld, sizeof(ld));
519		if (error)
520			return (error);
521
522		ldt = stackgap_alloc(&sg, sizeof(*ldt));
523		desc = stackgap_alloc(&sg, sizeof(*desc));
524		ldt->start = ld.entry_number;
525		ldt->descs = desc;
526		ldt->num = 1;
527		desc->sd.sd_lolimit = (ld.limit & 0x0000ffff);
528		desc->sd.sd_hilimit = (ld.limit & 0x000f0000) >> 16;
529		desc->sd.sd_lobase = (ld.base_addr & 0x00ffffff);
530		desc->sd.sd_hibase = (ld.base_addr & 0xff000000) >> 24;
531		desc->sd.sd_type = SDT_MEMRO | ((ld.read_exec_only ^ 1) << 1) |
532			(ld.contents << 2);
533		desc->sd.sd_dpl = 3;
534		desc->sd.sd_p = (ld.seg_not_present ^ 1);
535		desc->sd.sd_xx = 0;
536		desc->sd.sd_def32 = ld.seg_32bit;
537		desc->sd.sd_gran = ld.limit_in_pages;
538		args.op = I386_SET_LDT;
539		args.parms = (char*)ldt;
540		error = sysarch(p, &args);
541		break;
542	default:
543		error = EINVAL;
544		break;
545	}
546
547	if (error == EOPNOTSUPP) {
548		printf("linux: modify_ldt needs kernel option USER_LDT\n");
549		error = ENOSYS;
550	}
551
552	return (error);
553}
554
555int
556linux_sigaction(struct proc *p, struct linux_sigaction_args *args)
557{
558	linux_osigaction_t osa;
559	linux_sigaction_t act, oact;
560	int error;
561
562#ifdef DEBUG
563	if (ldebug(sigaction))
564		printf(ARGS(sigaction, "%d, %p, %p"),
565		    args->sig, (void *)args->nsa, (void *)args->osa);
566#endif
567
568	if (args->nsa != NULL) {
569		error = copyin(args->nsa, &osa, sizeof(linux_osigaction_t));
570		if (error)
571			return (error);
572		act.lsa_handler = osa.lsa_handler;
573		act.lsa_flags = osa.lsa_flags;
574		act.lsa_restorer = osa.lsa_restorer;
575		LINUX_SIGEMPTYSET(act.lsa_mask);
576		act.lsa_mask.__bits[0] = osa.lsa_mask;
577	}
578
579	error = linux_do_sigaction(p, args->sig, args->nsa ? &act : NULL,
580	    args->osa ? &oact : NULL);
581
582	if (args->osa != NULL && !error) {
583		osa.lsa_handler = oact.lsa_handler;
584		osa.lsa_flags = oact.lsa_flags;
585		osa.lsa_restorer = oact.lsa_restorer;
586		osa.lsa_mask = oact.lsa_mask.__bits[0];
587		error = copyout(&osa, args->osa, sizeof(linux_osigaction_t));
588	}
589
590	return (error);
591}
592
593/*
594 * Linux has two extra args, restart and oldmask.  We dont use these,
595 * but it seems that "restart" is actually a context pointer that
596 * enables the signal to happen with a different register set.
597 */
598int
599linux_sigsuspend(struct proc *p, struct linux_sigsuspend_args *args)
600{
601	struct sigsuspend_args bsd;
602	sigset_t *sigmask;
603	linux_sigset_t mask;
604	caddr_t sg = stackgap_init();
605
606#ifdef DEBUG
607	if (ldebug(sigsuspend))
608		printf(ARGS(sigsuspend, "%08lx"), (unsigned long)args->mask);
609#endif
610
611	sigmask = stackgap_alloc(&sg, sizeof(sigset_t));
612	LINUX_SIGEMPTYSET(mask);
613	mask.__bits[0] = args->mask;
614	linux_to_bsd_sigset(&mask, sigmask);
615	bsd.sigmask = sigmask;
616	return (sigsuspend(p, &bsd));
617}
618
619int
620linux_rt_sigsuspend(p, uap)
621	struct proc *p;
622	struct linux_rt_sigsuspend_args *uap;
623{
624	linux_sigset_t lmask;
625	sigset_t *bmask;
626	struct sigsuspend_args bsd;
627	caddr_t sg = stackgap_init();
628	int error;
629
630#ifdef DEBUG
631	if (ldebug(rt_sigsuspend))
632		printf(ARGS(rt_sigsuspend, "%p, %d"),
633		    (void *)uap->newset, uap->sigsetsize);
634#endif
635
636	if (uap->sigsetsize != sizeof(linux_sigset_t))
637		return (EINVAL);
638
639	error = copyin(uap->newset, &lmask, sizeof(linux_sigset_t));
640	if (error)
641		return (error);
642
643	bmask = stackgap_alloc(&sg, sizeof(sigset_t));
644	linux_to_bsd_sigset(&lmask, bmask);
645	bsd.sigmask = bmask;
646	return (sigsuspend(p, &bsd));
647}
648
649int
650linux_pause(struct proc *p, struct linux_pause_args *args)
651{
652	struct sigsuspend_args bsd;
653	sigset_t *sigmask;
654	caddr_t sg = stackgap_init();
655
656#ifdef DEBUG
657	if (ldebug(pause))
658		printf(ARGS(pause, ""));
659#endif
660
661	sigmask = stackgap_alloc(&sg, sizeof(sigset_t));
662	PROC_LOCK(p);
663	*sigmask = p->p_sigmask;
664	PROC_UNLOCK(p);
665	bsd.sigmask = sigmask;
666	return (sigsuspend(p, &bsd));
667}
668
669int
670linux_sigaltstack(p, uap)
671	struct proc *p;
672	struct linux_sigaltstack_args *uap;
673{
674	struct sigaltstack_args bsd;
675	stack_t *ss, *oss;
676	linux_stack_t lss;
677	int error;
678	caddr_t sg = stackgap_init();
679
680#ifdef DEBUG
681	if (ldebug(sigaltstack))
682		printf(ARGS(sigaltstack, "%p, %p"), uap->uss, uap->uoss);
683#endif
684
685	if (uap->uss == NULL) {
686		ss = NULL;
687	} else {
688		error = copyin(uap->uss, &lss, sizeof(linux_stack_t));
689		if (error)
690			return (error);
691
692		ss = stackgap_alloc(&sg, sizeof(stack_t));
693		ss->ss_sp = lss.ss_sp;
694		ss->ss_size = lss.ss_size;
695		ss->ss_flags = linux_to_bsd_sigaltstack(lss.ss_flags);
696	}
697	oss = (uap->uoss != NULL)
698	    ? stackgap_alloc(&sg, sizeof(stack_t))
699	    : NULL;
700
701	bsd.ss = ss;
702	bsd.oss = oss;
703	error = sigaltstack(p, &bsd);
704
705	if (!error && oss != NULL) {
706		lss.ss_sp = oss->ss_sp;
707		lss.ss_size = oss->ss_size;
708		lss.ss_flags = bsd_to_linux_sigaltstack(oss->ss_flags);
709		error = copyout(&lss, uap->uoss, sizeof(linux_stack_t));
710	}
711
712	return (error);
713}
714