xref: /linux/arch/arm64/kvm/hyp/nvhe/clock.c (revision 53597deca0e38c30e6cd4ba2114fa42d2bcd85bb)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2025 Google LLC
4  * Author: Vincent Donnefort <vdonnefort@google.com>
5  */
6 
7 #include <nvhe/clock.h>
8 
9 #include <asm/arch_timer.h>
10 #include <asm/div64.h>
11 
12 static struct clock_data {
13 	struct {
14 		u32 mult;
15 		u32 shift;
16 		u64 epoch_ns;
17 		u64 epoch_cyc;
18 		u64 cyc_overflow64;
19 	} data[2];
20 	u64 cur;
21 } trace_clock_data;
22 
23 static u64 __clock_mult_uint128(u64 cyc, u32 mult, u32 shift)
24 {
25 	__uint128_t ns = (__uint128_t)cyc * mult;
26 
27 	ns >>= shift;
28 
29 	return (u64)ns;
30 }
31 
32 /* Does not guarantee no reader on the modified bank. */
33 void trace_clock_update(u32 mult, u32 shift, u64 epoch_ns, u64 epoch_cyc)
34 {
35 	struct clock_data *clock = &trace_clock_data;
36 	u64 bank = clock->cur ^ 1;
37 
38 	clock->data[bank].mult			= mult;
39 	clock->data[bank].shift			= shift;
40 	clock->data[bank].epoch_ns		= epoch_ns;
41 	clock->data[bank].epoch_cyc		= epoch_cyc;
42 	clock->data[bank].cyc_overflow64	= ULONG_MAX / mult;
43 
44 	smp_store_release(&clock->cur, bank);
45 }
46 
47 /* Use untrusted host data */
48 u64 trace_clock(void)
49 {
50 	struct clock_data *clock = &trace_clock_data;
51 	u64 bank = smp_load_acquire(&clock->cur);
52 	u64 cyc, ns;
53 
54 	cyc = __arch_counter_get_cntvct() - clock->data[bank].epoch_cyc;
55 
56 	if (likely(cyc < clock->data[bank].cyc_overflow64)) {
57 		ns = cyc * clock->data[bank].mult;
58 		ns >>= clock->data[bank].shift;
59 	} else {
60 		ns = __clock_mult_uint128(cyc, clock->data[bank].mult,
61 					  clock->data[bank].shift);
62 	}
63 
64 	return (u64)ns + clock->data[bank].epoch_ns;
65 }
66