-int sysclk_config(void);
-
-int sysclk_init(void);
-
-kern_return_t sysclk_gettime(
- mach_timespec_t *cur_time);
-
-kern_return_t sysclk_getattr(
- clock_flavor_t flavor,
- clock_attr_t attr,
- mach_msg_type_number_t *count);
-
-void sysclk_setalarm(
- mach_timespec_t *alarm_time);
-
-/*
- * Lists of clock routines.
- */
-struct clock_ops sysclk_ops = {
- sysclk_config, sysclk_init,
- sysclk_gettime, 0,
- sysclk_getattr, 0,
- sysclk_setalarm,
-};
-
-int calend_config(void);
-
-int calend_init(void);
-
-kern_return_t calend_gettime(
- mach_timespec_t *cur_time);
-
-kern_return_t calend_getattr(
- clock_flavor_t flavor,
- clock_attr_t attr,
- mach_msg_type_number_t *count);
-
-struct clock_ops calend_ops = {
- calend_config, calend_init,
- calend_gettime, 0,
- calend_getattr, 0,
- 0,
-};
-
-/* local data declarations */
-
-static clock_timer_func_t rtclock_timer_expire;
-
-static timer_call_data_t rtclock_alarm_timer;
-
-static void rtclock_alarm_expire(
- timer_call_param_t p0,
- timer_call_param_t p1);
-
-struct {
- mach_timespec_t calend_offset;
- boolean_t calend_is_set;
-
- int64_t calend_adjtotal;
- int32_t calend_adjdelta;
-
- uint32_t boottime;
-
- mach_timebase_info_data_t timebase_const;
-
- decl_simple_lock_data(,lock) /* real-time clock device lock */
-} rtclock;
-
-boolean_t rtc_initialized = FALSE;
-clock_res_t rtc_intr_nsec = NSEC_PER_HZ; /* interrupt res */
-uint64_t rtc_cycle_count; /* clocks in 1/20th second */
-uint64_t rtc_cyc_per_sec; /* processor cycles per sec */
-uint32_t rtc_boot_frequency; /* provided by 1st speed-step */
-uint32_t rtc_quant_scale; /* clock to nanos multiplier */
-uint32_t rtc_quant_shift; /* clock to nanos right shift */
-uint64_t rtc_decrementer_min;
-
-static mach_timebase_info_data_t rtc_lapic_scale; /* nsec to lapic count */
-
-/*
- * Macros to lock/unlock real-time clock data.
- */
-#define RTC_INTRS_OFF(s) \
- (s) = splclock()
-
-#define RTC_INTRS_ON(s) \
- splx(s)
-
-#define RTC_LOCK(s) \
-MACRO_BEGIN \
- RTC_INTRS_OFF(s); \
- simple_lock(&rtclock.lock); \
-MACRO_END
-
-#define RTC_UNLOCK(s) \
-MACRO_BEGIN \
- simple_unlock(&rtclock.lock); \
- RTC_INTRS_ON(s); \
-MACRO_END
-
-/*
- * i8254 control. ** MONUMENT **
- *
- * The i8254 is a traditional PC device with some arbitrary characteristics.
- * Basically, it is a register that counts at a fixed rate and can be
- * programmed to generate an interrupt every N counts. The count rate is
- * clknum counts per sec (see pit.h), historically 1193167=14.318MHz/12
- * but the more accurate value is 1193182=14.31818MHz/12. [14.31818 MHz being
- * the master crystal oscillator reference frequency since the very first PC.]
- * Various constants are computed based on this value, and we calculate
- * them at init time for execution efficiency. To obtain sufficient
- * accuracy, some of the calculation are most easily done in floating
- * point and then converted to int.
- *
- */
-
-/*
- * Forward decl.
- */
-
-static uint64_t rtc_set_cyc_per_sec(uint64_t cycles);
-uint64_t rtc_nanotime_read(void);
-
-/*
- * create_mul_quant_GHZ
- * create a constant used to multiply the TSC by to convert to nanoseconds.
- * This is a 32 bit number and the TSC *MUST* have a frequency higher than
- * 1000Mhz for this routine to work.
- *
- * The theory here is that we know how many TSCs-per-sec the processor runs at.
- * Normally to convert this to nanoseconds you would multiply the current
- * timestamp by 1000000000 (a billion) then divide by TSCs-per-sec.
- * Unfortunatly the TSC is 64 bits which would leave us with 96 bit intermediate
- * results from the multiply that must be divided by.
- * Usually thats
- * uint96 = tsc * numer
- * nanos = uint96 / denom
- * Instead, we create this quant constant and it becomes the numerator,
- * the denominator can then be 0x100000000 which makes our division as simple as
- * forgetting the lower 32 bits of the result. We can also pass this number to
- * user space as the numer and pass 0xFFFFFFFF (RTC_FAST_DENOM) as the denom to
- * convert raw counts * to nanos. The difference is so small as to be
- * undetectable by anything.
- *
- * Unfortunatly we can not do this for sub GHZ processors. In this case, all
- * we do is pass the CPU speed in raw as the denom and we pass in 1000000000
- * as the numerator. No short cuts allowed
- */
-#define RTC_FAST_DENOM 0xFFFFFFFF
-inline static uint32_t
-create_mul_quant_GHZ(int shift, uint32_t quant)
-{
- return (uint32_t)((((uint64_t)NSEC_PER_SEC/20) << shift) / quant);
-}
-/*
- * This routine takes a value of raw TSC ticks and applies the passed mul_quant
- * generated by create_mul_quant() This is our internal routine for creating
- * nanoseconds.
- * Since we don't really have uint96_t this routine basically does this....
- * uint96_t intermediate = (*value) * scale
- * return (intermediate >> 32)
- */
-inline static uint64_t
-fast_get_nano_from_abs(uint64_t value, int scale)
-{
- asm (" movl %%edx,%%esi \n\t"
- " mull %%ecx \n\t"
- " movl %%edx,%%edi \n\t"
- " movl %%esi,%%eax \n\t"
- " mull %%ecx \n\t"
- " xorl %%ecx,%%ecx \n\t"
- " addl %%edi,%%eax \n\t"
- " adcl %%ecx,%%edx "
- : "+A" (value)
- : "c" (scale)
- : "%esi", "%edi");
- return value;
-}
-
-/*
- * This routine basically does this...
- * ts.tv_sec = nanos / 1000000000; create seconds
- * ts.tv_nsec = nanos % 1000000000; create remainder nanos
- */
-inline static mach_timespec_t
-nanos_to_timespec(uint64_t nanos)
-{
- union {
- mach_timespec_t ts;
- uint64_t u64;
- } ret;
- ret.u64 = nanos;
- asm volatile("divl %1" : "+A" (ret.u64) : "r" (NSEC_PER_SEC));
- return ret.ts;
-}
-
-/*
- * The following two routines perform the 96 bit arithmetic we need to
- * convert generic absolute<->nanoseconds
- * The multiply routine takes a uint64_t and a uint32_t and returns the result
- * in a uint32_t[3] array.
- * The divide routine takes this uint32_t[3] array and divides it by a uint32_t
- * returning a uint64_t
- */
-inline static void
-longmul(uint64_t *abstime, uint32_t multiplicand, uint32_t *result)
-{
- asm volatile(
- " pushl %%ebx \n\t"
- " movl %%eax,%%ebx \n\t"
- " movl (%%eax),%%eax \n\t"
- " mull %%ecx \n\t"
- " xchg %%eax,%%ebx \n\t"
- " pushl %%edx \n\t"
- " movl 4(%%eax),%%eax \n\t"
- " mull %%ecx \n\t"
- " movl %2,%%ecx \n\t"
- " movl %%ebx,(%%ecx) \n\t"
- " popl %%ebx \n\t"
- " addl %%ebx,%%eax \n\t"
- " popl %%ebx \n\t"
- " movl %%eax,4(%%ecx) \n\t"
- " adcl $0,%%edx \n\t"
- " movl %%edx,8(%%ecx) // and save it"
- : : "a"(abstime), "c"(multiplicand), "m"(result));
-
-}
-
-inline static uint64_t
-longdiv(uint32_t *numer, uint32_t denom)
-{
- uint64_t result;
- asm volatile(
- " pushl %%ebx \n\t"
- " movl %%eax,%%ebx \n\t"
- " movl 8(%%eax),%%edx \n\t"
- " movl 4(%%eax),%%eax \n\t"
- " divl %%ecx \n\t"
- " xchg %%ebx,%%eax \n\t"
- " movl (%%eax),%%eax \n\t"
- " divl %%ecx \n\t"
- " xchg %%ebx,%%edx \n\t"
- " popl %%ebx \n\t"
- : "=A"(result) : "a"(numer),"c"(denom));
- return result;
-}
-
-/*
- * Enable or disable timer 2.
- * Port 0x61 controls timer 2:
- * bit 0 gates the clock,
- * bit 1 gates output to speaker.
- */
-inline static void
-enable_PIT2(void)
-{
- asm volatile(
- " inb $0x61,%%al \n\t"
- " and $0xFC,%%al \n\t"
- " or $1,%%al \n\t"
- " outb %%al,$0x61 \n\t"
- : : : "%al" );
-}
-
-inline static void
-disable_PIT2(void)
-{
- asm volatile(
- " inb $0x61,%%al \n\t"
- " and $0xFC,%%al \n\t"
- " outb %%al,$0x61 \n\t"
- : : : "%al" );
-}