1 /*
2  * Copyright 2019 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 "perfmon.h"
10 
11 #include "hf/check.h"
12 #include "hf/dlog.h"
13 #include "hf/types.h"
14 
15 #include "msr.h"
16 #include "sysregs.h"
17 
18 /* clang-format off */
19 
20 /**
21  * Definitions of read-only performance monitor registers' encodings.
22  * See Arm Architecture Reference Manual Armv8-A, D12.3.1.
23  * NAME, op0, op1, crn, crm, op2
24  */
25 #define PERFMON_REGISTERS_READ                 \
26 	X(PMCEID0_EL0       , 3, 3,  9, 12, 6) \
27 	X(PMCEID1_EL0       , 3, 3,  9, 12, 7) \
28 	X(PMEVCNTR0_EL0     , 3, 3, 14,  8, 0) \
29 	X(PMEVCNTR1_EL0     , 3, 3, 14,  8, 1) \
30 	X(PMEVCNTR2_EL0     , 3, 3, 14,  8, 2) \
31 	X(PMEVCNTR3_EL0     , 3, 3, 14,  8, 3) \
32 	X(PMEVCNTR4_EL0     , 3, 3, 14,  8, 4) \
33 	X(PMEVCNTR5_EL0     , 3, 3, 14,  8, 5) \
34 	X(PMEVCNTR6_EL0     , 3, 3, 14,  8, 6) \
35 	X(PMEVCNTR7_EL0     , 3, 3, 14,  8, 7) \
36 	X(PMEVCNTR8_EL0     , 3, 3, 14,  9, 0) \
37 	X(PMEVCNTR9_EL0     , 3, 3, 14,  9, 1) \
38 	X(PMEVCNTR10_EL0    , 3, 3, 14,  9, 2) \
39 	X(PMEVCNTR11_EL0    , 3, 3, 14,  9, 3) \
40 	X(PMEVCNTR12_EL0    , 3, 3, 14,  9, 4) \
41 	X(PMEVCNTR13_EL0    , 3, 3, 14,  9, 5) \
42 	X(PMEVCNTR14_EL0    , 3, 3, 14,  9, 6) \
43 	X(PMEVCNTR15_EL0    , 3, 3, 14,  9, 7) \
44 	X(PMEVCNTR16_EL0    , 3, 3, 14, 10, 0) \
45 	X(PMEVCNTR17_EL0    , 3, 3, 14, 10, 1) \
46 	X(PMEVCNTR18_EL0    , 3, 3, 14, 10, 2) \
47 	X(PMEVCNTR19_EL0    , 3, 3, 14, 10, 3) \
48 	X(PMEVCNTR20_EL0    , 3, 3, 14, 10, 4) \
49 	X(PMEVCNTR21_EL0    , 3, 3, 14, 10, 5) \
50 	X(PMEVCNTR22_EL0    , 3, 3, 14, 10, 6) \
51 	X(PMEVCNTR23_EL0    , 3, 3, 14, 10, 7) \
52 	X(PMEVCNTR24_EL0    , 3, 3, 14, 11, 0) \
53 	X(PMEVCNTR25_EL0    , 3, 3, 14, 11, 1) \
54 	X(PMEVCNTR26_EL0    , 3, 3, 14, 11, 2) \
55 	X(PMEVCNTR27_EL0    , 3, 3, 14, 11, 3) \
56 	X(PMEVCNTR28_EL0    , 3, 3, 14, 11, 4) \
57 	X(PMEVCNTR29_EL0    , 3, 3, 14, 11, 5) \
58 	X(PMEVCNTR30_EL0    , 3, 3, 14, 11, 6) \
59 
60 /**
61  * Definitions of write-only performance monitor registers' encodings.
62  * See Arm Architecture Reference Manual Armv8-A, D12.3.1.
63  * NAME, op0, op1, crn, crm, op2
64  */
65 #define PERFMON_REGISTERS_WRITE                \
66 	X(PMSWINC_EL0       , 3, 3,  9, 12, 4) \
67 
68 /**
69  * Definitions of readable and writeable performance monitor registers' encodings.
70  * See Arm Architecture Reference Manual Armv8-A, D12.3.1.
71  * NAME, op0, op1, crn, crm, op2
72  */
73 #define PERFMON_REGISTERS_READ_WRITE           \
74 	X(PMINTENSET_EL1    , 3, 0,  9, 14, 1) \
75 	X(PMINTENCLR_EL1    , 3, 0,  9, 14, 2) \
76 	X(PMCR_EL0          , 3, 3,  9, 12, 0) \
77 	X(PMCNTENSET_EL0    , 3, 3,  9, 12, 1) \
78 	X(PMCNTENCLR_EL0    , 3, 3,  9, 12, 2) \
79 	X(PMOVSCLR_EL0      , 3, 3,  9, 12, 3) \
80 	X(PMSELR_EL0        , 3, 3,  9, 12, 5) \
81 	X(PMCCNTR_EL0       , 3, 3,  9, 13, 0) \
82 	X(PMXEVTYPER_EL0    , 3, 3,  9, 13, 1) \
83 	X(PMXEVCNTR_EL0     , 3, 3,  9, 13, 2) \
84 	X(PMUSERENR_EL0     , 3, 3,  9, 14, 0) \
85 	X(PMOVSSET_EL0      , 3, 3,  9, 14, 3) \
86 	X(PMEVTYPER0_EL0    , 3, 3, 14, 12, 0) \
87 	X(PMEVTYPER1_EL0    , 3, 3, 14, 12, 1) \
88 	X(PMEVTYPER2_EL0    , 3, 3, 14, 12, 2) \
89 	X(PMEVTYPER3_EL0    , 3, 3, 14, 12, 3) \
90 	X(PMEVTYPER4_EL0    , 3, 3, 14, 12, 4) \
91 	X(PMEVTYPER5_EL0    , 3, 3, 14, 12, 5) \
92 	X(PMEVTYPER6_EL0    , 3, 3, 14, 12, 6) \
93 	X(PMEVTYPER7_EL0    , 3, 3, 14, 12, 7) \
94 	X(PMEVTYPER8_EL0    , 3, 3, 14, 13, 0) \
95 	X(PMEVTYPER9_EL0    , 3, 3, 14, 13, 1) \
96 	X(PMEVTYPER10_EL0   , 3, 3, 14, 13, 2) \
97 	X(PMEVTYPER11_EL0   , 3, 3, 14, 13, 3) \
98 	X(PMEVTYPER12_EL0   , 3, 3, 14, 13, 4) \
99 	X(PMEVTYPER13_EL0   , 3, 3, 14, 13, 5) \
100 	X(PMEVTYPER14_EL0   , 3, 3, 14, 13, 6) \
101 	X(PMEVTYPER15_EL0   , 3, 3, 14, 13, 7) \
102 	X(PMEVTYPER16_EL0   , 3, 3, 14, 14, 0) \
103 	X(PMEVTYPER17_EL0   , 3, 3, 14, 14, 1) \
104 	X(PMEVTYPER18_EL0   , 3, 3, 14, 14, 2) \
105 	X(PMEVTYPER19_EL0   , 3, 3, 14, 14, 3) \
106 	X(PMEVTYPER20_EL0   , 3, 3, 14, 14, 4) \
107 	X(PMEVTYPER21_EL0   , 3, 3, 14, 14, 5) \
108 	X(PMEVTYPER22_EL0   , 3, 3, 14, 14, 6) \
109 	X(PMEVTYPER23_EL0   , 3, 3, 14, 14, 7) \
110 	X(PMEVTYPER24_EL0   , 3, 3, 14, 15, 0) \
111 	X(PMEVTYPER25_EL0   , 3, 3, 14, 15, 1) \
112 	X(PMEVTYPER26_EL0   , 3, 3, 14, 15, 2) \
113 	X(PMEVTYPER27_EL0   , 3, 3, 14, 15, 3) \
114 	X(PMEVTYPER28_EL0   , 3, 3, 14, 15, 4) \
115 	X(PMEVTYPER29_EL0   , 3, 3, 14, 15, 5) \
116 	X(PMEVTYPER30_EL0   , 3, 3, 14, 15, 6) \
117 	X(PMCCFILTR_EL0     , 3, 3, 14, 15, 7)
118 
119 /* clang-format on */
120 
121 /**
122  * Returns true if the ESR register shows an access to a performance monitor
123  * register.
124  */
perfmon_is_register_access(uintreg_t esr)125 bool perfmon_is_register_access(uintreg_t esr)
126 {
127 	uintreg_t op0 = GET_ISS_OP0(esr);
128 	uintreg_t op1 = GET_ISS_OP1(esr);
129 	uintreg_t crn = GET_ISS_CRN(esr);
130 	uintreg_t crm = GET_ISS_CRM(esr);
131 
132 	/* From the Arm Architecture Reference Manual Table D12-2. */
133 
134 	/* For PMINTENCLR_EL1 and PMINTENSET_EL1*/
135 	if (op0 == 3 && op1 == 0 && crn == 9 && crm == 14) {
136 		return true;
137 	}
138 
139 	/* For PMEVCNTRn_EL0, PMEVTYPERn_EL0, and PMCCFILTR_EL0. */
140 	if (op0 == 3 && op1 == 3 && crn == 14 && crm >= 8 && crm <= 15) {
141 		return true;
142 	}
143 
144 	/* For all remaining performance monitor registers. */
145 	return op0 == 3 && op1 == 3 && crn == 9 && crm >= 12 && crm <= 14;
146 }
147 
148 /**
149  * Processes an access (msr, mrs) to a performance monitor register.
150  * Returns true if the access was allowed and performed, false otherwise.
151  */
perfmon_process_access(struct vcpu * vcpu,ffa_vm_id_t vm_id,uintreg_t esr)152 bool perfmon_process_access(struct vcpu *vcpu, ffa_vm_id_t vm_id, uintreg_t esr)
153 {
154 	/*
155 	 * For now, performance monitor registers are not supported by secondary
156 	 * VMs. Disallow accesses to them.
157 	 */
158 	if (vm_id != HF_PRIMARY_VM_ID) {
159 		return false;
160 	}
161 
162 	uintreg_t sys_register = GET_ISS_SYSREG(esr);
163 	uintreg_t rt_register = GET_ISS_RT(esr);
164 	uintreg_t value;
165 
166 	/* +1 because Rt can access register XZR */
167 	CHECK(rt_register < NUM_GP_REGS + 1);
168 
169 	if (ISS_IS_READ(esr)) {
170 		switch (sys_register) {
171 #define X(reg_name, op0, op1, crn, crm, op2)              \
172 	case (GET_ISS_ENCODING(op0, op1, crn, crm, op2)): \
173 		value = read_msr(reg_name);               \
174 		break;
175 			PERFMON_REGISTERS_READ
176 			PERFMON_REGISTERS_READ_WRITE
177 #undef X
178 		default:
179 			value = vcpu->regs.r[rt_register];
180 			dlog_notice(
181 				"Unsupported performance monitor register "
182 				"read: "
183 				"op0=%d, op1=%d, crn=%d, crm=%d, op2=%d, "
184 				"rt=%d.\n",
185 				GET_ISS_OP0(esr), GET_ISS_OP1(esr),
186 				GET_ISS_CRN(esr), GET_ISS_CRM(esr),
187 				GET_ISS_OP2(esr), GET_ISS_RT(esr));
188 			break;
189 		}
190 		if (rt_register != RT_REG_XZR) {
191 			vcpu->regs.r[rt_register] = value;
192 		}
193 	} else {
194 		if (rt_register != RT_REG_XZR) {
195 			value = vcpu->regs.r[rt_register];
196 		} else {
197 			value = 0;
198 		}
199 		switch (sys_register) {
200 #define X(reg_name, op0, op1, crn, crm, op2)              \
201 	case (GET_ISS_ENCODING(op0, op1, crn, crm, op2)): \
202 		write_msr(reg_name, value);               \
203 		break;
204 			PERFMON_REGISTERS_WRITE
205 			PERFMON_REGISTERS_READ_WRITE
206 #undef X
207 		default:
208 			dlog_notice(
209 				"Unsupported performance monitor register "
210 				"write: "
211 				"op0=%d, op1=%d, crn=%d, crm=%d, op2=%d, "
212 				"rt=%d.\n",
213 				GET_ISS_OP0(esr), GET_ISS_OP1(esr),
214 				GET_ISS_CRN(esr), GET_ISS_CRM(esr),
215 				GET_ISS_OP2(esr), GET_ISS_RT(esr));
216 			break;
217 		}
218 	}
219 
220 	return true;
221 }
222 
223 /**
224  * Returns the value register PMCCFILTR_EL0 should have at initialization.
225  */
perfmon_get_pmccfiltr_el0_init_value(ffa_vm_id_t vm_id)226 uintreg_t perfmon_get_pmccfiltr_el0_init_value(ffa_vm_id_t vm_id)
227 {
228 	if (vm_id != HF_PRIMARY_VM_ID) {
229 		/* Disable cycle counting for secondary VMs. */
230 		return PMCCFILTR_EL0_P | PMCCFILTR_EL0_U;
231 	}
232 
233 	return 0;
234 }
235