1 /* $NetBSD: netbsd32_time.c,v 1.19 2006/02/17 15:44:17 he 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.19 2006/02/17 15:44:17 he 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/timevar.h> 44 #include <sys/proc.h> 45 #include <sys/pool.h> 46 #include <sys/resourcevar.h> 47 #include <sys/dirent.h> 48 49 #include <compat/netbsd32/netbsd32.h> 50 #include <compat/netbsd32/netbsd32_syscallargs.h> 51 #include <compat/netbsd32/netbsd32_conv.h> 52 53 #ifdef NTP 54 55 #ifdef PPS_SYNC 56 /* 57 * The following variables are used only if the PPS signal discipline 58 * is configured in the kernel. 59 */ 60 extern int pps_shift; /* interval duration (s) (shift) */ 61 extern long pps_freq; /* pps frequency offset (scaled ppm) */ 62 extern long pps_jitter; /* pps jitter (us) */ 63 extern long pps_stabil; /* pps stability (scaled ppm) */ 64 extern long pps_jitcnt; /* jitter limit exceeded */ 65 extern long pps_calcnt; /* calibration intervals */ 66 extern long pps_errcnt; /* calibration errors */ 67 extern long pps_stbcnt; /* stability limit exceeded */ 68 #endif /* PPS_SYNC */ 69 70 int 71 netbsd32_ntp_gettime(l, v, retval) 72 struct lwp *l; 73 void *v; 74 register_t *retval; 75 { 76 struct netbsd32_ntp_gettime_args /* { 77 syscallarg(netbsd32_ntptimevalp_t) ntvp; 78 } */ *uap = v; 79 struct netbsd32_ntptimeval ntv32; 80 struct timeval atv; 81 struct ntptimeval ntv; 82 int error = 0; 83 int s; 84 85 /* The following are NTP variables */ 86 extern long time_maxerror; 87 extern long time_esterror; 88 extern int time_status; 89 extern int time_state; /* clock state */ 90 extern int time_status; /* clock status bits */ 91 92 if (SCARG(uap, ntvp)) { 93 s = splclock(); 94 #ifdef EXT_CLOCK 95 /* 96 * The microtime() external clock routine returns a 97 * status code. If less than zero, we declare an error 98 * in the clock status word and return the kernel 99 * (software) time variable. While there are other 100 * places that call microtime(), this is the only place 101 * that matters from an application point of view. 102 */ 103 if (microtime(&atv) < 0) { 104 time_status |= STA_CLOCKERR; 105 ntv.time = time; 106 } else 107 time_status &= ~STA_CLOCKERR; 108 #else /* EXT_CLOCK */ 109 microtime(&atv); 110 #endif /* EXT_CLOCK */ 111 ntv.time = atv; 112 ntv.maxerror = time_maxerror; 113 ntv.esterror = time_esterror; 114 (void) splx(s); 115 116 netbsd32_from_timeval(&ntv.time, &ntv32.time); 117 ntv32.maxerror = (netbsd32_long)ntv.maxerror; 118 ntv32.esterror = (netbsd32_long)ntv.esterror; 119 error = copyout((caddr_t)&ntv32, 120 (caddr_t)NETBSD32PTR64(SCARG(uap, ntvp)), sizeof(ntv32)); 121 } 122 if (!error) { 123 124 /* 125 * Status word error decode. If any of these conditions 126 * occur, an error is returned, instead of the status 127 * word. Most applications will care only about the fact 128 * the system clock may not be trusted, not about the 129 * details. 130 * 131 * Hardware or software error 132 */ 133 if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) || 134 135 /* 136 * PPS signal lost when either time or frequency 137 * synchronization requested 138 */ 139 (time_status & (STA_PPSFREQ | STA_PPSTIME) && 140 !(time_status & STA_PPSSIGNAL)) || 141 142 /* 143 * PPS jitter exceeded when time synchronization 144 * requested 145 */ 146 (time_status & STA_PPSTIME && 147 time_status & STA_PPSJITTER) || 148 149 /* 150 * PPS wander exceeded or calibration error when 151 * frequency synchronization requested 152 */ 153 (time_status & STA_PPSFREQ && 154 time_status & (STA_PPSWANDER | STA_PPSERROR))) 155 *retval = TIME_ERROR; 156 else 157 *retval = time_state; 158 } 159 return (error); 160 } 161 162 int 163 netbsd32_ntp_adjtime(l, v, retval) 164 struct lwp *l; 165 void *v; 166 register_t *retval; 167 { 168 struct netbsd32_ntp_adjtime_args /* { 169 syscallarg(netbsd32_timexp_t) tp; 170 } */ *uap = v; 171 struct netbsd32_timex ntv32; 172 struct timex ntv; 173 int error = 0; 174 int modes; 175 int s; 176 struct proc *p = l->l_proc; 177 extern long time_freq; /* frequency offset (scaled ppm) */ 178 extern long time_maxerror; 179 extern long time_esterror; 180 extern int time_state; /* clock state */ 181 extern int time_status; /* clock status bits */ 182 extern long time_constant; /* pll time constant */ 183 extern long time_offset; /* time offset (us) */ 184 extern long time_tolerance; /* frequency tolerance (scaled ppm) */ 185 extern long time_precision; /* clock precision (us) */ 186 187 if ((error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, tp)), 188 (caddr_t)&ntv32, sizeof(ntv32)))) 189 return (error); 190 netbsd32_to_timex(&ntv32, &ntv); 191 192 /* 193 * Update selected clock variables - only the superuser can 194 * change anything. Note that there is no error checking here on 195 * the assumption the superuser should know what it is doing. 196 */ 197 modes = ntv.modes; 198 if (modes != 0 && (error = suser(p->p_ucred, &p->p_acflag))) 199 return (error); 200 201 s = splclock(); 202 if (modes & MOD_FREQUENCY) 203 #ifdef PPS_SYNC 204 time_freq = ntv.freq - pps_freq; 205 #else /* PPS_SYNC */ 206 time_freq = ntv.freq; 207 #endif /* PPS_SYNC */ 208 if (modes & MOD_MAXERROR) 209 time_maxerror = ntv.maxerror; 210 if (modes & MOD_ESTERROR) 211 time_esterror = ntv.esterror; 212 if (modes & MOD_STATUS) { 213 time_status &= STA_RONLY; 214 time_status |= ntv.status & ~STA_RONLY; 215 } 216 if (modes & MOD_TIMECONST) 217 time_constant = ntv.constant; 218 if (modes & MOD_OFFSET) 219 hardupdate(ntv.offset); 220 221 /* 222 * Retrieve all clock variables 223 */ 224 if (time_offset < 0) 225 ntv.offset = -(-time_offset >> SHIFT_UPDATE); 226 else 227 ntv.offset = time_offset >> SHIFT_UPDATE; 228 #ifdef PPS_SYNC 229 ntv.freq = time_freq + pps_freq; 230 #else /* PPS_SYNC */ 231 ntv.freq = time_freq; 232 #endif /* PPS_SYNC */ 233 ntv.maxerror = time_maxerror; 234 ntv.esterror = time_esterror; 235 ntv.status = time_status; 236 ntv.constant = time_constant; 237 ntv.precision = time_precision; 238 ntv.tolerance = time_tolerance; 239 #ifdef PPS_SYNC 240 ntv.shift = pps_shift; 241 ntv.ppsfreq = pps_freq; 242 ntv.jitter = pps_jitter >> PPS_AVG; 243 ntv.stabil = pps_stabil; 244 ntv.calcnt = pps_calcnt; 245 ntv.errcnt = pps_errcnt; 246 ntv.jitcnt = pps_jitcnt; 247 ntv.stbcnt = pps_stbcnt; 248 #endif /* PPS_SYNC */ 249 (void)splx(s); 250 251 netbsd32_from_timex(&ntv, &ntv32); 252 error = copyout((caddr_t)&ntv32, (caddr_t)NETBSD32PTR64(SCARG(uap, tp)), 253 sizeof(ntv32)); 254 if (!error) { 255 256 /* 257 * Status word error decode. See comments in 258 * ntp_gettime() routine. 259 */ 260 if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) || 261 (time_status & (STA_PPSFREQ | STA_PPSTIME) && 262 !(time_status & STA_PPSSIGNAL)) || 263 (time_status & STA_PPSTIME && 264 time_status & STA_PPSJITTER) || 265 (time_status & STA_PPSFREQ && 266 time_status & (STA_PPSWANDER | STA_PPSERROR))) 267 *retval = TIME_ERROR; 268 else 269 *retval = time_state; 270 } 271 return error; 272 } 273 #else 274 int 275 netbsd32_ntp_gettime(l, v, retval) 276 struct lwp *l; 277 void *v; 278 register_t *retval; 279 { 280 281 return (ENOSYS); 282 } 283 284 int 285 netbsd32_ntp_adjtime(l, v, retval) 286 struct lwp *l; 287 void *v; 288 register_t *retval; 289 { 290 291 return (ENOSYS); 292 } 293 #endif 294 295 int 296 netbsd32_setitimer(l, v, retval) 297 struct lwp *l; 298 void *v; 299 register_t *retval; 300 { 301 struct netbsd32_setitimer_args /* { 302 syscallarg(int) which; 303 syscallarg(const netbsd32_itimervalp_t) itv; 304 syscallarg(netbsd32_itimervalp_t) oitv; 305 } */ *uap = v; 306 struct proc *p = l->l_proc; 307 struct netbsd32_itimerval s32it, *itv32; 308 int which = SCARG(uap, which); 309 struct netbsd32_getitimer_args getargs; 310 struct itimerval aitv; 311 int error; 312 313 if ((u_int)which > ITIMER_PROF) 314 return (EINVAL); 315 itv32 = (struct netbsd32_itimerval *)NETBSD32PTR64(SCARG(uap, itv)); 316 if (itv32) { 317 if ((error = copyin(itv32, &s32it, sizeof(s32it)))) 318 return (error); 319 netbsd32_to_itimerval(&s32it, &aitv); 320 } 321 if (SCARG(uap, oitv) != 0) { 322 SCARG(&getargs, which) = which; 323 SCARG(&getargs, itv) = SCARG(uap, oitv); 324 if ((error = netbsd32_getitimer(l, &getargs, retval)) != 0) 325 return (error); 326 } 327 if (itv32 == 0) 328 return 0; 329 330 return dosetitimer(p, which, &aitv); 331 } 332 333 int 334 netbsd32_getitimer(l, v, retval) 335 struct lwp *l; 336 void *v; 337 register_t *retval; 338 { 339 struct netbsd32_getitimer_args /* { 340 syscallarg(int) which; 341 syscallarg(netbsd32_itimervalp_t) itv; 342 } */ *uap = v; 343 struct proc *p = l->l_proc; 344 struct netbsd32_itimerval s32it; 345 struct itimerval aitv; 346 int error; 347 348 error = dogetitimer(p, SCARG(uap, which), &aitv); 349 if (error) 350 return error; 351 352 netbsd32_from_itimerval(&aitv, &s32it); 353 return (copyout(&s32it, (caddr_t)NETBSD32PTR64(SCARG(uap, itv)), 354 sizeof(s32it))); 355 } 356 357 int 358 netbsd32_gettimeofday(l, v, retval) 359 struct lwp *l; 360 void *v; 361 register_t *retval; 362 { 363 struct netbsd32_gettimeofday_args /* { 364 syscallarg(netbsd32_timevalp_t) tp; 365 syscallarg(netbsd32_timezonep_t) tzp; 366 } */ *uap = v; 367 struct timeval atv; 368 struct netbsd32_timeval tv32; 369 int error = 0; 370 struct netbsd32_timezone tzfake; 371 372 if (SCARG(uap, tp)) { 373 microtime(&atv); 374 netbsd32_from_timeval(&atv, &tv32); 375 error = copyout(&tv32, (caddr_t)NETBSD32PTR64(SCARG(uap, tp)), 376 sizeof(tv32)); 377 if (error) 378 return (error); 379 } 380 if (SCARG(uap, tzp)) { 381 /* 382 * NetBSD has no kernel notion of time zone, so we just 383 * fake up a timezone struct and return it if demanded. 384 */ 385 tzfake.tz_minuteswest = 0; 386 tzfake.tz_dsttime = 0; 387 error = copyout(&tzfake, 388 (caddr_t)NETBSD32PTR64(SCARG(uap, tzp)), sizeof(tzfake)); 389 } 390 return (error); 391 } 392 393 int 394 netbsd32_settimeofday(l, v, retval) 395 struct lwp *l; 396 void *v; 397 register_t *retval; 398 { 399 struct netbsd32_settimeofday_args /* { 400 syscallarg(const netbsd32_timevalp_t) tv; 401 syscallarg(const netbsd32_timezonep_t) tzp; 402 } */ *uap = v; 403 struct netbsd32_timeval atv32; 404 struct timeval atv; 405 struct timespec ats; 406 int error; 407 struct proc *p = l->l_proc; 408 409 /* Verify all parameters before changing time. */ 410 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 411 return error; 412 413 /* 414 * NetBSD has no kernel notion of time zone, and only an 415 * obsolete program would try to set it, so we log a warning. 416 */ 417 if (SCARG(uap, tzp)) 418 printf("pid %d attempted to set the " 419 "(obsolete) kernel time zone\n", p->p_pid); 420 421 if (SCARG(uap, tv) == 0) 422 return 0; 423 424 if ((error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, tv)), &atv32, 425 sizeof(atv32))) != 0) 426 return error; 427 428 netbsd32_to_timeval(&atv32, &atv); 429 TIMEVAL_TO_TIMESPEC(&atv, &ats); 430 return settime(p, &ats); 431 } 432 433 int 434 netbsd32_adjtime(l, v, retval) 435 struct lwp *l; 436 void *v; 437 register_t *retval; 438 { 439 struct netbsd32_adjtime_args /* { 440 syscallarg(const netbsd32_timevalp_t) delta; 441 syscallarg(netbsd32_timevalp_t) olddelta; 442 } */ *uap = v; 443 struct netbsd32_timeval atv; 444 int32_t ndelta, ntickdelta, odelta; 445 int s, error; 446 struct proc *p = l->l_proc; 447 extern long bigadj, timedelta; 448 extern int tickdelta; 449 450 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 451 return (error); 452 453 error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, delta)), &atv, 454 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, 489 (caddr_t)NETBSD32PTR64(SCARG(uap, olddelta)), sizeof(atv)); 490 } 491 return (0); 492 } 493 494 int 495 netbsd32_clock_gettime(l, v, retval) 496 struct lwp *l; 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 timespec ats; 506 struct netbsd32_timespec ts32; 507 508 clock_id = SCARG(uap, clock_id); 509 if (clock_id != CLOCK_REALTIME) 510 return (EINVAL); 511 512 nanotime(&ats); 513 netbsd32_from_timespec(&ats, &ts32); 514 515 return copyout(&ts32, (caddr_t)NETBSD32PTR64(SCARG(uap, tp)), 516 sizeof(ts32)); 517 } 518 519 int 520 netbsd32_clock_settime(l, v, retval) 521 struct lwp *l; 522 void *v; 523 register_t *retval; 524 { 525 struct netbsd32_clock_settime_args /* { 526 syscallarg(netbsd32_clockid_t) clock_id; 527 syscallarg(const netbsd32_timespecp_t) tp; 528 } */ *uap = v; 529 struct netbsd32_timespec ts32; 530 clockid_t clock_id; 531 struct timespec ats; 532 int error; 533 struct proc *p = l->l_proc; 534 535 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 536 return (error); 537 538 clock_id = SCARG(uap, clock_id); 539 if (clock_id != CLOCK_REALTIME) 540 return (EINVAL); 541 542 if ((error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, tp)), &ts32, 543 sizeof(ts32))) != 0) 544 return (error); 545 546 netbsd32_to_timespec(&ts32, &ats); 547 return settime(p, &ats); 548 } 549 550 int 551 netbsd32_clock_getres(l, v, retval) 552 struct lwp *l; 553 void *v; 554 register_t *retval; 555 { 556 struct netbsd32_clock_getres_args /* { 557 syscallarg(netbsd32_clockid_t) clock_id; 558 syscallarg(netbsd32_timespecp_t) tp; 559 } */ *uap = v; 560 struct netbsd32_timespec ts32; 561 clockid_t clock_id; 562 struct timespec ts; 563 int error = 0; 564 565 clock_id = SCARG(uap, clock_id); 566 if (clock_id != CLOCK_REALTIME) 567 return (EINVAL); 568 569 if (SCARG(uap, tp)) { 570 ts.tv_sec = 0; 571 ts.tv_nsec = 1000000000 / hz; 572 573 netbsd32_from_timespec(&ts, &ts32); 574 error = copyout(&ts, (caddr_t)NETBSD32PTR64(SCARG(uap, tp)), 575 sizeof(ts)); 576 } 577 578 return error; 579 } 580 581 int 582 netbsd32_nanosleep(l, v, retval) 583 struct lwp *l; 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)NETBSD32PTR64(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 error1; 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 error1 = copyout(&ts32, 638 NETBSD32PTR64(SCARG(uap,rmtp)), sizeof(ts32)); 639 if (error1) 640 return (error1); 641 } 642 643 return error; 644 } 645 646 static int 647 netbsd32_timer_create_fetch(const void *src, void *dst, size_t size) 648 { 649 struct sigevent *evp = dst; 650 struct netbsd32_sigevent ev32; 651 int error; 652 653 error = copyin(src, &ev32, sizeof(ev32)); 654 if (error) 655 return error; 656 657 netbsd32_to_sigevent(&ev32, evp); 658 return 0; 659 } 660 661 int 662 netbsd32_timer_create(struct lwp *l, void *v, register_t *retval) 663 { 664 struct netbsd32_timer_create_args /* { 665 syscallarg(netbsd32_clockid_t) clock_id; 666 syscallarg(netbsd32_sigeventp_t) evp; 667 syscallarg(netbsd32_timerp_t) timerid; 668 } */ *uap = v; 669 670 return timer_create1(NETBSD32PTR64(SCARG(uap, timerid)), 671 SCARG(uap, clock_id), NETBSD32PTR64(SCARG(uap, evp)), 672 netbsd32_timer_create_fetch, l->l_proc); 673 } 674 675 int 676 netbsd32_timer_delete(struct lwp *l, void *v, register_t *retval) 677 { 678 struct netbsd32_timer_delete_args /* { 679 syscallarg(netbsd32_timer_t) timerid; 680 } */ *uap = v; 681 struct sys_timer_delete_args ua; 682 683 NETBSD32TO64_UAP(timerid); 684 return sys_timer_delete(l, (void *)&ua, retval); 685 } 686 687 int 688 netbsd32_timer_settime(struct lwp *l, void *v, register_t *retval) 689 { 690 struct netbsd32_timer_settime_args /* { 691 syscallarg(netbsd32_timer_t) timerid; 692 syscallarg(int) flags; 693 syscallarg(const netbsd32_itimerspecp_t) value; 694 syscallarg(netbsd32_itimerspecp_t) ovalue; 695 } */ *uap = v; 696 int error; 697 struct itimerspec value, ovalue, *ovp = NULL; 698 struct netbsd32_itimerspec its32; 699 700 if ((error = copyin(NETBSD32PTR64(SCARG(uap, value)), &its32, 701 sizeof(its32))) != 0) 702 return (error); 703 netbsd32_to_timespec(&its32.it_interval, &value.it_interval); 704 netbsd32_to_timespec(&its32.it_value, &value.it_value); 705 706 if (SCARG(uap, ovalue)) 707 ovp = &ovalue; 708 709 if ((error = dotimer_settime(SCARG(uap, timerid), &value, ovp, 710 SCARG(uap, flags), l->l_proc)) != 0) 711 return error; 712 713 if (ovp) { 714 netbsd32_from_timespec(&ovp->it_interval, &its32.it_interval); 715 netbsd32_from_timespec(&ovp->it_value, &its32.it_value); 716 return copyout(&its32, NETBSD32PTR64(SCARG(uap, ovalue)), 717 sizeof(its32)); 718 } 719 return 0; 720 } 721 722 int 723 netbsd32_timer_gettime(struct lwp *l, void *v, register_t *retval) 724 { 725 struct netbsd32_timer_gettime_args /* { 726 syscallarg(netbsd32_timer_t) timerid; 727 syscallarg(netbsd32_itimerspecp_t) value; 728 } */ *uap = v; 729 int error; 730 struct itimerspec its; 731 struct netbsd32_itimerspec its32; 732 733 if ((error = dotimer_gettime(SCARG(uap, timerid), l->l_proc, 734 &its)) != 0) 735 return error; 736 737 netbsd32_from_timespec(&its.it_interval, &its32.it_interval); 738 netbsd32_from_timespec(&its.it_value, &its32.it_value); 739 740 return copyout(&its32, (caddr_t)NETBSD32PTR64(SCARG(uap, value)), 741 sizeof(its32)); 742 } 743 744 int 745 netbsd32_timer_getoverrun(struct lwp *l, void *v, register_t *retval) 746 { 747 struct netbsd32_timer_getoverrun_args /* { 748 syscallarg(netbsd32_timer_t) timerid; 749 } */ *uap = v; 750 struct sys_timer_getoverrun_args ua; 751 752 NETBSD32TO64_UAP(timerid); 753 return sys_timer_getoverrun(l, (void *)&ua, retval); 754 } 755