Recently the Linux kernel started to use a non default value, for the scounteren CSR, which is ignored by QEMU. Fix that by implementing the PMU CSR predicate function for U-mode.
Signed-off-by: Aurelien Jarno <aurel...@aurel32.net> --- target/riscv/csr.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 235f2a011e..8aba1b35d9 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -137,6 +137,55 @@ static RISCVException ctr(CPURISCVState *env, int csrno) break; } } + } else if (env->priv == PRV_U) { + switch (csrno) { + case CSR_CYCLE: + if (!get_field(env->scounteren, COUNTEREN_CY)) { + return RISCV_EXCP_ILLEGAL_INST; + } + break; + case CSR_TIME: + if (!get_field(env->scounteren, COUNTEREN_TM)) { + return RISCV_EXCP_ILLEGAL_INST; + } + break; + case CSR_INSTRET: + if (!get_field(env->scounteren, COUNTEREN_IR)) { + return RISCV_EXCP_ILLEGAL_INST; + } + break; + case CSR_HPMCOUNTER3...CSR_HPMCOUNTER31: + ctr_index = csrno - CSR_CYCLE; + if (!get_field(env->scounteren, 1 << ctr_index)) { + return RISCV_EXCP_ILLEGAL_INST; + } + break; + } + if (rv32) { + switch (csrno) { + case CSR_CYCLEH: + if (!get_field(env->scounteren, COUNTEREN_CY)) { + return RISCV_EXCP_ILLEGAL_INST; + } + break; + case CSR_TIMEH: + if (!get_field(env->scounteren, COUNTEREN_TM)) { + return RISCV_EXCP_ILLEGAL_INST; + } + break; + case CSR_INSTRETH: + if (!get_field(env->scounteren, COUNTEREN_IR)) { + return RISCV_EXCP_ILLEGAL_INST; + } + break; + case CSR_HPMCOUNTER3H...CSR_HPMCOUNTER31H: + ctr_index = csrno - CSR_CYCLEH; + if (!get_field(env->scounteren, 1 << ctr_index)) { + return RISCV_EXCP_ILLEGAL_INST; + } + break; + } + } } if (riscv_cpu_virt_enabled(env)) { -- 2.35.1