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