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