netbsd32_time.c revision 1.1.4.1 1 /* $NetBSD: netbsd32_time.c,v 1.1.4.1 2001/06/21 20:00:11 nathanw 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