]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/kern/clock.c
xnu-792.6.61.tar.gz
[apple/xnu.git] / osfmk / kern / clock.c
index b6a263b70d464d4e1ade8225b5a514e67bca961d..25fecf46f2306c39298749974cf05d78a0249e4b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *                     machine-independent clock service layer.
  */
 
-#include <cpus.h>
 #include <mach_host.h>
 
+#include <mach/mach_types.h>
 #include <mach/boolean.h>
 #include <mach/processor_info.h>
 #include <mach/vm_param.h>
-#include <machine/mach_param.h>
+
 #include <kern/cpu_number.h>
 #include <kern/misc_protos.h>
 #include <kern/lock.h>
 #include <kern/host.h>
 #include <kern/spl.h>
+#include <kern/sched_prim.h>
 #include <kern/thread.h>
-#include <kern/thread_swap.h>
 #include <kern/ipc_host.h>
 #include <kern/clock.h>
 #include <kern/zalloc.h>
+
+#include <ipc/ipc_types.h>
 #include <ipc/ipc_port.h>
 
-#include <mach/mach_syscalls.h>
+#include <mach/mach_traps.h>
 #include <mach/clock_reply.h>
 #include <mach/mach_time.h>
 
-#include <kern/mk_timer.h>
+#include <mach/clock_server.h>
+#include <mach/clock_priv_server.h>
+#include <mach/host_priv_server.h>
 
 /*
  * Exported interface
@@ -71,15 +75,11 @@ static long                                 alrm_seqno;             /* uniquely identifies alarms */
 static thread_call_data_t      alarm_deliver;
 
 decl_simple_lock_data(static,calend_adjlock)
-static int64_t                         calend_adjtotal;
-static uint32_t                                calend_adjdelta;
 
 static timer_call_data_t       calend_adjcall;
-static uint64_t                                calend_adjinterval, calend_adjdeadline;
+static uint64_t                                calend_adjdeadline;
 
-/* backwards compatibility */
-int             hz = HZ;                /* GET RID OF THIS !!! */
-int             tick = (1000000 / HZ);  /* GET RID OF THIS !!! */
+static thread_call_data_t      calend_wakecall;
 
 /* external declarations */
 extern struct clock    clock_list[];
@@ -107,10 +107,15 @@ void      clock_alarm_deliver(
                        thread_call_param_t             p1);
 
 static
-void   clock_calend_adjust(
+void   calend_adjust_call(
                        timer_call_param_t      p0,
                        timer_call_param_t      p1);
 
+static
+void   calend_dowakeup(
+                       thread_call_param_t             p0,
+                       thread_call_param_t             p1);
+
 /*
  *     Macros to lock/unlock clock system.
  */
@@ -123,8 +128,9 @@ void        clock_calend_adjust(
        splx(s);
 
 /*
- * Configure the clock system. (Not sure if we need this,
- * as separate from clock_init()).
+ *     clock_config:
+ *
+ *     Called once at boot to configure the clock subsystem.
  */
 void
 clock_config(void)
@@ -132,14 +138,19 @@ clock_config(void)
        clock_t                 clock;
        register int    i;
 
-       if (cpu_number() != master_cpu)
-               panic("clock_config");
+       assert(cpu_number() == master_cpu);
+
+       simple_lock_init(&ClockLock, 0);
+       thread_call_setup(&alarm_deliver, clock_alarm_deliver, NULL);
+
+       simple_lock_init(&calend_adjlock, 0);
+       timer_call_setup(&calend_adjcall, calend_adjust_call, NULL);
+
+       thread_call_setup(&calend_wakecall, calend_dowakeup, NULL);
 
        /*
         * Configure clock devices.
         */
-       simple_lock_init(&calend_adjlock, ETAP_MISC_CLOCK);
-       simple_lock_init(&ClockLock, ETAP_MISC_CLOCK);
        for (i = 0; i < clock_count; i++) {
                clock = &clock_list[i];
                if (clock->cl_ops) {
@@ -148,12 +159,19 @@ clock_config(void)
                }
        }
 
+       /*
+        * Initialize the timer callouts.
+        */
+       timer_call_initialize();
+
        /* start alarm sequence numbers at 0 */
        alrm_seqno = 0;
 }
 
 /*
- * Initialize the clock system.
+ *     clock_init:
+ *
+ *     Called on a processor each time started.
  */
 void
 clock_init(void)
@@ -166,11 +184,23 @@ clock_init(void)
         */
        for (i = 0; i < clock_count; i++) {
                clock = &clock_list[i];
-               if (clock->cl_ops)
+               if (clock->cl_ops && clock->cl_ops->c_init)
                        (*clock->cl_ops->c_init)();
        }
 }
 
