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