Skip to content

Commit 13cb706

Browse files
atishp04avpatel
authored andcommitted
KVM: riscv: selftests: Add a test for PMU snapshot functionality
Verify PMU snapshot functionality by setting up the shared memory correctly and reading the counter values from the shared memory instead of the CSR. Reviewed-by: Andrew Jones <[email protected]> Reviewed-by: Anup Patel <[email protected]> Signed-off-by: Atish Patra <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Anup Patel <[email protected]>
1 parent 158cb9e commit 13cb706

File tree

3 files changed

+181
-0
lines changed

3 files changed

+181
-0
lines changed

tools/testing/selftests/kvm/include/riscv/sbi.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88
#ifndef SELFTEST_KVM_SBI_H
99
#define SELFTEST_KVM_SBI_H
1010

11+
/* SBI spec version fields */
12+
#define SBI_SPEC_VERSION_DEFAULT 0x1
13+
#define SBI_SPEC_VERSION_MAJOR_SHIFT 24
14+
#define SBI_SPEC_VERSION_MAJOR_MASK 0x7f
15+
#define SBI_SPEC_VERSION_MINOR_MASK 0xffffff
16+
1117
/* SBI return error codes */
1218
#define SBI_SUCCESS 0
1319
#define SBI_ERR_FAILURE -1
@@ -33,6 +39,9 @@ enum sbi_ext_id {
3339
};
3440

3541
enum sbi_ext_base_fid {
42+
SBI_EXT_BASE_GET_SPEC_VERSION = 0,
43+
SBI_EXT_BASE_GET_IMP_ID,
44+
SBI_EXT_BASE_GET_IMP_VERSION,
3645
SBI_EXT_BASE_PROBE_EXT = 3,
3746
};
3847
enum sbi_ext_pmu_fid {
@@ -60,6 +69,12 @@ union sbi_pmu_ctr_info {
6069
};
6170
};
6271

72+
struct riscv_pmu_snapshot_data {
73+
u64 ctr_overflow_mask;
74+
u64 ctr_values[64];
75+
u64 reserved[447];
76+
};
77+
6378
struct sbiret {
6479
long error;
6580
long value;
@@ -113,4 +128,14 @@ struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
113128

114129
bool guest_sbi_probe_extension(int extid, long *out_val);
115130

131+
/* Make SBI version */
132+
static inline unsigned long sbi_mk_version(unsigned long major,
133+
unsigned long minor)
134+
{
135+
return ((major & SBI_SPEC_VERSION_MAJOR_MASK) << SBI_SPEC_VERSION_MAJOR_SHIFT)
136+
| (minor & SBI_SPEC_VERSION_MINOR_MASK);
137+
}
138+
139+
unsigned long get_host_sbi_spec_version(void);
140+
116141
#endif /* SELFTEST_KVM_SBI_H */

tools/testing/selftests/kvm/lib/riscv/processor.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,3 +502,15 @@ bool guest_sbi_probe_extension(int extid, long *out_val)
502502

503503
return true;
504504
}
505+
506+
unsigned long get_host_sbi_spec_version(void)
507+
{
508+
struct sbiret ret;
509+
510+
ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_SPEC_VERSION, 0,
511+
0, 0, 0, 0, 0);
512+
513+
GUEST_ASSERT(!ret.error);
514+
515+
return ret.value;
516+
}

tools/testing/selftests/kvm/riscv/sbi_pmu_test.c

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919
#define RISCV_MAX_PMU_COUNTERS 64
2020
union sbi_pmu_ctr_info ctrinfo_arr[RISCV_MAX_PMU_COUNTERS];
2121

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+
2227
/* Cache the available counters in a bitmask */
2328
static unsigned long counter_mask_available;
2429

@@ -186,6 +191,32 @@ static unsigned long read_counter(int idx, union sbi_pmu_ctr_info ctrinfo)
186191
return counter_val;
187192
}
188193

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+
189220
static void test_pmu_event(unsigned long event)
190221
{
191222
unsigned long counter;
@@ -234,6 +265,59 @@ static void test_pmu_event(unsigned long event)
234265
stop_reset_counter(counter, 0);
235266
}
236267

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+
237321
static void test_invalid_event(void)
238322
{
239323
struct sbiret ret;
@@ -301,6 +385,34 @@ static void test_pmu_basic_sanity(void)
301385
GUEST_DONE();
302386
}
303387

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+
304416
static void run_vcpu(struct kvm_vcpu *vcpu)
305417
{
306418
struct ucall uc;
@@ -357,6 +469,35 @@ static void test_vm_events_test(void *guest_code)
357469
test_vm_destroy(vm);
358470
}
359471

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+
360501
int main(void)
361502
{
362503
test_vm_basic_test(test_pmu_basic_sanity);
@@ -365,5 +506,8 @@ int main(void)
365506
test_vm_events_test(test_pmu_events);
366507
pr_info("SBI PMU event verification test : PASS\n");
367508

509+
test_vm_events_snapshot_test(test_pmu_events_snaphost);
510+
pr_info("SBI PMU event verification with snapshot test : PASS\n");
511+
368512
return 0;
369513
}

0 commit comments

Comments
 (0)