target/riscv: Support the Virtual Instruction fault
Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Message-id: 4c744dce9b0b057cbb5cc0f4d4ac75cda682a8af.1597259519.git.alistair.francis@wdc.com Message-Id: <4c744dce9b0b057cbb5cc0f4d4ac75cda682a8af.1597259519.git.alistair.francis@wdc.com>
This commit is contained in:
parent
57cb2083e6
commit
e39a8320b0
@ -461,6 +461,11 @@
|
|||||||
#define HSTATUS_WPRI HSTATUS64_WPRI
|
#define HSTATUS_WPRI HSTATUS64_WPRI
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define HCOUNTEREN_CY (1 << 0)
|
||||||
|
#define HCOUNTEREN_TM (1 << 1)
|
||||||
|
#define HCOUNTEREN_IR (1 << 2)
|
||||||
|
#define HCOUNTEREN_HPM3 (1 << 3)
|
||||||
|
|
||||||
/* Privilege modes */
|
/* Privilege modes */
|
||||||
#define PRV_U 0
|
#define PRV_U 0
|
||||||
#define PRV_S 1
|
#define PRV_S 1
|
||||||
@ -553,6 +558,7 @@
|
|||||||
#define RISCV_EXCP_STORE_PAGE_FAULT 0xf /* since: priv-1.10.0 */
|
#define RISCV_EXCP_STORE_PAGE_FAULT 0xf /* since: priv-1.10.0 */
|
||||||
#define RISCV_EXCP_INST_GUEST_PAGE_FAULT 0x14
|
#define RISCV_EXCP_INST_GUEST_PAGE_FAULT 0x14
|
||||||
#define RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT 0x15
|
#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_STORE_GUEST_AMO_ACCESS_FAULT 0x17
|
||||||
|
|
||||||
#define RISCV_EXCP_INT_FLAG 0x80000000
|
#define RISCV_EXCP_INT_FLAG 0x80000000
|
||||||
|
@ -75,6 +75,61 @@ static int ctr(CPURISCVState *env, int csrno)
|
|||||||
/* The Counters extensions is not enabled */
|
/* The Counters extensions is not enabled */
|
||||||
return -RISCV_EXCP_ILLEGAL_INST;
|
return -RISCV_EXCP_ILLEGAL_INST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (riscv_cpu_virt_enabled(env)) {
|
||||||
|
switch (csrno) {
|
||||||
|
case CSR_CYCLE:
|
||||||
|
if (!get_field(env->hcounteren, HCOUNTEREN_CY) &&
|
||||||
|
get_field(env->mcounteren, HCOUNTEREN_CY)) {
|
||||||
|
return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CSR_TIME:
|
||||||
|
if (!get_field(env->hcounteren, HCOUNTEREN_TM) &&
|
||||||
|
get_field(env->mcounteren, HCOUNTEREN_TM)) {
|
||||||
|
return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CSR_INSTRET:
|
||||||
|
if (!get_field(env->hcounteren, HCOUNTEREN_IR) &&
|
||||||
|
get_field(env->mcounteren, HCOUNTEREN_IR)) {
|
||||||
|
return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CSR_HPMCOUNTER3...CSR_HPMCOUNTER31:
|
||||||
|
if (!get_field(env->hcounteren, 1 << (csrno - CSR_HPMCOUNTER3)) &&
|
||||||
|
get_field(env->mcounteren, 1 << (csrno - CSR_HPMCOUNTER3))) {
|
||||||
|
return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#if defined(TARGET_RISCV32)
|
||||||
|
case CSR_CYCLEH:
|
||||||
|
if (!get_field(env->hcounteren, HCOUNTEREN_CY) &&
|
||||||
|
get_field(env->mcounteren, HCOUNTEREN_CY)) {
|
||||||
|
return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CSR_TIMEH:
|
||||||
|
if (!get_field(env->hcounteren, HCOUNTEREN_TM) &&
|
||||||
|
get_field(env->mcounteren, HCOUNTEREN_TM)) {
|
||||||
|
return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CSR_INSTRETH:
|
||||||
|
if (!get_field(env->hcounteren, HCOUNTEREN_IR) &&
|
||||||
|
get_field(env->mcounteren, HCOUNTEREN_IR)) {
|
||||||
|
return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CSR_HPMCOUNTER3H...CSR_HPMCOUNTER31H:
|
||||||
|
if (!get_field(env->hcounteren, 1 << (csrno - CSR_HPMCOUNTER3H)) &&
|
||||||
|
get_field(env->mcounteren, 1 << (csrno - CSR_HPMCOUNTER3H))) {
|
||||||
|
return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -98,6 +153,8 @@ static int hmode(CPURISCVState *env, int csrno)
|
|||||||
if ((env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) ||
|
if ((env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) ||
|
||||||
env->priv == PRV_M) {
|
env->priv == PRV_M) {
|
||||||
return 0;
|
return 0;
|
||||||
|
} else {
|
||||||
|
return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,6 +397,7 @@ static const target_ulong delegable_excps =
|
|||||||
(1ULL << (RISCV_EXCP_STORE_PAGE_FAULT)) |
|
(1ULL << (RISCV_EXCP_STORE_PAGE_FAULT)) |
|
||||||
(1ULL << (RISCV_EXCP_INST_GUEST_PAGE_FAULT)) |
|
(1ULL << (RISCV_EXCP_INST_GUEST_PAGE_FAULT)) |
|
||||||
(1ULL << (RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT)) |
|
(1ULL << (RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT)) |
|
||||||
|
(1ULL << (RISCV_EXCP_VIRT_INSTRUCTION_FAULT)) |
|
||||||
(1ULL << (RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT));
|
(1ULL << (RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT));
|
||||||
static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE |
|
static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE |
|
||||||
SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS |
|
SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS |
|
||||||
@ -1238,9 +1296,13 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* check predicate */
|
/* check predicate */
|
||||||
if (!csr_ops[csrno].predicate || csr_ops[csrno].predicate(env, csrno) < 0) {
|
if (!csr_ops[csrno].predicate) {
|
||||||
return -RISCV_EXCP_ILLEGAL_INST;
|
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 */
|
/* execute combined read/write operation if it exists */
|
||||||
if (csr_ops[csrno].op) {
|
if (csr_ops[csrno].op) {
|
||||||
|
@ -80,6 +80,7 @@ DEF_HELPER_1(tlb_flush, void, env)
|
|||||||
/* Hypervisor functions */
|
/* Hypervisor functions */
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
DEF_HELPER_1(hyp_tlb_flush, void, env)
|
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_4(hyp_load, tl, env, tl, tl, tl)
|
||||||
DEF_HELPER_5(hyp_store, void, env, tl, 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)
|
DEF_HELPER_4(hyp_x_load, tl, env, tl, tl, tl)
|
||||||
|
@ -360,7 +360,7 @@ static bool trans_hfence_gvma(DisasContext *ctx, arg_sfence_vma *a)
|
|||||||
{
|
{
|
||||||
REQUIRE_EXT(ctx, RVH);
|
REQUIRE_EXT(ctx, RVH);
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
gen_helper_hyp_tlb_flush(cpu_env);
|
gen_helper_hyp_gvma_tlb_flush(cpu_env);
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
return false;
|
return false;
|
||||||
|
@ -94,6 +94,11 @@ target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
|
|||||||
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
|
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;
|
mstatus = env->mstatus;
|
||||||
|
|
||||||
if (riscv_has_ext(env, RVH) && !riscv_cpu_virt_enabled(env)) {
|
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 &&
|
if ((env->priv == PRV_S &&
|
||||||
get_field(env->mstatus, MSTATUS_TW)) ||
|
get_field(env->mstatus, MSTATUS_TW)) ||
|
||||||
riscv_cpu_virt_enabled(env)) {
|
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 {
|
} else {
|
||||||
cs->halted = 1;
|
cs->halted = 1;
|
||||||
cs->exception_index = EXCP_HLT;
|
cs->exception_index = EXCP_HLT;
|
||||||
@ -191,6 +196,9 @@ void helper_tlb_flush(CPURISCVState *env)
|
|||||||
(env->priv == PRV_S &&
|
(env->priv == PRV_S &&
|
||||||
get_field(env->mstatus, MSTATUS_TVM))) {
|
get_field(env->mstatus, MSTATUS_TVM))) {
|
||||||
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
|
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 {
|
} else {
|
||||||
tlb_flush(cs);
|
tlb_flush(cs);
|
||||||
}
|
}
|
||||||
@ -200,6 +208,10 @@ void helper_hyp_tlb_flush(CPURISCVState *env)
|
|||||||
{
|
{
|
||||||
CPUState *cs = env_cpu(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 ||
|
if (env->priv == PRV_M ||
|
||||||
(env->priv == PRV_S && !riscv_cpu_virt_enabled(env))) {
|
(env->priv == PRV_S && !riscv_cpu_virt_enabled(env))) {
|
||||||
tlb_flush(cs);
|
tlb_flush(cs);
|
||||||
@ -209,6 +221,16 @@ void helper_hyp_tlb_flush(CPURISCVState *env)
|
|||||||
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
|
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 helper_hyp_load(CPURISCVState *env, target_ulong address,
|
||||||
target_ulong attrs, target_ulong memop)
|
target_ulong attrs, target_ulong memop)
|
||||||
{
|
{
|
||||||
@ -251,7 +273,11 @@ target_ulong helper_hyp_load(CPURISCVState *env, target_ulong address,
|
|||||||
return pte;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,7 +315,11 @@ void helper_hyp_store(CPURISCVState *env, target_ulong address,
|
|||||||
return;
|
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,
|
target_ulong helper_hyp_x_load(CPURISCVState *env, target_ulong address,
|
||||||
@ -319,7 +349,11 @@ target_ulong helper_hyp_x_load(CPURISCVState *env, target_ulong address,
|
|||||||
return pte;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user