From d6db7c975e2e0d60850043ea8f208dd446a61d0a Mon Sep 17 00:00:00 2001 From: Yi Chen Date: Thu, 6 Apr 2023 18:15:59 +0800 Subject: [PATCH] target/riscv: fix H extension TVM trap - Trap satp/hgatp accesses from HS-mode when MSTATUS.TVM is enabled. - Trap satp accesses from VS-mode when HSTATUS.VTVM is enabled. - Raise RISCV_EXCP_ILLEGAL_INST when U-mode executes SFENCE.VMA/SINVAL.VMA. - Raise RISCV_EXCP_VIRT_INSTRUCTION_FAULT when VU-mode executes SFENCE.VMA/SINVAL.VMA or VS-mode executes SFENCE.VMA/SINVAL.VMA with HSTATUS.VTVM enabled. - Raise RISCV_EXCP_VIRT_INSTRUCTION_FAULT when VU-mode executes HFENCE.GVMA/HFENCE.VVMA/HINVAL.GVMA/HINVAL.VVMA. Signed-off-by: Yi Chen Reviewed-by: Weiwei Li Reviewed-by: LIU Zhiwei Reviewed-by: Alistair Francis Message-Id: <20230406101559.39632-1-chenyi2000@zju.edu.cn> Signed-off-by: Alistair Francis --- target/riscv/csr.c | 56 +++++++++++++++++++++++++--------------- target/riscv/op_helper.c | 12 ++++----- 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index f4d2dcfdc8..d2271da137 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -449,6 +449,30 @@ static RISCVException sstc_32(CPURISCVState *env, int csrno) return sstc(env, csrno); } +static RISCVException satp(CPURISCVState *env, int csrno) +{ + if (env->priv == PRV_S && !env->virt_enabled && + get_field(env->mstatus, MSTATUS_TVM)) { + return RISCV_EXCP_ILLEGAL_INST; + } + if (env->priv == PRV_S && env->virt_enabled && + get_field(env->hstatus, HSTATUS_VTVM)) { + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } + + return smode(env, csrno); +} + +static RISCVException hgatp(CPURISCVState *env, int csrno) +{ + if (env->priv == PRV_S && !env->virt_enabled && + get_field(env->mstatus, MSTATUS_TVM)) { + return RISCV_EXCP_ILLEGAL_INST; + } + + return hmode(env, csrno); +} + /* Checks if PointerMasking registers could be accessed */ static RISCVException pointer_masking(CPURISCVState *env, int csrno) { @@ -2679,13 +2703,7 @@ static RISCVException read_satp(CPURISCVState *env, int csrno, *val = 0; return RISCV_EXCP_NONE; } - - if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) { - return RISCV_EXCP_ILLEGAL_INST; - } else { - *val = env->satp; - } - + *val = env->satp; return RISCV_EXCP_NONE; } @@ -2708,18 +2726,14 @@ static RISCVException write_satp(CPURISCVState *env, int csrno, } if (vm && mask) { - if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) { - return RISCV_EXCP_ILLEGAL_INST; - } else { - /* - * The ISA defines SATP.MODE=Bare as "no translation", but we still - * pass these through QEMU's TLB emulation as it improves - * performance. Flushing the TLB on SATP writes with paging - * enabled avoids leaking those invalid cached mappings. - */ - tlb_flush(env_cpu(env)); - env->satp = val; - } + /* + * The ISA defines SATP.MODE=Bare as "no translation", but we still + * pass these through QEMU's TLB emulation as it improves + * performance. Flushing the TLB on SATP writes with paging + * enabled avoids leaking those invalid cached mappings. + */ + tlb_flush(env_cpu(env)); + env->satp = val; } return RISCV_EXCP_NONE; } @@ -4215,7 +4229,7 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { .min_priv_ver = PRIV_VERSION_1_12_0 }, /* Supervisor Protection and Translation */ - [CSR_SATP] = { "satp", smode, read_satp, write_satp }, + [CSR_SATP] = { "satp", satp, read_satp, write_satp }, /* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */ [CSR_SISELECT] = { "siselect", aia_smode, NULL, NULL, rmw_xiselect }, @@ -4252,7 +4266,7 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { .min_priv_ver = PRIV_VERSION_1_12_0 }, [CSR_HGEIP] = { "hgeip", hmode, read_hgeip, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_HGATP] = { "hgatp", hmode, read_hgatp, write_hgatp, + [CSR_HGATP] = { "hgatp", hgatp, read_hgatp, write_hgatp, .min_priv_ver = PRIV_VERSION_1_12_0 }, [CSR_HTIMEDELTA] = { "htimedelta", hmode, read_htimedelta, write_htimedelta, diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index bd21c6eeef..0c10dd7a78 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -381,12 +381,12 @@ void helper_wfi(CPURISCVState *env) void helper_tlb_flush(CPURISCVState *env) { CPUState *cs = env_cpu(env); - if (!(env->priv >= PRV_S) || - (env->priv == PRV_S && - get_field(env->mstatus, MSTATUS_TVM))) { + if (!env->virt_enabled && + (env->priv == PRV_U || + (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)))) { riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); - } else if (riscv_has_ext(env, RVH) && env->virt_enabled && - get_field(env->hstatus, HSTATUS_VTVM)) { + } else if (env->virt_enabled && + (env->priv == PRV_U || get_field(env->hstatus, HSTATUS_VTVM))) { riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC()); } else { tlb_flush(cs); @@ -403,7 +403,7 @@ void helper_hyp_tlb_flush(CPURISCVState *env) { CPUState *cs = env_cpu(env); - if (env->priv == PRV_S && env->virt_enabled) { + if (env->virt_enabled) { riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC()); }