Skip to content

Commit 0c0dd58

Browse files
ouptonjannau
authored andcommitted
KVM: arm64: selftests: Add test for probing PMUv3 sysregs
Add a test for sniffing out PMUv3 register traps. Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
1 parent 0a4cfe2 commit 0c0dd58

2 files changed

Lines changed: 136 additions & 0 deletions

File tree

tools/testing/selftests/kvm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions
159159
TEST_GEN_PROGS_aarch64 += aarch64/hypercalls
160160
TEST_GEN_PROGS_aarch64 += aarch64/mmio_abort
161161
TEST_GEN_PROGS_aarch64 += aarch64/page_fault_test
162+
TEST_GEN_PROGS_aarch64 += aarch64/pmuv3_register_probe
162163
TEST_GEN_PROGS_aarch64 += aarch64/psci_test
163164
TEST_GEN_PROGS_aarch64 += aarch64/set_id_regs
164165
TEST_GEN_PROGS_aarch64 += aarch64/smccc_filter
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
#include <perf/arm_pmuv3.h>
2+
3+
#include "vgic.h"
4+
#include "test_util.h"
5+
#include "processor.h"
6+
7+
static bool undef_taken;
8+
9+
#define test_read(sr) \
10+
do { \
11+
u64 __val = read_sysreg(sr); \
12+
\
13+
if (READ_ONCE(undef_taken)) \
14+
GUEST_PRINTF("read_sysreg("#sr"): UNDEFINED\n"); \
15+
else \
16+
GUEST_PRINTF("read_sysreg("#sr"): %lx\n", __val); \
17+
WRITE_ONCE(undef_taken, false); \
18+
} while (0)
19+
20+
#define test_write(val, sr) \
21+
do { \
22+
write_sysreg(val, sr); \
23+
\
24+
if (READ_ONCE(undef_taken)) \
25+
GUEST_PRINTF("write_sysreg(%x, "#sr"): UNDEFINED\n", val); \
26+
else \
27+
GUEST_PRINTF("write_sysreg(%x, "#sr"): OK\n", val); \
28+
WRITE_ONCE(undef_taken, false); \
29+
} while (0)
30+
31+
static void guest_undef_handler(struct ex_regs *regs)
32+
{
33+
WRITE_ONCE(undef_taken, true);
34+
regs->pc += 4;
35+
}
36+
37+
#define READ_PMEVCNTRN(n) test_read(pmevcntr##n##_el0)
38+
static void test_read_evcntr(int n)
39+
{
40+
PMEVN_SWITCH(n, READ_PMEVCNTRN);
41+
}
42+
43+
#define READ_PMEVTYPERN(n) test_read(pmevtyper##n##_el0);
44+
static void test_read_evtyper(int n)
45+
{
46+
PMEVN_SWITCH(n, READ_PMEVTYPERN);
47+
}
48+
49+
static void guest_code(void)
50+
{
51+
test_read(pmcr_el0);
52+
test_read(pmcntenset_el0);
53+
test_read(pmcntenclr_el0);
54+
test_read(pmovsset_el0);
55+
test_read(pmovsclr_el0);
56+
test_read(pmintenset_el1);
57+
test_read(pmintenclr_el1);
58+
test_read(pmceid0_el0);
59+
test_read(pmceid1_el0);
60+
61+
test_read(pmccntr_el0);
62+
test_read(pmccfiltr_el0);
63+
test_write(0, pmswinc_el0);
64+
65+
test_write(0, pmselr_el0);
66+
test_read(pmxevcntr_el0);
67+
test_read(pmxevtyper_el0);
68+
69+
test_read(pmuserenr_el0);
70+
71+
for (int i = 0; i < 31; i++) {
72+
test_read_evcntr(i);
73+
test_read_evtyper(i);
74+
}
75+
76+
GUEST_DONE();
77+
}
78+
79+
static void run_test(struct kvm_vcpu *vcpu)
80+
{
81+
struct ucall uc;
82+
83+
while (true) {
84+
vcpu_run(vcpu);
85+
86+
switch (get_ucall(vcpu, &uc)) {
87+
case UCALL_PRINTF:
88+
REPORT_GUEST_PRINTF(uc);
89+
break;
90+
case UCALL_DONE:
91+
return;
92+
default:
93+
TEST_FAIL("Unknown ucall %lu", uc.cmd);
94+
}
95+
}
96+
}
97+
98+
int main(void)
99+
{
100+
struct kvm_device_attr attr;
101+
struct kvm_vcpu_init init;
102+
struct kvm_vcpu *vcpu;
103+
struct kvm_vm *vm;
104+
int irq = 23;
105+
106+
TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_PMU_V3));
107+
108+
vm = vm_create(1);
109+
vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &init);
110+
init.features[0] |= (1 << KVM_ARM_VCPU_PMU_V3);
111+
vcpu = aarch64_vcpu_add(vm, 0, &init, guest_code);
112+
113+
__TEST_REQUIRE(vgic_v3_setup(vm, 1, 64) >= 0,
114+
"Failed to create vgic-v3, skipping");
115+
116+
vm_init_descriptor_tables(vm);
117+
vcpu_init_descriptor_tables(vcpu);
118+
vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT, ESR_ELx_EC_UNKNOWN,
119+
guest_undef_handler);
120+
121+
attr = (struct kvm_device_attr) {
122+
.group = KVM_ARM_VCPU_PMU_V3_CTRL,
123+
.attr = KVM_ARM_VCPU_PMU_V3_IRQ,
124+
.addr = (u64)&irq,
125+
};
126+
vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &attr);
127+
128+
attr = (struct kvm_device_attr) {
129+
.group = KVM_ARM_VCPU_PMU_V3_CTRL,
130+
.attr = KVM_ARM_VCPU_PMU_V3_INIT,
131+
};
132+
vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &attr);
133+
134+
run_test(vcpu);
135+
}

0 commit comments

Comments
 (0)