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