1 /*
2  * Copyright 2018 The Hafnium Authors.
3  *
4  * Use of this source code is governed by a BSD-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/BSD-3-Clause.
7  */
8 
9 #include "hf/arch/timer.h"
10 
11 #include <stdbool.h>
12 #include <stddef.h>
13 #include <stdint.h>
14 
15 #include "hf/arch/cpu.h"
16 #include "hf/arch/vm/timer.h"
17 
18 #include "hf/addr.h"
19 
20 #include "msr.h"
21 #include "sysregs.h"
22 
23 #define CNTV_CTL_EL0_ENABLE (1u << 0)
24 #define CNTV_CTL_EL0_IMASK (1u << 1)
25 #define CNTV_CTL_EL0_ISTATUS (1u << 2)
26 
27 /**
28  * Sets the bit to mask virtual timer interrupts.
29  */
arch_timer_mask(struct arch_regs * regs)30 void arch_timer_mask(struct arch_regs *regs)
31 {
32 	regs->peripherals.cntv_ctl_el0 |= CNTV_CTL_EL0_IMASK;
33 }
34 
35 /**
36  * Checks whether the virtual timer is enabled and its interrupt not masked.
37  */
arch_timer_enabled(struct arch_regs * regs)38 bool arch_timer_enabled(struct arch_regs *regs)
39 {
40 	uintreg_t cntv_ctl_el0 = regs->peripherals.cntv_ctl_el0;
41 
42 	return (cntv_ctl_el0 & CNTV_CTL_EL0_ENABLE) &&
43 	       !(cntv_ctl_el0 & CNTV_CTL_EL0_IMASK);
44 }
45 
46 /**
47  * Converts a number of timer ticks to the equivalent number of nanoseconds.
48  */
ticks_to_ns(uint64_t ticks)49 static uint64_t ticks_to_ns(uint64_t ticks)
50 {
51 	return (ticks * NANOS_PER_UNIT) / read_msr(cntfrq_el0);
52 }
53 
54 /**
55  * Returns the number of ticks remaining on the virtual timer as stored in
56  * the given `arch_regs`, or 0 if it has already expired. This is undefined if
57  * the timer is not enabled.
58  */
arch_timer_remaining_ticks(struct arch_regs * regs)59 static uint64_t arch_timer_remaining_ticks(struct arch_regs *regs)
60 {
61 	/*
62 	 * Calculate the value from the saved CompareValue (cntv_cval_el0) and
63 	 * the virtual count value.
64 	 */
65 	uintreg_t cntv_cval_el0 = regs->peripherals.cntv_cval_el0;
66 	uintreg_t cntvct_el0 = read_msr(cntvct_el0);
67 
68 	if (cntv_cval_el0 >= cntvct_el0) {
69 		return cntv_cval_el0 - cntvct_el0;
70 	}
71 
72 	return 0;
73 }
74 
75 /**
76  * Returns the number of nanoseconds remaining on the virtual timer as stored in
77  * the given `arch_regs`, or 0 if it has already expired. This is undefined if
78  * the timer is not enabled.
79  */
arch_timer_remaining_ns(struct arch_regs * regs)80 uint64_t arch_timer_remaining_ns(struct arch_regs *regs)
81 {
82 	return ticks_to_ns(arch_timer_remaining_ticks(regs));
83 }
84 
85 /**
86  * Returns whether the timer is ready to fire: i.e. it is enabled, not masked,
87  * and the condition is met.
88  */
arch_timer_pending(struct arch_regs * regs)89 bool arch_timer_pending(struct arch_regs *regs)
90 {
91 	if (!arch_timer_enabled(regs)) {
92 		return false;
93 	}
94 
95 	if (regs->peripherals.cntv_ctl_el0 & CNTV_CTL_EL0_ISTATUS) {
96 		return true;
97 	}
98 
99 	if (arch_timer_remaining_ticks(regs) == 0) {
100 		/*
101 		 * This can happen even if the (stored) ISTATUS bit is not set,
102 		 * because time has passed between when the registers were
103 		 * stored and now.
104 		 */
105 		return true;
106 	}
107 
108 	return false;
109 }
110 
111 /**
112  * Checks whether the virtual timer is enabled and its interrupt not masked, for
113  * the currently active vCPU.
114  */
arch_timer_enabled_current(void)115 bool arch_timer_enabled_current(void)
116 {
117 	uintreg_t cntv_ctl_el0 = has_vhe_support() ? read_msr(MSR_CNTV_CTL_EL02)
118 						   : read_msr(cntv_ctl_el0);
119 
120 	return (cntv_ctl_el0 & CNTV_CTL_EL0_ENABLE) &&
121 	       !(cntv_ctl_el0 & CNTV_CTL_EL0_IMASK);
122 }
123 
124 /**
125  * Disables the virtual timer for the currently active vCPU.
126  */
arch_timer_disable_current(void)127 void arch_timer_disable_current(void)
128 {
129 	has_vhe_support() ? write_msr(MSR_CNTV_CTL_EL02, 0x0)
130 			  : write_msr(cntv_ctl_el0, 0x0);
131 }
132 
133 /**
134  * Returns the number of ticks remaining on the virtual timer of the currently
135  * active vCPU, or 0 if it has already expired. This is undefined if the timer
136  * is not enabled.
137  */
arch_timer_remaining_ticks_current(void)138 static uint64_t arch_timer_remaining_ticks_current(void)
139 {
140 	uintreg_t cntv_cval_el0 = has_vhe_support()
141 					  ? read_msr(MSR_CNTV_CVAL_EL02)
142 					  : read_msr(cntv_cval_el0);
143 	uintreg_t cntvct_el0 = read_msr(cntvct_el0);
144 
145 	if (cntv_cval_el0 >= cntvct_el0) {
146 		return cntv_cval_el0 - cntvct_el0;
147 	}
148 
149 	return 0;
150 }
151 
152 /**
153  * Returns the number of nanoseconds remaining on the virtual timer of the
154  * currently active vCPU, or 0 if it has already expired. This is undefined if
155  * the timer is not enabled.
156  */
arch_timer_remaining_ns_current(void)157 uint64_t arch_timer_remaining_ns_current(void)
158 {
159 	return ticks_to_ns(arch_timer_remaining_ticks_current());
160 }
161