+/*
+ * get_scale_factors_from_adj:
+ *
+ * computes scale factors from the value given in adjustment.
+ *
+ * Part of the code has been taken from tc_windup of FreeBSD
+ * written by Poul-Henning Kamp <phk@FreeBSD.ORG>, Julien Ridoux and
+ * Konstantin Belousov.
+ * https://github.com/freebsd/freebsd/blob/master/sys/kern/kern_tc.c
+ */
+static void
+get_scale_factors_from_adj(int64_t adjustment, uint64_t* tick_scale_x, uint64_t* s_scale_ns, int64_t* s_adj_nsx)
+{
+ uint64_t scale;
+ int64_t nano, frac;
+
+ /*-
+ * Calculating the scaling factor. We want the number of 1/2^64
+ * fractions of a second per period of the hardware counter, taking
+ * into account the th_adjustment factor which the NTP PLL/adjtime(2)
+ * processing provides us with.
+ *
+ * The th_adjustment is nanoseconds per second with 32 bit binary
+ * fraction and we want 64 bit binary fraction of second:
+ *
+ * x = a * 2^32 / 10^9 = a * 4.294967296
+ *
+ * The range of th_adjustment is +/- 5000PPM so inside a 64bit int
+ * we can only multiply by about 850 without overflowing, that
+ * leaves no suitably precise fractions for multiply before divide.
+ *
+ * Divide before multiply with a fraction of 2199/512 results in a
+ * systematic undercompensation of 10PPM of th_adjustment. On a
+ * 5000PPM adjustment this is a 0.05PPM error. This is acceptable.
+ *
+ * We happily sacrifice the lowest of the 64 bits of our result
+ * to the goddess of code clarity.
+ *
+ */
+ scale = (uint64_t)1 << 63;
+ scale += (adjustment / 1024) * 2199;
+ scale /= ticks_per_sec;
+ *tick_scale_x = scale * 2;
+
+ /*
+ * hi part of adj
+ * it contains ns (without fraction) to add to the next sec.
+ * Get ns scale factor for the next sec.
+ */
+ nano = (adjustment > 0)? adjustment >> 32 : -((-adjustment) >> 32);
+ scale = (uint64_t) NSEC_PER_SEC;
+ scale += nano;
+ *s_scale_ns = scale;
+
+ /*
+ * lo part of adj
+ * it contains 32 bit frac of ns to add to the next sec.
+ * Keep it as additional adjustment for the next sec.
+ */
+ frac = (adjustment > 0)? ((uint32_t) adjustment) : -((uint32_t) (-adjustment));
+ *s_adj_nsx = (frac>0)? frac << 32 : -( (-frac) << 32);
+
+ return;
+}
+
+/*
+ * scale_delta:
+ *
+ * returns a bintime struct representing delta scaled accordingly to the
+ * scale factors provided to this function.
+ */
+static struct bintime
+scale_delta(uint64_t delta, uint64_t tick_scale_x, uint64_t s_scale_ns, int64_t s_adj_nsx)
+{
+ uint64_t sec, new_ns, over;
+ struct bintime bt;
+
+ bt.sec = 0;
+ bt.frac = 0;
+
+ /*
+ * If more than one second is elapsed,
+ * scale fully elapsed seconds using scale factors for seconds.
+ * s_scale_ns -> scales sec to ns.
+ * s_adj_nsx -> additional adj expressed in 64 bit frac of ns to apply to each sec.
+ */
+ if (delta > ticks_per_sec) {
+ sec = (delta/ticks_per_sec);
+ new_ns = sec * s_scale_ns;
+ bintime_addns(&bt, new_ns);
+ if (s_adj_nsx) {
+ if (sec == 1) {
+ /* shortcut, no overflow can occur */
+ if (s_adj_nsx > 0)
+ bintime_addx(&bt, (uint64_t)s_adj_nsx/ (uint64_t)NSEC_PER_SEC);
+ else
+ bintime_subx(&bt, (uint64_t)-s_adj_nsx/ (uint64_t)NSEC_PER_SEC);
+ }
+ else{
+ /*
+ * s_adj_nsx is 64 bit frac of ns.
+ * sec*s_adj_nsx might overflow in int64_t.
+ * use bintime_addxns to not lose overflowed ns.
+ */
+ bintime_addxns(&bt, sec, s_adj_nsx);
+ }
+ }
+ delta = (delta % ticks_per_sec);
+ }
+
+ over = multi_overflow(tick_scale_x, delta);
+ if(over){
+ bt.sec += over;
+ }
+
+ /*
+ * scale elapsed ticks using the scale factor for ticks.
+ */
+ bintime_addx(&bt, delta * tick_scale_x);
+
+ return bt;
+}
+
+/*
+ * get_scaled_time:
+ *
+ * returns the scaled time of the time elapsed from the last time
+ * scale factors were updated to now.
+ */
+static struct bintime
+get_scaled_time(uint64_t now)
+{
+ uint64_t delta;
+
+ /*
+ * Compute ticks elapsed since last scale update.
+ * This time will be scaled according to the value given by ntp kern.
+ */
+ delta = now - clock_calend.offset_count;
+
+ return scale_delta(delta, clock_calend.tick_scale_x, clock_calend.s_scale_ns, clock_calend.s_adj_nsx);
+}
+
+static void
+clock_get_calendar_absolute_and_microtime_locked(
+ clock_sec_t *secs,
+ clock_usec_t *microsecs,
+ uint64_t *abstime)
+{
+ uint64_t now;
+ struct bintime bt;
+
+ now = mach_absolute_time();
+ if (abstime)
+ *abstime = now;
+
+ bt = get_scaled_time(now);
+ bintime_add(&bt, &clock_calend.bintime);
+ bintime2usclock(&bt, secs, microsecs);
+}
+
+static void
+clock_get_calendar_absolute_and_nanotime_locked(
+ clock_sec_t *secs,
+ clock_usec_t *nanosecs,
+ uint64_t *abstime)
+{
+ uint64_t now;
+ struct bintime bt;
+
+ now = mach_absolute_time();
+ if (abstime)
+ *abstime = now;
+
+ bt = get_scaled_time(now);
+ bintime_add(&bt, &clock_calend.bintime);
+ bintime2nsclock(&bt, secs, nanosecs);
+}
+