+/*
+ * Called by machine dependent code
+ * to initialize areas dependent on the
+ * timebase value.  May be called multiple
+ * times during start up.
+ */
+void
+clock_timebase_init(void)
+{
+       sched_timebase_init();
+}
+
 /*
  * Initialize the clock ipc service facility.
  */
@@ -180,8 +210,6 @@ clock_service_create(void)
        clock_t                 clock;
        register int    i;
 
-       mk_timer_initialize();
-
        /*
         * Initialize ipc clock services.
         */
@@ -193,15 +221,12 @@ clock_service_create(void)
                }
        }
 
-       timer_call_setup(&calend_adjcall, clock_calend_adjust, NULL);
-
        /*
-        * Initialize clock service alarms.
+        * Perform miscellaneous late
+        * initialization.
         */
        i = sizeof(struct alarm);
        alarm_zone = zinit(i, (4096/i)*i, 10*i, "alarms");
-
-       thread_call_setup(&alarm_deliver, clock_alarm_deliver, NULL);
 }
 
 /*
@@ -267,15 +292,10 @@ clock_get_attributes(
        clock_attr_t                    attr,           /* OUT */
        mach_msg_type_number_t  *count)         /* IN/OUT */
 {
-       kern_return_t   (*getattr)(
-                                               clock_flavor_t                  flavor,
-                                               clock_attr_t                    attr,
-                                               mach_msg_type_number_t  *count);
-
        if (clock == CLOCK_NULL)
                return (KERN_INVALID_ARGUMENT);
-       if (getattr = clock->cl_ops->c_getattr)
-               return((*getattr)(flavor, attr, count));
+       if (clock->cl_ops->c_getattr)
+               return(clock->cl_ops->c_getattr(flavor, attr, count));
        else
                return (KERN_FAILURE);
 }
