1 /* $NetBSD: netbsd32_time.c,v 1.4 2002/10/23 13:16:46 scw 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.4 2002/10/23 13:16:46 scw 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, 101 (caddr_t)NETBSD32PTR64(SCARG(uap, ntvp)), 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)NETBSD32PTR64(SCARG(uap, tp)), 168 (caddr_t)&ntv32, 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)NETBSD32PTR64(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 *)NETBSD32PTR64(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)NETBSD32PTR64(SCARG(uap, itv)), 364 sizeof(s32it))); 365 } 366 367 int 368 netbsd32_gettimeofday(p, v, retval) 369 struct proc *p; 370 void *v; 371 register_t *retval; 372 { 373 struct netbsd32_gettimeofday_args /* { 374 syscallarg(netbsd32_timevalp_t) tp; 375 syscallarg(netbsd32_timezonep_t) tzp; 376 } */ *uap = v; 377 struct timeval atv; 378 struct netbsd32_timeval tv32; 379 int error = 0; 380 struct netbsd32_timezone tzfake; 381 382 if (SCARG(uap, tp)) { 383 microtime(&atv); 384 netbsd32_from_timeval(&atv, &tv32); 385 error = copyout(&tv32, (caddr_t)NETBSD32PTR64(SCARG(uap, tp)), 386 sizeof(tv32)); 387 if (error) 388 return (error); 389 } 390 if (SCARG(uap, tzp)) { 391 /* 392 * NetBSD has no kernel notion of time zone, so we just 393 * fake up a timezone struct and return it if demanded. 394 */ 395 tzfake.tz_minuteswest = 0; 396 tzfake.tz_dsttime = 0; 397 error = copyout(&tzfake, 398 (caddr_t)NETBSD32PTR64(SCARG(uap, tzp)), sizeof(tzfake)); 399 } 400 return (error); 401 } 402 403 int 404 netbsd32_settimeofday(p, v, retval) 405 struct proc *p; 406 void *v; 407 register_t *retval; 408 { 409 struct netbsd32_settimeofday_args /* { 410 syscallarg(const netbsd32_timevalp_t) tv; 411 syscallarg(const netbsd32_timezonep_t) tzp; 412 } */ *uap = v; 413 struct netbsd32_timeval atv32; 414 struct timeval atv; 415 int error; 416 417 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 418 return (error); 419 /* Verify all parameters before changing time. */ 420 if (SCARG(uap, tv) && 421 (error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, tv)), &atv32, 422 sizeof(atv32)))) 423 return (error); 424 netbsd32_to_timeval(&atv32, &atv); 425 if (SCARG(uap, tv)) 426 if ((error = settime(&atv))) 427 return (error); 428 /* don't bother copying the tz in, we don't use it. */ 429 /* 430 * NetBSD has no kernel notion of time zone, and only an 431 * obsolete program would try to set it, so we log a warning. 432 */ 433 if (SCARG(uap, tzp)) 434 printf("pid %d attempted to set the " 435 "(obsolete) kernel time zone\n", p->p_pid); 436 return (0); 437 } 438 439 int 440 netbsd32_adjtime(p, v, retval) 441 struct proc *p; 442 void *v; 443 register_t *retval; 444 { 445 struct netbsd32_adjtime_args /* { 446 syscallarg(const netbsd32_timevalp_t) delta; 447 syscallarg(netbsd32_timevalp_t) olddelta; 448 } */ *uap = v; 449 struct netbsd32_timeval atv; 450 int32_t ndelta, ntickdelta, odelta; 451 int s, error; 452 extern long bigadj, timedelta; 453 extern int tickdelta; 454 455 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 456 return (error); 457 458 error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, delta)), &atv, 459 sizeof(struct timeval)); 460 if (error) 461 return (error); 462 /* 463 * Compute the total correction and the rate at which to apply it. 464 * Round the adjustment down to a whole multiple of the per-tick 465 * delta, so that after some number of incremental changes in 466 * hardclock(), tickdelta will become zero, lest the correction 467 * overshoot and start taking us away from the desired final time. 468 */ 469 ndelta = atv.tv_sec * 1000000 + atv.tv_usec; 470 if (ndelta > bigadj) 471 ntickdelta = 10 * tickadj; 472 else 473 ntickdelta = tickadj; 474 if (ndelta % ntickdelta) 475 ndelta = ndelta / ntickdelta * ntickdelta; 476 477 /* 478 * To make hardclock()'s job easier, make the per-tick delta negative 479 * if we want time to run slower; then hardclock can simply compute 480 * tick + tickdelta, and subtract tickdelta from timedelta. 481 */ 482 if (ndelta < 0) 483 ntickdelta = -ntickdelta; 484 s = splclock(); 485 odelta = timedelta; 486 timedelta = ndelta; 487 tickdelta = ntickdelta; 488 splx(s); 489 490 if (SCARG(uap, olddelta)) { 491 atv.tv_sec = odelta / 1000000; 492 atv.tv_usec = odelta % 1000000; 493 (void) copyout(&atv, 494 (caddr_t)NETBSD32PTR64(SCARG(uap, olddelta)), sizeof(atv)); 495 } 496 return (0); 497 } 498 499 int 500 netbsd32_clock_gettime(p, v, retval) 501 struct proc *p; 502 void *v; 503 register_t *retval; 504 { 505 struct netbsd32_clock_gettime_args /* { 506 syscallarg(netbsd32_clockid_t) clock_id; 507 syscallarg(netbsd32_timespecp_t) tp; 508 } */ *uap = v; 509 clockid_t clock_id; 510 struct timeval atv; 511 struct timespec ats; 512 struct netbsd32_timespec ts32; 513 514 clock_id = SCARG(uap, clock_id); 515 if (clock_id != CLOCK_REALTIME) 516 return (EINVAL); 517 518 microtime(&atv); 519 TIMEVAL_TO_TIMESPEC(&atv,&ats); 520 netbsd32_from_timespec(&ats, &ts32); 521 522 return copyout(&ts32, (caddr_t)NETBSD32PTR64(SCARG(uap, tp)), 523 sizeof(ts32)); 524 } 525 526 int 527 netbsd32_clock_settime(p, v, retval) 528 struct proc *p; 529 void *v; 530 register_t *retval; 531 { 532 struct netbsd32_clock_settime_args /* { 533 syscallarg(netbsd32_clockid_t) clock_id; 534 syscallarg(const netbsd32_timespecp_t) tp; 535 } */ *uap = v; 536 struct netbsd32_timespec ts32; 537 clockid_t clock_id; 538 struct timeval atv; 539 struct timespec ats; 540 int error; 541 542 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 543 return (error); 544 545 clock_id = SCARG(uap, clock_id); 546 if (clock_id != CLOCK_REALTIME) 547 return (EINVAL); 548 549 if ((error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, tp)), &ts32, 550 sizeof(ts32))) != 0) 551 return (error); 552 553 netbsd32_to_timespec(&ts32, &ats); 554 TIMESPEC_TO_TIMEVAL(&atv,&ats); 555 if ((error = settime(&atv))) 556 return (error); 557 558 return 0; 559 } 560 561 int 562 netbsd32_clock_getres(p, v, retval) 563 struct proc *p; 564 void *v; 565 register_t *retval; 566 { 567 struct netbsd32_clock_getres_args /* { 568 syscallarg(netbsd32_clockid_t) clock_id; 569 syscallarg(netbsd32_timespecp_t) tp; 570 } */ *uap = v; 571 struct netbsd32_timespec ts32; 572 clockid_t clock_id; 573 struct timespec ts; 574 int error = 0; 575 576 clock_id = SCARG(uap, clock_id); 577 if (clock_id != CLOCK_REALTIME) 578 return (EINVAL); 579 580 if (SCARG(uap, tp)) { 581 ts.tv_sec = 0; 582 ts.tv_nsec = 1000000000 / hz; 583 584 netbsd32_from_timespec(&ts, &ts32); 585 error = copyout(&ts, (caddr_t)NETBSD32PTR64(SCARG(uap, tp)), 586 sizeof(ts)); 587 } 588 589 return error; 590 } 591 592 int 593 netbsd32_nanosleep(p, v, retval) 594 struct proc *p; 595 void *v; 596 register_t *retval; 597 { 598 struct netbsd32_nanosleep_args /* { 599 syscallarg(const netbsd32_timespecp_t) rqtp; 600 syscallarg(netbsd32_timespecp_t) rmtp; 601 } */ *uap = v; 602 static int nanowait; 603 struct netbsd32_timespec ts32; 604 struct timespec rqt; 605 struct timespec rmt; 606 struct timeval atv, utv; 607 int error, s, timo; 608 609 error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, rqtp)), (caddr_t)&ts32, 610 sizeof(ts32)); 611 if (error) 612 return (error); 613 614 netbsd32_to_timespec(&ts32, &rqt); 615 TIMESPEC_TO_TIMEVAL(&atv,&rqt) 616 if (itimerfix(&atv)) 617 return (EINVAL); 618 619 s = splclock(); 620 timeradd(&atv,&time,&atv); 621 timo = hzto(&atv); 622 /* 623 * Avoid inadvertantly sleeping forever 624 */ 625 if (timo == 0) 626 timo = 1; 627 splx(s); 628 629 error = tsleep(&nanowait, PWAIT | PCATCH, "nanosleep", timo); 630 if (error == ERESTART) 631 error = EINTR; 632 if (error == EWOULDBLOCK) 633 error = 0; 634 635 if (SCARG(uap, rmtp)) { 636 int error; 637 638 s = splclock(); 639 utv = time; 640 splx(s); 641 642 timersub(&atv, &utv, &utv); 643 if (utv.tv_sec < 0) 644 timerclear(&utv); 645 646 TIMEVAL_TO_TIMESPEC(&utv,&rmt); 647 netbsd32_from_timespec(&rmt, &ts32); 648 error = copyout((caddr_t)&ts32, 649 (caddr_t)NETBSD32PTR64(SCARG(uap,rmtp)), sizeof(ts32)); 650 if (error) 651 return (error); 652 } 653 654 return error; 655 } 656