blob: a89a3c1d9edaff000a48be2ccbebfa4762ca6e06 [file] [log] [blame] [edit]
// Copyright 2016 The Fuchsia Authors
// Copyright (c) 2008 Travis Geiselbrecht
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#ifndef ZIRCON_KERNEL_INCLUDE_PLATFORM_TIMER_H_
#define ZIRCON_KERNEL_INCLUDE_PLATFORM_TIMER_H_
#include <assert.h>
#include <lib/arch/ticks.h>
#include <zircon/compiler.h>
#include <zircon/time.h>
#include <zircon/types.h>
#include <fbl/enum_bits.h>
#include <ktl/atomic.h>
#include <ktl/optional.h>
#include <ktl/type_traits.h>
namespace internal {
// A modifier that converts a raw ticks counter value to a point on the monotonic ticks timeline.
// This modifier has three different modes of operation.
// 1. If the value is ZX_TIME_INFINITE_PAST, then the modifier is being updated and all attempts
// to read it should be retried.
// 2. If the value is positive (> 0), the monotonic clock is paused and this variable contains the
// value of the clock when it was paused.
// 3. If the value is non-positive (<= 0), the monotonic clock is ticking and this variable contains
// the offset between the monotonic ticks and the raw ticks counter.
inline ktl::atomic<zx_ticks_t> mono_ticks_modifier{0};
// This threshold detects when the initial ticks offset is set to a value that is "Very Close" to
// setting bit 63. This would be a problem because modifying bit 63 would change the sign of the
// offset value, which would then break our ability to use the sign as a sentinel that indicates
// how the mono_ticks_modifier value should be interpreted (see the comment around that variable
// for more information on how that works).
//
// "Very Close" in this case means a value that is within approximately 10 years of setting bit 63,
// assuming a clock rate of 10ghz.
inline constexpr zx_ticks_t kMonoTicksOopsThreshold =
0x8000'0000'0000'0000ul -
(static_cast<uint64_t>(365.2422 * 10 * 86400) * // 10 years of seconds
10'000'000'000); // 10GHz
// Offset between the raw ticks counter and the boot ticks timeline.
inline ktl::atomic<uint64_t> boot_ticks_offset{0};
} // namespace internal
// Sets the initial ticks offset. This offset is used to ensure that both the boot and monotonic
// timelines start at 0.
//
// Must be called with interrupts disabled, before secondary CPUs are booted.
inline void timer_set_initial_ticks_offset(uint64_t offset) {
// Check that the new offset is non-positive. If it's not, this is an immediate failure.
const zx_ticks_t new_mono_offset = static_cast<zx_ticks_t>(offset);
DEBUG_ASSERT(new_mono_offset <= 0);
// Now, verify that the offset is not "dangerously close" to setting bit 63. If it is, emit
// a KERNEL OOPS. We have to negate the new_mono_offset as it's passed in as the negation of the
// current value of the ticks counter, and we want to undo that before comparing to the threshold.
if ((-new_mono_offset) > internal::kMonoTicksOopsThreshold) {
KERNEL_OOPS("initial ticks offset %ld is very close to setting the bit 63\n", new_mono_offset);
}
internal::mono_ticks_modifier.store(new_mono_offset, ktl::memory_order_relaxed);
internal::boot_ticks_offset.store(offset, ktl::memory_order_relaxed);
}
// Converts a ticks value on the monotonic timeline to a raw hardware ticks value.
// Returns the raw ticks value if the monotonic clock is not paused, and nullopt if it is.
inline ktl::optional<zx_ticks_t> timer_convert_mono_to_raw_ticks(
zx_instant_mono_ticks_t mono_ticks) {
const zx_ticks_t modifier = internal::mono_ticks_modifier.load(ktl::memory_order_relaxed);
if (modifier > 0) {
return ktl::nullopt;
}
return ktl::optional<zx_ticks_t>(zx_ticks_sub_ticks(mono_ticks, modifier));
}
// Access the platform specific offset from the raw ticks timeline to the monotonic ticks
// timeline. The only current legit uses for this function are when
// initializing the RO data for the VDSO, and when fixing up timer values during
// vmexit on ARM (see arch/arm64/hypervisor/vmexit.cc).
inline zx_ticks_t timer_get_mono_ticks_offset() {
const zx_ticks_t offset = internal::mono_ticks_modifier.load(ktl::memory_order_relaxed);
DEBUG_ASSERT(offset <= 0);
return offset;
}
// Access the offset from the raw ticks timeline to the boot ticks timeline.
inline zx_ticks_t timer_get_boot_ticks_offset() {
return internal::boot_ticks_offset.load(ktl::memory_order_relaxed);
}
// API to set/clear a hardware timer that is responsible for calling timer_tick() when it fires.
zx_status_t platform_set_oneshot_timer(zx_ticks_t deadline);
void platform_stop_timer();
// Shutdown the calling CPU's platform timer.
//
// Should be called after |platform_stop_timer|, but before taking the CPU offline.
//
// TODO(maniscalco): Provide a "resume" function so we can suspend/resume.
void platform_shutdown_timer();
// Suspend the platform timer for the calling CPU.
//
// It is an error to call this function with interrupts enabled.
zx_status_t platform_suspend_timer_curr_cpu();
// Resume the platform timer for the calling CPU.
//
// It is an error to call this function with interrupts enabled.
zx_status_t platform_resume_timer_curr_cpu();
void timer_tick();
// A bool indicating whether or not user mode has direct access to the registers
// which allow directly observing the tick counter or not.
bool platform_usermode_can_access_tick_registers();
// Current monotonic time in nanoseconds.
zx_instant_mono_t current_mono_time();
// Current boot time in nanoseconds.
zx_instant_boot_t current_boot_time();
// Monotonic and boot time representing the same instant in both timelines.
struct InstantMonoAndBootTime {
zx_instant_mono_t mono_time;
zx_instant_boot_t boot_time;
};
// Current monotonic and boot time in nanoseconds, derived from a coherent
// observation of the offsets and raw ticks.
InstantMonoAndBootTime current_mono_and_boot_time();
// Monotonic time and boot ticks representing same instant in both timelines.
// This is primarily useful for lining up samples of monotonic time with
// corresponding trace events, which use boot ticks, so that computed and
// visualized intervals are accurate.
struct InstantMonoTimeAndBootTicks {
zx_instant_mono_t mono_time;
zx_instant_boot_ticks_t boot_ticks;
};
// Current monotonic time in nanoseconds and boot ticks, derived from a coherent
// observation of the offsets and raw ticks.
InstantMonoTimeAndBootTicks current_mono_time_and_boot_ticks();
// High-precision timer ticks per second.
zx_ticks_t ticks_per_second();
namespace affine {
class Ratio; // Fwd decl.
} // namespace affine
// Setter/getter pair for the ratio which defines the relationship between the
// system's tick counter, and the current_time/clock_monotonic clock. This gets
// set once by architecture specific platform code, after an appropriate ticks
// source has been selected and characterized.
void timer_set_ticks_to_time_ratio(const affine::Ratio& ticks_to_time);
const affine::Ratio& timer_get_ticks_to_time_ratio();
// Convert a sample taken early on to a proper zx_ticks_t, if possible.
// This returns 0 if early samples are not convertible.
zx_ticks_t platform_convert_early_ticks(arch::EarlyTicks sample);
// A special version of `current_ticks` which is explicitly synchronized with
// memory loads/stores in an architecture/timer specific way. For example, when
// using TSC as the ticks reference on an x64 system, there is nothing
// explicitly preventing the actual read of the TSC finishing before or after
// previous/subsequent loads/stores (unless we are talking about a subsequent
// store which has a dependency on the TSC read).
//
// Most of the time, this does not matter, but occasionally it can be an issue.
// For example, some algorithms need to record a timestamp while inside of a
// critical section (either shared or exclusive). While the implementation of
// the synchronization object typically uses atomics and explicit C++ memory
// order annotations to be sure that (for example) stores to some payload done
// by a thread with exclusive access to the payload "happen-before" any
// subsequent loads from threads with shared access to the payload, accesses to
// the ticks reference on a system is typically not constrained by such
// dependencies.
//
// Without special care, the time observed on the system timer can actually
// occur before/after any loads or stores which are part of the entry/exit
// into/out-of the critical section.
//
// In such situations, timer_current_mono_ticks_synchronized can be used instead
// to order to contain the timer observation. Users pass (via template args) a
// set of flags which cause appropriate architecture specific barriers to be
// inserted before/after the ticks reference observation in order to contain it.
// Specifically, users can demand that the observation must take place:
//
// + After any previous loads
// + After any previous stores
// + Before any subsequent loads
// + Before any subsequent stores
//
// or any combination of the above. Some timer/architecture combinations might
// require even more strict synchronization than was requested, but all should
// provide at least the minimum level of synchronization to satisfy the request.
enum class GetTicksSyncFlag : uint8_t {
kNone = 0,
kAfterPreviousLoads = (1 << 0),
kAfterPreviousStores = (1 << 1),
kBeforeSubsequentLoads = (1 << 2),
kBeforeSubsequentStores = (1 << 3),
};
FBL_ENABLE_ENUM_BITS(GetTicksSyncFlag)
// Reads a platform-specific ticks counter.
//
// This function is required to return zero if it is invoked before the timer hardware is
// initialized. Not doing so could violate the monotonicity of both the monotonic and boot
// timelines.
//
// This raw counter value is almost certainly not what you want; callers generally want to use the
// monotonic ticks value provided by timer_current_mono_ticks. This ticks value is the raw counter
// adjusted by a constant used to make the ticks timeline start ticking from 0 when the system
// boots.
template <GetTicksSyncFlag Flags>
zx_ticks_t platform_current_raw_ticks_synchronized();
inline zx_ticks_t platform_current_raw_ticks() {
return platform_current_raw_ticks_synchronized<GetTicksSyncFlag::kNone>();
}
template <GetTicksSyncFlag Flags>
inline zx_instant_mono_ticks_t timer_current_mono_ticks_synchronized() {
while (true) {
const zx_ticks_t obs1 = internal::mono_ticks_modifier.load(ktl::memory_order_relaxed);
const zx_ticks_t raw_ticks = platform_current_raw_ticks_synchronized<Flags>();
const zx_ticks_t obs2 = internal::mono_ticks_modifier.load(ktl::memory_order_relaxed);
if (obs1 == obs2 && obs1 != ZX_TIME_INFINITE_PAST) {
// If the observation is positive, it's the value of the paused monotonic clock, so return
// the observation directly. Otherwise, it's an offset, so return the sum of the observation
// and the raw ticks counter.
if (unlikely(obs1 > 0)) {
return obs1;
}
return raw_ticks + obs1;
}
}
}
inline zx_instant_mono_ticks_t timer_current_mono_ticks() {
return timer_current_mono_ticks_synchronized<GetTicksSyncFlag::kAfterPreviousLoads |
GetTicksSyncFlag::kBeforeSubsequentLoads>();
}
template <GetTicksSyncFlag Flags>
inline zx_instant_boot_ticks_t timer_current_boot_ticks_synchronized() {
while (true) {
const zx_ticks_t off1 = internal::boot_ticks_offset.load(ktl::memory_order_relaxed);
const zx_ticks_t raw_ticks = platform_current_raw_ticks_synchronized<Flags>();
const zx_ticks_t off2 = internal::boot_ticks_offset.load(ktl::memory_order_relaxed);
if (off1 == off2) {
return raw_ticks + off1;
}
}
}
inline zx_instant_boot_ticks_t timer_current_boot_ticks() {
return timer_current_boot_ticks_synchronized<GetTicksSyncFlag::kNone>();
}
// CurrentTicksObservation contains a coherent read of the current ticks on both the monotonic and
// boot timeline.
struct CurrentTicksObservation {
zx_instant_mono_ticks_t mono_now;
zx_instant_boot_ticks_t boot_now;
};
// Performs a coherent read of both the mono and boot timelines and returns a tuple with the current
// value of both timelines.
inline CurrentTicksObservation timer_current_mono_and_boot_ticks() {
while (true) {
const zx_ticks_t boot_off1 = internal::boot_ticks_offset.load(ktl::memory_order_relaxed);
const zx_ticks_t mono_obs1 = internal::mono_ticks_modifier.load(ktl::memory_order_relaxed);
const zx_ticks_t raw_ticks =
platform_current_raw_ticks_synchronized<GetTicksSyncFlag::kAfterPreviousLoads |
GetTicksSyncFlag::kBeforeSubsequentLoads>();
const zx_ticks_t boot_off2 = internal::boot_ticks_offset.load(ktl::memory_order_relaxed);
const zx_ticks_t mono_obs2 = internal::mono_ticks_modifier.load(ktl::memory_order_relaxed);
if (boot_off1 == boot_off2 && mono_obs1 == mono_obs2 && mono_obs1 != ZX_TIME_INFINITE_PAST) {
// If our monotonic modifier observation was positive, the clock is paused and the observation
// is the current monotonic ticks value.
const zx_instant_mono_ticks_t mono_now = mono_obs1 > 0 ? mono_obs1 : raw_ticks + mono_obs1;
const zx_instant_boot_ticks_t boot_now = raw_ticks + boot_off1;
return {.mono_now = mono_now, .boot_now = boot_now};
}
}
}
// The current monotonic time in ticks.
inline zx_instant_mono_ticks_t current_mono_ticks() { return timer_current_mono_ticks(); }
// The current boot time in ticks.
inline zx_instant_boot_ticks_t current_boot_ticks() { return timer_current_boot_ticks(); }
// Pause/unpause the monotonic clock.
//
// These functions are safe to call concurrently with `timer_current_mono_ticks_synchronized`, as
// that function will retry its read of the current ticks if the value of the `mono_ticks_modifier`
// is ZX_TIME_INFINITE_PAST, which we set it to before our update, or if it notices that the value
// has changed during its read.
//
// It is NOT safe to call timer_pause_monotonic and timer_unpause_monotonic concurrently, nor is it
// safe to call this function concurrently with itself.
inline void timer_pause_monotonic() {
// Read the current value of the modifier. We can do this without performing a sequential read
// because this function is the only function that can modify the modifier after the timer has
// been initialized.
const zx_ticks_t modifier = internal::mono_ticks_modifier.load(ktl::memory_order_relaxed);
DEBUG_ASSERT(modifier != ZX_TIME_INFINITE_PAST);
DEBUG_ASSERT(modifier <= 0);
// Set the modifier to ZX_TIME_INFINITE_PAST to signal to any concurrent calls to
// timer_current_mono_ticks that the modifier is being updated and they should therefore retry
// their read.
internal::mono_ticks_modifier.store(ZX_TIME_INFINITE_PAST, ktl::memory_order_relaxed);
// Compute the current monotonic time. To do so, we load the raw ticks with synchronization
// barriers that will prevent it from being reordered above the previous load and store. This is
// necessary to prevent this call from retrieving a raw ticks value from before we started the
// pause operation. We don't need to specify `GetTicksSyncFlag::kBeforeSubsequentStores` because
// the store of the mono_ticks_modifier below has a data dependency on this call.
const zx_instant_mono_ticks_t raw_ticks =
platform_current_raw_ticks_synchronized<GetTicksSyncFlag::kAfterPreviousLoads |
GetTicksSyncFlag::kAfterPreviousStores>();
// Finally, update the mono_ticks_modifier to the paused ticks value.
const zx_instant_mono_ticks_t paused_ticks = raw_ticks + modifier;
internal::mono_ticks_modifier.store(paused_ticks, ktl::memory_order_relaxed);
}
inline void timer_unpause_monotonic() {
// First, load the existing modifier and assert that it is actually a paused value by checking
// that it is positive.
const zx_instant_mono_ticks_t paused_value =
internal::mono_ticks_modifier.load(ktl::memory_order_relaxed);
DEBUG_ASSERT(paused_value > 0);
// Then, compute the new offset by subtracting the current raw ticks counter value from the
// paused value. Assert the new offset is non-positive as expected.
const zx_ticks_t raw_ticks = platform_current_raw_ticks();
const zx_ticks_t new_offset = paused_value - raw_ticks;
DEBUG_ASSERT(new_offset <= 0);
// Finally, update the modifier value with the new offset.
internal::mono_ticks_modifier.store(new_offset, ktl::memory_order_relaxed);
}
// Returns true iff the monotonic clock is paused.
//
// Intended to be used in asserts. Does not synchronize-with anything.
inline bool timer_is_monotonic_paused() {
return internal::mono_ticks_modifier.load(ktl::memory_order_relaxed) > 0;
}
#endif // ZIRCON_KERNEL_INCLUDE_PLATFORM_TIMER_H_