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, and if the guest can access
9
- * those counters.
8
+ * counters (PMCR_EL0.N) that userspace sets, if the guest can access
9
+ * those counters, and if the guest is prevented from accessing any
10
+ * other counters.
10
11
* This test runs only when KVM_CAP_ARM_PMU_V3 is supported on the host.
11
12
*/
12
13
#include <kvm_util.h>
@@ -287,25 +288,74 @@ static void test_access_pmc_regs(struct pmc_accessor *acc, int pmc_idx)
287
288
pmc_idx , PMC_ACC_TO_IDX (acc ), read_data , write_data );
288
289
}
289
290
291
+ #define INVALID_EC (-1ul)
292
+ uint64_t expected_ec = INVALID_EC ;
293
+
290
294
static void guest_sync_handler (struct ex_regs * regs )
291
295
{
292
296
uint64_t esr , ec ;
293
297
294
298
esr = read_sysreg (esr_el1 );
295
299
ec = (esr >> ESR_EC_SHIFT ) & ESR_EC_MASK ;
296
- __GUEST_ASSERT (0 , "PC: 0x%lx; ESR: 0x%lx; EC: 0x%lx" , regs -> pc , esr , ec );
300
+
301
+ __GUEST_ASSERT (expected_ec == ec ,
302
+ "PC: 0x%lx; ESR: 0x%lx; EC: 0x%lx; EC expected: 0x%lx" ,
303
+ regs -> pc , esr , ec , expected_ec );
304
+
305
+ /* skip the trapping instruction */
306
+ regs -> pc += 4 ;
307
+
308
+ /* Use INVALID_EC to indicate an exception occurred */
309
+ expected_ec = INVALID_EC ;
310
+ }
311
+
312
+ /*
313
+ * Run the given operation that should trigger an exception with the
314
+ * given exception class. The exception handler (guest_sync_handler)
315
+ * will reset op_end_addr to 0, expected_ec to INVALID_EC, and skip
316
+ * the instruction that trapped.
317
+ */
318
+ #define TEST_EXCEPTION (ec , ops ) \
319
+ ({ \
320
+ GUEST_ASSERT(ec != INVALID_EC); \
321
+ WRITE_ONCE(expected_ec, ec); \
322
+ dsb(ish); \
323
+ ops; \
324
+ GUEST_ASSERT(expected_ec == INVALID_EC); \
325
+ })
326
+
327
+ /*
328
+ * Tests for reading/writing registers for the unimplemented event counter
329
+ * specified by @pmc_idx (>= PMCR_EL0.N).
330
+ */
331
+ static void test_access_invalid_pmc_regs (struct pmc_accessor * acc , int pmc_idx )
332
+ {
333
+ /*
334
+ * Reading/writing the event count/type registers should cause
335
+ * an UNDEFINED exception.
336
+ */
337
+ TEST_EXCEPTION (ESR_EC_UNKNOWN , acc -> read_cntr (pmc_idx ));
338
+ TEST_EXCEPTION (ESR_EC_UNKNOWN , acc -> write_cntr (pmc_idx , 0 ));
339
+ TEST_EXCEPTION (ESR_EC_UNKNOWN , acc -> read_typer (pmc_idx ));
340
+ TEST_EXCEPTION (ESR_EC_UNKNOWN , acc -> write_typer (pmc_idx , 0 ));
341
+ /*
342
+ * The bit corresponding to the (unimplemented) counter in
343
+ * {PMCNTEN,PMINTEN,PMOVS}{SET,CLR} registers should be RAZ.
344
+ */
345
+ test_bitmap_pmu_regs (pmc_idx , 1 );
346
+ test_bitmap_pmu_regs (pmc_idx , 0 );
297
347
}
298
348
299
349
/*
300
350
* The guest is configured with PMUv3 with @expected_pmcr_n number of
301
351
* event counters.
302
352
* 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.
353
+ * if reading/writing PMU registers for implemented or unimplemented
354
+ * counters works as expected.
305
355
*/
306
356
static void guest_code (uint64_t expected_pmcr_n )
307
357
{
308
- uint64_t pmcr , pmcr_n ;
358
+ uint64_t pmcr , pmcr_n , unimp_mask ;
309
359
int i , pmc ;
310
360
311
361
__GUEST_ASSERT (expected_pmcr_n <= ARMV8_PMU_MAX_GENERAL_COUNTERS ,
@@ -320,15 +370,33 @@ static void guest_code(uint64_t expected_pmcr_n)
320
370
"Expected PMCR.N: 0x%lx, PMCR.N: 0x%lx" ,
321
371
expected_pmcr_n , pmcr_n );
322
372
373
+ /*
374
+ * Make sure that (RAZ) bits corresponding to unimplemented event
375
+ * counters in {PMCNTEN,PMINTEN,PMOVS}{SET,CLR} registers are reset
376
+ * to zero.
377
+ * (NOTE: bits for implemented event counters are reset to UNKNOWN)
378
+ */
379
+ unimp_mask = GENMASK_ULL (ARMV8_PMU_MAX_GENERAL_COUNTERS - 1 , pmcr_n );
380
+ check_bitmap_pmu_regs (unimp_mask , false);
381
+
323
382
/*
324
383
* Tests for reading/writing PMU registers for implemented counters.
325
- * Use each combination of PMEVT {CNTR,TYPER}<n>_EL0 accessor functions.
384
+ * Use each combination of PMEV {CNTR,TYPER}<n>_EL0 accessor functions.
326
385
*/
327
386
for (i = 0 ; i < ARRAY_SIZE (pmc_accessors ); i ++ ) {
328
387
for (pmc = 0 ; pmc < pmcr_n ; pmc ++ )
329
388
test_access_pmc_regs (& pmc_accessors [i ], pmc );
330
389
}
331
390
391
+ /*
392
+ * Tests for reading/writing PMU registers for unimplemented counters.
393
+ * Use each combination of PMEV{CNTR,TYPER}<n>_EL0 accessor functions.
394
+ */
395
+ for (i = 0 ; i < ARRAY_SIZE (pmc_accessors ); i ++ ) {
396
+ for (pmc = pmcr_n ; pmc < ARMV8_PMU_MAX_GENERAL_COUNTERS ; pmc ++ )
397
+ test_access_invalid_pmc_regs (& pmc_accessors [i ], pmc );
398
+ }
399
+
332
400
GUEST_DONE ();
333
401
}
334
402
0 commit comments