xref: /xnu-8796.101.5/osfmk/arm/rtclock.c (revision aca3beaa3dfbd42498b42c5e5ce20a938e6554e5)
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