freebsd32_misc.c revision 111119
1/*-
2 * Copyright (c) 2002 Doug Rabson
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 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/compat/freebsd32/freebsd32_misc.c 111119 2003-02-19 05:47:46Z imp $
27 */
28
29#include "opt_compat.h"
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/bus.h>
34#include <sys/exec.h>
35#include <sys/fcntl.h>
36#include <sys/filedesc.h>
37#include <sys/imgact.h>
38#include <sys/kernel.h>
39#include <sys/lock.h>
40#include <sys/malloc.h>
41#include <sys/file.h>		/* Must come after sys/malloc.h */
42#include <sys/mman.h>
43#include <sys/module.h>
44#include <sys/mount.h>
45#include <sys/mutex.h>
46#include <sys/namei.h>
47#include <sys/param.h>
48#include <sys/proc.h>
49#include <sys/reboot.h>
50#include <sys/resource.h>
51#include <sys/resourcevar.h>
52#include <sys/selinfo.h>
53#include <sys/pipe.h>		/* Must come after sys/selinfo.h */
54#include <sys/signal.h>
55#include <sys/signalvar.h>
56#include <sys/socket.h>
57#include <sys/socketvar.h>
58#include <sys/stat.h>
59#include <sys/sysctl.h>
60#include <sys/sysent.h>
61#include <sys/sysproto.h>
62#include <sys/systm.h>
63#include <sys/unistd.h>
64#include <sys/user.h>
65#include <sys/utsname.h>
66#include <sys/vnode.h>
67
68#include <vm/vm.h>
69#include <vm/vm_kern.h>
70#include <vm/vm_param.h>
71#include <vm/pmap.h>
72#include <vm/vm_map.h>
73#include <vm/vm_object.h>
74#include <vm/vm_extern.h>
75
76#include <ia64/ia32/ia32_util.h>
77#include <ia64/ia32/ia32.h>
78#include <ia64/ia32/ia32_proto.h>
79
80static const char ia32_emul_path[] = "/compat/ia32";
81/*
82 * [ taken from the linux emulator ]
83 * Search an alternate path before passing pathname arguments on
84 * to system calls. Useful for keeping a separate 'emulation tree'.
85 *
86 * If cflag is set, we check if an attempt can be made to create
87 * the named file, i.e. we check if the directory it should
88 * be in exists.
89 */
90int
91ia32_emul_find(td, sgp, prefix, path, pbuf, cflag)
92	struct thread	*td;
93	caddr_t		*sgp;		/* Pointer to stackgap memory */
94	const char	*prefix;
95	char		*path;
96	char		**pbuf;
97	int		cflag;
98{
99	int			error;
100	size_t			len, sz;
101	char			*buf, *cp, *ptr;
102	struct ucred		*ucred;
103	struct nameidata	nd;
104	struct nameidata	ndroot;
105	struct vattr		vat;
106	struct vattr		vatroot;
107
108	buf = (char *) malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
109	*pbuf = path;
110
111	for (ptr = buf; (*ptr = *prefix) != '\0'; ptr++, prefix++)
112		continue;
113
114	sz = MAXPATHLEN - (ptr - buf);
115
116	/*
117	 * If sgp is not given then the path is already in kernel space
118	 */
119	if (sgp == NULL)
120		error = copystr(path, ptr, sz, &len);
121	else
122		error = copyinstr(path, ptr, sz, &len);
123
124	if (error) {
125		free(buf, M_TEMP);
126		return error;
127	}
128
129	if (*ptr != '/') {
130		free(buf, M_TEMP);
131		return EINVAL;
132	}
133
134	/*
135	 *  We know that there is a / somewhere in this pathname.
136	 *  Search backwards for it, to find the file's parent dir
137	 *  to see if it exists in the alternate tree. If it does,
138	 *  and we want to create a file (cflag is set). We don't
139	 *  need to worry about the root comparison in this case.
140	 */
141
142	if (cflag) {
143		for (cp = &ptr[len] - 1; *cp != '/'; cp--)
144			;
145		*cp = '\0';
146
147		NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, buf, td);
148
149		if ((error = namei(&nd)) != 0) {
150			free(buf, M_TEMP);
151			return error;
152		}
153
154		*cp = '/';
155	} else {
156		NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, buf, td);
157
158		if ((error = namei(&nd)) != 0) {
159			free(buf, M_TEMP);
160			return error;
161		}
162
163		/*
164		 * We now compare the vnode of the ia32_root to the one
165		 * vnode asked. If they resolve to be the same, then we
166		 * ignore the match so that the real root gets used.
167		 * This avoids the problem of traversing "../.." to find the
168		 * root directory and never finding it, because "/" resolves
169		 * to the emulation root directory. This is expensive :-(
170		 */
171		NDINIT(&ndroot, LOOKUP, FOLLOW, UIO_SYSSPACE, ia32_emul_path,
172		    td);
173
174		if ((error = namei(&ndroot)) != 0) {
175			/* Cannot happen! */
176			free(buf, M_TEMP);
177			vrele(nd.ni_vp);
178			return error;
179		}
180
181		ucred = td->td_ucred;
182		if ((error = VOP_GETATTR(nd.ni_vp, &vat, ucred, td)) != 0) {
183			goto bad;
184		}
185
186		if ((error = VOP_GETATTR(ndroot.ni_vp, &vatroot, ucred,
187		    td)) != 0) {
188			goto bad;
189		}
190
191		if (vat.va_fsid == vatroot.va_fsid &&
192		    vat.va_fileid == vatroot.va_fileid) {
193			error = ENOENT;
194			goto bad;
195		}
196
197	}
198	if (sgp == NULL)
199		*pbuf = buf;
200	else {
201		sz = &ptr[len] - buf;
202		*pbuf = stackgap_alloc(sgp, sz + 1);
203		error = copyout(buf, *pbuf, sz);
204		free(buf, M_TEMP);
205	}
206
207	vrele(nd.ni_vp);
208	if (!cflag)
209		vrele(ndroot.ni_vp);
210
211	return error;
212
213bad:
214	vrele(ndroot.ni_vp);
215	vrele(nd.ni_vp);
216	free(buf, M_TEMP);
217	return error;
218}
219
220int
221ia32_open(struct thread *td, struct ia32_open_args *uap)
222{
223	caddr_t sg;
224
225	sg = stackgap_init();
226	CHECKALTEXIST(td, &sg, uap->path);
227
228	return open(td, (struct open_args *) uap);
229}
230
231int
232ia32_wait4(struct thread *td, struct ia32_wait4_args *uap)
233{
234	int error;
235	caddr_t sg;
236	struct rusage32 *rusage32, ru32;
237	struct rusage *rusage = NULL, ru;
238
239	rusage32 = uap->rusage;
240	if (rusage32) {
241		sg = stackgap_init();
242		rusage = stackgap_alloc(&sg, sizeof(struct rusage));
243		uap->rusage = (struct rusage32 *)rusage;
244	}
245	error = wait4(td, (struct wait_args *)uap);
246	if (error)
247		return (error);
248	if (rusage32 && (error = copyin(rusage, &ru, sizeof(ru)) == 0)) {
249		TV_CP(ru, ru32, ru_utime);
250		TV_CP(ru, ru32, ru_stime);
251		CP(ru, ru32, ru_maxrss);
252		CP(ru, ru32, ru_ixrss);
253		CP(ru, ru32, ru_idrss);
254		CP(ru, ru32, ru_isrss);
255		CP(ru, ru32, ru_minflt);
256		CP(ru, ru32, ru_majflt);
257		CP(ru, ru32, ru_nswap);
258		CP(ru, ru32, ru_inblock);
259		CP(ru, ru32, ru_oublock);
260		CP(ru, ru32, ru_msgsnd);
261		CP(ru, ru32, ru_msgrcv);
262		CP(ru, ru32, ru_nsignals);
263		CP(ru, ru32, ru_nvcsw);
264		CP(ru, ru32, ru_nivcsw);
265		error = copyout(&ru32, rusage32, sizeof(ru32));
266	}
267	return (error);
268}
269
270static void
271copy_statfs(struct statfs *in, struct statfs32 *out)
272{
273	CP(*in, *out, f_bsize);
274	CP(*in, *out, f_iosize);
275	CP(*in, *out, f_blocks);
276	CP(*in, *out, f_bfree);
277	CP(*in, *out, f_bavail);
278	CP(*in, *out, f_files);
279	CP(*in, *out, f_ffree);
280	CP(*in, *out, f_fsid);
281	CP(*in, *out, f_owner);
282	CP(*in, *out, f_type);
283	CP(*in, *out, f_flags);
284	CP(*in, *out, f_flags);
285	CP(*in, *out, f_syncwrites);
286	CP(*in, *out, f_asyncwrites);
287	bcopy(in->f_fstypename,
288	      out->f_fstypename, MFSNAMELEN);
289	bcopy(in->f_mntonname,
290	      out->f_mntonname, MNAMELEN);
291	CP(*in, *out, f_syncreads);
292	CP(*in, *out, f_asyncreads);
293	bcopy(in->f_mntfromname,
294	      out->f_mntfromname, MNAMELEN);
295}
296
297int
298ia32_getfsstat(struct thread *td, struct ia32_getfsstat_args *uap)
299{
300	int error;
301	caddr_t sg;
302	struct statfs32 *sp32, stat32;
303	struct statfs *sp = NULL, stat;
304	int maxcount, count, i;
305
306	sp32 = uap->buf;
307	maxcount = uap->bufsize / sizeof(struct statfs32);
308
309	if (sp32) {
310		sg = stackgap_init();
311		sp = stackgap_alloc(&sg, sizeof(struct statfs) * maxcount);
312		uap->buf = (struct statfs32 *)sp;
313	}
314	error = getfsstat(td, (struct getfsstat_args *) uap);
315	if (sp32 && !error) {
316		count = td->td_retval[0];
317		for (i = 0; i < count; i++) {
318			error = copyin(&sp[i], &stat, sizeof(stat));
319			if (error)
320				return (error);
321			copy_statfs(&stat, &stat32);
322			error = copyout(&stat32, &sp32[i], sizeof(stat32));
323			if (error)
324				return (error);
325		}
326	}
327	return (error);
328}
329
330int
331ia32_access(struct thread *td, struct ia32_access_args *uap)
332{
333	caddr_t sg;
334
335	sg = stackgap_init();
336	CHECKALTEXIST(td, &sg, uap->path);
337
338	return access(td, (struct access_args *)uap);
339}
340
341int
342ia32_chflags(struct thread *td, struct ia32_chflags_args *uap)
343{
344	caddr_t sg;
345
346	sg = stackgap_init();
347	CHECKALTEXIST(td, &sg, uap->path);
348
349	return chflags(td, (struct chflags_args *)uap);
350}
351
352struct sigaltstack32 {
353	u_int32_t	ss_sp;
354	u_int32_t	ss_size;
355	int		ss_flags;
356};
357
358int
359ia32_sigaltstack(struct thread *td, struct ia32_sigaltstack_args *uap)
360{
361	int error;
362	caddr_t sg;
363	struct sigaltstack32 *p32, *op32, s32;
364	struct sigaltstack *p = NULL, *op = NULL, s;
365
366	p32 = uap->ss;
367	if (p32) {
368		sg = stackgap_init();
369		p = stackgap_alloc(&sg, sizeof(struct sigaltstack));
370		uap->ss = (struct sigaltstack32 *)p;
371		error = copyin(p32, &s32, sizeof(s32));
372		if (error)
373			return (error);
374		PTRIN_CP(s32, s, ss_sp);
375		CP(s32, s, ss_size);
376		CP(s32, s, ss_flags);
377		error = copyout(&s, p, sizeof(s));
378		if (error)
379			return (error);
380	}
381	op32 = uap->oss;
382	if (op32) {
383		sg = stackgap_init();
384		op = stackgap_alloc(&sg, sizeof(struct sigaltstack));
385		uap->oss = (struct sigaltstack32 *)op;
386	}
387	error = sigaltstack(td, (struct sigaltstack_args *) uap);
388	if (error)
389		return (error);
390	if (op32) {
391		error = copyin(op, &s, sizeof(s));
392		if (error)
393			return (error);
394		PTROUT_CP(s, s32, ss_sp);
395		CP(s, s32, ss_size);
396		CP(s, s32, ss_flags);
397		error = copyout(&s32, op32, sizeof(s32));
398	}
399	return (error);
400}
401
402int
403ia32_execve(struct thread *td, struct ia32_execve_args *uap)
404{
405	int error;
406	caddr_t sg;
407	struct execve_args ap;
408	u_int32_t *p32, arg;
409	char **p;
410	int count;
411
412	sg = stackgap_init();
413	CHECKALTEXIST(td, &sg, uap->fname);
414	ap.fname = uap->fname;
415
416	if (uap->argv) {
417		count = 0;
418		p32 = uap->argv;
419		do {
420			error = copyin(p32++, &arg, sizeof(arg));
421			if (error)
422				return error;
423			count++;
424		} while (arg != 0);
425		p = stackgap_alloc(&sg, count * sizeof(char *));
426		ap.argv = p;
427		p32 = uap->argv;
428		do {
429			error = copyin(p32++, &arg, sizeof(arg));
430			if (error)
431				return error;
432			*p++ = PTRIN(arg);
433		} while (arg != 0);
434	}
435	if (uap->envv) {
436		count = 0;
437		p32 = uap->envv;
438		do {
439			error = copyin(p32++, &arg, sizeof(arg));
440			if (error)
441				return error;
442			count++;
443		} while (arg != 0);
444		p = stackgap_alloc(&sg, count * sizeof(char *));
445		ap.envv = p;
446		p32 = uap->envv;
447		do {
448			error = copyin(p32++, &arg, sizeof(arg));
449			if (error)
450				return error;
451			*p++ = PTRIN(arg);
452		} while (arg != 0);
453	}
454
455	return execve(td, &ap);
456}
457
458static int
459ia32_mmap_partial(struct thread *td, vm_offset_t start, vm_offset_t end,
460		  int prot, int fd, off_t pos)
461{
462	vm_map_t map;
463	vm_map_entry_t entry;
464	int rv;
465
466	map = &td->td_proc->p_vmspace->vm_map;
467	if (fd != -1)
468		prot |= VM_PROT_WRITE;
469
470	if (vm_map_lookup_entry(map, start, &entry)) {
471		if ((entry->protection & prot) != prot) {
472			rv = vm_map_protect(map,
473					    trunc_page(start),
474					    round_page(end),
475					    entry->protection | prot,
476					    FALSE);
477			if (rv != KERN_SUCCESS)
478				return (EINVAL);
479		}
480	} else {
481		vm_offset_t addr = trunc_page(start);
482		rv = vm_map_find(map, 0, 0,
483				 &addr, PAGE_SIZE, FALSE, prot,
484				 VM_PROT_ALL, 0);
485		if (rv != KERN_SUCCESS)
486			return (EINVAL);
487	}
488
489	if (fd != -1) {
490		struct pread_args r;
491		r.fd = fd;
492		r.buf = (void *) start;
493		r.nbyte = end - start;
494		r.offset = pos;
495		return (pread(td, &r));
496	} else {
497		while (start < end) {
498			subyte((void *) start, 0);
499			start++;
500		}
501		return (0);
502	}
503}
504
505int
506ia32_mmap(struct thread *td, struct ia32_mmap_args *uap)
507{
508	struct mmap_args ap;
509	vm_offset_t addr = (vm_offset_t) uap->addr;
510	vm_size_t len	 = uap->len;
511	int prot	 = uap->prot;
512	int flags	 = uap->flags;
513	int fd		 = uap->fd;
514	off_t pos	 = (uap->poslo
515			    | ((off_t)uap->poshi << 32));
516	vm_size_t pageoff;
517	int error;
518
519	/*
520	 * Attempt to handle page size hassles.
521	 */
522	pageoff = (pos & PAGE_MASK);
523	if (flags & MAP_FIXED) {
524		vm_offset_t start, end;
525		start = addr;
526		end = addr + len;
527
528		if (start != trunc_page(start)) {
529			error = ia32_mmap_partial(td, start, round_page(start),
530						  prot, fd, pos);
531			if (fd != -1)
532				pos += round_page(start) - start;
533			start = round_page(start);
534		}
535		if (end != round_page(end)) {
536			vm_offset_t t = trunc_page(end);
537			error = ia32_mmap_partial(td, t, end,
538						  prot, fd,
539						  pos + t - start);
540			end = trunc_page(end);
541		}
542		if (end > start && fd != -1 && (pos & PAGE_MASK)) {
543			/*
544			 * We can't map this region at all. The specified
545			 * address doesn't have the same alignment as the file
546			 * position. Fake the mapping by simply reading the
547			 * entire region into memory. First we need to make
548			 * sure the region exists.
549			 */
550			vm_map_t map;
551			struct pread_args r;
552			int rv;
553
554			prot |= VM_PROT_WRITE;
555			map = &td->td_proc->p_vmspace->vm_map;
556			rv = vm_map_remove(map, start, end);
557			if (rv != KERN_SUCCESS)
558				return (EINVAL);
559			rv = vm_map_find(map, 0, 0,
560					 &start, end - start, FALSE,
561					 prot, VM_PROT_ALL, 0);
562			if (rv != KERN_SUCCESS)
563				return (EINVAL);
564			r.fd = fd;
565			r.buf = (void *) start;
566			r.nbyte = end - start;
567			r.offset = pos;
568			error = pread(td, &r);
569			if (error)
570				return (error);
571
572			td->td_retval[0] = addr;
573			return (0);
574		}
575		if (end == start) {
576			/*
577			 * After dealing with the ragged ends, there
578			 * might be none left.
579			 */
580			td->td_retval[0] = addr;
581			return (0);
582		}
583		addr = start;
584		len = end - start;
585	}
586
587	ap.addr = (void *) addr;
588	ap.len = len;
589	ap.prot = prot;
590	ap.flags = flags;
591	ap.fd = fd;
592	ap.pos = pos;
593
594	return (mmap(td, &ap));
595}
596
597struct itimerval32 {
598	struct timeval32 it_interval;
599	struct timeval32 it_value;
600};
601
602int
603ia32_setitimer(struct thread *td, struct ia32_setitimer_args *uap)
604{
605	int error;
606	caddr_t sg;
607	struct itimerval32 *p32, *op32, s32;
608	struct itimerval *p = NULL, *op = NULL, s;
609
610	p32 = uap->itv;
611	if (p32) {
612		sg = stackgap_init();
613		p = stackgap_alloc(&sg, sizeof(struct itimerval));
614		uap->itv = (struct itimerval32 *)p;
615		error = copyin(p32, &s32, sizeof(s32));
616		if (error)
617			return (error);
618		TV_CP(s32, s, it_interval);
619		TV_CP(s32, s, it_value);
620		error = copyout(&s, p, sizeof(s));
621		if (error)
622			return (error);
623	}
624	op32 = uap->oitv;
625	if (op32) {
626		sg = stackgap_init();
627		op = stackgap_alloc(&sg, sizeof(struct itimerval));
628		uap->oitv = (struct itimerval32 *)op;
629	}
630	error = setitimer(td, (struct setitimer_args *) uap);
631	if (error)
632		return (error);
633	if (op32) {
634		error = copyin(op, &s, sizeof(s));
635		if (error)
636			return (error);
637		TV_CP(s, s32, it_interval);
638		TV_CP(s, s32, it_value);
639		error = copyout(&s32, op32, sizeof(s32));
640	}
641	return (error);
642}
643
644int
645ia32_select(struct thread *td, struct ia32_select_args *uap)
646{
647	int error;
648	caddr_t sg;
649	struct timeval32 *p32, s32;
650	struct timeval *p = NULL, s;
651
652	p32 = uap->tv;
653	if (p32) {
654		sg = stackgap_init();
655		p = stackgap_alloc(&sg, sizeof(struct timeval));
656		uap->tv = (struct timeval32 *)p;
657		error = copyin(p32, &s32, sizeof(s32));
658		if (error)
659			return (error);
660		CP(s32, s, tv_sec);
661		CP(s32, s, tv_usec);
662		error = copyout(&s, p, sizeof(s));
663		if (error)
664			return (error);
665	}
666	/*
667	 * XXX big-endian needs to convert the fd_sets too.
668	 */
669	return (select(td, (struct select_args *) uap));
670}
671
672int
673ia32_gettimeofday(struct thread *td, struct ia32_gettimeofday_args *uap)
674{
675	int error;
676	caddr_t sg;
677	struct timeval32 *p32, s32;
678	struct timeval *p = NULL, s;
679
680	p32 = uap->tp;
681	if (p32) {
682		sg = stackgap_init();
683		p = stackgap_alloc(&sg, sizeof(struct timeval));
684		uap->tp = (struct timeval32 *)p;
685	}
686	error = gettimeofday(td, (struct gettimeofday_args *) uap);
687	if (error)
688		return (error);
689	if (p32) {
690		error = copyin(p, &s, sizeof(s));
691		if (error)
692			return (error);
693		CP(s, s32, tv_sec);
694		CP(s, s32, tv_usec);
695		error = copyout(&s32, p32, sizeof(s32));
696		if (error)
697			return (error);
698	}
699	return (error);
700}
701
702int
703ia32_getrusage(struct thread *td, struct ia32_getrusage_args *uap)
704{
705	int error;
706	caddr_t sg;
707	struct rusage32 *p32, s32;
708	struct rusage *p = NULL, s;
709
710	p32 = uap->rusage;
711	if (p32) {
712		sg = stackgap_init();
713		p = stackgap_alloc(&sg, sizeof(struct rusage));
714		uap->rusage = (struct rusage32 *)p;
715	}
716	error = getrusage(td, (struct getrusage_args *) uap);
717	if (error)
718		return (error);
719	if (p32) {
720		error = copyin(p, &s, sizeof(s));
721		if (error)
722			return (error);
723		TV_CP(s, s32, ru_utime);
724		TV_CP(s, s32, ru_stime);
725		CP(s, s32, ru_maxrss);
726		CP(s, s32, ru_ixrss);
727		CP(s, s32, ru_idrss);
728		CP(s, s32, ru_isrss);
729		CP(s, s32, ru_minflt);
730		CP(s, s32, ru_majflt);
731		CP(s, s32, ru_nswap);
732		CP(s, s32, ru_inblock);
733		CP(s, s32, ru_oublock);
734		CP(s, s32, ru_msgsnd);
735		CP(s, s32, ru_msgrcv);
736		CP(s, s32, ru_nsignals);
737		CP(s, s32, ru_nvcsw);
738		CP(s, s32, ru_nivcsw);
739		error = copyout(&s32, p32, sizeof(s32));
740	}
741	return (error);
742}
743
744struct iovec32 {
745	u_int32_t iov_base;
746	int	iov_len;
747};
748#define	STACKGAPLEN	400
749
750int
751ia32_readv(struct thread *td, struct ia32_readv_args *uap)
752{
753	int error, osize, nsize, i;
754	caddr_t sg;
755	struct readv_args /* {
756		syscallarg(int) fd;
757		syscallarg(struct iovec *) iovp;
758		syscallarg(u_int) iovcnt;
759	} */ a;
760	struct iovec32 *oio;
761	struct iovec *nio;
762
763	sg = stackgap_init();
764
765	if (uap->iovcnt > (STACKGAPLEN / sizeof (struct iovec)))
766		return (EINVAL);
767
768	osize = uap->iovcnt * sizeof (struct iovec32);
769	nsize = uap->iovcnt * sizeof (struct iovec);
770
771	oio = malloc(osize, M_TEMP, M_WAITOK);
772	nio = malloc(nsize, M_TEMP, M_WAITOK);
773
774	error = 0;
775	if ((error = copyin(uap->iovp, oio, osize)))
776		goto punt;
777	for (i = 0; i < uap->iovcnt; i++) {
778		nio[i].iov_base = PTRIN(oio[i].iov_base);
779		nio[i].iov_len = oio[i].iov_len;
780	}
781
782	a.fd = uap->fd;
783	a.iovp = stackgap_alloc(&sg, nsize);
784	a.iovcnt = uap->iovcnt;
785
786	if ((error = copyout(nio, (caddr_t)a.iovp, nsize)))
787		goto punt;
788	error = readv(td, &a);
789
790punt:
791	free(oio, M_TEMP);
792	free(nio, M_TEMP);
793	return (error);
794}
795
796int
797ia32_writev(struct thread *td, struct ia32_writev_args *uap)
798{
799	int error, i, nsize, osize;
800	caddr_t sg;
801	struct writev_args /* {
802		syscallarg(int) fd;
803		syscallarg(struct iovec *) iovp;
804		syscallarg(u_int) iovcnt;
805	} */ a;
806	struct iovec32 *oio;
807	struct iovec *nio;
808
809	sg = stackgap_init();
810
811	if (uap->iovcnt > (STACKGAPLEN / sizeof (struct iovec)))
812		return (EINVAL);
813
814	osize = uap->iovcnt * sizeof (struct iovec32);
815	nsize = uap->iovcnt * sizeof (struct iovec);
816
817	oio = malloc(osize, M_TEMP, M_WAITOK);
818	nio = malloc(nsize, M_TEMP, M_WAITOK);
819
820	error = 0;
821	if ((error = copyin(uap->iovp, oio, osize)))
822		goto punt;
823	for (i = 0; i < uap->iovcnt; i++) {
824		nio[i].iov_base = PTRIN(oio[i].iov_base);
825		nio[i].iov_len = oio[i].iov_len;
826	}
827
828	a.fd = uap->fd;
829	a.iovp = stackgap_alloc(&sg, nsize);
830	a.iovcnt = uap->iovcnt;
831
832	if ((error = copyout(nio, (caddr_t)a.iovp, nsize)))
833		goto punt;
834	error = writev(td, &a);
835
836punt:
837	free(oio, M_TEMP);
838	free(nio, M_TEMP);
839	return (error);
840}
841
842int
843ia32_settimeofday(struct thread *td, struct ia32_settimeofday_args *uap)
844{
845	int error;
846	caddr_t sg;
847	struct timeval32 *p32, s32;
848	struct timeval *p = NULL, s;
849
850	p32 = uap->tv;
851	if (p32) {
852		sg = stackgap_init();
853		p = stackgap_alloc(&sg, sizeof(struct timeval));
854		uap->tv = (struct timeval32 *)p;
855		error = copyin(p32, &s32, sizeof(s32));
856		if (error)
857			return (error);
858		CP(s32, s, tv_sec);
859		CP(s32, s, tv_usec);
860		error = copyout(&s, p, sizeof(s));
861		if (error)
862			return (error);
863	}
864	return (settimeofday(td, (struct settimeofday_args *) uap));
865}
866
867int
868ia32_utimes(struct thread *td, struct ia32_utimes_args *uap)
869{
870	int error;
871	caddr_t sg;
872	struct timeval32 *p32, s32[2];
873	struct timeval *p = NULL, s[2];
874
875	p32 = uap->tptr;
876	if (p32) {
877		sg = stackgap_init();
878		p = stackgap_alloc(&sg, 2*sizeof(struct timeval));
879		uap->tptr = (struct timeval32 *)p;
880		error = copyin(p32, s32, sizeof(s32));
881		if (error)
882			return (error);
883		CP(s32[0], s[0], tv_sec);
884		CP(s32[0], s[0], tv_usec);
885		CP(s32[1], s[1], tv_sec);
886		CP(s32[1], s[1], tv_usec);
887		error = copyout(s, p, sizeof(s));
888		if (error)
889			return (error);
890	}
891	return (utimes(td, (struct utimes_args *) uap));
892}
893
894int
895ia32_adjtime(struct thread *td, struct ia32_adjtime_args *uap)
896{
897	int error;
898	caddr_t sg;
899	struct timeval32 *p32, *op32, s32;
900	struct timeval *p = NULL, *op = NULL, s;
901
902	p32 = uap->delta;
903	if (p32) {
904		sg = stackgap_init();
905		p = stackgap_alloc(&sg, sizeof(struct timeval));
906		uap->delta = (struct timeval32 *)p;
907		error = copyin(p32, &s32, sizeof(s32));
908		if (error)
909			return (error);
910		CP(s32, s, tv_sec);
911		CP(s32, s, tv_usec);
912		error = copyout(&s, p, sizeof(s));
913		if (error)
914			return (error);
915	}
916	op32 = uap->olddelta;
917	if (op32) {
918		sg = stackgap_init();
919		op = stackgap_alloc(&sg, sizeof(struct timeval));
920		uap->olddelta = (struct timeval32 *)op;
921	}
922	error = utimes(td, (struct utimes_args *) uap);
923	if (error)
924		return error;
925	if (op32) {
926		error = copyin(op, &s, sizeof(s));
927		if (error)
928			return (error);
929		CP(s, s32, tv_sec);
930		CP(s, s32, tv_usec);
931		error = copyout(&s32, op32, sizeof(s32));
932	}
933	return (error);
934}
935
936int
937ia32_statfs(struct thread *td, struct ia32_statfs_args *uap)
938{
939	int error;
940	caddr_t sg;
941	struct statfs32 *p32, s32;
942	struct statfs *p = NULL, s;
943
944	p32 = uap->buf;
945	if (p32) {
946		sg = stackgap_init();
947		p = stackgap_alloc(&sg, sizeof(struct statfs));
948		uap->buf = (struct statfs32 *)p;
949	}
950	error = statfs(td, (struct statfs_args *) uap);
951	if (error)
952		return (error);
953	if (p32) {
954		error = copyin(p, &s, sizeof(s));
955		if (error)
956			return (error);
957		copy_statfs(&s, &s32);
958		error = copyout(&s32, p32, sizeof(s32));
959	}
960	return (error);
961}
962
963int
964ia32_fstatfs(struct thread *td, struct ia32_fstatfs_args *uap)
965{
966	int error;
967	caddr_t sg;
968	struct statfs32 *p32, s32;
969	struct statfs *p = NULL, s;
970
971	p32 = uap->buf;
972	if (p32) {
973		sg = stackgap_init();
974		p = stackgap_alloc(&sg, sizeof(struct statfs));
975		uap->buf = (struct statfs32 *)p;
976	}
977	error = fstatfs(td, (struct fstatfs_args *) uap);
978	if (error)
979		return (error);
980	if (p32) {
981		error = copyin(p, &s, sizeof(s));
982		if (error)
983			return (error);
984		copy_statfs(&s, &s32);
985		error = copyout(&s32, p32, sizeof(s32));
986	}
987	return (error);
988}
989
990int
991ia32_semsys(struct thread *td, struct ia32_semsys_args *uap)
992{
993	/*
994	 * Vector through to semsys if it is loaded.
995	 */
996	return sysent[169].sy_call(td, uap);
997}
998
999int
1000ia32_msgsys(struct thread *td, struct ia32_msgsys_args *uap)
1001{
1002	/*
1003	 * Vector through to msgsys if it is loaded.
1004	 */
1005	return sysent[170].sy_call(td, uap);
1006}
1007
1008int
1009ia32_shmsys(struct thread *td, struct ia32_shmsys_args *uap)
1010{
1011	/*
1012	 * Vector through to shmsys if it is loaded.
1013	 */
1014	return sysent[171].sy_call(td, uap);
1015}
1016
1017int
1018ia32_pread(struct thread *td, struct ia32_pread_args *uap)
1019{
1020	struct pread_args ap;
1021
1022	ap.fd = uap->fd;
1023	ap.buf = uap->buf;
1024	ap.nbyte = uap->nbyte;
1025	ap.offset = (uap->offsetlo
1026			      | ((off_t)uap->offsethi << 32));
1027	return (pread(td, &ap));
1028}
1029
1030int
1031ia32_pwrite(struct thread *td, struct ia32_pwrite_args *uap)
1032{
1033	struct pwrite_args ap;
1034
1035	ap.fd = uap->fd;
1036	ap.buf = uap->buf;
1037	ap.nbyte = uap->nbyte;
1038	ap.offset = (uap->offsetlo
1039			      | ((off_t)uap->offsethi << 32));
1040	return (pwrite(td, &ap));
1041}
1042
1043int
1044ia32_lseek(struct thread *td, struct ia32_lseek_args *uap)
1045{
1046	int error;
1047	struct lseek_args ap;
1048	off_t pos;
1049
1050	ap.fd = uap->fd;
1051	ap.offset = (uap->offsetlo
1052			      | ((off_t)uap->offsethi << 32));
1053	ap.whence = uap->whence;
1054	error = lseek(td, &ap);
1055	/* Expand the quad return into two parts for eax and edx */
1056	pos = *(off_t *)(td->td_retval);
1057	td->td_retval[0] = pos & 0xffffffff;	/* %eax */
1058	td->td_retval[1] = pos >> 32;		/* %edx */
1059	return error;
1060}
1061
1062int
1063ia32_truncate(struct thread *td, struct ia32_truncate_args *uap)
1064{
1065	struct truncate_args ap;
1066
1067	ap.path = uap->path;
1068	ap.length = (uap->lengthlo
1069			      | ((off_t)uap->lengthhi << 32));
1070	return (truncate(td, &ap));
1071}
1072
1073int
1074ia32_ftruncate(struct thread *td, struct ia32_ftruncate_args *uap)
1075{
1076	struct ftruncate_args ap;
1077
1078	ap.fd = uap->fd;
1079	ap.length = (uap->lengthlo
1080			      | ((off_t)uap->lengthhi << 32));
1081	return (ftruncate(td, &ap));
1082}
1083
1084#ifdef COMPAT_FREEBSD4
1085int
1086freebsd4_ia32_sendfile(struct thread *td,
1087    struct freebsd4_ia32_sendfile_args *uap)
1088{
1089	struct freebsd4_sendfile_args ap;
1090
1091	ap.fd = uap->fd;
1092	ap.s = uap->s;
1093	ap.offset = (uap->offsetlo
1094			      | ((off_t)uap->offsethi << 32));
1095	ap.nbytes = uap->nbytes;	/* XXX check */
1096	ap.hdtr = uap->hdtr;		/* XXX check */
1097	ap.sbytes = uap->sbytes;	/* XXX FIXME!! */
1098	ap.flags = uap->flags;
1099	return (freebsd4_sendfile(td, &ap));
1100}
1101#endif
1102
1103int
1104ia32_sendfile(struct thread *td, struct ia32_sendfile_args *uap)
1105{
1106	struct sendfile_args ap;
1107
1108	ap.fd = uap->fd;
1109	ap.s = uap->s;
1110	ap.offset = (uap->offsetlo
1111			      | ((off_t)uap->offsethi << 32));
1112	ap.nbytes = uap->nbytes;	/* XXX check */
1113	ap.hdtr = uap->hdtr;		/* XXX check */
1114	ap.sbytes = uap->sbytes;	/* XXX FIXME!! */
1115	ap.flags = uap->flags;
1116	return (sendfile(td, &ap));
1117}
1118
1119struct stat32 {
1120	udev_t	st_dev;
1121	ino_t	st_ino;
1122	mode_t	st_mode;
1123	nlink_t	st_nlink;
1124	uid_t	st_uid;
1125	gid_t	st_gid;
1126	udev_t	st_rdev;
1127	struct timespec32 st_atimespec;
1128	struct timespec32 st_mtimespec;
1129	struct timespec32 st_ctimespec;
1130	off_t	st_size;
1131	int64_t	st_blocks;
1132	u_int32_t st_blksize;
1133	u_int32_t st_flags;
1134	u_int32_t st_gen;
1135};
1136
1137static void
1138copy_stat( struct stat *in, struct stat32 *out)
1139{
1140	CP(*in, *out, st_dev);
1141	CP(*in, *out, st_ino);
1142	CP(*in, *out, st_mode);
1143	CP(*in, *out, st_nlink);
1144	CP(*in, *out, st_uid);
1145	CP(*in, *out, st_gid);
1146	CP(*in, *out, st_rdev);
1147	TS_CP(*in, *out, st_atimespec);
1148	TS_CP(*in, *out, st_mtimespec);
1149	TS_CP(*in, *out, st_ctimespec);
1150	CP(*in, *out, st_size);
1151	CP(*in, *out, st_blocks);
1152	CP(*in, *out, st_blksize);
1153	CP(*in, *out, st_flags);
1154	CP(*in, *out, st_gen);
1155}
1156
1157int
1158ia32_stat(struct thread *td, struct ia32_stat_args *uap)
1159{
1160	int error;
1161	caddr_t sg;
1162	struct stat32 *p32, s32;
1163	struct stat *p = NULL, s;
1164
1165	p32 = uap->ub;
1166	if (p32) {
1167		sg = stackgap_init();
1168		p = stackgap_alloc(&sg, sizeof(struct stat));
1169		uap->ub = (struct stat32 *)p;
1170	}
1171	error = stat(td, (struct stat_args *) uap);
1172	if (error)
1173		return (error);
1174	if (p32) {
1175		error = copyin(p, &s, sizeof(s));
1176		if (error)
1177			return (error);
1178		copy_stat(&s, &s32);
1179		error = copyout(&s32, p32, sizeof(s32));
1180	}
1181	return (error);
1182}
1183
1184int
1185ia32_fstat(struct thread *td, struct ia32_fstat_args *uap)
1186{
1187	int error;
1188	caddr_t sg;
1189	struct stat32 *p32, s32;
1190	struct stat *p = NULL, s;
1191
1192	p32 = uap->ub;
1193	if (p32) {
1194		sg = stackgap_init();
1195		p = stackgap_alloc(&sg, sizeof(struct stat));
1196		uap->ub = (struct stat32 *)p;
1197	}
1198	error = fstat(td, (struct fstat_args *) uap);
1199	if (error)
1200		return (error);
1201	if (p32) {
1202		error = copyin(p, &s, sizeof(s));
1203		if (error)
1204			return (error);
1205		copy_stat(&s, &s32);
1206		error = copyout(&s32, p32, sizeof(s32));
1207	}
1208	return (error);
1209}
1210
1211int
1212ia32_lstat(struct thread *td, struct ia32_lstat_args *uap)
1213{
1214	int error;
1215	caddr_t sg;
1216	struct stat32 *p32, s32;
1217	struct stat *p = NULL, s;
1218
1219	p32 = uap->ub;
1220	if (p32) {
1221		sg = stackgap_init();
1222		p = stackgap_alloc(&sg, sizeof(struct stat));
1223		uap->ub = (struct stat32 *)p;
1224	}
1225	error = lstat(td, (struct lstat_args *) uap);
1226	if (error)
1227		return (error);
1228	if (p32) {
1229		error = copyin(p, &s, sizeof(s));
1230		if (error)
1231			return (error);
1232		copy_stat(&s, &s32);
1233		error = copyout(&s32, p32, sizeof(s32));
1234	}
1235	return (error);
1236}
1237
1238/*
1239 * MPSAFE
1240 */
1241int
1242ia32_sysctl(struct thread *td, struct ia32_sysctl_args *uap)
1243{
1244	int error, name[CTL_MAXNAME];
1245	size_t j, oldlen;
1246
1247	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
1248		return (EINVAL);
1249
1250 	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
1251 	if (error)
1252		return (error);
1253
1254	mtx_lock(&Giant);
1255
1256	if (uap->oldlenp)
1257		oldlen = fuword32(uap->oldlenp);
1258	else
1259		oldlen = 0;
1260	error = userland_sysctl(td, name, uap->namelen,
1261		uap->old, &oldlen, 1,
1262		uap->new, uap->newlen, &j);
1263	if (error && error != ENOMEM)
1264		goto done2;
1265	if (uap->oldlenp) {
1266		suword32(uap->oldlenp, j);
1267	}
1268done2:
1269	mtx_unlock(&Giant);
1270	return (error);
1271}
1272
1273struct sigaction32 {
1274	u_int32_t	sa_u;
1275	int		sa_flags;
1276	sigset_t	sa_mask;
1277};
1278
1279int
1280ia32_sigaction(struct thread *td, struct ia32_sigaction_args *uap)
1281{
1282	int error;
1283	caddr_t sg;
1284	struct sigaction32 *p32, *op32, s32;
1285	struct sigaction *p = NULL, *op = NULL, s;
1286
1287	p32 = uap->act;
1288	if (p32) {
1289		sg = stackgap_init();
1290		p = stackgap_alloc(&sg, sizeof(struct sigaction));
1291		uap->act = (struct sigaction32 *)p;
1292		error = copyin(p32, &s32, sizeof(s32));
1293		if (error)
1294			return (error);
1295		s.sa_handler = PTRIN(s32.sa_u);
1296		CP(s32, s, sa_flags);
1297		CP(s32, s, sa_mask);
1298		error = copyout(&s, p, sizeof(s));
1299		if (error)
1300			return (error);
1301	}
1302	op32 = uap->oact;
1303	if (op32) {
1304		sg = stackgap_init();
1305		op = stackgap_alloc(&sg, sizeof(struct sigaction));
1306		uap->oact = (struct sigaction32 *)op;
1307	}
1308	error = sigaction(td, (struct sigaction_args *) uap);
1309	if (error)
1310		return (error);
1311	if (op32) {
1312		error = copyin(op, &s, sizeof(s));
1313		if (error)
1314			return (error);
1315		s32.sa_u = PTROUT(s.sa_handler);
1316		CP(s, s32, sa_flags);
1317		CP(s, s32, sa_mask);
1318		error = copyout(&s32, op32, sizeof(s32));
1319	}
1320	return (error);
1321}
1322
1323#if 0
1324
1325int
1326ia32_xxx(struct thread *td, struct ia32_xxx_args *uap)
1327{
1328	int error;
1329	caddr_t sg;
1330	struct yyy32 *p32, s32;
1331	struct yyy *p = NULL, s;
1332
1333	p32 = uap->zzz;
1334	if (p32) {
1335		sg = stackgap_init();
1336		p = stackgap_alloc(&sg, sizeof(struct yyy));
1337		uap->zzz = (struct yyy32 *)p;
1338		error = copyin(p32, &s32, sizeof(s32));
1339		if (error)
1340			return (error);
1341		/* translate in */
1342		error = copyout(&s, p, sizeof(s));
1343		if (error)
1344			return (error);
1345	}
1346	error = xxx(td, (struct xxx_args *) uap);
1347	if (error)
1348		return (error);
1349	if (p32) {
1350		error = copyin(p, &s, sizeof(s));
1351		if (error)
1352			return (error);
1353		/* translate out */
1354		error = copyout(&s32, p32, sizeof(s32));
1355	}
1356	return (error);
1357}
1358
1359#endif
1360