blob: 3840a77b6fcaf9f182ce23ab4858f818af67578f [file] [log] [blame]
// Copyright 2023 The Fuchsia Authors
//
// 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
#include <platform.h>
#include <arch/riscv64/feature.h>
#include <dev/timer.h>
#include <platform/timer.h>
template <GetTicksSyncFlag Flags>
inline zx_ticks_t platform_current_raw_ticks_synchronized() {
// If the caller requested that the read of the current raw ticks be synchronized with respect to
// previous loads and/or stores, ensure that we emit a fence instruction guaranteeing this as
// described in section 6.1.1 ("CSR Access Ordering") in "The RISC-V Instruction Set Manual,
// Volume I, Unprivileged Architecture" Version 20250508. The specification provides more detail
// on this approach, but in summary:
// * The timer is read via a CSR, which is modeled as a device input operation in the RISC-V
// memory model. As such, the successor set must consist of the "i" operand.
// * Depending on the GetTicksSyncFlag, the predecessor set must be "r", "w", or "rw".
constexpr GetTicksSyncFlag AfterPreviousLoadsAndStores =
GetTicksSyncFlag::kAfterPreviousLoads | GetTicksSyncFlag::kAfterPreviousStores;
if constexpr ((Flags & AfterPreviousLoadsAndStores) == AfterPreviousLoadsAndStores) {
__asm__ volatile("fence rw, i" ::: "memory");
} else if constexpr ((Flags & GetTicksSyncFlag::kAfterPreviousLoads) != GetTicksSyncFlag::kNone) {
__asm__ volatile("fence r, i" ::: "memory");
} else if constexpr ((Flags & GetTicksSyncFlag::kAfterPreviousStores) !=
GetTicksSyncFlag::kNone) {
__asm__ volatile("fence w, i" ::: "memory");
}
// Redirect the current ticks call to the pdev layer.
const zx_ticks_t ticks = timer_current_ticks();
// If the caller requested that the read of the current raw ticks be synchronized with respect
// to subsequent loads and/or stores, then once again ensure that we emit a fence instruction.
// Once again, timer reads are modeled as a device input operation, so:
// * The predecessor set must consist of the "i" operand.
// * Depending on the GetTicksSyncFlag, the successor set must be "r", "w", or "rw".
constexpr GetTicksSyncFlag BeforeSubsequentLoadsAndStores =
GetTicksSyncFlag::kBeforeSubsequentLoads | GetTicksSyncFlag::kBeforeSubsequentStores;
if constexpr ((Flags & BeforeSubsequentLoadsAndStores) == BeforeSubsequentLoadsAndStores) {
__asm__ volatile("fence i, rw" ::: "memory");
} else if constexpr ((Flags & GetTicksSyncFlag::kBeforeSubsequentLoads) !=
GetTicksSyncFlag::kNone) {
__asm__ volatile("fence i, r" ::: "memory");
} else if constexpr ((Flags & GetTicksSyncFlag::kBeforeSubsequentStores) !=
GetTicksSyncFlag::kNone) {
__asm__ volatile("fence i, w" ::: "memory");
}
return ticks;
}
zx_instant_mono_ticks_t platform_convert_early_ticks(arch::EarlyTicks sample) {
return sample.time + timer_get_mono_ticks_offset();
}
zx_status_t platform_set_oneshot_timer(zx_ticks_t deadline) {
return timer_set_oneshot_timer(deadline);
}
void platform_stop_timer() { timer_stop(); }
void platform_shutdown_timer() { timer_shutdown(); }
zx_status_t platform_suspend_timer_curr_cpu() { return ZX_ERR_NOT_SUPPORTED; }
zx_status_t platform_resume_timer_curr_cpu() { return ZX_ERR_NOT_SUPPORTED; }
bool platform_usermode_can_access_tick_registers() {
// If the cpu claims to have Zicntr support, then it's relatively cheap for user
// space to access the time CSR via rdtime instruction.
return gRiscvFeatures[arch::RiscvFeature::kZicntr];
}
// Explicit instantiation of all of the forms of synchronized tick access.
#define EXPAND_PLATFORM_CURRENT_RAW_TICKS_SYNCHRONIZED(flags) \
template zx_ticks_t \
platform_current_raw_ticks_synchronized<static_cast<GetTicksSyncFlag>(flags)>()
EXPAND_PLATFORM_CURRENT_RAW_TICKS_SYNCHRONIZED(0);
EXPAND_PLATFORM_CURRENT_RAW_TICKS_SYNCHRONIZED(1);
EXPAND_PLATFORM_CURRENT_RAW_TICKS_SYNCHRONIZED(2);
EXPAND_PLATFORM_CURRENT_RAW_TICKS_SYNCHRONIZED(3);
EXPAND_PLATFORM_CURRENT_RAW_TICKS_SYNCHRONIZED(4);
EXPAND_PLATFORM_CURRENT_RAW_TICKS_SYNCHRONIZED(5);
EXPAND_PLATFORM_CURRENT_RAW_TICKS_SYNCHRONIZED(6);
EXPAND_PLATFORM_CURRENT_RAW_TICKS_SYNCHRONIZED(7);
EXPAND_PLATFORM_CURRENT_RAW_TICKS_SYNCHRONIZED(8);
EXPAND_PLATFORM_CURRENT_RAW_TICKS_SYNCHRONIZED(9);
EXPAND_PLATFORM_CURRENT_RAW_TICKS_SYNCHRONIZED(10);
EXPAND_PLATFORM_CURRENT_RAW_TICKS_SYNCHRONIZED(11);
EXPAND_PLATFORM_CURRENT_RAW_TICKS_SYNCHRONIZED(12);
EXPAND_PLATFORM_CURRENT_RAW_TICKS_SYNCHRONIZED(13);
EXPAND_PLATFORM_CURRENT_RAW_TICKS_SYNCHRONIZED(14);
EXPAND_PLATFORM_CURRENT_RAW_TICKS_SYNCHRONIZED(15);
#undef EXPAND_PLATFORM_CURRENT_RAW_TICKS_SYNCHRONIZED