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