@@ -289,17 +309,10 @@ clock_set_time(
        mach_timespec_t new_time)
 {
        mach_timespec_t *clock_time;
-       kern_return_t   (*settime)(
-                                               mach_timespec_t         *clock_time);
-       extern kern_return_t
-                                       calend_settime(
-                                               mach_timespec_t         *clock_time);
 
        if (clock == CLOCK_NULL)
                return (KERN_INVALID_ARGUMENT);
-       if ((settime = clock->cl_ops->c_settime) == 0)
-               return (KERN_FAILURE);
-       if (settime == calend_settime)
+       if (clock->cl_ops->c_settime == NULL)
                return (KERN_FAILURE);
        clock_time = &new_time;
        if (BAD_MACH_TIMESPEC(clock_time))
@@ -313,7 +326,7 @@ clock_set_time(
        /*
         * Set the new time.
         */
-       return ((*settime)(clock_time));
+       return (clock->cl_ops->c_settime(clock_time));
 }
 
 /*
@@ -326,15 +339,10 @@ clock_set_attributes(
        clock_attr_t                    attr,
        mach_msg_type_number_t  count)
 {
-       kern_return_t   (*setattr)(
-                                               clock_flavor_t                  flavor,
-                                               clock_attr_t                    attr,
-                                               mach_msg_type_number_t  count);
-
        if (clock == CLOCK_NULL)
                return (KERN_INVALID_ARGUMENT);
-       if (setattr = clock->cl_ops->c_setattr)
-               return ((*setattr)(flavor, attr, count));
+       if (clock->cl_ops->c_setattr)
+               return (clock->cl_ops->c_setattr(flavor, attr, count));
        else
                return (KERN_FAILURE);
 }
@@ -412,12 +420,13 @@ clock_alarm(
  */
 kern_return_t
 clock_sleep_trap(
-       mach_port_name_t        clock_name,
-       sleep_type_t            sleep_type,
-       int                                     sleep_sec,
-       int                                     sleep_nsec,
-       mach_timespec_t         *wakeup_time)
+       struct clock_sleep_trap_args *args)
 {
+       mach_port_name_t        clock_name = args->clock_name;
+       sleep_type_t            sleep_type = args->sleep_type;
+       int                                     sleep_sec = args->sleep_sec;
+       int                                     sleep_nsec = args->sleep_nsec;
+       mach_vm_address_t       wakeup_time_addr = args->wakeup_time;  
        clock_t                         clock;
        mach_timespec_t         swtime;
        kern_return_t           rvalue;
@@ -442,8 +451,7 @@ clock_sleep_trap(
         * Return current time as wakeup time.
         */
        if (rvalue != KERN_INVALID_ARGUMENT && rvalue != KERN_FAILURE) {
-               copyout((char *)&swtime, (char *)wakeup_time,
-                       sizeof(mach_timespec_t));
+               copyout((char *)&swtime, wakeup_time_addr, sizeof(mach_timespec_t));
        }
        return (rvalue);
 }      
@@ -517,7 +525,7 @@ clock_sleep_internal(
                        LOCK_CLOCK(s);
                        if (alarm->al_status != ALARM_DONE) {
                                assert(wait_result != THREAD_AWAKENED);
-                               if ((alarm->al_prev)->al_next = alarm->al_next)
+                               if (((alarm->al_prev)->al_next = alarm->al_next) != NULL)
                                        (alarm->al_next)->al_prev = alarm->al_prev;
                                rvalue = KERN_ABORTED;
                        }
@@ -567,7 +575,7 @@ clock_alarm_intr(
 
        LOCK_CLOCK(s);
        alrm1 = (alarm_t) &clock->cl_alarm;
-       while (alrm2 = alrm1->al_next) {
+       while ((alrm2 = alrm1->al_next) != NULL) {
                alarm_time = &alrm2->al_time;
                if (CMP_MACH_TIMESPEC(alarm_time, clock_time) > 0)
                        break;
@@ -576,7 +584,7 @@ clock_alarm_intr(
                 * Alarm has expired, so remove it from the
                 * clock alarm list.
                 */  
-               if (alrm1->al_next = alrm2->al_next)
+               if ((alrm1->al_next = alrm2->al_next) != NULL)
                        (alrm1->al_next)->al_prev = alrm1;
 
                /*
@@ -597,7 +605,7 @@ clock_alarm_intr(
                 */
                else {
                        assert(alrm2->al_status == ALARM_CLOCK);
-                       if (alrm2->al_next = alrmdone)
+                       if ((alrm2->al_next = alrmdone) != NULL)
                                alrmdone->al_prev = alrm2;
                        else
                                thread_call_enter(&alarm_deliver);
@@ -623,16 +631,16 @@ clock_alarm_intr(
 
 static void
 clock_alarm_deliver(
-       thread_call_param_t             p0,
-       thread_call_param_t             p1)
+       __unused thread_call_param_t            p0,
+       __unused thread_call_param_t            p1)
 {
        register alarm_t        alrm;
        kern_return_t           code;
        spl_t                           s;
 
        LOCK_CLOCK(s);
-       while (alrm = alrmdone) {
-               if (alrmdone = alrm->al_next)
+       while ((alrm = alrmdone) != NULL) {
+               if ((alrmdone = alrm->al_next) != NULL)
                        alrmdone->al_prev = (alarm_t) &alrmdone;
                UNLOCK_CLOCK(s);
 
@@ -679,11 +687,11 @@ flush_alarms(
         */
        LOCK_CLOCK(s);
        alrm1 = (alarm_t) &clock->cl_alarm;
-       while (alrm2 = alrm1->al_next) {
+       while ((alrm2 = alrm1->al_next) != NULL) {
                /*
                 * Remove alarm from the clock alarm list.
                 */  
-               if (alrm1->al_next = alrm2->al_next)
+               if ((alrm1->al_next = alrm2->al_next) != NULL)
                        (alrm1->al_next)->al_prev = alrm1;
 
                /*
@@ -701,7 +709,7 @@ flush_alarms(
                         * kernel alarm_thread to service the alarm.
                         */
                        assert(alrm2->al_status == ALARM_CLOCK);
-                       if (alrm2->al_next = alrmdone)
+                       if ((alrm2->al_next = alrmdone) != NULL)
                                alrmdone->al_prev = alrm2;
                        else
                                thread_wakeup((event_t)&alrmdone);
@@ -733,7 +741,7 @@ post_alarm(
         */
        alarm_time = &alarm->al_time;
        alrm1 = (alarm_t) &clock->cl_alarm;
-       while (alrm2 = alrm1->al_next) {
+       while ((alrm2 = alrm1->al_next) != NULL) {
                queue_time = &alrm2->al_time;
                if (CMP_MACH_TIMESPEC(queue_time, alarm_time) > 0)
                        break;
@@ -802,15 +810,6 @@ clock_get_calendar_value(void)
        return value;
 }
 
-void
-clock_set_calendar_value(
-       mach_timespec_t         value)
-{
-       clock_t                         clock = &clock_list[CALENDAR_CLOCK];
-
-       (void) (*clock->cl_ops->c_settime)(&value);
-}
-
 void
 clock_deadline_for_periodic_event(
        uint64_t                        interval,
@@ -822,157 +821,179 @@ clock_deadline_for_periodic_event(
        *deadline += interval;
 
        if (*deadline <= abstime) {
-               *deadline = abstime;
-               clock_get_uptime(&abstime);
-               *deadline += interval;
+               *deadline = abstime + interval;
+               abstime = mach_absolute_time();
 
-               if (*deadline <= abstime) {
-                       *deadline = abstime;
-                       *deadline += interval;
-               }
+               if (*deadline <= abstime)
+                       *deadline = abstime + interval;
        }
 }
 
 void
-mk_timebase_info(
-       uint32_t                        *delta,
-       uint32_t                        *abs_to_ns_numer,
-       uint32_t                        *abs_to_ns_denom,
-       uint32_t                        *proc_to_abs_numer,
-       uint32_t                        *proc_to_abs_denom)
+mk_timebase_info_trap(
+       struct mk_timebase_info_trap_args *args)
 {
+       uint32_t                                        *delta = args->delta;
+       uint32_t                                        *abs_to_ns_numer = args->abs_to_ns_numer;
+       uint32_t                                        *abs_to_ns_denom = args->abs_to_ns_denom;
+       uint32_t                                        *proc_to_abs_numer = args->proc_to_abs_numer;
+       uint32_t                                        *proc_to_abs_denom = args->proc_to_abs_denom;
        mach_timebase_info_data_t       info;
        uint32_t                                        one = 1;
 
        clock_timebase_info(&info);
 
-       copyout((void *)&one, (void *)delta, sizeof (uint32_t));
+       copyout((void *)&one, CAST_USER_ADDR_T(delta), sizeof (uint32_t));
 
-       copyout((void *)&info.numer, (void *)abs_to_ns_numer, sizeof (uint32_t));
-       copyout((void *)&info.denom, (void *)abs_to_ns_denom, sizeof (uint32_t));
+       copyout((void *)&info.numer, CAST_USER_ADDR_T(abs_to_ns_numer), sizeof (uint32_t));
+       copyout((void *)&info.denom, CAST_USER_ADDR_T(abs_to_ns_denom), sizeof (uint32_t));
 
-       copyout((void *)&one, (void *)proc_to_abs_numer, sizeof (uint32_t));
-       copyout((void *)&one, (void *)proc_to_abs_denom, sizeof (uint32_t));
+       copyout((void *)&one, CAST_USER_ADDR_T(proc_to_abs_numer), sizeof (uint32_t));
+       copyout((void *)&one, CAST_USER_ADDR_T(proc_to_abs_denom), sizeof (uint32_t));
 }
 
 kern_return_t
-mach_timebase_info(
-       mach_timebase_info_t    out_info)
+mach_timebase_info_trap(
+       struct mach_timebase_info_trap_args *args)
 {
+       mach_vm_address_t                       out_info_addr = args->info;
        mach_timebase_info_data_t       info;
 
        clock_timebase_info(&info);
 
-       copyout((void *)&info, (void *)out_info, sizeof (info));
+       copyout((void *)&info, out_info_addr, sizeof (info));
 
        return (KERN_SUCCESS);
 }
 
+static void
+mach_wait_until_continue(
+       __unused void   *parameter,
+       wait_result_t   wresult)
+{
+       thread_syscall_return((wresult == THREAD_INTERRUPTED)? KERN_ABORTED: KERN_SUCCESS);
+       /*NOTREACHED*/
+}
+
 kern_return_t
-mach_wait_until(
-       uint64_t                deadline)
+mach_wait_until_trap(
+       struct mach_wait_until_trap_args        *args)
 {
-       int                             wait_result;
+       uint64_t                deadline = args->deadline;
+       wait_result_t   wresult;
 
-       wait_result = assert_wait((event_t)&mach_wait_until, THREAD_ABORTSAFE);
-       if (wait_result == THREAD_WAITING) {
-               thread_set_timer_deadline(deadline);
-               wait_result = thread_block(THREAD_CONTINUE_NULL);
-               if (wait_result != THREAD_TIMED_OUT)
-                       thread_cancel_timer();
-       }
+       wresult = assert_wait_deadline((event_t)mach_wait_until_trap, THREAD_ABORTSAFE, deadline);
+       if (wresult == THREAD_WAITING)
+               wresult = thread_block(mach_wait_until_continue);
 
-       return ((wait_result == THREAD_INTERRUPTED)? KERN_ABORTED: KERN_SUCCESS);
+       return ((wresult == THREAD_INTERRUPTED)? KERN_ABORTED: KERN_SUCCESS);
 }
 
-int64_t
-clock_set_calendar_adjtime(
-       int64_t                                 total,
-       uint32_t                                delta)
+/*
+ * Delay primitives.
+ */
+void
+clock_delay_until(
+       uint64_t                deadline)
 {
-       int64_t                 ototal;
-       spl_t                   s;
+       uint64_t                now = mach_absolute_time();
 
-       s = splclock();
-       simple_lock(&calend_adjlock);
+       if (now >= deadline)
+               return;
 
-       if (calend_adjinterval == 0)
-               clock_interval_to_absolutetime_interval(10000, NSEC_PER_USEC,
-                                                                                                               &calend_adjinterval);
+       if (    (deadline - now) < (8 * sched_cswtime)  ||
+                       get_preemption_level() != 0                             ||
+                       ml_get_interrupts_enabled() == FALSE    )
+               machine_delay_until(deadline);
+       else {
+               assert_wait_deadline((event_t)clock_delay_until, THREAD_UNINT, deadline - sched_cswtime);
 
-       ototal = calend_adjtotal;
+               thread_block(THREAD_CONTINUE_NULL);
+       }
+}
 
-       if (total != 0) {
-               uint64_t                abstime;
+void
+delay_for_interval(
+       uint32_t                interval,
+       uint32_t                scale_factor)
+{
+       uint64_t                end;
 
-               if (total > 0) {
-                       if (delta > total)
-                               delta = total;
-               }
-               else {
-                       if (delta > -total)
-                               delta = -total;
-               }
+       clock_interval_to_deadline(interval, scale_factor, &end);
+
+       clock_delay_until(end);
+}
+
+void
+delay(
+       int             usec)
+{
+       delay_for_interval((usec < 0)? -usec: usec, NSEC_PER_USEC);
+}
+
+void
+clock_adjtime(
+       int32_t         *secs,
+       int32_t         *microsecs)
+{
+       uint32_t        interval;
+       spl_t           s;
 
-               calend_adjtotal = total;
-               calend_adjdelta = delta;
+       s = splclock();
+       simple_lock(&calend_adjlock);
 
-               if (calend_adjdeadline >= calend_adjinterval)
-                       calend_adjdeadline -= calend_adjinterval;
-               clock_get_uptime(&abstime);
-               clock_deadline_for_periodic_event(calend_adjinterval, abstime,
-                                                                                                               &calend_adjdeadline);
+       interval = clock_set_calendar_adjtime(secs, microsecs);
+       if (interval != 0) {
+               if (calend_adjdeadline >= interval)
+                       calend_adjdeadline -= interval;
+               clock_deadline_for_periodic_event(interval, mach_absolute_time(),
+                                                                                               &calend_adjdeadline);
 
                timer_call_enter(&calend_adjcall, calend_adjdeadline);
        }
-       else {
-               calend_adjtotal = 0;
-
+       else
                timer_call_cancel(&calend_adjcall);
-       }
 
        simple_unlock(&calend_adjlock);
        splx(s);
-
-       return (ototal);
 }
 
 static void
-clock_calend_adjust(
-       timer_call_param_t              p0,
-       timer_call_param_t              p1)
+calend_adjust_call(
+       __unused timer_call_param_t             p0,
+       __unused timer_call_param_t             p1)
 {
+       uint32_t        interval;
        spl_t           s;
 
        s = splclock();
        simple_lock(&calend_adjlock);
 
-       if (calend_adjtotal > 0) {
-               clock_adjust_calendar((clock_res_t)calend_adjdelta);
-               calend_adjtotal -= calend_adjdelta;
+       interval = clock_adjust_calendar();
+       if (interval != 0) {
+               clock_deadline_for_periodic_event(interval, mach_absolute_time(),
+                                                                                               &calend_adjdeadline);
 
-               if (calend_adjdelta > calend_adjtotal)
-                       calend_adjdelta = calend_adjtotal;
+               timer_call_enter(&calend_adjcall, calend_adjdeadline);
        }
-       else
-       if (calend_adjtotal < 0) {
-               clock_adjust_calendar(-(clock_res_t)calend_adjdelta);
-               calend_adjtotal += calend_adjdelta;
 
-               if (calend_adjdelta > -calend_adjtotal)
-                       calend_adjdelta = -calend_adjtotal;
-       }
+       simple_unlock(&calend_adjlock);
+       splx(s);
+}
 
-       if (calend_adjtotal != 0) {
-               uint64_t        abstime;
+void
+clock_wakeup_calendar(void)
+{
+       thread_call_enter(&calend_wakecall);
+}
 
-               clock_get_uptime(&abstime);
-               clock_deadline_for_periodic_event(calend_adjinterval, abstime,
-                                                                                                               &calend_adjdeadline);
+extern void            IOKitResetTime(void); /* XXX */
 
-               timer_call_enter(&calend_adjcall, calend_adjdeadline);
-       }
+static void
+calend_dowakeup(
+       __unused thread_call_param_t            p0,
+       __unused thread_call_param_t            p1)
+{
 
-       simple_unlock(&calend_adjlock);
-       splx(s);
+       IOKitResetTime();
 }