2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
28 #include <mach/mach_types.h>
30 #include <kern/lock.h>
32 #include <kern/sched_prim.h>
33 #include <kern/thread.h>
34 #include <kern/clock.h>
35 #include <kern/host_notify.h>
37 #include <IOKit/IOPlatformExpert.h>
39 #include <machine/commpage.h>
41 #include <mach/mach_traps.h>
42 #include <mach/mach_time.h>
44 decl_simple_lock_data(static,clock_lock
)
47 * Time of day (calendar) variables.
51 * TOD <- (seconds + epoch, fraction) <- CONV(current absolute time + offset)
53 * where CONV converts absolute time units into seconds and a fraction.
55 static struct clock_calend
{
61 * Calendar adjustment variables and values.
63 #define calend_adjperiod (NSEC_PER_SEC / 100) /* adjustment period, ns */
64 #define calend_adjskew (40 * NSEC_PER_USEC) /* "standard" skew, ns / period */
65 #define calend_adjbig (NSEC_PER_SEC) /* use 10x skew above adjbig ns */
67 static uint64_t calend_adjstart
; /* Absolute time value for start of this adjustment period */
68 static uint32_t calend_adjoffset
; /* Absolute time offset for this adjustment period as absolute value */
70 static int32_t calend_adjdelta
; /* Nanosecond time delta for this adjustment period */
71 static int64_t calend_adjtotal
; /* Nanosecond remaining total adjustment */
73 static uint64_t calend_adjdeadline
; /* Absolute time value for next adjustment period */
74 static uint32_t calend_adjinterval
; /* Absolute time interval of adjustment period */
76 static timer_call_data_t calend_adjcall
;
77 static uint32_t calend_adjactive
;
79 static uint32_t calend_set_adjustment(
83 static void calend_adjust_call(void);
84 static uint32_t calend_adjust(void);
86 static thread_call_data_t calend_wakecall
;
88 extern void IOKitResetTime(void);
90 static uint64_t clock_boottime
; /* Seconds boottime epoch */
92 #define TIME_ADD(rsecs, secs, rfrac, frac, unit) \
94 if (((rfrac) += (frac)) >= (unit)) { \
101 #define TIME_SUB(rsecs, secs, rfrac, frac, unit) \
103 if ((int32_t)((rfrac) -= (frac)) < 0) { \
113 * Called once at boot to configure the clock subsystem.
118 simple_lock_init(&clock_lock
, 0);
120 timer_call_setup(&calend_adjcall
, (timer_call_func_t
)calend_adjust_call
, NULL
);
121 thread_call_setup(&calend_wakecall
, (thread_call_func_t
)IOKitResetTime
, NULL
);
126 * Initialize the timer callouts.
128 timer_call_initialize();
134 * Called on a processor each time started.
143 * clock_timebase_init:
145 * Called by machine dependent code
146 * to initialize areas dependent on the
147 * timebase value. May be called multiple
148 * times during start up.
151 clock_timebase_init(void)
155 nanoseconds_to_absolutetime(calend_adjperiod
, &abstime
);
156 calend_adjinterval
= abstime
;
158 sched_timebase_init();
162 * mach_timebase_info_trap:
164 * User trap returns timebase constant.
167 mach_timebase_info_trap(
168 struct mach_timebase_info_trap_args
*args
)
170 mach_vm_address_t out_info_addr
= args
->info
;
171 mach_timebase_info_data_t info
;
173 clock_timebase_info(&info
);
175 copyout((void *)&info
, out_info_addr
, sizeof (info
));
177 return (KERN_SUCCESS
);
185 * clock_get_calendar_microtime:
187 * Returns the current calendar value,
188 * microseconds as the fraction.
191 clock_get_calendar_microtime(
199 simple_lock(&clock_lock
);
201 now
= mach_absolute_time();
203 if (calend_adjdelta
< 0) {
206 if (now
> calend_adjstart
) {
207 t32
= now
- calend_adjstart
;
209 if (t32
> calend_adjoffset
)
210 now
-= calend_adjoffset
;
212 now
= calend_adjstart
;
216 now
+= clock_calend
.offset
;
218 absolutetime_to_microtime(now
, secs
, microsecs
);
220 *secs
+= clock_calend
.epoch
;
222 simple_unlock(&clock_lock
);
227 * clock_get_calendar_nanotime:
229 * Returns the current calendar value,
230 * nanoseconds as the fraction.
232 * Since we do not have an interface to
233 * set the calendar with resolution greater
234 * than a microsecond, we honor that here.
237 clock_get_calendar_nanotime(
245 simple_lock(&clock_lock
);
247 now
= mach_absolute_time();
249 if (calend_adjdelta
< 0) {
252 if (now
> calend_adjstart
) {
253 t32
= now
- calend_adjstart
;
255 if (t32
> calend_adjoffset
)
256 now
-= calend_adjoffset
;
258 now
= calend_adjstart
;
262 now
+= clock_calend
.offset
;
264 absolutetime_to_microtime(now
, secs
, nanosecs
);
265 *nanosecs
*= NSEC_PER_USEC
;
267 *secs
+= clock_calend
.epoch
;
269 simple_unlock(&clock_lock
);
274 * clock_gettimeofday:
276 * Kernel interface for commpage implementation of
277 * gettimeofday() syscall.
279 * Returns the current calendar value, and updates the
280 * commpage info as appropriate. Because most calls to
281 * gettimeofday() are handled in user mode by the commpage,
282 * this routine should be used infrequently.
293 simple_lock(&clock_lock
);
295 now
= mach_absolute_time();
297 if (calend_adjdelta
>= 0) {
298 clock_gettimeofday_set_commpage(now
, clock_calend
.epoch
, clock_calend
.offset
, secs
, microsecs
);
303 if (now
> calend_adjstart
) {
304 t32
= now
- calend_adjstart
;
306 if (t32
> calend_adjoffset
)
307 now
-= calend_adjoffset
;
309 now
= calend_adjstart
;
312 now
+= clock_calend
.offset
;
314 absolutetime_to_microtime(now
, secs
, microsecs
);
316 *secs
+= clock_calend
.epoch
;
319 simple_unlock(&clock_lock
);
324 * clock_set_calendar_microtime:
326 * Sets the current calendar value by
327 * recalculating the epoch and offset
328 * from the system clock.
330 * Also adjusts the boottime to keep the
331 * value consistent, writes the new
332 * calendar value to the platform clock,
333 * and sends calendar change notifications.
336 clock_set_calendar_microtime(
340 uint32_t sys
, microsys
;
344 newsecs
= (microsecs
< 500*USEC_PER_SEC
)?
348 simple_lock(&clock_lock
);
350 commpage_set_timestamp(0,0,0);
353 * Calculate the new calendar epoch based on
354 * the new value and the system clock.
356 clock_get_system_microtime(&sys
, µsys
);
357 TIME_SUB(secs
, sys
, microsecs
, microsys
, USEC_PER_SEC
);
360 * Adjust the boottime based on the delta.
362 clock_boottime
+= secs
- clock_calend
.epoch
;
365 * Set the new calendar epoch.
367 clock_calend
.epoch
= secs
;
368 nanoseconds_to_absolutetime((uint64_t)microsecs
* NSEC_PER_USEC
, &clock_calend
.offset
);
371 * Cancel any adjustment in progress.
373 calend_adjdelta
= calend_adjtotal
= 0;
375 simple_unlock(&clock_lock
);
378 * Set the new value for the platform clock.
380 PESetGMTTimeOfDay(newsecs
);
385 * Send host notifications.
387 host_notify_calendar_change();
391 * clock_initialize_calendar:
393 * Set the calendar and related clocks
394 * from the platform clock at boot or
397 * Also sends host notifications.
400 clock_initialize_calendar(void)
402 uint32_t sys
, microsys
;
403 uint32_t microsecs
= 0, secs
= PEGetGMTTimeOfDay();
407 simple_lock(&clock_lock
);
409 commpage_set_timestamp(0,0,0);
411 if ((int32_t)secs
>= (int32_t)clock_boottime
) {
413 * Initialize the boot time based on the platform clock.
415 if (clock_boottime
== 0)
416 clock_boottime
= secs
;
419 * Calculate the new calendar epoch based on
420 * the platform clock and the system clock.
422 clock_get_system_microtime(&sys
, µsys
);
423 TIME_SUB(secs
, sys
, microsecs
, microsys
, USEC_PER_SEC
);
426 * Set the new calendar epoch.
428 clock_calend
.epoch
= secs
;
429 nanoseconds_to_absolutetime((uint64_t)microsecs
* NSEC_PER_USEC
, &clock_calend
.offset
);
432 * Cancel any adjustment in progress.
434 calend_adjdelta
= calend_adjtotal
= 0;
437 simple_unlock(&clock_lock
);
441 * Send host notifications.
443 host_notify_calendar_change();
447 * clock_get_boottime_nanotime:
449 * Return the boottime, used by sysctl.
452 clock_get_boottime_nanotime(
456 *secs
= clock_boottime
;
463 * Interface to adjtime() syscall.
465 * Calculates adjustment variables and
466 * initiates adjustment.
477 simple_lock(&clock_lock
);
479 interval
= calend_set_adjustment(secs
, microsecs
);
481 calend_adjdeadline
= mach_absolute_time() + interval
;
482 if (!timer_call_enter(&calend_adjcall
, calend_adjdeadline
))
486 if (timer_call_cancel(&calend_adjcall
))
489 simple_unlock(&clock_lock
);
494 calend_set_adjustment(
499 int64_t total
, ototal
;
500 uint32_t interval
= 0;
502 total
= (int64_t)*secs
* NSEC_PER_SEC
+ *microsecs
* NSEC_PER_USEC
;
504 commpage_set_timestamp(0,0,0);
506 now
= mach_absolute_time();
508 ototal
= calend_adjtotal
;
511 int32_t delta
= calend_adjskew
;
514 if (total
> calend_adjbig
)
519 nanoseconds_to_absolutetime((uint64_t)delta
, &t64
);
520 calend_adjoffset
= t64
;
523 if (total
< -calend_adjbig
)
529 calend_adjstart
= now
;
531 nanoseconds_to_absolutetime((uint64_t)-delta
, &t64
);
532 calend_adjoffset
= t64
;
535 calend_adjtotal
= total
;
536 calend_adjdelta
= delta
;
538 interval
= calend_adjinterval
;
541 calend_adjdelta
= calend_adjtotal
= 0;
544 *secs
= ototal
/ NSEC_PER_SEC
;
545 *microsecs
= (ototal
% NSEC_PER_SEC
) / NSEC_PER_USEC
;
548 *secs
= *microsecs
= 0;
554 calend_adjust_call(void)
560 simple_lock(&clock_lock
);
562 if (--calend_adjactive
== 0) {
563 interval
= calend_adjust();
565 clock_deadline_for_periodic_event(interval
, mach_absolute_time(),
566 &calend_adjdeadline
);
568 if (!timer_call_enter(&calend_adjcall
, calend_adjdeadline
))
573 simple_unlock(&clock_lock
);
582 uint32_t interval
= 0;
584 commpage_set_timestamp(0,0,0);
586 now
= mach_absolute_time();
588 delta
= calend_adjdelta
;
591 clock_calend
.offset
+= calend_adjoffset
;
593 calend_adjtotal
-= delta
;
594 if (delta
> calend_adjtotal
) {
595 calend_adjdelta
= delta
= calend_adjtotal
;
597 nanoseconds_to_absolutetime((uint64_t)delta
, &t64
);
598 calend_adjoffset
= t64
;
603 clock_calend
.offset
-= calend_adjoffset
;
605 calend_adjtotal
-= delta
;
606 if (delta
< calend_adjtotal
) {
607 calend_adjdelta
= delta
= calend_adjtotal
;
609 nanoseconds_to_absolutetime((uint64_t)-delta
, &t64
);
610 calend_adjoffset
= t64
;
613 if (calend_adjdelta
!= 0)
614 calend_adjstart
= now
;
617 if (calend_adjdelta
!= 0)
618 interval
= calend_adjinterval
;
624 * clock_wakeup_calendar:
626 * Interface to power management, used
627 * to initiate the reset of the calendar
628 * on wake from sleep event.
631 clock_wakeup_calendar(void)
633 thread_call_enter(&calend_wakecall
);
637 * Wait / delay routines.
640 mach_wait_until_continue(
641 __unused
void *parameter
,
642 wait_result_t wresult
)
644 thread_syscall_return((wresult
== THREAD_INTERRUPTED
)? KERN_ABORTED
: KERN_SUCCESS
);
649 mach_wait_until_trap(
650 struct mach_wait_until_trap_args
*args
)
652 uint64_t deadline
= args
->deadline
;
653 wait_result_t wresult
;
655 wresult
= assert_wait_deadline((event_t
)mach_wait_until_trap
, THREAD_ABORTSAFE
, deadline
);
656 if (wresult
== THREAD_WAITING
)
657 wresult
= thread_block(mach_wait_until_continue
);
659 return ((wresult
== THREAD_INTERRUPTED
)? KERN_ABORTED
: KERN_SUCCESS
);
666 uint64_t now
= mach_absolute_time();
671 if ( (deadline
- now
) < (8 * sched_cswtime
) ||
672 get_preemption_level() != 0 ||
673 ml_get_interrupts_enabled() == FALSE
)
674 machine_delay_until(deadline
);
676 assert_wait_deadline((event_t
)clock_delay_until
, THREAD_UNINT
, deadline
- sched_cswtime
);
678 thread_block(THREAD_CONTINUE_NULL
);
685 uint32_t scale_factor
)
689 clock_interval_to_deadline(interval
, scale_factor
, &end
);
691 clock_delay_until(end
);
698 delay_for_interval((usec
< 0)? -usec
: usec
, NSEC_PER_USEC
);
702 * Miscellaneous routines.
705 clock_interval_to_deadline(
707 uint32_t scale_factor
,
712 clock_interval_to_absolutetime_interval(interval
, scale_factor
, &abstime
);
714 *result
= mach_absolute_time() + abstime
;
718 clock_absolutetime_interval_to_deadline(
722 *result
= mach_absolute_time() + abstime
;
729 *result
= mach_absolute_time();
733 clock_deadline_for_periodic_event(
738 assert(interval
!= 0);
740 *deadline
+= interval
;
742 if (*deadline
<= abstime
) {
743 *deadline
= abstime
+ interval
;
744 abstime
= mach_absolute_time();
746 if (*deadline
<= abstime
)
747 *deadline
= abstime
+ interval
;