mirror of https://github.com/xemu-project/xemu.git
target/riscv: Combine set_mode and set_virt functions.
Combining riscv_cpu_set_virt_enabled() and riscv_cpu_set_mode() functions. This is to make complete mode change information available through a single function. This allows to easily differentiate between HS->VS, VS->HS and VS->VS transitions when executing state update codes. For example: One use-case which inspired this change is to update mode-specific instruction and cycle counters which requires information of both prev mode and current mode. Signed-off-by: Rajnesh Kanwal <rkanwal@rivosinc.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20240711-smcntrpmf_v7-v8-1-b7c38ae7b263@rivosinc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
parent
3cb9f20499
commit
68c05fb530
|
@ -567,7 +567,7 @@ void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, uint32_t priv,
|
||||||
RISCVException smstateen_acc_ok(CPURISCVState *env, int index, uint64_t bit);
|
RISCVException smstateen_acc_ok(CPURISCVState *env, int index, uint64_t bit);
|
||||||
#endif /* !CONFIG_USER_ONLY */
|
#endif /* !CONFIG_USER_ONLY */
|
||||||
|
|
||||||
void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv);
|
void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv, bool virt_en);
|
||||||
|
|
||||||
void riscv_translate_init(void);
|
void riscv_translate_init(void);
|
||||||
G_NORETURN void riscv_raise_exception(CPURISCVState *env,
|
G_NORETURN void riscv_raise_exception(CPURISCVState *env,
|
||||||
|
|
|
@ -619,30 +619,6 @@ void riscv_cpu_set_geilen(CPURISCVState *env, target_ulong geilen)
|
||||||
env->geilen = geilen;
|
env->geilen = geilen;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function can only be called to set virt when RVH is enabled */
|
|
||||||
void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable)
|
|
||||||
{
|
|
||||||
/* Flush the TLB on all virt mode changes. */
|
|
||||||
if (env->virt_enabled != enable) {
|
|
||||||
tlb_flush(env_cpu(env));
|
|
||||||
}
|
|
||||||
|
|
||||||
env->virt_enabled = enable;
|
|
||||||
|
|
||||||
if (enable) {
|
|
||||||
/*
|
|
||||||
* The guest external interrupts from an interrupt controller are
|
|
||||||
* delivered only when the Guest/VM is running (i.e. V=1). This means
|
|
||||||
* any guest external interrupt which is triggered while the Guest/VM
|
|
||||||
* is not running (i.e. V=0) will be missed on QEMU resulting in guest
|
|
||||||
* with sluggish response to serial console input and other I/O events.
|
|
||||||
*
|
|
||||||
* To solve this, we check and inject interrupt after setting V=1.
|
|
||||||
*/
|
|
||||||
riscv_cpu_update_mip(env, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts)
|
int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts)
|
||||||
{
|
{
|
||||||
CPURISCVState *env = &cpu->env;
|
CPURISCVState *env = &cpu->env;
|
||||||
|
@ -715,7 +691,7 @@ void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, uint32_t priv,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
|
void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv, bool virt_en)
|
||||||
{
|
{
|
||||||
g_assert(newpriv <= PRV_M && newpriv != PRV_RESERVED);
|
g_assert(newpriv <= PRV_M && newpriv != PRV_RESERVED);
|
||||||
|
|
||||||
|
@ -736,6 +712,28 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
|
||||||
* preemptive context switch. As a result, do both.
|
* preemptive context switch. As a result, do both.
|
||||||
*/
|
*/
|
||||||
env->load_res = -1;
|
env->load_res = -1;
|
||||||
|
|
||||||
|
if (riscv_has_ext(env, RVH)) {
|
||||||
|
/* Flush the TLB on all virt mode changes. */
|
||||||
|
if (env->virt_enabled != virt_en) {
|
||||||
|
tlb_flush(env_cpu(env));
|
||||||
|
}
|
||||||
|
|
||||||
|
env->virt_enabled = virt_en;
|
||||||
|
if (virt_en) {
|
||||||
|
/*
|
||||||
|
* The guest external interrupts from an interrupt controller are
|
||||||
|
* delivered only when the Guest/VM is running (i.e. V=1). This
|
||||||
|
* means any guest external interrupt which is triggered while the
|
||||||
|
* Guest/VM is not running (i.e. V=0) will be missed on QEMU
|
||||||
|
* resulting in guest with sluggish response to serial console
|
||||||
|
* input and other I/O events.
|
||||||
|
*
|
||||||
|
* To solve this, we check and inject interrupt after setting V=1.
|
||||||
|
*/
|
||||||
|
riscv_cpu_update_mip(env, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1648,6 +1646,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
||||||
{
|
{
|
||||||
RISCVCPU *cpu = RISCV_CPU(cs);
|
RISCVCPU *cpu = RISCV_CPU(cs);
|
||||||
CPURISCVState *env = &cpu->env;
|
CPURISCVState *env = &cpu->env;
|
||||||
|
bool virt = env->virt_enabled;
|
||||||
bool write_gva = false;
|
bool write_gva = false;
|
||||||
uint64_t s;
|
uint64_t s;
|
||||||
|
|
||||||
|
@ -1778,7 +1777,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
||||||
|
|
||||||
htval = env->guest_phys_fault_addr;
|
htval = env->guest_phys_fault_addr;
|
||||||
|
|
||||||
riscv_cpu_set_virt_enabled(env, 0);
|
virt = false;
|
||||||
} else {
|
} else {
|
||||||
/* Trap into HS mode */
|
/* Trap into HS mode */
|
||||||
env->hstatus = set_field(env->hstatus, HSTATUS_SPV, false);
|
env->hstatus = set_field(env->hstatus, HSTATUS_SPV, false);
|
||||||
|
@ -1799,7 +1798,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
||||||
env->htinst = tinst;
|
env->htinst = tinst;
|
||||||
env->pc = (env->stvec >> 2 << 2) +
|
env->pc = (env->stvec >> 2 << 2) +
|
||||||
((async && (env->stvec & 3) == 1) ? cause * 4 : 0);
|
((async && (env->stvec & 3) == 1) ? cause * 4 : 0);
|
||||||
riscv_cpu_set_mode(env, PRV_S);
|
riscv_cpu_set_mode(env, PRV_S, virt);
|
||||||
} else {
|
} else {
|
||||||
/* handle the trap in M-mode */
|
/* handle the trap in M-mode */
|
||||||
if (riscv_has_ext(env, RVH)) {
|
if (riscv_has_ext(env, RVH)) {
|
||||||
|
@ -1815,7 +1814,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
||||||
mtval2 = env->guest_phys_fault_addr;
|
mtval2 = env->guest_phys_fault_addr;
|
||||||
|
|
||||||
/* Trapping to M mode, virt is disabled */
|
/* Trapping to M mode, virt is disabled */
|
||||||
riscv_cpu_set_virt_enabled(env, 0);
|
virt = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
s = env->mstatus;
|
s = env->mstatus;
|
||||||
|
@ -1830,7 +1829,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
||||||
env->mtinst = tinst;
|
env->mtinst = tinst;
|
||||||
env->pc = (env->mtvec >> 2 << 2) +
|
env->pc = (env->mtvec >> 2 << 2) +
|
||||||
((async && (env->mtvec & 3) == 1) ? cause * 4 : 0);
|
((async && (env->mtvec & 3) == 1) ? cause * 4 : 0);
|
||||||
riscv_cpu_set_mode(env, PRV_M);
|
riscv_cpu_set_mode(env, PRV_M, virt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -264,7 +264,7 @@ void helper_cbo_inval(CPURISCVState *env, target_ulong address)
|
||||||
target_ulong helper_sret(CPURISCVState *env)
|
target_ulong helper_sret(CPURISCVState *env)
|
||||||
{
|
{
|
||||||
uint64_t mstatus;
|
uint64_t mstatus;
|
||||||
target_ulong prev_priv, prev_virt;
|
target_ulong prev_priv, prev_virt = env->virt_enabled;
|
||||||
|
|
||||||
if (!(env->priv >= PRV_S)) {
|
if (!(env->priv >= PRV_S)) {
|
||||||
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
|
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
|
||||||
|
@ -307,11 +307,9 @@ target_ulong helper_sret(CPURISCVState *env)
|
||||||
if (prev_virt) {
|
if (prev_virt) {
|
||||||
riscv_cpu_swap_hypervisor_regs(env);
|
riscv_cpu_swap_hypervisor_regs(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
riscv_cpu_set_virt_enabled(env, prev_virt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
riscv_cpu_set_mode(env, prev_priv);
|
riscv_cpu_set_mode(env, prev_priv, prev_virt);
|
||||||
|
|
||||||
return retpc;
|
return retpc;
|
||||||
}
|
}
|
||||||
|
@ -347,16 +345,13 @@ target_ulong helper_mret(CPURISCVState *env)
|
||||||
mstatus = set_field(mstatus, MSTATUS_MPRV, 0);
|
mstatus = set_field(mstatus, MSTATUS_MPRV, 0);
|
||||||
}
|
}
|
||||||
env->mstatus = mstatus;
|
env->mstatus = mstatus;
|
||||||
riscv_cpu_set_mode(env, prev_priv);
|
|
||||||
|
|
||||||
if (riscv_has_ext(env, RVH)) {
|
if (riscv_has_ext(env, RVH) && prev_virt) {
|
||||||
if (prev_virt) {
|
riscv_cpu_swap_hypervisor_regs(env);
|
||||||
riscv_cpu_swap_hypervisor_regs(env);
|
|
||||||
}
|
|
||||||
|
|
||||||
riscv_cpu_set_virt_enabled(env, prev_virt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
riscv_cpu_set_mode(env, prev_priv, prev_virt);
|
||||||
|
|
||||||
return retpc;
|
return retpc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue