freebsd32_misc.c revision 125171
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
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/compat/freebsd32/freebsd32_misc.c 125171 2004-01-28 23:45:48Z peter $");
29
30#include "opt_compat.h"
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/bus.h>
35#include <sys/exec.h>
36#include <sys/fcntl.h>
37#include <sys/filedesc.h>
38#include <sys/namei.h>
39#include <sys/imgact.h>
40#include <sys/kernel.h>
41#include <sys/lock.h>
42#include <sys/malloc.h>
43#include <sys/file.h>		/* Must come after sys/malloc.h */
44#include <sys/mman.h>
45#include <sys/module.h>
46#include <sys/mount.h>
47#include <sys/mutex.h>
48#include <sys/namei.h>
49#include <sys/param.h>
50#include <sys/proc.h>
51#include <sys/reboot.h>
52#include <sys/resource.h>
53#include <sys/resourcevar.h>
54#include <sys/selinfo.h>
55#include <sys/pipe.h>		/* Must come after sys/selinfo.h */
56#include <sys/signal.h>
57#include <sys/signalvar.h>
58#include <sys/socket.h>
59#include <sys/socketvar.h>
60#include <sys/stat.h>
61#include <sys/syscallsubr.h>
62#include <sys/sysctl.h>
63#include <sys/sysent.h>
64#include <sys/sysproto.h>
65#include <sys/systm.h>
66#include <sys/unistd.h>
67#include <sys/user.h>
68#include <sys/utsname.h>
69#include <sys/vnode.h>
70
71#include <vm/vm.h>
72#include <vm/vm_kern.h>
73#include <vm/vm_param.h>
74#include <vm/pmap.h>
75#include <vm/vm_map.h>
76#include <vm/vm_object.h>
77#include <vm/vm_extern.h>
78
79#include <compat/freebsd32/freebsd32_util.h>
80#include <compat/freebsd32/freebsd32.h>
81#include <compat/freebsd32/freebsd32_proto.h>
82
83CTASSERT(sizeof(struct timeval32) == 8);
84CTASSERT(sizeof(struct timespec32) == 8);
85CTASSERT(sizeof(struct statfs32) == 256);
86CTASSERT(sizeof(struct rusage32) == 72);
87
88int
89freebsd32_wait4(struct thread *td, struct freebsd32_wait4_args *uap)
90{
91	int error;
92	caddr_t sg;
93	struct rusage32 *rusage32, ru32;
94	struct rusage *rusage = NULL, ru;
95
96	rusage32 = uap->rusage;
97	if (rusage32) {
98		sg = stackgap_init();
99		rusage = stackgap_alloc(&sg, sizeof(struct rusage));
100		uap->rusage = (struct rusage32 *)rusage;
101	}
102	error = wait4(td, (struct wait_args *)uap);
103	if (error)
104		return (error);
105	if (rusage32 && (error = copyin(rusage, &ru, sizeof(ru)) == 0)) {
106		TV_CP(ru, ru32, ru_utime);
107		TV_CP(ru, ru32, ru_stime);
108		CP(ru, ru32, ru_maxrss);
109		CP(ru, ru32, ru_ixrss);
110		CP(ru, ru32, ru_idrss);
111		CP(ru, ru32, ru_isrss);
112		CP(ru, ru32, ru_minflt);
113		CP(ru, ru32, ru_majflt);
114		CP(ru, ru32, ru_nswap);
115		CP(ru, ru32, ru_inblock);
116		CP(ru, ru32, ru_oublock);
117		CP(ru, ru32, ru_msgsnd);
118		CP(ru, ru32, ru_msgrcv);
119		CP(ru, ru32, ru_nsignals);
120		CP(ru, ru32, ru_nvcsw);
121		CP(ru, ru32, ru_nivcsw);
122		error = copyout(&ru32, rusage32, sizeof(ru32));
123	}
124	return (error);
125}
126
127static void
128copy_statfs(struct statfs *in, struct statfs32 *out)
129{
130	CP(*in, *out, f_bsize);
131	CP(*in, *out, f_iosize);
132	CP(*in, *out, f_blocks);
133	CP(*in, *out, f_bfree);
134	CP(*in, *out, f_bavail);
135	CP(*in, *out, f_files);
136	CP(*in, *out, f_ffree);
137	CP(*in, *out, f_fsid);
138	CP(*in, *out, f_owner);
139	CP(*in, *out, f_type);
140	CP(*in, *out, f_flags);
141	CP(*in, *out, f_flags);
142	CP(*in, *out, f_syncwrites);
143	CP(*in, *out, f_asyncwrites);
144	bcopy(in->f_fstypename,
145	      out->f_fstypename, MFSNAMELEN);
146	bcopy(in->f_mntonname,
147	      out->f_mntonname, MNAMELEN);
148	CP(*in, *out, f_syncreads);
149	CP(*in, *out, f_asyncreads);
150	bcopy(in->f_mntfromname,
151	      out->f_mntfromname, MNAMELEN);
152}
153
154int
155freebsd32_getfsstat(struct thread *td, struct freebsd32_getfsstat_args *uap)
156{
157	int error;
158	caddr_t sg;
159	struct statfs32 *sp32, stat32;
160	struct statfs *sp = NULL, stat;
161	int maxcount, count, i;
162
163	sp32 = uap->buf;
164	maxcount = uap->bufsize / sizeof(struct statfs32);
165
166	if (sp32) {
167		sg = stackgap_init();
168		sp = stackgap_alloc(&sg, sizeof(struct statfs) * maxcount);
169		uap->buf = (struct statfs32 *)sp;
170	}
171	error = getfsstat(td, (struct getfsstat_args *) uap);
172	if (sp32 && !error) {
173		count = td->td_retval[0];
174		for (i = 0; i < count; i++) {
175			error = copyin(&sp[i], &stat, sizeof(stat));
176			if (error)
177				return (error);
178			copy_statfs(&stat, &stat32);
179			error = copyout(&stat32, &sp32[i], sizeof(stat32));
180			if (error)
181				return (error);
182		}
183	}
184	return (error);
185}
186
187struct sigaltstack32 {
188	u_int32_t	ss_sp;
189	u_int32_t	ss_size;
190	int		ss_flags;
191};
192
193CTASSERT(sizeof(struct sigaltstack32) == 12);
194
195int
196freebsd32_sigaltstack(struct thread *td,
197		      struct freebsd32_sigaltstack_args *uap)
198{
199	struct sigaltstack32 s32;
200	struct sigaltstack ss, oss, *ssp;
201	int error;
202
203	if (uap->ss != NULL) {
204		error = copyin(uap->ss, &s32, sizeof(s32));
205		if (error)
206			return (error);
207		PTRIN_CP(s32, ss, ss_sp);
208		CP(s32, ss, ss_size);
209		CP(s32, ss, ss_flags);
210		ssp = &ss;
211	} else
212		ssp = NULL;
213	error = kern_sigaltstack(td, ssp, &oss);
214	if (error == 0 && uap->oss != NULL) {
215		PTROUT_CP(oss, s32, ss_sp);
216		CP(oss, s32, ss_size);
217		CP(oss, s32, ss_flags);
218		error = copyout(&s32, uap->oss, sizeof(s32));
219	}
220	return (error);
221}
222
223int
224freebsd32_execve(struct thread *td, struct freebsd32_execve_args *uap)
225{
226	int error;
227	caddr_t sg;
228	struct execve_args ap;
229	u_int32_t *p32, arg;
230	char **p, *p64;
231	int count;
232
233	sg = stackgap_init();
234	ap.fname = uap->fname;
235
236	if (uap->argv) {
237		count = 0;
238		p32 = uap->argv;
239		do {
240			error = copyin(p32++, &arg, sizeof(arg));
241			if (error)
242				return error;
243			count++;
244		} while (arg != 0);
245		p = stackgap_alloc(&sg, count * sizeof(char *));
246		ap.argv = p;
247		p32 = uap->argv;
248		do {
249			error = copyin(p32++, &arg, sizeof(arg));
250			if (error)
251				return error;
252			p64 = PTRIN(arg);
253			error = copyout(&p64, p++, sizeof(p64));
254			if (error)
255				return error;
256		} while (arg != 0);
257	}
258	if (uap->envv) {
259		count = 0;
260		p32 = uap->envv;
261		do {
262			error = copyin(p32++, &arg, sizeof(arg));
263			if (error)
264				return error;
265			count++;
266		} while (arg != 0);
267		p = stackgap_alloc(&sg, count * sizeof(char *));
268		ap.envv = p;
269		p32 = uap->envv;
270		do {
271			error = copyin(p32++, &arg, sizeof(arg));
272			if (error)
273				return error;
274			p64 = PTRIN(arg);
275			error = copyout(&p64, p++, sizeof(p64));
276			if (error)
277				return error;
278		} while (arg != 0);
279	}
280
281	return execve(td, &ap);
282}
283
284#ifdef __ia64__
285static int
286freebsd32_mmap_partial(struct thread *td, vm_offset_t start, vm_offset_t end,
287		       int prot, int fd, off_t pos)
288{
289	vm_map_t map;
290	vm_map_entry_t entry;
291	int rv;
292
293	map = &td->td_proc->p_vmspace->vm_map;
294	if (fd != -1)
295		prot |= VM_PROT_WRITE;
296
297	if (vm_map_lookup_entry(map, start, &entry)) {
298		if ((entry->protection & prot) != prot) {
299			rv = vm_map_protect(map,
300					    trunc_page(start),
301					    round_page(end),
302					    entry->protection | prot,
303					    FALSE);
304			if (rv != KERN_SUCCESS)
305				return (EINVAL);
306		}
307	} else {
308		vm_offset_t addr = trunc_page(start);
309		rv = vm_map_find(map, 0, 0,
310				 &addr, PAGE_SIZE, FALSE, prot,
311				 VM_PROT_ALL, 0);
312		if (rv != KERN_SUCCESS)
313			return (EINVAL);
314	}
315
316	if (fd != -1) {
317		struct pread_args r;
318		r.fd = fd;
319		r.buf = (void *) start;
320		r.nbyte = end - start;
321		r.offset = pos;
322		return (pread(td, &r));
323	} else {
324		while (start < end) {
325			subyte((void *) start, 0);
326			start++;
327		}
328		return (0);
329	}
330}
331#endif
332
333int
334freebsd32_mmap(struct thread *td, struct freebsd32_mmap_args *uap)
335{
336	struct mmap_args ap;
337	vm_offset_t addr = (vm_offset_t) uap->addr;
338	vm_size_t len	 = uap->len;
339	int prot	 = uap->prot;
340	int flags	 = uap->flags;
341	int fd		 = uap->fd;
342	off_t pos	 = (uap->poslo
343			    | ((off_t)uap->poshi << 32));
344#ifdef __ia64__
345	vm_size_t pageoff;
346	int error;
347
348	/*
349	 * Attempt to handle page size hassles.
350	 */
351	pageoff = (pos & PAGE_MASK);
352	if (flags & MAP_FIXED) {
353		vm_offset_t start, end;
354		start = addr;
355		end = addr + len;
356
357		if (start != trunc_page(start)) {
358			error = freebsd32_mmap_partial(td, start,
359						       round_page(start), prot,
360						       fd, pos);
361			if (fd != -1)
362				pos += round_page(start) - start;
363			start = round_page(start);
364		}
365		if (end != round_page(end)) {
366			vm_offset_t t = trunc_page(end);
367			error = freebsd32_mmap_partial(td, t, end,
368						  prot, fd,
369						  pos + t - start);
370			end = trunc_page(end);
371		}
372		if (end > start && fd != -1 && (pos & PAGE_MASK)) {
373			/*
374			 * We can't map this region at all. The specified
375			 * address doesn't have the same alignment as the file
376			 * position. Fake the mapping by simply reading the
377			 * entire region into memory. First we need to make
378			 * sure the region exists.
379			 */
380			vm_map_t map;
381			struct pread_args r;
382			int rv;
383
384			prot |= VM_PROT_WRITE;
385			map = &td->td_proc->p_vmspace->vm_map;
386			rv = vm_map_remove(map, start, end);
387			if (rv != KERN_SUCCESS)
388				return (EINVAL);
389			rv = vm_map_find(map, 0, 0,
390					 &start, end - start, FALSE,
391					 prot, VM_PROT_ALL, 0);
392			if (rv != KERN_SUCCESS)
393				return (EINVAL);
394			r.fd = fd;
395			r.buf = (void *) start;
396			r.nbyte = end - start;
397			r.offset = pos;
398			error = pread(td, &r);
399			if (error)
400				return (error);
401
402			td->td_retval[0] = addr;
403			return (0);
404		}
405		if (end == start) {
406			/*
407			 * After dealing with the ragged ends, there
408			 * might be none left.
409			 */
410			td->td_retval[0] = addr;
411			return (0);
412		}
413		addr = start;
414		len = end - start;
415	}
416#endif
417
418	ap.addr = (void *) addr;
419	ap.len = len;
420	ap.prot = prot;
421	ap.flags = flags;
422	ap.fd = fd;
423	ap.pos = pos;
424
425	return (mmap(td, &ap));
426}
427
428struct itimerval32 {
429	struct timeval32 it_interval;
430	struct timeval32 it_value;
431};
432
433CTASSERT(sizeof(struct itimerval32) == 16);
434
435int
436freebsd32_setitimer(struct thread *td, struct freebsd32_setitimer_args *uap)
437{
438	int error;
439	caddr_t sg;
440	struct itimerval32 *p32, *op32, s32;
441	struct itimerval *p = NULL, *op = NULL, s;
442
443	p32 = uap->itv;
444	if (p32) {
445		sg = stackgap_init();
446		p = stackgap_alloc(&sg, sizeof(struct itimerval));
447		uap->itv = (struct itimerval32 *)p;
448		error = copyin(p32, &s32, sizeof(s32));
449		if (error)
450			return (error);
451		TV_CP(s32, s, it_interval);
452		TV_CP(s32, s, it_value);
453		error = copyout(&s, p, sizeof(s));
454		if (error)
455			return (error);
456	}
457	op32 = uap->oitv;
458	if (op32) {
459		sg = stackgap_init();
460		op = stackgap_alloc(&sg, sizeof(struct itimerval));
461		uap->oitv = (struct itimerval32 *)op;
462	}
463	error = setitimer(td, (struct setitimer_args *) uap);
464	if (error)
465		return (error);
466	if (op32) {
467		error = copyin(op, &s, sizeof(s));
468		if (error)
469			return (error);
470		TV_CP(s, s32, it_interval);
471		TV_CP(s, s32, it_value);
472		error = copyout(&s32, op32, sizeof(s32));
473	}
474	return (error);
475}
476
477int
478freebsd32_getitimer(struct thread *td, struct freebsd32_getitimer_args *uap)
479{
480	int error;
481	caddr_t sg;
482	struct itimerval32 *p32, s32;
483	struct itimerval *p = NULL, s;
484
485	p32 = uap->itv;
486	if (p32) {
487		sg = stackgap_init();
488		p = stackgap_alloc(&sg, sizeof(struct itimerval));
489		uap->itv = (struct itimerval32 *)p;
490	}
491	error = getitimer(td, (struct getitimer_args *) uap);
492	if (error)
493		return (error);
494	if (p32) {
495		error = copyin(p, &s, sizeof(s));
496		if (error)
497			return (error);
498		TV_CP(s, s32, it_interval);
499		TV_CP(s, s32, it_value);
500		error = copyout(&s32, p32, sizeof(s32));
501	}
502	return (error);
503}
504
505int
506freebsd32_select(struct thread *td, struct freebsd32_select_args *uap)
507{
508	int error;
509	caddr_t sg;
510	struct timeval32 *p32, s32;
511	struct timeval *p = NULL, s;
512
513	p32 = uap->tv;
514	if (p32) {
515		sg = stackgap_init();
516		p = stackgap_alloc(&sg, sizeof(struct timeval));
517		uap->tv = (struct timeval32 *)p;
518		error = copyin(p32, &s32, sizeof(s32));
519		if (error)
520			return (error);
521		CP(s32, s, tv_sec);
522		CP(s32, s, tv_usec);
523		error = copyout(&s, p, sizeof(s));
524		if (error)
525			return (error);
526	}
527	/*
528	 * XXX big-endian needs to convert the fd_sets too.
529	 */
530	return (select(td, (struct select_args *) uap));
531}
532
533struct kevent32 {
534	u_int32_t	ident;		/* identifier for this event */
535	short		filter;		/* filter for event */
536	u_short		flags;
537	u_int		fflags;
538	int32_t		data;
539	u_int32_t	udata;		/* opaque user data identifier */
540};
541
542CTASSERT(sizeof(struct kevent32) == 20);
543
544int
545freebsd32_kevent(struct thread *td, struct freebsd32_kevent_args *uap)
546{
547	int error;
548	caddr_t sg;
549	struct timespec32 ts32;
550	struct timespec ts;
551	struct kevent32 ks32;
552	struct kevent *ks;
553	struct kevent_args a;
554	int i;
555
556	sg = stackgap_init();
557
558	a.fd = uap->fd;
559	a.changelist = uap->changelist;
560	a.nchanges = uap->nchanges;
561	a.eventlist = uap->eventlist;
562	a.nevents = uap->nevents;
563	a.timeout = NULL;
564
565	if (uap->timeout) {
566		a.timeout = stackgap_alloc(&sg, sizeof(struct timespec));
567		error = copyin(uap->timeout, &ts32, sizeof(ts32));
568		if (error)
569			return (error);
570		CP(ts32, ts, tv_sec);
571		CP(ts32, ts, tv_nsec);
572		error = copyout(&ts, (void *)(uintptr_t)a.timeout, sizeof(ts));
573		if (error)
574			return (error);
575	}
576	if (uap->changelist) {
577		a.changelist = (struct kevent *)stackgap_alloc(&sg,
578		    uap->nchanges * sizeof(struct kevent));
579		for (i = 0; i < uap->nchanges; i++) {
580			error = copyin(&uap->changelist[i], &ks32,
581			    sizeof(ks32));
582			if (error)
583				return (error);
584			ks = (struct kevent *)(uintptr_t)&a.changelist[i];
585			CP(ks32, *ks, ident);
586			CP(ks32, *ks, filter);
587			CP(ks32, *ks, flags);
588			CP(ks32, *ks, fflags);
589			CP(ks32, *ks, data);
590			PTRIN_CP(ks32, *ks, udata);
591		}
592	}
593	if (uap->eventlist) {
594		a.eventlist = stackgap_alloc(&sg,
595		    uap->nevents * sizeof(struct kevent));
596	}
597	error = kevent(td, &a);
598	if (uap->eventlist && error > 0) {
599		for (i = 0; i < error; i++) {
600			ks = &a.eventlist[i];
601			CP(*ks, ks32, ident);
602			CP(*ks, ks32, filter);
603			CP(*ks, ks32, flags);
604			CP(*ks, ks32, fflags);
605			CP(*ks, ks32, data);
606			PTROUT_CP(*ks, ks32, udata);
607			error = copyout(&ks32, &uap->eventlist[i],
608			    sizeof(ks32));
609			if (error)
610				return (error);
611		}
612	}
613	return error;
614}
615
616int
617freebsd32_gettimeofday(struct thread *td,
618		       struct freebsd32_gettimeofday_args *uap)
619{
620	struct timeval atv;
621	struct timeval32 atv32;
622	struct timezone rtz;
623	int error = 0;
624
625	if (uap->tp) {
626		microtime(&atv);
627		CP(atv, atv32, tv_sec);
628		CP(atv, atv32, tv_usec);
629		error = copyout(&atv32, uap->tp, sizeof (atv32));
630	}
631	if (error == 0 && uap->tzp != NULL) {
632		rtz.tz_minuteswest = tz_minuteswest;
633		rtz.tz_dsttime = tz_dsttime;
634		error = copyout(&rtz, uap->tzp, sizeof (rtz));
635	}
636	return (error);
637}
638
639int
640freebsd32_getrusage(struct thread *td, struct freebsd32_getrusage_args *uap)
641{
642	int error;
643	caddr_t sg;
644	struct rusage32 *p32, s32;
645	struct rusage *p = NULL, s;
646
647	p32 = uap->rusage;
648	if (p32) {
649		sg = stackgap_init();
650		p = stackgap_alloc(&sg, sizeof(struct rusage));
651		uap->rusage = (struct rusage32 *)p;
652	}
653	error = getrusage(td, (struct getrusage_args *) uap);
654	if (error)
655		return (error);
656	if (p32) {
657		error = copyin(p, &s, sizeof(s));
658		if (error)
659			return (error);
660		TV_CP(s, s32, ru_utime);
661		TV_CP(s, s32, ru_stime);
662		CP(s, s32, ru_maxrss);
663		CP(s, s32, ru_ixrss);
664		CP(s, s32, ru_idrss);
665		CP(s, s32, ru_isrss);
666		CP(s, s32, ru_minflt);
667		CP(s, s32, ru_majflt);
668		CP(s, s32, ru_nswap);
669		CP(s, s32, ru_inblock);
670		CP(s, s32, ru_oublock);
671		CP(s, s32, ru_msgsnd);
672		CP(s, s32, ru_msgrcv);
673		CP(s, s32, ru_nsignals);
674		CP(s, s32, ru_nvcsw);
675		CP(s, s32, ru_nivcsw);
676		error = copyout(&s32, p32, sizeof(s32));
677	}
678	return (error);
679}
680
681struct iovec32 {
682	u_int32_t iov_base;
683	int	iov_len;
684};
685#define	STACKGAPLEN	400
686
687CTASSERT(sizeof(struct iovec32) == 8);
688
689int
690freebsd32_readv(struct thread *td, struct freebsd32_readv_args *uap)
691{
692	int error, osize, nsize, i;
693	caddr_t sg;
694	struct readv_args /* {
695		syscallarg(int) fd;
696		syscallarg(struct iovec *) iovp;
697		syscallarg(u_int) iovcnt;
698	} */ a;
699	struct iovec32 *oio;
700	struct iovec *nio;
701
702	sg = stackgap_init();
703
704	if (uap->iovcnt > (STACKGAPLEN / sizeof (struct iovec)))
705		return (EINVAL);
706
707	osize = uap->iovcnt * sizeof (struct iovec32);
708	nsize = uap->iovcnt * sizeof (struct iovec);
709
710	oio = malloc(osize, M_TEMP, M_WAITOK);
711	nio = malloc(nsize, M_TEMP, M_WAITOK);
712
713	error = 0;
714	if ((error = copyin(uap->iovp, oio, osize)))
715		goto punt;
716	for (i = 0; i < uap->iovcnt; i++) {
717		nio[i].iov_base = PTRIN(oio[i].iov_base);
718		nio[i].iov_len = oio[i].iov_len;
719	}
720
721	a.fd = uap->fd;
722	a.iovp = stackgap_alloc(&sg, nsize);
723	a.iovcnt = uap->iovcnt;
724
725	if ((error = copyout(nio, (caddr_t)a.iovp, nsize)))
726		goto punt;
727	error = readv(td, &a);
728
729punt:
730	free(oio, M_TEMP);
731	free(nio, M_TEMP);
732	return (error);
733}
734
735int
736freebsd32_writev(struct thread *td, struct freebsd32_writev_args *uap)
737{
738	int error, i, nsize, osize;
739	caddr_t sg;
740	struct writev_args /* {
741		syscallarg(int) fd;
742		syscallarg(struct iovec *) iovp;
743		syscallarg(u_int) iovcnt;
744	} */ a;
745	struct iovec32 *oio;
746	struct iovec *nio;
747
748	sg = stackgap_init();
749
750	if (uap->iovcnt > (STACKGAPLEN / sizeof (struct iovec)))
751		return (EINVAL);
752
753	osize = uap->iovcnt * sizeof (struct iovec32);
754	nsize = uap->iovcnt * sizeof (struct iovec);
755
756	oio = malloc(osize, M_TEMP, M_WAITOK);
757	nio = malloc(nsize, M_TEMP, M_WAITOK);
758
759	error = 0;
760	if ((error = copyin(uap->iovp, oio, osize)))
761		goto punt;
762	for (i = 0; i < uap->iovcnt; i++) {
763		nio[i].iov_base = PTRIN(oio[i].iov_base);
764		nio[i].iov_len = oio[i].iov_len;
765	}
766
767	a.fd = uap->fd;
768	a.iovp = stackgap_alloc(&sg, nsize);
769	a.iovcnt = uap->iovcnt;
770
771	if ((error = copyout(nio, (caddr_t)a.iovp, nsize)))
772		goto punt;
773	error = writev(td, &a);
774
775punt:
776	free(oio, M_TEMP);
777	free(nio, M_TEMP);
778	return (error);
779}
780
781int
782freebsd32_settimeofday(struct thread *td,
783		       struct freebsd32_settimeofday_args *uap)
784{
785	int error;
786	caddr_t sg;
787	struct timeval32 *p32, s32;
788	struct timeval *p = NULL, s;
789
790	p32 = uap->tv;
791	if (p32) {
792		sg = stackgap_init();
793		p = stackgap_alloc(&sg, sizeof(struct timeval));
794		uap->tv = (struct timeval32 *)p;
795		error = copyin(p32, &s32, sizeof(s32));
796		if (error)
797			return (error);
798		CP(s32, s, tv_sec);
799		CP(s32, s, tv_usec);
800		error = copyout(&s, p, sizeof(s));
801		if (error)
802			return (error);
803	}
804	return (settimeofday(td, (struct settimeofday_args *) uap));
805}
806
807int
808freebsd32_utimes(struct thread *td, struct freebsd32_utimes_args *uap)
809{
810	int error;
811	caddr_t sg;
812	struct timeval32 *p32, s32[2];
813	struct timeval *p = NULL, s[2];
814
815	p32 = uap->tptr;
816	if (p32) {
817		sg = stackgap_init();
818		p = stackgap_alloc(&sg, 2*sizeof(struct timeval));
819		uap->tptr = (struct timeval32 *)p;
820		error = copyin(p32, s32, sizeof(s32));
821		if (error)
822			return (error);
823		CP(s32[0], s[0], tv_sec);
824		CP(s32[0], s[0], tv_usec);
825		CP(s32[1], s[1], tv_sec);
826		CP(s32[1], s[1], tv_usec);
827		error = copyout(s, p, sizeof(s));
828		if (error)
829			return (error);
830	}
831	return (utimes(td, (struct utimes_args *) uap));
832}
833
834int
835freebsd32_adjtime(struct thread *td, struct freebsd32_adjtime_args *uap)
836{
837	int error;
838	caddr_t sg;
839	struct timeval32 *p32, *op32, s32;
840	struct timeval *p = NULL, *op = NULL, s;
841
842	p32 = uap->delta;
843	if (p32) {
844		sg = stackgap_init();
845		p = stackgap_alloc(&sg, sizeof(struct timeval));
846		uap->delta = (struct timeval32 *)p;
847		error = copyin(p32, &s32, sizeof(s32));
848		if (error)
849			return (error);
850		CP(s32, s, tv_sec);
851		CP(s32, s, tv_usec);
852		error = copyout(&s, p, sizeof(s));
853		if (error)
854			return (error);
855	}
856	op32 = uap->olddelta;
857	if (op32) {
858		sg = stackgap_init();
859		op = stackgap_alloc(&sg, sizeof(struct timeval));
860		uap->olddelta = (struct timeval32 *)op;
861	}
862	error = utimes(td, (struct utimes_args *) uap);
863	if (error)
864		return error;
865	if (op32) {
866		error = copyin(op, &s, sizeof(s));
867		if (error)
868			return (error);
869		CP(s, s32, tv_sec);
870		CP(s, s32, tv_usec);
871		error = copyout(&s32, op32, sizeof(s32));
872	}
873	return (error);
874}
875
876int
877freebsd32_statfs(struct thread *td, struct freebsd32_statfs_args *uap)
878{
879	int error;
880	caddr_t sg;
881	struct statfs32 *p32, s32;
882	struct statfs *p = NULL, s;
883
884	p32 = uap->buf;
885	if (p32) {
886		sg = stackgap_init();
887		p = stackgap_alloc(&sg, sizeof(struct statfs));
888		uap->buf = (struct statfs32 *)p;
889	}
890	error = statfs(td, (struct statfs_args *) uap);
891	if (error)
892		return (error);
893	if (p32) {
894		error = copyin(p, &s, sizeof(s));
895		if (error)
896			return (error);
897		copy_statfs(&s, &s32);
898		error = copyout(&s32, p32, sizeof(s32));
899	}
900	return (error);
901}
902
903int
904freebsd32_fstatfs(struct thread *td, struct freebsd32_fstatfs_args *uap)
905{
906	int error;
907	caddr_t sg;
908	struct statfs32 *p32, s32;
909	struct statfs *p = NULL, s;
910
911	p32 = uap->buf;
912	if (p32) {
913		sg = stackgap_init();
914		p = stackgap_alloc(&sg, sizeof(struct statfs));
915		uap->buf = (struct statfs32 *)p;
916	}
917	error = fstatfs(td, (struct fstatfs_args *) uap);
918	if (error)
919		return (error);
920	if (p32) {
921		error = copyin(p, &s, sizeof(s));
922		if (error)
923			return (error);
924		copy_statfs(&s, &s32);
925		error = copyout(&s32, p32, sizeof(s32));
926	}
927	return (error);
928}
929
930int
931freebsd32_semsys(struct thread *td, struct freebsd32_semsys_args *uap)
932{
933	/*
934	 * Vector through to semsys if it is loaded.
935	 */
936	return sysent[169].sy_call(td, uap);
937}
938
939int
940freebsd32_msgsys(struct thread *td, struct freebsd32_msgsys_args *uap)
941{
942	/*
943	 * Vector through to msgsys if it is loaded.
944	 */
945	return sysent[170].sy_call(td, uap);
946}
947
948int
949freebsd32_shmsys(struct thread *td, struct freebsd32_shmsys_args *uap)
950{
951	/*
952	 * Vector through to shmsys if it is loaded.
953	 */
954	return sysent[171].sy_call(td, uap);
955}
956
957int
958freebsd32_pread(struct thread *td, struct freebsd32_pread_args *uap)
959{
960	struct pread_args ap;
961
962	ap.fd = uap->fd;
963	ap.buf = uap->buf;
964	ap.nbyte = uap->nbyte;
965	ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32));
966	return (pread(td, &ap));
967}
968
969int
970freebsd32_pwrite(struct thread *td, struct freebsd32_pwrite_args *uap)
971{
972	struct pwrite_args ap;
973
974	ap.fd = uap->fd;
975	ap.buf = uap->buf;
976	ap.nbyte = uap->nbyte;
977	ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32));
978	return (pwrite(td, &ap));
979}
980
981int
982freebsd32_lseek(struct thread *td, struct freebsd32_lseek_args *uap)
983{
984	int error;
985	struct lseek_args ap;
986	off_t pos;
987
988	ap.fd = uap->fd;
989	ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32));
990	ap.whence = uap->whence;
991	error = lseek(td, &ap);
992	/* Expand the quad return into two parts for eax and edx */
993	pos = *(off_t *)(td->td_retval);
994	td->td_retval[0] = pos & 0xffffffff;	/* %eax */
995	td->td_retval[1] = pos >> 32;		/* %edx */
996	return error;
997}
998
999int
1000freebsd32_truncate(struct thread *td, struct freebsd32_truncate_args *uap)
1001{
1002	struct truncate_args ap;
1003
1004	ap.path = uap->path;
1005	ap.length = (uap->lengthlo | ((off_t)uap->lengthhi << 32));
1006	return (truncate(td, &ap));
1007}
1008
1009int
1010freebsd32_ftruncate(struct thread *td, struct freebsd32_ftruncate_args *uap)
1011{
1012	struct ftruncate_args ap;
1013
1014	ap.fd = uap->fd;
1015	ap.length = (uap->lengthlo | ((off_t)uap->lengthhi << 32));
1016	return (ftruncate(td, &ap));
1017}
1018
1019#ifdef COMPAT_FREEBSD4
1020int
1021freebsd4_freebsd32_sendfile(struct thread *td,
1022    struct freebsd4_freebsd32_sendfile_args *uap)
1023{
1024	struct freebsd4_sendfile_args ap;
1025
1026	ap.fd = uap->fd;
1027	ap.s = uap->s;
1028	ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32));
1029	ap.nbytes = uap->nbytes;	/* XXX check */
1030	ap.hdtr = uap->hdtr;		/* XXX check */
1031	ap.sbytes = uap->sbytes;	/* XXX FIXME!! */
1032	ap.flags = uap->flags;
1033	return (freebsd4_sendfile(td, &ap));
1034}
1035#endif
1036
1037int
1038freebsd32_sendfile(struct thread *td, struct freebsd32_sendfile_args *uap)
1039{
1040	struct sendfile_args ap;
1041
1042	ap.fd = uap->fd;
1043	ap.s = uap->s;
1044	ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32));
1045	ap.nbytes = uap->nbytes;	/* XXX check */
1046	ap.hdtr = uap->hdtr;		/* XXX check */
1047	ap.sbytes = uap->sbytes;	/* XXX FIXME!! */
1048	ap.flags = uap->flags;
1049	return (sendfile(td, &ap));
1050}
1051
1052struct stat32 {
1053	udev_t	st_dev;
1054	ino_t	st_ino;
1055	mode_t	st_mode;
1056	nlink_t	st_nlink;
1057	uid_t	st_uid;
1058	gid_t	st_gid;
1059	udev_t	st_rdev;
1060	struct timespec32 st_atimespec;
1061	struct timespec32 st_mtimespec;
1062	struct timespec32 st_ctimespec;
1063	off_t	st_size;
1064	int64_t	st_blocks;
1065	u_int32_t st_blksize;
1066	u_int32_t st_flags;
1067	u_int32_t st_gen;
1068	struct timespec32 st_birthtimespec;
1069	unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec32));
1070	unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec32));
1071};
1072
1073
1074CTASSERT(sizeof(struct stat32) == 96);
1075
1076static void
1077copy_stat( struct stat *in, struct stat32 *out)
1078{
1079	CP(*in, *out, st_dev);
1080	CP(*in, *out, st_ino);
1081	CP(*in, *out, st_mode);
1082	CP(*in, *out, st_nlink);
1083	CP(*in, *out, st_uid);
1084	CP(*in, *out, st_gid);
1085	CP(*in, *out, st_rdev);
1086	TS_CP(*in, *out, st_atimespec);
1087	TS_CP(*in, *out, st_mtimespec);
1088	TS_CP(*in, *out, st_ctimespec);
1089	CP(*in, *out, st_size);
1090	CP(*in, *out, st_blocks);
1091	CP(*in, *out, st_blksize);
1092	CP(*in, *out, st_flags);
1093	CP(*in, *out, st_gen);
1094}
1095
1096int
1097freebsd32_stat(struct thread *td, struct freebsd32_stat_args *uap)
1098{
1099	struct stat sb;
1100	struct stat32 sb32;
1101	int error;
1102	struct nameidata nd;
1103
1104#ifdef LOOKUP_SHARED
1105	NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | NOOBJ,
1106	    UIO_USERSPACE, uap->path, td);
1107#else
1108	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1109	    uap->path, td);
1110#endif
1111	if ((error = namei(&nd)) != 0)
1112		return (error);
1113	error = vn_stat(nd.ni_vp, &sb, td->td_ucred, NOCRED, td);
1114	NDFREE(&nd, NDF_ONLY_PNBUF);
1115	vput(nd.ni_vp);
1116	if (error)
1117		return (error);
1118	copy_stat(&sb, &sb32);
1119	error = copyout(&sb32, uap->ub, sizeof (sb32));
1120	return (error);
1121}
1122
1123int
1124freebsd32_fstat(struct thread *td, struct freebsd32_fstat_args *uap)
1125{
1126	struct file *fp;
1127	struct stat ub;
1128	struct stat32 ub32;
1129	int error;
1130
1131	if ((error = fget(td, uap->fd, &fp)) != 0)
1132		return (error);
1133	mtx_lock(&Giant);
1134	error = fo_stat(fp, &ub, td->td_ucred, td);
1135	mtx_unlock(&Giant);
1136	fdrop(fp, td);
1137	if (error)
1138		return (error);
1139	copy_stat(&ub, &ub32);
1140	error = copyout(&ub32, uap->ub, sizeof(ub32));
1141	return (error);
1142}
1143
1144int
1145freebsd32_lstat(struct thread *td, struct freebsd32_lstat_args *uap)
1146{
1147	int error;
1148	struct vnode *vp;
1149	struct stat sb;
1150	struct stat32 sb32;
1151	struct nameidata nd;
1152
1153	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1154	    uap->path, td);
1155	if ((error = namei(&nd)) != 0)
1156		return (error);
1157	vp = nd.ni_vp;
1158	error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td);
1159	NDFREE(&nd, NDF_ONLY_PNBUF);
1160	vput(vp);
1161	if (error)
1162		return (error);
1163	copy_stat(&sb, &sb32);
1164	error = copyout(&sb32, uap->ub, sizeof (sb32));
1165	return (error);
1166}
1167
1168/*
1169 * MPSAFE
1170 */
1171int
1172freebsd32_sysctl(struct thread *td, struct freebsd32_sysctl_args *uap)
1173{
1174	int error, name[CTL_MAXNAME];
1175	size_t j, oldlen;
1176
1177	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
1178		return (EINVAL);
1179
1180 	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
1181 	if (error)
1182		return (error);
1183
1184	mtx_lock(&Giant);
1185
1186	if (uap->oldlenp)
1187		oldlen = fuword32(uap->oldlenp);
1188	else
1189		oldlen = 0;
1190	error = userland_sysctl(td, name, uap->namelen,
1191		uap->old, &oldlen, 1,
1192		uap->new, uap->newlen, &j);
1193	if (error && error != ENOMEM)
1194		goto done2;
1195	if (uap->oldlenp) {
1196		suword32(uap->oldlenp, j);
1197	}
1198done2:
1199	mtx_unlock(&Giant);
1200	return (error);
1201}
1202
1203struct sigaction32 {
1204	u_int32_t	sa_u;
1205	int		sa_flags;
1206	sigset_t	sa_mask;
1207};
1208
1209CTASSERT(sizeof(struct sigaction32) == 24);
1210
1211int
1212freebsd32_sigaction(struct thread *td, struct freebsd32_sigaction_args *uap)
1213{
1214	struct sigaction32 s32;
1215	struct sigaction sa, osa, *sap;
1216	int error;
1217
1218	if (uap->act) {
1219		error = copyin(uap->act, &s32, sizeof(s32));
1220		if (error)
1221			return (error);
1222		sa.sa_handler = PTRIN(s32.sa_u);
1223		CP(s32, sa, sa_flags);
1224		CP(s32, sa, sa_mask);
1225		sap = &sa;
1226	} else
1227		sap = NULL;
1228	error = kern_sigaction(td, uap->sig, sap, &osa, 0);
1229	if (error != 0 && uap->oact != NULL) {
1230		s32.sa_u = PTROUT(osa.sa_handler);
1231		CP(osa, s32, sa_flags);
1232		CP(osa, s32, sa_mask);
1233		error = copyout(&s32, uap->oact, sizeof(s32));
1234	}
1235	return (error);
1236}
1237
1238#ifdef COMPAT_FREEBSD4
1239int
1240freebsd4_freebsd32_sigaction(struct thread *td,
1241			     struct freebsd4_freebsd32_sigaction_args *uap)
1242{
1243	struct sigaction32 s32;
1244	struct sigaction sa, osa, *sap;
1245	int error;
1246
1247	if (uap->act) {
1248		error = copyin(uap->act, &s32, sizeof(s32));
1249		if (error)
1250			return (error);
1251		sa.sa_handler = PTRIN(s32.sa_u);
1252		CP(s32, sa, sa_flags);
1253		CP(s32, sa, sa_mask);
1254		sap = &sa;
1255	} else
1256		sap = NULL;
1257	error = kern_sigaction(td, uap->sig, sap, &osa, KSA_FREEBSD4);
1258	if (error != 0 && uap->oact != NULL) {
1259		s32.sa_u = PTROUT(osa.sa_handler);
1260		CP(osa, s32, sa_flags);
1261		CP(osa, s32, sa_mask);
1262		error = copyout(&s32, uap->oact, sizeof(s32));
1263	}
1264	return (error);
1265}
1266#endif
1267
1268#if 0
1269
1270int
1271freebsd32_xxx(struct thread *td, struct freebsd32_xxx_args *uap)
1272{
1273	int error;
1274	caddr_t sg;
1275	struct yyy32 *p32, s32;
1276	struct yyy *p = NULL, s;
1277
1278	p32 = uap->zzz;
1279	if (p32) {
1280		sg = stackgap_init();
1281		p = stackgap_alloc(&sg, sizeof(struct yyy));
1282		uap->zzz = (struct yyy32 *)p;
1283		error = copyin(p32, &s32, sizeof(s32));
1284		if (error)
1285			return (error);
1286		/* translate in */
1287		error = copyout(&s, p, sizeof(s));
1288		if (error)
1289			return (error);
1290	}
1291	error = xxx(td, (struct xxx_args *) uap);
1292	if (error)
1293		return (error);
1294	if (p32) {
1295		error = copyin(p, &s, sizeof(s));
1296		if (error)
1297			return (error);
1298		/* translate out */
1299		error = copyout(&s32, p32, sizeof(s32));
1300	}
1301	return (error);
1302}
1303
1304#endif
1305