Home | History | Annotate | Line # | Download | only in netbsd32
netbsd32_time.c revision 1.25.2.1
      1 /*	$NetBSD: netbsd32_time.c,v 1.25.2.1 2007/04/10 13:26:30 ad 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.25.2.1 2007/04/10 13:26:30 ad Exp $");
     33 
     34 #if defined(_KERNEL_OPT)
     35 #include "opt_ntp.h"
     36 #include "opt_compat_netbsd.h"
     37 #endif
     38 
     39 #include <sys/param.h>
     40 #include <sys/systm.h>
     41 #include <sys/mount.h>
     42 #include <sys/time.h>
     43 #include <sys/timex.h>
     44 #include <sys/timevar.h>
     45 #include <sys/timetc.h>
     46 #include <sys/proc.h>
     47 #include <sys/pool.h>
     48 #include <sys/resourcevar.h>
     49 #include <sys/dirent.h>
     50 #include <sys/kauth.h>
     51 
     52 #include <compat/netbsd32/netbsd32.h>
     53 #include <compat/netbsd32/netbsd32_syscallargs.h>
     54 #include <compat/netbsd32/netbsd32_conv.h>
     55 
     56 #ifdef NTP
     57 
     58 int
     59 netbsd32_ntp_gettime(l, v, retval)
     60 	struct lwp *l;
     61 	void *v;
     62 	register_t *retval;
     63 {
     64 	struct netbsd32_ntp_gettime_args /* {
     65 		syscallarg(netbsd32_ntptimevalp_t) ntvp;
     66 	} */ *uap = v;
     67 	struct netbsd32_ntptimeval ntv32;
     68 	struct ntptimeval ntv;
     69 	int error = 0;
     70 
     71 	if (SCARG_P32(uap, ntvp)) {
     72 		ntp_gettime(&ntv);
     73 
     74 		ntv32.time.tv_sec = ntv.time.tv_sec;
     75 		ntv32.time.tv_nsec = ntv.time.tv_nsec;
     76 		ntv32.maxerror = (netbsd32_long)ntv.maxerror;
     77 		ntv32.esterror = (netbsd32_long)ntv.esterror;
     78 		ntv32.tai = (netbsd32_long)ntv.tai;
     79 		ntv32.time_state = ntv.time_state;
     80 		error = copyout(&ntv32, SCARG_P32(uap, ntvp), sizeof(ntv32));
     81 	}
     82 	if (!error) {
     83 		*retval = ntp_timestatus();
     84 	}
     85 
     86 	return (error);
     87 }
     88 
     89 #ifdef COMPAT_30
     90 int
     91 compat_30_netbsd32_ntp_gettime(l, v, retval)
     92 	struct lwp *l;
     93 	void *v;
     94 	register_t *retval;
     95 {
     96 	struct compat_30_netbsd32_ntp_gettime_args /* {
     97 		syscallarg(netbsd32_ntptimevalp_t) ntvp;
     98 	} */ *uap = v;
     99 	struct netbsd32_ntptimeval30 ntv32;
    100 	struct ntptimeval ntv;
    101 	int error = 0;
    102 
    103 	if (SCARG_P32(uap, ntvp)) {
    104 		ntp_gettime(&ntv);
    105 
    106 		ntv32.time.tv_sec = ntv.time.tv_sec;
    107 		ntv32.time.tv_usec = ntv.time.tv_nsec / 1000;
    108 		ntv32.maxerror = (netbsd32_long)ntv.maxerror;
    109 		ntv32.esterror = (netbsd32_long)ntv.esterror;
    110 		error = copyout(&ntv32, SCARG_P32(uap, ntvp), sizeof(ntv32));
    111 	}
    112 	if (!error) {
    113 		*retval = ntp_timestatus();
    114 	}
    115 
    116 	return (error);
    117 }
    118 #endif
    119 
    120 int
    121 netbsd32_ntp_adjtime(l, v, retval)
    122 	struct lwp *l;
    123 	void *v;
    124 	register_t *retval;
    125 {
    126 	struct netbsd32_ntp_adjtime_args /* {
    127 		syscallarg(netbsd32_timexp_t) tp;
    128 	} */ *uap = v;
    129 	struct netbsd32_timex ntv32;
    130 	struct timex ntv;
    131 	int error = 0;
    132 	int modes;
    133 
    134 	if ((error = copyin(SCARG_P32(uap, tp), &ntv32, sizeof(ntv32))))
    135 		return (error);
    136 
    137 	netbsd32_to_timex(&ntv32, &ntv);
    138 
    139 	/*
    140 	 * Update selected clock variables - only the superuser can
    141 	 * change anything. Note that there is no error checking here on
    142 	 * the assumption the superuser should know what it is doing.
    143 	 */
    144 	modes = ntv.modes;
    145 	if (modes != 0 && (error = kauth_authorize_system(l->l_cred,
    146 	    KAUTH_SYSTEM_TIME, KAUTH_REQ_SYSTEM_TIME_NTPADJTIME, NULL, NULL,
    147 	    NULL)))
    148 		return (error);
    149 
    150 	ntp_adjtime1(&ntv);
    151 
    152 	netbsd32_from_timex(&ntv, &ntv32);
    153 	error = copyout(&ntv32, SCARG_P32(uap, tp), sizeof(ntv32));
    154 	if (!error) {
    155 		*retval = ntp_timestatus();
    156 	}
    157 	return error;
    158 }
    159 #else /* !NTP */
    160 int
    161 netbsd32_ntp_gettime(l, v, retval)
    162 	struct lwp *l;
    163 	void *v;
    164 	register_t *retval;
    165 {
    166 
    167 	return (ENOSYS);
    168 }
    169 
    170 #ifdef COMPAT_30
    171 int
    172 compat_30_netbsd32_ntp_gettime(l, v, retval)
    173 	struct lwp *l;
    174 	void *v;
    175 	register_t *retval;
    176 {
    177 
    178 	return (ENOSYS);
    179 }
    180 #endif
    181 
    182 int
    183 netbsd32_ntp_adjtime(l, v, retval)
    184 	struct lwp *l;
    185 	void *v;
    186 	register_t *retval;
    187 {
    188 
    189 	return (ENOSYS);
    190 }
    191 #endif /* NTP */
    192 
    193 int
    194 netbsd32_setitimer(l, v, retval)
    195 	struct lwp *l;
    196 	void *v;
    197 	register_t *retval;
    198 {
    199 	struct netbsd32_setitimer_args /* {
    200 		syscallarg(int) which;
    201 		syscallarg(const netbsd32_itimervalp_t) itv;
    202 		syscallarg(netbsd32_itimervalp_t) oitv;
    203 	} */ *uap = v;
    204 	struct proc *p = l->l_proc;
    205 	struct netbsd32_itimerval s32it, *itv32;
    206 	int which = SCARG(uap, which);
    207 	struct netbsd32_getitimer_args getargs;
    208 	struct itimerval aitv;
    209 	int error;
    210 
    211 	if ((u_int)which > ITIMER_PROF)
    212 		return (EINVAL);
    213 	itv32 = SCARG_P32(uap, itv);
    214 	if (itv32) {
    215 		if ((error = copyin(itv32, &s32it, sizeof(s32it))))
    216 			return (error);
    217 		netbsd32_to_itimerval(&s32it, &aitv);
    218 	}
    219 	if (SCARG_P32(uap, oitv) != 0) {
    220 		SCARG(&getargs, which) = which;
    221 		SCARG(&getargs, itv) = SCARG(uap, oitv);
    222 		if ((error = netbsd32_getitimer(l, &getargs, retval)) != 0)
    223 			return (error);
    224 	}
    225 	if (itv32 == 0)
    226 		return 0;
    227 
    228 	return dosetitimer(p, which, &aitv);
    229 }
    230 
    231 int
    232 netbsd32_getitimer(l, v, retval)
    233 	struct lwp *l;
    234 	void *v;
    235 	register_t *retval;
    236 {
    237 	struct netbsd32_getitimer_args /* {
    238 		syscallarg(int) which;
    239 		syscallarg(netbsd32_itimervalp_t) itv;
    240 	} */ *uap = v;
    241 	struct proc *p = l->l_proc;
    242 	struct netbsd32_itimerval s32it;
    243 	struct itimerval aitv;
    244 	int error;
    245 
    246 	error = dogetitimer(p, SCARG(uap, which), &aitv);
    247 	if (error)
    248 		return error;
    249 
    250 	netbsd32_from_itimerval(&aitv, &s32it);
    251 	return copyout(&s32it, SCARG_P32(uap, itv), sizeof(s32it));
    252 }
    253 
    254 int
    255 netbsd32_gettimeofday(l, v, retval)
    256 	struct lwp *l;
    257 	void *v;
    258 	register_t *retval;
    259 {
    260 	struct netbsd32_gettimeofday_args /* {
    261 		syscallarg(netbsd32_timevalp_t) tp;
    262 		syscallarg(netbsd32_timezonep_t) tzp;
    263 	} */ *uap = v;
    264 	struct timeval atv;
    265 	struct netbsd32_timeval tv32;
    266 	int error = 0;
    267 	struct netbsd32_timezone tzfake;
    268 
    269 	if (SCARG_P32(uap, tp)) {
    270 		microtime(&atv);
    271 		netbsd32_from_timeval(&atv, &tv32);
    272 		error = copyout(&tv32, SCARG_P32(uap, tp), sizeof(tv32));
    273 		if (error)
    274 			return (error);
    275 	}
    276 	if (SCARG_P32(uap, tzp)) {
    277 		/*
    278 		 * NetBSD has no kernel notion of time zone, so we just
    279 		 * fake up a timezone struct and return it if demanded.
    280 		 */
    281 		tzfake.tz_minuteswest = 0;
    282 		tzfake.tz_dsttime = 0;
    283 		error = copyout(&tzfake, SCARG_P32(uap, tzp), sizeof(tzfake));
    284 	}
    285 	return (error);
    286 }
    287 
    288 int
    289 netbsd32_settimeofday(l, v, retval)
    290 	struct lwp *l;
    291 	void *v;
    292 	register_t *retval;
    293 {
    294 	struct netbsd32_settimeofday_args /* {
    295 		syscallarg(const netbsd32_timevalp_t) tv;
    296 		syscallarg(const netbsd32_timezonep_t) tzp;
    297 	} */ *uap = v;
    298 	struct netbsd32_timeval atv32;
    299 	struct timeval atv;
    300 	struct timespec ats;
    301 	int error;
    302 	struct proc *p = l->l_proc;
    303 
    304 	/* Verify all parameters before changing time. */
    305 	if ((error = kauth_authorize_system(l->l_cred,
    306 	    KAUTH_SYSTEM_TIME, KAUTH_REQ_SYSTEM_TIME_SYSTEM, NULL, NULL,
    307 	    NULL)) != 0)
    308 		return error;
    309 
    310 	/*
    311 	 * NetBSD has no kernel notion of time zone, and only an
    312 	 * obsolete program would try to set it, so we log a warning.
    313 	 */
    314 	if (SCARG_P32(uap, tzp))
    315 		printf("pid %d attempted to set the "
    316 		    "(obsolete) kernel time zone\n", p->p_pid);
    317 
    318 	if (SCARG_P32(uap, tv) == 0)
    319 		return 0;
    320 
    321 	if ((error = copyin(SCARG_P32(uap, tv), &atv32, sizeof(atv32))) != 0)
    322 		return error;
    323 
    324 	netbsd32_to_timeval(&atv32, &atv);
    325 	TIMEVAL_TO_TIMESPEC(&atv, &ats);
    326 	return settime(p, &ats);
    327 }
    328 
    329 int
    330 netbsd32_adjtime(l, v, retval)
    331 	struct lwp *l;
    332 	void *v;
    333 	register_t *retval;
    334 {
    335 	struct netbsd32_adjtime_args /* {
    336 		syscallarg(const netbsd32_timevalp_t) delta;
    337 		syscallarg(netbsd32_timevalp_t) olddelta;
    338 	} */ *uap = v;
    339 	struct netbsd32_timeval atv;
    340 	int error;
    341 
    342 	if ((error = kauth_authorize_system(l->l_cred,
    343 	    KAUTH_SYSTEM_TIME, KAUTH_REQ_SYSTEM_TIME_ADJTIME, NULL, NULL,
    344 	    NULL)) != 0)
    345 		return (error);
    346 
    347 #ifdef __HAVE_TIMECOUNTER
    348 	{
    349 		extern int time_adjusted;     /* in kern_ntptime.c */
    350 		extern int64_t time_adjtime;  /* in kern_ntptime.c */
    351 		if (SCARG_P32(uap, olddelta)) {
    352 			atv.tv_sec = time_adjtime / 1000000;
    353 			atv.tv_usec = time_adjtime % 1000000;
    354 			if (atv.tv_usec < 0) {
    355 				atv.tv_usec += 1000000;
    356 				atv.tv_sec--;
    357 			}
    358 			(void) copyout(&atv,
    359 				       SCARG_P32(uap, olddelta),
    360 				       sizeof(atv));
    361 			if (error)
    362 				return (error);
    363 		}
    364 
    365 		if (SCARG_P32(uap, delta)) {
    366 			error = copyin(SCARG_P32(uap, delta), &atv,
    367 				       sizeof(struct timeval));
    368 			if (error)
    369 				return (error);
    370 
    371 			time_adjtime = (int64_t)atv.tv_sec * 1000000 +
    372 				atv.tv_usec;
    373 
    374 			if (time_adjtime)
    375 				/* We need to save the system time during shutdown */
    376 				time_adjusted |= 1;
    377 		}
    378 	}
    379 #else /* !__HAVE_TIMECOUNTER */
    380 	{
    381 		int32_t ndelta, ntickdelta, odelta;
    382 		extern long bigadj, timedelta;
    383 		extern int tickdelta;
    384 		int s;
    385 		error = copyin(SCARG_P32(uap, delta), &atv,
    386 			       sizeof(struct timeval));
    387 		if (error)
    388 			return (error);
    389 		/*
    390 		 * Compute the total correction and the rate at which to apply it.
    391 		 * Round the adjustment down to a whole multiple of the per-tick
    392 		 * delta, so that after some number of incremental changes in
    393 		 * hardclock(), tickdelta will become zero, lest the correction
    394 		 * overshoot and start taking us away from the desired final time.
    395 		 */
    396 		ndelta = atv.tv_sec * 1000000 + atv.tv_usec;
    397 		if (ndelta > bigadj)
    398 			ntickdelta = 10 * tickadj;
    399 		else
    400 			ntickdelta = tickadj;
    401 		if (ndelta % ntickdelta)
    402 			ndelta = ndelta / ntickdelta * ntickdelta;
    403 
    404 		/*
    405 		 * To make hardclock()'s job easier, make the per-tick delta negative
    406 		 * if we want time to run slower; then hardclock can simply compute
    407 		 * tick + tickdelta, and subtract tickdelta from timedelta.
    408 		 */
    409 		if (ndelta < 0)
    410 			ntickdelta = -ntickdelta;
    411 		s = splclock();
    412 		odelta = timedelta;
    413 		timedelta = ndelta;
    414 		tickdelta = ntickdelta;
    415 		splx(s);
    416 
    417 		if (SCARG_P32(uap, olddelta)) {
    418 			atv.tv_sec = odelta / 1000000;
    419 			atv.tv_usec = odelta % 1000000;
    420 			(void) copyout(&atv,
    421 				       SCARG_P32(uap, olddelta), sizeof(atv));
    422 		}
    423 	}
    424 #endif /* !__HAVE_TIMECOUNTER */
    425 	return (0);
    426 }
    427 
    428 int
    429 netbsd32_clock_gettime(l, v, retval)
    430 	struct lwp *l;
    431 	void *v;
    432 	register_t *retval;
    433 {
    434 	struct netbsd32_clock_gettime_args /* {
    435 		syscallarg(netbsd32_clockid_t) clock_id;
    436 		syscallarg(netbsd32_timespecp_t) tp;
    437 	} */ *uap = v;
    438 	clockid_t clock_id;
    439 	struct timespec ats;
    440 	struct netbsd32_timespec ts32;
    441 
    442 	clock_id = SCARG(uap, clock_id);
    443 	if (clock_id != CLOCK_REALTIME)
    444 		return (EINVAL);
    445 
    446 	nanotime(&ats);
    447 	netbsd32_from_timespec(&ats, &ts32);
    448 
    449 	return copyout(&ts32, SCARG_P32(uap, tp), sizeof(ts32));
    450 }
    451 
    452 int
    453 netbsd32_clock_settime(l, v, retval)
    454 	struct lwp *l;
    455 	void *v;
    456 	register_t *retval;
    457 {
    458 	struct netbsd32_clock_settime_args /* {
    459 		syscallarg(netbsd32_clockid_t) clock_id;
    460 		syscallarg(const netbsd32_timespecp_t) tp;
    461 	} */ *uap = v;
    462 	struct netbsd32_timespec ts32;
    463 	clockid_t clock_id;
    464 	struct timespec ats;
    465 	int error;
    466 
    467 	if ((error = kauth_authorize_system(l->l_cred,
    468 	    KAUTH_SYSTEM_TIME, KAUTH_REQ_SYSTEM_TIME_SYSTEM, NULL, NULL,
    469 	    NULL)) != 0)
    470 		return (error);
    471 
    472 	clock_id = SCARG(uap, clock_id);
    473 	if (clock_id != CLOCK_REALTIME)
    474 		return (EINVAL);
    475 
    476 	if ((error = copyin(SCARG_P32(uap, tp), &ts32, sizeof(ts32))) != 0)
    477 		return (error);
    478 
    479 	netbsd32_to_timespec(&ts32, &ats);
    480 	return settime(l->l_proc, &ats);
    481 }
    482 
    483 int
    484 netbsd32_clock_getres(l, v, retval)
    485 	struct lwp *l;
    486 	void *v;
    487 	register_t *retval;
    488 {
    489 	struct netbsd32_clock_getres_args /* {
    490 		syscallarg(netbsd32_clockid_t) clock_id;
    491 		syscallarg(netbsd32_timespecp_t) tp;
    492 	} */ *uap = v;
    493 	struct netbsd32_timespec ts32;
    494 	clockid_t clock_id;
    495 	struct timespec ts;
    496 	int error = 0;
    497 
    498 	clock_id = SCARG(uap, clock_id);
    499 	if (clock_id != CLOCK_REALTIME)
    500 		return (EINVAL);
    501 
    502 	if (SCARG_P32(uap, tp)) {
    503 		ts.tv_sec = 0;
    504 		ts.tv_nsec = 1000000000 / hz;
    505 
    506 		netbsd32_from_timespec(&ts, &ts32);
    507 		error = copyout(&ts, SCARG_P32(uap, tp), sizeof(ts));
    508 	}
    509 
    510 	return error;
    511 }
    512 
    513 int
    514 netbsd32_nanosleep(l, v, retval)
    515 	struct lwp *l;
    516 	void *v;
    517 	register_t *retval;
    518 {
    519 	struct netbsd32_nanosleep_args /* {
    520 		syscallarg(const netbsd32_timespecp_t) rqtp;
    521 		syscallarg(netbsd32_timespecp_t) rmtp;
    522 	} */ *uap = v;
    523 	static int nanowait;
    524 	struct netbsd32_timespec ts32;
    525 	struct timespec rqt;
    526 	struct timespec rmt;
    527 	struct timeval atv, utv, ctime;
    528 	int error, timo;
    529 
    530 	error = copyin(SCARG_P32(uap, rqtp), &ts32, sizeof(ts32));
    531 	if (error)
    532 		return (error);
    533 
    534 	netbsd32_to_timespec(&ts32, &rqt);
    535 	TIMESPEC_TO_TIMEVAL(&atv,&rqt);
    536 	if (itimerfix(&atv))
    537 		return (EINVAL);
    538 
    539 	getmicrotime(&ctime);
    540 	timeradd(&atv,&ctime,&atv);
    541 	timo = hzto(&atv);
    542 	/*
    543 	 * Avoid inadvertantly sleeping forever
    544 	 */
    545 	if (timo == 0)
    546 		timo = 1;
    547 
    548 	error = tsleep(&nanowait, PWAIT | PCATCH, "nanosleep", timo);
    549 	if (error == ERESTART)
    550 		error = EINTR;
    551 	if (error == EWOULDBLOCK)
    552 		error = 0;
    553 
    554 	if (SCARG_P32(uap, rmtp)) {
    555 		int error1;
    556 
    557 		getmicrotime(&utv);
    558 
    559 		timersub(&atv, &utv, &utv);
    560 		if (utv.tv_sec < 0)
    561 			timerclear(&utv);
    562 
    563 		TIMEVAL_TO_TIMESPEC(&utv,&rmt);
    564 		netbsd32_from_timespec(&rmt, &ts32);
    565 		error1 = copyout(&ts32, SCARG_P32(uap,rmtp), sizeof(ts32));
    566 		if (error1)
    567 			return (error1);
    568 	}
    569 
    570 	return error;
    571 }
    572 
    573 static int
    574 netbsd32_timer_create_fetch(const void *src, void *dst, size_t size)
    575 {
    576 	struct sigevent *evp = dst;
    577 	struct netbsd32_sigevent ev32;
    578 	int error;
    579 
    580 	error = copyin(src, &ev32, sizeof(ev32));
    581 	if (error)
    582 		return error;
    583 
    584 	netbsd32_to_sigevent(&ev32, evp);
    585 	return 0;
    586 }
    587 
    588 int
    589 netbsd32_timer_create(struct lwp *l, void *v, register_t *retval)
    590 {
    591 	struct netbsd32_timer_create_args /* {
    592 		syscallarg(netbsd32_clockid_t) clock_id;
    593 		syscallarg(netbsd32_sigeventp_t) evp;
    594 		syscallarg(netbsd32_timerp_t) timerid;
    595 	} */ *uap = v;
    596 
    597 	return timer_create1(SCARG_P32(uap, timerid),
    598 	    SCARG(uap, clock_id), SCARG_P32(uap, evp),
    599 	    netbsd32_timer_create_fetch, l);
    600 }
    601 
    602 int
    603 netbsd32_timer_delete(struct lwp *l, void *v, register_t *retval)
    604 {
    605 	struct netbsd32_timer_delete_args /* {
    606 		syscallarg(netbsd32_timer_t) timerid;
    607 	} */ *uap = v;
    608 	struct sys_timer_delete_args ua;
    609 
    610 	NETBSD32TO64_UAP(timerid);
    611 	return sys_timer_delete(l, (void *)&ua, retval);
    612 }
    613 
    614 int
    615 netbsd32_timer_settime(struct lwp *l, void *v, register_t *retval)
    616 {
    617 	struct netbsd32_timer_settime_args /* {
    618 		syscallarg(netbsd32_timer_t) timerid;
    619 		syscallarg(int) flags;
    620 		syscallarg(const netbsd32_itimerspecp_t) value;
    621 		syscallarg(netbsd32_itimerspecp_t) ovalue;
    622 	} */ *uap = v;
    623 	int error;
    624 	struct itimerspec value, ovalue, *ovp = NULL;
    625 	struct netbsd32_itimerspec its32;
    626 
    627 	if ((error = copyin(SCARG_P32(uap, value), &its32, sizeof(its32))) != 0)
    628 		return (error);
    629 	netbsd32_to_timespec(&its32.it_interval, &value.it_interval);
    630 	netbsd32_to_timespec(&its32.it_value, &value.it_value);
    631 
    632 	if (SCARG_P32(uap, ovalue))
    633 		ovp = &ovalue;
    634 
    635 	if ((error = dotimer_settime(SCARG(uap, timerid), &value, ovp,
    636 	    SCARG(uap, flags), l->l_proc)) != 0)
    637 		return error;
    638 
    639 	if (ovp) {
    640 		netbsd32_from_timespec(&ovp->it_interval, &its32.it_interval);
    641 		netbsd32_from_timespec(&ovp->it_value, &its32.it_value);
    642 		return copyout(&its32, SCARG_P32(uap, ovalue), sizeof(its32));
    643 	}
    644 	return 0;
    645 }
    646 
    647 int
    648 netbsd32_timer_gettime(struct lwp *l, void *v, register_t *retval)
    649 {
    650 	struct netbsd32_timer_gettime_args /* {
    651 		syscallarg(netbsd32_timer_t) timerid;
    652 		syscallarg(netbsd32_itimerspecp_t) value;
    653 	} */ *uap = v;
    654 	int error;
    655 	struct itimerspec its;
    656 	struct netbsd32_itimerspec its32;
    657 
    658 	if ((error = dotimer_gettime(SCARG(uap, timerid), l->l_proc,
    659 	    &its)) != 0)
    660 		return error;
    661 
    662 	netbsd32_from_timespec(&its.it_interval, &its32.it_interval);
    663 	netbsd32_from_timespec(&its.it_value, &its32.it_value);
    664 
    665 	return copyout(&its32, SCARG_P32(uap, value), sizeof(its32));
    666 }
    667 
    668 int
    669 netbsd32_timer_getoverrun(struct lwp *l, void *v, register_t *retval)
    670 {
    671 	struct netbsd32_timer_getoverrun_args /* {
    672 		syscallarg(netbsd32_timer_t) timerid;
    673 	} */ *uap = v;
    674 	struct sys_timer_getoverrun_args ua;
    675 
    676 	NETBSD32TO64_UAP(timerid);
    677 	return sys_timer_getoverrun(l, (void *)&ua, retval);
    678 }
    679