RISC-V: KVM: Implement trap & emulate for hpmcounters
As the KVM guests only see the virtual PMU counters, all hpmcounter access should trap and KVM emulates the read access on behalf of guests. Reviewed-by: Anup Patel <anup@brainfault.org> Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Signed-off-by: Atish Patra <atishp@rivosinc.com> Signed-off-by: Anup Patel <anup@brainfault.org>
This commit is contained in:
parent
f04bafb52f
commit
a9ac6c3752
@ -44,6 +44,19 @@ struct kvm_pmu {
|
||||
#define vcpu_to_pmu(vcpu) (&(vcpu)->arch.pmu_context)
|
||||
#define pmu_to_vcpu(pmu) (container_of((pmu), struct kvm_vcpu, arch.pmu_context))
|
||||
|
||||
#if defined(CONFIG_32BIT)
|
||||
#define KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS \
|
||||
{.base = CSR_CYCLEH, .count = 31, .func = kvm_riscv_vcpu_pmu_read_hpm }, \
|
||||
{.base = CSR_CYCLE, .count = 31, .func = kvm_riscv_vcpu_pmu_read_hpm },
|
||||
#else
|
||||
#define KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS \
|
||||
{.base = CSR_CYCLE, .count = 31, .func = kvm_riscv_vcpu_pmu_read_hpm },
|
||||
#endif
|
||||
|
||||
int kvm_riscv_vcpu_pmu_read_hpm(struct kvm_vcpu *vcpu, unsigned int csr_num,
|
||||
unsigned long *val, unsigned long new_val,
|
||||
unsigned long wr_mask);
|
||||
|
||||
int kvm_riscv_vcpu_pmu_num_ctrs(struct kvm_vcpu *vcpu, struct kvm_vcpu_sbi_return *retdata);
|
||||
int kvm_riscv_vcpu_pmu_ctr_info(struct kvm_vcpu *vcpu, unsigned long cidx,
|
||||
struct kvm_vcpu_sbi_return *retdata);
|
||||
@ -67,6 +80,9 @@ void kvm_riscv_vcpu_pmu_reset(struct kvm_vcpu *vcpu);
|
||||
struct kvm_pmu {
|
||||
};
|
||||
|
||||
#define KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS \
|
||||
{.base = 0, .count = 0, .func = NULL },
|
||||
|
||||
static inline void kvm_riscv_vcpu_pmu_init(struct kvm_vcpu *vcpu) {}
|
||||
static inline void kvm_riscv_vcpu_pmu_deinit(struct kvm_vcpu *vcpu) {}
|
||||
static inline void kvm_riscv_vcpu_pmu_reset(struct kvm_vcpu *vcpu) {}
|
||||
|
@ -213,7 +213,9 @@ struct csr_func {
|
||||
unsigned long wr_mask);
|
||||
};
|
||||
|
||||
static const struct csr_func csr_funcs[] = { };
|
||||
static const struct csr_func csr_funcs[] = {
|
||||
KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS
|
||||
};
|
||||
|
||||
/**
|
||||
* kvm_riscv_vcpu_csr_return -- Handle CSR read/write after user space
|
||||
|
@ -17,6 +17,58 @@
|
||||
|
||||
#define kvm_pmu_num_counters(pmu) ((pmu)->num_hw_ctrs + (pmu)->num_fw_ctrs)
|
||||
|
||||
static int pmu_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx,
|
||||
unsigned long *out_val)
|
||||
{
|
||||
struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu);
|
||||
struct kvm_pmc *pmc;
|
||||
u64 enabled, running;
|
||||
|
||||
pmc = &kvpmu->pmc[cidx];
|
||||
if (!pmc->perf_event)
|
||||
return -EINVAL;
|
||||
|
||||
pmc->counter_val += perf_event_read_value(pmc->perf_event, &enabled, &running);
|
||||
*out_val = pmc->counter_val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_riscv_vcpu_pmu_read_hpm(struct kvm_vcpu *vcpu, unsigned int csr_num,
|
||||
unsigned long *val, unsigned long new_val,
|
||||
unsigned long wr_mask)
|
||||
{
|
||||
struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu);
|
||||
int cidx, ret = KVM_INSN_CONTINUE_NEXT_SEPC;
|
||||
|
||||
if (!kvpmu || !kvpmu->init_done) {
|
||||
/*
|
||||
* In absence of sscofpmf in the platform, the guest OS may use
|
||||
* the legacy PMU driver to read cycle/instret. In that case,
|
||||
* just return 0 to avoid any illegal trap. However, any other
|
||||
* hpmcounter access should result in illegal trap as they must
|
||||
* be access through SBI PMU only.
|
||||
*/
|
||||
if (csr_num == CSR_CYCLE || csr_num == CSR_INSTRET) {
|
||||
*val = 0;
|
||||
return ret;
|
||||
} else {
|
||||
return KVM_INSN_ILLEGAL_TRAP;
|
||||
}
|
||||
}
|
||||
|
||||
/* The counter CSR are read only. Thus, any write should result in illegal traps */
|
||||
if (wr_mask)
|
||||
return KVM_INSN_ILLEGAL_TRAP;
|
||||
|
||||
cidx = csr_num - CSR_CYCLE;
|
||||
|
||||
if (pmu_ctr_read(vcpu, cidx, val) < 0)
|
||||
return KVM_INSN_ILLEGAL_TRAP;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int kvm_riscv_vcpu_pmu_num_ctrs(struct kvm_vcpu *vcpu,
|
||||
struct kvm_vcpu_sbi_return *retdata)
|
||||
{
|
||||
@ -70,7 +122,12 @@ int kvm_riscv_vcpu_pmu_ctr_cfg_match(struct kvm_vcpu *vcpu, unsigned long ctr_ba
|
||||
int kvm_riscv_vcpu_pmu_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx,
|
||||
struct kvm_vcpu_sbi_return *retdata)
|
||||
{
|
||||
/* TODO */
|
||||
int ret;
|
||||
|
||||
ret = pmu_ctr_read(vcpu, cidx, &retdata->out_val);
|
||||
if (ret == -EINVAL)
|
||||
retdata->err_val = SBI_ERR_INVALID_PARAM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user