Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions arch/riscv/kvm/vcpu_pmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,14 @@ static int pmu_fw_ctr_read_hi(struct kvm_vcpu *vcpu, unsigned long cidx,
if (pmc->cinfo.type != SBI_PMU_CTR_TYPE_FW)
return -EINVAL;

if (pmc->event_idx == SBI_PMU_EVENT_IDX_INVALID)
return -EINVAL;

fevent_code = get_event_code(pmc->event_idx);
if (WARN_ONCE(fevent_code >= SBI_PMU_FW_MAX,
"Invalid firmware event code: %d\n", fevent_code))
return -EINVAL;

pmc->counter_val = kvpmu->fw_event[fevent_code].value;

*out_val = pmc->counter_val >> 32;
Expand All @@ -247,7 +254,14 @@ static int pmu_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx,
pmc = &kvpmu->pmc[cidx];

if (pmc->cinfo.type == SBI_PMU_CTR_TYPE_FW) {
if (pmc->event_idx == SBI_PMU_EVENT_IDX_INVALID)
return -EINVAL;

fevent_code = get_event_code(pmc->event_idx);
if (WARN_ONCE(fevent_code >= SBI_PMU_FW_MAX,
"Invalid firmware event code: %d\n", fevent_code))
return -EINVAL;

pmc->counter_val = kvpmu->fw_event[fevent_code].value;
} else if (pmc->perf_event) {
pmc->counter_val += perf_event_read_value(pmc->perf_event, &enabled, &running);
Expand Down
37 changes: 37 additions & 0 deletions tools/testing/selftests/kvm/include/riscv/sbi.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,43 @@ enum sbi_pmu_hw_generic_events_t {
SBI_PMU_HW_GENERAL_MAX,
};

enum sbi_pmu_fw_generic_events_t {
SBI_PMU_FW_MISALIGNED_LOAD = 0,
SBI_PMU_FW_MISALIGNED_STORE = 1,
SBI_PMU_FW_ACCESS_LOAD = 2,
SBI_PMU_FW_ACCESS_STORE = 3,
SBI_PMU_FW_ILLEGAL_INSN = 4,
SBI_PMU_FW_SET_TIMER = 5,
SBI_PMU_FW_IPI_SENT = 6,
SBI_PMU_FW_IPI_RCVD = 7,
SBI_PMU_FW_FENCE_I_SENT = 8,
SBI_PMU_FW_FENCE_I_RCVD = 9,
SBI_PMU_FW_SFENCE_VMA_SENT = 10,
SBI_PMU_FW_SFENCE_VMA_RCVD = 11,
SBI_PMU_FW_SFENCE_VMA_ASID_SENT = 12,
SBI_PMU_FW_SFENCE_VMA_ASID_RCVD = 13,

SBI_PMU_FW_HFENCE_GVMA_SENT = 14,
SBI_PMU_FW_HFENCE_GVMA_RCVD = 15,
SBI_PMU_FW_HFENCE_GVMA_VMID_SENT = 16,
SBI_PMU_FW_HFENCE_GVMA_VMID_RCVD = 17,

SBI_PMU_FW_HFENCE_VVMA_SENT = 18,
SBI_PMU_FW_HFENCE_VVMA_RCVD = 19,
SBI_PMU_FW_HFENCE_VVMA_ASID_SENT = 20,
SBI_PMU_FW_HFENCE_VVMA_ASID_RCVD = 21,
SBI_PMU_FW_MAX,
};

/* SBI PMU event types */
enum sbi_pmu_event_type {
SBI_PMU_EVENT_TYPE_HW = 0x0,
SBI_PMU_EVENT_TYPE_CACHE = 0x1,
SBI_PMU_EVENT_TYPE_RAW = 0x2,
SBI_PMU_EVENT_TYPE_RAW_V2 = 0x3,
SBI_PMU_EVENT_TYPE_FW = 0xf,
};

/* SBI PMU counter types */
enum sbi_pmu_ctr_type {
SBI_PMU_CTR_TYPE_HW = 0x0,
Expand Down
20 changes: 19 additions & 1 deletion tools/testing/selftests/kvm/riscv/sbi_pmu_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ static void test_pmu_basic_sanity(void)
struct sbiret ret;
int num_counters = 0, i;
union sbi_pmu_ctr_info ctrinfo;
unsigned long fw_eidx;

probe = guest_sbi_probe_extension(SBI_EXT_PMU, &out_val);
GUEST_ASSERT(probe && out_val == 1);
Expand All @@ -461,7 +462,24 @@ static void test_pmu_basic_sanity(void)
pmu_csr_read_num(ctrinfo.csr);
GUEST_ASSERT(illegal_handler_invoked);
} else if (ctrinfo.type == SBI_PMU_CTR_TYPE_FW) {
read_fw_counter(i, ctrinfo);
/* Read without configure should fail */
ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_FW_READ,
i, 0, 0, 0, 0, 0);
GUEST_ASSERT(ret.error == SBI_ERR_INVALID_PARAM);

/*
* Try to configure with a common firmware event.
* If configuration succeeds, verify we can read it.
*/
fw_eidx = ((unsigned long)SBI_PMU_EVENT_TYPE_FW << 16) |
SBI_PMU_FW_ACCESS_LOAD;

ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_CFG_MATCH,
i, 1, 0, fw_eidx, 0, 0);
if (ret.error == 0) {
GUEST_ASSERT(ret.value == i);
read_fw_counter(i, ctrinfo);
}
}
}

Expand Down
Loading