xref: /netbsd-src/sys/compat/netbsd32/netbsd32_time.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /*	$NetBSD: netbsd32_time.c,v 1.7 2004/11/14 03:30:10 atatat 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.7 2004/11/14 03:30:10 atatat 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, *itvp;
290 	int which = SCARG(uap, which);
291 	struct netbsd32_getitimer_args getargs;
292 	struct itimerval aitv;
293 	int s, error;
294 	struct ptimer *pt;
295 
296 	if ((u_int)which > ITIMER_PROF)
297 		return (EINVAL);
298 	itvp = (struct netbsd32_itimerval *)NETBSD32PTR64(SCARG(uap, itv));
299 	if (itvp && (error = copyin(itvp, &s32it, sizeof(s32it))))
300 		return (error);
301 	netbsd32_to_itimerval(&s32it, &aitv);
302 	if (SCARG(uap, oitv) != 0) {
303 		SCARG(&getargs, which) = which;
304 		SCARG(&getargs, itv) = SCARG(uap, oitv);
305 		if ((error = netbsd32_getitimer(l, &getargs, retval)) != 0)
306 			return (error);
307 	}
308 	if (itvp == 0)
309 		return (0);
310 	if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval))
311 		return (EINVAL);
312 
313 /* XXX there should be a way to share code with kern_time */
314 /* XXX just copied some from there */
315 	/*
316 	 * Don't bother allocating data structures if the process just
317 	 * wants to clear the timer.
318 	 */
319 	if (!timerisset(&aitv.it_value) &&
320 	    ((p->p_timers == NULL) || (p->p_timers->pts_timers[which] == NULL)))
321 		return (0);
322 
323 	if (p->p_timers == NULL)
324 		timers_alloc(p);
325 	if (p->p_timers->pts_timers[which] == NULL) {
326 		pt = pool_get(&ptimer_pool, PR_WAITOK);
327 		callout_init(&pt->pt_ch);
328 		pt->pt_ev.sigev_notify = SIGEV_SIGNAL;
329 		pt->pt_overruns = 0;
330 		pt->pt_proc = p;
331 		pt->pt_type = which;
332 		switch (which) {
333 		case ITIMER_REAL:
334 			pt->pt_ev.sigev_signo = SIGALRM;
335 			break;
336 		case ITIMER_VIRTUAL:
337 			pt->pt_ev.sigev_signo = SIGVTALRM;
338 			break;
339 		case ITIMER_PROF:
340 			pt->pt_ev.sigev_signo = SIGPROF;
341 			break;
342 		}
343 	} else
344 		pt = p->p_timers->pts_timers[which];
345 
346 	pt->pt_time = aitv;
347 	p->p_timers->pts_timers[which] = pt;
348 	if (which == ITIMER_REAL) {
349 		s = splclock();
350 		callout_stop(&pt->pt_ch);
351 		if (timerisset(&pt->pt_time.it_value)) {
352 			timeradd(&pt->pt_time.it_value, &time,
353 			    &pt->pt_time.it_value);
354 			/*
355 			 * Don't need to check hzto() return value, here.
356 			 * callout_reset() does it for us.
357 			 */
358 			callout_reset(&pt->pt_ch, hzto(&pt->pt_time.it_value),
359 			    realtimerexpire, pt);
360 		}
361 		splx(s);
362 	}
363 	return (0);
364 }
365 
366 int
367 netbsd32_getitimer(l, v, retval)
368 	struct lwp *l;
369 	void *v;
370 	register_t *retval;
371 {
372 	struct netbsd32_getitimer_args /* {
373 		syscallarg(int) which;
374 		syscallarg(netbsd32_itimervalp_t) itv;
375 	} */ *uap = v;
376 	struct proc *p = l->l_proc;
377 	int which = SCARG(uap, which);
378 	struct netbsd32_itimerval s32it;
379 	struct itimerval aitv;
380 	int s;
381 
382 	if ((u_int)which > ITIMER_PROF)
383 		return (EINVAL);
384 
385 /* XXX same as setitimer */
386 	if ((p->p_timers == NULL) || (p->p_timers->pts_timers[which] == NULL)) {
387 		timerclear(&aitv.it_value);
388 		timerclear(&aitv.it_interval);
389 	} else {
390 		s = splclock();
391 		if (which == ITIMER_REAL) {
392 			/*
393 			 * Convert from absolute to relative time in
394 			 * .it_value part of real time timer.  If time
395 			 * for real time timer has passed return 0,
396 			 * else return difference between current time
397 			 * and time for the timer to go off.
398 			 */
399 			aitv = p->p_timers->pts_timers[ITIMER_REAL]->pt_time;
400 			if (timerisset(&aitv.it_value)) {
401 				if (timercmp(&aitv.it_value, &time, <))
402 					timerclear(&aitv.it_value);
403 				else
404 					timersub(&aitv.it_value, &time, &aitv.it_value);
405 			}
406 		} else
407 			aitv = p->p_timers->pts_timers[which]->pt_time;
408 		splx(s);
409 	}
410 	netbsd32_from_itimerval(&aitv, &s32it);
411 	return (copyout(&s32it, (caddr_t)NETBSD32PTR64(SCARG(uap, itv)),
412 	    sizeof(s32it)));
413 }
414 
415 int
416 netbsd32_gettimeofday(l, v, retval)
417 	struct lwp *l;
418 	void *v;
419 	register_t *retval;
420 {
421 	struct netbsd32_gettimeofday_args /* {
422 		syscallarg(netbsd32_timevalp_t) tp;
423 		syscallarg(netbsd32_timezonep_t) tzp;
424 	} */ *uap = v;
425 	struct timeval atv;
426 	struct netbsd32_timeval tv32;
427 	int error = 0;
428 	struct netbsd32_timezone tzfake;
429 
430 	if (SCARG(uap, tp)) {
431 		microtime(&atv);
432 		netbsd32_from_timeval(&atv, &tv32);
433 		error = copyout(&tv32, (caddr_t)NETBSD32PTR64(SCARG(uap, tp)),
434 		    sizeof(tv32));
435 		if (error)
436 			return (error);
437 	}
438 	if (SCARG(uap, tzp)) {
439 		/*
440 		 * NetBSD has no kernel notion of time zone, so we just
441 		 * fake up a timezone struct and return it if demanded.
442 		 */
443 		tzfake.tz_minuteswest = 0;
444 		tzfake.tz_dsttime = 0;
445 		error = copyout(&tzfake,
446 		    (caddr_t)NETBSD32PTR64(SCARG(uap, tzp)), sizeof(tzfake));
447 	}
448 	return (error);
449 }
450 
451 int
452 netbsd32_settimeofday(l, v, retval)
453 	struct lwp *l;
454 	void *v;
455 	register_t *retval;
456 {
457 	struct netbsd32_settimeofday_args /* {
458 		syscallarg(const netbsd32_timevalp_t) tv;
459 		syscallarg(const netbsd32_timezonep_t) tzp;
460 	} */ *uap = v;
461 	struct netbsd32_timeval atv32;
462 	struct timeval atv;
463 	int error;
464 	struct proc *p = l->l_proc;
465 
466 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
467 		return (error);
468 	/* Verify all parameters before changing time. */
469 	if (SCARG(uap, tv) &&
470 	    (error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, tv)), &atv32,
471 	    sizeof(atv32))))
472 		return (error);
473 	netbsd32_to_timeval(&atv32, &atv);
474 	if (SCARG(uap, tv))
475 		if ((error = settime(&atv)))
476 			return (error);
477 	/* don't bother copying the tz in, we don't use it. */
478 	/*
479 	 * NetBSD has no kernel notion of time zone, and only an
480 	 * obsolete program would try to set it, so we log a warning.
481 	 */
482 	if (SCARG(uap, tzp))
483 		printf("pid %d attempted to set the "
484 		    "(obsolete) kernel time zone\n", p->p_pid);
485 	return (0);
486 }
487 
488 int
489 netbsd32_adjtime(l, v, retval)
490 	struct lwp *l;
491 	void *v;
492 	register_t *retval;
493 {
494 	struct netbsd32_adjtime_args /* {
495 		syscallarg(const netbsd32_timevalp_t) delta;
496 		syscallarg(netbsd32_timevalp_t) olddelta;
497 	} */ *uap = v;
498 	struct netbsd32_timeval atv;
499 	int32_t ndelta, ntickdelta, odelta;
500 	int s, error;
501 	struct proc *p = l->l_proc;
502 	extern long bigadj, timedelta;
503 	extern int tickdelta;
504 
505 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
506 		return (error);
507 
508 	error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, delta)), &atv,
509 	    sizeof(struct timeval));
510 	if (error)
511 		return (error);
512 	/*
513 	 * Compute the total correction and the rate at which to apply it.
514 	 * Round the adjustment down to a whole multiple of the per-tick
515 	 * delta, so that after some number of incremental changes in
516 	 * hardclock(), tickdelta will become zero, lest the correction
517 	 * overshoot and start taking us away from the desired final time.
518 	 */
519 	ndelta = atv.tv_sec * 1000000 + atv.tv_usec;
520 	if (ndelta > bigadj)
521 		ntickdelta = 10 * tickadj;
522 	else
523 		ntickdelta = tickadj;
524 	if (ndelta % ntickdelta)
525 		ndelta = ndelta / ntickdelta * ntickdelta;
526 
527 	/*
528 	 * To make hardclock()'s job easier, make the per-tick delta negative
529 	 * if we want time to run slower; then hardclock can simply compute
530 	 * tick + tickdelta, and subtract tickdelta from timedelta.
531 	 */
532 	if (ndelta < 0)
533 		ntickdelta = -ntickdelta;
534 	s = splclock();
535 	odelta = timedelta;
536 	timedelta = ndelta;
537 	tickdelta = ntickdelta;
538 	splx(s);
539 
540 	if (SCARG(uap, olddelta)) {
541 		atv.tv_sec = odelta / 1000000;
542 		atv.tv_usec = odelta % 1000000;
543 		(void) copyout(&atv,
544 		    (caddr_t)NETBSD32PTR64(SCARG(uap, olddelta)), sizeof(atv));
545 	}
546 	return (0);
547 }
548 
549 int
550 netbsd32_clock_gettime(l, v, retval)
551 	struct lwp *l;
552 	void *v;
553 	register_t *retval;
554 {
555 	struct netbsd32_clock_gettime_args /* {
556 		syscallarg(netbsd32_clockid_t) clock_id;
557 		syscallarg(netbsd32_timespecp_t) tp;
558 	} */ *uap = v;
559 	clockid_t clock_id;
560 	struct timeval atv;
561 	struct timespec ats;
562 	struct netbsd32_timespec ts32;
563 
564 	clock_id = SCARG(uap, clock_id);
565 	if (clock_id != CLOCK_REALTIME)
566 		return (EINVAL);
567 
568 	microtime(&atv);
569 	TIMEVAL_TO_TIMESPEC(&atv,&ats);
570 	netbsd32_from_timespec(&ats, &ts32);
571 
572 	return copyout(&ts32, (caddr_t)NETBSD32PTR64(SCARG(uap, tp)),
573 	    sizeof(ts32));
574 }
575 
576 int
577 netbsd32_clock_settime(l, v, retval)
578 	struct lwp *l;
579 	void *v;
580 	register_t *retval;
581 {
582 	struct netbsd32_clock_settime_args /* {
583 		syscallarg(netbsd32_clockid_t) clock_id;
584 		syscallarg(const netbsd32_timespecp_t) tp;
585 	} */ *uap = v;
586 	struct netbsd32_timespec ts32;
587 	clockid_t clock_id;
588 	struct timeval atv;
589 	struct timespec ats;
590 	int error;
591 	struct proc *p = l->l_proc;
592 
593 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
594 		return (error);
595 
596 	clock_id = SCARG(uap, clock_id);
597 	if (clock_id != CLOCK_REALTIME)
598 		return (EINVAL);
599 
600 	if ((error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, tp)), &ts32,
601 	    sizeof(ts32))) != 0)
602 		return (error);
603 
604 	netbsd32_to_timespec(&ts32, &ats);
605 	TIMESPEC_TO_TIMEVAL(&atv,&ats);
606 	if ((error = settime(&atv)))
607 		return (error);
608 
609 	return 0;
610 }
611 
612 int
613 netbsd32_clock_getres(l, v, retval)
614 	struct lwp *l;
615 	void *v;
616 	register_t *retval;
617 {
618 	struct netbsd32_clock_getres_args /* {
619 		syscallarg(netbsd32_clockid_t) clock_id;
620 		syscallarg(netbsd32_timespecp_t) tp;
621 	} */ *uap = v;
622 	struct netbsd32_timespec ts32;
623 	clockid_t clock_id;
624 	struct timespec ts;
625 	int error = 0;
626 
627 	clock_id = SCARG(uap, clock_id);
628 	if (clock_id != CLOCK_REALTIME)
629 		return (EINVAL);
630 
631 	if (SCARG(uap, tp)) {
632 		ts.tv_sec = 0;
633 		ts.tv_nsec = 1000000000 / hz;
634 
635 		netbsd32_from_timespec(&ts, &ts32);
636 		error = copyout(&ts, (caddr_t)NETBSD32PTR64(SCARG(uap, tp)),
637 		    sizeof(ts));
638 	}
639 
640 	return error;
641 }
642 
643 int
644 netbsd32_nanosleep(l, v, retval)
645 	struct lwp *l;
646 	void *v;
647 	register_t *retval;
648 {
649 	struct netbsd32_nanosleep_args /* {
650 		syscallarg(const netbsd32_timespecp_t) rqtp;
651 		syscallarg(netbsd32_timespecp_t) rmtp;
652 	} */ *uap = v;
653 	static int nanowait;
654 	struct netbsd32_timespec ts32;
655 	struct timespec rqt;
656 	struct timespec rmt;
657 	struct timeval atv, utv;
658 	int error, s, timo;
659 
660 	error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, rqtp)), (caddr_t)&ts32,
661 	    sizeof(ts32));
662 	if (error)
663 		return (error);
664 
665 	netbsd32_to_timespec(&ts32, &rqt);
666 	TIMESPEC_TO_TIMEVAL(&atv,&rqt);
667 	if (itimerfix(&atv))
668 		return (EINVAL);
669 
670 	s = splclock();
671 	timeradd(&atv,&time,&atv);
672 	timo = hzto(&atv);
673 	/*
674 	 * Avoid inadvertantly sleeping forever
675 	 */
676 	if (timo == 0)
677 		timo = 1;
678 	splx(s);
679 
680 	error = tsleep(&nanowait, PWAIT | PCATCH, "nanosleep", timo);
681 	if (error == ERESTART)
682 		error = EINTR;
683 	if (error == EWOULDBLOCK)
684 		error = 0;
685 
686 	if (SCARG(uap, rmtp)) {
687 		int error;
688 
689 		s = splclock();
690 		utv = time;
691 		splx(s);
692 
693 		timersub(&atv, &utv, &utv);
694 		if (utv.tv_sec < 0)
695 			timerclear(&utv);
696 
697 		TIMEVAL_TO_TIMESPEC(&utv,&rmt);
698 		netbsd32_from_timespec(&rmt, &ts32);
699 		error = copyout((caddr_t)&ts32,
700 		    (caddr_t)NETBSD32PTR64(SCARG(uap,rmtp)), sizeof(ts32));
701 		if (error)
702 			return (error);
703 	}
704 
705 	return error;
706 }
707