1*aca3beaaSApple OSS Distributions /*
2*aca3beaaSApple OSS Distributions * Copyright (c) 2007-2021 Apple Inc. All rights reserved.
3*aca3beaaSApple OSS Distributions *
4*aca3beaaSApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*aca3beaaSApple OSS Distributions *
6*aca3beaaSApple OSS Distributions * This file contains Original Code and/or Modifications of Original Code
7*aca3beaaSApple OSS Distributions * as defined in and that are subject to the Apple Public Source License
8*aca3beaaSApple OSS Distributions * Version 2.0 (the 'License'). You may not use this file except in
9*aca3beaaSApple OSS Distributions * compliance with the License. The rights granted to you under the License
10*aca3beaaSApple OSS Distributions * may not be used to create, or enable the creation or redistribution of,
11*aca3beaaSApple OSS Distributions * unlawful or unlicensed copies of an Apple operating system, or to
12*aca3beaaSApple OSS Distributions * circumvent, violate, or enable the circumvention or violation of, any
13*aca3beaaSApple OSS Distributions * terms of an Apple operating system software license agreement.
14*aca3beaaSApple OSS Distributions *
15*aca3beaaSApple OSS Distributions * Please obtain a copy of the License at
16*aca3beaaSApple OSS Distributions * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*aca3beaaSApple OSS Distributions *
18*aca3beaaSApple OSS Distributions * The Original Code and all software distributed under the License are
19*aca3beaaSApple OSS Distributions * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*aca3beaaSApple OSS Distributions * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*aca3beaaSApple OSS Distributions * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*aca3beaaSApple OSS Distributions * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*aca3beaaSApple OSS Distributions * Please see the License for the specific language governing rights and
24*aca3beaaSApple OSS Distributions * limitations under the License.
25*aca3beaaSApple OSS Distributions *
26*aca3beaaSApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*aca3beaaSApple OSS Distributions */
28*aca3beaaSApple OSS Distributions /*
29*aca3beaaSApple OSS Distributions * @OSF_COPYRIGHT@
30*aca3beaaSApple OSS Distributions */
31*aca3beaaSApple OSS Distributions /*
32*aca3beaaSApple OSS Distributions * @APPLE_FREE_COPYRIGHT@
33*aca3beaaSApple OSS Distributions */
34*aca3beaaSApple OSS Distributions /*
35*aca3beaaSApple OSS Distributions * File: arm/rtclock.c
36*aca3beaaSApple OSS Distributions * Purpose: Routines for handling the machine dependent
37*aca3beaaSApple OSS Distributions * real-time clock.
38*aca3beaaSApple OSS Distributions */
39*aca3beaaSApple OSS Distributions
40*aca3beaaSApple OSS Distributions #include <mach/mach_types.h>
41*aca3beaaSApple OSS Distributions
42*aca3beaaSApple OSS Distributions #include <kern/clock.h>
43*aca3beaaSApple OSS Distributions #include <kern/thread.h>
44*aca3beaaSApple OSS Distributions #include <kern/macro_help.h>
45*aca3beaaSApple OSS Distributions #include <kern/spl.h>
46*aca3beaaSApple OSS Distributions #include <kern/timer_queue.h>
47*aca3beaaSApple OSS Distributions
48*aca3beaaSApple OSS Distributions #include <kern/host_notify.h>
49*aca3beaaSApple OSS Distributions
50*aca3beaaSApple OSS Distributions #include <machine/commpage.h>
51*aca3beaaSApple OSS Distributions #include <machine/machine_routines.h>
52*aca3beaaSApple OSS Distributions #include <machine/config.h>
53*aca3beaaSApple OSS Distributions #include <arm/exception.h>
54*aca3beaaSApple OSS Distributions #include <arm/cpu_data_internal.h>
55*aca3beaaSApple OSS Distributions #if __arm64__
56*aca3beaaSApple OSS Distributions #include <arm64/proc_reg.h>
57*aca3beaaSApple OSS Distributions #else
58*aca3beaaSApple OSS Distributions #error Unsupported arch
59*aca3beaaSApple OSS Distributions #endif
60*aca3beaaSApple OSS Distributions #include <arm/rtclock.h>
61*aca3beaaSApple OSS Distributions
62*aca3beaaSApple OSS Distributions #include <IOKit/IOPlatformExpert.h>
63*aca3beaaSApple OSS Distributions #include <libkern/OSAtomic.h>
64*aca3beaaSApple OSS Distributions
65*aca3beaaSApple OSS Distributions #include <sys/kdebug.h>
66*aca3beaaSApple OSS Distributions
67*aca3beaaSApple OSS Distributions #define MAX_TIMEBASE_TRIES 10
68*aca3beaaSApple OSS Distributions
69*aca3beaaSApple OSS Distributions int rtclock_init(void);
70*aca3beaaSApple OSS Distributions
71*aca3beaaSApple OSS Distributions static int
72*aca3beaaSApple OSS Distributions deadline_to_decrementer(uint64_t deadline,
73*aca3beaaSApple OSS Distributions uint64_t now);
74*aca3beaaSApple OSS Distributions static void
75*aca3beaaSApple OSS Distributions timebase_callback(struct timebase_freq_t * freq);
76*aca3beaaSApple OSS Distributions
77*aca3beaaSApple OSS Distributions #if DEVELOPMENT || DEBUG
78*aca3beaaSApple OSS Distributions uint32_t timebase_validation = 0;
79*aca3beaaSApple OSS Distributions #endif
80*aca3beaaSApple OSS Distributions
81*aca3beaaSApple OSS Distributions /*
82*aca3beaaSApple OSS Distributions * Configure the real-time clock device at boot
83*aca3beaaSApple OSS Distributions */
84*aca3beaaSApple OSS Distributions void
rtclock_early_init(void)85*aca3beaaSApple OSS Distributions rtclock_early_init(void)
86*aca3beaaSApple OSS Distributions {
87*aca3beaaSApple OSS Distributions PE_register_timebase_callback(timebase_callback);
88*aca3beaaSApple OSS Distributions #if DEVELOPMENT || DEBUG
89*aca3beaaSApple OSS Distributions uint32_t tmp_mv = 1;
90*aca3beaaSApple OSS Distributions
91*aca3beaaSApple OSS Distributions #if defined(APPLE_ARM64_ARCH_FAMILY)
92*aca3beaaSApple OSS Distributions /* Enable MAT validation on A0 hardware by default. */
93*aca3beaaSApple OSS Distributions timebase_validation = ml_get_topology_info()->chip_revision == CPU_VERSION_A0;
94*aca3beaaSApple OSS Distributions #endif
95*aca3beaaSApple OSS Distributions
96*aca3beaaSApple OSS Distributions if (kern_feature_override(KF_MATV_OVRD)) {
97*aca3beaaSApple OSS Distributions timebase_validation = 0;
98*aca3beaaSApple OSS Distributions }
99*aca3beaaSApple OSS Distributions if (PE_parse_boot_argn("timebase_validation", &tmp_mv, sizeof(tmp_mv))) {
100*aca3beaaSApple OSS Distributions timebase_validation = tmp_mv;
101*aca3beaaSApple OSS Distributions }
102*aca3beaaSApple OSS Distributions #endif
103*aca3beaaSApple OSS Distributions }
104*aca3beaaSApple OSS Distributions
105*aca3beaaSApple OSS Distributions static void
timebase_callback(struct timebase_freq_t * freq)106*aca3beaaSApple OSS Distributions timebase_callback(struct timebase_freq_t * freq)
107*aca3beaaSApple OSS Distributions {
108*aca3beaaSApple OSS Distributions unsigned long numer, denom;
109*aca3beaaSApple OSS Distributions uint64_t t64_1, t64_2;
110*aca3beaaSApple OSS Distributions uint32_t divisor;
111*aca3beaaSApple OSS Distributions
112*aca3beaaSApple OSS Distributions if (freq->timebase_den < 1 || freq->timebase_den > 4 ||
113*aca3beaaSApple OSS Distributions freq->timebase_num < freq->timebase_den) {
114*aca3beaaSApple OSS Distributions panic("rtclock timebase_callback: invalid constant %ld / %ld",
115*aca3beaaSApple OSS Distributions freq->timebase_num, freq->timebase_den);
116*aca3beaaSApple OSS Distributions }
117*aca3beaaSApple OSS Distributions
118*aca3beaaSApple OSS Distributions denom = freq->timebase_num;
119*aca3beaaSApple OSS Distributions numer = freq->timebase_den * NSEC_PER_SEC;
120*aca3beaaSApple OSS Distributions // reduce by the greatest common denominator to minimize overflow
121*aca3beaaSApple OSS Distributions if (numer > denom) {
122*aca3beaaSApple OSS Distributions t64_1 = numer;
123*aca3beaaSApple OSS Distributions t64_2 = denom;
124*aca3beaaSApple OSS Distributions } else {
125*aca3beaaSApple OSS Distributions t64_1 = denom;
126*aca3beaaSApple OSS Distributions t64_2 = numer;
127*aca3beaaSApple OSS Distributions }
128*aca3beaaSApple OSS Distributions while (t64_2 != 0) {
129*aca3beaaSApple OSS Distributions uint64_t temp = t64_2;
130*aca3beaaSApple OSS Distributions t64_2 = t64_1 % t64_2;
131*aca3beaaSApple OSS Distributions t64_1 = temp;
132*aca3beaaSApple OSS Distributions }
133*aca3beaaSApple OSS Distributions numer /= t64_1;
134*aca3beaaSApple OSS Distributions denom /= t64_1;
135*aca3beaaSApple OSS Distributions
136*aca3beaaSApple OSS Distributions rtclock_timebase_const.numer = (uint32_t)numer;
137*aca3beaaSApple OSS Distributions rtclock_timebase_const.denom = (uint32_t)denom;
138*aca3beaaSApple OSS Distributions divisor = (uint32_t)(freq->timebase_num / freq->timebase_den);
139*aca3beaaSApple OSS Distributions
140*aca3beaaSApple OSS Distributions rtclock_sec_divisor = divisor;
141*aca3beaaSApple OSS Distributions rtclock_usec_divisor = divisor / USEC_PER_SEC;
142*aca3beaaSApple OSS Distributions }
143*aca3beaaSApple OSS Distributions
144*aca3beaaSApple OSS Distributions /*
145*aca3beaaSApple OSS Distributions * Initialize the system clock device for the current cpu
146*aca3beaaSApple OSS Distributions */
147*aca3beaaSApple OSS Distributions int
rtclock_init(void)148*aca3beaaSApple OSS Distributions rtclock_init(void)
149*aca3beaaSApple OSS Distributions {
150*aca3beaaSApple OSS Distributions uint64_t abstime;
151*aca3beaaSApple OSS Distributions cpu_data_t * cdp;
152*aca3beaaSApple OSS Distributions
153*aca3beaaSApple OSS Distributions clock_timebase_init();
154*aca3beaaSApple OSS Distributions
155*aca3beaaSApple OSS Distributions cdp = getCpuDatap();
156*aca3beaaSApple OSS Distributions
157*aca3beaaSApple OSS Distributions abstime = mach_absolute_time();
158*aca3beaaSApple OSS Distributions cdp->rtcPop = EndOfAllTime; /* Init Pop time */
159*aca3beaaSApple OSS Distributions timer_resync_deadlines(); /* Start the timers going */
160*aca3beaaSApple OSS Distributions
161*aca3beaaSApple OSS Distributions return 1;
162*aca3beaaSApple OSS Distributions }
163*aca3beaaSApple OSS Distributions
164*aca3beaaSApple OSS Distributions
165*aca3beaaSApple OSS Distributions uint64_t
mach_absolute_time(void)166*aca3beaaSApple OSS Distributions mach_absolute_time(void)
167*aca3beaaSApple OSS Distributions {
168*aca3beaaSApple OSS Distributions #if DEVELOPMENT || DEBUG
169*aca3beaaSApple OSS Distributions if (__improbable(timebase_validation)) {
170*aca3beaaSApple OSS Distributions #if __ARM_ARCH_8_6__ || HAS_ACNTVCT
171*aca3beaaSApple OSS Distributions static _Atomic uint64_t s_last_absolute_time = 1;
172*aca3beaaSApple OSS Distributions
173*aca3beaaSApple OSS Distributions uint64_t old_absolute_time = os_atomic_load(&s_last_absolute_time, relaxed);
174*aca3beaaSApple OSS Distributions
175*aca3beaaSApple OSS Distributions /*
176*aca3beaaSApple OSS Distributions * Because this timebase read is nonspeculative, it cannot begin reading
177*aca3beaaSApple OSS Distributions * the timebase value until after the load of the old value completes.
178*aca3beaaSApple OSS Distributions */
179*aca3beaaSApple OSS Distributions
180*aca3beaaSApple OSS Distributions if (old_absolute_time == 0) {
181*aca3beaaSApple OSS Distributions timebase_validation = 0; // we know it's bad, now prevent nested panics
182*aca3beaaSApple OSS Distributions panic("old_absolute_time was 0");
183*aca3beaaSApple OSS Distributions }
184*aca3beaaSApple OSS Distributions
185*aca3beaaSApple OSS Distributions uint64_t new_absolute_time = ml_get_timebase();
186*aca3beaaSApple OSS Distributions
187*aca3beaaSApple OSS Distributions if (old_absolute_time > new_absolute_time) {
188*aca3beaaSApple OSS Distributions timebase_validation = 0; // prevent nested panics
189*aca3beaaSApple OSS Distributions panic("mach_absolute_time returning non-monotonically increasing value 0x%llx (old value 0x%llx)",
190*aca3beaaSApple OSS Distributions new_absolute_time, old_absolute_time);
191*aca3beaaSApple OSS Distributions }
192*aca3beaaSApple OSS Distributions
193*aca3beaaSApple OSS Distributions if (old_absolute_time < new_absolute_time) {
194*aca3beaaSApple OSS Distributions /* read again, to pretest the atomic max */
195*aca3beaaSApple OSS Distributions uint64_t pretest_absolute_time = os_atomic_load(&s_last_absolute_time, relaxed);
196*aca3beaaSApple OSS Distributions if (pretest_absolute_time < new_absolute_time) {
197*aca3beaaSApple OSS Distributions uint64_t fresh_last_absolute_time = os_atomic_max_orig(&s_last_absolute_time, new_absolute_time, relaxed);
198*aca3beaaSApple OSS Distributions
199*aca3beaaSApple OSS Distributions if (fresh_last_absolute_time != pretest_absolute_time) {
200*aca3beaaSApple OSS Distributions /*
201*aca3beaaSApple OSS Distributions * Someone else published a newer time after we loaded s_last_absolute_time.
202*aca3beaaSApple OSS Distributions * Enforce that our timebase is not behind this new one.
203*aca3beaaSApple OSS Distributions * We can't compare it with our previous timebase read, as it is too old.
204*aca3beaaSApple OSS Distributions */
205*aca3beaaSApple OSS Distributions
206*aca3beaaSApple OSS Distributions uint64_t newest_absolute_time = ml_get_timebase();
207*aca3beaaSApple OSS Distributions
208*aca3beaaSApple OSS Distributions if (fresh_last_absolute_time > newest_absolute_time) {
209*aca3beaaSApple OSS Distributions timebase_validation = 0; // prevent nested panics
210*aca3beaaSApple OSS Distributions panic("mach_absolute_time returning non-monotonically increasing value 0x%llx (old values 0x%llx, 0x%llx, 0x%llx, 0x%llx)\n",
211*aca3beaaSApple OSS Distributions newest_absolute_time, fresh_last_absolute_time, pretest_absolute_time, old_absolute_time, new_absolute_time);
212*aca3beaaSApple OSS Distributions }
213*aca3beaaSApple OSS Distributions }
214*aca3beaaSApple OSS Distributions }
215*aca3beaaSApple OSS Distributions }
216*aca3beaaSApple OSS Distributions
217*aca3beaaSApple OSS Distributions return new_absolute_time;
218*aca3beaaSApple OSS Distributions
219*aca3beaaSApple OSS Distributions #else /* !(__ARM_ARCH_8_6__ || HAS_ACNTVCT) */
220*aca3beaaSApple OSS Distributions static volatile uint64_t s_last_absolute_time = 0;
221*aca3beaaSApple OSS Distributions uint64_t new_absolute_time, old_absolute_time;
222*aca3beaaSApple OSS Distributions int attempts = 0;
223*aca3beaaSApple OSS Distributions
224*aca3beaaSApple OSS Distributions /* ARM 64: We need a dsb here to ensure that the load of s_last_absolute_time
225*aca3beaaSApple OSS Distributions * completes before the timebase read. Were the load to complete after the
226*aca3beaaSApple OSS Distributions * timebase read, there would be a window for another CPU to update
227*aca3beaaSApple OSS Distributions * s_last_absolute_time and leave us in an inconsistent state. Consider the
228*aca3beaaSApple OSS Distributions * following interleaving:
229*aca3beaaSApple OSS Distributions *
230*aca3beaaSApple OSS Distributions * Let s_last_absolute_time = t0
231*aca3beaaSApple OSS Distributions * CPU0: Read timebase at t1
232*aca3beaaSApple OSS Distributions * CPU1: Read timebase at t2
233*aca3beaaSApple OSS Distributions * CPU1: Update s_last_absolute_time to t2
234*aca3beaaSApple OSS Distributions * CPU0: Load completes
235*aca3beaaSApple OSS Distributions * CPU0: Update s_last_absolute_time to t1
236*aca3beaaSApple OSS Distributions *
237*aca3beaaSApple OSS Distributions * This would cause the assertion to fail even though time did not go
238*aca3beaaSApple OSS Distributions * backwards. Thus, we use a dsb to guarantee completion of the load before
239*aca3beaaSApple OSS Distributions * the timebase read.
240*aca3beaaSApple OSS Distributions */
241*aca3beaaSApple OSS Distributions do {
242*aca3beaaSApple OSS Distributions attempts++;
243*aca3beaaSApple OSS Distributions old_absolute_time = s_last_absolute_time;
244*aca3beaaSApple OSS Distributions
245*aca3beaaSApple OSS Distributions __builtin_arm_dsb(DSB_ISHLD);
246*aca3beaaSApple OSS Distributions
247*aca3beaaSApple OSS Distributions new_absolute_time = ml_get_timebase();
248*aca3beaaSApple OSS Distributions } while (attempts < MAX_TIMEBASE_TRIES && !OSCompareAndSwap64(old_absolute_time, new_absolute_time, &s_last_absolute_time));
249*aca3beaaSApple OSS Distributions
250*aca3beaaSApple OSS Distributions if (attempts < MAX_TIMEBASE_TRIES && old_absolute_time > new_absolute_time) {
251*aca3beaaSApple OSS Distributions timebase_validation = 0; // we know it's bad, now prevent nested panics
252*aca3beaaSApple OSS Distributions panic("mach_absolute_time returning non-monotonically increasing value 0x%llx (old value 0x%llx\n)",
253*aca3beaaSApple OSS Distributions new_absolute_time, old_absolute_time);
254*aca3beaaSApple OSS Distributions }
255*aca3beaaSApple OSS Distributions return new_absolute_time;
256*aca3beaaSApple OSS Distributions #endif /* __ARM_ARCH_8_6__ || HAS_ACNTVCT */
257*aca3beaaSApple OSS Distributions }
258*aca3beaaSApple OSS Distributions #endif /* DEVELOPMENT || DEBUG */
259*aca3beaaSApple OSS Distributions
260*aca3beaaSApple OSS Distributions return ml_get_timebase();
261*aca3beaaSApple OSS Distributions }
262*aca3beaaSApple OSS Distributions
263*aca3beaaSApple OSS Distributions uint64_t
mach_approximate_time(void)264*aca3beaaSApple OSS Distributions mach_approximate_time(void)
265*aca3beaaSApple OSS Distributions {
266*aca3beaaSApple OSS Distributions #if __ARM_TIME__ || __ARM_TIME_TIMEBASE_ONLY__ || __arm64__
267*aca3beaaSApple OSS Distributions /* Hardware supports a fast timestamp, so grab it without asserting monotonicity */
268*aca3beaaSApple OSS Distributions return ml_get_timebase();
269*aca3beaaSApple OSS Distributions #else
270*aca3beaaSApple OSS Distributions processor_t processor;
271*aca3beaaSApple OSS Distributions uint64_t approx_time;
272*aca3beaaSApple OSS Distributions
273*aca3beaaSApple OSS Distributions disable_preemption();
274*aca3beaaSApple OSS Distributions processor = current_processor();
275*aca3beaaSApple OSS Distributions approx_time = processor->last_dispatch;
276*aca3beaaSApple OSS Distributions enable_preemption();
277*aca3beaaSApple OSS Distributions
278*aca3beaaSApple OSS Distributions return approx_time;
279*aca3beaaSApple OSS Distributions #endif
280*aca3beaaSApple OSS Distributions }
281*aca3beaaSApple OSS Distributions
282*aca3beaaSApple OSS Distributions void
clock_get_system_microtime(clock_sec_t * secs,clock_usec_t * microsecs)283*aca3beaaSApple OSS Distributions clock_get_system_microtime(clock_sec_t * secs,
284*aca3beaaSApple OSS Distributions clock_usec_t * microsecs)
285*aca3beaaSApple OSS Distributions {
286*aca3beaaSApple OSS Distributions absolutetime_to_microtime(mach_absolute_time(), secs, microsecs);
287*aca3beaaSApple OSS Distributions }
288*aca3beaaSApple OSS Distributions
289*aca3beaaSApple OSS Distributions void
clock_get_system_nanotime(clock_sec_t * secs,clock_nsec_t * nanosecs)290*aca3beaaSApple OSS Distributions clock_get_system_nanotime(clock_sec_t * secs,
291*aca3beaaSApple OSS Distributions clock_nsec_t * nanosecs)
292*aca3beaaSApple OSS Distributions {
293*aca3beaaSApple OSS Distributions uint64_t abstime;
294*aca3beaaSApple OSS Distributions uint64_t t64;
295*aca3beaaSApple OSS Distributions
296*aca3beaaSApple OSS Distributions abstime = mach_absolute_time();
297*aca3beaaSApple OSS Distributions *secs = (t64 = abstime / rtclock_sec_divisor);
298*aca3beaaSApple OSS Distributions abstime -= (t64 * rtclock_sec_divisor);
299*aca3beaaSApple OSS Distributions
300*aca3beaaSApple OSS Distributions *nanosecs = (clock_nsec_t)((abstime * NSEC_PER_SEC) / rtclock_sec_divisor);
301*aca3beaaSApple OSS Distributions }
302*aca3beaaSApple OSS Distributions
303*aca3beaaSApple OSS Distributions void
clock_gettimeofday_set_commpage(uint64_t abstime,uint64_t sec,uint64_t frac,uint64_t scale,uint64_t tick_per_sec)304*aca3beaaSApple OSS Distributions clock_gettimeofday_set_commpage(uint64_t abstime,
305*aca3beaaSApple OSS Distributions uint64_t sec,
306*aca3beaaSApple OSS Distributions uint64_t frac,
307*aca3beaaSApple OSS Distributions uint64_t scale,
308*aca3beaaSApple OSS Distributions uint64_t tick_per_sec)
309*aca3beaaSApple OSS Distributions {
310*aca3beaaSApple OSS Distributions commpage_set_timestamp(abstime, sec, frac, scale, tick_per_sec);
311*aca3beaaSApple OSS Distributions }
312*aca3beaaSApple OSS Distributions
313*aca3beaaSApple OSS Distributions void
clock_timebase_info(mach_timebase_info_t info)314*aca3beaaSApple OSS Distributions clock_timebase_info(mach_timebase_info_t info)
315*aca3beaaSApple OSS Distributions {
316*aca3beaaSApple OSS Distributions *info = rtclock_timebase_const;
317*aca3beaaSApple OSS Distributions }
318*aca3beaaSApple OSS Distributions
319*aca3beaaSApple OSS Distributions /*
320*aca3beaaSApple OSS Distributions * Real-time clock device interrupt.
321*aca3beaaSApple OSS Distributions */
322*aca3beaaSApple OSS Distributions void
rtclock_intr(__unused unsigned int is_user_context)323*aca3beaaSApple OSS Distributions rtclock_intr(__unused unsigned int is_user_context)
324*aca3beaaSApple OSS Distributions {
325*aca3beaaSApple OSS Distributions uint64_t abstime;
326*aca3beaaSApple OSS Distributions cpu_data_t * cdp;
327*aca3beaaSApple OSS Distributions struct arm_saved_state * regs;
328*aca3beaaSApple OSS Distributions unsigned int user_mode;
329*aca3beaaSApple OSS Distributions uintptr_t pc;
330*aca3beaaSApple OSS Distributions
331*aca3beaaSApple OSS Distributions cdp = getCpuDatap();
332*aca3beaaSApple OSS Distributions
333*aca3beaaSApple OSS Distributions cdp->cpu_stat.timer_cnt++;
334*aca3beaaSApple OSS Distributions SCHED_STATS_INC(timer_pop_count);
335*aca3beaaSApple OSS Distributions
336*aca3beaaSApple OSS Distributions assert(!ml_get_interrupts_enabled());
337*aca3beaaSApple OSS Distributions
338*aca3beaaSApple OSS Distributions abstime = mach_absolute_time();
339*aca3beaaSApple OSS Distributions
340*aca3beaaSApple OSS Distributions if (cdp->cpu_idle_pop != 0x0ULL) {
341*aca3beaaSApple OSS Distributions if ((cdp->rtcPop - abstime) < cdp->cpu_idle_latency) {
342*aca3beaaSApple OSS Distributions cdp->cpu_idle_pop = 0x0ULL;
343*aca3beaaSApple OSS Distributions while (abstime < cdp->rtcPop) {
344*aca3beaaSApple OSS Distributions abstime = mach_absolute_time();
345*aca3beaaSApple OSS Distributions }
346*aca3beaaSApple OSS Distributions } else {
347*aca3beaaSApple OSS Distributions ClearIdlePop(FALSE);
348*aca3beaaSApple OSS Distributions }
349*aca3beaaSApple OSS Distributions }
350*aca3beaaSApple OSS Distributions
351*aca3beaaSApple OSS Distributions if ((regs = cdp->cpu_int_state)) {
352*aca3beaaSApple OSS Distributions pc = get_saved_state_pc(regs);
353*aca3beaaSApple OSS Distributions
354*aca3beaaSApple OSS Distributions #if __arm64__
355*aca3beaaSApple OSS Distributions user_mode = PSR64_IS_USER(get_saved_state_cpsr(regs));
356*aca3beaaSApple OSS Distributions #endif
357*aca3beaaSApple OSS Distributions } else {
358*aca3beaaSApple OSS Distributions pc = 0;
359*aca3beaaSApple OSS Distributions user_mode = 0;
360*aca3beaaSApple OSS Distributions }
361*aca3beaaSApple OSS Distributions if (abstime >= cdp->rtcPop) {
362*aca3beaaSApple OSS Distributions /* Log the interrupt service latency (-ve value expected by tool) */
363*aca3beaaSApple OSS Distributions KDBG_RELEASE(DECR_TRAP_LATENCY | DBG_FUNC_NONE,
364*aca3beaaSApple OSS Distributions -(abstime - cdp->rtcPop),
365*aca3beaaSApple OSS Distributions user_mode ? pc : VM_KERNEL_UNSLIDE(pc), user_mode);
366*aca3beaaSApple OSS Distributions }
367*aca3beaaSApple OSS Distributions
368*aca3beaaSApple OSS Distributions /* call the generic etimer */
369*aca3beaaSApple OSS Distributions timer_intr(user_mode, pc);
370*aca3beaaSApple OSS Distributions }
371*aca3beaaSApple OSS Distributions
372*aca3beaaSApple OSS Distributions static int
deadline_to_decrementer(uint64_t deadline,uint64_t now)373*aca3beaaSApple OSS Distributions deadline_to_decrementer(uint64_t deadline,
374*aca3beaaSApple OSS Distributions uint64_t now)
375*aca3beaaSApple OSS Distributions {
376*aca3beaaSApple OSS Distributions uint64_t delt;
377*aca3beaaSApple OSS Distributions
378*aca3beaaSApple OSS Distributions if (deadline <= now) {
379*aca3beaaSApple OSS Distributions return DECREMENTER_MIN;
380*aca3beaaSApple OSS Distributions } else {
381*aca3beaaSApple OSS Distributions delt = deadline - now;
382*aca3beaaSApple OSS Distributions
383*aca3beaaSApple OSS Distributions return (delt >= (DECREMENTER_MAX + 1)) ? DECREMENTER_MAX : ((delt >= (DECREMENTER_MIN + 1)) ? (int)delt : DECREMENTER_MIN);
384*aca3beaaSApple OSS Distributions }
385*aca3beaaSApple OSS Distributions }
386*aca3beaaSApple OSS Distributions
387*aca3beaaSApple OSS Distributions /*
388*aca3beaaSApple OSS Distributions * Request a decrementer pop
389*aca3beaaSApple OSS Distributions */
390*aca3beaaSApple OSS Distributions int
setPop(uint64_t time)391*aca3beaaSApple OSS Distributions setPop(uint64_t time)
392*aca3beaaSApple OSS Distributions {
393*aca3beaaSApple OSS Distributions int delay_time;
394*aca3beaaSApple OSS Distributions uint64_t current_time;
395*aca3beaaSApple OSS Distributions cpu_data_t * cdp;
396*aca3beaaSApple OSS Distributions
397*aca3beaaSApple OSS Distributions cdp = getCpuDatap();
398*aca3beaaSApple OSS Distributions current_time = mach_absolute_time();
399*aca3beaaSApple OSS Distributions
400*aca3beaaSApple OSS Distributions delay_time = deadline_to_decrementer(time, current_time);
401*aca3beaaSApple OSS Distributions cdp->rtcPop = delay_time + current_time;
402*aca3beaaSApple OSS Distributions
403*aca3beaaSApple OSS Distributions ml_set_decrementer((uint32_t) delay_time);
404*aca3beaaSApple OSS Distributions
405*aca3beaaSApple OSS Distributions return delay_time;
406*aca3beaaSApple OSS Distributions }
407*aca3beaaSApple OSS Distributions
408*aca3beaaSApple OSS Distributions /*
409*aca3beaaSApple OSS Distributions * Request decrementer Idle Pop. Return true if set
410*aca3beaaSApple OSS Distributions */
411*aca3beaaSApple OSS Distributions boolean_t
SetIdlePop(void)412*aca3beaaSApple OSS Distributions SetIdlePop(void)
413*aca3beaaSApple OSS Distributions {
414*aca3beaaSApple OSS Distributions int delay_time;
415*aca3beaaSApple OSS Distributions uint64_t time;
416*aca3beaaSApple OSS Distributions uint64_t current_time;
417*aca3beaaSApple OSS Distributions cpu_data_t * cdp;
418*aca3beaaSApple OSS Distributions
419*aca3beaaSApple OSS Distributions cdp = getCpuDatap();
420*aca3beaaSApple OSS Distributions current_time = mach_absolute_time();
421*aca3beaaSApple OSS Distributions
422*aca3beaaSApple OSS Distributions if (((cdp->rtcPop < current_time) ||
423*aca3beaaSApple OSS Distributions (cdp->rtcPop - current_time) < cdp->cpu_idle_latency)) {
424*aca3beaaSApple OSS Distributions return FALSE;
425*aca3beaaSApple OSS Distributions }
426*aca3beaaSApple OSS Distributions
427*aca3beaaSApple OSS Distributions time = cdp->rtcPop - cdp->cpu_idle_latency;
428*aca3beaaSApple OSS Distributions
429*aca3beaaSApple OSS Distributions delay_time = deadline_to_decrementer(time, current_time);
430*aca3beaaSApple OSS Distributions cdp->cpu_idle_pop = delay_time + current_time;
431*aca3beaaSApple OSS Distributions ml_set_decrementer((uint32_t) delay_time);
432*aca3beaaSApple OSS Distributions
433*aca3beaaSApple OSS Distributions return TRUE;
434*aca3beaaSApple OSS Distributions }
435*aca3beaaSApple OSS Distributions
436*aca3beaaSApple OSS Distributions /*
437*aca3beaaSApple OSS Distributions * Clear decrementer Idle Pop
438*aca3beaaSApple OSS Distributions */
439*aca3beaaSApple OSS Distributions void
ClearIdlePop(boolean_t wfi)440*aca3beaaSApple OSS Distributions ClearIdlePop(
441*aca3beaaSApple OSS Distributions boolean_t wfi)
442*aca3beaaSApple OSS Distributions {
443*aca3beaaSApple OSS Distributions cpu_data_t * cdp;
444*aca3beaaSApple OSS Distributions
445*aca3beaaSApple OSS Distributions cdp = getCpuDatap();
446*aca3beaaSApple OSS Distributions cdp->cpu_idle_pop = 0x0ULL;
447*aca3beaaSApple OSS Distributions
448*aca3beaaSApple OSS Distributions /*
449*aca3beaaSApple OSS Distributions * Don't update the HW timer if there's a pending
450*aca3beaaSApple OSS Distributions * interrupt (we can lose interrupt assertion);
451*aca3beaaSApple OSS Distributions * we want to take the interrupt right now and update
452*aca3beaaSApple OSS Distributions * the deadline from the handler).
453*aca3beaaSApple OSS Distributions *
454*aca3beaaSApple OSS Distributions * ARM64_TODO: consider this more carefully.
455*aca3beaaSApple OSS Distributions */
456*aca3beaaSApple OSS Distributions if (!(wfi && ml_get_timer_pending())) {
457*aca3beaaSApple OSS Distributions setPop(cdp->rtcPop);
458*aca3beaaSApple OSS Distributions }
459*aca3beaaSApple OSS Distributions }
460*aca3beaaSApple OSS Distributions
461*aca3beaaSApple OSS Distributions void
absolutetime_to_microtime(uint64_t abstime,clock_sec_t * secs,clock_usec_t * microsecs)462*aca3beaaSApple OSS Distributions absolutetime_to_microtime(uint64_t abstime,
463*aca3beaaSApple OSS Distributions clock_sec_t * secs,
464*aca3beaaSApple OSS Distributions clock_usec_t * microsecs)
465*aca3beaaSApple OSS Distributions {
466*aca3beaaSApple OSS Distributions uint64_t t64;
467*aca3beaaSApple OSS Distributions
468*aca3beaaSApple OSS Distributions *secs = t64 = abstime / rtclock_sec_divisor;
469*aca3beaaSApple OSS Distributions abstime -= (t64 * rtclock_sec_divisor);
470*aca3beaaSApple OSS Distributions
471*aca3beaaSApple OSS Distributions *microsecs = (uint32_t)(abstime / rtclock_usec_divisor);
472*aca3beaaSApple OSS Distributions }
473*aca3beaaSApple OSS Distributions
474*aca3beaaSApple OSS Distributions void
absolutetime_to_nanoseconds(uint64_t abstime,uint64_t * result)475*aca3beaaSApple OSS Distributions absolutetime_to_nanoseconds(uint64_t abstime,
476*aca3beaaSApple OSS Distributions uint64_t * result)
477*aca3beaaSApple OSS Distributions {
478*aca3beaaSApple OSS Distributions uint64_t t64;
479*aca3beaaSApple OSS Distributions
480*aca3beaaSApple OSS Distributions *result = (t64 = abstime / rtclock_sec_divisor) * NSEC_PER_SEC;
481*aca3beaaSApple OSS Distributions abstime -= (t64 * rtclock_sec_divisor);
482*aca3beaaSApple OSS Distributions *result += (abstime * NSEC_PER_SEC) / rtclock_sec_divisor;
483*aca3beaaSApple OSS Distributions }
484*aca3beaaSApple OSS Distributions
485*aca3beaaSApple OSS Distributions void
nanoseconds_to_absolutetime(uint64_t nanosecs,uint64_t * result)486*aca3beaaSApple OSS Distributions nanoseconds_to_absolutetime(uint64_t nanosecs,
487*aca3beaaSApple OSS Distributions uint64_t * result)
488*aca3beaaSApple OSS Distributions {
489*aca3beaaSApple OSS Distributions uint64_t t64;
490*aca3beaaSApple OSS Distributions
491*aca3beaaSApple OSS Distributions *result = (t64 = nanosecs / NSEC_PER_SEC) * rtclock_sec_divisor;
492*aca3beaaSApple OSS Distributions nanosecs -= (t64 * NSEC_PER_SEC);
493*aca3beaaSApple OSS Distributions *result += (nanosecs * rtclock_sec_divisor) / NSEC_PER_SEC;
494*aca3beaaSApple OSS Distributions }
495*aca3beaaSApple OSS Distributions
496*aca3beaaSApple OSS Distributions void
nanotime_to_absolutetime(clock_sec_t secs,clock_nsec_t nanosecs,uint64_t * result)497*aca3beaaSApple OSS Distributions nanotime_to_absolutetime(clock_sec_t secs,
498*aca3beaaSApple OSS Distributions clock_nsec_t nanosecs,
499*aca3beaaSApple OSS Distributions uint64_t * result)
500*aca3beaaSApple OSS Distributions {
501*aca3beaaSApple OSS Distributions *result = ((uint64_t) secs * rtclock_sec_divisor) +
502*aca3beaaSApple OSS Distributions ((uint64_t) nanosecs * rtclock_sec_divisor) / NSEC_PER_SEC;
503*aca3beaaSApple OSS Distributions }
504*aca3beaaSApple OSS Distributions
505*aca3beaaSApple OSS Distributions void
clock_interval_to_absolutetime_interval(uint32_t interval,uint32_t scale_factor,uint64_t * result)506*aca3beaaSApple OSS Distributions clock_interval_to_absolutetime_interval(uint32_t interval,
507*aca3beaaSApple OSS Distributions uint32_t scale_factor,
508*aca3beaaSApple OSS Distributions uint64_t * result)
509*aca3beaaSApple OSS Distributions {
510*aca3beaaSApple OSS Distributions uint64_t nanosecs = (uint64_t) interval * scale_factor;
511*aca3beaaSApple OSS Distributions uint64_t t64;
512*aca3beaaSApple OSS Distributions
513*aca3beaaSApple OSS Distributions *result = (t64 = nanosecs / NSEC_PER_SEC) * rtclock_sec_divisor;
514*aca3beaaSApple OSS Distributions nanosecs -= (t64 * NSEC_PER_SEC);
515*aca3beaaSApple OSS Distributions *result += (nanosecs * rtclock_sec_divisor) / NSEC_PER_SEC;
516*aca3beaaSApple OSS Distributions }
517*aca3beaaSApple OSS Distributions
518*aca3beaaSApple OSS Distributions void
machine_delay_until(uint64_t interval,uint64_t deadline)519*aca3beaaSApple OSS Distributions machine_delay_until(uint64_t interval,
520*aca3beaaSApple OSS Distributions uint64_t deadline)
521*aca3beaaSApple OSS Distributions {
522*aca3beaaSApple OSS Distributions #pragma unused(interval)
523*aca3beaaSApple OSS Distributions uint64_t now;
524*aca3beaaSApple OSS Distributions
525*aca3beaaSApple OSS Distributions do {
526*aca3beaaSApple OSS Distributions __builtin_arm_wfe();
527*aca3beaaSApple OSS Distributions now = mach_absolute_time();
528*aca3beaaSApple OSS Distributions } while (now < deadline);
529*aca3beaaSApple OSS Distributions }
530