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