xref: /netbsd-src/sys/compat/netbsd32/netbsd32_time.c (revision eb961d0e02b7a46a9acfa877b02df48df6637278)
1 /*	$NetBSD: netbsd32_time.c,v 1.19 2006/02/17 15:44:17 he Exp $	*/
2 
3 /*
4  * Copyright (c) 1998, 2001 Matthew R. Green
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: netbsd32_time.c,v 1.19 2006/02/17 15:44:17 he Exp $");
33 
34 #if defined(_KERNEL_OPT)
35 #include "opt_ntp.h"
36 #endif
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/mount.h>
41 #include <sys/time.h>
42 #include <sys/timex.h>
43 #include <sys/timevar.h>
44 #include <sys/proc.h>
45 #include <sys/pool.h>
46 #include <sys/resourcevar.h>
47 #include <sys/dirent.h>
48 
49 #include <compat/netbsd32/netbsd32.h>
50 #include <compat/netbsd32/netbsd32_syscallargs.h>
51 #include <compat/netbsd32/netbsd32_conv.h>
52 
53 #ifdef NTP
54 
55 #ifdef PPS_SYNC
56 /*
57  * The following variables are used only if the PPS signal discipline
58  * is configured in the kernel.
59  */
60 extern int pps_shift;		/* interval duration (s) (shift) */
61 extern long pps_freq;		/* pps frequency offset (scaled ppm) */
62 extern long pps_jitter;		/* pps jitter (us) */
63 extern long pps_stabil;		/* pps stability (scaled ppm) */
64 extern long pps_jitcnt;		/* jitter limit exceeded */
65 extern long pps_calcnt;		/* calibration intervals */
66 extern long pps_errcnt;		/* calibration errors */
67 extern long pps_stbcnt;		/* stability limit exceeded */
68 #endif /* PPS_SYNC */
69 
70 int
71 netbsd32_ntp_gettime(l, v, retval)
72 	struct lwp *l;
73 	void *v;
74 	register_t *retval;
75 {
76 	struct netbsd32_ntp_gettime_args /* {
77 		syscallarg(netbsd32_ntptimevalp_t) ntvp;
78 	} */ *uap = v;
79 	struct netbsd32_ntptimeval ntv32;
80 	struct timeval atv;
81 	struct ntptimeval ntv;
82 	int error = 0;
83 	int s;
84 
85 	/* The following are NTP variables */
86 	extern long time_maxerror;
87 	extern long time_esterror;
88 	extern int time_status;
89 	extern int time_state;	/* clock state */
90 	extern int time_status;	/* clock status bits */
91 
92 	if (SCARG(uap, ntvp)) {
93 		s = splclock();
94 #ifdef EXT_CLOCK
95 		/*
96 		 * The microtime() external clock routine returns a
97 		 * status code. If less than zero, we declare an error
98 		 * in the clock status word and return the kernel
99 		 * (software) time variable. While there are other
100 		 * places that call microtime(), this is the only place
101 		 * that matters from an application point of view.
102 		 */
103 		if (microtime(&atv) < 0) {
104 			time_status |= STA_CLOCKERR;
105 			ntv.time = time;
106 		} else
107 			time_status &= ~STA_CLOCKERR;
108 #else /* EXT_CLOCK */
109 		microtime(&atv);
110 #endif /* EXT_CLOCK */
111 		ntv.time = atv;
112 		ntv.maxerror = time_maxerror;
113 		ntv.esterror = time_esterror;
114 		(void) splx(s);
115 
116 		netbsd32_from_timeval(&ntv.time, &ntv32.time);
117 		ntv32.maxerror = (netbsd32_long)ntv.maxerror;
118 		ntv32.esterror = (netbsd32_long)ntv.esterror;
119 		error = copyout((caddr_t)&ntv32,
120 		    (caddr_t)NETBSD32PTR64(SCARG(uap, ntvp)), sizeof(ntv32));
121 	}
122 	if (!error) {
123 
124 		/*
125 		 * Status word error decode. If any of these conditions
126 		 * occur, an error is returned, instead of the status
127 		 * word. Most applications will care only about the fact
128 		 * the system clock may not be trusted, not about the
129 		 * details.
130 		 *
131 		 * Hardware or software error
132 		 */
133 		if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) ||
134 
135 		/*
136 		 * PPS signal lost when either time or frequency
137 		 * synchronization requested
138 		 */
139 		    (time_status & (STA_PPSFREQ | STA_PPSTIME) &&
140 		    !(time_status & STA_PPSSIGNAL)) ||
141 
142 		/*
143 		 * PPS jitter exceeded when time synchronization
144 		 * requested
145 		 */
146 		    (time_status & STA_PPSTIME &&
147 		    time_status & STA_PPSJITTER) ||
148 
149 		/*
150 		 * PPS wander exceeded or calibration error when
151 		 * frequency synchronization requested
152 		 */
153 		    (time_status & STA_PPSFREQ &&
154 		    time_status & (STA_PPSWANDER | STA_PPSERROR)))
155 			*retval = TIME_ERROR;
156 		else
157 			*retval = time_state;
158 	}
159 	return (error);
160 }
161 
162 int
163 netbsd32_ntp_adjtime(l, v, retval)
164 	struct lwp *l;
165 	void *v;
166 	register_t *retval;
167 {
168 	struct netbsd32_ntp_adjtime_args /* {
169 		syscallarg(netbsd32_timexp_t) tp;
170 	} */ *uap = v;
171 	struct netbsd32_timex ntv32;
172 	struct timex ntv;
173 	int error = 0;
174 	int modes;
175 	int s;
176 	struct proc *p = l->l_proc;
177 	extern long time_freq;		/* frequency offset (scaled ppm) */
178 	extern long time_maxerror;
179 	extern long time_esterror;
180 	extern int time_state;	/* clock state */
181 	extern int time_status;	/* clock status bits */
182 	extern long time_constant;		/* pll time constant */
183 	extern long time_offset;		/* time offset (us) */
184 	extern long time_tolerance;	/* frequency tolerance (scaled ppm) */
185 	extern long time_precision;	/* clock precision (us) */
186 
187 	if ((error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, tp)),
188 	    (caddr_t)&ntv32, sizeof(ntv32))))
189 		return (error);
190 	netbsd32_to_timex(&ntv32, &ntv);
191 
192 	/*
193 	 * Update selected clock variables - only the superuser can
194 	 * change anything. Note that there is no error checking here on
195 	 * the assumption the superuser should know what it is doing.
196 	 */
197 	modes = ntv.modes;
198 	if (modes != 0 && (error = suser(p->p_ucred, &p->p_acflag)))
199 		return (error);
200 
201 	s = splclock();
202 	if (modes & MOD_FREQUENCY)
203 #ifdef PPS_SYNC
204 		time_freq = ntv.freq - pps_freq;
205 #else /* PPS_SYNC */
206 		time_freq = ntv.freq;
207 #endif /* PPS_SYNC */
208 	if (modes & MOD_MAXERROR)
209 		time_maxerror = ntv.maxerror;
210 	if (modes & MOD_ESTERROR)
211 		time_esterror = ntv.esterror;
212 	if (modes & MOD_STATUS) {
213 		time_status &= STA_RONLY;
214 		time_status |= ntv.status & ~STA_RONLY;
215 	}
216 	if (modes & MOD_TIMECONST)
217 		time_constant = ntv.constant;
218 	if (modes & MOD_OFFSET)
219 		hardupdate(ntv.offset);
220 
221 	/*
222 	 * Retrieve all clock variables
223 	 */
224 	if (time_offset < 0)
225 		ntv.offset = -(-time_offset >> SHIFT_UPDATE);
226 	else
227 		ntv.offset = time_offset >> SHIFT_UPDATE;
228 #ifdef PPS_SYNC
229 	ntv.freq = time_freq + pps_freq;
230 #else /* PPS_SYNC */
231 	ntv.freq = time_freq;
232 #endif /* PPS_SYNC */
233 	ntv.maxerror = time_maxerror;
234 	ntv.esterror = time_esterror;
235 	ntv.status = time_status;
236 	ntv.constant = time_constant;
237 	ntv.precision = time_precision;
238 	ntv.tolerance = time_tolerance;
239 #ifdef PPS_SYNC
240 	ntv.shift = pps_shift;
241 	ntv.ppsfreq = pps_freq;
242 	ntv.jitter = pps_jitter >> PPS_AVG;
243 	ntv.stabil = pps_stabil;
244 	ntv.calcnt = pps_calcnt;
245 	ntv.errcnt = pps_errcnt;
246 	ntv.jitcnt = pps_jitcnt;
247 	ntv.stbcnt = pps_stbcnt;
248 #endif /* PPS_SYNC */
249 	(void)splx(s);
250 
251 	netbsd32_from_timex(&ntv, &ntv32);
252 	error = copyout((caddr_t)&ntv32, (caddr_t)NETBSD32PTR64(SCARG(uap, tp)),
253 	    sizeof(ntv32));
254 	if (!error) {
255 
256 		/*
257 		 * Status word error decode. See comments in
258 		 * ntp_gettime() routine.
259 		 */
260 		if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) ||
261 		    (time_status & (STA_PPSFREQ | STA_PPSTIME) &&
262 		    !(time_status & STA_PPSSIGNAL)) ||
263 		    (time_status & STA_PPSTIME &&
264 		    time_status & STA_PPSJITTER) ||
265 		    (time_status & STA_PPSFREQ &&
266 		    time_status & (STA_PPSWANDER | STA_PPSERROR)))
267 			*retval = TIME_ERROR;
268 		else
269 			*retval = time_state;
270 	}
271 	return error;
272 }
273 #else
274 int
275 netbsd32_ntp_gettime(l, v, retval)
276 	struct lwp *l;
277 	void *v;
278 	register_t *retval;
279 {
280 
281 	return (ENOSYS);
282 }
283 
284 int
285 netbsd32_ntp_adjtime(l, v, retval)
286 	struct lwp *l;
287 	void *v;
288 	register_t *retval;
289 {
290 
291 	return (ENOSYS);
292 }
293 #endif
294 
295 int
296 netbsd32_setitimer(l, v, retval)
297 	struct lwp *l;
298 	void *v;
299 	register_t *retval;
300 {
301 	struct netbsd32_setitimer_args /* {
302 		syscallarg(int) which;
303 		syscallarg(const netbsd32_itimervalp_t) itv;
304 		syscallarg(netbsd32_itimervalp_t) oitv;
305 	} */ *uap = v;
306 	struct proc *p = l->l_proc;
307 	struct netbsd32_itimerval s32it, *itv32;
308 	int which = SCARG(uap, which);
309 	struct netbsd32_getitimer_args getargs;
310 	struct itimerval aitv;
311 	int error;
312 
313 	if ((u_int)which > ITIMER_PROF)
314 		return (EINVAL);
315 	itv32 = (struct netbsd32_itimerval *)NETBSD32PTR64(SCARG(uap, itv));
316 	if (itv32) {
317 		if ((error = copyin(itv32, &s32it, sizeof(s32it))))
318 			return (error);
319 		netbsd32_to_itimerval(&s32it, &aitv);
320 	}
321 	if (SCARG(uap, oitv) != 0) {
322 		SCARG(&getargs, which) = which;
323 		SCARG(&getargs, itv) = SCARG(uap, oitv);
324 		if ((error = netbsd32_getitimer(l, &getargs, retval)) != 0)
325 			return (error);
326 	}
327 	if (itv32 == 0)
328 		return 0;
329 
330 	return dosetitimer(p, which, &aitv);
331 }
332 
333 int
334 netbsd32_getitimer(l, v, retval)
335 	struct lwp *l;
336 	void *v;
337 	register_t *retval;
338 {
339 	struct netbsd32_getitimer_args /* {
340 		syscallarg(int) which;
341 		syscallarg(netbsd32_itimervalp_t) itv;
342 	} */ *uap = v;
343 	struct proc *p = l->l_proc;
344 	struct netbsd32_itimerval s32it;
345 	struct itimerval aitv;
346 	int error;
347 
348 	error = dogetitimer(p, SCARG(uap, which), &aitv);
349 	if (error)
350 		return error;
351 
352 	netbsd32_from_itimerval(&aitv, &s32it);
353 	return (copyout(&s32it, (caddr_t)NETBSD32PTR64(SCARG(uap, itv)),
354 	    sizeof(s32it)));
355 }
356 
357 int
358 netbsd32_gettimeofday(l, v, retval)
359 	struct lwp *l;
360 	void *v;
361 	register_t *retval;
362 {
363 	struct netbsd32_gettimeofday_args /* {
364 		syscallarg(netbsd32_timevalp_t) tp;
365 		syscallarg(netbsd32_timezonep_t) tzp;
366 	} */ *uap = v;
367 	struct timeval atv;
368 	struct netbsd32_timeval tv32;
369 	int error = 0;
370 	struct netbsd32_timezone tzfake;
371 
372 	if (SCARG(uap, tp)) {
373 		microtime(&atv);
374 		netbsd32_from_timeval(&atv, &tv32);
375 		error = copyout(&tv32, (caddr_t)NETBSD32PTR64(SCARG(uap, tp)),
376 		    sizeof(tv32));
377 		if (error)
378 			return (error);
379 	}
380 	if (SCARG(uap, tzp)) {
381 		/*
382 		 * NetBSD has no kernel notion of time zone, so we just
383 		 * fake up a timezone struct and return it if demanded.
384 		 */
385 		tzfake.tz_minuteswest = 0;
386 		tzfake.tz_dsttime = 0;
387 		error = copyout(&tzfake,
388 		    (caddr_t)NETBSD32PTR64(SCARG(uap, tzp)), sizeof(tzfake));
389 	}
390 	return (error);
391 }
392 
393 int
394 netbsd32_settimeofday(l, v, retval)
395 	struct lwp *l;
396 	void *v;
397 	register_t *retval;
398 {
399 	struct netbsd32_settimeofday_args /* {
400 		syscallarg(const netbsd32_timevalp_t) tv;
401 		syscallarg(const netbsd32_timezonep_t) tzp;
402 	} */ *uap = v;
403 	struct netbsd32_timeval atv32;
404 	struct timeval atv;
405 	struct timespec ats;
406 	int error;
407 	struct proc *p = l->l_proc;
408 
409 	/* Verify all parameters before changing time. */
410 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
411 		return error;
412 
413 	/*
414 	 * NetBSD has no kernel notion of time zone, and only an
415 	 * obsolete program would try to set it, so we log a warning.
416 	 */
417 	if (SCARG(uap, tzp))
418 		printf("pid %d attempted to set the "
419 		    "(obsolete) kernel time zone\n", p->p_pid);
420 
421 	if (SCARG(uap, tv) == 0)
422 		return 0;
423 
424 	if ((error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, tv)), &atv32,
425 	    sizeof(atv32))) != 0)
426 		return error;
427 
428 	netbsd32_to_timeval(&atv32, &atv);
429 	TIMEVAL_TO_TIMESPEC(&atv, &ats);
430 	return settime(p, &ats);
431 }
432 
433 int
434 netbsd32_adjtime(l, v, retval)
435 	struct lwp *l;
436 	void *v;
437 	register_t *retval;
438 {
439 	struct netbsd32_adjtime_args /* {
440 		syscallarg(const netbsd32_timevalp_t) delta;
441 		syscallarg(netbsd32_timevalp_t) olddelta;
442 	} */ *uap = v;
443 	struct netbsd32_timeval atv;
444 	int32_t ndelta, ntickdelta, odelta;
445 	int s, error;
446 	struct proc *p = l->l_proc;
447 	extern long bigadj, timedelta;
448 	extern int tickdelta;
449 
450 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
451 		return (error);
452 
453 	error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, delta)), &atv,
454 	    sizeof(struct timeval));
455 	if (error)
456 		return (error);
457 	/*
458 	 * Compute the total correction and the rate at which to apply it.
459 	 * Round the adjustment down to a whole multiple of the per-tick
460 	 * delta, so that after some number of incremental changes in
461 	 * hardclock(), tickdelta will become zero, lest the correction
462 	 * overshoot and start taking us away from the desired final time.
463 	 */
464 	ndelta = atv.tv_sec * 1000000 + atv.tv_usec;
465 	if (ndelta > bigadj)
466 		ntickdelta = 10 * tickadj;
467 	else
468 		ntickdelta = tickadj;
469 	if (ndelta % ntickdelta)
470 		ndelta = ndelta / ntickdelta * ntickdelta;
471 
472 	/*
473 	 * To make hardclock()'s job easier, make the per-tick delta negative
474 	 * if we want time to run slower; then hardclock can simply compute
475 	 * tick + tickdelta, and subtract tickdelta from timedelta.
476 	 */
477 	if (ndelta < 0)
478 		ntickdelta = -ntickdelta;
479 	s = splclock();
480 	odelta = timedelta;
481 	timedelta = ndelta;
482 	tickdelta = ntickdelta;
483 	splx(s);
484 
485 	if (SCARG(uap, olddelta)) {
486 		atv.tv_sec = odelta / 1000000;
487 		atv.tv_usec = odelta % 1000000;
488 		(void) copyout(&atv,
489 		    (caddr_t)NETBSD32PTR64(SCARG(uap, olddelta)), sizeof(atv));
490 	}
491 	return (0);
492 }
493 
494 int
495 netbsd32_clock_gettime(l, v, retval)
496 	struct lwp *l;
497 	void *v;
498 	register_t *retval;
499 {
500 	struct netbsd32_clock_gettime_args /* {
501 		syscallarg(netbsd32_clockid_t) clock_id;
502 		syscallarg(netbsd32_timespecp_t) tp;
503 	} */ *uap = v;
504 	clockid_t clock_id;
505 	struct timespec ats;
506 	struct netbsd32_timespec ts32;
507 
508 	clock_id = SCARG(uap, clock_id);
509 	if (clock_id != CLOCK_REALTIME)
510 		return (EINVAL);
511 
512 	nanotime(&ats);
513 	netbsd32_from_timespec(&ats, &ts32);
514 
515 	return copyout(&ts32, (caddr_t)NETBSD32PTR64(SCARG(uap, tp)),
516 	    sizeof(ts32));
517 }
518 
519 int
520 netbsd32_clock_settime(l, v, retval)
521 	struct lwp *l;
522 	void *v;
523 	register_t *retval;
524 {
525 	struct netbsd32_clock_settime_args /* {
526 		syscallarg(netbsd32_clockid_t) clock_id;
527 		syscallarg(const netbsd32_timespecp_t) tp;
528 	} */ *uap = v;
529 	struct netbsd32_timespec ts32;
530 	clockid_t clock_id;
531 	struct timespec ats;
532 	int error;
533 	struct proc *p = l->l_proc;
534 
535 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
536 		return (error);
537 
538 	clock_id = SCARG(uap, clock_id);
539 	if (clock_id != CLOCK_REALTIME)
540 		return (EINVAL);
541 
542 	if ((error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, tp)), &ts32,
543 	    sizeof(ts32))) != 0)
544 		return (error);
545 
546 	netbsd32_to_timespec(&ts32, &ats);
547 	return settime(p, &ats);
548 }
549 
550 int
551 netbsd32_clock_getres(l, v, retval)
552 	struct lwp *l;
553 	void *v;
554 	register_t *retval;
555 {
556 	struct netbsd32_clock_getres_args /* {
557 		syscallarg(netbsd32_clockid_t) clock_id;
558 		syscallarg(netbsd32_timespecp_t) tp;
559 	} */ *uap = v;
560 	struct netbsd32_timespec ts32;
561 	clockid_t clock_id;
562 	struct timespec ts;
563 	int error = 0;
564 
565 	clock_id = SCARG(uap, clock_id);
566 	if (clock_id != CLOCK_REALTIME)
567 		return (EINVAL);
568 
569 	if (SCARG(uap, tp)) {
570 		ts.tv_sec = 0;
571 		ts.tv_nsec = 1000000000 / hz;
572 
573 		netbsd32_from_timespec(&ts, &ts32);
574 		error = copyout(&ts, (caddr_t)NETBSD32PTR64(SCARG(uap, tp)),
575 		    sizeof(ts));
576 	}
577 
578 	return error;
579 }
580 
581 int
582 netbsd32_nanosleep(l, v, retval)
583 	struct lwp *l;
584 	void *v;
585 	register_t *retval;
586 {
587 	struct netbsd32_nanosleep_args /* {
588 		syscallarg(const netbsd32_timespecp_t) rqtp;
589 		syscallarg(netbsd32_timespecp_t) rmtp;
590 	} */ *uap = v;
591 	static int nanowait;
592 	struct netbsd32_timespec ts32;
593 	struct timespec rqt;
594 	struct timespec rmt;
595 	struct timeval atv, utv;
596 	int error, s, timo;
597 
598 	error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, rqtp)), (caddr_t)&ts32,
599 	    sizeof(ts32));
600 	if (error)
601 		return (error);
602 
603 	netbsd32_to_timespec(&ts32, &rqt);
604 	TIMESPEC_TO_TIMEVAL(&atv,&rqt);
605 	if (itimerfix(&atv))
606 		return (EINVAL);
607 
608 	s = splclock();
609 	timeradd(&atv,&time,&atv);
610 	timo = hzto(&atv);
611 	/*
612 	 * Avoid inadvertantly sleeping forever
613 	 */
614 	if (timo == 0)
615 		timo = 1;
616 	splx(s);
617 
618 	error = tsleep(&nanowait, PWAIT | PCATCH, "nanosleep", timo);
619 	if (error == ERESTART)
620 		error = EINTR;
621 	if (error == EWOULDBLOCK)
622 		error = 0;
623 
624 	if (SCARG(uap, rmtp)) {
625 		int error1;
626 
627 		s = splclock();
628 		utv = time;
629 		splx(s);
630 
631 		timersub(&atv, &utv, &utv);
632 		if (utv.tv_sec < 0)
633 			timerclear(&utv);
634 
635 		TIMEVAL_TO_TIMESPEC(&utv,&rmt);
636 		netbsd32_from_timespec(&rmt, &ts32);
637 		error1 = copyout(&ts32,
638 		    NETBSD32PTR64(SCARG(uap,rmtp)), sizeof(ts32));
639 		if (error1)
640 			return (error1);
641 	}
642 
643 	return error;
644 }
645 
646 static int
647 netbsd32_timer_create_fetch(const void *src, void *dst, size_t size)
648 {
649 	struct sigevent *evp = dst;
650 	struct netbsd32_sigevent ev32;
651 	int error;
652 
653 	error = copyin(src, &ev32, sizeof(ev32));
654 	if (error)
655 		return error;
656 
657 	netbsd32_to_sigevent(&ev32, evp);
658 	return 0;
659 }
660 
661 int
662 netbsd32_timer_create(struct lwp *l, void *v, register_t *retval)
663 {
664 	struct netbsd32_timer_create_args /* {
665 		syscallarg(netbsd32_clockid_t) clock_id;
666 		syscallarg(netbsd32_sigeventp_t) evp;
667 		syscallarg(netbsd32_timerp_t) timerid;
668 	} */ *uap = v;
669 
670 	return timer_create1(NETBSD32PTR64(SCARG(uap, timerid)),
671 	    SCARG(uap, clock_id), NETBSD32PTR64(SCARG(uap, evp)),
672 	    netbsd32_timer_create_fetch, l->l_proc);
673 }
674 
675 int
676 netbsd32_timer_delete(struct lwp *l, void *v, register_t *retval)
677 {
678 	struct netbsd32_timer_delete_args /* {
679 		syscallarg(netbsd32_timer_t) timerid;
680 	} */ *uap = v;
681 	struct sys_timer_delete_args ua;
682 
683 	NETBSD32TO64_UAP(timerid);
684 	return sys_timer_delete(l, (void *)&ua, retval);
685 }
686 
687 int
688 netbsd32_timer_settime(struct lwp *l, void *v, register_t *retval)
689 {
690 	struct netbsd32_timer_settime_args /* {
691 		syscallarg(netbsd32_timer_t) timerid;
692 		syscallarg(int) flags;
693 		syscallarg(const netbsd32_itimerspecp_t) value;
694 		syscallarg(netbsd32_itimerspecp_t) ovalue;
695 	} */ *uap = v;
696 	int error;
697 	struct itimerspec value, ovalue, *ovp = NULL;
698 	struct netbsd32_itimerspec its32;
699 
700 	if ((error = copyin(NETBSD32PTR64(SCARG(uap, value)), &its32,
701 	    sizeof(its32))) != 0)
702 		return (error);
703 	netbsd32_to_timespec(&its32.it_interval, &value.it_interval);
704 	netbsd32_to_timespec(&its32.it_value, &value.it_value);
705 
706 	if (SCARG(uap, ovalue))
707 		ovp = &ovalue;
708 
709 	if ((error = dotimer_settime(SCARG(uap, timerid), &value, ovp,
710 	    SCARG(uap, flags), l->l_proc)) != 0)
711 		return error;
712 
713 	if (ovp) {
714 		netbsd32_from_timespec(&ovp->it_interval, &its32.it_interval);
715 		netbsd32_from_timespec(&ovp->it_value, &its32.it_value);
716 		return copyout(&its32, NETBSD32PTR64(SCARG(uap, ovalue)),
717 		    sizeof(its32));
718 	}
719 	return 0;
720 }
721 
722 int
723 netbsd32_timer_gettime(struct lwp *l, void *v, register_t *retval)
724 {
725 	struct netbsd32_timer_gettime_args /* {
726 		syscallarg(netbsd32_timer_t) timerid;
727 		syscallarg(netbsd32_itimerspecp_t) value;
728 	} */ *uap = v;
729 	int error;
730 	struct itimerspec its;
731 	struct netbsd32_itimerspec its32;
732 
733 	if ((error = dotimer_gettime(SCARG(uap, timerid), l->l_proc,
734 	    &its)) != 0)
735 		return error;
736 
737 	netbsd32_from_timespec(&its.it_interval, &its32.it_interval);
738 	netbsd32_from_timespec(&its.it_value, &its32.it_value);
739 
740 	return copyout(&its32, (caddr_t)NETBSD32PTR64(SCARG(uap, value)),
741 	    sizeof(its32));
742 }
743 
744 int
745 netbsd32_timer_getoverrun(struct lwp *l, void *v, register_t *retval)
746 {
747 	struct netbsd32_timer_getoverrun_args /* {
748 		syscallarg(netbsd32_timer_t) timerid;
749 	} */ *uap = v;
750 	struct sys_timer_getoverrun_args ua;
751 
752 	NETBSD32TO64_UAP(timerid);
753 	return sys_timer_getoverrun(l, (void *)&ua, retval);
754 }
755