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