xref: /freebsd/sys/i386/linux/linux_machdep.c (revision 3ff369fed2a08f32dda232c10470b949bef9489f)
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$
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 
57 struct 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 
69 struct 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 
77 int
78 linux_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 
89 int
90 bsd_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 
101 int
102 linux_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 
121 struct l_ipc_kludge {
122 	struct l_msgbuf *msgp;
123 	l_long msgtyp;
124 };
125 
126 int
127 linux_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 
244 int
245 linux_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 
268 int
269 linux_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 
286 int
287 linux_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 
310 int
311 linux_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 		p2->p_stat = SRUN;
365 		setrunqueue(FIRST_THREAD_IN_PROC(p2));
366 		mtx_unlock_spin(&sched_lock);
367 		PROC_UNLOCK(p2);
368 	}
369 	mtx_unlock(&Giant);
370 
371 	return (error);
372 }
373 
374 /* XXX move */
375 struct l_mmap_argv {
376 	l_caddr_t	addr;
377 	l_int		len;
378 	l_int		prot;
379 	l_int		flags;
380 	l_int		fd;
381 	l_int		pos;
382 };
383 
384 #define STACK_SIZE  (2 * 1024 * 1024)
385 #define GUARD_SIZE  (4 * PAGE_SIZE)
386 
387 int
388 linux_mmap(struct thread *td, struct linux_mmap_args *args)
389 {
390 	struct proc *p = td->td_proc;
391 	struct mmap_args /* {
392 		caddr_t addr;
393 		size_t len;
394 		int prot;
395 		int flags;
396 		int fd;
397 		long pad;
398 		off_t pos;
399 	} */ bsd_args;
400 	int error;
401 	struct l_mmap_argv linux_args;
402 
403 	error = copyin((caddr_t)args->ptr, &linux_args, sizeof(linux_args));
404 	if (error)
405 		return (error);
406 
407 #ifdef DEBUG
408 	if (ldebug(mmap))
409 		printf(ARGS(mmap, "%p, %d, %d, 0x%08x, %d, %d"),
410 		    (void *)linux_args.addr, linux_args.len, linux_args.prot,
411 		    linux_args.flags, linux_args.fd, linux_args.pos);
412 #endif
413 
414 	bsd_args.flags = 0;
415 	if (linux_args.flags & LINUX_MAP_SHARED)
416 		bsd_args.flags |= MAP_SHARED;
417 	if (linux_args.flags & LINUX_MAP_PRIVATE)
418 		bsd_args.flags |= MAP_PRIVATE;
419 	if (linux_args.flags & LINUX_MAP_FIXED)
420 		bsd_args.flags |= MAP_FIXED;
421 	if (linux_args.flags & LINUX_MAP_ANON)
422 		bsd_args.flags |= MAP_ANON;
423 	else
424 		bsd_args.flags |= MAP_NOSYNC;
425 	if (linux_args.flags & LINUX_MAP_GROWSDOWN) {
426 		bsd_args.flags |= MAP_STACK;
427 
428 		/* The linux MAP_GROWSDOWN option does not limit auto
429 		 * growth of the region.  Linux mmap with this option
430 		 * takes as addr the inital BOS, and as len, the initial
431 		 * region size.  It can then grow down from addr without
432 		 * limit.  However, linux threads has an implicit internal
433 		 * limit to stack size of STACK_SIZE.  Its just not
434 		 * enforced explicitly in linux.  But, here we impose
435 		 * a limit of (STACK_SIZE - GUARD_SIZE) on the stack
436 		 * region, since we can do this with our mmap.
437 		 *
438 		 * Our mmap with MAP_STACK takes addr as the maximum
439 		 * downsize limit on BOS, and as len the max size of
440 		 * the region.  It them maps the top SGROWSIZ bytes,
441 		 * and autgrows the region down, up to the limit
442 		 * in addr.
443 		 *
444 		 * If we don't use the MAP_STACK option, the effect
445 		 * of this code is to allocate a stack region of a
446 		 * fixed size of (STACK_SIZE - GUARD_SIZE).
447 		 */
448 
449 		/* This gives us TOS */
450 		bsd_args.addr = linux_args.addr + linux_args.len;
451 
452 		if (bsd_args.addr > p->p_vmspace->vm_maxsaddr) {
453 			/* Some linux apps will attempt to mmap
454 			 * thread stacks near the top of their
455 			 * address space.  If their TOS is greater
456 			 * than vm_maxsaddr, vm_map_growstack()
457 			 * will confuse the thread stack with the
458 			 * process stack and deliver a SEGV if they
459 			 * attempt to grow the thread stack past their
460 			 * current stacksize rlimit.  To avoid this,
461 			 * adjust vm_maxsaddr upwards to reflect
462 			 * the current stacksize rlimit rather
463 			 * than the maximum possible stacksize.
464 			 * It would be better to adjust the
465 			 * mmap'ed region, but some apps do not check
466 			 * mmap's return value.
467 			 */
468 			mtx_assert(&Giant, MA_OWNED);
469 			p->p_vmspace->vm_maxsaddr = (char *)USRSTACK -
470 			    p->p_rlimit[RLIMIT_STACK].rlim_cur;
471 		}
472 
473 		/* This gives us our maximum stack size */
474 		if (linux_args.len > STACK_SIZE - GUARD_SIZE)
475 			bsd_args.len = linux_args.len;
476 		else
477 			bsd_args.len  = STACK_SIZE - GUARD_SIZE;
478 
479 		/* This gives us a new BOS.  If we're using VM_STACK, then
480 		 * mmap will just map the top SGROWSIZ bytes, and let
481 		 * the stack grow down to the limit at BOS.  If we're
482 		 * not using VM_STACK we map the full stack, since we
483 		 * don't have a way to autogrow it.
484 		 */
485 		bsd_args.addr -= bsd_args.len;
486 	} else {
487 		bsd_args.addr = linux_args.addr;
488 		bsd_args.len  = linux_args.len;
489 	}
490 
491 	bsd_args.prot = linux_args.prot | PROT_READ;	/* always required */
492 	if (linux_args.flags & LINUX_MAP_ANON)
493 		bsd_args.fd = -1;
494 	else
495 		bsd_args.fd = linux_args.fd;
496 	bsd_args.pos = linux_args.pos;
497 	bsd_args.pad = 0;
498 
499 #ifdef DEBUG
500 	if (ldebug(mmap))
501 		printf("-> (%p, %d, %d, 0x%08x, %d, %d)\n",
502 		    (void *)bsd_args.addr, bsd_args.len, bsd_args.prot,
503 		    bsd_args.flags, bsd_args.fd, (int)bsd_args.pos);
504 #endif
505 
506 	return (mmap(td, &bsd_args));
507 }
508 
509 int
510 linux_pipe(struct thread *td, struct linux_pipe_args *args)
511 {
512 	int error;
513 	int reg_edx;
514 
515 #ifdef DEBUG
516 	if (ldebug(pipe))
517 		printf(ARGS(pipe, "*"));
518 #endif
519 
520 	reg_edx = td->td_retval[1];
521 	error = pipe(td, 0);
522 	if (error) {
523 		td->td_retval[1] = reg_edx;
524 		return (error);
525 	}
526 
527 	error = copyout(td->td_retval, args->pipefds, 2*sizeof(int));
528 	if (error) {
529 		td->td_retval[1] = reg_edx;
530 		return (error);
531 	}
532 
533 	td->td_retval[1] = reg_edx;
534 	td->td_retval[0] = 0;
535 	return (0);
536 }
537 
538 int
539 linux_ioperm(struct thread *td, struct linux_ioperm_args *args)
540 {
541 	struct sysarch_args sa;
542 	struct i386_ioperm_args *iia;
543 	caddr_t sg;
544 
545 	sg = stackgap_init();
546 	iia = stackgap_alloc(&sg, sizeof(struct i386_ioperm_args));
547 	iia->start = args->start;
548 	iia->length = args->length;
549 	iia->enable = args->enable;
550 	sa.op = I386_SET_IOPERM;
551 	sa.parms = (char *)iia;
552 	return (sysarch(td, &sa));
553 }
554 
555 int
556 linux_iopl(struct thread *td, struct linux_iopl_args *args)
557 {
558 	int error;
559 
560 	if (args->level < 0 || args->level > 3)
561 		return (EINVAL);
562 	if ((error = suser(td)) != 0)
563 		return (error);
564 	if ((error = securelevel_gt(td->td_ucred, 0)) != 0)
565 		return (error);
566 	td->td_frame->tf_eflags = (td->td_frame->tf_eflags & ~PSL_IOPL) |
567 	    (args->level * (PSL_IOPL / 3));
568 	return (0);
569 }
570 
571 int
572 linux_modify_ldt(td, uap)
573 	struct thread *td;
574 	struct linux_modify_ldt_args *uap;
575 {
576 	int error;
577 	caddr_t sg;
578 	struct sysarch_args args;
579 	struct i386_ldt_args *ldt;
580 	struct l_descriptor ld;
581 	union descriptor *desc;
582 
583 	sg = stackgap_init();
584 
585 	if (uap->ptr == NULL)
586 		return (EINVAL);
587 
588 	switch (uap->func) {
589 	case 0x00: /* read_ldt */
590 		ldt = stackgap_alloc(&sg, sizeof(*ldt));
591 		ldt->start = 0;
592 		ldt->descs = uap->ptr;
593 		ldt->num = uap->bytecount / sizeof(union descriptor);
594 		args.op = I386_GET_LDT;
595 		args.parms = (char*)ldt;
596 		error = sysarch(td, &args);
597 		td->td_retval[0] *= sizeof(union descriptor);
598 		break;
599 	case 0x01: /* write_ldt */
600 	case 0x11: /* write_ldt */
601 		if (uap->bytecount != sizeof(ld))
602 			return (EINVAL);
603 
604 		error = copyin(uap->ptr, &ld, sizeof(ld));
605 		if (error)
606 			return (error);
607 
608 		ldt = stackgap_alloc(&sg, sizeof(*ldt));
609 		desc = stackgap_alloc(&sg, sizeof(*desc));
610 		ldt->start = ld.entry_number;
611 		ldt->descs = desc;
612 		ldt->num = 1;
613 		desc->sd.sd_lolimit = (ld.limit & 0x0000ffff);
614 		desc->sd.sd_hilimit = (ld.limit & 0x000f0000) >> 16;
615 		desc->sd.sd_lobase = (ld.base_addr & 0x00ffffff);
616 		desc->sd.sd_hibase = (ld.base_addr & 0xff000000) >> 24;
617 		desc->sd.sd_type = SDT_MEMRO | ((ld.read_exec_only ^ 1) << 1) |
618 			(ld.contents << 2);
619 		desc->sd.sd_dpl = 3;
620 		desc->sd.sd_p = (ld.seg_not_present ^ 1);
621 		desc->sd.sd_xx = 0;
622 		desc->sd.sd_def32 = ld.seg_32bit;
623 		desc->sd.sd_gran = ld.limit_in_pages;
624 		args.op = I386_SET_LDT;
625 		args.parms = (char*)ldt;
626 		error = sysarch(td, &args);
627 		break;
628 	default:
629 		error = EINVAL;
630 		break;
631 	}
632 
633 	if (error == EOPNOTSUPP) {
634 		printf("linux: modify_ldt needs kernel option USER_LDT\n");
635 		error = ENOSYS;
636 	}
637 
638 	return (error);
639 }
640 
641 int
642 linux_sigaction(struct thread *td, struct linux_sigaction_args *args)
643 {
644 	l_osigaction_t osa;
645 	l_sigaction_t act, oact;
646 	int error;
647 
648 #ifdef DEBUG
649 	if (ldebug(sigaction))
650 		printf(ARGS(sigaction, "%d, %p, %p"),
651 		    args->sig, (void *)args->nsa, (void *)args->osa);
652 #endif
653 
654 	if (args->nsa != NULL) {
655 		error = copyin((caddr_t)args->nsa, &osa,
656 		    sizeof(l_osigaction_t));
657 		if (error)
658 			return (error);
659 		act.lsa_handler = osa.lsa_handler;
660 		act.lsa_flags = osa.lsa_flags;
661 		act.lsa_restorer = osa.lsa_restorer;
662 		LINUX_SIGEMPTYSET(act.lsa_mask);
663 		act.lsa_mask.__bits[0] = osa.lsa_mask;
664 	}
665 
666 	error = linux_do_sigaction(td, args->sig, args->nsa ? &act : NULL,
667 	    args->osa ? &oact : NULL);
668 
669 	if (args->osa != NULL && !error) {
670 		osa.lsa_handler = oact.lsa_handler;
671 		osa.lsa_flags = oact.lsa_flags;
672 		osa.lsa_restorer = oact.lsa_restorer;
673 		osa.lsa_mask = oact.lsa_mask.__bits[0];
674 		error = copyout(&osa, (caddr_t)args->osa,
675 		    sizeof(l_osigaction_t));
676 	}
677 
678 	return (error);
679 }
680 
681 /*
682  * Linux has two extra args, restart and oldmask.  We dont use these,
683  * but it seems that "restart" is actually a context pointer that
684  * enables the signal to happen with a different register set.
685  */
686 int
687 linux_sigsuspend(struct thread *td, struct linux_sigsuspend_args *args)
688 {
689 	struct sigsuspend_args bsd;
690 	sigset_t *sigmask;
691 	l_sigset_t mask;
692 	caddr_t sg = stackgap_init();
693 
694 #ifdef DEBUG
695 	if (ldebug(sigsuspend))
696 		printf(ARGS(sigsuspend, "%08lx"), (unsigned long)args->mask);
697 #endif
698 
699 	sigmask = stackgap_alloc(&sg, sizeof(sigset_t));
700 	LINUX_SIGEMPTYSET(mask);
701 	mask.__bits[0] = args->mask;
702 	linux_to_bsd_sigset(&mask, sigmask);
703 	bsd.sigmask = sigmask;
704 	return (sigsuspend(td, &bsd));
705 }
706 
707 int
708 linux_rt_sigsuspend(td, uap)
709 	struct thread *td;
710 	struct linux_rt_sigsuspend_args *uap;
711 {
712 	l_sigset_t lmask;
713 	sigset_t *bmask;
714 	struct sigsuspend_args bsd;
715 	caddr_t sg = stackgap_init();
716 	int error;
717 
718 #ifdef DEBUG
719 	if (ldebug(rt_sigsuspend))
720 		printf(ARGS(rt_sigsuspend, "%p, %d"),
721 		    (void *)uap->newset, uap->sigsetsize);
722 #endif
723 
724 	if (uap->sigsetsize != sizeof(l_sigset_t))
725 		return (EINVAL);
726 
727 	error = copyin(uap->newset, &lmask, sizeof(l_sigset_t));
728 	if (error)
729 		return (error);
730 
731 	bmask = stackgap_alloc(&sg, sizeof(sigset_t));
732 	linux_to_bsd_sigset(&lmask, bmask);
733 	bsd.sigmask = bmask;
734 	return (sigsuspend(td, &bsd));
735 }
736 
737 int
738 linux_pause(struct thread *td, struct linux_pause_args *args)
739 {
740 	struct proc *p = td->td_proc;
741 	struct sigsuspend_args bsd;
742 	sigset_t *sigmask;
743 	caddr_t sg = stackgap_init();
744 
745 #ifdef DEBUG
746 	if (ldebug(pause))
747 		printf(ARGS(pause, ""));
748 #endif
749 
750 	sigmask = stackgap_alloc(&sg, sizeof(sigset_t));
751 	PROC_LOCK(p);
752 	*sigmask = p->p_sigmask;
753 	PROC_UNLOCK(p);
754 	bsd.sigmask = sigmask;
755 	return (sigsuspend(td, &bsd));
756 }
757 
758 int
759 linux_sigaltstack(struct thread *td, struct linux_sigaltstack_args *uap)
760 {
761 	struct sigaltstack_args bsd;
762 	stack_t *ss, *oss;
763 	l_stack_t lss;
764 	int error;
765 	caddr_t sg = stackgap_init();
766 
767 #ifdef DEBUG
768 	if (ldebug(sigaltstack))
769 		printf(ARGS(sigaltstack, "%p, %p"), uap->uss, uap->uoss);
770 #endif
771 
772 	if (uap->uss == NULL) {
773 		ss = NULL;
774 	} else {
775 		error = copyin(uap->uss, &lss, sizeof(l_stack_t));
776 		if (error)
777 			return (error);
778 
779 		ss = stackgap_alloc(&sg, sizeof(stack_t));
780 		ss->ss_sp = lss.ss_sp;
781 		ss->ss_size = lss.ss_size;
782 		ss->ss_flags = linux_to_bsd_sigaltstack(lss.ss_flags);
783 	}
784 	oss = (uap->uoss != NULL)
785 	    ? stackgap_alloc(&sg, sizeof(stack_t))
786 	    : NULL;
787 
788 	bsd.ss = ss;
789 	bsd.oss = oss;
790 	error = sigaltstack(td, &bsd);
791 
792 	if (!error && oss != NULL) {
793 		lss.ss_sp = oss->ss_sp;
794 		lss.ss_size = oss->ss_size;
795 		lss.ss_flags = bsd_to_linux_sigaltstack(oss->ss_flags);
796 		error = copyout(&lss, uap->uoss, sizeof(l_stack_t));
797 	}
798 
799 	return (error);
800 }
801