netbsd32_time.c revision 1.18.4.1 1 /* $NetBSD: netbsd32_time.c,v 1.18.4.1 2006/09/09 02:46:12 rpaulo 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.18.4.1 2006/09/09 02:46:12 rpaulo Exp $");
33
34 #if defined(_KERNEL_OPT)
35 #include "opt_ntp.h"
36 #include "opt_compat_netbsd.h"
37 #endif
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/mount.h>
42 #include <sys/time.h>
43 #include <sys/timex.h>
44 #include <sys/timevar.h>
45 #include <sys/timetc.h>
46 #include <sys/proc.h>
47 #include <sys/pool.h>
48 #include <sys/resourcevar.h>
49 #include <sys/dirent.h>
50 #include <sys/kauth.h>
51
52 #include <compat/netbsd32/netbsd32.h>
53 #include <compat/netbsd32/netbsd32_syscallargs.h>
54 #include <compat/netbsd32/netbsd32_conv.h>
55
56 #ifdef NTP
57
58 int
59 netbsd32_ntp_gettime(l, v, retval)
60 struct lwp *l;
61 void *v;
62 register_t *retval;
63 {
64 struct netbsd32_ntp_gettime_args /* {
65 syscallarg(netbsd32_ntptimevalp_t) ntvp;
66 } */ *uap = v;
67 struct netbsd32_ntptimeval ntv32;
68 struct ntptimeval ntv;
69 int error = 0;
70
71 if (SCARG(uap, ntvp)) {
72 ntp_gettime(&ntv);
73
74 ntv32.time.tv_sec = ntv.time.tv_sec;
75 ntv32.time.tv_nsec = ntv.time.tv_nsec;
76 ntv32.maxerror = (netbsd32_long)ntv.maxerror;
77 ntv32.esterror = (netbsd32_long)ntv.esterror;
78 ntv32.tai = (netbsd32_long)ntv.tai;
79 ntv32.time_state = ntv.time_state;
80 error = copyout((caddr_t)&ntv32,
81 (caddr_t)NETBSD32PTR64(SCARG(uap, ntvp)), sizeof(ntv32));
82 }
83 if (!error) {
84 *retval = ntp_timestatus();
85 }
86
87 return (error);
88 }
89
90 #ifdef COMPAT_30
91 int
92 compat_30_netbsd32_ntp_gettime(l, v, retval)
93 struct lwp *l;
94 void *v;
95 register_t *retval;
96 {
97 struct compat_30_netbsd32_ntp_gettime_args /* {
98 syscallarg(netbsd32_ntptimevalp_t) ntvp;
99 } */ *uap = v;
100 struct netbsd32_ntptimeval30 ntv32;
101 struct ntptimeval ntv;
102 int error = 0;
103
104 if (SCARG(uap, ntvp)) {
105 ntp_gettime(&ntv);
106
107 ntv32.time.tv_sec = ntv.time.tv_sec;
108 ntv32.time.tv_usec = ntv.time.tv_nsec / 1000;
109 ntv32.maxerror = (netbsd32_long)ntv.maxerror;
110 ntv32.esterror = (netbsd32_long)ntv.esterror;
111 error = copyout((caddr_t)&ntv32,
112 (caddr_t)NETBSD32PTR64(SCARG(uap, ntvp)), sizeof(ntv32));
113 }
114 if (!error) {
115 *retval = ntp_timestatus();
116 }
117
118 return (error);
119 }
120 #endif
121
122 int
123 netbsd32_ntp_adjtime(l, v, retval)
124 struct lwp *l;
125 void *v;
126 register_t *retval;
127 {
128 struct netbsd32_ntp_adjtime_args /* {
129 syscallarg(netbsd32_timexp_t) tp;
130 } */ *uap = v;
131 struct netbsd32_timex ntv32;
132 struct timex ntv;
133 int error = 0;
134 int modes;
135
136 if ((error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, tp)),
137 (caddr_t)&ntv32, sizeof(ntv32))))
138 return (error);
139
140 netbsd32_to_timex(&ntv32, &ntv);
141
142 /*
143 * Update selected clock variables - only the superuser can
144 * change anything. Note that there is no error checking here on
145 * the assumption the superuser should know what it is doing.
146 */
147 modes = ntv.modes;
148 if (modes != 0 && (error = kauth_authorize_generic(l->l_cred,
149 KAUTH_GENERIC_ISSUSER, &l->l_acflag)))
150 return (error);
151
152 ntp_adjtime1(&ntv);
153
154 netbsd32_from_timex(&ntv, &ntv32);
155 error = copyout((caddr_t)&ntv32, (caddr_t)NETBSD32PTR64(SCARG(uap, tp)),
156 sizeof(ntv32));
157 if (!error) {
158 *retval = ntp_timestatus();
159 }
160 return error;
161 }
162 #else /* !NTP */
163 int
164 netbsd32_ntp_gettime(l, v, retval)
165 struct lwp *l;
166 void *v;
167 register_t *retval;
168 {
169
170 return (ENOSYS);
171 }
172
173 #ifdef COMPAT_30
174 int
175 compat_30_netbsd32_ntp_gettime(l, v, retval)
176 struct lwp *l;
177 void *v;
178 register_t *retval;
179 {
180
181 return (ENOSYS);
182 }
183 #endif
184
185 int
186 netbsd32_ntp_adjtime(l, v, retval)
187 struct lwp *l;
188 void *v;
189 register_t *retval;
190 {
191
192 return (ENOSYS);
193 }
194 #endif /* NTP */
195
196 int
197 netbsd32_setitimer(l, v, retval)
198 struct lwp *l;
199 void *v;
200 register_t *retval;
201 {
202 struct netbsd32_setitimer_args /* {
203 syscallarg(int) which;
204 syscallarg(const netbsd32_itimervalp_t) itv;
205 syscallarg(netbsd32_itimervalp_t) oitv;
206 } */ *uap = v;
207 struct proc *p = l->l_proc;
208 struct netbsd32_itimerval s32it, *itv32;
209 int which = SCARG(uap, which);
210 struct netbsd32_getitimer_args getargs;
211 struct itimerval aitv;
212 int error;
213
214 if ((u_int)which > ITIMER_PROF)
215 return (EINVAL);
216 itv32 = (struct netbsd32_itimerval *)NETBSD32PTR64(SCARG(uap, itv));
217 if (itv32) {
218 if ((error = copyin(itv32, &s32it, sizeof(s32it))))
219 return (error);
220 netbsd32_to_itimerval(&s32it, &aitv);
221 }
222 if (SCARG(uap, oitv) != 0) {
223 SCARG(&getargs, which) = which;
224 SCARG(&getargs, itv) = SCARG(uap, oitv);
225 if ((error = netbsd32_getitimer(l, &getargs, retval)) != 0)
226 return (error);
227 }
228 if (itv32 == 0)
229 return 0;
230
231 return dosetitimer(p, which, &aitv);
232 }
233
234 int
235 netbsd32_getitimer(l, v, retval)
236 struct lwp *l;
237 void *v;
238 register_t *retval;
239 {
240 struct netbsd32_getitimer_args /* {
241 syscallarg(int) which;
242 syscallarg(netbsd32_itimervalp_t) itv;
243 } */ *uap = v;
244 struct proc *p = l->l_proc;
245 struct netbsd32_itimerval s32it;
246 struct itimerval aitv;
247 int error;
248
249 error = dogetitimer(p, SCARG(uap, which), &aitv);
250 if (error)
251 return error;
252
253 netbsd32_from_itimerval(&aitv, &s32it);
254 return (copyout(&s32it, (caddr_t)NETBSD32PTR64(SCARG(uap, itv)),
255 sizeof(s32it)));
256 }
257
258 int
259 netbsd32_gettimeofday(l, v, retval)
260 struct lwp *l;
261 void *v;
262 register_t *retval;
263 {
264 struct netbsd32_gettimeofday_args /* {
265 syscallarg(netbsd32_timevalp_t) tp;
266 syscallarg(netbsd32_timezonep_t) tzp;
267 } */ *uap = v;
268 struct timeval atv;
269 struct netbsd32_timeval tv32;
270 int error = 0;
271 struct netbsd32_timezone tzfake;
272
273 if (SCARG(uap, tp)) {
274 microtime(&atv);
275 netbsd32_from_timeval(&atv, &tv32);
276 error = copyout(&tv32, (caddr_t)NETBSD32PTR64(SCARG(uap, tp)),
277 sizeof(tv32));
278 if (error)
279 return (error);
280 }
281 if (SCARG(uap, tzp)) {
282 /*
283 * NetBSD has no kernel notion of time zone, so we just
284 * fake up a timezone struct and return it if demanded.
285 */
286 tzfake.tz_minuteswest = 0;
287 tzfake.tz_dsttime = 0;
288 error = copyout(&tzfake,
289 (caddr_t)NETBSD32PTR64(SCARG(uap, tzp)), sizeof(tzfake));
290 }
291 return (error);
292 }
293
294 int
295 netbsd32_settimeofday(l, v, retval)
296 struct lwp *l;
297 void *v;
298 register_t *retval;
299 {
300 struct netbsd32_settimeofday_args /* {
301 syscallarg(const netbsd32_timevalp_t) tv;
302 syscallarg(const netbsd32_timezonep_t) tzp;
303 } */ *uap = v;
304 struct netbsd32_timeval atv32;
305 struct timeval atv;
306 struct timespec ats;
307 int error;
308 struct proc *p = l->l_proc;
309
310 /* Verify all parameters before changing time. */
311 if ((error = kauth_authorize_generic(l->l_cred,
312 KAUTH_GENERIC_ISSUSER, &l->l_acflag)) != 0)
313 return error;
314
315 /*
316 * NetBSD has no kernel notion of time zone, and only an
317 * obsolete program would try to set it, so we log a warning.
318 */
319 if (SCARG(uap, tzp))
320 printf("pid %d attempted to set the "
321 "(obsolete) kernel time zone\n", p->p_pid);
322
323 if (SCARG(uap, tv) == 0)
324 return 0;
325
326 if ((error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, tv)), &atv32,
327 sizeof(atv32))) != 0)
328 return error;
329
330 netbsd32_to_timeval(&atv32, &atv);
331 TIMEVAL_TO_TIMESPEC(&atv, &ats);
332 return settime(p, &ats);
333 }
334
335 int
336 netbsd32_adjtime(l, v, retval)
337 struct lwp *l;
338 void *v;
339 register_t *retval;
340 {
341 struct netbsd32_adjtime_args /* {
342 syscallarg(const netbsd32_timevalp_t) delta;
343 syscallarg(netbsd32_timevalp_t) olddelta;
344 } */ *uap = v;
345 struct netbsd32_timeval atv;
346 int error;
347
348 if ((error = kauth_authorize_generic(l->l_cred,
349 KAUTH_GENERIC_ISSUSER, &l->l_acflag)) != 0)
350 return (error);
351
352 #ifdef __HAVE_TIMECOUNTER
353 {
354 extern int time_adjusted; /* in kern_ntptime.c */
355 extern int64_t time_adjtime; /* in kern_ntptime.c */
356 if (SCARG(uap, olddelta)) {
357 atv.tv_sec = time_adjtime / 1000000;
358 atv.tv_usec = time_adjtime % 1000000;
359 if (atv.tv_usec < 0) {
360 atv.tv_usec += 1000000;
361 atv.tv_sec--;
362 }
363 (void) copyout(&atv,
364 (caddr_t)NETBSD32PTR64(SCARG(uap, olddelta)),
365 sizeof(atv));
366 if (error)
367 return (error);
368 }
369
370 if (SCARG(uap, delta)) {
371 error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, delta)), &atv,
372 sizeof(struct timeval));
373 if (error)
374 return (error);
375
376 time_adjtime = (int64_t)atv.tv_sec * 1000000 +
377 atv.tv_usec;
378
379 if (time_adjtime)
380 /* We need to save the system time during shutdown */
381 time_adjusted |= 1;
382 }
383 }
384 #else /* !__HAVE_TIMECOUNTER */
385 {
386 int32_t ndelta, ntickdelta, odelta;
387 extern long bigadj, timedelta;
388 extern int tickdelta;
389 int s;
390 error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, delta)), &atv,
391 sizeof(struct timeval));
392 if (error)
393 return (error);
394 /*
395 * Compute the total correction and the rate at which to apply it.
396 * Round the adjustment down to a whole multiple of the per-tick
397 * delta, so that after some number of incremental changes in
398 * hardclock(), tickdelta will become zero, lest the correction
399 * overshoot and start taking us away from the desired final time.
400 */
401 ndelta = atv.tv_sec * 1000000 + atv.tv_usec;
402 if (ndelta > bigadj)
403 ntickdelta = 10 * tickadj;
404 else
405 ntickdelta = tickadj;
406 if (ndelta % ntickdelta)
407 ndelta = ndelta / ntickdelta * ntickdelta;
408
409 /*
410 * To make hardclock()'s job easier, make the per-tick delta negative
411 * if we want time to run slower; then hardclock can simply compute
412 * tick + tickdelta, and subtract tickdelta from timedelta.
413 */
414 if (ndelta < 0)
415 ntickdelta = -ntickdelta;
416 s = splclock();
417 odelta = timedelta;
418 timedelta = ndelta;
419 tickdelta = ntickdelta;
420 splx(s);
421
422 if (SCARG(uap, olddelta)) {
423 atv.tv_sec = odelta / 1000000;
424 atv.tv_usec = odelta % 1000000;
425 (void) copyout(&atv,
426 (caddr_t)NETBSD32PTR64(SCARG(uap, olddelta)), sizeof(atv));
427 }
428 }
429 #endif /* !__HAVE_TIMECOUNTER */
430 return (0);
431 }
432
433 int
434 netbsd32_clock_gettime(l, v, retval)
435 struct lwp *l;
436 void *v;
437 register_t *retval;
438 {
439 struct netbsd32_clock_gettime_args /* {
440 syscallarg(netbsd32_clockid_t) clock_id;
441 syscallarg(netbsd32_timespecp_t) tp;
442 } */ *uap = v;
443 clockid_t clock_id;
444 struct timespec ats;
445 struct netbsd32_timespec ts32;
446
447 clock_id = SCARG(uap, clock_id);
448 if (clock_id != CLOCK_REALTIME)
449 return (EINVAL);
450
451 nanotime(&ats);
452 netbsd32_from_timespec(&ats, &ts32);
453
454 return copyout(&ts32, (caddr_t)NETBSD32PTR64(SCARG(uap, tp)),
455 sizeof(ts32));
456 }
457
458 int
459 netbsd32_clock_settime(l, v, retval)
460 struct lwp *l;
461 void *v;
462 register_t *retval;
463 {
464 struct netbsd32_clock_settime_args /* {
465 syscallarg(netbsd32_clockid_t) clock_id;
466 syscallarg(const netbsd32_timespecp_t) tp;
467 } */ *uap = v;
468 struct netbsd32_timespec ts32;
469 clockid_t clock_id;
470 struct timespec ats;
471 int error;
472
473 if ((error = kauth_authorize_generic(l->l_cred,
474 KAUTH_GENERIC_ISSUSER, &l->l_acflag)) != 0)
475 return (error);
476
477 clock_id = SCARG(uap, clock_id);
478 if (clock_id != CLOCK_REALTIME)
479 return (EINVAL);
480
481 if ((error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, tp)), &ts32,
482 sizeof(ts32))) != 0)
483 return (error);
484
485 netbsd32_to_timespec(&ts32, &ats);
486 return settime(l->l_proc, &ats);
487 }
488
489 int
490 netbsd32_clock_getres(l, v, retval)
491 struct lwp *l;
492 void *v;
493 register_t *retval;
494 {
495 struct netbsd32_clock_getres_args /* {
496 syscallarg(netbsd32_clockid_t) clock_id;
497 syscallarg(netbsd32_timespecp_t) tp;
498 } */ *uap = v;
499 struct netbsd32_timespec ts32;
500 clockid_t clock_id;
501 struct timespec ts;
502 int error = 0;
503
504 clock_id = SCARG(uap, clock_id);
505 if (clock_id != CLOCK_REALTIME)
506 return (EINVAL);
507
508 if (SCARG(uap, tp)) {
509 ts.tv_sec = 0;
510 ts.tv_nsec = 1000000000 / hz;
511
512 netbsd32_from_timespec(&ts, &ts32);
513 error = copyout(&ts, (caddr_t)NETBSD32PTR64(SCARG(uap, tp)),
514 sizeof(ts));
515 }
516
517 return error;
518 }
519
520 int
521 netbsd32_nanosleep(l, v, retval)
522 struct lwp *l;
523 void *v;
524 register_t *retval;
525 {
526 struct netbsd32_nanosleep_args /* {
527 syscallarg(const netbsd32_timespecp_t) rqtp;
528 syscallarg(netbsd32_timespecp_t) rmtp;
529 } */ *uap = v;
530 static int nanowait;
531 struct netbsd32_timespec ts32;
532 struct timespec rqt;
533 struct timespec rmt;
534 struct timeval atv, utv, ctime;
535 int error, timo;
536
537 error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, rqtp)), (caddr_t)&ts32,
538 sizeof(ts32));
539 if (error)
540 return (error);
541
542 netbsd32_to_timespec(&ts32, &rqt);
543 TIMESPEC_TO_TIMEVAL(&atv,&rqt);
544 if (itimerfix(&atv))
545 return (EINVAL);
546
547 getmicrotime(&ctime);
548 timeradd(&atv,&ctime,&atv);
549 timo = hzto(&atv);
550 /*
551 * Avoid inadvertantly sleeping forever
552 */
553 if (timo == 0)
554 timo = 1;
555
556 error = tsleep(&nanowait, PWAIT | PCATCH, "nanosleep", timo);
557 if (error == ERESTART)
558 error = EINTR;
559 if (error == EWOULDBLOCK)
560 error = 0;
561
562 if (SCARG(uap, rmtp)) {
563 int error1;
564
565 getmicrotime(&utv);
566
567 timersub(&atv, &utv, &utv);
568 if (utv.tv_sec < 0)
569 timerclear(&utv);
570
571 TIMEVAL_TO_TIMESPEC(&utv,&rmt);
572 netbsd32_from_timespec(&rmt, &ts32);
573 error1 = copyout(&ts32,
574 NETBSD32PTR64(SCARG(uap,rmtp)), sizeof(ts32));
575 if (error1)
576 return (error1);
577 }
578
579 return error;
580 }
581
582 static int
583 netbsd32_timer_create_fetch(const void *src, void *dst, size_t size)
584 {
585 struct sigevent *evp = dst;
586 struct netbsd32_sigevent ev32;
587 int error;
588
589 error = copyin(src, &ev32, sizeof(ev32));
590 if (error)
591 return error;
592
593 netbsd32_to_sigevent(&ev32, evp);
594 return 0;
595 }
596
597 int
598 netbsd32_timer_create(struct lwp *l, void *v, register_t *retval)
599 {
600 struct netbsd32_timer_create_args /* {
601 syscallarg(netbsd32_clockid_t) clock_id;
602 syscallarg(netbsd32_sigeventp_t) evp;
603 syscallarg(netbsd32_timerp_t) timerid;
604 } */ *uap = v;
605
606 return timer_create1(NETBSD32PTR64(SCARG(uap, timerid)),
607 SCARG(uap, clock_id), NETBSD32PTR64(SCARG(uap, evp)),
608 netbsd32_timer_create_fetch, l);
609 }
610
611 int
612 netbsd32_timer_delete(struct lwp *l, void *v, register_t *retval)
613 {
614 struct netbsd32_timer_delete_args /* {
615 syscallarg(netbsd32_timer_t) timerid;
616 } */ *uap = v;
617 struct sys_timer_delete_args ua;
618
619 NETBSD32TO64_UAP(timerid);
620 return sys_timer_delete(l, (void *)&ua, retval);
621 }
622
623 int
624 netbsd32_timer_settime(struct lwp *l, void *v, register_t *retval)
625 {
626 struct netbsd32_timer_settime_args /* {
627 syscallarg(netbsd32_timer_t) timerid;
628 syscallarg(int) flags;
629 syscallarg(const netbsd32_itimerspecp_t) value;
630 syscallarg(netbsd32_itimerspecp_t) ovalue;
631 } */ *uap = v;
632 int error;
633 struct itimerspec value, ovalue, *ovp = NULL;
634 struct netbsd32_itimerspec its32;
635
636 if ((error = copyin(NETBSD32PTR64(SCARG(uap, value)), &its32,
637 sizeof(its32))) != 0)
638 return (error);
639 netbsd32_to_timespec(&its32.it_interval, &value.it_interval);
640 netbsd32_to_timespec(&its32.it_value, &value.it_value);
641
642 if (SCARG(uap, ovalue))
643 ovp = &ovalue;
644
645 if ((error = dotimer_settime(SCARG(uap, timerid), &value, ovp,
646 SCARG(uap, flags), l->l_proc)) != 0)
647 return error;
648
649 if (ovp) {
650 netbsd32_from_timespec(&ovp->it_interval, &its32.it_interval);
651 netbsd32_from_timespec(&ovp->it_value, &its32.it_value);
652 return copyout(&its32, NETBSD32PTR64(SCARG(uap, ovalue)),
653 sizeof(its32));
654 }
655 return 0;
656 }
657
658 int
659 netbsd32_timer_gettime(struct lwp *l, void *v, register_t *retval)
660 {
661 struct netbsd32_timer_gettime_args /* {
662 syscallarg(netbsd32_timer_t) timerid;
663 syscallarg(netbsd32_itimerspecp_t) value;
664 } */ *uap = v;
665 int error;
666 struct itimerspec its;
667 struct netbsd32_itimerspec its32;
668
669 if ((error = dotimer_gettime(SCARG(uap, timerid), l->l_proc,
670 &its)) != 0)
671 return error;
672
673 netbsd32_from_timespec(&its.it_interval, &its32.it_interval);
674 netbsd32_from_timespec(&its.it_value, &its32.it_value);
675
676 return copyout(&its32, (caddr_t)NETBSD32PTR64(SCARG(uap, value)),
677 sizeof(its32));
678 }
679
680 int
681 netbsd32_timer_getoverrun(struct lwp *l, void *v, register_t *retval)
682 {
683 struct netbsd32_timer_getoverrun_args /* {
684 syscallarg(netbsd32_timer_t) timerid;
685 } */ *uap = v;
686 struct sys_timer_getoverrun_args ua;
687
688 NETBSD32TO64_UAP(timerid);
689 return sys_timer_getoverrun(l, (void *)&ua, retval);
690 }
691