19
19
#define RISCV_MAX_PMU_COUNTERS 64
20
20
union sbi_pmu_ctr_info ctrinfo_arr [RISCV_MAX_PMU_COUNTERS ];
21
21
22
+ /* Snapshot shared memory data */
23
+ #define PMU_SNAPSHOT_GPA_BASE BIT(30)
24
+ static void * snapshot_gva ;
25
+ static vm_paddr_t snapshot_gpa ;
26
+
22
27
/* Cache the available counters in a bitmask */
23
28
static unsigned long counter_mask_available ;
24
29
@@ -186,6 +191,32 @@ static unsigned long read_counter(int idx, union sbi_pmu_ctr_info ctrinfo)
186
191
return counter_val ;
187
192
}
188
193
194
+ static inline void verify_sbi_requirement_assert (void )
195
+ {
196
+ long out_val = 0 ;
197
+ bool probe ;
198
+
199
+ probe = guest_sbi_probe_extension (SBI_EXT_PMU , & out_val );
200
+ GUEST_ASSERT (probe && out_val == 1 );
201
+
202
+ if (get_host_sbi_spec_version () < sbi_mk_version (2 , 0 ))
203
+ __GUEST_ASSERT (0 , "SBI implementation version doesn't support PMU Snapshot" );
204
+ }
205
+
206
+ static void snapshot_set_shmem (vm_paddr_t gpa , unsigned long flags )
207
+ {
208
+ unsigned long lo = (unsigned long )gpa ;
209
+ #if __riscv_xlen == 32
210
+ unsigned long hi = (unsigned long )(gpa >> 32 );
211
+ #else
212
+ unsigned long hi = gpa == -1 ? -1 : 0 ;
213
+ #endif
214
+ struct sbiret ret = sbi_ecall (SBI_EXT_PMU , SBI_EXT_PMU_SNAPSHOT_SET_SHMEM ,
215
+ lo , hi , flags , 0 , 0 , 0 );
216
+
217
+ GUEST_ASSERT (ret .value == 0 && ret .error == 0 );
218
+ }
219
+
189
220
static void test_pmu_event (unsigned long event )
190
221
{
191
222
unsigned long counter ;
@@ -234,6 +265,59 @@ static void test_pmu_event(unsigned long event)
234
265
stop_reset_counter (counter , 0 );
235
266
}
236
267
268
+ static void test_pmu_event_snapshot (unsigned long event )
269
+ {
270
+ unsigned long counter ;
271
+ unsigned long counter_value_pre , counter_value_post ;
272
+ unsigned long counter_init_value = 100 ;
273
+ struct riscv_pmu_snapshot_data * snapshot_data = snapshot_gva ;
274
+
275
+ counter = get_counter_index (0 , counter_mask_available , 0 , event );
276
+ counter_value_pre = read_counter (counter , ctrinfo_arr [counter ]);
277
+
278
+ /* Do not set the initial value */
279
+ start_counter (counter , 0 , 0 );
280
+ dummy_func_loop (10000 );
281
+ stop_counter (counter , SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT );
282
+
283
+ /* The counter value is updated w.r.t relative index of cbase */
284
+ counter_value_post = READ_ONCE (snapshot_data -> ctr_values [0 ]);
285
+ __GUEST_ASSERT (counter_value_post > counter_value_pre ,
286
+ "Event update verification failed: post [%lx] pre [%lx]\n" ,
287
+ counter_value_post , counter_value_pre );
288
+
289
+ /*
290
+ * We can't just update the counter without starting it.
291
+ * Do start/stop twice to simulate that by first initializing to a very
292
+ * high value and a low value after that.
293
+ */
294
+ WRITE_ONCE (snapshot_data -> ctr_values [0 ], ULONG_MAX /2 );
295
+ start_counter (counter , SBI_PMU_START_FLAG_INIT_SNAPSHOT , 0 );
296
+ stop_counter (counter , SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT );
297
+ counter_value_pre = READ_ONCE (snapshot_data -> ctr_values [0 ]);
298
+
299
+ WRITE_ONCE (snapshot_data -> ctr_values [0 ], counter_init_value );
300
+ start_counter (counter , SBI_PMU_START_FLAG_INIT_SNAPSHOT , 0 );
301
+ stop_counter (counter , SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT );
302
+ counter_value_post = READ_ONCE (snapshot_data -> ctr_values [0 ]);
303
+ __GUEST_ASSERT (counter_value_pre > counter_value_post ,
304
+ "Counter reinitialization verification failed : post [%lx] pre [%lx]\n" ,
305
+ counter_value_post , counter_value_pre );
306
+
307
+ /* Now set the initial value and compare */
308
+ WRITE_ONCE (snapshot_data -> ctr_values [0 ], counter_init_value );
309
+ start_counter (counter , SBI_PMU_START_FLAG_INIT_SNAPSHOT , 0 );
310
+ dummy_func_loop (10000 );
311
+ stop_counter (counter , SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT );
312
+
313
+ counter_value_post = READ_ONCE (snapshot_data -> ctr_values [0 ]);
314
+ __GUEST_ASSERT (counter_value_post > counter_init_value ,
315
+ "Event update verification failed: post [%lx] pre [%lx]\n" ,
316
+ counter_value_post , counter_init_value );
317
+
318
+ stop_reset_counter (counter , 0 );
319
+ }
320
+
237
321
static void test_invalid_event (void )
238
322
{
239
323
struct sbiret ret ;
@@ -301,6 +385,34 @@ static void test_pmu_basic_sanity(void)
301
385
GUEST_DONE ();
302
386
}
303
387
388
+ static void test_pmu_events_snaphost (void )
389
+ {
390
+ int num_counters = 0 ;
391
+ struct riscv_pmu_snapshot_data * snapshot_data = snapshot_gva ;
392
+ int i ;
393
+
394
+ /* Verify presence of SBI PMU and minimum requrired SBI version */
395
+ verify_sbi_requirement_assert ();
396
+
397
+ snapshot_set_shmem (snapshot_gpa , 0 );
398
+
399
+ /* Get the counter details */
400
+ num_counters = get_num_counters ();
401
+ update_counter_info (num_counters );
402
+
403
+ /* Validate shared memory access */
404
+ GUEST_ASSERT_EQ (READ_ONCE (snapshot_data -> ctr_overflow_mask ), 0 );
405
+ for (i = 0 ; i < num_counters ; i ++ ) {
406
+ if (counter_mask_available & (BIT (i )))
407
+ GUEST_ASSERT_EQ (READ_ONCE (snapshot_data -> ctr_values [i ]), 0 );
408
+ }
409
+ /* Only these two events are guranteed to be present */
410
+ test_pmu_event_snapshot (SBI_PMU_HW_CPU_CYCLES );
411
+ test_pmu_event_snapshot (SBI_PMU_HW_INSTRUCTIONS );
412
+
413
+ GUEST_DONE ();
414
+ }
415
+
304
416
static void run_vcpu (struct kvm_vcpu * vcpu )
305
417
{
306
418
struct ucall uc ;
@@ -357,6 +469,35 @@ static void test_vm_events_test(void *guest_code)
357
469
test_vm_destroy (vm );
358
470
}
359
471
472
+ static void test_vm_setup_snapshot_mem (struct kvm_vm * vm , struct kvm_vcpu * vcpu )
473
+ {
474
+ /* PMU Snapshot requires single page only */
475
+ vm_userspace_mem_region_add (vm , VM_MEM_SRC_ANONYMOUS , PMU_SNAPSHOT_GPA_BASE , 1 , 1 , 0 );
476
+ /* PMU_SNAPSHOT_GPA_BASE is identity mapped */
477
+ virt_map (vm , PMU_SNAPSHOT_GPA_BASE , PMU_SNAPSHOT_GPA_BASE , 1 );
478
+
479
+ snapshot_gva = (void * )(PMU_SNAPSHOT_GPA_BASE );
480
+ snapshot_gpa = addr_gva2gpa (vcpu -> vm , (vm_vaddr_t )snapshot_gva );
481
+ sync_global_to_guest (vcpu -> vm , snapshot_gva );
482
+ sync_global_to_guest (vcpu -> vm , snapshot_gpa );
483
+ }
484
+
485
+ static void test_vm_events_snapshot_test (void * guest_code )
486
+ {
487
+ struct kvm_vm * vm = NULL ;
488
+ struct kvm_vcpu * vcpu ;
489
+
490
+ vm = vm_create_with_one_vcpu (& vcpu , guest_code );
491
+ __TEST_REQUIRE (__vcpu_has_sbi_ext (vcpu , KVM_RISCV_SBI_EXT_PMU ),
492
+ "SBI PMU not available, skipping test" );
493
+
494
+ test_vm_setup_snapshot_mem (vm , vcpu );
495
+
496
+ run_vcpu (vcpu );
497
+
498
+ test_vm_destroy (vm );
499
+ }
500
+
360
501
int main (void )
361
502
{
362
503
test_vm_basic_test (test_pmu_basic_sanity );
@@ -365,5 +506,8 @@ int main(void)
365
506
test_vm_events_test (test_pmu_events );
366
507
pr_info ("SBI PMU event verification test : PASS\n" );
367
508
509
+ test_vm_events_snapshot_test (test_pmu_events_snaphost );
510
+ pr_info ("SBI PMU event verification with snapshot test : PASS\n" );
511
+
368
512
return 0 ;
369
513
}
0 commit comments