linux_machdep.c revision 99072
1/*-
2 * Copyright (c) 2000 Marcel Moolenaar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer
10 *    in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * $FreeBSD: head/sys/i386/linux/linux_machdep.c 99072 2002-06-29 17:26:22Z julian $
29 */
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/lock.h>
34#include <sys/mman.h>
35#include <sys/mutex.h>
36#include <sys/proc.h>
37#include <sys/resource.h>
38#include <sys/resourcevar.h>
39#include <sys/sysproto.h>
40#include <sys/unistd.h>
41
42#include <machine/frame.h>
43#include <machine/psl.h>
44#include <machine/segments.h>
45#include <machine/sysarch.h>
46
47#include <vm/vm.h>
48#include <vm/pmap.h>
49#include <vm/vm_map.h>
50
51#include <i386/linux/linux.h>
52#include <i386/linux/linux_proto.h>
53#include <compat/linux/linux_ipc.h>
54#include <compat/linux/linux_signal.h>
55#include <compat/linux/linux_util.h>
56
57struct l_descriptor {
58	l_uint		entry_number;
59	l_ulong		base_addr;
60	l_uint		limit;
61	l_uint		seg_32bit:1;
62	l_uint		contents:2;
63	l_uint		read_exec_only:1;
64	l_uint		limit_in_pages:1;
65	l_uint		seg_not_present:1;
66	l_uint		useable:1;
67};
68
69struct l_old_select_argv {
70	l_int		nfds;
71	l_fd_set	*readfds;
72	l_fd_set	*writefds;
73	l_fd_set	*exceptfds;
74	struct l_timeval	*timeout;
75};
76
77int
78linux_to_bsd_sigaltstack(int lsa)
79{
80	int bsa = 0;
81
82	if (lsa & LINUX_SS_DISABLE)
83		bsa |= SS_DISABLE;
84	if (lsa & LINUX_SS_ONSTACK)
85		bsa |= SS_ONSTACK;
86	return (bsa);
87}
88
89int
90bsd_to_linux_sigaltstack(int bsa)
91{
92	int lsa = 0;
93
94	if (bsa & SS_DISABLE)
95		lsa |= LINUX_SS_DISABLE;
96	if (bsa & SS_ONSTACK)
97		lsa |= LINUX_SS_ONSTACK;
98	return (lsa);
99}
100
101int
102linux_execve(struct thread *td, struct linux_execve_args *args)
103{
104	struct execve_args bsd;
105	caddr_t sg;
106
107	sg = stackgap_init();
108	CHECKALTEXIST(td, &sg, args->path);
109
110#ifdef DEBUG
111	if (ldebug(execve))
112		printf(ARGS(execve, "%s"), args->path);
113#endif
114
115	bsd.fname = args->path;
116	bsd.argv = args->argp;
117	bsd.envv = args->envp;
118	return (execve(td, &bsd));
119}
120
121struct l_ipc_kludge {
122	struct l_msgbuf *msgp;
123	l_long msgtyp;
124};
125
126int
127linux_ipc(struct thread *td, struct linux_ipc_args *args)
128{
129
130	switch (args->what & 0xFFFF) {
131	case LINUX_SEMOP: {
132		struct linux_semop_args a;
133
134		a.semid = args->arg1;
135		a.tsops = args->ptr;
136		a.nsops = args->arg2;
137		return (linux_semop(td, &a));
138	}
139	case LINUX_SEMGET: {
140		struct linux_semget_args a;
141
142		a.key = args->arg1;
143		a.nsems = args->arg2;
144		a.semflg = args->arg3;
145		return (linux_semget(td, &a));
146	}
147	case LINUX_SEMCTL: {
148		struct linux_semctl_args a;
149		int error;
150
151		a.semid = args->arg1;
152		a.semnum = args->arg2;
153		a.cmd = args->arg3;
154		error = copyin((caddr_t)args->ptr, &a.arg, sizeof(a.arg));
155		if (error)
156			return (error);
157		return (linux_semctl(td, &a));
158	}
159	case LINUX_MSGSND: {
160		struct linux_msgsnd_args a;
161
162		a.msqid = args->arg1;
163		a.msgp = args->ptr;
164		a.msgsz = args->arg2;
165		a.msgflg = args->arg3;
166		return (linux_msgsnd(td, &a));
167	}
168	case LINUX_MSGRCV: {
169		struct linux_msgrcv_args a;
170
171		a.msqid = args->arg1;
172		a.msgsz = args->arg2;
173		a.msgflg = args->arg3;
174		if ((args->what >> 16) == 0) {
175			struct l_ipc_kludge tmp;
176			int error;
177
178			if (args->ptr == NULL)
179				return (EINVAL);
180			error = copyin((caddr_t)args->ptr, &tmp, sizeof(tmp));
181			if (error)
182				return (error);
183			a.msgp = tmp.msgp;
184			a.msgtyp = tmp.msgtyp;
185		} else {
186			a.msgp = args->ptr;
187			a.msgtyp = args->arg5;
188		}
189		return (linux_msgrcv(td, &a));
190	}
191	case LINUX_MSGGET: {
192		struct linux_msgget_args a;
193
194		a.key = args->arg1;
195		a.msgflg = args->arg2;
196		return (linux_msgget(td, &a));
197	}
198	case LINUX_MSGCTL: {
199		struct linux_msgctl_args a;
200
201		a.msqid = args->arg1;
202		a.cmd = args->arg2;
203		a.buf = args->ptr;
204		return (linux_msgctl(td, &a));
205	}
206	case LINUX_SHMAT: {
207		struct linux_shmat_args a;
208
209		a.shmid = args->arg1;
210		a.shmaddr = args->ptr;
211		a.shmflg = args->arg2;
212		a.raddr = (l_ulong *)args->arg3;
213		return (linux_shmat(td, &a));
214	}
215	case LINUX_SHMDT: {
216		struct linux_shmdt_args a;
217
218		a.shmaddr = args->ptr;
219		return (linux_shmdt(td, &a));
220	}
221	case LINUX_SHMGET: {
222		struct linux_shmget_args a;
223
224		a.key = args->arg1;
225		a.size = args->arg2;
226		a.shmflg = args->arg3;
227		return (linux_shmget(td, &a));
228	}
229	case LINUX_SHMCTL: {
230		struct linux_shmctl_args a;
231
232		a.shmid = args->arg1;
233		a.cmd = args->arg2;
234		a.buf = args->ptr;
235		return (linux_shmctl(td, &a));
236	}
237	default:
238		break;
239	}
240
241	return (EINVAL);
242}
243
244int
245linux_old_select(struct thread *td, struct linux_old_select_args *args)
246{
247	struct l_old_select_argv linux_args;
248	struct linux_select_args newsel;
249	int error;
250
251#ifdef DEBUG
252	if (ldebug(old_select))
253		printf(ARGS(old_select, "%p"), args->ptr);
254#endif
255
256	error = copyin((caddr_t)args->ptr, &linux_args, sizeof(linux_args));
257	if (error)
258		return (error);
259
260	newsel.nfds = linux_args.nfds;
261	newsel.readfds = linux_args.readfds;
262	newsel.writefds = linux_args.writefds;
263	newsel.exceptfds = linux_args.exceptfds;
264	newsel.timeout = linux_args.timeout;
265	return (linux_select(td, &newsel));
266}
267
268int
269linux_fork(struct thread *td, struct linux_fork_args *args)
270{
271	int error;
272
273#ifdef DEBUG
274	if (ldebug(fork))
275		printf(ARGS(fork, ""));
276#endif
277
278	if ((error = fork(td, (struct fork_args *)args)) != 0)
279		return (error);
280
281	if (td->td_retval[1] == 1)
282		td->td_retval[0] = 0;
283	return (0);
284}
285
286int
287linux_vfork(struct thread *td, struct linux_vfork_args *args)
288{
289	int error;
290
291#ifdef DEBUG
292	if (ldebug(vfork))
293		printf(ARGS(vfork, ""));
294#endif
295
296	if ((error = vfork(td, (struct vfork_args *)args)) != 0)
297		return (error);
298	/* Are we the child? */
299	if (td->td_retval[1] == 1)
300		td->td_retval[0] = 0;
301	return (0);
302}
303
304#define CLONE_VM	0x100
305#define CLONE_FS	0x200
306#define CLONE_FILES	0x400
307#define CLONE_SIGHAND	0x800
308#define CLONE_PID	0x1000
309
310int
311linux_clone(struct thread *td, struct linux_clone_args *args)
312{
313	int error, ff = RFPROC | RFSTOPPED;
314	struct proc *p2;
315	int exit_signal;
316
317#ifdef DEBUG
318	if (ldebug(clone)) {
319		printf(ARGS(clone, "flags %x, stack %x"),
320		    (unsigned int)args->flags, (unsigned int)args->stack);
321		if (args->flags & CLONE_PID)
322			printf(LMSG("CLONE_PID not yet supported"));
323	}
324#endif
325
326	if (!args->stack)
327		return (EINVAL);
328
329	exit_signal = args->flags & 0x000000ff;
330	if (exit_signal >= LINUX_NSIG)
331		return (EINVAL);
332
333	if (exit_signal <= LINUX_SIGTBLSZ)
334		exit_signal = linux_to_bsd_signal[_SIG_IDX(exit_signal)];
335
336	if (args->flags & CLONE_VM)
337		ff |= RFMEM;
338	if (args->flags & CLONE_SIGHAND)
339		ff |= RFSIGSHARE;
340	if (!(args->flags & CLONE_FILES))
341		ff |= RFFDG;
342
343	mtx_lock(&Giant);
344	error = fork1(td, ff, &p2);
345	if (error == 0) {
346		td->td_retval[0] = p2->p_pid;
347		td->td_retval[1] = 0;
348
349		PROC_LOCK(p2);
350		p2->p_sigparent = exit_signal;
351		FIRST_THREAD_IN_PROC(p2)->td_frame->tf_esp =
352					(unsigned int)args->stack;
353
354#ifdef DEBUG
355		if (ldebug(clone))
356			printf(LMSG("clone: successful rfork to %ld"),
357			    (long)p2->p_pid);
358#endif
359
360		/*
361		 * Make this runnable after we are finished with it.
362		 */
363		mtx_lock_spin(&sched_lock);
364		setrunqueue(FIRST_THREAD_IN_PROC(p2));
365		mtx_unlock_spin(&sched_lock);
366		PROC_UNLOCK(p2);
367	}
368	mtx_unlock(&Giant);
369
370	return (error);
371}
372
373/* XXX move */
374struct l_mmap_argv {
375	l_caddr_t	addr;
376	l_int		len;
377	l_int		prot;
378	l_int		flags;
379	l_int		fd;
380	l_int		pos;
381};
382
383#define STACK_SIZE  (2 * 1024 * 1024)
384#define GUARD_SIZE  (4 * PAGE_SIZE)
385
386int
387linux_mmap(struct thread *td, struct linux_mmap_args *args)
388{
389	struct proc *p = td->td_proc;
390	struct mmap_args /* {
391		caddr_t addr;
392		size_t len;
393		int prot;
394		int flags;
395		int fd;
396		long pad;
397		off_t pos;
398	} */ bsd_args;
399	int error;
400	struct l_mmap_argv linux_args;
401
402	error = copyin((caddr_t)args->ptr, &linux_args, sizeof(linux_args));
403	if (error)
404		return (error);
405
406#ifdef DEBUG
407	if (ldebug(mmap))
408		printf(ARGS(mmap, "%p, %d, %d, 0x%08x, %d, %d"),
409		    (void *)linux_args.addr, linux_args.len, linux_args.prot,
410		    linux_args.flags, linux_args.fd, linux_args.pos);
411#endif
412
413	bsd_args.flags = 0;
414	if (linux_args.flags & LINUX_MAP_SHARED)
415		bsd_args.flags |= MAP_SHARED;
416	if (linux_args.flags & LINUX_MAP_PRIVATE)
417		bsd_args.flags |= MAP_PRIVATE;
418	if (linux_args.flags & LINUX_MAP_FIXED)
419		bsd_args.flags |= MAP_FIXED;
420	if (linux_args.flags & LINUX_MAP_ANON)
421		bsd_args.flags |= MAP_ANON;
422	else
423		bsd_args.flags |= MAP_NOSYNC;
424	if (linux_args.flags & LINUX_MAP_GROWSDOWN) {
425		bsd_args.flags |= MAP_STACK;
426
427		/* The linux MAP_GROWSDOWN option does not limit auto
428		 * growth of the region.  Linux mmap with this option
429		 * takes as addr the inital BOS, and as len, the initial
430		 * region size.  It can then grow down from addr without
431		 * limit.  However, linux threads has an implicit internal
432		 * limit to stack size of STACK_SIZE.  Its just not
433		 * enforced explicitly in linux.  But, here we impose
434		 * a limit of (STACK_SIZE - GUARD_SIZE) on the stack
435		 * region, since we can do this with our mmap.
436		 *
437		 * Our mmap with MAP_STACK takes addr as the maximum
438		 * downsize limit on BOS, and as len the max size of
439		 * the region.  It them maps the top SGROWSIZ bytes,
440		 * and autgrows the region down, up to the limit
441		 * in addr.
442		 *
443		 * If we don't use the MAP_STACK option, the effect
444		 * of this code is to allocate a stack region of a
445		 * fixed size of (STACK_SIZE - GUARD_SIZE).
446		 */
447
448		/* This gives us TOS */
449		bsd_args.addr = linux_args.addr + linux_args.len;
450
451		if (bsd_args.addr > p->p_vmspace->vm_maxsaddr) {
452			/* Some linux apps will attempt to mmap
453			 * thread stacks near the top of their
454			 * address space.  If their TOS is greater
455			 * than vm_maxsaddr, vm_map_growstack()
456			 * will confuse the thread stack with the
457			 * process stack and deliver a SEGV if they
458			 * attempt to grow the thread stack past their
459			 * current stacksize rlimit.  To avoid this,
460			 * adjust vm_maxsaddr upwards to reflect
461			 * the current stacksize rlimit rather
462			 * than the maximum possible stacksize.
463			 * It would be better to adjust the
464			 * mmap'ed region, but some apps do not check
465			 * mmap's return value.
466			 */
467			mtx_assert(&Giant, MA_OWNED);
468			p->p_vmspace->vm_maxsaddr = (char *)USRSTACK -
469			    p->p_rlimit[RLIMIT_STACK].rlim_cur;
470		}
471
472		/* This gives us our maximum stack size */
473		if (linux_args.len > STACK_SIZE - GUARD_SIZE)
474			bsd_args.len = linux_args.len;
475		else
476			bsd_args.len  = STACK_SIZE - GUARD_SIZE;
477
478		/* This gives us a new BOS.  If we're using VM_STACK, then
479		 * mmap will just map the top SGROWSIZ bytes, and let
480		 * the stack grow down to the limit at BOS.  If we're
481		 * not using VM_STACK we map the full stack, since we
482		 * don't have a way to autogrow it.
483		 */
484		bsd_args.addr -= bsd_args.len;
485	} else {
486		bsd_args.addr = linux_args.addr;
487		bsd_args.len  = linux_args.len;
488	}
489
490	bsd_args.prot = linux_args.prot | PROT_READ;	/* always required */
491	if (linux_args.flags & LINUX_MAP_ANON)
492		bsd_args.fd = -1;
493	else
494		bsd_args.fd = linux_args.fd;
495	bsd_args.pos = linux_args.pos;
496	bsd_args.pad = 0;
497
498#ifdef DEBUG
499	if (ldebug(mmap))
500		printf("-> (%p, %d, %d, 0x%08x, %d, %d)\n",
501		    (void *)bsd_args.addr, bsd_args.len, bsd_args.prot,
502		    bsd_args.flags, bsd_args.fd, (int)bsd_args.pos);
503#endif
504
505	return (mmap(td, &bsd_args));
506}
507
508int
509linux_pipe(struct thread *td, struct linux_pipe_args *args)
510{
511	int error;
512	int reg_edx;
513
514#ifdef DEBUG
515	if (ldebug(pipe))
516		printf(ARGS(pipe, "*"));
517#endif
518
519	reg_edx = td->td_retval[1];
520	error = pipe(td, 0);
521	if (error) {
522		td->td_retval[1] = reg_edx;
523		return (error);
524	}
525
526	error = copyout(td->td_retval, args->pipefds, 2*sizeof(int));
527	if (error) {
528		td->td_retval[1] = reg_edx;
529		return (error);
530	}
531
532	td->td_retval[1] = reg_edx;
533	td->td_retval[0] = 0;
534	return (0);
535}
536
537int
538linux_ioperm(struct thread *td, struct linux_ioperm_args *args)
539{
540	struct sysarch_args sa;
541	struct i386_ioperm_args *iia;
542	caddr_t sg;
543
544	sg = stackgap_init();
545	iia = stackgap_alloc(&sg, sizeof(struct i386_ioperm_args));
546	iia->start = args->start;
547	iia->length = args->length;
548	iia->enable = args->enable;
549	sa.op = I386_SET_IOPERM;
550	sa.parms = (char *)iia;
551	return (sysarch(td, &sa));
552}
553
554int
555linux_iopl(struct thread *td, struct linux_iopl_args *args)
556{
557	int error;
558
559	if (args->level < 0 || args->level > 3)
560		return (EINVAL);
561	if ((error = suser(td)) != 0)
562		return (error);
563	if ((error = securelevel_gt(td->td_ucred, 0)) != 0)
564		return (error);
565	td->td_frame->tf_eflags = (td->td_frame->tf_eflags & ~PSL_IOPL) |
566	    (args->level * (PSL_IOPL / 3));
567	return (0);
568}
569
570int
571linux_modify_ldt(td, uap)
572	struct thread *td;
573	struct linux_modify_ldt_args *uap;
574{
575	int error;
576	caddr_t sg;
577	struct sysarch_args args;
578	struct i386_ldt_args *ldt;
579	struct l_descriptor ld;
580	union descriptor *desc;
581
582	sg = stackgap_init();
583
584	if (uap->ptr == NULL)
585		return (EINVAL);
586
587	switch (uap->func) {
588	case 0x00: /* read_ldt */
589		ldt = stackgap_alloc(&sg, sizeof(*ldt));
590		ldt->start = 0;
591		ldt->descs = uap->ptr;
592		ldt->num = uap->bytecount / sizeof(union descriptor);
593		args.op = I386_GET_LDT;
594		args.parms = (char*)ldt;
595		error = sysarch(td, &args);
596		td->td_retval[0] *= sizeof(union descriptor);
597		break;
598	case 0x01: /* write_ldt */
599	case 0x11: /* write_ldt */
600		if (uap->bytecount != sizeof(ld))
601			return (EINVAL);
602
603		error = copyin(uap->ptr, &ld, sizeof(ld));
604		if (error)
605			return (error);
606
607		ldt = stackgap_alloc(&sg, sizeof(*ldt));
608		desc = stackgap_alloc(&sg, sizeof(*desc));
609		ldt->start = ld.entry_number;
610		ldt->descs = desc;
611		ldt->num = 1;
612		desc->sd.sd_lolimit = (ld.limit & 0x0000ffff);
613		desc->sd.sd_hilimit = (ld.limit & 0x000f0000) >> 16;
614		desc->sd.sd_lobase = (ld.base_addr & 0x00ffffff);
615		desc->sd.sd_hibase = (ld.base_addr & 0xff000000) >> 24;
616		desc->sd.sd_type = SDT_MEMRO | ((ld.read_exec_only ^ 1) << 1) |
617			(ld.contents << 2);
618		desc->sd.sd_dpl = 3;
619		desc->sd.sd_p = (ld.seg_not_present ^ 1);
620		desc->sd.sd_xx = 0;
621		desc->sd.sd_def32 = ld.seg_32bit;
622		desc->sd.sd_gran = ld.limit_in_pages;
623		args.op = I386_SET_LDT;
624		args.parms = (char*)ldt;
625		error = sysarch(td, &args);
626		break;
627	default:
628		error = EINVAL;
629		break;
630	}
631
632	if (error == EOPNOTSUPP) {
633		printf("linux: modify_ldt needs kernel option USER_LDT\n");
634		error = ENOSYS;
635	}
636
637	return (error);
638}
639
640int
641linux_sigaction(struct thread *td, struct linux_sigaction_args *args)
642{
643	l_osigaction_t osa;
644	l_sigaction_t act, oact;
645	int error;
646
647#ifdef DEBUG
648	if (ldebug(sigaction))
649		printf(ARGS(sigaction, "%d, %p, %p"),
650		    args->sig, (void *)args->nsa, (void *)args->osa);
651#endif
652
653	if (args->nsa != NULL) {
654		error = copyin((caddr_t)args->nsa, &osa,
655		    sizeof(l_osigaction_t));
656		if (error)
657			return (error);
658		act.lsa_handler = osa.lsa_handler;
659		act.lsa_flags = osa.lsa_flags;
660		act.lsa_restorer = osa.lsa_restorer;
661		LINUX_SIGEMPTYSET(act.lsa_mask);
662		act.lsa_mask.__bits[0] = osa.lsa_mask;
663	}
664
665	error = linux_do_sigaction(td, args->sig, args->nsa ? &act : NULL,
666	    args->osa ? &oact : NULL);
667
668	if (args->osa != NULL && !error) {
669		osa.lsa_handler = oact.lsa_handler;
670		osa.lsa_flags = oact.lsa_flags;
671		osa.lsa_restorer = oact.lsa_restorer;
672		osa.lsa_mask = oact.lsa_mask.__bits[0];
673		error = copyout(&osa, (caddr_t)args->osa,
674		    sizeof(l_osigaction_t));
675	}
676
677	return (error);
678}
679
680/*
681 * Linux has two extra args, restart and oldmask.  We dont use these,
682 * but it seems that "restart" is actually a context pointer that
683 * enables the signal to happen with a different register set.
684 */
685int
686linux_sigsuspend(struct thread *td, struct linux_sigsuspend_args *args)
687{
688	struct sigsuspend_args bsd;
689	sigset_t *sigmask;
690	l_sigset_t mask;
691	caddr_t sg = stackgap_init();
692
693#ifdef DEBUG
694	if (ldebug(sigsuspend))
695		printf(ARGS(sigsuspend, "%08lx"), (unsigned long)args->mask);
696#endif
697
698	sigmask = stackgap_alloc(&sg, sizeof(sigset_t));
699	LINUX_SIGEMPTYSET(mask);
700	mask.__bits[0] = args->mask;
701	linux_to_bsd_sigset(&mask, sigmask);
702	bsd.sigmask = sigmask;
703	return (sigsuspend(td, &bsd));
704}
705
706int
707linux_rt_sigsuspend(td, uap)
708	struct thread *td;
709	struct linux_rt_sigsuspend_args *uap;
710{
711	l_sigset_t lmask;
712	sigset_t *bmask;
713	struct sigsuspend_args bsd;
714	caddr_t sg = stackgap_init();
715	int error;
716
717#ifdef DEBUG
718	if (ldebug(rt_sigsuspend))
719		printf(ARGS(rt_sigsuspend, "%p, %d"),
720		    (void *)uap->newset, uap->sigsetsize);
721#endif
722
723	if (uap->sigsetsize != sizeof(l_sigset_t))
724		return (EINVAL);
725
726	error = copyin(uap->newset, &lmask, sizeof(l_sigset_t));
727	if (error)
728		return (error);
729
730	bmask = stackgap_alloc(&sg, sizeof(sigset_t));
731	linux_to_bsd_sigset(&lmask, bmask);
732	bsd.sigmask = bmask;
733	return (sigsuspend(td, &bsd));
734}
735
736int
737linux_pause(struct thread *td, struct linux_pause_args *args)
738{
739	struct proc *p = td->td_proc;
740	struct sigsuspend_args bsd;
741	sigset_t *sigmask;
742	caddr_t sg = stackgap_init();
743
744#ifdef DEBUG
745	if (ldebug(pause))
746		printf(ARGS(pause, ""));
747#endif
748
749	sigmask = stackgap_alloc(&sg, sizeof(sigset_t));
750	PROC_LOCK(p);
751	*sigmask = p->p_sigmask;
752	PROC_UNLOCK(p);
753	bsd.sigmask = sigmask;
754	return (sigsuspend(td, &bsd));
755}
756
757int
758linux_sigaltstack(struct thread *td, struct linux_sigaltstack_args *uap)
759{
760	struct sigaltstack_args bsd;
761	stack_t *ss, *oss;
762	l_stack_t lss;
763	int error;
764	caddr_t sg = stackgap_init();
765
766#ifdef DEBUG
767	if (ldebug(sigaltstack))
768		printf(ARGS(sigaltstack, "%p, %p"), uap->uss, uap->uoss);
769#endif
770
771	if (uap->uss == NULL) {
772		ss = NULL;
773	} else {
774		error = copyin(uap->uss, &lss, sizeof(l_stack_t));
775		if (error)
776			return (error);
777
778		ss = stackgap_alloc(&sg, sizeof(stack_t));
779		ss->ss_sp = lss.ss_sp;
780		ss->ss_size = lss.ss_size;
781		ss->ss_flags = linux_to_bsd_sigaltstack(lss.ss_flags);
782	}
783	oss = (uap->uoss != NULL)
784	    ? stackgap_alloc(&sg, sizeof(stack_t))
785	    : NULL;
786
787	bsd.ss = ss;
788	bsd.oss = oss;
789	error = sigaltstack(td, &bsd);
790
791	if (!error && oss != NULL) {
792		lss.ss_sp = oss->ss_sp;
793		lss.ss_size = oss->ss_size;
794		lss.ss_flags = bsd_to_linux_sigaltstack(oss->ss_flags);
795		error = copyout(&lss, uap->uoss, sizeof(l_stack_t));
796	}
797
798	return (error);
799}
800