]>
Commit | Line | Data |
---|---|---|
0a7de745 A |
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 | */ | |
0a7de745 A |
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> | |
33 | #include <kern/spl.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> | |
cb323159 | 41 | #include <machine/atomic.h> |
0a7de745 A |
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 | |
cb323159 | 61 | mach_bridge_timer_maintenance(void) |
0a7de745 | 62 | { |
cb323159 | 63 | if (!os_atomic_load(&bt_init_flag, acquire)) { |
0a7de745 A |
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 | { | |
cb323159 | 84 | assert(!os_atomic_load(&bt_init_flag, relaxed)); |
0a7de745 A |
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; | |
cb323159 | 100 | assert(os_atomic_load(&bt_init_flag, relaxed)); |
0a7de745 A |
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; | |
cb323159 | 122 | void bt_params_add(struct bt_params *params); |
0a7de745 A |
123 | |
124 | /* function called by sysctl */ | |
125 | struct bt_params bt_params_get_latest(void); | |
126 | ||
127 | /* | |
128 | * Platform specific bridge time receiving interface. | |
129 | * These variables should be exported by the platform specific time receiving code. | |
130 | */ | |
131 | extern lck_spin_t *bt_spin_lock; | |
132 | extern _Atomic uint32_t bt_init_flag; | |
133 | ||
134 | static uint64_t received_local_timestamp = 0; | |
135 | static uint64_t received_remote_timestamp = 0; | |
136 | /* | |
137 | * Buffer the previous timestamp pairs and rate | |
138 | * It is protected by the ts_conversion_lock | |
139 | */ | |
140 | #define BT_PARAMS_COUNT 10 | |
141 | static struct bt_params bt_params_hist[BT_PARAMS_COUNT] = {}; | |
142 | static int bt_params_idx = -1; | |
143 | ||
cb323159 | 144 | void |
0a7de745 A |
145 | bt_params_add(struct bt_params *params) |
146 | { | |
147 | lck_spin_assert(ts_conversion_lock, LCK_ASSERT_OWNED); | |
148 | ||
149 | bt_params_idx = (bt_params_idx + 1) % BT_PARAMS_COUNT; | |
150 | bt_params_hist[bt_params_idx] = *params; | |
151 | } | |
152 | ||
cb323159 | 153 | #if defined(XNU_TARGET_OS_BRIDGE) |
0a7de745 A |
154 | static inline struct bt_params* |
155 | bt_params_find(uint64_t local_ts) | |
156 | { | |
157 | lck_spin_assert(ts_conversion_lock, LCK_ASSERT_OWNED); | |
158 | ||
159 | int idx = bt_params_idx; | |
160 | if (idx < 0) { | |
161 | return NULL; | |
162 | } | |
163 | do { | |
164 | if (local_ts >= bt_params_hist[idx].base_local_ts) { | |
165 | return &bt_params_hist[idx]; | |
166 | } | |
167 | if (--idx < 0) { | |
168 | idx = BT_PARAMS_COUNT - 1; | |
169 | } | |
170 | } while (idx != bt_params_idx); | |
171 | ||
172 | return NULL; | |
173 | } | |
cb323159 A |
174 | #endif /* defined(XNU_TARGET_OS_BRIDGE) */ |
175 | ||
176 | static inline struct bt_params | |
177 | bt_params_get_latest_locked(void) | |
178 | { | |
179 | lck_spin_assert(ts_conversion_lock, LCK_ASSERT_OWNED); | |
180 | ||
181 | struct bt_params latest_params = {}; | |
182 | if (bt_params_idx >= 0) { | |
183 | latest_params = bt_params_hist[bt_params_idx]; | |
184 | } | |
185 | ||
186 | return latest_params; | |
187 | } | |
0a7de745 A |
188 | |
189 | struct bt_params | |
190 | bt_params_get_latest(void) | |
191 | { | |
192 | struct bt_params latest_params = {}; | |
193 | ||
194 | /* Check if ts_converison_lock has been initialized */ | |
cb323159 | 195 | if (os_atomic_load(&bt_init_flag, acquire)) { |
0a7de745 | 196 | lck_spin_lock(ts_conversion_lock); |
cb323159 | 197 | latest_params = bt_params_get_latest_locked(); |
0a7de745 A |
198 | lck_spin_unlock(ts_conversion_lock); |
199 | } | |
200 | return latest_params; | |
201 | } | |
202 | ||
203 | /* | |
204 | * Conditions: bt_spin_lock held and called from primary interrupt context | |
205 | */ | |
206 | void | |
207 | mach_bridge_add_timestamp(uint64_t remote_timestamp, uint64_t local_timestamp) | |
208 | { | |
209 | lck_spin_assert(bt_spin_lock, LCK_ASSERT_OWNED); | |
210 | ||
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)) { | |
214 | return; | |
215 | } | |
216 | ||
217 | received_local_timestamp = local_timestamp; | |
218 | received_remote_timestamp = remote_timestamp; | |
219 | thread_wakeup((event_t)bt_params_hist); | |
220 | } | |
221 | ||
222 | static double | |
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) | |
225 | { | |
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; | |
229 | return calc_rate; | |
230 | } | |
231 | ||
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 | |
246 | ||
247 | static void | |
248 | bt_calibration_thread(void) | |
249 | { | |
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; | |
258 | bool sleep = 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; | |
269 | } | |
270 | } | |
271 | /* Nothing to do the first time */ | |
272 | goto block; | |
273 | } | |
274 | /* | |
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. | |
291 | */ | |
292 | recalculate: | |
293 | assertf(recalculate_count <= MAX_RECALCULATE_COUNT, "bt_caliberation_thread: recalculate \ | |
294 | invocation exceeds MAX_RECALCULATE_COUNT"); | |
295 | ||
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); | |
298 | reset = true; | |
299 | skip_reset_count = MAX_SKIP_RESET_COUNT; | |
300 | ts_pair_mismatch_reset_count = 0; | |
301 | goto block; | |
302 | } else if (received_remote_timestamp == BT_SLEEP_SENTINEL_TS) { | |
303 | sleep = true; | |
304 | } else if (!received_local_timestamp) { | |
305 | /* If the local timestamp isn't accurately captured, the received value will be ignored */ | |
306 | skip_rcv_ts = true; | |
307 | goto block; | |
308 | } | |
309 | ||
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; | |
313 | ||
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; | |
317 | ||
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); | |
325 | goto block; | |
326 | } else { | |
327 | skip_rcv_ts = false; | |
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; | |
331 | } | |
332 | lck_spin_unlock(bt_spin_lock); | |
333 | splx(s); | |
334 | ||
335 | struct bt_params bt_params = {}; | |
336 | ||
337 | lck_spin_lock(ts_conversion_lock); | |
338 | if (reset) { | |
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); | |
342 | skip_reset_count--; | |
343 | goto skip_reset; | |
344 | } | |
345 | bt_params.base_local_ts = curr_local_ts; | |
346 | bt_params.base_remote_ts = curr_remote_ts; | |
347 | bt_params.rate = cumulative_rate; | |
348 | prev_local_ts = 0; | |
349 | prev_remote_ts = 0; | |
350 | ts_pair_mismatch = 0; | |
351 | initial_sample_count = 1; | |
352 | reset = false; | |
353 | KDBG(MACHDBG_CODE(DBG_MACH_CLOCK, MACH_BRIDGE_RESET_TS), curr_local_ts, curr_remote_ts, 2); | |
354 | } else if (sleep) { | |
355 | absolutetime_to_nanoseconds(mach_absolute_time(), &bt_params.base_local_ts); | |
356 | bt_params.base_remote_ts = 0; | |
357 | bt_params.rate = 0; | |
358 | sleep = false; | |
359 | } else { | |
360 | struct bt_params bt_params_snapshot = {}; | |
361 | if (bt_params_idx >= 0) { | |
362 | bt_params_snapshot = bt_params_hist[bt_params_idx]; | |
363 | } | |
364 | lck_spin_unlock(ts_conversion_lock); | |
365 | if (bt_params_snapshot.rate == 0.0) { | |
366 | /* | |
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. | |
373 | */ | |
374 | reset = true; | |
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); | |
378 | s = splsched(); | |
379 | lck_spin_lock(bt_spin_lock); | |
380 | goto block; | |
381 | } | |
382 | ||
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); | |
385 | uint64_t diff = 0; | |
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; | |
389 | } else { | |
390 | diff = curr_remote_ts - pred_remote_ts; | |
391 | } | |
392 | if (diff > TS_PAIR_MISMATCH_THRESHOLD_NS) { | |
393 | ts_pair_mismatch++; | |
394 | KDBG(MACHDBG_CODE(DBG_MACH_CLOCK, MACH_BRIDGE_TS_MISMATCH), curr_local_ts, | |
395 | curr_remote_ts, pred_remote_ts, ts_pair_mismatch); | |
396 | } else { | |
397 | ts_pair_mismatch = 0; | |
398 | } | |
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"); | |
403 | } | |
404 | #endif /* (DEVELOPMENT || DEBUG) */ | |
405 | reset = true; | |
406 | ts_pair_mismatch_reset_count++; | |
407 | KDBG(MACHDBG_CODE(DBG_MACH_CLOCK, MACH_BRIDGE_RESET_TS), curr_local_ts, curr_remote_ts, 4); | |
408 | s = splsched(); | |
409 | lck_spin_lock(bt_spin_lock); | |
410 | goto block; | |
411 | } | |
412 | } | |
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; | |
419 | s = splsched(); | |
420 | lck_spin_lock(bt_spin_lock); | |
421 | goto block; | |
422 | } | |
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; | |
426 | } else { | |
427 | if (initial_sample_count < max_initial_sample_count) { | |
428 | initial_sample_count++; | |
429 | } | |
430 | cumulative_rate = cumulative_rate + CUMULATIVE_RATE_DECAY_CONSTANT * (observed_rate - cumulative_rate); | |
431 | } | |
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; | |
435 | /* | |
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. | |
440 | */ | |
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; | |
445 | } | |
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)); | |
450 | ||
451 | skip_reset: | |
452 | lck_spin_unlock(ts_conversion_lock); | |
453 | ||
454 | s = splsched(); | |
455 | lck_spin_lock(bt_spin_lock); | |
456 | /* Check if a new timestamp pair was received */ | |
457 | if (received_local_timestamp != curr_local_abs) { | |
458 | recalculate_count++; | |
459 | goto recalculate; | |
460 | } | |
461 | block: | |
462 | assert_wait((event_t)bt_params_hist, THREAD_UNINT); | |
463 | lck_spin_unlock(bt_spin_lock); | |
464 | splx(s); | |
465 | thread_block((thread_continue_t)bt_calibration_thread); | |
466 | } | |
467 | ||
468 | void | |
469 | bt_calibration_thread_start(void) | |
470 | { | |
471 | thread_t thread; | |
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"); | |
476 | } | |
477 | thread_deallocate(thread); | |
478 | } | |
479 | ||
480 | #endif /* CONFIG_MACH_BRIDGE_RECV_TIME */ | |
481 | ||
482 | /** | |
483 | * mach_bridge_remote_time | |
484 | * | |
485 | * This function is used to predict the remote CPU's clock time, given | |
486 | * the local time. | |
487 | * | |
488 | * If local_timestamp = 0, then the remote_timestamp is calculated | |
cb323159 A |
489 | * corresponding to the current mach_absolute_time. |
490 | * | |
491 | * If XNU_TARGET_OS_BRIDGE is defined, then monotonicity of | |
0a7de745 A |
492 | * predicted time is guaranteed only for recent local_timestamp values |
493 | * lesser than the current mach_absolute_time upto 1 second. | |
494 | * | |
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. | |
499 | */ | |
500 | uint64_t | |
501 | mach_bridge_remote_time(uint64_t local_timestamp) | |
502 | { | |
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(); | |
508 | } | |
509 | return 0; | |
510 | #else | |
511 | #error "You cannot define both sides of the bridge!" | |
512 | #endif /* !defined(CONFIG_MACH_BRIDGE_RECV_TIME) */ | |
513 | #else | |
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; | |
517 | #else | |
cb323159 | 518 | if (!os_atomic_load(&bt_init_flag, acquire)) { |
0a7de745 A |
519 | return 0; |
520 | } | |
521 | ||
cb323159 A |
522 | uint64_t remote_timestamp = 0; |
523 | ||
0a7de745 A |
524 | lck_spin_lock(ts_conversion_lock); |
525 | uint64_t now = mach_absolute_time(); | |
0a7de745 A |
526 | if (!local_timestamp) { |
527 | local_timestamp = now; | |
0a7de745 | 528 | } |
cb323159 A |
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); | |
535 | } | |
536 | #else | |
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) */ | |
0a7de745 A |
540 | lck_spin_unlock(ts_conversion_lock); |
541 | KDBG(MACHDBG_CODE(DBG_MACH_CLOCK, MACH_BRIDGE_REMOTE_TIME), local_timestamp, remote_timestamp, now); | |
cb323159 | 542 | |
0a7de745 A |
543 | return remote_timestamp; |
544 | #endif /* !defined(CONFIG_MACH_BRIDGE_RECV_TIME) */ | |
545 | #endif /* defined(CONFIG_MACH_BRIDGE_SEND_TIME) */ | |
546 | } |