blob: 30b2ca9533ef9a9d9b0f40e5f0ccf46677e47588 [file] [log] [blame]
/*
* Copyright 2019 Google LLC
*
* Licensed under both the 3-Clause BSD License and the GPLv2, found in the
* LICENSE and LICENSE.GPL-2.0 files, respectively, in the root directory.
*
* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
*/
.global MeasureReadLatency
// uint64_t MeasureReadLatency(const void* address);
MeasureReadLatency:
// x0 = address
// Full memory and speculation barrier. See docs/fencing.md for details.
//
// Of special note: we need the ISB here to prevent some processors from
// speculating ahead and reading the timestamp counter early. DSB doesn't
// stop later instructions from "[r]eading ... System registers that are
// directly or indirectly read without causing side-effects"[1], which seems
// to include the virtual count.
//
// Linux adds an ISB before reading CNTVCT_EL0: https://git.io/Jeivz
//
// [1] DSB: https://cpu.fyi/d/047#G9.10258412
dsb sy
isb
// x1 = <virtual count>
// CNTVCT_EL0: https://cpu.fyi/d/047#G31.5432229
mrs x1, cntvct_el0
// Finish reading the virtual count before starting the read.
dsb sy
// Read *address.
ldrb w0, [x0]
// Finish the read before reading the virtual count again. As before, we need
// ISB to prevent the timestamp read from issuing early.
dsb sy
isb
// x2 = <virtual count>
mrs x2, cntvct_el0
// x0 = x2 - x1
sub x0, x2, x1
ret