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