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 <chenyi2000@zju.edu.cn> Reviewed-by: Weiwei Li <liweiwei@iscas.ac.cn> Reviewed-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-Id: <20230406101559.39632-1-chenyi2000@zju.edu.cn> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
parent
9ba63f9442
commit
d6db7c975e
@ -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,
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user