5
5
* Copyright (c) 2023 Google LLC.
6
6
*
7
7
* This test checks if the guest can see the same number of the PMU event
8
- * counters (PMCR_EL0.N) that userspace sets.
8
+ * counters (PMCR_EL0.N) that userspace sets, and if the guest can access
9
+ * those counters.
9
10
* This test runs only when KVM_CAP_ARM_PMU_V3 is supported on the host.
10
11
*/
11
12
#include <kvm_util.h>
@@ -37,6 +38,255 @@ static void set_pmcr_n(uint64_t *pmcr, uint64_t pmcr_n)
37
38
* pmcr |= (pmcr_n << ARMV8_PMU_PMCR_N_SHIFT );
38
39
}
39
40
41
+ /* Read PMEVTCNTR<n>_EL0 through PMXEVCNTR_EL0 */
42
+ static inline unsigned long read_sel_evcntr (int sel )
43
+ {
44
+ write_sysreg (sel , pmselr_el0 );
45
+ isb ();
46
+ return read_sysreg (pmxevcntr_el0 );
47
+ }
48
+
49
+ /* Write PMEVTCNTR<n>_EL0 through PMXEVCNTR_EL0 */
50
+ static inline void write_sel_evcntr (int sel , unsigned long val )
51
+ {
52
+ write_sysreg (sel , pmselr_el0 );
53
+ isb ();
54
+ write_sysreg (val , pmxevcntr_el0 );
55
+ isb ();
56
+ }
57
+
58
+ /* Read PMEVTYPER<n>_EL0 through PMXEVTYPER_EL0 */
59
+ static inline unsigned long read_sel_evtyper (int sel )
60
+ {
61
+ write_sysreg (sel , pmselr_el0 );
62
+ isb ();
63
+ return read_sysreg (pmxevtyper_el0 );
64
+ }
65
+
66
+ /* Write PMEVTYPER<n>_EL0 through PMXEVTYPER_EL0 */
67
+ static inline void write_sel_evtyper (int sel , unsigned long val )
68
+ {
69
+ write_sysreg (sel , pmselr_el0 );
70
+ isb ();
71
+ write_sysreg (val , pmxevtyper_el0 );
72
+ isb ();
73
+ }
74
+
75
+ static inline void enable_counter (int idx )
76
+ {
77
+ uint64_t v = read_sysreg (pmcntenset_el0 );
78
+
79
+ write_sysreg (BIT (idx ) | v , pmcntenset_el0 );
80
+ isb ();
81
+ }
82
+
83
+ static inline void disable_counter (int idx )
84
+ {
85
+ uint64_t v = read_sysreg (pmcntenset_el0 );
86
+
87
+ write_sysreg (BIT (idx ) | v , pmcntenclr_el0 );
88
+ isb ();
89
+ }
90
+
91
+ static void pmu_disable_reset (void )
92
+ {
93
+ uint64_t pmcr = read_sysreg (pmcr_el0 );
94
+
95
+ /* Reset all counters, disabling them */
96
+ pmcr &= ~ARMV8_PMU_PMCR_E ;
97
+ write_sysreg (pmcr | ARMV8_PMU_PMCR_P , pmcr_el0 );
98
+ isb ();
99
+ }
100
+
101
+ #define RETURN_READ_PMEVCNTRN (n ) \
102
+ return read_sysreg(pmevcntr##n##_el0)
103
+ static unsigned long read_pmevcntrn (int n )
104
+ {
105
+ PMEVN_SWITCH (n , RETURN_READ_PMEVCNTRN );
106
+ return 0 ;
107
+ }
108
+
109
+ #define WRITE_PMEVCNTRN (n ) \
110
+ write_sysreg(val, pmevcntr##n##_el0)
111
+ static void write_pmevcntrn (int n , unsigned long val )
112
+ {
113
+ PMEVN_SWITCH (n , WRITE_PMEVCNTRN );
114
+ isb ();
115
+ }
116
+
117
+ #define READ_PMEVTYPERN (n ) \
118
+ return read_sysreg(pmevtyper##n##_el0)
119
+ static unsigned long read_pmevtypern (int n )
120
+ {
121
+ PMEVN_SWITCH (n , READ_PMEVTYPERN );
122
+ return 0 ;
123
+ }
124
+
125
+ #define WRITE_PMEVTYPERN (n ) \
126
+ write_sysreg(val, pmevtyper##n##_el0)
127
+ static void write_pmevtypern (int n , unsigned long val )
128
+ {
129
+ PMEVN_SWITCH (n , WRITE_PMEVTYPERN );
130
+ isb ();
131
+ }
132
+
133
+ /*
134
+ * The pmc_accessor structure has pointers to PMEV{CNTR,TYPER}<n>_EL0
135
+ * accessors that test cases will use. Each of the accessors will
136
+ * either directly reads/writes PMEV{CNTR,TYPER}<n>_EL0
137
+ * (i.e. {read,write}_pmev{cnt,type}rn()), or reads/writes them through
138
+ * PMXEV{CNTR,TYPER}_EL0 (i.e. {read,write}_sel_ev{cnt,type}r()).
139
+ *
140
+ * This is used to test that combinations of those accessors provide
141
+ * the consistent behavior.
142
+ */
143
+ struct pmc_accessor {
144
+ /* A function to be used to read PMEVTCNTR<n>_EL0 */
145
+ unsigned long (* read_cntr )(int idx );
146
+ /* A function to be used to write PMEVTCNTR<n>_EL0 */
147
+ void (* write_cntr )(int idx , unsigned long val );
148
+ /* A function to be used to read PMEVTYPER<n>_EL0 */
149
+ unsigned long (* read_typer )(int idx );
150
+ /* A function to be used to write PMEVTYPER<n>_EL0 */
151
+ void (* write_typer )(int idx , unsigned long val );
152
+ };
153
+
154
+ struct pmc_accessor pmc_accessors [] = {
155
+ /* test with all direct accesses */
156
+ { read_pmevcntrn , write_pmevcntrn , read_pmevtypern , write_pmevtypern },
157
+ /* test with all indirect accesses */
158
+ { read_sel_evcntr , write_sel_evcntr , read_sel_evtyper , write_sel_evtyper },
159
+ /* read with direct accesses, and write with indirect accesses */
160
+ { read_pmevcntrn , write_sel_evcntr , read_pmevtypern , write_sel_evtyper },
161
+ /* read with indirect accesses, and write with direct accesses */
162
+ { read_sel_evcntr , write_pmevcntrn , read_sel_evtyper , write_pmevtypern },
163
+ };
164
+
165
+ /*
166
+ * Convert a pointer of pmc_accessor to an index in pmc_accessors[],
167
+ * assuming that the pointer is one of the entries in pmc_accessors[].
168
+ */
169
+ #define PMC_ACC_TO_IDX (acc ) (acc - &pmc_accessors[0])
170
+
171
+ #define GUEST_ASSERT_BITMAP_REG (regname , mask , set_expected ) \
172
+ { \
173
+ uint64_t _tval = read_sysreg(regname); \
174
+ \
175
+ if (set_expected) \
176
+ __GUEST_ASSERT((_tval & mask), \
177
+ "tval: 0x%lx; mask: 0x%lx; set_expected: 0x%lx", \
178
+ _tval, mask, set_expected); \
179
+ else \
180
+ __GUEST_ASSERT(!(_tval & mask), \
181
+ "tval: 0x%lx; mask: 0x%lx; set_expected: 0x%lx", \
182
+ _tval, mask, set_expected); \
183
+ }
184
+
185
+ /*
186
+ * Check if @mask bits in {PMCNTEN,PMINTEN,PMOVS}{SET,CLR} registers
187
+ * are set or cleared as specified in @set_expected.
188
+ */
189
+ static void check_bitmap_pmu_regs (uint64_t mask , bool set_expected )
190
+ {
191
+ GUEST_ASSERT_BITMAP_REG (pmcntenset_el0 , mask , set_expected );
192
+ GUEST_ASSERT_BITMAP_REG (pmcntenclr_el0 , mask , set_expected );
193
+ GUEST_ASSERT_BITMAP_REG (pmintenset_el1 , mask , set_expected );
194
+ GUEST_ASSERT_BITMAP_REG (pmintenclr_el1 , mask , set_expected );
195
+ GUEST_ASSERT_BITMAP_REG (pmovsset_el0 , mask , set_expected );
196
+ GUEST_ASSERT_BITMAP_REG (pmovsclr_el0 , mask , set_expected );
197
+ }
198
+
199
+ /*
200
+ * Check if the bit in {PMCNTEN,PMINTEN,PMOVS}{SET,CLR} registers corresponding
201
+ * to the specified counter (@pmc_idx) can be read/written as expected.
202
+ * When @set_op is true, it tries to set the bit for the counter in
203
+ * those registers by writing the SET registers (the bit won't be set
204
+ * if the counter is not implemented though).
205
+ * Otherwise, it tries to clear the bits in the registers by writing
206
+ * the CLR registers.
207
+ * Then, it checks if the values indicated in the registers are as expected.
208
+ */
209
+ static void test_bitmap_pmu_regs (int pmc_idx , bool set_op )
210
+ {
211
+ uint64_t pmcr_n , test_bit = BIT (pmc_idx );
212
+ bool set_expected = false;
213
+
214
+ if (set_op ) {
215
+ write_sysreg (test_bit , pmcntenset_el0 );
216
+ write_sysreg (test_bit , pmintenset_el1 );
217
+ write_sysreg (test_bit , pmovsset_el0 );
218
+
219
+ /* The bit will be set only if the counter is implemented */
220
+ pmcr_n = get_pmcr_n (read_sysreg (pmcr_el0 ));
221
+ set_expected = (pmc_idx < pmcr_n ) ? true : false;
222
+ } else {
223
+ write_sysreg (test_bit , pmcntenclr_el0 );
224
+ write_sysreg (test_bit , pmintenclr_el1 );
225
+ write_sysreg (test_bit , pmovsclr_el0 );
226
+ }
227
+ check_bitmap_pmu_regs (test_bit , set_expected );
228
+ }
229
+
230
+ /*
231
+ * Tests for reading/writing registers for the (implemented) event counter
232
+ * specified by @pmc_idx.
233
+ */
234
+ static void test_access_pmc_regs (struct pmc_accessor * acc , int pmc_idx )
235
+ {
236
+ uint64_t write_data , read_data ;
237
+
238
+ /* Disable all PMCs and reset all PMCs to zero. */
239
+ pmu_disable_reset ();
240
+
241
+ /*
242
+ * Tests for reading/writing {PMCNTEN,PMINTEN,PMOVS}{SET,CLR}_EL1.
243
+ */
244
+
245
+ /* Make sure that the bit in those registers are set to 0 */
246
+ test_bitmap_pmu_regs (pmc_idx , false);
247
+ /* Test if setting the bit in those registers works */
248
+ test_bitmap_pmu_regs (pmc_idx , true);
249
+ /* Test if clearing the bit in those registers works */
250
+ test_bitmap_pmu_regs (pmc_idx , false);
251
+
252
+ /*
253
+ * Tests for reading/writing the event type register.
254
+ */
255
+
256
+ /*
257
+ * Set the event type register to an arbitrary value just for testing
258
+ * of reading/writing the register.
259
+ * Arm ARM says that for the event from 0x0000 to 0x003F,
260
+ * the value indicated in the PMEVTYPER<n>_EL0.evtCount field is
261
+ * the value written to the field even when the specified event
262
+ * is not supported.
263
+ */
264
+ write_data = (ARMV8_PMU_EXCLUDE_EL1 | ARMV8_PMUV3_PERFCTR_INST_RETIRED );
265
+ acc -> write_typer (pmc_idx , write_data );
266
+ read_data = acc -> read_typer (pmc_idx );
267
+ __GUEST_ASSERT (read_data == write_data ,
268
+ "pmc_idx: 0x%lx; acc_idx: 0x%lx; read_data: 0x%lx; write_data: 0x%lx" ,
269
+ pmc_idx , PMC_ACC_TO_IDX (acc ), read_data , write_data );
270
+
271
+ /*
272
+ * Tests for reading/writing the event count register.
273
+ */
274
+
275
+ read_data = acc -> read_cntr (pmc_idx );
276
+
277
+ /* The count value must be 0, as it is disabled and reset */
278
+ __GUEST_ASSERT (read_data == 0 ,
279
+ "pmc_idx: 0x%lx; acc_idx: 0x%lx; read_data: 0x%lx" ,
280
+ pmc_idx , PMC_ACC_TO_IDX (acc ), read_data );
281
+
282
+ write_data = read_data + pmc_idx + 0x12345 ;
283
+ acc -> write_cntr (pmc_idx , write_data );
284
+ read_data = acc -> read_cntr (pmc_idx );
285
+ __GUEST_ASSERT (read_data == write_data ,
286
+ "pmc_idx: 0x%lx; acc_idx: 0x%lx; read_data: 0x%lx; write_data: 0x%lx" ,
287
+ pmc_idx , PMC_ACC_TO_IDX (acc ), read_data , write_data );
288
+ }
289
+
40
290
static void guest_sync_handler (struct ex_regs * regs )
41
291
{
42
292
uint64_t esr , ec ;
@@ -49,11 +299,14 @@ static void guest_sync_handler(struct ex_regs *regs)
49
299
/*
50
300
* The guest is configured with PMUv3 with @expected_pmcr_n number of
51
301
* event counters.
52
- * Check if @expected_pmcr_n is consistent with PMCR_EL0.N.
302
+ * Check if @expected_pmcr_n is consistent with PMCR_EL0.N, and
303
+ * if reading/writing PMU registers for implemented counters works
304
+ * as expected.
53
305
*/
54
306
static void guest_code (uint64_t expected_pmcr_n )
55
307
{
56
308
uint64_t pmcr , pmcr_n ;
309
+ int i , pmc ;
57
310
58
311
__GUEST_ASSERT (expected_pmcr_n <= ARMV8_PMU_MAX_GENERAL_COUNTERS ,
59
312
"Expected PMCR.N: 0x%lx; ARMv8 general counters: 0x%lx" ,
@@ -67,6 +320,15 @@ static void guest_code(uint64_t expected_pmcr_n)
67
320
"Expected PMCR.N: 0x%lx, PMCR.N: 0x%lx" ,
68
321
expected_pmcr_n , pmcr_n );
69
322
323
+ /*
324
+ * Tests for reading/writing PMU registers for implemented counters.
325
+ * Use each combination of PMEVT{CNTR,TYPER}<n>_EL0 accessor functions.
326
+ */
327
+ for (i = 0 ; i < ARRAY_SIZE (pmc_accessors ); i ++ ) {
328
+ for (pmc = 0 ; pmc < pmcr_n ; pmc ++ )
329
+ test_access_pmc_regs (& pmc_accessors [i ], pmc );
330
+ }
331
+
70
332
GUEST_DONE ();
71
333
}
72
334
@@ -179,7 +441,7 @@ static void test_create_vpmu_vm_with_pmcr_n(uint64_t pmcr_n, bool expect_fail)
179
441
* Create a guest with one vCPU, set the PMCR_EL0.N for the vCPU to @pmcr_n,
180
442
* and run the test.
181
443
*/
182
- static void run_test (uint64_t pmcr_n )
444
+ static void run_access_test (uint64_t pmcr_n )
183
445
{
184
446
uint64_t sp ;
185
447
struct kvm_vcpu * vcpu ;
@@ -246,7 +508,7 @@ int main(void)
246
508
247
509
pmcr_n = get_pmcr_n_limit ();
248
510
for (i = 0 ; i <= pmcr_n ; i ++ )
249
- run_test (i );
511
+ run_access_test (i );
250
512
251
513
for (i = pmcr_n + 1 ; i < ARMV8_PMU_MAX_COUNTERS ; i ++ )
252
514
run_error_test (i );
0 commit comments