From: Rajnesh Kanwal <rkanwal@rivosinc.com>
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>
---
target/riscv/cpu.h | 2 +-
target/riscv/cpu_helper.c | 57 +++++++++++++++++++++++------------------------
target/riscv/op_helper.c | 17 +++++---------
3 files changed, 35 insertions(+), 41 deletions(-)
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 90b8f1b08f83..46faefd24e09 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -544,7 +544,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);
#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);
G_NORETURN void riscv_raise_exception(CPURISCVState *env,
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 6709622dd3ab..10d3fdaed376 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -619,30 +619,6 @@ void riscv_cpu_set_geilen(CPURISCVState *env, target_ulong 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)
{
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);
@@ -736,6 +712,28 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
* preemptive context switch. As a result, do both.
*/
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);
CPURISCVState *env = &cpu->env;
+ bool virt = env->virt_enabled;
bool write_gva = false;
uint64_t s;
@@ -1778,7 +1777,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
htval = env->guest_phys_fault_addr;
- riscv_cpu_set_virt_enabled(env, 0);
+ virt = false;
} else {
/* Trap into HS mode */
env->hstatus = set_field(env->hstatus, HSTATUS_SPV, false);
@@ -1799,7 +1798,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
env->htinst = tinst;
env->pc = (env->stvec >> 2 << 2) +
((async && (env->stvec & 3) == 1) ? cause * 4 : 0);
- riscv_cpu_set_mode(env, PRV_S);
+ riscv_cpu_set_mode(env, PRV_S, virt);
} else {
/* handle the trap in M-mode */
if (riscv_has_ext(env, RVH)) {
@@ -1815,7 +1814,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
mtval2 = env->guest_phys_fault_addr;
/* Trapping to M mode, virt is disabled */
- riscv_cpu_set_virt_enabled(env, 0);
+ virt = false;
}
s = env->mstatus;
@@ -1830,7 +1829,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
env->mtinst = tinst;
env->pc = (env->mtvec >> 2 << 2) +
((async && (env->mtvec & 3) == 1) ? cause * 4 : 0);
- riscv_cpu_set_mode(env, PRV_M);
+ riscv_cpu_set_mode(env, PRV_M, virt);
}
/*
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index 2baf5bc3ca19..ec1408ba0fb1 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -264,7 +264,7 @@ void helper_cbo_inval(CPURISCVState *env, target_ulong address)
target_ulong helper_sret(CPURISCVState *env)
{
uint64_t mstatus;
- target_ulong prev_priv, prev_virt;
+ target_ulong prev_priv, prev_virt = env->virt_enabled;
if (!(env->priv >= PRV_S)) {
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
@@ -307,11 +307,9 @@ target_ulong helper_sret(CPURISCVState *env)
if (prev_virt) {
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;
}
@@ -347,16 +345,13 @@ target_ulong helper_mret(CPURISCVState *env)
mstatus = set_field(mstatus, MSTATUS_MPRV, 0);
}
env->mstatus = mstatus;
- riscv_cpu_set_mode(env, prev_priv);
-
- if (riscv_has_ext(env, RVH)) {
- if (prev_virt) {
- riscv_cpu_swap_hypervisor_regs(env);
- }
- riscv_cpu_set_virt_enabled(env, prev_virt);
+ if (riscv_has_ext(env, RVH) && prev_virt) {
+ riscv_cpu_swap_hypervisor_regs(env);
}
+ riscv_cpu_set_mode(env, prev_priv, prev_virt);
+
return retpc;
}
--
2.34.1
On Thu, Jun 27, 2024 at 10:02 AM Atish Patra <atishp@rivosinc.com> wrote: > > From: Rajnesh Kanwal <rkanwal@rivosinc.com> > > 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> Alistair > --- > target/riscv/cpu.h | 2 +- > target/riscv/cpu_helper.c | 57 +++++++++++++++++++++++------------------------ > target/riscv/op_helper.c | 17 +++++--------- > 3 files changed, 35 insertions(+), 41 deletions(-) > > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h > index 90b8f1b08f83..46faefd24e09 100644 > --- a/target/riscv/cpu.h > +++ b/target/riscv/cpu.h > @@ -544,7 +544,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); > #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); > G_NORETURN void riscv_raise_exception(CPURISCVState *env, > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c > index 6709622dd3ab..10d3fdaed376 100644 > --- a/target/riscv/cpu_helper.c > +++ b/target/riscv/cpu_helper.c > @@ -619,30 +619,6 @@ void riscv_cpu_set_geilen(CPURISCVState *env, target_ulong 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) > { > 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); > > @@ -736,6 +712,28 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv) > * preemptive context switch. As a result, do both. > */ > 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); > CPURISCVState *env = &cpu->env; > + bool virt = env->virt_enabled; > bool write_gva = false; > uint64_t s; > > @@ -1778,7 +1777,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) > > htval = env->guest_phys_fault_addr; > > - riscv_cpu_set_virt_enabled(env, 0); > + virt = false; > } else { > /* Trap into HS mode */ > env->hstatus = set_field(env->hstatus, HSTATUS_SPV, false); > @@ -1799,7 +1798,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) > env->htinst = tinst; > env->pc = (env->stvec >> 2 << 2) + > ((async && (env->stvec & 3) == 1) ? cause * 4 : 0); > - riscv_cpu_set_mode(env, PRV_S); > + riscv_cpu_set_mode(env, PRV_S, virt); > } else { > /* handle the trap in M-mode */ > if (riscv_has_ext(env, RVH)) { > @@ -1815,7 +1814,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) > mtval2 = env->guest_phys_fault_addr; > > /* Trapping to M mode, virt is disabled */ > - riscv_cpu_set_virt_enabled(env, 0); > + virt = false; > } > > s = env->mstatus; > @@ -1830,7 +1829,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) > env->mtinst = tinst; > env->pc = (env->mtvec >> 2 << 2) + > ((async && (env->mtvec & 3) == 1) ? cause * 4 : 0); > - riscv_cpu_set_mode(env, PRV_M); > + riscv_cpu_set_mode(env, PRV_M, virt); > } > > /* > diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c > index 2baf5bc3ca19..ec1408ba0fb1 100644 > --- a/target/riscv/op_helper.c > +++ b/target/riscv/op_helper.c > @@ -264,7 +264,7 @@ void helper_cbo_inval(CPURISCVState *env, target_ulong address) > target_ulong helper_sret(CPURISCVState *env) > { > uint64_t mstatus; > - target_ulong prev_priv, prev_virt; > + target_ulong prev_priv, prev_virt = env->virt_enabled; > > if (!(env->priv >= PRV_S)) { > riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); > @@ -307,11 +307,9 @@ target_ulong helper_sret(CPURISCVState *env) > if (prev_virt) { > 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; > } > @@ -347,16 +345,13 @@ target_ulong helper_mret(CPURISCVState *env) > mstatus = set_field(mstatus, MSTATUS_MPRV, 0); > } > env->mstatus = mstatus; > - riscv_cpu_set_mode(env, prev_priv); > - > - if (riscv_has_ext(env, RVH)) { > - if (prev_virt) { > - riscv_cpu_swap_hypervisor_regs(env); > - } > > - riscv_cpu_set_virt_enabled(env, prev_virt); > + if (riscv_has_ext(env, RVH) && prev_virt) { > + riscv_cpu_swap_hypervisor_regs(env); > } > > + riscv_cpu_set_mode(env, prev_priv, prev_virt); > + > return retpc; > } > > > -- > 2.34.1 > >
On 6/26/24 8:57 PM, Atish Patra wrote: > From: Rajnesh Kanwal <rkanwal@rivosinc.com> > > 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: Daniel Henrique Barboza <dbarboza@ventanamicro.com> > target/riscv/cpu.h | 2 +- > target/riscv/cpu_helper.c | 57 +++++++++++++++++++++++------------------------ > target/riscv/op_helper.c | 17 +++++--------- > 3 files changed, 35 insertions(+), 41 deletions(-) > > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h > index 90b8f1b08f83..46faefd24e09 100644 > --- a/target/riscv/cpu.h > +++ b/target/riscv/cpu.h > @@ -544,7 +544,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); > #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); > G_NORETURN void riscv_raise_exception(CPURISCVState *env, > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c > index 6709622dd3ab..10d3fdaed376 100644 > --- a/target/riscv/cpu_helper.c > +++ b/target/riscv/cpu_helper.c > @@ -619,30 +619,6 @@ void riscv_cpu_set_geilen(CPURISCVState *env, target_ulong 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) > { > 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); > > @@ -736,6 +712,28 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv) > * preemptive context switch. As a result, do both. > */ > 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); > CPURISCVState *env = &cpu->env; > + bool virt = env->virt_enabled; > bool write_gva = false; > uint64_t s; > > @@ -1778,7 +1777,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) > > htval = env->guest_phys_fault_addr; > > - riscv_cpu_set_virt_enabled(env, 0); > + virt = false; > } else { > /* Trap into HS mode */ > env->hstatus = set_field(env->hstatus, HSTATUS_SPV, false); > @@ -1799,7 +1798,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) > env->htinst = tinst; > env->pc = (env->stvec >> 2 << 2) + > ((async && (env->stvec & 3) == 1) ? cause * 4 : 0); > - riscv_cpu_set_mode(env, PRV_S); > + riscv_cpu_set_mode(env, PRV_S, virt); > } else { > /* handle the trap in M-mode */ > if (riscv_has_ext(env, RVH)) { > @@ -1815,7 +1814,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) > mtval2 = env->guest_phys_fault_addr; > > /* Trapping to M mode, virt is disabled */ > - riscv_cpu_set_virt_enabled(env, 0); > + virt = false; > } > > s = env->mstatus; > @@ -1830,7 +1829,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) > env->mtinst = tinst; > env->pc = (env->mtvec >> 2 << 2) + > ((async && (env->mtvec & 3) == 1) ? cause * 4 : 0); > - riscv_cpu_set_mode(env, PRV_M); > + riscv_cpu_set_mode(env, PRV_M, virt); > } > > /* > diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c > index 2baf5bc3ca19..ec1408ba0fb1 100644 > --- a/target/riscv/op_helper.c > +++ b/target/riscv/op_helper.c > @@ -264,7 +264,7 @@ void helper_cbo_inval(CPURISCVState *env, target_ulong address) > target_ulong helper_sret(CPURISCVState *env) > { > uint64_t mstatus; > - target_ulong prev_priv, prev_virt; > + target_ulong prev_priv, prev_virt = env->virt_enabled; > > if (!(env->priv >= PRV_S)) { > riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); > @@ -307,11 +307,9 @@ target_ulong helper_sret(CPURISCVState *env) > if (prev_virt) { > 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; > } > @@ -347,16 +345,13 @@ target_ulong helper_mret(CPURISCVState *env) > mstatus = set_field(mstatus, MSTATUS_MPRV, 0); > } > env->mstatus = mstatus; > - riscv_cpu_set_mode(env, prev_priv); > - > - if (riscv_has_ext(env, RVH)) { > - if (prev_virt) { > - riscv_cpu_swap_hypervisor_regs(env); > - } > > - riscv_cpu_set_virt_enabled(env, prev_virt); > + if (riscv_has_ext(env, RVH) && prev_virt) { > + riscv_cpu_swap_hypervisor_regs(env); > } > > + riscv_cpu_set_mode(env, prev_priv, prev_virt); > + > return retpc; > } > >
© 2016 - 2024 Red Hat, Inc.