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