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