xref: /freebsd/sys/compat/freebsd32/freebsd32_misc.c (revision 6fd05b64b5b65dd4ba9b86482a0634a5f0b96c29)
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/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 
84 CTASSERT(sizeof(struct timeval32) == 8);
85 CTASSERT(sizeof(struct timespec32) == 8);
86 CTASSERT(sizeof(struct statfs32) == 256);
87 CTASSERT(sizeof(struct rusage32) == 72);
88 
89 int
90 freebsd32_wait4(struct thread *td, struct freebsd32_wait4_args *uap)
91 {
92 	int error, status;
93 	struct rusage32 ru32;
94 	struct rusage ru;
95 
96 	error = kern_wait(td, uap->pid, &status, uap->options, &ru);
97 	if (error)
98 		return (error);
99 	if (uap->status != NULL)
100 		error = copyout(&status, uap->status, sizeof(status));
101 	if (uap->rusage != NULL && error == 0) {
102 		TV_CP(ru, ru32, ru_utime);
103 		TV_CP(ru, ru32, ru_stime);
104 		CP(ru, ru32, ru_maxrss);
105 		CP(ru, ru32, ru_ixrss);
106 		CP(ru, ru32, ru_idrss);
107 		CP(ru, ru32, ru_isrss);
108 		CP(ru, ru32, ru_minflt);
109 		CP(ru, ru32, ru_majflt);
110 		CP(ru, ru32, ru_nswap);
111 		CP(ru, ru32, ru_inblock);
112 		CP(ru, ru32, ru_oublock);
113 		CP(ru, ru32, ru_msgsnd);
114 		CP(ru, ru32, ru_msgrcv);
115 		CP(ru, ru32, ru_nsignals);
116 		CP(ru, ru32, ru_nvcsw);
117 		CP(ru, ru32, ru_nivcsw);
118 		error = copyout(&ru32, uap->rusage, sizeof(ru32));
119 	}
120 	return (error);
121 }
122 
123 #ifdef COMPAT_FREEBSD4
124 static void
125 copy_statfs(struct statfs *in, struct statfs32 *out)
126 {
127 	CP(*in, *out, f_bsize);
128 	CP(*in, *out, f_iosize);
129 	CP(*in, *out, f_blocks);
130 	CP(*in, *out, f_bfree);
131 	CP(*in, *out, f_bavail);
132 	CP(*in, *out, f_files);
133 	CP(*in, *out, f_ffree);
134 	CP(*in, *out, f_fsid);
135 	CP(*in, *out, f_owner);
136 	CP(*in, *out, f_type);
137 	CP(*in, *out, f_flags);
138 	CP(*in, *out, f_flags);
139 	CP(*in, *out, f_syncwrites);
140 	CP(*in, *out, f_asyncwrites);
141 	bcopy(in->f_fstypename,
142 	      out->f_fstypename, MFSNAMELEN);
143 	bcopy(in->f_mntonname,
144 	      out->f_mntonname, min(MNAMELEN, FREEBSD4_MNAMELEN));
145 	CP(*in, *out, f_syncreads);
146 	CP(*in, *out, f_asyncreads);
147 	bcopy(in->f_mntfromname,
148 	      out->f_mntfromname, min(MNAMELEN, FREEBSD4_MNAMELEN));
149 }
150 #endif
151 
152 #ifdef COMPAT_FREEBSD4
153 int
154 freebsd4_freebsd32_getfsstat(struct thread *td, struct freebsd4_freebsd32_getfsstat_args *uap)
155 {
156 	int error;
157 	caddr_t sg;
158 	struct statfs32 *sp32, stat32;
159 	struct statfs *sp = NULL, stat;
160 	int maxcount, count, i;
161 
162 	sp32 = uap->buf;
163 	maxcount = uap->bufsize / sizeof(struct statfs32);
164 
165 	if (sp32) {
166 		sg = stackgap_init();
167 		sp = stackgap_alloc(&sg, sizeof(struct statfs) * maxcount);
168 		uap->buf = (struct statfs32 *)sp;
169 	}
170 	error = getfsstat(td, (struct getfsstat_args *) uap);
171 	if (sp32 && !error) {
172 		count = td->td_retval[0];
173 		for (i = 0; i < count; i++) {
174 			error = copyin(&sp[i], &stat, sizeof(stat));
175 			if (error)
176 				return (error);
177 			copy_statfs(&stat, &stat32);
178 			error = copyout(&stat32, &sp32[i], sizeof(stat32));
179 			if (error)
180 				return (error);
181 		}
182 	}
183 	return (error);
184 }
185 #endif
186 
187 struct sigaltstack32 {
188 	u_int32_t	ss_sp;
189 	u_int32_t	ss_size;
190 	int		ss_flags;
191 };
192 
193 CTASSERT(sizeof(struct sigaltstack32) == 12);
194 
195 int
196 freebsd32_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 
223 int
224 freebsd32_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__
285 static int
286 freebsd32_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 
333 int
334 freebsd32_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 
428 struct itimerval32 {
429 	struct timeval32 it_interval;
430 	struct timeval32 it_value;
431 };
432 
433 CTASSERT(sizeof(struct itimerval32) == 16);
434 
435 int
436 freebsd32_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 
477 int
478 freebsd32_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 
505 int
506 freebsd32_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 
533 struct 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 
542 CTASSERT(sizeof(struct kevent32) == 20);
543 
544 int
545 freebsd32_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 
616 int
617 freebsd32_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 
639 int
640 freebsd32_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 
681 struct iovec32 {
682 	u_int32_t iov_base;
683 	int	iov_len;
684 };
685 #define	STACKGAPLEN	400
686 
687 CTASSERT(sizeof(struct iovec32) == 8);
688 
689 int
690 freebsd32_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 
729 punt:
730 	free(oio, M_TEMP);
731 	free(nio, M_TEMP);
732 	return (error);
733 }
734 
735 int
736 freebsd32_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 
775 punt:
776 	free(oio, M_TEMP);
777 	free(nio, M_TEMP);
778 	return (error);
779 }
780 
781 int
782 freebsd32_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 
807 int
808 freebsd32_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 
834 int
835 freebsd32_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 
876 #ifdef COMPAT_FREEBSD4
877 int
878 freebsd4_freebsd32_statfs(struct thread *td, struct freebsd4_freebsd32_statfs_args *uap)
879 {
880 	int error;
881 	caddr_t sg;
882 	struct statfs32 *p32, s32;
883 	struct statfs *p = NULL, s;
884 
885 	p32 = uap->buf;
886 	if (p32) {
887 		sg = stackgap_init();
888 		p = stackgap_alloc(&sg, sizeof(struct statfs));
889 		uap->buf = (struct statfs32 *)p;
890 	}
891 	error = statfs(td, (struct statfs_args *) uap);
892 	if (error)
893 		return (error);
894 	if (p32) {
895 		error = copyin(p, &s, sizeof(s));
896 		if (error)
897 			return (error);
898 		copy_statfs(&s, &s32);
899 		error = copyout(&s32, p32, sizeof(s32));
900 	}
901 	return (error);
902 }
903 #endif
904 
905 #ifdef COMPAT_FREEBSD4
906 int
907 freebsd4_freebsd32_fstatfs(struct thread *td, struct freebsd4_freebsd32_fstatfs_args *uap)
908 {
909 	int error;
910 	caddr_t sg;
911 	struct statfs32 *p32, s32;
912 	struct statfs *p = NULL, s;
913 
914 	p32 = uap->buf;
915 	if (p32) {
916 		sg = stackgap_init();
917 		p = stackgap_alloc(&sg, sizeof(struct statfs));
918 		uap->buf = (struct statfs32 *)p;
919 	}
920 	error = fstatfs(td, (struct fstatfs_args *) uap);
921 	if (error)
922 		return (error);
923 	if (p32) {
924 		error = copyin(p, &s, sizeof(s));
925 		if (error)
926 			return (error);
927 		copy_statfs(&s, &s32);
928 		error = copyout(&s32, p32, sizeof(s32));
929 	}
930 	return (error);
931 }
932 #endif
933 
934 #ifdef COMPAT_FREEBSD4
935 int
936 freebsd4_freebsd32_fhstatfs(struct thread *td, struct freebsd4_freebsd32_fhstatfs_args *uap)
937 {
938 	int error;
939 	caddr_t sg;
940 	struct statfs32 *p32, s32;
941 	struct statfs *p = NULL, s;
942 
943 	p32 = uap->buf;
944 	if (p32) {
945 		sg = stackgap_init();
946 		p = stackgap_alloc(&sg, sizeof(struct statfs));
947 		uap->buf = (struct statfs32 *)p;
948 	}
949 	error = fhstatfs(td, (struct fhstatfs_args *) uap);
950 	if (error)
951 		return (error);
952 	if (p32) {
953 		error = copyin(p, &s, sizeof(s));
954 		if (error)
955 			return (error);
956 		copy_statfs(&s, &s32);
957 		error = copyout(&s32, p32, sizeof(s32));
958 	}
959 	return (error);
960 }
961 #endif
962 
963 int
964 freebsd32_semsys(struct thread *td, struct freebsd32_semsys_args *uap)
965 {
966 	/*
967 	 * Vector through to semsys if it is loaded.
968 	 */
969 	return sysent[169].sy_call(td, uap);
970 }
971 
972 int
973 freebsd32_msgsys(struct thread *td, struct freebsd32_msgsys_args *uap)
974 {
975 	/*
976 	 * Vector through to msgsys if it is loaded.
977 	 */
978 	return sysent[170].sy_call(td, uap);
979 }
980 
981 int
982 freebsd32_shmsys(struct thread *td, struct freebsd32_shmsys_args *uap)
983 {
984 	/*
985 	 * Vector through to shmsys if it is loaded.
986 	 */
987 	return sysent[171].sy_call(td, uap);
988 }
989 
990 int
991 freebsd32_pread(struct thread *td, struct freebsd32_pread_args *uap)
992 {
993 	struct pread_args ap;
994 
995 	ap.fd = uap->fd;
996 	ap.buf = uap->buf;
997 	ap.nbyte = uap->nbyte;
998 	ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32));
999 	return (pread(td, &ap));
1000 }
1001 
1002 int
1003 freebsd32_pwrite(struct thread *td, struct freebsd32_pwrite_args *uap)
1004 {
1005 	struct pwrite_args ap;
1006 
1007 	ap.fd = uap->fd;
1008 	ap.buf = uap->buf;
1009 	ap.nbyte = uap->nbyte;
1010 	ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32));
1011 	return (pwrite(td, &ap));
1012 }
1013 
1014 int
1015 freebsd32_lseek(struct thread *td, struct freebsd32_lseek_args *uap)
1016 {
1017 	int error;
1018 	struct lseek_args ap;
1019 	off_t pos;
1020 
1021 	ap.fd = uap->fd;
1022 	ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32));
1023 	ap.whence = uap->whence;
1024 	error = lseek(td, &ap);
1025 	/* Expand the quad return into two parts for eax and edx */
1026 	pos = *(off_t *)(td->td_retval);
1027 	td->td_retval[0] = pos & 0xffffffff;	/* %eax */
1028 	td->td_retval[1] = pos >> 32;		/* %edx */
1029 	return error;
1030 }
1031 
1032 int
1033 freebsd32_truncate(struct thread *td, struct freebsd32_truncate_args *uap)
1034 {
1035 	struct truncate_args ap;
1036 
1037 	ap.path = uap->path;
1038 	ap.length = (uap->lengthlo | ((off_t)uap->lengthhi << 32));
1039 	return (truncate(td, &ap));
1040 }
1041 
1042 int
1043 freebsd32_ftruncate(struct thread *td, struct freebsd32_ftruncate_args *uap)
1044 {
1045 	struct ftruncate_args ap;
1046 
1047 	ap.fd = uap->fd;
1048 	ap.length = (uap->lengthlo | ((off_t)uap->lengthhi << 32));
1049 	return (ftruncate(td, &ap));
1050 }
1051 
1052 #ifdef COMPAT_FREEBSD4
1053 int
1054 freebsd4_freebsd32_sendfile(struct thread *td,
1055     struct freebsd4_freebsd32_sendfile_args *uap)
1056 {
1057 	struct freebsd4_sendfile_args ap;
1058 
1059 	ap.fd = uap->fd;
1060 	ap.s = uap->s;
1061 	ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32));
1062 	ap.nbytes = uap->nbytes;	/* XXX check */
1063 	ap.hdtr = uap->hdtr;		/* XXX check */
1064 	ap.sbytes = uap->sbytes;	/* XXX FIXME!! */
1065 	ap.flags = uap->flags;
1066 	return (freebsd4_sendfile(td, &ap));
1067 }
1068 #endif
1069 
1070 int
1071 freebsd32_sendfile(struct thread *td, struct freebsd32_sendfile_args *uap)
1072 {
1073 	struct sendfile_args ap;
1074 
1075 	ap.fd = uap->fd;
1076 	ap.s = uap->s;
1077 	ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32));
1078 	ap.nbytes = uap->nbytes;	/* XXX check */
1079 	ap.hdtr = uap->hdtr;		/* XXX check */
1080 	ap.sbytes = uap->sbytes;	/* XXX FIXME!! */
1081 	ap.flags = uap->flags;
1082 	return (sendfile(td, &ap));
1083 }
1084 
1085 struct stat32 {
1086 	dev_t	st_dev;
1087 	ino_t	st_ino;
1088 	mode_t	st_mode;
1089 	nlink_t	st_nlink;
1090 	uid_t	st_uid;
1091 	gid_t	st_gid;
1092 	dev_t	st_rdev;
1093 	struct timespec32 st_atimespec;
1094 	struct timespec32 st_mtimespec;
1095 	struct timespec32 st_ctimespec;
1096 	off_t	st_size;
1097 	int64_t	st_blocks;
1098 	u_int32_t st_blksize;
1099 	u_int32_t st_flags;
1100 	u_int32_t st_gen;
1101 	struct timespec32 st_birthtimespec;
1102 	unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec32));
1103 	unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec32));
1104 };
1105 
1106 
1107 CTASSERT(sizeof(struct stat32) == 96);
1108 
1109 static void
1110 copy_stat( struct stat *in, struct stat32 *out)
1111 {
1112 	CP(*in, *out, st_dev);
1113 	CP(*in, *out, st_ino);
1114 	CP(*in, *out, st_mode);
1115 	CP(*in, *out, st_nlink);
1116 	CP(*in, *out, st_uid);
1117 	CP(*in, *out, st_gid);
1118 	CP(*in, *out, st_rdev);
1119 	TS_CP(*in, *out, st_atimespec);
1120 	TS_CP(*in, *out, st_mtimespec);
1121 	TS_CP(*in, *out, st_ctimespec);
1122 	CP(*in, *out, st_size);
1123 	CP(*in, *out, st_blocks);
1124 	CP(*in, *out, st_blksize);
1125 	CP(*in, *out, st_flags);
1126 	CP(*in, *out, st_gen);
1127 }
1128 
1129 int
1130 freebsd32_stat(struct thread *td, struct freebsd32_stat_args *uap)
1131 {
1132 	struct stat sb;
1133 	struct stat32 sb32;
1134 	int error;
1135 	struct nameidata nd;
1136 
1137 #ifdef LOOKUP_SHARED
1138 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | NOOBJ,
1139 	    UIO_USERSPACE, uap->path, td);
1140 #else
1141 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1142 	    uap->path, td);
1143 #endif
1144 	if ((error = namei(&nd)) != 0)
1145 		return (error);
1146 	error = vn_stat(nd.ni_vp, &sb, td->td_ucred, NOCRED, td);
1147 	NDFREE(&nd, NDF_ONLY_PNBUF);
1148 	vput(nd.ni_vp);
1149 	if (error)
1150 		return (error);
1151 	copy_stat(&sb, &sb32);
1152 	error = copyout(&sb32, uap->ub, sizeof (sb32));
1153 	return (error);
1154 }
1155 
1156 int
1157 freebsd32_fstat(struct thread *td, struct freebsd32_fstat_args *uap)
1158 {
1159 	struct file *fp;
1160 	struct stat ub;
1161 	struct stat32 ub32;
1162 	int error;
1163 
1164 	if ((error = fget(td, uap->fd, &fp)) != 0)
1165 		return (error);
1166 	mtx_lock(&Giant);
1167 	error = fo_stat(fp, &ub, td->td_ucred, td);
1168 	mtx_unlock(&Giant);
1169 	fdrop(fp, td);
1170 	if (error)
1171 		return (error);
1172 	copy_stat(&ub, &ub32);
1173 	error = copyout(&ub32, uap->ub, sizeof(ub32));
1174 	return (error);
1175 }
1176 
1177 int
1178 freebsd32_lstat(struct thread *td, struct freebsd32_lstat_args *uap)
1179 {
1180 	int error;
1181 	struct vnode *vp;
1182 	struct stat sb;
1183 	struct stat32 sb32;
1184 	struct nameidata nd;
1185 
1186 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1187 	    uap->path, td);
1188 	if ((error = namei(&nd)) != 0)
1189 		return (error);
1190 	vp = nd.ni_vp;
1191 	error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td);
1192 	NDFREE(&nd, NDF_ONLY_PNBUF);
1193 	vput(vp);
1194 	if (error)
1195 		return (error);
1196 	copy_stat(&sb, &sb32);
1197 	error = copyout(&sb32, uap->ub, sizeof (sb32));
1198 	return (error);
1199 }
1200 
1201 /*
1202  * MPSAFE
1203  */
1204 int
1205 freebsd32_sysctl(struct thread *td, struct freebsd32_sysctl_args *uap)
1206 {
1207 	int error, name[CTL_MAXNAME];
1208 	size_t j, oldlen;
1209 
1210 	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
1211 		return (EINVAL);
1212 
1213  	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
1214  	if (error)
1215 		return (error);
1216 
1217 	mtx_lock(&Giant);
1218 
1219 	if (uap->oldlenp)
1220 		oldlen = fuword32(uap->oldlenp);
1221 	else
1222 		oldlen = 0;
1223 	error = userland_sysctl(td, name, uap->namelen,
1224 		uap->old, &oldlen, 1,
1225 		uap->new, uap->newlen, &j);
1226 	if (error && error != ENOMEM)
1227 		goto done2;
1228 	if (uap->oldlenp) {
1229 		suword32(uap->oldlenp, j);
1230 	}
1231 done2:
1232 	mtx_unlock(&Giant);
1233 	return (error);
1234 }
1235 
1236 struct sigaction32 {
1237 	u_int32_t	sa_u;
1238 	int		sa_flags;
1239 	sigset_t	sa_mask;
1240 };
1241 
1242 CTASSERT(sizeof(struct sigaction32) == 24);
1243 
1244 int
1245 freebsd32_sigaction(struct thread *td, struct freebsd32_sigaction_args *uap)
1246 {
1247 	struct sigaction32 s32;
1248 	struct sigaction sa, osa, *sap;
1249 	int error;
1250 
1251 	if (uap->act) {
1252 		error = copyin(uap->act, &s32, sizeof(s32));
1253 		if (error)
1254 			return (error);
1255 		sa.sa_handler = PTRIN(s32.sa_u);
1256 		CP(s32, sa, sa_flags);
1257 		CP(s32, sa, sa_mask);
1258 		sap = &sa;
1259 	} else
1260 		sap = NULL;
1261 	error = kern_sigaction(td, uap->sig, sap, &osa, 0);
1262 	if (error != 0 && uap->oact != NULL) {
1263 		s32.sa_u = PTROUT(osa.sa_handler);
1264 		CP(osa, s32, sa_flags);
1265 		CP(osa, s32, sa_mask);
1266 		error = copyout(&s32, uap->oact, sizeof(s32));
1267 	}
1268 	return (error);
1269 }
1270 
1271 #ifdef COMPAT_FREEBSD4
1272 int
1273 freebsd4_freebsd32_sigaction(struct thread *td,
1274 			     struct freebsd4_freebsd32_sigaction_args *uap)
1275 {
1276 	struct sigaction32 s32;
1277 	struct sigaction sa, osa, *sap;
1278 	int error;
1279 
1280 	if (uap->act) {
1281 		error = copyin(uap->act, &s32, sizeof(s32));
1282 		if (error)
1283 			return (error);
1284 		sa.sa_handler = PTRIN(s32.sa_u);
1285 		CP(s32, sa, sa_flags);
1286 		CP(s32, sa, sa_mask);
1287 		sap = &sa;
1288 	} else
1289 		sap = NULL;
1290 	error = kern_sigaction(td, uap->sig, sap, &osa, KSA_FREEBSD4);
1291 	if (error != 0 && uap->oact != NULL) {
1292 		s32.sa_u = PTROUT(osa.sa_handler);
1293 		CP(osa, s32, sa_flags);
1294 		CP(osa, s32, sa_mask);
1295 		error = copyout(&s32, uap->oact, sizeof(s32));
1296 	}
1297 	return (error);
1298 }
1299 #endif
1300 
1301 #if 0
1302 
1303 int
1304 freebsd32_xxx(struct thread *td, struct freebsd32_xxx_args *uap)
1305 {
1306 	int error;
1307 	caddr_t sg;
1308 	struct yyy32 *p32, s32;
1309 	struct yyy *p = NULL, s;
1310 
1311 	p32 = uap->zzz;
1312 	if (p32) {
1313 		sg = stackgap_init();
1314 		p = stackgap_alloc(&sg, sizeof(struct yyy));
1315 		uap->zzz = (struct yyy32 *)p;
1316 		error = copyin(p32, &s32, sizeof(s32));
1317 		if (error)
1318 			return (error);
1319 		/* translate in */
1320 		error = copyout(&s, p, sizeof(s));
1321 		if (error)
1322 			return (error);
1323 	}
1324 	error = xxx(td, (struct xxx_args *) uap);
1325 	if (error)
1326 		return (error);
1327 	if (p32) {
1328 		error = copyin(p, &s, sizeof(s));
1329 		if (error)
1330 			return (error);
1331 		/* translate out */
1332 		error = copyout(&s32, p32, sizeof(s32));
1333 	}
1334 	return (error);
1335 }
1336 
1337 #endif
1338