blob: 634e3e386de86aea85a328b4fd9d331cd03cc42e [file] [log] [blame]
// 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 <lib/arch/ticks.h>
#include <zircon/compiler.h>
#include <zircon/types.h>
#include <fbl/enum_bits.h>
#include <ktl/type_traits.h>
// 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_time_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();
void timer_tick(zx_time_t now);
// 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();
// Reads a platform-specific fixed-rate monotonic counter
// The "raw" form of the counter should give the current counter value (and is
// almost certainly not what you want). The normal form will give the counter
// value, potentially adjusted by a constant used to make the ticks timeline
// start ticking from 0 when the system boots.
zx_ticks_t platform_current_raw_ticks();
zx_ticks_t platform_current_ticks();
// high-precision timer current_ticks
inline zx_ticks_t current_ticks() { return platform_current_ticks(); }
// Access the platform specific offset from the raw ticks timeline to the 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).
zx_ticks_t platform_get_raw_ticks_to_ticks_offset();
// current time in nanoseconds
zx_time_t current_time();
// 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 platform_set_ticks_to_time_ratio(const affine::Ratio& ticks_to_time);
const affine::Ratio& platform_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, platform_current_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)
template <GetTicksSyncFlag Flags>
zx_ticks_t platform_current_ticks_synchronized();
#endif // ZIRCON_KERNEL_INCLUDE_PLATFORM_TIMER_H_