1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36#include <platforms.h>
37#include <mach_kdb.h>
38
39#include <mach/mach_types.h>
40
41#include <kern/cpu_data.h>
42#include <kern/cpu_number.h>
43#include <kern/clock.h>
44#include <kern/host_notify.h>
45#include <kern/macro_help.h>
46#include <kern/misc_protos.h>
47#include <kern/spl.h>
48#include <kern/assert.h>
49#include <mach/vm_prot.h>
50#include <vm/pmap.h>
51#include <vm/vm_kern.h>
52#include <i386/ipl.h>
53#include <i386/pit.h>
54#include <i386/pio.h>
55#include <i386/misc_protos.h>
56#include <i386/proc_reg.h>
57#include <i386/machine_cpu.h>
58#include <i386/mp.h>
59#include <i386/cpuid.h>
60#include <i386/cpu_data.h>
61#include <i386/cpu_threads.h>
62#include <i386/perfmon.h>
63#include <i386/machine_routines.h>
64#include <i386/AT386/bbclock_entries.h>
65#include <pexpert/pexpert.h>
66#include <machine/limits.h>
67#include <machine/commpage.h>
68#include <sys/kdebug.h>
69
70#define MAX(a,b) (((a)>(b))?(a):(b))
71#define MIN(a,b) (((a)>(b))?(b):(a))
72
73#define NSEC_PER_HZ (NSEC_PER_SEC / 100)
74
75#define UI_CPUFREQ_ROUNDING_FACTOR 10000000
76
77int sysclk_config(void);
78
79int sysclk_init(void);
80
81kern_return_t sysclk_gettime(
82 mach_timespec_t *cur_time);
83
84kern_return_t sysclk_getattr(
85 clock_flavor_t flavor,
86 clock_attr_t attr,
87 mach_msg_type_number_t *count);
88
89void sysclk_setalarm(
90 mach_timespec_t *alarm_time);
91
92
93
94
95struct clock_ops sysclk_ops = {
96 sysclk_config, sysclk_init,
97 sysclk_gettime, 0,
98 sysclk_getattr, 0,
99 sysclk_setalarm,
100};
101
102int calend_config(void);
103
104int calend_init(void);
105
106kern_return_t calend_gettime(
107 mach_timespec_t *cur_time);
108
109kern_return_t calend_getattr(
110 clock_flavor_t flavor,
111 clock_attr_t attr,
112 mach_msg_type_number_t *count);
113
114struct clock_ops calend_ops = {
115 calend_config, calend_init,
116 calend_gettime, 0,
117 calend_getattr, 0,
118 0,
119};
120
121
122
123static clock_timer_func_t rtclock_timer_expire;
124
125static timer_call_data_t rtclock_alarm_timer;
126
127static void rtclock_alarm_expire(
128 timer_call_param_t p0,
129 timer_call_param_t p1);
130
131struct {
132 mach_timespec_t calend_offset;
133 boolean_t calend_is_set;
134
135 int64_t calend_adjtotal;
136 int32_t calend_adjdelta;
137
138 uint32_t boottime;
139
140 mach_timebase_info_data_t timebase_const;
141
142 decl_simple_lock_data(,lock)
143} rtclock;
144
145boolean_t rtc_initialized = FALSE;
146clock_res_t rtc_intr_nsec = NSEC_PER_HZ;
147uint64_t rtc_cycle_count;
148uint64_t rtc_cyc_per_sec;
149uint32_t rtc_boot_frequency;
150uint32_t rtc_quant_scale;
151uint32_t rtc_quant_shift;
152uint64_t rtc_decrementer_min;
153
154static mach_timebase_info_data_t rtc_lapic_scale;
155
156
157
158
159#define RTC_INTRS_OFF(s) \
160 (s) = splclock()
161
162#define RTC_INTRS_ON(s) \
163 splx(s)
164
165#define RTC_LOCK(s) \
166MACRO_BEGIN \
167 RTC_INTRS_OFF(s); \
168 simple_lock(&rtclock.lock); \
169MACRO_END
170
171#define RTC_UNLOCK(s) \
172MACRO_BEGIN \
173 simple_unlock(&rtclock.lock); \
174 RTC_INTRS_ON(s); \
175MACRO_END
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197static uint64_t rtc_set_cyc_per_sec(uint64_t cycles);
198uint64_t rtc_nanotime_read(void);
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225#define RTC_FAST_DENOM 0xFFFFFFFF
226inline static uint32_t
227create_mul_quant_GHZ(int shift, uint32_t quant)
228{
229 return (uint32_t)((((uint64_t)NSEC_PER_SEC/20) << shift) / quant);
230}
231
232
233
234
235
236
237
238
239inline static uint64_t
240fast_get_nano_from_abs(uint64_t value, int scale)
241{
242 asm (" movl %%edx,%%esi \n\t"
243 " mull %%ecx \n\t"
244 " movl %%edx,%%edi \n\t"
245 " movl %%esi,%%eax \n\t"
246 " mull %%ecx \n\t"
247 " xorl %%ecx,%%ecx \n\t"
248 " addl %%edi,%%eax \n\t"
249 " adcl %%ecx,%%edx "
250 : "+A" (value)
251 : "c" (scale)
252 : "%esi", "%edi");
253 return value;
254}
255
256
257
258
259
260
261inline static mach_timespec_t
262nanos_to_timespec(uint64_t nanos)
263{
264 union {
265 mach_timespec_t ts;
266 uint64_t u64;
267 } ret;
268 ret.u64 = nanos;
269 asm volatile("divl %1" : "+A" (ret.u64) : "r" (NSEC_PER_SEC));
270 return ret.ts;
271}
272
273
274
275
276
277
278
279
280
281inline static void
282longmul(uint64_t *abstime, uint32_t multiplicand, uint32_t *result)
283{
284 asm volatile(
285 " pushl %%ebx \n\t"
286 " movl %%eax,%%ebx \n\t"
287 " movl (%%eax),%%eax \n\t"
288 " mull %%ecx \n\t"
289 " xchg %%eax,%%ebx \n\t"
290 " pushl %%edx \n\t"
291 " movl 4(%%eax),%%eax \n\t"
292 " mull %%ecx \n\t"
293 " movl %2,%%ecx \n\t"
294 " movl %%ebx,(%%ecx) \n\t"
295 " popl %%ebx \n\t"
296 " addl %%ebx,%%eax \n\t"
297 " popl %%ebx \n\t"
298 " movl %%eax,4(%%ecx) \n\t"
299 " adcl $0,%%edx \n\t"
300 " movl %%edx,8(%%ecx) // and save it"
301 : : "a"(abstime), "c"(multiplicand), "m"(result));
302
303}
304
305inline static uint64_t
306longdiv(uint32_t *numer, uint32_t denom)
307{
308 uint64_t result;
309 asm volatile(
310 " pushl %%ebx \n\t"
311 " movl %%eax,%%ebx \n\t"
312 " movl 8(%%eax),%%edx \n\t"
313 " movl 4(%%eax),%%eax \n\t"
314 " divl %%ecx \n\t"
315 " xchg %%ebx,%%eax \n\t"
316 " movl (%%eax),%%eax \n\t"
317 " divl %%ecx \n\t"
318 " xchg %%ebx,%%edx \n\t"
319 " popl %%ebx \n\t"
320 : "=A"(result) : "a"(numer),"c"(denom));
321 return result;
322}
323
324
325
326
327
328
329
330inline static void
331enable_PIT2(void)
332{
333 asm volatile(
334 " inb $0x61,%%al \n\t"
335 " and $0xFC,%%al \n\t"
336 " or $1,%%al \n\t"
337 " outb %%al,$0x61 \n\t"
338 : : : "%al" );
339}
340
341inline static void
342disable_PIT2(void)
343{
344 asm volatile(
345 " inb $0x61,%%al \n\t"
346 " and $0xFC,%%al \n\t"
347 " outb %%al,$0x61 \n\t"
348 : : : "%al" );
349}
350
351inline static void
352set_PIT2(int value)
353{
354
355
356
357
358
359
360
361 asm volatile(
362 " movb $0xB8,%%al \n\t"
363 " outb %%al,$0x43 \n\t"
364 " movb %%dl,%%al \n\t"
365 " outb %%al,$0x42 \n\t"
366 " movb %%dh,%%al \n\t"
367 " outb %%al,$0x42 \n"
368"1: inb $0x42,%%al \n\t"
369 " inb $0x42,%%al \n\t"
370 " cmp %%al,%%dh \n\t"
371 " jne 1b"
372 : : "d"(value) : "%al");
373}
374
375inline static uint64_t
376get_PIT2(unsigned int *value)
377{
378 register uint64_t result;
379
380
381
382
383
384 asm volatile(
385 " xorl %%ecx,%%ecx \n\t"
386 " movb $0x80,%%al \n\t"
387 " outb %%al,$0x43 \n\t"
388 " rdtsc \n\t"
389 " pushl %%eax \n\t"
390 " inb $0x42,%%al \n\t"
391 " movb %%al,%%cl \n\t"
392 " inb $0x42,%%al \n\t"
393 " movb %%al,%%ch \n\t"
394 " popl %%eax "
395 : "=A"(result), "=c"(*value));
396 return result;
397}
398
399
400
401
402
403
404
405static uint64_t
406timeRDTSC(void)
407{
408 int attempts = 0;
409 uint64_t latchTime;
410 uint64_t saveTime,intermediate;
411 unsigned int timerValue, lastValue;
412 boolean_t int_enabled;
413
414
415
416
417
418#define SAMPLE_CLKS_EXACT (((double) CLKNUM) / 20.0)
419#define SAMPLE_CLKS_INT ((int) CLKNUM / 20)
420#define SAMPLE_NSECS (2000000000LL)
421#define SAMPLE_MULTIPLIER (((double)SAMPLE_NSECS)*SAMPLE_CLKS_EXACT)
422#define ROUND64(x) ((uint64_t)((x) + 0.5))
423 uint64_t scale[6] = {
424 ROUND64(SAMPLE_MULTIPLIER/(double)(SAMPLE_CLKS_INT-0)),
425 ROUND64(SAMPLE_MULTIPLIER/(double)(SAMPLE_CLKS_INT-1)),
426 ROUND64(SAMPLE_MULTIPLIER/(double)(SAMPLE_CLKS_INT-2)),
427 ROUND64(SAMPLE_MULTIPLIER/(double)(SAMPLE_CLKS_INT-3)),
428 ROUND64(SAMPLE_MULTIPLIER/(double)(SAMPLE_CLKS_INT-4)),
429 ROUND64(SAMPLE_MULTIPLIER/(double)(SAMPLE_CLKS_INT-5))
430 };
431
432 int_enabled = ml_set_interrupts_enabled(FALSE);
433
434restart:
435 if (attempts >= 2)
436 panic("timeRDTSC() calibation failed with %d attempts\n", attempts);
437 attempts++;
438 enable_PIT2();
439 set_PIT2(0);
440 latchTime = rdtsc64();
441 latchTime = get_PIT2(&timerValue) - latchTime;
442 set_PIT2(SAMPLE_CLKS_INT);
443 saveTime = rdtsc64();
444 get_PIT2(&lastValue);
445 get_PIT2(&lastValue);
446 do {
447 intermediate = get_PIT2(&timerValue);
448 if (timerValue > lastValue) {
449 printf("Hey we are going backwards! %u -> %u, restarting timing\n",
450 timerValue,lastValue);
451 set_PIT2(0);
452 disable_PIT2();
453 goto restart;
454 }
455 lastValue = timerValue;
456 } while (timerValue > 5);
457 kprintf("timerValue %d\n",timerValue);
458 kprintf("intermediate 0x%016llx\n",intermediate);
459 kprintf("saveTime 0x%016llx\n",saveTime);
460
461 intermediate -= saveTime;
462 intermediate *= scale[timerValue];
463 intermediate /= SAMPLE_NSECS;
464 intermediate += latchTime;
465
466 set_PIT2(0);
467 disable_PIT2();
468
469 ml_set_interrupts_enabled(int_enabled);
470 return intermediate;
471}
472
473static uint64_t
474tsc_to_nanoseconds(uint64_t abstime)
475{
476 uint32_t numer;
477 uint32_t denom;
478 uint32_t intermediate[3];
479
480 numer = rtclock.timebase_const.numer;
481 denom = rtclock.timebase_const.denom;
482 if (denom == RTC_FAST_DENOM) {
483 abstime = fast_get_nano_from_abs(abstime, numer);
484 } else {
485 longmul(&abstime, numer, intermediate);
486 abstime = longdiv(intermediate, denom);
487 }
488 return abstime;
489}
490
491inline static mach_timespec_t
492tsc_to_timespec(void)
493{
494 uint64_t currNanos;
495 currNanos = rtc_nanotime_read();
496 return nanos_to_timespec(currNanos);
497}
498
499#define DECREMENTER_MAX UINT_MAX
500static uint32_t
501deadline_to_decrementer(
502 uint64_t deadline,
503 uint64_t now)
504{
505 uint64_t delta;
506
507 if (deadline <= now)
508 return rtc_decrementer_min;
509 else {
510 delta = deadline - now;
511 return MIN(MAX(rtc_decrementer_min,delta),DECREMENTER_MAX);
512 }
513}
514
515static inline uint64_t
516lapic_time_countdown(uint32_t initial_count)
517{
518 boolean_t state;
519 uint64_t start_time;
520 uint64_t stop_time;
521 lapic_timer_count_t count;
522
523 state = ml_set_interrupts_enabled(FALSE);
524 lapic_set_timer(FALSE, one_shot, divide_by_1, initial_count);
525 start_time = rdtsc64();
526 do {
527 lapic_get_timer(NULL, NULL, NULL, &count);
528 } while (count > 0);
529 stop_time = rdtsc64();
530 ml_set_interrupts_enabled(state);
531
532 return tsc_to_nanoseconds(stop_time - start_time);
533}
534
535static void
536rtc_lapic_timer_calibrate(void)
537{
538 uint32_t nsecs;
539 uint64_t countdown;
540
541 if (!(cpuid_features() & CPUID_FEATURE_APIC))
542 return;
543
544
545
546
547
548 nsecs = (uint32_t) lapic_time_countdown(rtc_intr_nsec);
549
550
551
552
553
554 countdown = (uint64_t)rtc_intr_nsec * (uint64_t)rtc_intr_nsec / nsecs;
555
556 nsecs = (uint32_t) lapic_time_countdown((uint32_t) countdown);
557
558 rtc_lapic_scale.numer = countdown;
559 rtc_lapic_scale.denom = nsecs;
560
561 kprintf("rtc_lapic_timer_calibrate() scale: %d/%d\n",
562 (uint32_t) countdown, nsecs);
563}
564
565static void
566rtc_lapic_set_timer(
567 uint32_t interval)
568{
569 uint64_t count;
570
571 assert(rtc_lapic_scale.denom);
572
573 count = interval * (uint64_t) rtc_lapic_scale.numer;
574 count /= rtc_lapic_scale.denom;
575
576 lapic_set_timer(TRUE, one_shot, divide_by_1, (uint32_t) count);
577}
578
579static void
580rtc_lapic_start_ticking(void)
581{
582 uint64_t abstime;
583 uint64_t first_tick;
584 uint64_t decr;
585
586 abstime = mach_absolute_time();
587 first_tick = abstime + NSEC_PER_HZ;
588 current_cpu_datap()->cpu_rtc_tick_deadline = first_tick;
589 decr = deadline_to_decrementer(first_tick, abstime);
590 rtc_lapic_set_timer(decr);
591}
592
593
594
595
596
597
598int
599sysclk_config(void)
600{
601
602 mp_disable_preemption();
603 if (cpu_number() != master_cpu) {
604 mp_enable_preemption();
605 return(1);
606 }
607 mp_enable_preemption();
608
609 timer_call_setup(&rtclock_alarm_timer, rtclock_alarm_expire, NULL);
610
611 simple_lock_init(&rtclock.lock, 0);
612
613 return (1);
614}
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652static inline void
653rtc_nanotime_set_commpage(rtc_nanotime_t *rntp)
654{
655 commpage_nanotime_t cp_nanotime;
656
657
658 if (cpu_number() != master_cpu)
659 return;
660
661 cp_nanotime.nt_base_tsc = rntp->rnt_tsc;
662 cp_nanotime.nt_base_ns = rntp->rnt_nanos;
663 cp_nanotime.nt_scale = rntp->rnt_scale;
664 cp_nanotime.nt_shift = rntp->rnt_shift;
665
666 commpage_set_nanotime(&cp_nanotime);
667}
668
669static void
670rtc_nanotime_init(void)
671{
672 rtc_nanotime_t *rntp = ¤t_cpu_datap()->cpu_rtc_nanotime;
673 rtc_nanotime_t *master_rntp = &cpu_datap(master_cpu)->cpu_rtc_nanotime;
674
675 if (cpu_number() == master_cpu) {
676 rntp->rnt_tsc = rdtsc64();
677 rntp->rnt_nanos = tsc_to_nanoseconds(rntp->rnt_tsc);
678 rntp->rnt_scale = rtc_quant_scale;
679 rntp->rnt_shift = rtc_quant_shift;
680 rntp->rnt_step_tsc = 0ULL;
681 rntp->rnt_step_nanos = 0ULL;
682 } else {
683
684
685
686
687 do {
688 *rntp = *master_rntp;
689 } while (rntp->rnt_tsc != master_rntp->rnt_tsc);
690 }
691}
692
693static inline void
694_rtc_nanotime_update(rtc_nanotime_t *rntp, uint64_t tsc)
695{
696 uint64_t tsc_delta;
697 uint64_t ns_delta;
698
699 tsc_delta = tsc - rntp->rnt_step_tsc;
700 ns_delta = tsc_to_nanoseconds(tsc_delta);
701 rntp->rnt_nanos = rntp->rnt_step_nanos + ns_delta;
702 rntp->rnt_tsc = tsc;
703}
704
705static void
706rtc_nanotime_update(void)
707{
708 rtc_nanotime_t *rntp = ¤t_cpu_datap()->cpu_rtc_nanotime;
709
710 assert(get_preemption_level() > 0);
711 assert(!ml_get_interrupts_enabled());
712
713 _rtc_nanotime_update(rntp, rdtsc64());
714 rtc_nanotime_set_commpage(rntp);
715}
716
717static void
718rtc_nanotime_scale_update(void)
719{
720 rtc_nanotime_t *rntp = ¤t_cpu_datap()->cpu_rtc_nanotime;
721 uint64_t tsc = rdtsc64();
722
723 assert(!ml_get_interrupts_enabled());
724
725
726
727
728 _rtc_nanotime_update(rntp, tsc);
729
730
731
732
733 rntp->rnt_scale = rtc_quant_scale;
734 rntp->rnt_shift = rtc_quant_shift;
735 rntp->rnt_step_tsc = rntp->rnt_tsc;
736 rntp->rnt_step_nanos = rntp->rnt_nanos;
737
738
739 rtc_nanotime_set_commpage(rntp);
740}
741
742static uint64_t
743_rtc_nanotime_read(void)
744{
745 rtc_nanotime_t *rntp = ¤t_cpu_datap()->cpu_rtc_nanotime;
746 uint64_t rnt_tsc;
747 uint32_t rnt_scale;
748 uint32_t rnt_shift;
749 uint64_t rnt_nanos;
750 uint64_t tsc;
751 uint64_t tsc_delta;
752
753 rnt_scale = rntp->rnt_scale;
754 if (rnt_scale == 0)
755 return 0ULL;
756
757 rnt_shift = rntp->rnt_shift;
758 rnt_nanos = rntp->rnt_nanos;
759 rnt_tsc = rntp->rnt_tsc;
760 tsc = rdtsc64();
761
762 tsc_delta = tsc - rnt_tsc;
763 if ((tsc_delta >> 32) != 0)
764 return rnt_nanos + tsc_to_nanoseconds(tsc_delta);
765
766
767 if (rnt_shift == 32)
768 return rnt_nanos + ((tsc_delta * rnt_scale) >> 32);
769 else
770 return rnt_nanos + ((tsc_delta * rnt_scale) >> rnt_shift);
771}
772
773uint64_t
774rtc_nanotime_read(void)
775{
776 uint64_t result;
777 uint64_t rnt_tsc;
778 rtc_nanotime_t *rntp = ¤t_cpu_datap()->cpu_rtc_nanotime;
779
780
781
782
783
784
785 do {
786 rnt_tsc = rntp->rnt_tsc;
787 result = _rtc_nanotime_read();
788 } while (rnt_tsc != rntp->rnt_tsc);
789
790 return result;
791}
792
793
794
795
796
797
798
799
800
801
802void
803rtc_clock_stepping(__unused uint32_t new_frequency,
804 __unused uint32_t old_frequency)
805{
806 boolean_t istate;
807
808 istate = ml_set_interrupts_enabled(FALSE);
809 rtc_nanotime_scale_update();
810 ml_set_interrupts_enabled(istate);
811}
812
813
814
815
816
817
818void
819rtc_clock_stepped(uint32_t new_frequency, uint32_t old_frequency)
820{
821 boolean_t istate;
822
823 istate = ml_set_interrupts_enabled(FALSE);
824 if (rtc_boot_frequency == 0) {
825
826
827
828
829
830
831
832 rtc_boot_frequency = old_frequency;
833 }
834 rtc_set_cyc_per_sec(rtc_cycle_count * new_frequency /
835 rtc_boot_frequency);
836 rtc_nanotime_scale_update();
837 ml_set_interrupts_enabled(istate);
838}
839
840
841
842
843void
844rtc_sleep_wakeup(void)
845{
846 rtc_nanotime_t *rntp = ¤t_cpu_datap()->cpu_rtc_nanotime;
847
848 boolean_t istate;
849
850 istate = ml_set_interrupts_enabled(FALSE);
851
852
853
854
855
856
857
858 rntp->rnt_tsc = rdtsc64();
859 rntp->rnt_step_tsc = 0ULL;
860 rntp->rnt_step_nanos = rntp->rnt_nanos;
861 rtc_nanotime_set_commpage(rntp);
862
863
864 rtc_lapic_start_ticking();
865
866 ml_set_interrupts_enabled(istate);
867}
868
869
870
871
872
873int
874sysclk_init(void)
875{
876 uint64_t cycles;
877
878 mp_disable_preemption();
879 if (cpu_number() == master_cpu) {
880
881
882
883
884
885 rtc_cycle_count = timeRDTSC();
886 cycles = rtc_set_cyc_per_sec(rtc_cycle_count);
887
888
889
890
891
892 gPEClockFrequencyInfo.cpu_frequency_min_hz = cycles;
893 gPEClockFrequencyInfo.cpu_frequency_max_hz = cycles;
894 printf("[RTCLOCK] frequency %llu (%llu)\n",
895 cycles, rtc_cyc_per_sec);
896
897 rtc_lapic_timer_calibrate();
898
899
900 rtc_decrementer_min = deadline_to_decrementer(NSEC_PER_USEC,
901 0ULL);
902
903 lapic_set_timer_func((i386_intr_func_t) rtclock_intr);
904
905 clock_timebase_init();
906 rtc_initialized = TRUE;
907 }
908
909 rtc_nanotime_init();
910
911 rtc_lapic_start_ticking();
912
913 mp_enable_preemption();
914
915 return (1);
916}
917
918
919
920
921
922
923static kern_return_t
924sysclk_gettime_internal(
925 mach_timespec_t *cur_time)
926{
927 *cur_time = tsc_to_timespec();
928 return (KERN_SUCCESS);
929}
930
931kern_return_t
932sysclk_gettime(
933 mach_timespec_t *cur_time)
934{
935 return sysclk_gettime_internal(cur_time);
936}
937
938void
939sysclk_gettime_interrupts_disabled(
940 mach_timespec_t *cur_time)
941{
942 (void) sysclk_gettime_internal(cur_time);
943}
944
945
946
947
948static uint64_t
949rtc_set_cyc_per_sec(uint64_t cycles)
950{
951
952 if (cycles > (NSEC_PER_SEC/20)) {
953
954 rtc_quant_shift = 32;
955 rtc_quant_scale = create_mul_quant_GHZ(rtc_quant_shift, cycles);
956 rtclock.timebase_const.numer = rtc_quant_scale;
957 rtclock.timebase_const.denom = RTC_FAST_DENOM;
958 } else {
959 rtc_quant_shift = 26;
960 rtc_quant_scale = create_mul_quant_GHZ(rtc_quant_shift, cycles);
961 rtclock.timebase_const.numer = NSEC_PER_SEC/20;
962 rtclock.timebase_const.denom = cycles;
963 }
964 rtc_cyc_per_sec = cycles*20;
965
966
967 cycles = ((rtc_cyc_per_sec + (UI_CPUFREQ_ROUNDING_FACTOR/2))
968 / UI_CPUFREQ_ROUNDING_FACTOR)
969 * UI_CPUFREQ_ROUNDING_FACTOR;
970
971
972
973
974 if (cycles >= 0x100000000ULL) {
975 gPEClockFrequencyInfo.cpu_clock_rate_hz = 0xFFFFFFFFUL;
976 } else {
977 gPEClockFrequencyInfo.cpu_clock_rate_hz = (unsigned long)cycles;
978 }
979 gPEClockFrequencyInfo.cpu_frequency_hz = cycles;
980
981 kprintf("[RTCLOCK] frequency %llu (%llu)\n", cycles, rtc_cyc_per_sec);
982 return(cycles);
983}
984
985void
986clock_get_system_microtime(
987 uint32_t *secs,
988 uint32_t *microsecs)
989{
990 mach_timespec_t now;
991
992 (void) sysclk_gettime_internal(&now);
993
994 *secs = now.tv_sec;
995 *microsecs = now.tv_nsec / NSEC_PER_USEC;
996}
997
998void
999clock_get_system_nanotime(
1000 uint32_t *secs,
1001 uint32_t *nanosecs)
1002{
1003 mach_timespec_t now;
1004
1005 (void) sysclk_gettime_internal(&now);
1006
1007 *secs = now.tv_sec;
1008 *nanosecs = now.tv_nsec;
1009}
1010
1011
1012
1013
1014kern_return_t
1015sysclk_getattr(
1016 clock_flavor_t flavor,
1017 clock_attr_t attr,
1018 mach_msg_type_number_t *count)
1019{
1020 if (*count != 1)
1021 return (KERN_FAILURE);
1022 switch (flavor) {
1023
1024 case CLOCK_GET_TIME_RES:
1025 *(clock_res_t *) attr = rtc_intr_nsec;
1026 break;
1027
1028 case CLOCK_ALARM_CURRES:
1029 case CLOCK_ALARM_MAXRES:
1030 case CLOCK_ALARM_MINRES:
1031 *(clock_res_t *) attr = 0;
1032 break;
1033
1034 default:
1035 return (KERN_INVALID_VALUE);
1036 }
1037 return (KERN_SUCCESS);
1038}
1039
1040
1041
1042
1043
1044
1045void
1046sysclk_setalarm(
1047 mach_timespec_t *alarm_time)
1048{
1049 timer_call_enter(&rtclock_alarm_timer,
1050 (uint64_t) alarm_time->tv_sec * NSEC_PER_SEC
1051 + alarm_time->tv_nsec);
1052}
1053
1054
1055
1056
1057int
1058calend_config(void)
1059{
1060 return bbc_config();
1061}
1062
1063
1064
1065
1066int
1067calend_init(void)
1068{
1069 return (1);
1070}
1071
1072
1073
1074
1075kern_return_t
1076calend_gettime(
1077 mach_timespec_t *cur_time)
1078{
1079 spl_t s;
1080
1081 RTC_LOCK(s);
1082 if (!rtclock.calend_is_set) {
1083 RTC_UNLOCK(s);
1084 return (KERN_FAILURE);
1085 }
1086
1087 (void) sysclk_gettime_internal(cur_time);
1088 ADD_MACH_TIMESPEC(cur_time, &rtclock.calend_offset);
1089 RTC_UNLOCK(s);
1090
1091 return (KERN_SUCCESS);
1092}
1093
1094void
1095clock_get_calendar_microtime(
1096 uint32_t *secs,
1097 uint32_t *microsecs)
1098{
1099 mach_timespec_t now;
1100
1101 calend_gettime(&now);
1102
1103 *secs = now.tv_sec;
1104 *microsecs = now.tv_nsec / NSEC_PER_USEC;
1105}
1106
1107void
1108clock_get_calendar_nanotime(
1109 uint32_t *secs,
1110 uint32_t *nanosecs)
1111{
1112 mach_timespec_t now;
1113
1114 calend_gettime(&now);
1115
1116 *secs = now.tv_sec;
1117 *nanosecs = now.tv_nsec;
1118}
1119
1120void
1121clock_set_calendar_microtime(
1122 uint32_t secs,
1123 uint32_t microsecs)
1124{
1125 mach_timespec_t new_time, curr_time;
1126 uint32_t old_offset;
1127 spl_t s;
1128
1129 new_time.tv_sec = secs;
1130 new_time.tv_nsec = microsecs * NSEC_PER_USEC;
1131
1132 RTC_LOCK(s);
1133 old_offset = rtclock.calend_offset.tv_sec;
1134 (void) sysclk_gettime_internal(&curr_time);
1135 rtclock.calend_offset = new_time;
1136 SUB_MACH_TIMESPEC(&rtclock.calend_offset, &curr_time);
1137 rtclock.boottime += rtclock.calend_offset.tv_sec - old_offset;
1138 rtclock.calend_is_set = TRUE;
1139 RTC_UNLOCK(s);
1140
1141 (void) bbc_settime(&new_time);
1142
1143 host_notify_calendar_change();
1144}
1145
1146
1147
1148
1149kern_return_t
1150calend_getattr(
1151 clock_flavor_t flavor,
1152 clock_attr_t attr,
1153 mach_msg_type_number_t *count)
1154{
1155 if (*count != 1)
1156 return (KERN_FAILURE);
1157 switch (flavor) {
1158
1159 case CLOCK_GET_TIME_RES:
1160 *(clock_res_t *) attr = rtc_intr_nsec;
1161 break;
1162
1163 case CLOCK_ALARM_CURRES:
1164 case CLOCK_ALARM_MINRES:
1165 case CLOCK_ALARM_MAXRES:
1166 *(clock_res_t *) attr = 0;
1167 break;
1168
1169 default:
1170 return (KERN_INVALID_VALUE);
1171 }
1172 return (KERN_SUCCESS);
1173}
1174
1175#define tickadj (40*NSEC_PER_USEC)
1176#define bigadj (NSEC_PER_SEC)
1177
1178uint32_t
1179clock_set_calendar_adjtime(
1180 int32_t *secs,
1181 int32_t *microsecs)
1182{
1183 int64_t total, ototal;
1184 uint32_t interval = 0;
1185 spl_t s;
1186
1187 total = (int64_t)*secs * NSEC_PER_SEC + *microsecs * NSEC_PER_USEC;
1188
1189 RTC_LOCK(s);
1190 ototal = rtclock.calend_adjtotal;
1191
1192 if (total != 0) {
1193 int32_t delta = tickadj;
1194
1195 if (total > 0) {
1196 if (total > bigadj)
1197 delta *= 10;
1198 if (delta > total)
1199 delta = total;
1200 }
1201 else {
1202 if (total < -bigadj)
1203 delta *= 10;
1204 delta = -delta;
1205 if (delta < total)
1206 delta = total;
1207 }
1208
1209 rtclock.calend_adjtotal = total;
1210 rtclock.calend_adjdelta = delta;
1211
1212 interval = NSEC_PER_HZ;
1213 }
1214 else
1215 rtclock.calend_adjdelta = rtclock.calend_adjtotal = 0;
1216
1217 RTC_UNLOCK(s);
1218
1219 if (ototal == 0)
1220 *secs = *microsecs = 0;
1221 else {
1222 *secs = ototal / NSEC_PER_SEC;
1223 *microsecs = ototal % NSEC_PER_SEC;
1224 }
1225
1226 return (interval);
1227}
1228
1229uint32_t
1230clock_adjust_calendar(void)
1231{
1232 uint32_t interval = 0;
1233 int32_t delta;
1234 spl_t s;
1235
1236 RTC_LOCK(s);
1237 delta = rtclock.calend_adjdelta;
1238 ADD_MACH_TIMESPEC_NSEC(&rtclock.calend_offset, delta);
1239
1240 rtclock.calend_adjtotal -= delta;
1241
1242 if (delta > 0) {
1243 if (delta > rtclock.calend_adjtotal)
1244 rtclock.calend_adjdelta = rtclock.calend_adjtotal;
1245 }
1246 else
1247 if (delta < 0) {
1248 if (delta < rtclock.calend_adjtotal)
1249 rtclock.calend_adjdelta = rtclock.calend_adjtotal;
1250 }
1251
1252 if (rtclock.calend_adjdelta != 0)
1253 interval = NSEC_PER_HZ;
1254
1255 RTC_UNLOCK(s);
1256
1257 return (interval);
1258}
1259
1260void
1261clock_initialize_calendar(void)
1262{
1263 mach_timespec_t bbc_time, curr_time;
1264 spl_t s;
1265
1266 if (bbc_gettime(&bbc_time) != KERN_SUCCESS)
1267 return;
1268
1269 RTC_LOCK(s);
1270 if (rtclock.boottime == 0)
1271 rtclock.boottime = bbc_time.tv_sec;
1272 (void) sysclk_gettime_internal(&curr_time);
1273 rtclock.calend_offset = bbc_time;
1274 SUB_MACH_TIMESPEC(&rtclock.calend_offset, &curr_time);
1275 rtclock.calend_is_set = TRUE;
1276 RTC_UNLOCK(s);
1277
1278 host_notify_calendar_change();
1279}
1280
1281void
1282clock_get_boottime_nanotime(
1283 uint32_t *secs,
1284 uint32_t *nanosecs)
1285{
1286 *secs = rtclock.boottime;
1287 *nanosecs = 0;
1288}
1289
1290void
1291clock_timebase_info(
1292 mach_timebase_info_t info)
1293{
1294 info->numer = info->denom = 1;
1295}
1296
1297void
1298clock_set_timer_deadline(
1299 uint64_t deadline)
1300{
1301 spl_t s;
1302 cpu_data_t *pp = current_cpu_datap();
1303 rtclock_timer_t *mytimer = &pp->cpu_rtc_timer;
1304 uint64_t abstime;
1305 uint64_t decr;
1306
1307 assert(get_preemption_level() > 0);
1308 assert(rtclock_timer_expire);
1309
1310 RTC_INTRS_OFF(s);
1311 mytimer->deadline = deadline;
1312 mytimer->is_set = TRUE;
1313 if (!mytimer->has_expired) {
1314 abstime = mach_absolute_time();
1315 if (mytimer->deadline < pp->cpu_rtc_tick_deadline) {
1316 decr = deadline_to_decrementer(mytimer->deadline,
1317 abstime);
1318 rtc_lapic_set_timer(decr);
1319 pp->cpu_rtc_intr_deadline = mytimer->deadline;
1320 KERNEL_DEBUG_CONSTANT(
1321 MACHDBG_CODE(DBG_MACH_EXCP_DECI, 1) |
1322 DBG_FUNC_NONE, decr, 2, 0, 0, 0);
1323 }
1324 }
1325 RTC_INTRS_ON(s);
1326}
1327
1328void
1329clock_set_timer_func(
1330 clock_timer_func_t func)
1331{
1332 if (rtclock_timer_expire == NULL)
1333 rtclock_timer_expire = func;
1334}
1335
1336
1337
1338
1339void
1340rtclock_intr(struct i386_interrupt_state *regs)
1341{
1342 uint64_t abstime;
1343 uint32_t latency;
1344 uint64_t decr;
1345 uint64_t decr_tick;
1346 uint64_t decr_timer;
1347 cpu_data_t *pp = current_cpu_datap();
1348 rtclock_timer_t *mytimer = &pp->cpu_rtc_timer;
1349
1350 assert(get_preemption_level() > 0);
1351 assert(!ml_get_interrupts_enabled());
1352
1353 abstime = _rtc_nanotime_read();
1354 latency = (uint32_t) abstime - pp->cpu_rtc_intr_deadline;
1355 if (pp->cpu_rtc_tick_deadline <= abstime) {
1356 rtc_nanotime_update();
1357 clock_deadline_for_periodic_event(
1358 NSEC_PER_HZ, abstime, &pp->cpu_rtc_tick_deadline);
1359 hertz_tick(
1360#if STAT_TIME
1361 NSEC_PER_HZ,
1362#endif
1363 (regs->efl & EFL_VM) || ((regs->cs & 0x03) != 0),
1364 regs->eip);
1365 }
1366
1367 abstime = _rtc_nanotime_read();
1368 if (mytimer->is_set && mytimer->deadline <= abstime) {
1369 mytimer->has_expired = TRUE;
1370 mytimer->is_set = FALSE;
1371 (*rtclock_timer_expire)(abstime);
1372 assert(!ml_get_interrupts_enabled());
1373 mytimer->has_expired = FALSE;
1374 }
1375
1376
1377 KERNEL_DEBUG_CONSTANT(
1378 MACHDBG_CODE(DBG_MACH_EXCP_DECI, 0) | DBG_FUNC_NONE,
1379 -latency, (uint32_t)regs->eip, 0, 0, 0);
1380
1381 abstime = _rtc_nanotime_read();
1382 decr_tick = deadline_to_decrementer(pp->cpu_rtc_tick_deadline, abstime);
1383 decr_timer = (mytimer->is_set) ?
1384 deadline_to_decrementer(mytimer->deadline, abstime) :
1385 DECREMENTER_MAX;
1386 decr = MIN(decr_tick, decr_timer);
1387 pp->cpu_rtc_intr_deadline = abstime + decr;
1388
1389 rtc_lapic_set_timer(decr);
1390
1391
1392 KERNEL_DEBUG_CONSTANT(
1393 MACHDBG_CODE(DBG_MACH_EXCP_DECI, 1) | DBG_FUNC_NONE,
1394 decr, 3, 0, 0, 0);
1395
1396}
1397
1398static void
1399rtclock_alarm_expire(
1400 __unused timer_call_param_t p0,
1401 __unused timer_call_param_t p1)
1402{
1403 mach_timespec_t clock_time;
1404
1405 (void) sysclk_gettime_internal(&clock_time);
1406
1407 clock_alarm_intr(SYSTEM_CLOCK, &clock_time);
1408}
1409
1410void
1411clock_get_uptime(
1412 uint64_t *result)
1413{
1414 *result = rtc_nanotime_read();
1415}
1416
1417uint64_t
1418mach_absolute_time(void)
1419{
1420 return rtc_nanotime_read();
1421}
1422
1423void
1424absolutetime_to_microtime(
1425 uint64_t abstime,
1426 uint32_t *secs,
1427 uint32_t *microsecs)
1428{
1429 uint32_t remain;
1430
1431 asm volatile(
1432 "divl %3"
1433 : "=a" (*secs), "=d" (remain)
1434 : "A" (abstime), "r" (NSEC_PER_SEC));
1435 asm volatile(
1436 "divl %3"
1437 : "=a" (*microsecs)
1438 : "0" (remain), "d" (0), "r" (NSEC_PER_USEC));
1439}
1440
1441void
1442clock_interval_to_deadline(
1443 uint32_t interval,
1444 uint32_t scale_factor,
1445 uint64_t *result)
1446{
1447 uint64_t abstime;
1448
1449 clock_get_uptime(result);
1450
1451 clock_interval_to_absolutetime_interval(interval, scale_factor, &abstime);
1452
1453 *result += abstime;
1454}
1455
1456void
1457clock_interval_to_absolutetime_interval(
1458 uint32_t interval,
1459 uint32_t scale_factor,
1460 uint64_t *result)
1461{
1462 *result = (uint64_t)interval * scale_factor;
1463}
1464
1465void
1466clock_absolutetime_interval_to_deadline(
1467 uint64_t abstime,
1468 uint64_t *result)
1469{
1470 clock_get_uptime(result);
1471
1472 *result += abstime;
1473}
1474
1475void
1476absolutetime_to_nanoseconds(
1477 uint64_t abstime,
1478 uint64_t *result)
1479{
1480 *result = abstime;
1481}
1482
1483void
1484nanoseconds_to_absolutetime(
1485 uint64_t nanoseconds,
1486 uint64_t *result)
1487{
1488 *result = nanoseconds;
1489}
1490
1491void
1492machine_delay_until(
1493 uint64_t deadline)
1494{
1495 uint64_t now;
1496
1497 do {
1498 cpu_pause();
1499 now = mach_absolute_time();
1500 } while (now < deadline);
1501}
1502