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