55 * Copyright (c) 2023 Google LLC.
66 *
77 * 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.
1011 * This test runs only when KVM_CAP_ARM_PMU_V3 is supported on the host.
1112 */
1213#include <kvm_util.h>
@@ -287,25 +288,74 @@ static void test_access_pmc_regs(struct pmc_accessor *acc, int pmc_idx)
287288 pmc_idx , PMC_ACC_TO_IDX (acc ), read_data , write_data );
288289}
289290
291+ #define INVALID_EC (-1ul)
292+ uint64_t expected_ec = INVALID_EC ;
293+
290294static void guest_sync_handler (struct ex_regs * regs )
291295{
292296 uint64_t esr , ec ;
293297
294298 esr = read_sysreg (esr_el1 );
295299 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 );
297347}
298348
299349/*
300350 * The guest is configured with PMUv3 with @expected_pmcr_n number of
301351 * event counters.
302352 * 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.
305355 */
306356static void guest_code (uint64_t expected_pmcr_n )
307357{
308- uint64_t pmcr , pmcr_n ;
358+ uint64_t pmcr , pmcr_n , unimp_mask ;
309359 int i , pmc ;
310360
311361 __GUEST_ASSERT (expected_pmcr_n <= ARMV8_PMU_MAX_GENERAL_COUNTERS ,
@@ -320,15 +370,33 @@ static void guest_code(uint64_t expected_pmcr_n)
320370 "Expected PMCR.N: 0x%lx, PMCR.N: 0x%lx" ,
321371 expected_pmcr_n , pmcr_n );
322372
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+
323382 /*
324383 * 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.
326385 */
327386 for (i = 0 ; i < ARRAY_SIZE (pmc_accessors ); i ++ ) {
328387 for (pmc = 0 ; pmc < pmcr_n ; pmc ++ )
329388 test_access_pmc_regs (& pmc_accessors [i ], pmc );
330389 }
331390
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+
332400 GUEST_DONE ();
333401}
334402
0 commit comments