]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/remote_time.c
11022ed4d9bb7afa9e9f74cc42cf3c9117639680
[apple/xnu.git] / osfmk / kern / remote_time.c
1 /*
2 * Copyright (c) 2017 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 #include <stdatomic.h>
29 #include <mach/mach_time.h>
30 #include <mach/clock_types.h>
31 #include <kern/misc_protos.h>
32 #include <kern/clock.h>
33 #include <kern/remote_time.h>
34 #include <kern/spl.h>
35 #include <kern/locks.h>
36 #include <sys/kdebug.h>
37 #include <machine/machine_routines.h>
38 #include <kern/assert.h>
39 #include <kern/kern_types.h>
40 #include <kern/thread.h>
41 #include <machine/commpage.h>
42
43 #if CONFIG_MACH_BRIDGE_SEND_TIME
44
45 uint32_t bt_enable_flag = 0;
46 lck_spin_t *bt_maintenance_lock = NULL;
47 _Atomic uint32_t bt_init_flag = 0;
48
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);
52
53 /*
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.
57 */
58 extern void mach_bridge_send_timestamp(uint64_t);
59
60 void
61 mach_bridge_timer_maintenance()
62 {
63 if (!bt_init_flag) {
64 return;
65 }
66
67 lck_spin_lock(bt_maintenance_lock);
68 if (!bt_enable_flag) {
69 goto done;
70 }
71 mach_bridge_send_timestamp(0);
72
73 done:
74 lck_spin_unlock(bt_maintenance_lock);
75 }
76
77 /*
78 * This function should be called only once from the callback
79 * registration function
80 */
81 void
82 mach_bridge_timer_init(void)
83 {
84 assert(!bt_init_flag);
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);
89 }
90
91 /*
92 * If change = 0, return the current value of bridge_timer_enable
93 * If change = 1, update bridge_timer_enable and return the updated
94 * value
95 */
96 uint32_t
97 mach_bridge_timer_enable(uint32_t new_value, int change)
98 {
99 uint32_t current_value = 0;
100 assert(bt_init_flag == 1);
101 lck_spin_lock(bt_maintenance_lock);
102 if (change) {
103 bt_enable_flag = new_value;
104 }
105 current_value = bt_enable_flag;
106 lck_spin_unlock(bt_maintenance_lock);
107 return current_value;
108 }
109
110 #endif /* CONFIG_MACH_BRIDGE_SEND_TIME */
111
112 #if CONFIG_MACH_BRIDGE_RECV_TIME
113 #include <machine/machine_remote_time.h>
114
115 /*
116 * functions used by machine-specific code
117 * that implements CONFIG_MACH_BRIDGE_RECV_TIME
118 */
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
123 /* function called by sysctl */
124 struct bt_params bt_params_get_latest(void);
125
126 /*
127 * Platform specific bridge time receiving interface.
128 * These variables should be exported by the platform specific time receiving code.
129 */
130 extern lck_spin_t *bt_spin_lock;
131 extern _Atomic uint32_t bt_init_flag;
132
133 static uint64_t received_local_timestamp = 0;
134 static uint64_t received_remote_timestamp = 0;
135 /*
136 * Buffer the previous timestamp pairs and rate
137 * It is protected by the ts_conversion_lock
138 */
139 #define BT_PARAMS_COUNT 10
140 static struct bt_params bt_params_hist[BT_PARAMS_COUNT] = {};
141 static int bt_params_idx = -1;
142
143 static inline void
144 bt_params_add(struct bt_params *params)
145 {
146 lck_spin_assert(ts_conversion_lock, LCK_ASSERT_OWNED);
147
148 bt_params_idx = (bt_params_idx + 1) % BT_PARAMS_COUNT;
149 bt_params_hist[bt_params_idx] = *params;
150 }
151
152 static inline struct bt_params*
153 bt_params_find(uint64_t local_ts)
154 {
155 lck_spin_assert(ts_conversion_lock, LCK_ASSERT_OWNED);
156
157 int idx = bt_params_idx;
158 if (idx < 0) {
159 return NULL;
160 }
161 do {
162 if (local_ts >= bt_params_hist[idx].base_local_ts) {
163 return &bt_params_hist[idx];
164 }
165 if (--idx < 0) {
166 idx = BT_PARAMS_COUNT - 1;
167 }
168 } while (idx != bt_params_idx);
169
170 return NULL;
171 }
172
173 struct bt_params
174 bt_params_get_latest(void)
175 {
176 struct bt_params latest_params = {};
177
178 /* Check if ts_converison_lock has been initialized */
179 if (atomic_load(&bt_init_flag)) {
180 lck_spin_lock(ts_conversion_lock);
181 if (bt_params_idx >= 0) {
182 latest_params = bt_params_hist[bt_params_idx];
183 }
184 lck_spin_unlock(ts_conversion_lock);
185 }
186 return latest_params;
187 }
188
189 /*
190 * Conditions: bt_spin_lock held and called from primary interrupt context
191 */
192 void
193 mach_bridge_add_timestamp(uint64_t remote_timestamp, uint64_t local_timestamp)
194 {
195 lck_spin_assert(bt_spin_lock, LCK_ASSERT_OWNED);
196
197 /* sleep/wake might return the same mach_absolute_time as the previous timestamp pair */
198 if ((received_local_timestamp == local_timestamp) ||
199 (received_remote_timestamp == remote_timestamp)) {
200 return;
201 }
202
203 received_local_timestamp = local_timestamp;
204 received_remote_timestamp = remote_timestamp;
205 thread_wakeup((event_t)bt_params_hist);
206 }
207
208 static double
209 mach_bridge_compute_rate(uint64_t new_local_ts, uint64_t new_remote_ts,
210 uint64_t old_local_ts, uint64_t old_remote_ts)
211 {
212 int64_t rdiff = (int64_t)new_remote_ts - (int64_t)old_remote_ts;
213 int64_t ldiff = (int64_t)new_local_ts - (int64_t)old_local_ts;
214 double calc_rate = ((double)rdiff) / ldiff;
215 return calc_rate;
216 }
217
218 #define MAX_RECALCULATE_COUNT 8
219 #define CUMULATIVE_RATE_DECAY_CONSTANT 0.01
220 #define CUMULATIVE_RATE_WEIGHT 0.99
221 #define INITIAL_RATE 1.0
222 #define MIN_INITIAL_SAMPLE_COUNT 10
223 #define MAX_INITIAL_SAMPLE_COUNT 50
224 #define MAX_SKIP_RESET_COUNT 2
225 #define MIN_LOCAL_TS_DISTANCE_NS 100000000 /* 100 ms */
226 #define MAX_LOCAL_TS_DISTANCE_NS 350000000 /* 350 ms */
227 #define TS_PAIR_MISMATCH_THRESHOLD_NS 50000000 /* 50 ms */
228 #define MAX_TS_PAIR_MISMATCHES 5
229 #define MAX_TS_PAIR_MISMATCH_RESET_COUNT 3
230 #define MIN_OBSERVED_RATE 0.8
231 #define MAX_OBSERVED_RATE 1.2
232
233 static void
234 bt_calibration_thread(void)
235 {
236 static uint64_t prev_local_ts = 0, prev_remote_ts = 0, curr_local_ts = 0, curr_remote_ts = 0;
237 static uint64_t prev_received_local_ts = 0, prev_received_remote_ts = 0;
238 static double cumulative_rate = INITIAL_RATE;
239 static uint32_t initial_sample_count = 1;
240 static uint32_t max_initial_sample_count = MAX_INITIAL_SAMPLE_COUNT;
241 static uint32_t skip_reset_count = MAX_SKIP_RESET_COUNT;
242 int recalculate_count = 1;
243 static bool reset = false;
244 bool sleep = false;
245 static bool skip_rcv_ts = false;
246 static uint64_t ts_pair_mismatch = 0;
247 static uint32_t ts_pair_mismatch_reset_count = 0;
248 spl_t s = splsched();
249 lck_spin_lock(bt_spin_lock);
250 if (!received_remote_timestamp) {
251 if (PE_parse_boot_argn("rt_ini_count", &max_initial_sample_count,
252 sizeof(uint32_t)) == TRUE) {
253 if (max_initial_sample_count < MIN_INITIAL_SAMPLE_COUNT) {
254 max_initial_sample_count = MIN_INITIAL_SAMPLE_COUNT;
255 }
256 }
257 /* Nothing to do the first time */
258 goto block;
259 }
260 /*
261 * The values in bt_params are recalculated every time a new timestamp
262 * pair is received. Firstly, both timestamps are converted to nanoseconds.
263 * The current and previous timestamp pairs are used to compute the
264 * observed_rate of the two clocks w.r.t each other. For the first
265 * MIN_INITIAL_SAMPLE_COUNT number of pairs, the cumulative_rate is a simple
266 * average of the observed_rate. For the later pairs, the cumulative_rate
267 * is updated using exponential moving average of the observed_rate.
268 * The current and bt_params' base timestamp pairs are used to compute
269 * the rate_from_base. This value ensures that the bt_params base
270 * timestamp pair curve doesn't stay parallel to the observed timestamp
271 * pair curve, rather moves in the direction of the observed timestamp curve.
272 * The bt_params.rate is computed as a weighted average of the cumulative_rate
273 * and the rate_from_base. For each current local timestamp, the remote_time
274 * is predicted using the previous values of bt_params. After computing the new
275 * bt_params.rate, bt_params.base_remote_time is set to this predicted value
276 * and bt_params.base_local_time is set to the current local timestamp.
277 */
278 recalculate:
279 assertf(recalculate_count <= MAX_RECALCULATE_COUNT, "bt_caliberation_thread: recalculate \
280 invocation exceeds MAX_RECALCULATE_COUNT");
281
282 if ((received_remote_timestamp == BT_RESET_SENTINEL_TS) || (received_remote_timestamp == BT_WAKE_SENTINEL_TS)) {
283 KDBG(MACHDBG_CODE(DBG_MACH_CLOCK, MACH_BRIDGE_RESET_TS), received_local_timestamp, received_remote_timestamp, 1);
284 reset = true;
285 skip_reset_count = MAX_SKIP_RESET_COUNT;
286 ts_pair_mismatch_reset_count = 0;
287 goto block;
288 } else if (received_remote_timestamp == BT_SLEEP_SENTINEL_TS) {
289 sleep = true;
290 } else if (!received_local_timestamp) {
291 /* If the local timestamp isn't accurately captured, the received value will be ignored */
292 skip_rcv_ts = true;
293 goto block;
294 }
295
296 /* Keep a copy of the prev timestamps to compute distance */
297 prev_received_local_ts = curr_local_ts;
298 prev_received_remote_ts = curr_remote_ts;
299
300 uint64_t curr_local_abs = received_local_timestamp;
301 absolutetime_to_nanoseconds(curr_local_abs, &curr_local_ts);
302 curr_remote_ts = received_remote_timestamp;
303
304 /* Prevent unusual rate changes caused by delayed timestamps */
305 uint64_t local_diff = curr_local_ts - prev_received_local_ts;
306 if (!(reset || sleep) && ((local_diff < MIN_LOCAL_TS_DISTANCE_NS) ||
307 (!skip_rcv_ts && (local_diff > MAX_LOCAL_TS_DISTANCE_NS)))) {
308 /* Skip the current timestamp */
309 KDBG(MACHDBG_CODE(DBG_MACH_CLOCK, MACH_BRIDGE_SKIP_TS), curr_local_ts, curr_remote_ts,
310 prev_received_local_ts);
311 goto block;
312 } else {
313 skip_rcv_ts = false;
314 /* Use the prev copy of timestamps only if the distance is acceptable */
315 prev_local_ts = prev_received_local_ts;
316 prev_remote_ts = prev_received_remote_ts;
317 }
318 lck_spin_unlock(bt_spin_lock);
319 splx(s);
320
321 struct bt_params bt_params = {};
322
323 lck_spin_lock(ts_conversion_lock);
324 if (reset) {
325 if (skip_reset_count > 0) {
326 KDBG(MACHDBG_CODE(DBG_MACH_CLOCK, MACH_BRIDGE_SKIP_TS), curr_local_ts, curr_remote_ts,
327 prev_local_ts, skip_reset_count);
328 skip_reset_count--;
329 goto skip_reset;
330 }
331 bt_params.base_local_ts = curr_local_ts;
332 bt_params.base_remote_ts = curr_remote_ts;
333 bt_params.rate = cumulative_rate;
334 prev_local_ts = 0;
335 prev_remote_ts = 0;
336 ts_pair_mismatch = 0;
337 initial_sample_count = 1;
338 reset = false;
339 KDBG(MACHDBG_CODE(DBG_MACH_CLOCK, MACH_BRIDGE_RESET_TS), curr_local_ts, curr_remote_ts, 2);
340 } else if (sleep) {
341 absolutetime_to_nanoseconds(mach_absolute_time(), &bt_params.base_local_ts);
342 bt_params.base_remote_ts = 0;
343 bt_params.rate = 0;
344 sleep = false;
345 } else {
346 struct bt_params bt_params_snapshot = {};
347 if (bt_params_idx >= 0) {
348 bt_params_snapshot = bt_params_hist[bt_params_idx];
349 }
350 lck_spin_unlock(ts_conversion_lock);
351 if (bt_params_snapshot.rate == 0.0) {
352 /*
353 * The rate should never be 0 because we always expect a reset/wake
354 * sentinel after sleep, followed by valid timestamp pair data that
355 * will be handled by the reset clause (above). However, we should
356 * not rely on a paired version of the remote OS - we could actually
357 * be running a completely different OS! Treat a timestamp after
358 * a sleep as a reset condition.
359 */
360 reset = true;
361 skip_reset_count = MAX_SKIP_RESET_COUNT;
362 ts_pair_mismatch_reset_count = 0;
363 KDBG(MACHDBG_CODE(DBG_MACH_CLOCK, MACH_BRIDGE_RESET_TS), curr_local_ts, curr_remote_ts, 3);
364 s = splsched();
365 lck_spin_lock(bt_spin_lock);
366 goto block;
367 }
368
369 /* Check if the predicted remote timestamp is within the expected current remote timestamp range */
370 uint64_t pred_remote_ts = mach_bridge_compute_timestamp(curr_local_ts, &bt_params_snapshot);
371 uint64_t diff = 0;
372 if (initial_sample_count >= max_initial_sample_count) {
373 if (pred_remote_ts > curr_remote_ts) {
374 diff = pred_remote_ts - curr_remote_ts;
375 } else {
376 diff = curr_remote_ts - pred_remote_ts;
377 }
378 if (diff > TS_PAIR_MISMATCH_THRESHOLD_NS) {
379 ts_pair_mismatch++;
380 KDBG(MACHDBG_CODE(DBG_MACH_CLOCK, MACH_BRIDGE_TS_MISMATCH), curr_local_ts,
381 curr_remote_ts, pred_remote_ts, ts_pair_mismatch);
382 } else {
383 ts_pair_mismatch = 0;
384 }
385 if (ts_pair_mismatch > MAX_TS_PAIR_MISMATCHES) {
386 #if (DEVELOPMENT || DEBUG)
387 if (ts_pair_mismatch_reset_count == MAX_TS_PAIR_MISMATCH_RESET_COUNT) {
388 panic("remote_time: timestamp pair mismatch exceeded limit");
389 }
390 #endif /* (DEVELOPMENT || DEBUG) */
391 reset = true;
392 ts_pair_mismatch_reset_count++;
393 KDBG(MACHDBG_CODE(DBG_MACH_CLOCK, MACH_BRIDGE_RESET_TS), curr_local_ts, curr_remote_ts, 4);
394 s = splsched();
395 lck_spin_lock(bt_spin_lock);
396 goto block;
397 }
398 }
399 double observed_rate, rate_from_base, new_rate;
400 observed_rate = mach_bridge_compute_rate(curr_local_ts, curr_remote_ts, prev_local_ts, prev_remote_ts);
401 /* Log bad observed rates and skip the timestamp pair */
402 if ((observed_rate < MIN_OBSERVED_RATE) || (observed_rate > MAX_OBSERVED_RATE)) {
403 KDBG(MACHDBG_CODE(DBG_MACH_CLOCK, MACH_BRIDGE_OBSV_RATE), *(uint64_t *)((void *)&observed_rate));
404 ts_pair_mismatch = ts_pair_mismatch > 0 ? (ts_pair_mismatch - 1) : 0;
405 s = splsched();
406 lck_spin_lock(bt_spin_lock);
407 goto block;
408 }
409 if (initial_sample_count <= MIN_INITIAL_SAMPLE_COUNT) {
410 initial_sample_count++;
411 cumulative_rate = cumulative_rate + (observed_rate - cumulative_rate) / initial_sample_count;
412 } else {
413 if (initial_sample_count < max_initial_sample_count) {
414 initial_sample_count++;
415 }
416 cumulative_rate = cumulative_rate + CUMULATIVE_RATE_DECAY_CONSTANT * (observed_rate - cumulative_rate);
417 }
418 rate_from_base = mach_bridge_compute_rate(curr_local_ts, curr_remote_ts, bt_params_snapshot.base_local_ts,
419 bt_params_snapshot.base_remote_ts);
420 new_rate = CUMULATIVE_RATE_WEIGHT * cumulative_rate + (1 - CUMULATIVE_RATE_WEIGHT) * rate_from_base;
421 /*
422 * Acquire the lock first to ensure that bt_params.base_local_ts is always
423 * greater than the last value of now captured by mach_bridge_remote_time.
424 * This ensures that we always use the same parameters to compute remote
425 * timestamp for a given local timestamp.
426 */
427 lck_spin_lock(ts_conversion_lock);
428 absolutetime_to_nanoseconds(mach_absolute_time(), &bt_params.base_local_ts);
429 bt_params.base_remote_ts = mach_bridge_compute_timestamp(bt_params.base_local_ts, &bt_params_snapshot);
430 bt_params.rate = new_rate;
431 }
432 bt_params_add(&bt_params);
433 commpage_set_remotetime_params(bt_params.rate, bt_params.base_local_ts, bt_params.base_remote_ts);
434 KDBG(MACHDBG_CODE(DBG_MACH_CLOCK, MACH_BRIDGE_TS_PARAMS), bt_params.base_local_ts,
435 bt_params.base_remote_ts, *(uint64_t *)((void *)&bt_params.rate));
436
437 skip_reset:
438 lck_spin_unlock(ts_conversion_lock);
439
440 s = splsched();
441 lck_spin_lock(bt_spin_lock);
442 /* Check if a new timestamp pair was received */
443 if (received_local_timestamp != curr_local_abs) {
444 recalculate_count++;
445 goto recalculate;
446 }
447 block:
448 assert_wait((event_t)bt_params_hist, THREAD_UNINT);
449 lck_spin_unlock(bt_spin_lock);
450 splx(s);
451 thread_block((thread_continue_t)bt_calibration_thread);
452 }
453
454 void
455 bt_calibration_thread_start(void)
456 {
457 thread_t thread;
458 kern_return_t result = kernel_thread_start_priority((thread_continue_t)bt_calibration_thread,
459 NULL, BASEPRI_KERNEL, &thread);
460 if (result != KERN_SUCCESS) {
461 panic("mach_bridge_add_timestamp: thread_timestamp_calibration");
462 }
463 thread_deallocate(thread);
464 }
465
466 #endif /* CONFIG_MACH_BRIDGE_RECV_TIME */
467
468 /**
469 * mach_bridge_remote_time
470 *
471 * This function is used to predict the remote CPU's clock time, given
472 * the local time.
473 *
474 * If local_timestamp = 0, then the remote_timestamp is calculated
475 * corresponding to the current mach_absolute_time. Monotonicity of
476 * predicted time is guaranteed only for recent local_timestamp values
477 * lesser than the current mach_absolute_time upto 1 second.
478 *
479 * If CONFIG_MACH_BRIDGE_SEND_TIME is true, then the function is compiled
480 * for the remote CPU. If CONFIG_MACH_BRIDGE_RECV_TIME is true, then the
481 * the function is compiled for the local CPU. Both config options cannot
482 * be true simultaneously.
483 */
484 uint64_t
485 mach_bridge_remote_time(uint64_t local_timestamp)
486 {
487 #if defined(CONFIG_MACH_BRIDGE_SEND_TIME)
488 #if !defined(CONFIG_MACH_BRIDGE_RECV_TIME)
489 /* only send side of the bridge is defined: no translation needed */
490 if (!local_timestamp) {
491 return mach_absolute_time();
492 }
493 return 0;
494 #else
495 #error "You cannot define both sides of the bridge!"
496 #endif /* !defined(CONFIG_MACH_BRIDGE_RECV_TIME) */
497 #else
498 #if !defined(CONFIG_MACH_BRIDGE_RECV_TIME)
499 /* neither the send or receive side of the bridge is defined: echo the input */
500 return local_timestamp;
501 #else
502 if (!atomic_load(&bt_init_flag)) {
503 return 0;
504 }
505
506 lck_spin_lock(ts_conversion_lock);
507 uint64_t now = mach_absolute_time();
508
509 uint64_t remote_timestamp = 0;
510 uint64_t local_timestamp_ns = 0;
511 if (!local_timestamp) {
512 local_timestamp = now;
513 } else if (local_timestamp > now) {
514 goto out_unlock;
515 }
516 absolutetime_to_nanoseconds(local_timestamp, &local_timestamp_ns);
517 struct bt_params *params = bt_params_find(local_timestamp_ns);
518 remote_timestamp = mach_bridge_compute_timestamp(local_timestamp_ns, params);
519
520 out_unlock:
521 lck_spin_unlock(ts_conversion_lock);
522 KDBG(MACHDBG_CODE(DBG_MACH_CLOCK, MACH_BRIDGE_REMOTE_TIME), local_timestamp, remote_timestamp, now);
523 return remote_timestamp;
524 #endif /* !defined(CONFIG_MACH_BRIDGE_RECV_TIME) */
525 #endif /* defined(CONFIG_MACH_BRIDGE_SEND_TIME) */
526 }