mirror of
https://github.com/nxp-imx/linux-imx.git
synced 2025-07-07 18:05:21 +02:00
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 vcpu_to_pmu(vcpu) (&(vcpu)->arch.pmu_context)
|
||||||
#define pmu_to_vcpu(pmu) (container_of((pmu), struct kvm_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_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,
|
int kvm_riscv_vcpu_pmu_ctr_info(struct kvm_vcpu *vcpu, unsigned long cidx,
|
||||||
struct kvm_vcpu_sbi_return *retdata);
|
struct kvm_vcpu_sbi_return *retdata);
|
||||||
|
@ -67,6 +80,9 @@ void kvm_riscv_vcpu_pmu_reset(struct kvm_vcpu *vcpu);
|
||||||
struct kvm_pmu {
|
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_init(struct kvm_vcpu *vcpu) {}
|
||||||
static inline void kvm_riscv_vcpu_pmu_deinit(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) {}
|
static inline void kvm_riscv_vcpu_pmu_reset(struct kvm_vcpu *vcpu) {}
|
||||||
|
|
|
@ -213,7 +213,9 @@ struct csr_func {
|
||||||
unsigned long wr_mask);
|
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
|
* 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)
|
#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,
|
int kvm_riscv_vcpu_pmu_num_ctrs(struct kvm_vcpu *vcpu,
|
||||||
struct kvm_vcpu_sbi_return *retdata)
|
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,
|
int kvm_riscv_vcpu_pmu_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx,
|
||||||
struct kvm_vcpu_sbi_return *retdata)
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user