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