1414#include "test_util.h"
1515#include "processor.h"
1616#include "sbi.h"
17+ #include "arch_timer.h"
1718
1819/* Maximum counters(firmware + hardware) */
1920#define RISCV_MAX_PMU_COUNTERS 64
@@ -24,6 +25,9 @@ union sbi_pmu_ctr_info ctrinfo_arr[RISCV_MAX_PMU_COUNTERS];
2425static void * snapshot_gva ;
2526static vm_paddr_t snapshot_gpa ;
2627
28+ static int vcpu_shared_irq_count ;
29+ static int counter_in_use ;
30+
2731/* Cache the available counters in a bitmask */
2832static unsigned long counter_mask_available ;
2933
@@ -120,6 +124,31 @@ static void guest_illegal_exception_handler(struct ex_regs *regs)
120124 regs -> epc += 4 ;
121125}
122126
127+ static void guest_irq_handler (struct ex_regs * regs )
128+ {
129+ unsigned int irq_num = regs -> cause & ~CAUSE_IRQ_FLAG ;
130+ struct riscv_pmu_snapshot_data * snapshot_data = snapshot_gva ;
131+ unsigned long overflown_mask ;
132+ unsigned long counter_val = 0 ;
133+
134+ /* Validate that we are in the correct irq handler */
135+ GUEST_ASSERT_EQ (irq_num , IRQ_PMU_OVF );
136+
137+ /* Stop all counters first to avoid further interrupts */
138+ stop_counter (counter_in_use , SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT );
139+
140+ csr_clear (CSR_SIP , BIT (IRQ_PMU_OVF ));
141+
142+ overflown_mask = READ_ONCE (snapshot_data -> ctr_overflow_mask );
143+ GUEST_ASSERT (overflown_mask & 0x01 );
144+
145+ WRITE_ONCE (vcpu_shared_irq_count , vcpu_shared_irq_count + 1 );
146+
147+ counter_val = READ_ONCE (snapshot_data -> ctr_values [0 ]);
148+ /* Now start the counter to mimick the real driver behavior */
149+ start_counter (counter_in_use , SBI_PMU_START_FLAG_SET_INIT_VALUE , counter_val );
150+ }
151+
123152static unsigned long get_counter_index (unsigned long cbase , unsigned long cmask ,
124153 unsigned long cflags ,
125154 unsigned long event )
@@ -318,6 +347,33 @@ static void test_pmu_event_snapshot(unsigned long event)
318347 stop_reset_counter (counter , 0 );
319348}
320349
350+ static void test_pmu_event_overflow (unsigned long event )
351+ {
352+ unsigned long counter ;
353+ unsigned long counter_value_post ;
354+ unsigned long counter_init_value = ULONG_MAX - 10000 ;
355+ struct riscv_pmu_snapshot_data * snapshot_data = snapshot_gva ;
356+
357+ counter = get_counter_index (0 , counter_mask_available , 0 , event );
358+ counter_in_use = counter ;
359+
360+ /* The counter value is updated w.r.t relative index of cbase passed to start/stop */
361+ WRITE_ONCE (snapshot_data -> ctr_values [0 ], counter_init_value );
362+ start_counter (counter , SBI_PMU_START_FLAG_INIT_SNAPSHOT , 0 );
363+ dummy_func_loop (10000 );
364+ udelay (msecs_to_usecs (2000 ));
365+ /* irq handler should have stopped the counter */
366+ stop_counter (counter , SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT );
367+
368+ counter_value_post = READ_ONCE (snapshot_data -> ctr_values [0 ]);
369+ /* The counter value after stopping should be less the init value due to overflow */
370+ __GUEST_ASSERT (counter_value_post < counter_init_value ,
371+ "counter_value_post %lx counter_init_value %lx for counter\n" ,
372+ counter_value_post , counter_init_value );
373+
374+ stop_reset_counter (counter , 0 );
375+ }
376+
321377static void test_invalid_event (void )
322378{
323379 struct sbiret ret ;
@@ -413,6 +469,34 @@ static void test_pmu_events_snaphost(void)
413469 GUEST_DONE ();
414470}
415471
472+ static void test_pmu_events_overflow (void )
473+ {
474+ int num_counters = 0 ;
475+
476+ /* Verify presence of SBI PMU and minimum requrired SBI version */
477+ verify_sbi_requirement_assert ();
478+
479+ snapshot_set_shmem (snapshot_gpa , 0 );
480+ csr_set (CSR_IE , BIT (IRQ_PMU_OVF ));
481+ local_irq_enable ();
482+
483+ /* Get the counter details */
484+ num_counters = get_num_counters ();
485+ update_counter_info (num_counters );
486+
487+ /*
488+ * Qemu supports overflow for cycle/instruction.
489+ * This test may fail on any platform that do not support overflow for these two events.
490+ */
491+ test_pmu_event_overflow (SBI_PMU_HW_CPU_CYCLES );
492+ GUEST_ASSERT_EQ (vcpu_shared_irq_count , 1 );
493+
494+ test_pmu_event_overflow (SBI_PMU_HW_INSTRUCTIONS );
495+ GUEST_ASSERT_EQ (vcpu_shared_irq_count , 2 );
496+
497+ GUEST_DONE ();
498+ }
499+
416500static void run_vcpu (struct kvm_vcpu * vcpu )
417501{
418502 struct ucall uc ;
@@ -498,6 +582,32 @@ static void test_vm_events_snapshot_test(void *guest_code)
498582 test_vm_destroy (vm );
499583}
500584
585+ static void test_vm_events_overflow (void * guest_code )
586+ {
587+ struct kvm_vm * vm = NULL ;
588+ struct kvm_vcpu * vcpu ;
589+
590+ vm = vm_create_with_one_vcpu (& vcpu , guest_code );
591+ __TEST_REQUIRE (__vcpu_has_sbi_ext (vcpu , KVM_RISCV_SBI_EXT_PMU ),
592+ "SBI PMU not available, skipping test" );
593+
594+ __TEST_REQUIRE (__vcpu_has_isa_ext (vcpu , KVM_RISCV_ISA_EXT_SSCOFPMF ),
595+ "Sscofpmf is not available, skipping overflow test" );
596+
597+ test_vm_setup_snapshot_mem (vm , vcpu );
598+ vm_init_vector_tables (vm );
599+ vm_install_interrupt_handler (vm , guest_irq_handler );
600+
601+ vcpu_init_vector_tables (vcpu );
602+ /* Initialize guest timer frequency. */
603+ vcpu_get_reg (vcpu , RISCV_TIMER_REG (frequency ), & timer_freq );
604+ sync_global_to_guest (vm , timer_freq );
605+
606+ run_vcpu (vcpu );
607+
608+ test_vm_destroy (vm );
609+ }
610+
501611int main (void )
502612{
503613 test_vm_basic_test (test_pmu_basic_sanity );
@@ -509,5 +619,8 @@ int main(void)
509619 test_vm_events_snapshot_test (test_pmu_events_snaphost );
510620 pr_info ("SBI PMU event verification with snapshot test : PASS\n" );
511621
622+ test_vm_events_overflow (test_pmu_events_overflow );
623+ pr_info ("SBI PMU event verification with overflow test : PASS\n" );
624+
512625 return 0 ;
513626}
0 commit comments