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