target/riscv: Support the Virtual Instruction fault

Backports e39a8320b088dd5efc9ebaafe387e52b3d962665
This commit is contained in:
Alistair Francis 2021-03-08 13:54:58 -05:00 committed by Lioncash
parent c3d9e15f02
commit 0e14547c7d
8 changed files with 57 additions and 6 deletions

View file

@ -6259,6 +6259,7 @@ riscv_symbols = (
'helper_fsqrt_s',
'helper_fsub_d',
'helper_fsub_s',
'helper_hyp_gvma_tlb_flush',
'helper_hyp_load',
'helper_hyp_store',
'helper_hyp_tlb_flush',

View file

@ -3695,6 +3695,7 @@
#define helper_fsqrt_s helper_fsqrt_s_riscv32
#define helper_fsub_d helper_fsub_d_riscv32
#define helper_fsub_s helper_fsub_s_riscv32
#define helper_hyp_gvma_tlb_flush helper_hyp_gvma_tlb_flush_riscv32
#define helper_hyp_load helper_hyp_load_riscv32
#define helper_hyp_store helper_hyp_store_riscv32
#define helper_hyp_tlb_flush helper_hyp_tlb_flush_riscv32

View file

@ -3695,6 +3695,7 @@
#define helper_fsqrt_s helper_fsqrt_s_riscv64
#define helper_fsub_d helper_fsub_d_riscv64
#define helper_fsub_s helper_fsub_s_riscv64
#define helper_hyp_gvma_tlb_flush helper_hyp_gvma_tlb_flush_riscv64
#define helper_hyp_load helper_hyp_load_riscv64
#define helper_hyp_store helper_hyp_store_riscv64
#define helper_hyp_tlb_flush helper_hyp_tlb_flush_riscv64

View file

@ -461,6 +461,11 @@
#define HSTATUS_WPRI HSTATUS64_WPRI
#endif
#define HCOUNTEREN_CY (1 << 0)
#define HCOUNTEREN_TM (1 << 1)
#define HCOUNTEREN_IR (1 << 2)
#define HCOUNTEREN_HPM3 (1 << 3)
/* Privilege modes */
#define PRV_U 0
#define PRV_S 1
@ -553,6 +558,7 @@
#define RISCV_EXCP_STORE_PAGE_FAULT 0xf /* since: priv-1.10.0 */
#define RISCV_EXCP_INST_GUEST_PAGE_FAULT 0x14
#define RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT 0x15
#define RISCV_EXCP_VIRT_INSTRUCTION_FAULT 0x16
#define RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT 0x17
#define RISCV_EXCP_INT_FLAG 0x80000000

View file

@ -90,6 +90,8 @@ static int hmode(CPURISCVState *env, int csrno)
if ((env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) ||
env->priv == PRV_M) {
return 0;
} else {
return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
}
}
@ -340,6 +342,7 @@ static const target_ulong delegable_excps =
(1ULL << (RISCV_EXCP_STORE_PAGE_FAULT)) |
(1ULL << (RISCV_EXCP_INST_GUEST_PAGE_FAULT)) |
(1ULL << (RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT)) |
(1ULL << (RISCV_EXCP_VIRT_INSTRUCTION_FAULT)) |
(1ULL << (RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT));
static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE |
SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS |
@ -1239,9 +1242,13 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value,
}
/* check predicate */
if (!csr_ops[csrno].predicate || csr_ops[csrno].predicate(env, csrno) < 0) {
if (!csr_ops[csrno].predicate) {
return -RISCV_EXCP_ILLEGAL_INST;
}
ret = csr_ops[csrno].predicate(env, csrno);
if (ret < 0) {
return ret;
}
/* execute combined read/write operation if it exists */
if (csr_ops[csrno].op) {

View file

@ -83,6 +83,7 @@ DEF_HELPER_1(tlb_flush, void, env)
/* Hypervisor functions */
#ifndef CONFIG_USER_ONLY
DEF_HELPER_1(hyp_tlb_flush, void, env)
DEF_HELPER_1(hyp_gvma_tlb_flush, void, env)
DEF_HELPER_4(hyp_load, tl, env, tl, tl, tl)
DEF_HELPER_5(hyp_store, void, env, tl, tl, tl, tl)
DEF_HELPER_4(hyp_x_load, tl, env, tl, tl, tl)

View file

@ -374,7 +374,7 @@ static bool trans_hfence_gvma(DisasContext *ctx, arg_sfence_vma *a)
REQUIRE_EXT(ctx, RVH);
#ifndef CONFIG_USER_ONLY
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
gen_helper_hyp_tlb_flush(tcg_ctx, tcg_ctx->cpu_env);
gen_helper_hyp_gvma_tlb_flush(tcg_ctx, tcg_ctx->cpu_env);
return true;
#endif
return false;

View file

@ -94,6 +94,11 @@ target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
}
if (riscv_has_ext(env, RVH) && riscv_cpu_virt_enabled(env) &&
get_field(env->hstatus, HSTATUS_VTSR)) {
riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
}
mstatus = env->mstatus;
if (riscv_has_ext(env, RVH) && !riscv_cpu_virt_enabled(env)) {
@ -176,7 +181,7 @@ void helper_wfi(CPURISCVState *env)
if ((env->priv == PRV_S &&
get_field(env->mstatus, MSTATUS_TW)) ||
riscv_cpu_virt_enabled(env)) {
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
} else {
cs->halted = 1;
cs->exception_index = EXCP_HLT;
@ -191,6 +196,9 @@ void helper_tlb_flush(CPURISCVState *env)
(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) && riscv_cpu_virt_enabled(env) &&
get_field(env->hstatus, HSTATUS_VTVM)) {
riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
} else {
tlb_flush(cs);
}
@ -200,6 +208,10 @@ void helper_hyp_tlb_flush(CPURISCVState *env)
{
CPUState *cs = env_cpu(env);
if (env->priv == PRV_S && riscv_cpu_virt_enabled(env)) {
riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
}
if (env->priv == PRV_M ||
(env->priv == PRV_S && !riscv_cpu_virt_enabled(env))) {
tlb_flush(cs);
@ -209,6 +221,16 @@ void helper_hyp_tlb_flush(CPURISCVState *env)
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
}
void helper_hyp_gvma_tlb_flush(CPURISCVState *env)
{
if (env->priv == PRV_S && !riscv_cpu_virt_enabled(env) &&
get_field(env->mstatus, MSTATUS_TVM)) {
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
}
helper_hyp_tlb_flush(env);
}
target_ulong helper_hyp_load(CPURISCVState *env, target_ulong address,
target_ulong attrs, target_ulong memop)
{
@ -252,7 +274,11 @@ target_ulong helper_hyp_load(CPURISCVState *env, target_ulong address,
return pte;
}
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
if (riscv_cpu_virt_enabled(env)) {
riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
} else {
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
}
return 0;
}
@ -291,7 +317,11 @@ void helper_hyp_store(CPURISCVState *env, target_ulong address,
return;
}
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
if (riscv_cpu_virt_enabled(env)) {
riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
} else {
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
}
}
target_ulong helper_hyp_x_load(CPURISCVState *env, target_ulong address,
@ -321,7 +351,11 @@ target_ulong helper_hyp_x_load(CPURISCVState *env, target_ulong address,
return pte;
}
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
if (riscv_cpu_virt_enabled(env)) {
riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
} else {
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
}
return 0;
}