2 * Copyright (c) 2017 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 #include <mach/mach_time.h>
29 #include <mach/clock_types.h>
30 #include <kern/misc_protos.h>
31 #include <kern/clock.h>
32 #include <kern/remote_time.h>
34 #include <kern/locks.h>
35 #include <sys/kdebug.h>
36 #include <machine/machine_routines.h>
37 #include <kern/assert.h>
38 #include <kern/kern_types.h>
39 #include <kern/thread.h>
40 #include <machine/commpage.h>
41 #include <machine/atomic.h>
43 #if CONFIG_MACH_BRIDGE_SEND_TIME
45 uint32_t bt_enable_flag
= 0;
46 lck_spin_t
*bt_maintenance_lock
= NULL
;
47 _Atomic
uint32_t bt_init_flag
= 0;
49 void mach_bridge_timer_maintenance(void);
50 void mach_bridge_timer_init(void);
51 uint32_t mach_bridge_timer_enable(uint32_t new_value
, int change
);
54 * When CONFIG_MACH_BRIDGE_SEND_TIME is defined, it is expected
55 * that a machine-specific timestamp sending routine such as
56 * void mach_bridge_send_timestamp(uint64_t); has also been defined.
58 extern void mach_bridge_send_timestamp(uint64_t);
61 mach_bridge_timer_maintenance(void)
63 if (!os_atomic_load(&bt_init_flag
, acquire
)) {
67 lck_spin_lock(bt_maintenance_lock
);
68 if (!bt_enable_flag
) {
71 mach_bridge_send_timestamp(0);
74 lck_spin_unlock(bt_maintenance_lock
);
78 * This function should be called only once from the callback
79 * registration function
82 mach_bridge_timer_init(void)
84 assert(!os_atomic_load(&bt_init_flag
, relaxed
));
85 /* Initialize the lock */
86 static lck_grp_t
*bt_lck_grp
= NULL
;
87 bt_lck_grp
= lck_grp_alloc_init("bridgetimestamp", LCK_GRP_ATTR_NULL
);
88 bt_maintenance_lock
= lck_spin_alloc_init(bt_lck_grp
, NULL
);
92 * If change = 0, return the current value of bridge_timer_enable
93 * If change = 1, update bridge_timer_enable and return the updated
97 mach_bridge_timer_enable(uint32_t new_value
, int change
)
99 uint32_t current_value
= 0;
100 assert(os_atomic_load(&bt_init_flag
, relaxed
));
101 lck_spin_lock(bt_maintenance_lock
);
103 bt_enable_flag
= new_value
;
105 current_value
= bt_enable_flag
;
106 lck_spin_unlock(bt_maintenance_lock
);
107 return current_value
;
110 #endif /* CONFIG_MACH_BRIDGE_SEND_TIME */
112 #if CONFIG_MACH_BRIDGE_RECV_TIME
113 #include <machine/machine_remote_time.h>
116 * functions used by machine-specific code
117 * that implements CONFIG_MACH_BRIDGE_RECV_TIME
119 void mach_bridge_add_timestamp(uint64_t remote_timestamp
, uint64_t local_timestamp
);
120 void bt_calibration_thread_start(void);
121 lck_spin_t
*ts_conversion_lock
= NULL
;
122 void bt_params_add(struct bt_params
*params
);
124 /* function called by sysctl */
125 struct bt_params
bt_params_get_latest(void);
128 * Platform specific bridge time receiving interface.
129 * These variables should be exported by the platform specific time receiving code.
131 extern lck_spin_t
*bt_spin_lock
;
132 extern _Atomic
uint32_t bt_init_flag
;
134 static uint64_t received_local_timestamp
= 0;
135 static uint64_t received_remote_timestamp
= 0;
137 * Buffer the previous timestamp pairs and rate
138 * It is protected by the ts_conversion_lock
140 #define BT_PARAMS_COUNT 10
141 static struct bt_params bt_params_hist
[BT_PARAMS_COUNT
] = {};
142 static int bt_params_idx
= -1;
145 bt_params_add(struct bt_params
*params
)
147 lck_spin_assert(ts_conversion_lock
, LCK_ASSERT_OWNED
);
149 bt_params_idx
= (bt_params_idx
+ 1) % BT_PARAMS_COUNT
;
150 bt_params_hist
[bt_params_idx
] = *params
;
153 #if defined(XNU_TARGET_OS_BRIDGE)
154 static inline struct bt_params
*
155 bt_params_find(uint64_t local_ts
)
157 lck_spin_assert(ts_conversion_lock
, LCK_ASSERT_OWNED
);
159 int idx
= bt_params_idx
;
164 if (local_ts
>= bt_params_hist
[idx
].base_local_ts
) {
165 return &bt_params_hist
[idx
];
168 idx
= BT_PARAMS_COUNT
- 1;
170 } while (idx
!= bt_params_idx
);
174 #endif /* defined(XNU_TARGET_OS_BRIDGE) */
176 static inline struct bt_params
177 bt_params_get_latest_locked(void)
179 lck_spin_assert(ts_conversion_lock
, LCK_ASSERT_OWNED
);
181 struct bt_params latest_params
= {};
182 if (bt_params_idx
>= 0) {
183 latest_params
= bt_params_hist
[bt_params_idx
];
186 return latest_params
;
190 bt_params_get_latest(void)
192 struct bt_params latest_params
= {};
194 /* Check if ts_converison_lock has been initialized */
195 if (os_atomic_load(&bt_init_flag
, acquire
)) {
196 lck_spin_lock(ts_conversion_lock
);
197 latest_params
= bt_params_get_latest_locked();
198 lck_spin_unlock(ts_conversion_lock
);
200 return latest_params
;
204 * Conditions: bt_spin_lock held and called from primary interrupt context
207 mach_bridge_add_timestamp(uint64_t remote_timestamp
, uint64_t local_timestamp
)
209 lck_spin_assert(bt_spin_lock
, LCK_ASSERT_OWNED
);
211 /* sleep/wake might return the same mach_absolute_time as the previous timestamp pair */
212 if ((received_local_timestamp
== local_timestamp
) ||
213 (received_remote_timestamp
== remote_timestamp
)) {
217 received_local_timestamp
= local_timestamp
;
218 received_remote_timestamp
= remote_timestamp
;
219 thread_wakeup((event_t
)bt_params_hist
);
223 mach_bridge_compute_rate(uint64_t new_local_ts
, uint64_t new_remote_ts
,
224 uint64_t old_local_ts
, uint64_t old_remote_ts
)
226 int64_t rdiff
= (int64_t)new_remote_ts
- (int64_t)old_remote_ts
;
227 int64_t ldiff
= (int64_t)new_local_ts
- (int64_t)old_local_ts
;
228 double calc_rate
= ((double)rdiff
) / ldiff
;
232 #define MAX_RECALCULATE_COUNT 8
233 #define CUMULATIVE_RATE_DECAY_CONSTANT 0.01
234 #define CUMULATIVE_RATE_WEIGHT 0.99
235 #define INITIAL_RATE 1.0
236 #define MIN_INITIAL_SAMPLE_COUNT 10
237 #define MAX_INITIAL_SAMPLE_COUNT 50
238 #define MAX_SKIP_RESET_COUNT 2
239 #define MIN_LOCAL_TS_DISTANCE_NS 100000000 /* 100 ms */
240 #define MAX_LOCAL_TS_DISTANCE_NS 350000000 /* 350 ms */
241 #define TS_PAIR_MISMATCH_THRESHOLD_NS 50000000 /* 50 ms */
242 #define MAX_TS_PAIR_MISMATCHES 5
243 #define MAX_TS_PAIR_MISMATCH_RESET_COUNT 3
244 #define MIN_OBSERVED_RATE 0.8
245 #define MAX_OBSERVED_RATE 1.2
248 bt_calibration_thread(void)
250 static uint64_t prev_local_ts
= 0, prev_remote_ts
= 0, curr_local_ts
= 0, curr_remote_ts
= 0;
251 static uint64_t prev_received_local_ts
= 0, prev_received_remote_ts
= 0;
252 static double cumulative_rate
= INITIAL_RATE
;
253 static uint32_t initial_sample_count
= 1;
254 static uint32_t max_initial_sample_count
= MAX_INITIAL_SAMPLE_COUNT
;
255 static uint32_t skip_reset_count
= MAX_SKIP_RESET_COUNT
;
256 int recalculate_count
= 1;
257 static bool reset
= false;
259 static bool skip_rcv_ts
= false;
260 static uint64_t ts_pair_mismatch
= 0;
261 static uint32_t ts_pair_mismatch_reset_count
= 0;
262 spl_t s
= splsched();
263 lck_spin_lock(bt_spin_lock
);
264 if (!received_remote_timestamp
) {
265 if (PE_parse_boot_argn("rt_ini_count", &max_initial_sample_count
,
266 sizeof(uint32_t)) == TRUE
) {
267 if (max_initial_sample_count
< MIN_INITIAL_SAMPLE_COUNT
) {
268 max_initial_sample_count
= MIN_INITIAL_SAMPLE_COUNT
;
271 /* Nothing to do the first time */
275 * The values in bt_params are recalculated every time a new timestamp
276 * pair is received. Firstly, both timestamps are converted to nanoseconds.
277 * The current and previous timestamp pairs are used to compute the
278 * observed_rate of the two clocks w.r.t each other. For the first
279 * MIN_INITIAL_SAMPLE_COUNT number of pairs, the cumulative_rate is a simple
280 * average of the observed_rate. For the later pairs, the cumulative_rate
281 * is updated using exponential moving average of the observed_rate.
282 * The current and bt_params' base timestamp pairs are used to compute
283 * the rate_from_base. This value ensures that the bt_params base
284 * timestamp pair curve doesn't stay parallel to the observed timestamp
285 * pair curve, rather moves in the direction of the observed timestamp curve.
286 * The bt_params.rate is computed as a weighted average of the cumulative_rate
287 * and the rate_from_base. For each current local timestamp, the remote_time
288 * is predicted using the previous values of bt_params. After computing the new
289 * bt_params.rate, bt_params.base_remote_time is set to this predicted value
290 * and bt_params.base_local_time is set to the current local timestamp.
293 assertf(recalculate_count
<= MAX_RECALCULATE_COUNT
, "bt_caliberation_thread: recalculate \
294 invocation exceeds MAX_RECALCULATE_COUNT");
296 if ((received_remote_timestamp
== BT_RESET_SENTINEL_TS
) || (received_remote_timestamp
== BT_WAKE_SENTINEL_TS
)) {
297 KDBG(MACHDBG_CODE(DBG_MACH_CLOCK
, MACH_BRIDGE_RESET_TS
), received_local_timestamp
, received_remote_timestamp
, 1);
299 skip_reset_count
= MAX_SKIP_RESET_COUNT
;
300 ts_pair_mismatch_reset_count
= 0;
302 } else if (received_remote_timestamp
== BT_SLEEP_SENTINEL_TS
) {
304 } else if (!received_local_timestamp
) {
305 /* If the local timestamp isn't accurately captured, the received value will be ignored */
310 /* Keep a copy of the prev timestamps to compute distance */
311 prev_received_local_ts
= curr_local_ts
;
312 prev_received_remote_ts
= curr_remote_ts
;
314 uint64_t curr_local_abs
= received_local_timestamp
;
315 absolutetime_to_nanoseconds(curr_local_abs
, &curr_local_ts
);
316 curr_remote_ts
= received_remote_timestamp
;
318 /* Prevent unusual rate changes caused by delayed timestamps */
319 uint64_t local_diff
= curr_local_ts
- prev_received_local_ts
;
320 if (!(reset
|| sleep
) && ((local_diff
< MIN_LOCAL_TS_DISTANCE_NS
) ||
321 (!skip_rcv_ts
&& (local_diff
> MAX_LOCAL_TS_DISTANCE_NS
)))) {
322 /* Skip the current timestamp */
323 KDBG(MACHDBG_CODE(DBG_MACH_CLOCK
, MACH_BRIDGE_SKIP_TS
), curr_local_ts
, curr_remote_ts
,
324 prev_received_local_ts
);
328 /* Use the prev copy of timestamps only if the distance is acceptable */
329 prev_local_ts
= prev_received_local_ts
;
330 prev_remote_ts
= prev_received_remote_ts
;
332 lck_spin_unlock(bt_spin_lock
);
335 struct bt_params bt_params
= {};
337 lck_spin_lock(ts_conversion_lock
);
339 if (skip_reset_count
> 0) {
340 KDBG(MACHDBG_CODE(DBG_MACH_CLOCK
, MACH_BRIDGE_SKIP_TS
), curr_local_ts
, curr_remote_ts
,
341 prev_local_ts
, skip_reset_count
);
345 bt_params
.base_local_ts
= curr_local_ts
;
346 bt_params
.base_remote_ts
= curr_remote_ts
;
347 bt_params
.rate
= cumulative_rate
;
350 ts_pair_mismatch
= 0;
351 initial_sample_count
= 1;
353 KDBG(MACHDBG_CODE(DBG_MACH_CLOCK
, MACH_BRIDGE_RESET_TS
), curr_local_ts
, curr_remote_ts
, 2);
355 absolutetime_to_nanoseconds(mach_absolute_time(), &bt_params
.base_local_ts
);
356 bt_params
.base_remote_ts
= 0;
360 struct bt_params bt_params_snapshot
= {};
361 if (bt_params_idx
>= 0) {
362 bt_params_snapshot
= bt_params_hist
[bt_params_idx
];
364 lck_spin_unlock(ts_conversion_lock
);
365 if (bt_params_snapshot
.rate
== 0.0) {
367 * The rate should never be 0 because we always expect a reset/wake
368 * sentinel after sleep, followed by valid timestamp pair data that
369 * will be handled by the reset clause (above). However, we should
370 * not rely on a paired version of the remote OS - we could actually
371 * be running a completely different OS! Treat a timestamp after
372 * a sleep as a reset condition.
375 skip_reset_count
= MAX_SKIP_RESET_COUNT
;
376 ts_pair_mismatch_reset_count
= 0;
377 KDBG(MACHDBG_CODE(DBG_MACH_CLOCK
, MACH_BRIDGE_RESET_TS
), curr_local_ts
, curr_remote_ts
, 3);
379 lck_spin_lock(bt_spin_lock
);
383 /* Check if the predicted remote timestamp is within the expected current remote timestamp range */
384 uint64_t pred_remote_ts
= mach_bridge_compute_timestamp(curr_local_ts
, &bt_params_snapshot
);
386 if (initial_sample_count
>= max_initial_sample_count
) {
387 if (pred_remote_ts
> curr_remote_ts
) {
388 diff
= pred_remote_ts
- curr_remote_ts
;
390 diff
= curr_remote_ts
- pred_remote_ts
;
392 if (diff
> TS_PAIR_MISMATCH_THRESHOLD_NS
) {
394 KDBG(MACHDBG_CODE(DBG_MACH_CLOCK
, MACH_BRIDGE_TS_MISMATCH
), curr_local_ts
,
395 curr_remote_ts
, pred_remote_ts
, ts_pair_mismatch
);
397 ts_pair_mismatch
= 0;
399 if (ts_pair_mismatch
> MAX_TS_PAIR_MISMATCHES
) {
400 #if (DEVELOPMENT || DEBUG)
401 if (ts_pair_mismatch_reset_count
== MAX_TS_PAIR_MISMATCH_RESET_COUNT
) {
402 panic("remote_time: timestamp pair mismatch exceeded limit");
404 #endif /* (DEVELOPMENT || DEBUG) */
406 ts_pair_mismatch_reset_count
++;
407 KDBG(MACHDBG_CODE(DBG_MACH_CLOCK
, MACH_BRIDGE_RESET_TS
), curr_local_ts
, curr_remote_ts
, 4);
409 lck_spin_lock(bt_spin_lock
);
413 double observed_rate
, rate_from_base
, new_rate
;
414 observed_rate
= mach_bridge_compute_rate(curr_local_ts
, curr_remote_ts
, prev_local_ts
, prev_remote_ts
);
415 /* Log bad observed rates and skip the timestamp pair */
416 if ((observed_rate
< MIN_OBSERVED_RATE
) || (observed_rate
> MAX_OBSERVED_RATE
)) {
417 KDBG(MACHDBG_CODE(DBG_MACH_CLOCK
, MACH_BRIDGE_OBSV_RATE
), *(uint64_t *)((void *)&observed_rate
));
418 ts_pair_mismatch
= ts_pair_mismatch
> 0 ? (ts_pair_mismatch
- 1) : 0;
420 lck_spin_lock(bt_spin_lock
);
423 if (initial_sample_count
<= MIN_INITIAL_SAMPLE_COUNT
) {
424 initial_sample_count
++;
425 cumulative_rate
= cumulative_rate
+ (observed_rate
- cumulative_rate
) / initial_sample_count
;
427 if (initial_sample_count
< max_initial_sample_count
) {
428 initial_sample_count
++;
430 cumulative_rate
= cumulative_rate
+ CUMULATIVE_RATE_DECAY_CONSTANT
* (observed_rate
- cumulative_rate
);
432 rate_from_base
= mach_bridge_compute_rate(curr_local_ts
, curr_remote_ts
, bt_params_snapshot
.base_local_ts
,
433 bt_params_snapshot
.base_remote_ts
);
434 new_rate
= CUMULATIVE_RATE_WEIGHT
* cumulative_rate
+ (1 - CUMULATIVE_RATE_WEIGHT
) * rate_from_base
;
436 * Acquire the lock first to ensure that bt_params.base_local_ts is always
437 * greater than the last value of now captured by mach_bridge_remote_time.
438 * This ensures that we always use the same parameters to compute remote
439 * timestamp for a given local timestamp.
441 lck_spin_lock(ts_conversion_lock
);
442 absolutetime_to_nanoseconds(mach_absolute_time(), &bt_params
.base_local_ts
);
443 bt_params
.base_remote_ts
= mach_bridge_compute_timestamp(bt_params
.base_local_ts
, &bt_params_snapshot
);
444 bt_params
.rate
= new_rate
;
446 bt_params_add(&bt_params
);
447 commpage_set_remotetime_params(bt_params
.rate
, bt_params
.base_local_ts
, bt_params
.base_remote_ts
);
448 KDBG(MACHDBG_CODE(DBG_MACH_CLOCK
, MACH_BRIDGE_TS_PARAMS
), bt_params
.base_local_ts
,
449 bt_params
.base_remote_ts
, *(uint64_t *)((void *)&bt_params
.rate
));
452 lck_spin_unlock(ts_conversion_lock
);
455 lck_spin_lock(bt_spin_lock
);
456 /* Check if a new timestamp pair was received */
457 if (received_local_timestamp
!= curr_local_abs
) {
462 assert_wait((event_t
)bt_params_hist
, THREAD_UNINT
);
463 lck_spin_unlock(bt_spin_lock
);
465 thread_block((thread_continue_t
)bt_calibration_thread
);
469 bt_calibration_thread_start(void)
472 kern_return_t result
= kernel_thread_start_priority((thread_continue_t
)bt_calibration_thread
,
473 NULL
, BASEPRI_KERNEL
, &thread
);
474 if (result
!= KERN_SUCCESS
) {
475 panic("mach_bridge_add_timestamp: thread_timestamp_calibration");
477 thread_deallocate(thread
);
480 #endif /* CONFIG_MACH_BRIDGE_RECV_TIME */
483 * mach_bridge_remote_time
485 * This function is used to predict the remote CPU's clock time, given
488 * If local_timestamp = 0, then the remote_timestamp is calculated
489 * corresponding to the current mach_absolute_time.
491 * If XNU_TARGET_OS_BRIDGE is defined, then monotonicity of
492 * predicted time is guaranteed only for recent local_timestamp values
493 * lesser than the current mach_absolute_time upto 1 second.
495 * If CONFIG_MACH_BRIDGE_SEND_TIME is true, then the function is compiled
496 * for the remote CPU. If CONFIG_MACH_BRIDGE_RECV_TIME is true, then the
497 * the function is compiled for the local CPU. Both config options cannot
498 * be true simultaneously.
501 mach_bridge_remote_time(uint64_t local_timestamp
)
503 #if defined(CONFIG_MACH_BRIDGE_SEND_TIME)
504 #if !defined(CONFIG_MACH_BRIDGE_RECV_TIME)
505 /* only send side of the bridge is defined: no translation needed */
506 if (!local_timestamp
) {
507 return mach_absolute_time();
511 #error "You cannot define both sides of the bridge!"
512 #endif /* !defined(CONFIG_MACH_BRIDGE_RECV_TIME) */
514 #if !defined(CONFIG_MACH_BRIDGE_RECV_TIME)
515 /* neither the send or receive side of the bridge is defined: echo the input */
516 return local_timestamp
;
518 if (!os_atomic_load(&bt_init_flag
, acquire
)) {
522 uint64_t remote_timestamp
= 0;
524 lck_spin_lock(ts_conversion_lock
);
525 uint64_t now
= mach_absolute_time();
526 if (!local_timestamp
) {
527 local_timestamp
= now
;
529 #if defined(XNU_TARGET_OS_BRIDGE)
530 uint64_t local_timestamp_ns
= 0;
531 if (local_timestamp
< now
) {
532 absolutetime_to_nanoseconds(local_timestamp
, &local_timestamp_ns
);
533 struct bt_params
*params
= bt_params_find(local_timestamp_ns
);
534 remote_timestamp
= mach_bridge_compute_timestamp(local_timestamp_ns
, params
);
537 struct bt_params params
= bt_params_get_latest_locked();
538 remote_timestamp
= mach_bridge_compute_timestamp(local_timestamp
, ¶ms
);
539 #endif /* defined(XNU_TARGET_OS_BRIDGE) */
540 lck_spin_unlock(ts_conversion_lock
);
541 KDBG(MACHDBG_CODE(DBG_MACH_CLOCK
, MACH_BRIDGE_REMOTE_TIME
), local_timestamp
, remote_timestamp
, now
);
543 return remote_timestamp
;
544 #endif /* !defined(CONFIG_MACH_BRIDGE_RECV_TIME) */
545 #endif /* defined(CONFIG_MACH_BRIDGE_SEND_TIME) */